Skip to content
Draft
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
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
"@temporalio/envconfig": "workspace:*",
"@temporalio/interceptors-opentelemetry": "workspace:*",
"@temporalio/nexus": "workspace:*",
"@temporalio/openai-agents": "workspace:*",
"@temporalio/nyc-test-coverage": "workspace:*",
"@temporalio/plugin": "workspace:*",
"@temporalio/proto": "workspace:*",
Expand Down
99 changes: 99 additions & 0 deletions packages/openai-agents/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
{
"name": "@temporalio/openai-agents",
"version": "1.16.0",
"description": "Temporal OpenAI Agents SDK integration package",
"main": "lib/index.js",
"types": "./lib/index.d.ts",
"exports": {
".": {
"types": "./lib/index.d.ts",
"import": "./lib/index.js",
"require": "./lib/index.js",
"default": "./lib/index.js"
},
"./workflow": {
"types": "./lib/workflow.d.ts",
"import": "./lib/workflow.js",
"require": "./lib/workflow.js",
"default": "./lib/workflow.js"
},
"./load-polyfills": {
"types": "./lib/workflow/load-polyfills.d.ts",
"import": "./lib/workflow/load-polyfills.js",
"require": "./lib/workflow/load-polyfills.js",
"default": "./lib/workflow/load-polyfills.js"
},
"./lib/workflow": {
"types": "./lib/workflow.d.ts",
"import": "./lib/workflow.js",
"require": "./lib/workflow.js",
"default": "./lib/workflow.js"
},
"./lib/load-polyfills": {
"types": "./lib/workflow/load-polyfills.d.ts",
"import": "./lib/workflow/load-polyfills.js",
"require": "./lib/workflow/load-polyfills.js",
"default": "./lib/workflow/load-polyfills.js"
},
"./lib/index": {
"types": "./lib/index.d.ts",
"import": "./lib/index.js",
"require": "./lib/index.js",
"default": "./lib/index.js"
},
"./testing": {
"types": "./lib/worker/testing.d.ts",
"import": "./lib/worker/testing.js",
"require": "./lib/worker/testing.js",
"default": "./lib/worker/testing.js"
},
"./lib/testing": {
"types": "./lib/worker/testing.d.ts",
"import": "./lib/worker/testing.js",
"require": "./lib/worker/testing.js",
"default": "./lib/worker/testing.js"
}
},
"keywords": [
"temporal",
"workflow",
"ai",
"openai",
"agents"
],
"author": "Temporal Technologies Inc. <sdk@temporal.io>",
"license": "MIT",
"dependencies": {
"@opentelemetry/api": "^1.9.0",
"@temporalio/activity": "workspace:*",
"@temporalio/common": "workspace:*",
"@temporalio/plugin": "workspace:*",
"@temporalio/workflow": "workspace:*",
"@ungap/structured-clone": "^1.3.0",
"headers-polyfill": "^4.0.3",
"web-streams-polyfill": "^4.2.0"
},
"peerDependencies": {
"@openai/agents-core": "~0.3.0",
"@openai/agents-openai": "~0.3.0"
},
"engines": {
"node": ">= 20.0.0"
},
"bugs": {
"url": "https://github.com/temporalio/sdk-typescript/issues"
},
"repository": {
"type": "git",
"url": "git+https://github.com/temporalio/sdk-typescript.git",
"directory": "packages/openai-agents"
},
"homepage": "https://github.com/temporalio/sdk-typescript/tree/main/packages/openai-agents",
"publishConfig": {
"access": "public"
},
"files": [
"src",
"lib"
]
}
19 changes: 19 additions & 0 deletions packages/openai-agents/src/common/errors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import { TemporalFailure } from '@temporalio/common';

export function unwrapTemporalFailure(error: unknown): TemporalFailure | undefined {
const visited = new Set<unknown>();
const stack: unknown[] = [error];
while (stack.length > 0) {
const current = stack.pop();
if (!current || typeof current !== 'object' || visited.has(current)) continue;
visited.add(current);
if (current instanceof TemporalFailure) return current;
if (current instanceof AggregateError) {
for (const inner of current.errors) {
stack.push(inner);
}
}
stack.push((current as any).cause);
}
return undefined;
}
42 changes: 42 additions & 0 deletions packages/openai-agents/src/common/model-activity-options.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import type { Agent, AgentInputItem } from '@openai/agents-core';
import { ActivityCancellationType, type Duration, type Priority, type RetryPolicy } from '@temporalio/common';

export type { AgentInputItem } from '@openai/agents-core';

export interface ModelSummaryProvider {
/** Generate a human-readable summary for the model activity shown in the Temporal UI. */
provide(
agent: Agent<any, any> | undefined,
instructions: string | undefined,
input: string | AgentInputItem[]
): string;
}

export interface ModelActivityOptions {
/** Task queue for the model activity. Defaults to the current worker's task queue. */
taskQueue?: string;
/** Maximum total time from schedule to completion, including retries. */
scheduleToCloseTimeout?: Duration;
/** Maximum time the activity can wait in the task queue before a worker picks it up. */
scheduleToStartTimeout?: Duration;
/** Maximum time for a single activity execution attempt. @default '60s' */
startToCloseTimeout?: Duration;
/** Interval for heartbeat checks. The activity must heartbeat within this period. */
heartbeatTimeout?: Duration;
/** Retry policy for the model activity. Defaults to the server-defined policy. */
retryPolicy?: RetryPolicy;
/** Use local activities instead of regular activities. Avoids a server round-trip but lacks independent retry. @default false */
useLocalActivity?: boolean;
/** Activity summary shown in the Temporal UI. String for static text, ModelSummaryProvider for dynamic. */
summaryOverride?: string | ModelSummaryProvider;
/** How cancellation propagates from the workflow to the activity. @default ActivityCancellationType.TRY_CANCEL */
cancellationType?: ActivityCancellationType;
/** Priority for the model activity. Omit to use server defaults. */
priority?: Priority;
}

export const DEFAULT_MODEL_ACTIVITY_OPTIONS: ModelActivityOptions = {
startToCloseTimeout: '60s',
useLocalActivity: false,
cancellationType: ActivityCancellationType.TRY_CANCEL,
};
57 changes: 57 additions & 0 deletions packages/openai-agents/src/common/serialized-model.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
import type { ModelSettings, SerializedHandoff, SerializedOutputType, SerializedTool } from '@openai/agents-core';

/** Current wire protocol version. Activity validates this on every invocation. */
export const WIRE_VERSION = 1;

// Note: Some fields (modelSettings, tools, outputType, handoffs) reference upstream types directly.
// We trust these to remain JSON-safe; if upstream adds a non-serializable field, bump WIRE_VERSION
// and either project or exclude.

/** Recursive JSON-safe type replacing upstream `unknown` fields on the wire. */
export type JsonValue = null | string | number | boolean | JsonValue[] | { [k: string]: JsonValue };

/** JSON-serializable projection of upstream `ModelRequest`, sent workflow → activity. */
export interface SerializedModelRequest {
__wireVersion: typeof WIRE_VERSION;
systemInstructions?: string;
input: JsonValue;
modelSettings: ModelSettings;
tools: SerializedTool[];
toolsExplicitlyProvided?: boolean;
outputType: SerializedOutputType;
handoffs: SerializedHandoff[];
prompt?: JsonValue;
previousResponseId?: string;
conversationId?: string;
// tracing is ModelTracing (boolean | 'enabled_without_data') — an enablement flag, not trace context.
// OTel span context for activity-under-generation nesting is tracked separately (see TemporalTracingProcessor).
tracing: JsonValue;
overridePromptModel?: boolean;
// Excluded by design (must stay in this comment for future contributors):
// signal — AbortSignal; not serializable. Temporal cancellation provides equivalent.
}

/** JSON-serializable projection of upstream `ModelResponse`, returned activity → workflow. */
export interface SerializedModelResponse {
__wireVersion: typeof WIRE_VERSION;
usage: JsonValue;
output: JsonValue[];
responseId?: string;
/**
* Provider-specific metadata. Upstream type is `Record<string, any>`.
*
* **Coercion warning:** Temporal's JSON codec serializes this field as-is. Non-JSON-primitive
* values (Date, Map, Set, class instances) will be silently coerced — e.g., Date becomes an
* ISO 8601 string. Code consuming this field on the workflow side will receive the coerced
* form, not the original type. If your model provider populates providerData with non-JSON
* types, handle the coerced representation explicitly.
*/
providerData?: Record<string, JsonValue>;
// All upstream ModelResponse fields are present, with types narrowed to JSON-safe equivalents (Usage → JsonValue, etc.).
}

/** Activity input envelope: model name + serialized request. */
export interface InvokeModelActivityInput {
modelName: string;
request: SerializedModelRequest;
}
39 changes: 39 additions & 0 deletions packages/openai-agents/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
/**
* @temporalio/openai-agents — Temporal integration for the OpenAI Agents SDK.
*
* Deferred (not in this package):
* - StatefulMCPServerProvider — persistent MCP server connections across worker lifecycle
* - nexusOperationAsTool — TS SDK lacks executeNexusOperation; add when available
* - testing.AgentEnvironment — richer test harness beyond FakeModel
* - workflowFailureExceptionTypes registration (TS SDK doesn't support)
*/

// Main entry — all public exports (plugin, activities, workflow utilities, testing namespace, errors)

export { OpenAIAgentsPlugin } from './worker/plugin';
export type { OpenAIAgentsPluginOptions } from './worker/plugin';
export { toSerializedModelResponse } from './worker/activities';
export { StatelessMCPServerProvider } from './worker/mcp-provider';
export type { StatelessMCPServerFactory, MCPToolDefinition, MCPCallToolResult } from './worker/mcp-provider';
export {
WIRE_VERSION,
type SerializedModelRequest,
type SerializedModelResponse,
type InvokeModelActivityInput,
type JsonValue,
} from './common/serialized-model';
export type { ModelActivityOptions, ModelSummaryProvider, AgentInputItem } from './common/model-activity-options';
export { DEFAULT_MODEL_ACTIVITY_OPTIONS } from './common/model-activity-options';
export { ToolSerializationError } from './workflow/tools';
export type { ActivityToolDefinition, ActivityAsToolOptions, JsonObjectSchema } from './workflow/tools';
export type { StatelessMcpServerOptions, TemporalMCPServer, MCPPromptDefinition } from './workflow/mcp-client';
export {
isInWorkflow,
isReplaying,
TemporalTracingProcessor,
ensureTracingProcessorRegistered,
} from './workflow/tracing';
export type { TemporalTracingProcessorOptions } from './workflow/tracing';
export type { TemporalOpenAIRunnerOptions } from './workflow/runner';

export * as testing from './worker/testing';
9 changes: 9 additions & 0 deletions packages/openai-agents/src/testing.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
export {
FakeModel,
FakeModelProvider,
textResponse,
toolCallResponse,
handoffResponse,
multiToolCallResponse,
ResponseBuilders,
} from './worker/testing';
Loading
Loading