From 3e73d0d70b7e8086adef1a4451c0fda52ff665ce Mon Sep 17 00:00:00 2001 From: Brian Strauch Date: Tue, 18 Aug 2026 12:43:15 -0700 Subject: [PATCH] Add snipsync markers to the OpenAI Agents samples The TypeScript OpenAI Agents SDK integration guide hand-maintained its code blocks, so nothing verified them against a running sample. Add snipsync markers scoped to exactly the code that guide shows, so it can pull from here instead. Markers wrapping indented code sit at that code's indent level rather than column 0, so snipsync's dedent still applies (see #346). mcp/worker.ts hoists its MCP providers into two named locals before Worker.create. Behavior is unchanged; it gives the stateless and stateful registrations a contiguous region a marker can wrap, and names which is which. Co-Authored-By: Claude Opus 5 (1M context) --- openai-agents/src/agent-patterns/workflows.ts | 2 + openai-agents/src/basic/client.ts | 2 + openai-agents/src/basic/worker.ts | 2 + openai-agents/src/basic/workflows.ts | 6 +++ openai-agents/src/human-approval/workflows.ts | 2 + openai-agents/src/mcp/worker.ts | 42 +++++++++++-------- openai-agents/src/mcp/workflows.ts | 4 ++ openai-agents/src/nexus-tools/api.ts | 2 + openai-agents/src/nexus-tools/workflows.ts | 2 + openai-agents/src/sessions/workflows.ts | 4 ++ openai-agents/src/tools/workflows.ts | 2 + openai-agents/src/tracing/worker.ts | 2 + 12 files changed, 55 insertions(+), 17 deletions(-) diff --git a/openai-agents/src/agent-patterns/workflows.ts b/openai-agents/src/agent-patterns/workflows.ts index 609cc0a58..69840cfaf 100644 --- a/openai-agents/src/agent-patterns/workflows.ts +++ b/openai-agents/src/agent-patterns/workflows.ts @@ -99,6 +99,7 @@ export async function llmAsJudge(prompt: string): Promise { return output; } +// @@@SNIPSTART typescript-openai-agents-agent-as-tool-workflow export async function agentsAsTools(prompt: string): Promise { const specialistAgent = new Agent({ name: 'SpecialistAgent', @@ -121,6 +122,7 @@ export async function agentsAsTools(prompt: string): Promise { const result = await runner.run(orchestratorAgent, prompt); return result.finalOutput ?? ''; } +// @@@SNIPEND export async function inputGuardrail(prompt: string): Promise { const blockedKeywords = ['blocked', 'BLOCK', 'forbidden']; diff --git a/openai-agents/src/basic/client.ts b/openai-agents/src/basic/client.ts index 03f8e640c..ab0a857cc 100644 --- a/openai-agents/src/basic/client.ts +++ b/openai-agents/src/basic/client.ts @@ -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, @@ -30,6 +31,7 @@ async function run() { const taskQueue = 'openai-agents-basic'; const workflowId = 'openai-agents-' + nanoid(); + // @@@SNIPEND let handle; switch (scenario) { diff --git a/openai-agents/src/basic/worker.ts b/openai-agents/src/basic/worker.ts index d90f53275..1110b22c8 100644 --- a/openai-agents/src/basic/worker.ts +++ b/openai-agents/src/basic/worker.ts @@ -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', @@ -33,6 +34,7 @@ async function run() { }, }); await worker.run(); + // @@@SNIPEND } finally { await connection.close(); } diff --git a/openai-agents/src/basic/workflows.ts b/openai-agents/src/basic/workflows.ts index 45f6aef0e..aa7396904 100644 --- a/openai-agents/src/basic/workflows.ts +++ b/openai-agents/src/basic/workflows.ts @@ -6,12 +6,15 @@ import type * as activities from './activities'; const localActivities = proxyLocalActivities({ startToCloseTimeout: '10 seconds' }); +// @@@SNIPSTART typescript-openai-agents-hello-world-workflow export async function helloWorld(prompt: string): Promise { 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 { const weatherTool = activityAsTool( { @@ -35,7 +38,9 @@ export async function tools(prompt: string): Promise { 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 { const addTool = tool({ name: 'add', @@ -52,6 +57,7 @@ export async function inlineTool(prompt: string): Promise { const result = await new TemporalOpenAIRunner().run(agent, prompt); return result.finalOutput ?? ''; } +// @@@SNIPEND export async function localActivityTool(prompt: string): Promise { const headlinesTool = tool({ diff --git a/openai-agents/src/human-approval/workflows.ts b/openai-agents/src/human-approval/workflows.ts index 1bee9b39f..630450bb7 100644 --- a/openai-agents/src/human-approval/workflows.ts +++ b/openai-agents/src/human-approval/workflows.ts @@ -8,6 +8,7 @@ export interface ApprovalInput { resumeFromRunState?: string; } +// @@@SNIPSTART typescript-openai-agents-approval-workflow export async function approvalWorkflow(input: ApprovalInput = {}): Promise { const action = tool({ name: 'dangerousAction', @@ -57,3 +58,4 @@ export async function approvalWorkflow(input: ApprovalInput = {}): Promise({ resumeFromRunState: result.state.toString() }); throw new Error('unreachable'); } +// @@@SNIPEND diff --git a/openai-agents/src/mcp/worker.ts b/openai-agents/src/mcp/worker.ts index 5ede31a92..a71bd090d 100644 --- a/openai-agents/src/mcp/worker.ts +++ b/openai-agents/src/mcp/worker.ts @@ -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', @@ -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, diff --git a/openai-agents/src/mcp/workflows.ts b/openai-agents/src/mcp/workflows.ts index 81afc803d..b74143435 100644 --- a/openai-agents/src/mcp/workflows.ts +++ b/openai-agents/src/mcp/workflows.ts @@ -5,6 +5,7 @@ import type { Activities } from './activities'; const activities = proxyActivities({ startToCloseTimeout: '1 minute' }); +// @@@SNIPSTART typescript-openai-agents-stateless-mcp-workflow export async function filesystem(prompt: string): Promise { const agent = new Agent({ name: 'FilesystemAgent', @@ -14,6 +15,7 @@ export async function filesystem(prompt: string): Promise { const result = await new TemporalOpenAIRunner().run(agent, prompt); return result.finalOutput ?? ''; } +// @@@SNIPEND export async function streamableHttp(prompt: string): Promise { const agent = new Agent({ @@ -45,6 +47,7 @@ export async function promptServer(prompt: string): Promise { return result.finalOutput ?? ''; } +// @@@SNIPSTART typescript-openai-agents-stateful-mcp-workflow export async function statefulMemory(prompt: string): Promise { const server = statefulMcpServer('memory'); await server.connect(); @@ -60,3 +63,4 @@ export async function statefulMemory(prompt: string): Promise { await server.cleanup(); } } +// @@@SNIPEND diff --git a/openai-agents/src/nexus-tools/api.ts b/openai-agents/src/nexus-tools/api.ts index 87c172899..d26708207 100644 --- a/openai-agents/src/nexus-tools/api.ts +++ b/openai-agents/src/nexus-tools/api.ts @@ -1,5 +1,6 @@ import * as nexus from 'nexus-rpc'; +// @@@SNIPSTART typescript-openai-agents-nexus-tools-api export interface GetWeatherInput { city: string; } @@ -13,3 +14,4 @@ export interface GetWeatherOutput { export const weatherService = nexus.service('weather', { getWeather: nexus.operation(), }); +// @@@SNIPEND diff --git a/openai-agents/src/nexus-tools/workflows.ts b/openai-agents/src/nexus-tools/workflows.ts index a0efa1916..a9a6c6c07 100644 --- a/openai-agents/src/nexus-tools/workflows.ts +++ b/openai-agents/src/nexus-tools/workflows.ts @@ -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 { const weatherTool = nexusOperationAsTool( weatherService.operations.getWeather, @@ -29,3 +30,4 @@ export async function nexusToolWorkflow(prompt: string): Promise { const result = await new TemporalOpenAIRunner().run(agent, prompt); return result.finalOutput ?? ''; } +// @@@SNIPEND diff --git a/openai-agents/src/sessions/workflows.ts b/openai-agents/src/sessions/workflows.ts index 67bf86ff8..51ac54464 100644 --- a/openai-agents/src/sessions/workflows.ts +++ b/openai-agents/src/sessions/workflows.ts @@ -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 { const agent = new Agent({ name: 'ChatAgent', instructions: 'You are a helpful assistant.' }); const session = new WorkflowSafeMemorySession(); @@ -14,6 +15,7 @@ export async function multiTurnChat(prompts: string[]): Promise { } return replies; } +// @@@SNIPEND export interface CarryoverChatInput { prompts: string[]; @@ -21,6 +23,7 @@ export interface CarryoverChatInput { accumulated?: string[]; } +// @@@SNIPSTART typescript-openai-agents-session-carryover-workflow export async function carryoverChat(input: CarryoverChatInput): Promise { const agent = new Agent({ name: 'ChatAgent', instructions: 'You are a helpful assistant.' }); const session = new WorkflowSafeMemorySession({ initialItems: input.initialItems }); @@ -46,3 +49,4 @@ export async function carryoverChat(input: CarryoverChatInput): Promise { const agent = new Agent({ name: 'WebSearchAgent', @@ -11,6 +12,7 @@ export async function webSearch(prompt: string): Promise { const result = await new TemporalOpenAIRunner().run(agent, prompt); return result.finalOutput ?? ''; } +// @@@SNIPEND export async function imageGeneration(prompt: string): Promise { const agent = new Agent({ diff --git a/openai-agents/src/tracing/worker.ts b/openai-agents/src/tracing/worker.ts index aa7896da0..fc68951b3 100644 --- a/openai-agents/src/tracing/worker.ts +++ b/openai-agents/src/tracing/worker.ts @@ -40,6 +40,7 @@ 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 }), @@ -47,6 +48,7 @@ async function run() { interceptorOptions: { useOtelInstrumentation, addTemporalSpans: true }, }), ], + // @@@SNIPEND bundlerOptions: { webpackConfigHook: (config) => ({ ...config,