temporal-agent-harness 0.3.0__tar.gz
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.
- temporal_agent_harness-0.3.0/LICENSE +21 -0
- temporal_agent_harness-0.3.0/PKG-INFO +566 -0
- temporal_agent_harness-0.3.0/README.md +523 -0
- temporal_agent_harness-0.3.0/pyproject.toml +165 -0
- temporal_agent_harness-0.3.0/setup.cfg +4 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/__init__.py +15 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/__init__.py +11 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/google_genai_plugin/__init__.py +67 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/google_genai_plugin/_gemini_activity.py +235 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/google_genai_plugin/_google_genai_plugin.py +98 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/google_genai_plugin/_interactions_activity.py +411 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/google_genai_plugin/_interactions_models.py +31 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/google_genai_plugin/_interactions_workflow.py +56 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/google_genai_plugin/_models.py +121 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/google_genai_plugin/_temporal_api_client.py +292 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/google_genai_plugin/_temporal_async_client.py +64 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/google_genai_plugin/_temporal_file_search_stores.py +109 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/google_genai_plugin/_temporal_files.py +169 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/google_genai_plugin/_temporal_interactions.py +143 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/google_genai_plugin/workflow.py +96 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/integration_helpers/__init__.py +33 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/integration_helpers/_stream_observer.py +170 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/openai_agents/__init__.py +33 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/openai_agents/_heartbeat_decorator.py +38 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/openai_agents/_invoke_model_activity.py +451 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/openai_agents/_mcp.py +537 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/openai_agents/_model_parameters.py +127 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/openai_agents/_nexus_mcp.py +194 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/openai_agents/_openai_runner.py +378 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/openai_agents/_otel_trace_interceptor.py +88 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/openai_agents/_temporal_model_stub.py +317 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/openai_agents/_temporal_openai_agents.py +426 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/openai_agents/_temporal_trace_provider.py +211 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/openai_agents/_trace_interceptor.py +445 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/openai_agents/sandbox/__init__.py +1 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/openai_agents/sandbox/_sandbox_client_provider.py +285 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/openai_agents/sandbox/_temporal_activity_models.py +218 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/openai_agents/sandbox/_temporal_sandbox_client.py +124 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/openai_agents/sandbox/_temporal_sandbox_session.py +239 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/openai_agents/testing.py +262 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/openai_agents/workflow.py +435 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/openai_agents_harness.py +512 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ai_sdks/pydantic_ai_harness.py +512 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/harness/__init__.py +18 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/harness/agent.py +78 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/harness/agent_client.py +650 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/harness/agent_protocol/__init__.py +166 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/harness/agent_protocol/agent_interface.py +553 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/harness/agent_protocol/events.py +896 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/harness/agent_protocol/subagent_interface.py +103 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/harness/agent_workflow.py +2904 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/harness/code_mode/__init__.py +30 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/harness/code_mode/activities.py +123 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/harness/code_mode/batch_models.py +84 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/harness/code_mode/driver.py +203 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/harness/code_mode/monty_stepper.py +176 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/harness/code_mode/stubs.py +325 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/harness/code_mode/tool.py +197 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/harness/slash_commands.py +378 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/harness/stream_context.py +30 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/harness/stream_merge/__init__.py +32 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/harness/stream_merge/cursor.py +166 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/harness/stream_merge/gates.py +148 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/harness/stream_merge/merge.py +494 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/harness/subagent_activities.py +317 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/harness/subagent_toolset.py +203 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/nexus_agent_adapter/__init__.py +0 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/nexus_agent_adapter/generated/__init__.py +65 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/nexus_agent_adapter/generated/_definitions.py +514 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/nexus_agent_adapter/generated/models.py +2192 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/nexus_agent_adapter/generated/services.py +101 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/nexus_agent_adapter/handler.py +369 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/nexus_agent_adapter/worker.py +72 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/plugin.py +255 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ui/__init__.py +12 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ui/dist/assets/index-CSosuMGP.js +53 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ui/dist/assets/index-DNXWrDgV.css +1 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ui/dist/index.html +13 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/ui/dist/temporal-logo.svg +3 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/utils/__init__.py +6 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/utils/large_payload.py +227 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/web/__init__.py +50 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/web/app.py +682 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/web/cli.py +173 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/web/client.py +87 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/web/registry.py +82 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/web/serve.py +66 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/web/session_manager.py +124 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/web/session_manager_worker.py +90 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness/web/task_queue_status.py +158 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness.egg-info/PKG-INFO +566 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness.egg-info/SOURCES.txt +94 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness.egg-info/dependency_links.txt +1 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness.egg-info/entry_points.txt +2 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness.egg-info/requires.txt +31 -0
- temporal_agent_harness-0.3.0/temporal_agent_harness.egg-info/top_level.txt +1 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Temporal Technologies Inc. All rights reserved.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,566 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: temporal-agent-harness
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Temporal-native agent harness (experimental) — durable agents on Temporal, with the AI SDKs you already use.
|
|
5
|
+
Author: Temporal Technologies Inc.
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/temporal-community/temporal-agent-harness
|
|
8
|
+
Project-URL: Repository, https://github.com/temporal-community/temporal-agent-harness
|
|
9
|
+
Project-URL: Issues, https://github.com/temporal-community/temporal-agent-harness/issues
|
|
10
|
+
Project-URL: Changelog, https://github.com/temporal-community/temporal-agent-harness/releases
|
|
11
|
+
Keywords: temporal,workflow,agents,harness,llm,ai
|
|
12
|
+
Classifier: Development Status :: 2 - Pre-Alpha
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
17
|
+
Requires-Python: >=3.11
|
|
18
|
+
Description-Content-Type: text/markdown
|
|
19
|
+
License-File: LICENSE
|
|
20
|
+
Requires-Dist: temporalio>=1.31.0
|
|
21
|
+
Requires-Dist: pydantic>=2.0
|
|
22
|
+
Provides-Extra: genai
|
|
23
|
+
Requires-Dist: google-genai>=2.0.0; extra == "genai"
|
|
24
|
+
Requires-Dist: google-auth>=2.53.0; extra == "genai"
|
|
25
|
+
Provides-Extra: s3
|
|
26
|
+
Requires-Dist: temporalio[aioboto3]>=1.31.0; extra == "s3"
|
|
27
|
+
Provides-Extra: openai-agents
|
|
28
|
+
Requires-Dist: openai-agents>=0.22.0; extra == "openai-agents"
|
|
29
|
+
Requires-Dist: mcp<3,>=2.1.1; extra == "openai-agents"
|
|
30
|
+
Requires-Dist: temporalio[opentelemetry]>=1.31.0; extra == "openai-agents"
|
|
31
|
+
Provides-Extra: pydantic-ai
|
|
32
|
+
Requires-Dist: pydantic-ai-slim[temporal]>=2.13; extra == "pydantic-ai"
|
|
33
|
+
Provides-Extra: ui
|
|
34
|
+
Requires-Dist: fastapi[standard]>=0.136.3; extra == "ui"
|
|
35
|
+
Provides-Extra: code-mode
|
|
36
|
+
Requires-Dist: pydantic-monty==0.0.18; extra == "code-mode"
|
|
37
|
+
Provides-Extra: nexus-mcp
|
|
38
|
+
Requires-Dist: temporal-nexus-mcp; python_version >= "3.13" and extra == "nexus-mcp"
|
|
39
|
+
Requires-Dist: openai-agents>=0.22.0; extra == "nexus-mcp"
|
|
40
|
+
Requires-Dist: mcp<3,>=2.1.1; extra == "nexus-mcp"
|
|
41
|
+
Requires-Dist: temporalio[opentelemetry]>=1.31.0; extra == "nexus-mcp"
|
|
42
|
+
Dynamic: license-file
|
|
43
|
+
|
|
44
|
+
# Temporal Agent Harness
|
|
45
|
+
|
|
46
|
+
**Build durable, composable AI agents with a rich tool-approval policy engine that can seamlessly elevate to a human with built-in human-in-the-loop.**
|
|
47
|
+
|
|
48
|
+
> ⚠️ **Experimental.** An early, fast-moving project from Temporal Technologies. APIs will change.
|
|
49
|
+
|
|
50
|
+
The Temporal Agent Harness gives your agents capabilities that are painful and error-prone to
|
|
51
|
+
build yourself:
|
|
52
|
+
|
|
53
|
+
- agents **survive crashes and resume mid-turn**, exactly where they left off (no wasted tokens!);
|
|
54
|
+
- a **rich tool-approval policy engine** decides exactly when a tool call needs human
|
|
55
|
+
sign-off — handing control to a human only then, and resuming the moment it's granted —
|
|
56
|
+
- agents **compose programmatically**, through real typed contracts (not limited to just text in,
|
|
57
|
+
text out);
|
|
58
|
+
- **Code Mode** — one tool that runs a Python script over your toolset — so a single
|
|
59
|
+
turn orchestrates many tool calls with real control flow and concurrency;
|
|
60
|
+
- **callback tools** let an agent invoke a tool that runs on the *client* — reading a file on a
|
|
61
|
+
user's laptop, capturing a photo on their phone — even though the agent runs on a remote worker;
|
|
62
|
+
- agents are **fully observable** — a standardized, full-lifecycle event stream lets you watch them
|
|
63
|
+
live or replay exactly what they did;
|
|
64
|
+
|
|
65
|
+
all while you write the actual turn logic with the **AI SDKs you already know**.
|
|
66
|
+
|
|
67
|
+
Every agent is a durable Temporal workflow at its core, giving agents access to the full breadth
|
|
68
|
+
of Temporal primitives. Tools as activities or workflow functions, every turn a streamed,
|
|
69
|
+
replayable history. The harness packages those primitives into a toolkit built for first-class
|
|
70
|
+
agent development, so you get the power without hand-rolling the orchestration.
|
|
71
|
+
|
|
72
|
+
## Installation
|
|
73
|
+
|
|
74
|
+
There are two ways in, depending on what you want to do. Both pin to a **tagged release** —
|
|
75
|
+
see [Versioning and stability](#versioning-and-stability) for why that matters.
|
|
76
|
+
|
|
77
|
+
### Try it — run the example agents
|
|
78
|
+
|
|
79
|
+
Clone at a release tag. No Node/pnpm needed: the browser UI ships prebuilt.
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
git clone --branch 0.3.0 https://github.com/temporal-community/temporal-agent-harness.git
|
|
83
|
+
cd temporal-agent-harness
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
Git will note that you're in "detached HEAD" — that's expected, it just means you're sitting on
|
|
87
|
+
the tag rather than on a branch. Later, move to a newer release with
|
|
88
|
+
`git fetch --tags && git checkout <version>`, or see what changed between two of them with
|
|
89
|
+
`git diff 0.1.0 0.2.0`.
|
|
90
|
+
|
|
91
|
+
Then jump to [Run the examples](#run-the-examples). You'll need
|
|
92
|
+
[uv](https://docs.astral.sh/uv/), [just](https://just.systems/), and the Temporal cli (or Temporal Cloud).
|
|
93
|
+
|
|
94
|
+
### Build with it — add the harness to your own project
|
|
95
|
+
|
|
96
|
+
Add it as a **git dependency pinned to a tag**. In a [`uv`](https://docs.astral.sh/uv/)-managed
|
|
97
|
+
project:
|
|
98
|
+
|
|
99
|
+
```bash
|
|
100
|
+
# core harness — define and run agent workflows
|
|
101
|
+
uv add "temporal-agent-harness @ git+https://github.com/temporal-community/temporal-agent-harness.git@0.3.0"
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
Or declare it in `pyproject.toml` — depend on the package (with any extras you need) and point
|
|
105
|
+
its source at the tag:
|
|
106
|
+
|
|
107
|
+
```toml
|
|
108
|
+
[project]
|
|
109
|
+
dependencies = [
|
|
110
|
+
"temporal-agent-harness[ui]",
|
|
111
|
+
]
|
|
112
|
+
|
|
113
|
+
[tool.uv.sources]
|
|
114
|
+
temporal-agent-harness = { git = "https://github.com/temporal-community/temporal-agent-harness.git", tag = "0.3.0" }
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
Then run `uv sync`.
|
|
118
|
+
|
|
119
|
+
**Extras:**
|
|
120
|
+
|
|
121
|
+
- **`ui`** — the reusable FastAPI server and packaged browser UI (pulls in `fastapi[standard]`,
|
|
122
|
+
including Uvicorn). The built Svelte assets are always in the artifact; only the server runtime
|
|
123
|
+
dependencies are gated behind this extra, so core agent-worker installs stay smaller.
|
|
124
|
+
- **`code-mode`** — for workers that host **Code Mode** agents; pulls in
|
|
125
|
+
[`pydantic-monty`](https://pypi.org/project/pydantic-monty/), the sandbox the scripts run in.
|
|
126
|
+
(The workflow-side `agent.code_mode_tool` factory itself needs nothing extra, so importing it
|
|
127
|
+
never requires this dependency.)
|
|
128
|
+
|
|
129
|
+
Combine extras in the dependency spec, e.g. `"temporal-agent-harness[ui,code-mode]"`.
|
|
130
|
+
|
|
131
|
+
Agent authors use the harness runtime from `temporal_agent_harness.harness`. Applications that
|
|
132
|
+
want the built-in session manager and UI use `temporal_agent_harness.web`:
|
|
133
|
+
|
|
134
|
+
```python
|
|
135
|
+
from temporalio.client import Client
|
|
136
|
+
from temporalio.envconfig import ClientConfig
|
|
137
|
+
|
|
138
|
+
from temporal_agent_harness.plugin import AgentHarnessPlugin
|
|
139
|
+
from temporal_agent_harness.web import (
|
|
140
|
+
create_agent_harness_app,
|
|
141
|
+
create_session_manager_worker,
|
|
142
|
+
)
|
|
143
|
+
|
|
144
|
+
|
|
145
|
+
async def run_session_manager() -> None:
|
|
146
|
+
connect_config = ClientConfig.load_client_connect_config()
|
|
147
|
+
client = await Client.connect(**connect_config, plugins=[AgentHarnessPlugin()])
|
|
148
|
+
worker = create_session_manager_worker(client)
|
|
149
|
+
await worker.run()
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
app = create_agent_harness_app(registry_path="agents.toml")
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
Then serve the app with Uvicorn:
|
|
156
|
+
|
|
157
|
+
```bash
|
|
158
|
+
uvicorn my_app.web:app --host 0.0.0.0 --port 8000
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
The registry lists the launchable agents the UI can create:
|
|
162
|
+
|
|
163
|
+
```toml
|
|
164
|
+
[[agents]]
|
|
165
|
+
key = "my-agent"
|
|
166
|
+
workflow_type = "MyAgent"
|
|
167
|
+
task_queue = "my-agent-task-queue"
|
|
168
|
+
label = "My Agent"
|
|
169
|
+
description = "A short description shown in the UI."
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
The app factory serves both `/api/*` and the packaged Svelte UI. The helper
|
|
173
|
+
`create_session_manager_worker` only registers the packaged session-manager
|
|
174
|
+
workflow; run your own agent workflows on their own workers and task queues.
|
|
175
|
+
|
|
176
|
+
## Versioning and stability
|
|
177
|
+
|
|
178
|
+
**Install from a tagged release.** Every release is listed on the
|
|
179
|
+
[releases page](https://github.com/temporal-community/temporal-agent-harness/releases), and each
|
|
180
|
+
tag marks a commit that is known-good at the moment it was cut: the tests passed, and the
|
|
181
|
+
prebuilt browser UI matches the source it was built from.
|
|
182
|
+
|
|
183
|
+
**This project is very early and experimental - `main` may break at any time.**
|
|
184
|
+
|
|
185
|
+
Releases are cut manually, when the maintainers judge the state stable. This project is
|
|
186
|
+
**experimental** and pre-1.0: APIs will change between releases, without warning. Pinning to a
|
|
187
|
+
tag is what keeps that churn from reaching you unannounced — so pin, and upgrade deliberately
|
|
188
|
+
when you want to try out new harness capabilities.
|
|
189
|
+
|
|
190
|
+
## What you get
|
|
191
|
+
|
|
192
|
+
### 🛡️ Durable execution — the foundation
|
|
193
|
+
Every agent is a Temporal workflow, so durability isn't a feature you add, it's the ground you
|
|
194
|
+
build on. A worker can crash, redeploy, or restart mid-turn and the agent resumes precisely where
|
|
195
|
+
it was — no lost state, no double-run tool calls. Model and tool calls retry by policy; an agent
|
|
196
|
+
can wait minutes or days for an external event without holding a process open; and every turn,
|
|
197
|
+
tool call, and decision is recorded and replayable.
|
|
198
|
+
|
|
199
|
+
### 📊 Standardized agents, fully observable
|
|
200
|
+
The interface to agents built on this harness is **carefully standardized**. Every agent takes the
|
|
201
|
+
same configuration contract and emits the same structured **event stream**: a protocol (under
|
|
202
|
+
active development) that captures an agent's entire lifecycle — every turn, model interaction, tool
|
|
203
|
+
call (start / end / error), reply token, citation, approval decision, subagent hand-off, and
|
|
204
|
+
token-usage tally.
|
|
205
|
+
|
|
206
|
+
That one standardized stream is the foundation of **observability and analytics** for every agent
|
|
207
|
+
you build. **Watch an agent live** as it works, or **replay exactly what happened** afterward —
|
|
208
|
+
what it decided, which tools it ran, what it cost, and where a human stepped in. You instrument
|
|
209
|
+
once; every agent on the harness gets it.
|
|
210
|
+
|
|
211
|
+
### 🙋 Human-in-the-loop, solved
|
|
212
|
+
Tool approvals are built in and **safe-by-default**: any tool call can require human sign-off, and
|
|
213
|
+
a gated call **pauses inside the workflow and resumes durably** whenever a decision arrives (no
|
|
214
|
+
matter how long that takes) — there's no approval queue, state machine, or callback plumbing for
|
|
215
|
+
you to build. The policy engine is sophisticated out of the box: layered rules, inherently-safe
|
|
216
|
+
auto-approval, per-tool allow-lists, "approve and stop asking," per-session overrides, runtime
|
|
217
|
+
policy updates, and custom predicates.
|
|
218
|
+
|
|
219
|
+
### 🔌 Bring your own AI SDK
|
|
220
|
+
Write turn logic with the SDK you already know. The harness's integrations turn each SDK call into
|
|
221
|
+
a durable Temporal activity — so retries and credentials never leak into your workflow code.
|
|
222
|
+
Support is growing across the Python AI SDKs and agent frameworks Temporal integrates with:
|
|
223
|
+
|
|
224
|
+
| AI SDK | Status | Notes |
|
|
225
|
+
| --- | --- | --- |
|
|
226
|
+
| [Google Gemini](temporal_agent_harness/ai_sdks/google_genai_plugin) | ✅ Available now | Ships in this repo and is **experimental** - [Python SDK](https://github.com/temporalio/sdk-python) has a fully-supported non-harness integration. |
|
|
227
|
+
| [OpenAI Agents SDK](temporal_agent_harness/ai_sdks/openai_agents) | ✅ Available now | Ships in this repo and is **experimental** - [Python SDK](https://github.com/temporalio/sdk-python) has a fully-supported non-harness integration. |
|
|
228
|
+
| [Pydantic AI](temporal_agent_harness/ai_sdks/pydantic_ai_harness.py) | ✅ Available now | Directly uses Pydantic's Temporal plugin |
|
|
229
|
+
| [Google ADK](https://adk.dev/integrations/temporal/) | 🟡 Planned | - |
|
|
230
|
+
| [Strands Agents](https://docs.temporal.io/develop/python/integrations/strands-agents) | 🟡 Planned | - |
|
|
231
|
+
| [LangGraph](https://docs.temporal.io/develop/python/integrations/langgraph) | 🟡 Planned | - |
|
|
232
|
+
|
|
233
|
+
### 📡 Durable and inline tools
|
|
234
|
+
Tools come in two on-worker flavors — durable, activity-backed tools (`@agent.activity_tool_defn`)
|
|
235
|
+
that run as retried, observable Temporal activities, and inline workflow tools
|
|
236
|
+
(`@agent.tool_defn`). Each publishes its own start/end lifecycle events onto the agent's
|
|
237
|
+
standardized event stream. (A third flavor — **callback tools** — runs on an attached client
|
|
238
|
+
instead of the worker; see below.)
|
|
239
|
+
|
|
240
|
+
### 📞 Callback tools — let the client run the tool
|
|
241
|
+
An agent running on a Temporal worker often needs to act somewhere it can't reach — a file on the
|
|
242
|
+
user's laptop, a photo from their phone, a device on a private network. A **callback tool**
|
|
243
|
+
(`@agent.callback_tool_defn`) has no worker-side body: the agent **pauses inside the workflow**,
|
|
244
|
+
publishes the call, and an **attached client executes it on its own machine** and sends the result
|
|
245
|
+
back. You declare only the tool's typed contract (its `...` body is enforced) — the harness
|
|
246
|
+
supplies the single generic implementation. Because it's dispatched like any other tool, a callback
|
|
247
|
+
tool inherits the *same* approval policy, `tool_start`/`tool_end` events, and durable pause/resume:
|
|
248
|
+
the workflow simply waits (seconds or days) until a result arrives, and that result is validated
|
|
249
|
+
against the tool's declared output type before the turn continues. See
|
|
250
|
+
[`examples/callback_tools/wiki_agent`](examples/callback_tools/wiki_agent) — a cloud-shaped agent
|
|
251
|
+
that organizes a Markdown wiki on *your* local disk through a thin terminal client.
|
|
252
|
+
|
|
253
|
+
### 🧩 Agents that are more than chatbots
|
|
254
|
+
Most frameworks treat an agent as a single text-in / text-out function. Here, an agent exposes a
|
|
255
|
+
**strongly-typed interface**: declare named operations with `@agent.accepts` over pydantic models
|
|
256
|
+
(plain text is just one shape). The agent **advertises its own callable surface** — operation
|
|
257
|
+
names and input/output schemas — so it's self-describing and ready to be driven programmatically,
|
|
258
|
+
by your code or by another agent.
|
|
259
|
+
|
|
260
|
+
### 🔗 Composable by construction
|
|
261
|
+
Because agents have typed, self-describing interfaces, any harness agent can become a
|
|
262
|
+
**strongly-typed toolset** another agent drives — start it, call its operations, stop it.
|
|
263
|
+
Multi-agent systems compose through real contracts, not strings pasted between prompts.
|
|
264
|
+
|
|
265
|
+
### 🧑💻 Code Mode — give the model code, not just a call menu
|
|
266
|
+
Hand a model **one tool that runs a Python script** over your existing tools, instead of a long
|
|
267
|
+
menu of individual calls. `agent.code_mode_tool([...tools...])` turns any set of harness tools
|
|
268
|
+
into a single run-a-script tool: the model writes Python that calls them as async host functions,
|
|
269
|
+
with real control flow — loops, conditionals, `min`/`max`, and `asyncio.gather` concurrency — so
|
|
270
|
+
one turn orchestrates many calls. Each host call is still dispatched through the runner as a
|
|
271
|
+
durable, approval-gated, observable activity, and the script is statically type-checked against
|
|
272
|
+
your tools' signatures **before it runs**. And since a subagent toolset is just a list of tools,
|
|
273
|
+
Code Mode composes over subagents for free.
|
|
274
|
+
|
|
275
|
+
|
|
276
|
+
## A taste
|
|
277
|
+
|
|
278
|
+
```python
|
|
279
|
+
from datetime import timedelta
|
|
280
|
+
|
|
281
|
+
from pydantic import BaseModel
|
|
282
|
+
from temporalio import workflow
|
|
283
|
+
from temporalio.contrib.workflow_streams import WorkflowStream
|
|
284
|
+
from temporalio.workflow import ActivityConfig
|
|
285
|
+
|
|
286
|
+
from temporal_agent_harness.harness import AgentWorkflowRunner, agent, slash_commands
|
|
287
|
+
from temporal_agent_harness.harness.agent_protocol import AgentConfig, ToolApprovalPolicy
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
# A durable, activity-backed tool: runs as a retried, observable Temporal activity and
|
|
291
|
+
# publishes its own tool_start/tool_end events on the turn stream.
|
|
292
|
+
@agent.activity_tool_defn(
|
|
293
|
+
activity_config=ActivityConfig(start_to_close_timeout=timedelta(seconds=30)),
|
|
294
|
+
)
|
|
295
|
+
async def search_flights(origin: str, destination: str, date: str) -> str:
|
|
296
|
+
...
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
# Strongly-typed messages — an agent operation is more than a string in and a string out.
|
|
300
|
+
class PlanTrip(BaseModel):
|
|
301
|
+
destination: str
|
|
302
|
+
nights: int
|
|
303
|
+
|
|
304
|
+
|
|
305
|
+
class Itinerary(BaseModel):
|
|
306
|
+
summary: str
|
|
307
|
+
total_usd: float
|
|
308
|
+
|
|
309
|
+
|
|
310
|
+
@agent.defn
|
|
311
|
+
class TravelAgent:
|
|
312
|
+
@workflow.init
|
|
313
|
+
def __init__(self, config: AgentConfig) -> None:
|
|
314
|
+
# Tool approvals are safe-by-default; here, auto-approve only tools that
|
|
315
|
+
# statically declare themselves inherently safe.
|
|
316
|
+
self._runner = AgentWorkflowRunner(
|
|
317
|
+
config,
|
|
318
|
+
stream=WorkflowStream(),
|
|
319
|
+
approval_policy_default=ToolApprovalPolicy.allow_inherently_safe(),
|
|
320
|
+
slash_commands=slash_commands.default_commands(),
|
|
321
|
+
)
|
|
322
|
+
|
|
323
|
+
@workflow.run
|
|
324
|
+
async def run(self, config: AgentConfig) -> None:
|
|
325
|
+
await self._runner.run(self)
|
|
326
|
+
|
|
327
|
+
# A typed, self-describing operation. The agent advertises this signature, so callers —
|
|
328
|
+
# your code or another agent — can drive it programmatically. Your turn logic goes here:
|
|
329
|
+
# call your AI SDK, run tools through the runner, and return the typed reply.
|
|
330
|
+
# (See examples/monty for a complete, model-in-the-loop agent on the Gemini integration.)
|
|
331
|
+
@agent.accepts
|
|
332
|
+
async def plan_trip(self, request: PlanTrip) -> Itinerary:
|
|
333
|
+
...
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
## Running a worker — one plugin
|
|
337
|
+
|
|
338
|
+
An agent is a Temporal workflow, so it runs on a Temporal worker. `AgentHarnessPlugin` is the
|
|
339
|
+
single registration that wires that worker (and its client) for the harness — you never
|
|
340
|
+
assemble the harness's activity list or its data converter by hand:
|
|
341
|
+
|
|
342
|
+
```python
|
|
343
|
+
from temporalio.client import Client
|
|
344
|
+
from temporalio.envconfig import ClientConfig
|
|
345
|
+
from temporalio.worker import Worker
|
|
346
|
+
|
|
347
|
+
from temporal_agent_harness.plugin import AgentHarnessPlugin
|
|
348
|
+
|
|
349
|
+
client = await Client.connect(
|
|
350
|
+
**ClientConfig.load_client_connect_config(),
|
|
351
|
+
# Your AI SDK's plugin first, the harness plugin last.
|
|
352
|
+
plugins=[OpenAIAgentsPlugin(model_params=...), AgentHarnessPlugin(tools=MY_TOOLS)],
|
|
353
|
+
)
|
|
354
|
+
|
|
355
|
+
worker = Worker(client, task_queue="my-agent", workflows=[TravelAgent])
|
|
356
|
+
await worker.run()
|
|
357
|
+
```
|
|
358
|
+
|
|
359
|
+
The worker declares only its workflows. Adding the plugin brings:
|
|
360
|
+
|
|
361
|
+
- the harness's **data converter** (Pydantic + large-payload offload) — add the plugin to every
|
|
362
|
+
client, worker, and server in the deployment so they all agree on it;
|
|
363
|
+
- the durable **activity body** of each `@agent.activity_tool_defn` tool in `tools=` (pass your
|
|
364
|
+
whole toolset — tools with no worker-side body are skipped);
|
|
365
|
+
- the **subagent** and **Code Mode** activities.
|
|
366
|
+
|
|
367
|
+
Order it last, after any AI SDK's plugin, so that SDK's payload converter wins. Registering it
|
|
368
|
+
on the client is enough — Temporal applies a client's plugins to workers built from it.
|
|
369
|
+
|
|
370
|
+
## Code Mode
|
|
371
|
+
|
|
372
|
+
Most agents call tools one at a time — a round-trip per call. **Code Mode** hands the model a
|
|
373
|
+
single tool that runs a Python *script* over your tools, so one turn can search, filter, branch,
|
|
374
|
+
and act across many calls with ordinary control flow and `asyncio.gather` concurrency.
|
|
375
|
+
|
|
376
|
+
`agent.code_mode_tool(tools, name=...)` takes any list of harness tools and returns one inline
|
|
377
|
+
tool. Its generated description tells the model the sandbox contract and every host function's
|
|
378
|
+
signature + result shape — derived from your tools, so you never hand-write or maintain it. Hand
|
|
379
|
+
the returned tool to your model's tool-calling loop like any other tool.
|
|
380
|
+
|
|
381
|
+
```python
|
|
382
|
+
from temporal_agent_harness.harness import agent
|
|
383
|
+
|
|
384
|
+
# Any @agent.activity_tool_defn / @agent.tool_defn tools — including a subagent toolset.
|
|
385
|
+
run_code = agent.code_mode_tool(
|
|
386
|
+
[search_flights, search_hotels, book_flight, get_trip_summary],
|
|
387
|
+
name="run_travel_code",
|
|
388
|
+
)
|
|
389
|
+
# The model then writes, e.g., a script like this and calls run_travel_code with it:
|
|
390
|
+
#
|
|
391
|
+
# import asyncio
|
|
392
|
+
# async def main():
|
|
393
|
+
# flights, hotels = await asyncio.gather( # independent calls run concurrently
|
|
394
|
+
# search_flights({"origin": "SFO", "destination": "JFK", "date": "2026-07-01"}),
|
|
395
|
+
# search_hotels({"city": "New York", "check_in": "2026-07-01", "check_out": "2026-07-05"}),
|
|
396
|
+
# )
|
|
397
|
+
# cheapest = min(flights["flights"], key=lambda f: f["price_usd"])
|
|
398
|
+
# return await book_flight({"flight_id": cheapest["flight_id"], "passenger_name": "Ada Lovelace"})
|
|
399
|
+
# asyncio.run(main())
|
|
400
|
+
```
|
|
401
|
+
|
|
402
|
+
- **Durable, gated, and observable per call.** The script runs in a sandbox; each host call is
|
|
403
|
+
dispatched back through the runner as its own durable activity — keeping that tool's approval
|
|
404
|
+
policy and `tool_start`/`tool_end` events. Writing the script is inert; only the host calls act.
|
|
405
|
+
- **Type-checked before it runs.** Code Mode generates static type-check stubs from your tools'
|
|
406
|
+
signatures, so a wrong argument or an unknown result key comes back as an error to fix rather
|
|
407
|
+
than a bad run.
|
|
408
|
+
- **Composes over subagents.** `agent.subagent_toolset(...)` returns a list of tools, so drop it
|
|
409
|
+
straight into `code_mode_tool([...])` — the model's script can drive subagents too.
|
|
410
|
+
- **Several per agent.** Give one agent multiple `code_mode_tool`s (distinct `name`s) over
|
|
411
|
+
disjoint or overlapping tool sets.
|
|
412
|
+
|
|
413
|
+
A worker that hosts a Code Mode agent needs the two sandbox-stepping activities and the durable
|
|
414
|
+
bodies of any activity-backed host tools. Both come from
|
|
415
|
+
[`AgentHarnessPlugin`](#running-a-worker--one-plugin) — the stepping activities as soon as the
|
|
416
|
+
`code-mode` extra (which pulls in [`pydantic-monty`](https://pypi.org/project/pydantic-monty/),
|
|
417
|
+
the sandbox the scripts run in) is installed:
|
|
418
|
+
|
|
419
|
+
```python
|
|
420
|
+
client = await Client.connect(..., plugins=[AgentHarnessPlugin(tools=my_tools)])
|
|
421
|
+
worker = Worker(client, task_queue=..., workflows=[MyAgent])
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
See [`examples/monty`](examples/monty) for three agents all built on Code Mode: a no-model script
|
|
425
|
+
runner, a conversational agent that writes its own scripts, and a subagent-driven variant.
|
|
426
|
+
|
|
427
|
+
## Slash Commands
|
|
428
|
+
|
|
429
|
+
Agents can expose human/operator slash commands through a small library of
|
|
430
|
+
workflow-safe command definitions. A command bundles the UI metadata returned by
|
|
431
|
+
the `operator_interface` query with the deterministic handler that runs inside
|
|
432
|
+
the workflow.
|
|
433
|
+
|
|
434
|
+
If `slash_commands` is omitted, `AgentWorkflowRunner` enables the packaged
|
|
435
|
+
defaults:
|
|
436
|
+
|
|
437
|
+
| Command | Effect |
|
|
438
|
+
| --- | --- |
|
|
439
|
+
| `/approvals strict\|safe\|skip` | Change the live tool-approval policy. |
|
|
440
|
+
| `/allow-tools tool_name` | Auto-approve one or more named tools for this session. |
|
|
441
|
+
| `/status` | Show the current harness status. |
|
|
442
|
+
| `/stop` | Stop the agent workflow. |
|
|
443
|
+
|
|
444
|
+
Configure exactly the packaged commands you want in one place:
|
|
445
|
+
|
|
446
|
+
```python
|
|
447
|
+
from temporal_agent_harness.harness import slash_commands
|
|
448
|
+
|
|
449
|
+
self._runner = AgentWorkflowRunner(
|
|
450
|
+
config,
|
|
451
|
+
stream=WorkflowStream(),
|
|
452
|
+
approval_policy_default=ToolApprovalPolicy.always_require_approvals(),
|
|
453
|
+
slash_commands=slash_commands.commands("approvals", "status", "stop"),
|
|
454
|
+
)
|
|
455
|
+
```
|
|
456
|
+
|
|
457
|
+
Pass an empty list to disable packaged slash commands:
|
|
458
|
+
|
|
459
|
+
```python
|
|
460
|
+
slash_commands=[]
|
|
461
|
+
```
|
|
462
|
+
|
|
463
|
+
Custom commands use the same registry. For example, a model selector can share
|
|
464
|
+
one implementation across the first-class operator update path and the normal
|
|
465
|
+
`slash` turn path:
|
|
466
|
+
|
|
467
|
+
```python
|
|
468
|
+
SUPPORTED_MODELS = ("gemini-3.5-flash", "gemini-3.1-flash-lite")
|
|
469
|
+
|
|
470
|
+
self._runner = AgentWorkflowRunner(
|
|
471
|
+
config,
|
|
472
|
+
stream=WorkflowStream(),
|
|
473
|
+
approval_policy_default=ToolApprovalPolicy.always_require_approvals(),
|
|
474
|
+
slash_commands=[
|
|
475
|
+
*slash_commands.default_commands(),
|
|
476
|
+
slash_commands.model_selector(
|
|
477
|
+
choices=SUPPORTED_MODELS,
|
|
478
|
+
set_model=lambda model: setattr(self, "_model", model),
|
|
479
|
+
description="Set the model for this session.",
|
|
480
|
+
),
|
|
481
|
+
],
|
|
482
|
+
)
|
|
483
|
+
```
|
|
484
|
+
|
|
485
|
+
## Requirements
|
|
486
|
+
|
|
487
|
+
- Python **3.11+**
|
|
488
|
+
- [uv](https://docs.astral.sh/uv/) for dependency management
|
|
489
|
+
- [just](https://just.systems/) for the example recipes
|
|
490
|
+
- A Temporal service. `just temporal` starts a local dev server if you have the `temporal`
|
|
491
|
+
CLI installed.
|
|
492
|
+
|
|
493
|
+
[pnpm](https://pnpm.io/) is **not** required to run anything: the browser UI ships prebuilt in
|
|
494
|
+
`temporal_agent_harness/ui/dist`, both in release archives and in the repo. You only need it to
|
|
495
|
+
*change* the UI — see [UI development](docs/internal/development.md#ui-development).
|
|
496
|
+
|
|
497
|
+
## Run the examples
|
|
498
|
+
|
|
499
|
+
These run from a checkout or an unpacked
|
|
500
|
+
[release archive](#try-it--run-the-example-agents) — the steps are identical.
|
|
501
|
+
|
|
502
|
+
One `.env.local` at the **project root** serves every example. Create it once:
|
|
503
|
+
|
|
504
|
+
```bash
|
|
505
|
+
cp .env.example .env.local
|
|
506
|
+
```
|
|
507
|
+
|
|
508
|
+
Set the creds for whichever agents you'll run: `OPENAI_API_KEY` (react_agent, openai_hello,
|
|
509
|
+
pydantic_ai_hello) and/or `GEMINI_API_KEY` (monty, wiki, coding). The default committed
|
|
510
|
+
`temporal.local.toml` profile points at a local Temporal dev server.
|
|
511
|
+
|
|
512
|
+
### One example, standalone
|
|
513
|
+
|
|
514
|
+
Each example runs on its own from its directory — [`examples/monty`](examples/monty) (a
|
|
515
|
+
conversational Code Mode travel agent + a subagent variant) is the best starting point:
|
|
516
|
+
|
|
517
|
+
```bash
|
|
518
|
+
cd examples/monty
|
|
519
|
+
just temporal # local Temporal dev server; skip if you bring your own
|
|
520
|
+
just session-manager # worker hosting the packaged SessionManagerWorkflow
|
|
521
|
+
just server # serves the Svelte UI + /api on :8000 (this example's agents only)
|
|
522
|
+
just worker # this example's agent worker
|
|
523
|
+
```
|
|
524
|
+
|
|
525
|
+
Open <http://localhost:8000> and pick an agent. Every example follows the same recipe set
|
|
526
|
+
(`temporal` / `session-manager` / `server` / `worker`, plus `client` where noted). `just server`
|
|
527
|
+
serves the prebuilt UI from `temporal_agent_harness/ui/dist`, so it needs no Node/pnpm. If you're
|
|
528
|
+
changing the UI, use `just dev-server` (rebuild + serve) instead.
|
|
529
|
+
|
|
530
|
+
### All examples behind one UI
|
|
531
|
+
|
|
532
|
+
The **root** justfile runs every example agent at once so the UI lists them all. From the project root,
|
|
533
|
+
each in its own terminal:
|
|
534
|
+
|
|
535
|
+
```bash
|
|
536
|
+
just temporal # start FRESH (or `just reset-manager` first — see the gotcha)
|
|
537
|
+
just session-manager # shared session-manager worker
|
|
538
|
+
just server # serves the MERGED registry (all agents) on http://localhost:8000
|
|
539
|
+
just workers # co-launch all six agent workers (Ctrl-C stops them; or run `just worker-<name>` each)
|
|
540
|
+
```
|
|
541
|
+
|
|
542
|
+
Then create a session for any agent in the UI. A few need extra setup or a client:
|
|
543
|
+
|
|
544
|
+
| Agent | Needs |
|
|
545
|
+
|---|---|
|
|
546
|
+
| OpenAI Hello · Pydantic AI Hello | `OPENAI_API_KEY`; chat directly in the UI |
|
|
547
|
+
| Monty (both) | `GEMINI_API_KEY`; chat directly in the UI |
|
|
548
|
+
| ReAct Agent | `OPENAI_API_KEY`; the **F1 MCP server** at `F1_MCP_SERVER_HOME` ([setup](examples/react_agent/README.md#the-f1-mcp-server)); `just react-client` to answer its `ask_user` (chat alone works in the UI) |
|
|
549
|
+
| Wiki (callback) | `GEMINI_API_KEY`; **`just wiki-client --wiki-dir ./wiki`** — required, or its tool calls hang |
|
|
550
|
+
| Coding (callback) | `GEMINI_API_KEY`; **`just coding-shim <dir>`** + the OpenCode TUI — required |
|
|
551
|
+
|
|
552
|
+
**Gotcha — the session manager caches its registry.** The server seeds the `session-manager`
|
|
553
|
+
workflow with the registry on first start and reuses the existing one after that. So when you switch
|
|
554
|
+
between a single-example server and the all-agents server (or change the set), run
|
|
555
|
+
`just reset-manager` before the next `just server`, or start a fresh Temporal dev server. Also: an
|
|
556
|
+
agent whose worker isn't running will accept a created session but never progress (it parks) — start
|
|
557
|
+
its worker.
|
|
558
|
+
|
|
559
|
+
## Status & docs
|
|
560
|
+
|
|
561
|
+
This is experimental and under active development; expect breaking changes — see
|
|
562
|
+
[Versioning and stability](#versioning-and-stability) for what that means for installs. Deeper
|
|
563
|
+
design documentation — the agent protocol, the streaming model, human-in-the-loop approvals, and
|
|
564
|
+
agents-as-subagents — lives under [`docs/internal/`](docs/internal). Contributor setup
|
|
565
|
+
(repository layout, the root `justfile`, UI development, and packaging) is in
|
|
566
|
+
[`docs/internal/development.md`](docs/internal/development.md).
|