Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions docs/guides/code-execution.md
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,10 @@ See [E2B templates](https://e2b.dev/docs/templates) for details.
- Costs money (has free tier)
- Slightly higher latency than local

### Full Example

See [examples/e2b-example.ts](https://github.com/artificial-analysis/StirrupJS/blob/main/examples/e2b-example.ts) for a complete working example using E2B with the code interpreter template.

## Choosing a Backend

| Backend | Best For | Pros | Cons |
Expand Down
8 changes: 2 additions & 6 deletions examples/_helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,8 @@ export function loadEnv() {
*/
export function getApiConfig() {
const apiKey = process.env.OPENROUTER_API_KEY || process.env.OPENAI_API_KEY;
const baseURL = process.env.OPENROUTER_API_KEY
? 'https://openrouter.ai/api/v1'
: undefined;
const model = process.env.OPENROUTER_API_KEY
? 'anthropic/claude-sonnet-4.5'
: 'gpt-5.2';
const baseURL = process.env.OPENROUTER_API_KEY ? 'https://openrouter.ai/api/v1' : undefined;
const model = process.env.OPENROUTER_API_KEY ? 'anthropic/claude-sonnet-4.5' : 'gpt-5.2';

if (!apiKey) {
console.error('Error: Set OPENROUTER_API_KEY or OPENAI_API_KEY in .env file');
Expand Down
13 changes: 9 additions & 4 deletions examples/custom-tool.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,15 @@

import { z } from 'zod';
import { ChatCompletionsClient } from '../src/clients/openai-client.js';
import { Agent, SIMPLE_FINISH_TOOL, ToolUseCountMetadata, type AgentRunResult, type FinishParams, type Tool, type ToolResult } from '../src/index.js';
import {
Agent,
SIMPLE_FINISH_TOOL,
ToolUseCountMetadata,
type AgentRunResult,
type FinishParams,
type Tool,
type ToolResult,
} from '../src/index.js';
import { getApiConfig, loadEnv } from './_helpers.js';

// Load environment variables
Expand Down Expand Up @@ -51,9 +59,6 @@ const databaseTool: Tool<typeof DbQueryParamsSchema, ToolUseCountMetadata> = {
description: 'Execute a SQL query against the database',
parameters: DbQueryParamsSchema,
executor: async (params) => {
// Simulate database query
console.log(`Executing query: ${params.query}`);

// Mock results
const results = [
{ id: 1, name: 'Alice', age: 30 },
Expand Down
39 changes: 39 additions & 0 deletions examples/e2b-example.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* E2B Example
* Demonstrates how to use the E2BCodeExecToolProvider to execute code in a sandboxed environment
*
* To run this example:
* 1. Create a .env file with: E2B_API_KEY=your-key-here
* 2. Run: npx tsx examples/e2b-example.ts
*/
import 'dotenv/config';
import { Agent, E2BCodeExecToolProvider, SIMPLE_FINISH_TOOL } from '../src/index.js';
import { ChatCompletionsClient } from '../src/clients/openai-client.js';

async function main() {
const client = new ChatCompletionsClient({
apiKey: process.env.OPENROUTER_API_KEY,
baseURL: 'https://openrouter.ai/api/v1',
model: 'anthropic/claude-opus-4.5',
maxTokens: 100_000,
});

const codeExec = new E2BCodeExecToolProvider({ apiKey: process.env.E2B_API_KEY!, template: 'code-interpreter-v1' });

const agent = new Agent({
client,
name: 'agent',
maxTurns: 15,
tools: [codeExec],
finishTool: SIMPLE_FINISH_TOOL,
});

await using session = agent.session({ outputDir: './output' });

const result = await session.run(
'Generate the first 50 numbers of the Fibonacci sequence and create ' +
'a line chart showing the growth. Save the chart as fibonacci.png'
);
}

main().catch(console.error);
83 changes: 76 additions & 7 deletions examples/events-example.ts
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,9 @@ async function example1_BasicEvents() {
// Run the agent with session
// Note: We disable the default logger here to avoid duplicate logs with our custom event listeners
await using session = agent.session({ noLogger: true });
const result: AgentRunResult<FinishParams> = await session.run('What is 2+2? When you know the answer, call the finish tool.');

const result: AgentRunResult<FinishParams> = await session.run(
'What is 2+2? When you know the answer, call the finish tool.'
);
}

// ============================================================================
Expand Down Expand Up @@ -135,9 +136,7 @@ async function example2_Streaming() {
case 'message':
if (event.message.role === 'assistant') {
const content =
typeof event.message.content === 'string'
? event.message.content
: JSON.stringify(event.message.content);
typeof event.message.content === 'string' ? event.message.content : JSON.stringify(event.message.content);
console.log('💬 Assistant:', content.substring(0, 80));
} else if (event.message.role === 'tool') {
console.log('🔧 Tool result received');
Expand Down Expand Up @@ -233,6 +232,76 @@ async function example3_Cancellation() {
}
}

// ============================================================================
// Example 4: Structured Logging
// ============================================================================

async function example4_StructuredLogging() {
console.log('\n========================================');
console.log('Example 4: Structured Logging');
console.log('========================================\n');

const { apiKey, baseURL, model } = getApiConfig();
const client = new ChatCompletionsClient({
apiKey,
baseURL,
model,
});

const agent = new Agent({
client,
name: 'logging-agent',
maxTurns: 5,
finishTool: SIMPLE_FINISH_TOOL,
});

// The session automatically attaches the structured logger by default
// This provides formatted console output with boxes for messages, tool results, and summaries
await using session = agent.session();
await session.run('What is 2+2? Call finish when done.');
}

// ============================================================================
// Example 5: Combined Events and Structured Logging
// ============================================================================

async function example5_Combined() {
console.log('\n========================================');
console.log('Example 5: Combined Events + Logging');
console.log('========================================\n');

const { apiKey, baseURL, model } = getApiConfig();
const client = new ChatCompletionsClient({
apiKey,
baseURL,
model,
});

const agent = new Agent({
client,
name: 'combined-agent',
maxTurns: 5,
tools: [new WebToolProvider()],
finishTool: SIMPLE_FINISH_TOOL,
});

// Add custom event handlers alongside the structured logger
// These can be used for custom metrics, alerts, or side effects
agent.on('tool:complete', ({ name, success }) => {
// Example: Send metrics to monitoring system
console.log(`[METRICS] Tool ${name} completed: ${success ? 'success' : 'failure'}`);
});

agent.on('run:complete', ({ duration }) => {
// Example: Log to external system
console.log(`[METRICS] Total run duration: ${duration}ms`);
});

// The structured logger runs alongside custom event handlers
await using session = agent.session();
await session.run('What is 2+2? Call finish when done.');
}

// ============================================================================
// Main
// ============================================================================
Expand All @@ -254,11 +323,11 @@ if (import.meta.url === `file://${process.argv[1]}`) {
}

// Run examples - uncomment the ones you want to try:
await example1_BasicEvents();
// await example1_BasicEvents();
// await example2_Streaming();
// await example3_Cancellation();
// await example4_StructuredLogging();
// await example5_Combined();
await example5_Combined();

console.log('\n✨ Demo complete!');
}
13 changes: 11 additions & 2 deletions examples/getting-started.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,14 @@
*/

import { ChatCompletionsClient } from '../src/clients/openai-client.js';
import { Agent, CALCULATOR_TOOL, DEFAULT_TOOLS, SIMPLE_FINISH_TOOL, type AgentRunResult, type FinishParams } from '../src/index.js';
import {
Agent,
CALCULATOR_TOOL,
DEFAULT_TOOLS,
SIMPLE_FINISH_TOOL,
type AgentRunResult,
type FinishParams,
} from '../src/index.js';
import { getApiConfig, loadEnv } from './_helpers.js';

// Load environment variables from .env file
Expand Down Expand Up @@ -45,7 +52,9 @@ async function main() {
});

// 4. Run the agent with a task
const result: AgentRunResult<FinishParams> = await session.run('What is 2 + 2? Calculate it using the calculator tool and then finish.');
const result: AgentRunResult<FinishParams> = await session.run(
'What is 2 + 2? Calculate it using the calculator tool and then finish.'
);
console.log(result);
}

Expand Down
4 changes: 2 additions & 2 deletions examples/image.ts
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,8 @@ The paths parameter must always be an array of strings, even if there's only one

// 3. Use session to configure output directory (files will be auto-saved on cleanup)
// Structured logging is enabled by default with debug level
await using session = agent.session({
outputDir: './output'
await using session = agent.session({
outputDir: './output',
});

// 4. Run the agent with a task
Expand Down
2 changes: 0 additions & 2 deletions examples/skills/skills-example.ts
Original file line number Diff line number Diff line change
Expand Up @@ -53,5 +53,3 @@ async function main() {
}

main().catch(console.error);


18 changes: 15 additions & 3 deletions examples/sub-agent.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,14 @@
*/

import { ChatCompletionsClient } from '../src/clients/openai-client.js';
import { Agent, CALCULATOR_TOOL, SIMPLE_FINISH_TOOL, type AgentRunResult, type FinishParams } from '../src/index.js';
import {
Agent,
CALCULATOR_TOOL,
E2BCodeExecToolProvider,
SIMPLE_FINISH_TOOL,
type AgentRunResult,
type FinishParams,
} from '../src/index.js';
import { WebToolProvider } from '../src/tools/web/provider.js';
import { getApiConfig, loadEnv } from './_helpers.js';

Expand All @@ -27,6 +34,8 @@ async function main() {
maxTokens: 100_000,
});

const codeExec = new E2BCodeExecToolProvider({ apiKey: process.env.E2B_API_KEY!, template: 'code-interpreter-v1' });

// Create specialized sub-agents

// 1. Research Agent - specialized in web research
Expand All @@ -36,7 +45,8 @@ async function main() {
maxTurns: 5,
tools: [new WebToolProvider(180_000, process.env.BRAVE_API_KEY)],
finishTool: SIMPLE_FINISH_TOOL,
systemPrompt: 'You are a research specialist. Use web search to find accurate information.',
systemPrompt:
'You are a research specialist. Use web search to find accurate information. Return all relevant information in the finish tool.',
});

// 2. Calculator Agent - specialized in math
Expand All @@ -46,7 +56,8 @@ async function main() {
maxTurns: 3,
tools: [CALCULATOR_TOOL],
finishTool: SIMPLE_FINISH_TOOL,
systemPrompt: 'You are a math specialist. Calculate precisely using the calculator tool.',
systemPrompt:
'You are a math specialist. Calculate precisely using the calculator tool. Return all relevant information in the finish tool.',
});

// 3. Main Coordinator Agent - delegates to sub-agents
Expand All @@ -58,6 +69,7 @@ async function main() {
// Convert sub-agents to tools
researchAgent.toTool('Delegate research tasks to the research specialist'),
mathAgent.toTool('Delegate math calculations to the math specialist'),
codeExec,
],
finishTool: SIMPLE_FINISH_TOOL,
systemPrompt: `You are a task coordinator. Delegate tasks to specialized sub-agents:
Expand Down
2 changes: 0 additions & 2 deletions examples/user-input.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,5 +58,3 @@ What is the population of the user's home country over the last 3 years?
}

main().catch(console.error);


Loading