@temporalio/agent-harness 0.1.0 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (88) hide show
  1. package/LICENSE +0 -0
  2. package/README.md +534 -5
  3. package/dist/src/ai-sdks/google-genai-plugin/index.d.ts +0 -0
  4. package/dist/src/ai-sdks/google-genai-plugin/index.js +0 -0
  5. package/dist/src/ai-sdks/google-genai-plugin/interactions-conversation.d.ts +0 -0
  6. package/dist/src/ai-sdks/google-genai-plugin/interactions-conversation.js +0 -0
  7. package/dist/src/ai-sdks/google-genai-plugin/interactions-models.d.ts +0 -0
  8. package/dist/src/ai-sdks/google-genai-plugin/interactions-models.js +0 -0
  9. package/dist/src/ai-sdks/google-genai-plugin/interactions-workflow.d.ts +0 -0
  10. package/dist/src/ai-sdks/google-genai-plugin/interactions-workflow.js +0 -0
  11. package/dist/src/ai-sdks/google-genai-plugin/temporal-async-client.d.ts +0 -0
  12. package/dist/src/ai-sdks/google-genai-plugin/temporal-async-client.js +0 -0
  13. package/dist/src/ai-sdks/google-genai-plugin/temporal-interactions.d.ts +0 -0
  14. package/dist/src/ai-sdks/google-genai-plugin/temporal-interactions.js +0 -0
  15. package/dist/src/ai-sdks/google-genai-plugin/workflow.d.ts +0 -0
  16. package/dist/src/ai-sdks/google-genai-plugin/workflow.js +0 -0
  17. package/dist/src/ai-sdks/jev/evaluator.d.ts +0 -0
  18. package/dist/src/ai-sdks/jev/evaluator.js +0 -0
  19. package/dist/src/ai-sdks/openai-agents-harness.d.ts +0 -0
  20. package/dist/src/ai-sdks/openai-agents-harness.js +0 -0
  21. package/dist/src/harness/agent-protocol/agent-interface.d.ts +11 -0
  22. package/dist/src/harness/agent-protocol/agent-interface.js +14 -0
  23. package/dist/src/harness/agent-protocol/events.d.ts +0 -0
  24. package/dist/src/harness/agent-protocol/events.js +0 -0
  25. package/dist/src/harness/agent-protocol/index.d.ts +0 -0
  26. package/dist/src/harness/agent-protocol/index.js +0 -0
  27. package/dist/src/harness/agent-protocol/schema.d.ts +0 -0
  28. package/dist/src/harness/agent-protocol/schema.js +0 -0
  29. package/dist/src/harness/agent-protocol/subagent-interface.d.ts +0 -0
  30. package/dist/src/harness/agent-protocol/subagent-interface.js +0 -0
  31. package/dist/src/harness/agent-schema.d.ts +0 -0
  32. package/dist/src/harness/agent-schema.js +0 -0
  33. package/dist/src/harness/agent-workflow/errors.d.ts +0 -0
  34. package/dist/src/harness/agent-workflow/errors.js +0 -0
  35. package/dist/src/harness/agent-workflow/types.d.ts +3 -0
  36. package/dist/src/harness/agent-workflow/types.js +0 -0
  37. package/dist/src/harness/agent-workflow.d.ts +12 -1
  38. package/dist/src/harness/agent-workflow.js +106 -35
  39. package/dist/src/harness/agent.d.ts +7 -0
  40. package/dist/src/harness/agent.js +8 -2
  41. package/dist/src/harness/code-mode/activity-fs.d.ts +0 -0
  42. package/dist/src/harness/code-mode/activity-fs.js +0 -0
  43. package/dist/src/harness/code-mode/base64.d.ts +0 -0
  44. package/dist/src/harness/code-mode/base64.js +0 -0
  45. package/dist/src/harness/code-mode/driver.d.ts +0 -0
  46. package/dist/src/harness/code-mode/driver.js +0 -0
  47. package/dist/src/harness/code-mode/index.d.ts +0 -0
  48. package/dist/src/harness/code-mode/index.js +0 -0
  49. package/dist/src/harness/code-mode/mount-decl.d.ts +0 -0
  50. package/dist/src/harness/code-mode/mount-decl.js +0 -0
  51. package/dist/src/harness/code-mode/okf-tool.d.ts +0 -0
  52. package/dist/src/harness/code-mode/okf-tool.js +0 -0
  53. package/dist/src/harness/code-mode/okf.d.ts +0 -0
  54. package/dist/src/harness/code-mode/okf.js +0 -0
  55. package/dist/src/harness/code-mode/stubs.d.ts +0 -0
  56. package/dist/src/harness/code-mode/stubs.js +0 -0
  57. package/dist/src/harness/code-mode/texts.d.ts +0 -0
  58. package/dist/src/harness/code-mode/texts.js +0 -0
  59. package/dist/src/harness/code-mode/tool.d.ts +0 -0
  60. package/dist/src/harness/code-mode/tool.js +0 -0
  61. package/dist/src/harness/code-mode/vfs.d.ts +0 -0
  62. package/dist/src/harness/code-mode/vfs.js +0 -0
  63. package/dist/src/harness/py-repr.d.ts +0 -0
  64. package/dist/src/harness/py-repr.js +0 -0
  65. package/dist/src/harness/state/index.d.ts +0 -0
  66. package/dist/src/harness/state/index.js +0 -0
  67. package/dist/src/harness/stream-context.d.ts +0 -0
  68. package/dist/src/harness/stream-context.js +0 -0
  69. package/dist/src/harness/subagent-toolset.d.ts +0 -0
  70. package/dist/src/harness/subagent-toolset.js +0 -0
  71. package/dist/src/index.d.ts +0 -0
  72. package/dist/src/index.js +0 -0
  73. package/dist/src/sandbox.d.ts +0 -0
  74. package/package.json +6 -4
  75. package/skills/temporal-harness-typescript/SKILL.md +42 -0
  76. package/skills/temporal-harness-typescript/agents/openai.yaml +4 -0
  77. package/skills/temporal-harness-typescript/assets/starter/README.md.tmpl +95 -0
  78. package/skills/temporal-harness-typescript/assets/starter/agents.toml.tmpl +7 -0
  79. package/skills/temporal-harness-typescript/assets/starter/agents.ts.tmpl +61 -0
  80. package/skills/temporal-harness-typescript/assets/starter/env.example.tmpl +3 -0
  81. package/skills/temporal-harness-typescript/assets/starter/gitignore.tmpl +6 -0
  82. package/skills/temporal-harness-typescript/assets/starter/package.json.tmpl +35 -0
  83. package/skills/temporal-harness-typescript/assets/starter/tsconfig.json.tmpl +13 -0
  84. package/skills/temporal-harness-typescript/assets/starter/worker.ts.tmpl +24 -0
  85. package/skills/temporal-harness-typescript/references/advanced.md +57 -0
  86. package/skills/temporal-harness-typescript/references/api.md +110 -0
  87. package/skills/temporal-harness-typescript/references/authoring.md +65 -0
  88. package/skills/temporal-harness-typescript/references/verification.md +17 -0
@@ -0,0 +1,61 @@
1
+ import { Agent, type AgentInputItem } from "@openai/agents-core";
2
+ import { z } from "zod";
3
+ import {
4
+ TextMessage,
5
+ TextReply,
6
+ ToolApprovalPolicy,
7
+ defineAgent,
8
+ handler,
9
+ tool,
10
+ } from "@temporalio/agent-harness";
11
+ import {
12
+ asOpenAIAgentTool,
13
+ runStreamed,
14
+ } from "@temporalio/agent-harness/ai-sdks/openai-agents-harness";
15
+
16
+ const getWeather = tool({
17
+ name: "get_weather",
18
+ description: "Return sample weather for a city.",
19
+ inputSchema: z.object({ city: z.string() }),
20
+ outputSchema: z.string(),
21
+ inherentlySafe: true,
22
+ execute: async ({ city }) => `It's 72°F and sunny in ${city}.`,
23
+ });
24
+
25
+ export const OpenAIHelloAgentTs = defineAgent({
26
+ name: "OpenAIHelloAgentTs",
27
+ approvalPolicyDefault: ToolApprovalPolicy.allowInherentlySafe(),
28
+ handlers: {
29
+ ping: handler({ description: "Check the worker without a model call.", input: TextMessage, output: TextReply }),
30
+ ask: handler({
31
+ description: "Chat with the assistant. Ask about the weather to try its tool.",
32
+ input: TextMessage,
33
+ output: TextReply,
34
+ }),
35
+ },
36
+ create: ({ runner }) => {
37
+ let conversation: AgentInputItem[] = [];
38
+ return {
39
+ async ping({ text }) { return { text }; },
40
+ async ask({ text }) {
41
+ const sdkAgent = new Agent({
42
+ name: "Hello",
43
+ instructions: "Answer briefly. For weather questions, call get_weather and explain that it returns sample data.",
44
+ model: "gpt-5.1",
45
+ tools: [asOpenAIAgentTool(runner, getWeather)],
46
+ });
47
+ const input: AgentInputItem[] = [...conversation, { role: "user", content: text }];
48
+ const result = await runStreamed(runner, sdkAgent, input, {
49
+ defaultModelParams: {
50
+ startToCloseTimeout: "2 minutes",
51
+ heartbeatTimeout: "30 seconds",
52
+ },
53
+ });
54
+ for await (const _event of result) void _event;
55
+ await result.completed;
56
+ conversation = result.history;
57
+ return { text: String(result.finalOutput) };
58
+ },
59
+ };
60
+ },
61
+ });
@@ -0,0 +1,3 @@
1
+ # Uncomment and set your key before trying `ask`; `ping` works without one.
2
+ # OPENAI_API_KEY=sk-...
3
+ # Export the same TEMPORAL_* settings in every service terminal when using a profile.
@@ -0,0 +1,6 @@
1
+ .env.local
2
+ .venv/
3
+ __pycache__/
4
+ *.egg-info/
5
+ node_modules/
6
+ dist/
@@ -0,0 +1,35 @@
1
+ {
2
+ "name": "__PROJECT_NAME__",
3
+ "private": true,
4
+ "type": "module",
5
+ "scripts": {
6
+ "build": "tsc -p tsconfig.json",
7
+ "schema": "npm run build && agent-harness schema ./dist/agents.js#OpenAIHelloAgentTs -o agent.schema.json",
8
+ "harness:dev": "uvx --from 'temporal-agent-harness[ui]==0.9.0' temporal-agent-harness dev agents.toml",
9
+ "start": "node --env-file-if-exists=.env.local dist/worker.js",
10
+ "harness:skill": "agent-harness skills install",
11
+ "harness:doctor": "agent-harness doctor --schema agent.schema.json"
12
+ },
13
+ "dependencies": {
14
+ "@temporalio/agent-harness": "__HARNESS_VERSION__",
15
+ "@temporalio/agent-harness-worker": "__HARNESS_VERSION__",
16
+ "@temporalio/agent-harness-client": "__HARNESS_VERSION__",
17
+ "@temporalio/activity": "1.24.0",
18
+ "@temporalio/client": "1.24.0",
19
+ "@temporalio/common": "1.24.0",
20
+ "@temporalio/envconfig": "1.24.0",
21
+ "@temporalio/plugin": "1.24.0",
22
+ "@temporalio/worker": "1.24.0",
23
+ "@temporalio/workflow": "1.24.0",
24
+ "@temporalio/workflow-streams": "1.24.0",
25
+ "@temporalio/openai-agents": "1.24.0",
26
+ "@openai/agents-core": "0.14.3",
27
+ "@openai/agents-openai": "0.14.3",
28
+ "openai": "6.46.0",
29
+ "zod": "4.6.5"
30
+ },
31
+ "devDependencies": {
32
+ "typescript": "7.0.2",
33
+ "@types/node": "22.20.4"
34
+ }
35
+ }
@@ -0,0 +1,13 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2023",
4
+ "module": "NodeNext",
5
+ "moduleResolution": "NodeNext",
6
+ "strict": true,
7
+ "skipLibCheck": true,
8
+ "types": ["node"],
9
+ "rootDir": ".",
10
+ "outDir": "dist"
11
+ },
12
+ "include": ["agents.ts", "worker.ts"]
13
+ }
@@ -0,0 +1,24 @@
1
+ import { fileURLToPath } from "node:url";
2
+ import { loadClientConnectConfig } from "@temporalio/envconfig";
3
+ import { NativeConnection, Worker } from "@temporalio/worker";
4
+ import { AgentHarnessPlugin } from "@temporalio/agent-harness-worker";
5
+ import { OpenAIAgentsPlugin } from "@temporalio/agent-harness-worker/ai-sdks/openai-agents";
6
+
7
+ // `ping` needs no model, so the worker starts without a key; only `ask` fails without one.
8
+ if (!process.env.OPENAI_API_KEY)
9
+ console.warn("OPENAI_API_KEY is not set: `ping` works, `ask` will fail until it is (see env.example)");
10
+
11
+ const { connectionOptions, namespace } = loadClientConnectConfig();
12
+ const connection = await NativeConnection.connect(connectionOptions);
13
+ try {
14
+ const worker = await Worker.create({
15
+ connection,
16
+ namespace: namespace ?? "default",
17
+ taskQueue: "openai-hello-ts",
18
+ workflowsPath: fileURLToPath(new URL("./agents.js", import.meta.url)),
19
+ plugins: [new OpenAIAgentsPlugin(), new AgentHarnessPlugin()],
20
+ });
21
+ await worker.run();
22
+ } finally {
23
+ await connection.close();
24
+ }
@@ -0,0 +1,57 @@
1
+ # Advanced TypeScript features
2
+
3
+ Read the installed package's public types and the agent's generated schema for exact signatures.
4
+ Prefer a small change to the working starter over copying internal runtime implementation.
5
+
6
+ - **Observable state:** declare state on the agent, initialize it through its schema, and mutate
7
+ through the provided state reference. Mutations publish patches; changing an unrelated local
8
+ object does not publish observable state. Keep mutation callbacks synchronous.
9
+ - **Approvals:** distinguish permission to run a tool from supplying a callback result. Preserve
10
+ the requesting agent and tool IDs, especially for subagents. See `api.md` for HTTP calls.
11
+ - **Callbacks:** the tool implementation runs on the client; model execution waits for a result.
12
+ Use the application client's callback handlers or pending callback interface.
13
+ - **Subagents:** expose typed handlers and compose through the harness subagent APIs. Follow
14
+ events using their agent identity rather than flattening the tree into the parent's transcript.
15
+ - **Code Mode:** requires the optional Monty sandbox dependency on the worker. Expose an explicit
16
+ toolset; scripts run against those host functions. Filesystem mounts and durable activity
17
+ filesystems have separate declarations and worker registrations.
18
+ - **Mid-turn handlers:** choose enqueue/accept/reject intentionally. Use `/api/messages` plus
19
+ `/api/attach` for clients that support messages joining an existing turn.
20
+
21
+ For complete worked examples matching a release, use the repository's release-tagged Monty and
22
+ OpenAI examples. A checkout is optional for normal application development. Do not assume Python
23
+ and TypeScript model integrations or advanced feature signatures are interchangeable.
24
+
25
+ ## Add observable state to the starter
26
+
27
+ Import `state` from `@temporalio/agent-harness`. Add a declaration to `defineAgent` and read its
28
+ reference from the `create` context:
29
+
30
+ ```ts
31
+ // Alongside handlers in defineAgent({...}):
32
+ states: { counter: state(z.object({ messages: z.number().int().default(0) })) },
33
+
34
+ // In create({ runner, state }), inside a handler:
35
+ state.counter.mutate(draft => { draft.messages += 1; });
36
+ ```
37
+
38
+ Read `state.counter.current` for the current value. Mutation callbacks must be synchronous.
39
+ Regenerate the agent schema; client codegen then exposes the `counter` state.
40
+
41
+ ## Choose a tool boundary
42
+
43
+ | Work | Public declaration | Registration |
44
+ | --- | --- | --- |
45
+ | Deterministic, fast computation | `tool({ ..., execute })` | Adapt through the model integration |
46
+ | External I/O, database or provider calls | `activityTool({ ..., activityOptions })` | `new AgentHarnessPlugin({ tools: [toolActivity(declaration, implementation)] })` on the worker |
47
+ | Browser/user environment | `tool({ ..., outputSchema })` without `execute` | Supply the result through the application client |
48
+
49
+ Declarations come from `@temporalio/agent-harness`; `toolActivity` comes from
50
+ `@temporalio/agent-harness-worker`. Keep implementations with Node/network imports out of the
51
+ workflow bundle. Set timeouts and make side effects idempotent across retries. `inherentlySafe`
52
+ is an explicit approval-policy decision. Use `injected<T>()` bindings for workflow-supplied
53
+ values that should stay out of model input schemas.
54
+
55
+ `subagentToolset` and `codeModeTool` are exported from the core package. Code Mode also needs
56
+ `@pydantic/monty` on the worker. Inspect their installed declarations for lifecycle, mounting,
57
+ and toolset options. Keep each child's registry, worker queue, and generated interface aligned.
@@ -0,0 +1,110 @@
1
+ # Harness API and session lifecycle
2
+
3
+ The shared Python server serves the same HTTP API and browser console for Python and TypeScript
4
+ agents. Run a Temporal service, session-manager worker, API server, and your agent worker with
5
+ the same connection and namespace. Worker task queues must match the registry.
6
+
7
+ ## Discover and start
8
+
9
+ `GET /api/agents` lists registered workflow types, init-data schemas, and worker poller status.
10
+ A poller indicates availability on a queue, not proof that it hosts a particular workflow type.
11
+ `GET /api/sessions` lists sessions. Create one using the **workflow type**, not the registry key:
12
+
13
+ ```bash
14
+ curl --fail-with-body http://localhost:8000/api/sessions \
15
+ -H 'Content-Type: application/json' \
16
+ -d '{"agent_workflow_type":"OpenAIHelloAgentTs"}'
17
+ ```
18
+
19
+ The response's `workflow_id` is the session ID used by subsequent calls. An optional `session_id`
20
+ lets an integration derive a stable ID from its own conversation identity; repeated creation
21
+ with the same ID is idempotent. Supply `data` when the agent requires init data. Do not send it
22
+ for an agent that takes none. The server checks presence and the agent validates its schema.
23
+ Read `GET /api/agent-interface/{session_id}` for handlers and their input/output schemas.
24
+
25
+ ## Send and observe separately
26
+
27
+ Use `POST /api/messages` for typed messages:
28
+
29
+ ```json
30
+ {
31
+ "session_id": "the-workflow-id",
32
+ "message": {"type": "ask", "payload": {"text": "What's the weather in Paris?"}},
33
+ "request_id": "stable-id-for-this-one-delivery"
34
+ }
35
+ ```
36
+
37
+ An accepted message may open a turn, join a running turn, or be queued. Acceptance is not
38
+ completion. Save the returned `message_id` and follow the event stream for its result. Reuse
39
+ `request_id` only when retrying the same delivery; distinct user messages need distinct IDs.
40
+
41
+ Attach with `GET /api/attach?session_id=...&from_offset=0` (URL-encode the ID). The response is
42
+ SSE (`text/event-stream`). Events carry JSON data, including `resume_offset` when available.
43
+ Save the last processed resume offset and pass it as `from_offset` on reconnect. Do not assume
44
+ browser `Last-Event-ID` is the resume mechanism. Read the event's handler/message/agent identity:
45
+ a session can contain queued messages, mid-turn handlers, and subagent events.
46
+
47
+ Use the published `@temporalio/agent-harness-client`, React, or Svelte clients when possible;
48
+ they implement stream/state handling. `POST /api/chat` is a convenience for a turn it opens;
49
+ use message submission plus attach for general application clients and mid-turn handlers.
50
+
51
+ ## Human interaction
52
+
53
+ `POST /api/approve` takes `session_id`, `tool_id`, `approved`, optional `reason`, and optional
54
+ `remember`. An approval authorizes the pending tool; it does not provide a callback result.
55
+
56
+ `POST /api/callback-result` takes `session_id`, `tool_id`, and `result` or `error`. A callback
57
+ executes in the client environment. Preserve the identity of the agent requesting it; a UI may
58
+ be answering a subagent's request. The client SDK handles routing across the agent tree.
59
+
60
+ ## State, status, and closing
61
+
62
+ Apply a state snapshot before its subsequent patches, in stream order. Use the SDK's state
63
+ implementation instead of treating every event as a complete state document.
64
+
65
+ - `GET /api/status/{session_id}`: current turn, pending work, and agent status.
66
+ - `GET /api/workflow-status/{workflow_id}`: execution status.
67
+ - `POST /api/sessions/{session_id}/close`: signal the agent to wind down and settle pending interactions.
68
+
69
+ Disconnecting an SSE stream does **not** close the agent. A network error is not evidence that
70
+ its workflow has ended. Reconnect; only treat an explicit not-found/closed result as terminal.
71
+
72
+ ## Errors and schemas
73
+
74
+ Check HTTP status before parsing a success response. Invalid init-data presence returns 422;
75
+ other errors may contain `error`/`message` or FastAPI's `detail`. Do not retry a rejected payload
76
+ unchanged. On a transport failure, retry a submission using its original request ID.
77
+
78
+ The running server exposes `/openapi.json` and `/docs`, generated from its route declarations.
79
+ To save the HTTP contract while the server is running:
80
+
81
+ ```bash
82
+ curl --fail-with-body http://localhost:8000/openapi.json -o openapi.json
83
+ ```
84
+
85
+ Generate an agent's schema from its declaration:
86
+
87
+ ```bash
88
+ # Python
89
+ temporal-agent-harness schema my_agent.workflow:OpenAIHelloAgentWorkflow -o agent.schema.json
90
+ # TypeScript: compile first (agent-harness-schema is the same command)
91
+ agent-harness schema ./dist/agents.js#OpenAIHelloAgentTs -o agent.schema.json
92
+ # Either schema can generate a typed application client
93
+ harness-codegen agent.schema.json -o Agent.ts
94
+ ```
95
+
96
+ The code generator is distributed as `@temporalio/agent-harness-codegen`. Regenerate and commit
97
+ client types after changing handlers, state, or init data. Never patch generated types manually.
98
+
99
+ ## Registry and deployment
100
+
101
+ `agents.toml` declares a key, workflow type, task queue, label, description, and optional schema
102
+ path relative to the TOML file. Keep the schema's agent name equal to `workflow_type`. The server
103
+ never imports your agent implementation. The session manager caches its registry: replacing the
104
+ registry file alone does not update an already-running manager's list. Restart with fresh local
105
+ Temporal state only when the development sessions are disposable.
106
+
107
+ The built-in local payload store is for processes sharing a host/filesystem. For a multi-host
108
+ deployment, configure a shared offload store consistently across clients, workers, and server.
109
+ Expose the API through your application's authentication boundary when deploying beyond local
110
+ development. Embedding the FastAPI app lets you add your own middleware and routes.
@@ -0,0 +1,65 @@
1
+ # TypeScript authoring
2
+
3
+ Use `@temporalio/agent-harness` in workflow modules and `@temporalio/agent-harness-worker` on the
4
+ Node worker. `npx agent-harness init ./my-agent` materializes a runnable OpenAI starter. The same
5
+ starter is installed with this skill under `assets/starter/`; read `agents.ts.tmpl` and
6
+ `worker.ts.tmpl` there for the complete wiring. Its exact Temporal SDK versions match the model
7
+ plugin; keep those versions aligned. Harness package versions are separate from the underlying
8
+ Temporal SDK versions. Compile ESM before starting.
9
+
10
+ A minimal agent, with a safe inline tool and a model-free handler:
11
+
12
+ ```ts
13
+ import { z } from "zod";
14
+ import { TextMessage, TextReply, ToolApprovalPolicy, defineAgent, handler, tool } from "@temporalio/agent-harness";
15
+
16
+ export const getWeather = tool({
17
+ name: "get_weather",
18
+ description: "Return sample weather for a city.",
19
+ inputSchema: z.object({ city: z.string() }),
20
+ outputSchema: z.string(),
21
+ inherentlySafe: true,
22
+ execute: async ({ city }) => `It's 72°F and sunny in ${city}.`,
23
+ });
24
+
25
+ export const HelloAgent = defineAgent({
26
+ name: "HelloAgent",
27
+ approvalPolicyDefault: ToolApprovalPolicy.allowInherentlySafe(),
28
+ handlers: {
29
+ ping: handler({ description: "Echo without a model call.", input: TextMessage, output: TextReply }),
30
+ },
31
+ create: ({ runner }) => ({
32
+ async ping({ text }) {
33
+ return { text };
34
+ },
35
+ }),
36
+ });
37
+ ```
38
+
39
+ The starter's `ask` handler adds the model turn: it passes `getWeather` through
40
+ `asOpenAIAgentTool(runner, ...)` and awaits `runStreamed(runner, sdkAgent, input, ...)`.
41
+
42
+ Public authoring imports come from `@temporalio/agent-harness`: `defineAgent`, `handler`, `tool`,
43
+ `state`, `TextMessage`, `TextReply`, and `ToolApprovalPolicy`. Use Zod schemas for inputs and
44
+ outputs. `defineAgent({ name, handlers, create })` returns the workflow export; `create` receives
45
+ its runner, init data, and declared state references. Keep Node imports and external I/O in the
46
+ worker or activities, not in the workflow module.
47
+
48
+ Use `ToolApprovalPolicy.allowInherentlySafe()` for tools explicitly marked `inherentlySafe`.
49
+ For OpenAI, import `asOpenAIAgentTool` and `runStreamed` from
50
+ `@temporalio/agent-harness/ai-sdks/openai-agents-harness`. Consume the stream and await completion.
51
+ Keep conversation history inside the agent instance. The worker's `OpenAIAgentsPlugin` comes from
52
+ `@temporalio/agent-harness-worker/ai-sdks/openai-agents`, followed by `AgentHarnessPlugin`.
53
+ Activity tool implementations are registered using `toolActivity` on the harness plugin.
54
+
55
+ Point `workflowsPath` at the compiled agent module. Generate its schema with
56
+ `agent-harness schema ./dist/agents.js#Export -o Agent.schema.json` (the `agent-harness-schema`
57
+ binary is the same command). The registry's `workflow_type`
58
+ must match `defineAgent`'s `name`, and its queue must match the worker. The schema CLI does not
59
+ start Temporal. The shared Python server reads the schema without importing TypeScript code.
60
+
61
+ The shared services come from the Python package: the starter's `npm run harness:dev` runs
62
+ `temporal-agent-harness dev agents.toml` through `uvx`, beside Temporal and the Node worker.
63
+ `npx agent-harness doctor --schema Agent.schema.json` checks the installed package, schema, API,
64
+ and agent worker availability. For direct Temporal connection and local TOML validation, use the
65
+ shared Python CLI's `doctor --registry agents.toml`. Both support `--json` and never reset services.
@@ -0,0 +1,17 @@
1
+ # Verification and troubleshooting
2
+
3
+ Validate against the installed SDK version. Run the starter's schema command before launching
4
+ services. A successful check includes discovering the agent, creating a session, sending a typed
5
+ message, seeing a tool result and completed reply, and reconnecting to the same session.
6
+ Use a scripted model for repeatable automated tests; do not claim a scripted response is a live
7
+ provider test. Test approval/callback paths separately when your agent uses them.
8
+
9
+ If the console loads but cannot start a session, check the session-manager worker. If a session
10
+ exists but messages stall, check the agent worker, task queue, and namespace. If a model fails,
11
+ check the worker's provider credentials and optional integration dependencies. If registration
12
+ changes appear stale, inspect the session manager's cached registry before replacing local state.
13
+
14
+ Keep the Temporal server, namespace, and task queues isolated for tests. Do not terminate unrelated
15
+ sessions or reset a user's existing development server to make a test pass. Temporal workflow code
16
+ must remain deterministic; move external I/O into activities. Replaying a completed activity uses
17
+ its recorded result, but retryable activities with side effects still need idempotent design.