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
2 changes: 2 additions & 0 deletions openai-agents/src/agent-patterns/workflows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,7 @@ export async function llmAsJudge(prompt: string): Promise<string> {
return output;
}

// @@@SNIPSTART typescript-openai-agents-agent-as-tool-workflow
export async function agentsAsTools(prompt: string): Promise<string> {
const specialistAgent = new Agent({
name: 'SpecialistAgent',
Expand All @@ -121,6 +122,7 @@ export async function agentsAsTools(prompt: string): Promise<string> {
const result = await runner.run(orchestratorAgent, prompt);
return result.finalOutput ?? '';
}
// @@@SNIPEND

export async function inputGuardrail(prompt: string): Promise<string> {
const blockedKeywords = ['blocked', 'BLOCK', 'forbidden'];
Expand Down
2 changes: 2 additions & 0 deletions openai-agents/src/basic/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ async function run() {
const scenario = process.argv[2] ?? 'hello-world';
console.log(`Running scenario: ${scenario}`);

// @@@SNIPSTART typescript-openai-agents-hello-world-client
const connection = await Connection.connect();
const client = new Client({
connection,
Expand All @@ -30,6 +31,7 @@ async function run() {

const taskQueue = 'openai-agents-basic';
const workflowId = 'openai-agents-' + nanoid();
// @@@SNIPEND

let handle;
switch (scenario) {
Expand Down
2 changes: 2 additions & 0 deletions openai-agents/src/basic/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ async function run() {

const connection = await NativeConnection.connect({ address: 'localhost:7233' });
try {
// @@@SNIPSTART typescript-openai-agents-hello-world-worker
const worker = await Worker.create({
connection,
taskQueue: 'openai-agents-basic',
Expand All @@ -33,6 +34,7 @@ async function run() {
},
});
await worker.run();
// @@@SNIPEND
} finally {
await connection.close();
}
Expand Down
6 changes: 6 additions & 0 deletions openai-agents/src/basic/workflows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,15 @@ import type * as activities from './activities';

const localActivities = proxyLocalActivities<typeof activities>({ startToCloseTimeout: '10 seconds' });

// @@@SNIPSTART typescript-openai-agents-hello-world-workflow
export async function helloWorld(prompt: string): Promise<string> {
const agent = new Agent({ name: 'HelloAgent', instructions: 'You are a helpful assistant.' });
const result = await new TemporalOpenAIRunner().run(agent, prompt);
return result.finalOutput ?? '';
}
// @@@SNIPEND

// @@@SNIPSTART typescript-openai-agents-activity-tool-workflow
export async function tools(prompt: string): Promise<string> {
const weatherTool = activityAsTool<typeof activities.getWeather>(
{
Expand All @@ -35,7 +38,9 @@ export async function tools(prompt: string): Promise<string> {
const result = await new TemporalOpenAIRunner().run(agent, prompt);
return result.finalOutput ?? '';
}
// @@@SNIPEND

// @@@SNIPSTART typescript-openai-agents-inline-tool-workflow
export async function inlineTool(prompt: string): Promise<string> {
const addTool = tool({
name: 'add',
Expand All @@ -52,6 +57,7 @@ export async function inlineTool(prompt: string): Promise<string> {
const result = await new TemporalOpenAIRunner().run(agent, prompt);
return result.finalOutput ?? '';
}
// @@@SNIPEND

export async function localActivityTool(prompt: string): Promise<string> {
const headlinesTool = tool({
Expand Down
2 changes: 2 additions & 0 deletions openai-agents/src/human-approval/workflows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export interface ApprovalInput {
resumeFromRunState?: string;
}

// @@@SNIPSTART typescript-openai-agents-approval-workflow
export async function approvalWorkflow(input: ApprovalInput = {}): Promise<string> {
const action = tool({
name: 'dangerousAction',
Expand Down Expand Up @@ -57,3 +58,4 @@ export async function approvalWorkflow(input: ApprovalInput = {}): Promise<strin
await continueAsNew<typeof approvalWorkflow>({ resumeFromRunState: result.state.toString() });
throw new Error('unreachable');
}
// @@@SNIPEND
42 changes: 25 additions & 17 deletions openai-agents/src/mcp/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,29 @@ async function run() {

const filesystemServerPath = path.resolve(__dirname, 'servers', 'filesystem-server.ts');

// @@@SNIPSTART typescript-openai-agents-mcp-worker
// A stateless provider reconnects per operation, so each tool call stands alone.
const statelessProviders = [
new StatelessMCPServerProvider(
'filesystem',
() =>
new MCPServerStdio({
command: 'npx',
args: ['ts-node', filesystemServerPath],
name: 'filesystem',
}),
),
new StatelessMCPServerProvider(
'streamableHttp',
() => new MCPServerStreamableHttp({ url: toolsHttp.url, name: 'streamableHttp' }),
),
new StatelessMCPServerProvider('sse', () => new MCPServerSSE({ url: toolsSse.url, name: 'sse' })),
];

// A stateful provider also takes the connection, which the plugin uses to run a
// dedicated Worker holding the MCP session open for the life of the Workflow run.
const statefulProviders = [new StatefulMCPServerProvider('memory', () => createNotesServer(), connection)];

const worker = await Worker.create({
connection,
taskQueue: 'openai-agents-mcp',
Expand All @@ -35,25 +58,10 @@ async function run() {
new OpenAIAgentsPlugin({
modelProvider: new OpenAIProvider({ apiKey }),
modelParams: { useLocalActivity: true },
mcpServerProviders: [
new StatelessMCPServerProvider(
'filesystem',
() =>
new MCPServerStdio({
command: 'npx',
args: ['ts-node', filesystemServerPath],
name: 'filesystem',
}),
),
new StatelessMCPServerProvider(
'streamableHttp',
() => new MCPServerStreamableHttp({ url: toolsHttp.url, name: 'streamableHttp' }),
),
new StatelessMCPServerProvider('sse', () => new MCPServerSSE({ url: toolsSse.url, name: 'sse' })),
new StatefulMCPServerProvider('memory', () => createNotesServer(), connection),
],
mcpServerProviders: [...statelessProviders, ...statefulProviders],
}),
],
// @@@SNIPEND
bundlerOptions: {
webpackConfigHook: (config) => ({
...config,
Expand Down
4 changes: 4 additions & 0 deletions openai-agents/src/mcp/workflows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import type { Activities } from './activities';

const activities = proxyActivities<Activities>({ startToCloseTimeout: '1 minute' });

// @@@SNIPSTART typescript-openai-agents-stateless-mcp-workflow
export async function filesystem(prompt: string): Promise<string> {
const agent = new Agent({
name: 'FilesystemAgent',
Expand All @@ -14,6 +15,7 @@ export async function filesystem(prompt: string): Promise<string> {
const result = await new TemporalOpenAIRunner().run(agent, prompt);
return result.finalOutput ?? '';
}
// @@@SNIPEND

export async function streamableHttp(prompt: string): Promise<string> {
const agent = new Agent({
Expand Down Expand Up @@ -45,6 +47,7 @@ export async function promptServer(prompt: string): Promise<string> {
return result.finalOutput ?? '';
}

// @@@SNIPSTART typescript-openai-agents-stateful-mcp-workflow
export async function statefulMemory(prompt: string): Promise<string> {
const server = statefulMcpServer('memory');
await server.connect();
Expand All @@ -60,3 +63,4 @@ export async function statefulMemory(prompt: string): Promise<string> {
await server.cleanup();
}
}
// @@@SNIPEND
2 changes: 2 additions & 0 deletions openai-agents/src/nexus-tools/api.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import * as nexus from 'nexus-rpc';

// @@@SNIPSTART typescript-openai-agents-nexus-tools-api
export interface GetWeatherInput {
city: string;
}
Expand All @@ -13,3 +14,4 @@ export interface GetWeatherOutput {
export const weatherService = nexus.service('weather', {
getWeather: nexus.operation<GetWeatherInput, GetWeatherOutput>(),
});
// @@@SNIPEND
2 changes: 2 additions & 0 deletions openai-agents/src/nexus-tools/workflows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import { weatherService } from './api';

export const WEATHER_ENDPOINT = 'openai-agents-weather-endpoint';

// @@@SNIPSTART typescript-openai-agents-nexus-tool-workflow
export async function nexusToolWorkflow(prompt: string): Promise<string> {
const weatherTool = nexusOperationAsTool(
weatherService.operations.getWeather,
Expand All @@ -29,3 +30,4 @@ export async function nexusToolWorkflow(prompt: string): Promise<string> {
const result = await new TemporalOpenAIRunner().run(agent, prompt);
return result.finalOutput ?? '';
}
// @@@SNIPEND
4 changes: 4 additions & 0 deletions openai-agents/src/sessions/workflows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import type { AgentInputItem } from '@openai/agents-core';
import { TemporalOpenAIRunner, WorkflowSafeMemorySession } from '@temporalio/openai-agents/workflow';
import { continueAsNew } from '@temporalio/workflow';

// @@@SNIPSTART typescript-openai-agents-session-workflow
export async function multiTurnChat(prompts: string[]): Promise<string[]> {
const agent = new Agent({ name: 'ChatAgent', instructions: 'You are a helpful assistant.' });
const session = new WorkflowSafeMemorySession();
Expand All @@ -14,13 +15,15 @@ export async function multiTurnChat(prompts: string[]): Promise<string[]> {
}
return replies;
}
// @@@SNIPEND

export interface CarryoverChatInput {
prompts: string[];
initialItems?: AgentInputItem[];
accumulated?: string[];
}

// @@@SNIPSTART typescript-openai-agents-session-carryover-workflow
export async function carryoverChat(input: CarryoverChatInput): Promise<string[] | void> {
const agent = new Agent({ name: 'ChatAgent', instructions: 'You are a helpful assistant.' });
const session = new WorkflowSafeMemorySession({ initialItems: input.initialItems });
Expand All @@ -46,3 +49,4 @@ export async function carryoverChat(input: CarryoverChatInput): Promise<string[]
accumulated,
});
}
// @@@SNIPEND
2 changes: 2 additions & 0 deletions openai-agents/src/tools/workflows.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Agent } from '@openai/agents-core';
import { webSearchTool, imageGenerationTool, codeInterpreterTool } from '@openai/agents-openai';
import { TemporalOpenAIRunner } from '@temporalio/openai-agents/workflow';

// @@@SNIPSTART typescript-openai-agents-hosted-tool-workflow
export async function webSearch(prompt: string): Promise<string> {
const agent = new Agent({
name: 'WebSearchAgent',
Expand All @@ -11,6 +12,7 @@ export async function webSearch(prompt: string): Promise<string> {
const result = await new TemporalOpenAIRunner().run(agent, prompt);
return result.finalOutput ?? '';
}
// @@@SNIPEND

export async function imageGeneration(prompt: string): Promise<string> {
const agent = new Agent({
Expand Down
2 changes: 2 additions & 0 deletions openai-agents/src/tracing/worker.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,15 @@ async function run() {
connection,
taskQueue: 'openai-agents-tracing',
workflowsPath: require.resolve('./workflows'),
// @@@SNIPSTART typescript-openai-agents-tracing-worker
plugins: [
new OpenAIAgentsPlugin({
modelProvider: new OpenAIProvider({ apiKey }),
modelParams: { useLocalActivity: true },
interceptorOptions: { useOtelInstrumentation, addTemporalSpans: true },
}),
],
// @@@SNIPEND
bundlerOptions: {
webpackConfigHook: (config) => ({
...config,
Expand Down