@botbotgo/agent-harness 0.0.37 → 0.0.39

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 (38) hide show
  1. package/README.md +79 -137
  2. package/dist/api.d.ts +15 -12
  3. package/dist/api.js +25 -41
  4. package/dist/config/embedding-model.yaml +2 -2
  5. package/dist/config/workspace.yaml +37 -3
  6. package/dist/contracts/types.d.ts +17 -7
  7. package/dist/index.d.ts +1 -1
  8. package/dist/index.js +1 -1
  9. package/dist/mcp.d.ts +8 -3
  10. package/dist/mcp.js +10 -11
  11. package/dist/package-version.d.ts +1 -1
  12. package/dist/package-version.js +1 -1
  13. package/dist/resource/resource-impl.d.ts +2 -1
  14. package/dist/resource/resource-impl.js +16 -11
  15. package/dist/resource/resource.d.ts +1 -1
  16. package/dist/resource/resource.js +1 -1
  17. package/dist/runtime/agent-runtime-adapter.js +4 -2
  18. package/dist/runtime/event-bus.d.ts +5 -4
  19. package/dist/runtime/event-bus.js +7 -9
  20. package/dist/runtime/event-sink.d.ts +9 -0
  21. package/dist/runtime/event-sink.js +35 -0
  22. package/dist/runtime/harness.d.ts +21 -12
  23. package/dist/runtime/harness.js +81 -31
  24. package/dist/runtime/index.d.ts +3 -1
  25. package/dist/runtime/index.js +2 -1
  26. package/dist/runtime/parsing/stream-event-parsing.d.ts +2 -0
  27. package/dist/runtime/parsing/stream-event-parsing.js +35 -3
  28. package/dist/runtime/support/harness-support.d.ts +1 -0
  29. package/dist/runtime/support/harness-support.js +38 -4
  30. package/dist/runtime/thread-memory-sync.d.ts +4 -2
  31. package/dist/runtime/thread-memory-sync.js +10 -1
  32. package/dist/workspace/agent-binding-compiler.js +0 -3
  33. package/dist/workspace/compile.js +0 -1
  34. package/dist/workspace/support/discovery.js +11 -8
  35. package/dist/workspace/support/source-collectors.js +1 -1
  36. package/dist/workspace/support/workspace-ref-utils.d.ts +19 -0
  37. package/dist/workspace/support/workspace-ref-utils.js +112 -6
  38. package/package.json +3 -3
package/README.md CHANGED
@@ -2,33 +2,31 @@
2
2
 
3
3
  ## Product Overview
4
4
 
5
- `@botbotgo/agent-harness` helps developers build complex agent-based applications fast and keep them easy to maintain.
5
+ `@botbotgo/agent-harness` solves the gap between an agent execution engine and a real multi-agent application runtime.
6
6
 
7
- It helps developers:
7
+ The problem:
8
8
 
9
- - define agents in YAML
10
- - keep workspace behavior in `config/workspace.yaml`
11
- - keep shared bootstrap context in `config/agent-context.md`
12
- - discover tools and SKILL packages from `resources/`
13
- - bridge remote MCP servers into agent toolsets
14
- - expose harness-managed tools as an MCP server
15
- - run through either LangChain v1 or DeepAgents with one app-facing API
9
+ - agent logic, tools, MCP, routing, memory, and approvals usually end up scattered across code and scripts
10
+ - execution frameworks can run agents, but they do not give you a workspace-shaped product runtime by themselves
11
+ - applications need persisted threads, resumability, approvals, and operational control, not just model calls
16
12
 
17
- Why it works:
13
+ What this package provides:
18
14
 
19
- - it helps developers move from idea to working complex agent application with less setup friction
20
- - it makes ongoing maintenance lighter, including maintenance flows that can be automated by the application itself
21
- - one workspace becomes the source of truth for agent topology, models, tools, and operating context
22
- - one API covers direct agents and orchestration flows
23
- - local resources stay portable and versionable
24
- - thread state, approvals, resumability, and maintenance are built in
15
+ - a workspace runtime for multi-agent applications
16
+ - YAML-defined agents, models, routing, and maintenance policy
17
+ - local tools and SKILL packages loaded from `resources/`
18
+ - DeepAgents-first execution with LangChain v1 compatibility
19
+ - feature-level runtime APIs for runs, threads, approvals, and events
25
20
 
26
21
  Core API:
27
22
 
28
23
  - `createAgentHarness(...)`
29
24
  - `run(...)`
30
25
  - `subscribe(...)`
26
+ - `listThreads(...)`
31
27
  - `getThread(...)`
28
+ - `listApprovals(...)`
29
+ - `getApproval(...)`
32
30
  - `stop(...)`
33
31
 
34
32
  ## Quick Start
@@ -39,7 +37,7 @@ Install the package:
39
37
  npm install @botbotgo/agent-harness
40
38
  ```
41
39
 
42
- Create a workspace:
40
+ Workspace layout:
43
41
 
44
42
  ```text
45
43
  your-workspace/
@@ -56,109 +54,83 @@ your-workspace/
56
54
  skills/
57
55
  ```
58
56
 
59
- Use the standard layout only. Agent entry files must live under `config/agents/`; root-level files such as `agent.yaml`, `orchestra.yaml`, and `direct.yaml` are not loaded.
57
+ Use the standard layout only. Agent entry files must live under `config/agents/`.
60
58
 
61
59
  Minimal usage:
62
60
 
63
61
  ```ts
64
62
  import { createAgentHarness, run, stop } from "@botbotgo/agent-harness";
65
63
 
66
- const harness = await createAgentHarness("/absolute/path/to/your-workspace");
64
+ const runtime = await createAgentHarness("/absolute/path/to/your-workspace");
67
65
 
68
66
  try {
69
- const result = await run(harness, {
70
- agentId: "direct",
67
+ const result = await run(runtime, {
68
+ agentId: "auto",
71
69
  input: "Summarize what this workspace is for.",
72
70
  });
73
71
 
74
72
  console.log(result.output);
75
73
  } finally {
76
- await stop(harness);
74
+ await stop(runtime);
77
75
  }
78
76
  ```
79
77
 
80
78
  ## Feature List
81
79
 
82
- - One workspace for agents, models, tools, and runtime behavior
83
- - One API for both LangChain v1 and DeepAgents
84
- - Built-in routing for direct and orchestration flows
80
+ - Workspace runtime with DeepAgents-first execution and LangChain v1 compatibility
81
+ - YAML-defined host routing through `config/workspace.yaml`
85
82
  - Auto-discovered local tools and SKILL packages from `resources/tools/` and `resources/skills/`
86
- - MCP bridge support: agent YAML can mount remote or local MCP servers as agent tools
87
- - MCP server support: expose harness-managed tools over stdio or an in-memory MCP server
88
- - Built-in thread state, approvals, resumable runs, and long-term memory
89
- - MCP server helpers plus background checkpoint maintenance
83
+ - MCP bridge support for agent-declared servers
84
+ - MCP server support for exposing an agent toolset to other clients
85
+ - Persisted threads, approvals, run lifecycle, and resumable checkpoints
86
+ - Background checkpoint maintenance
90
87
 
91
88
  ## How To Use
92
89
 
93
- ### Create A Harness
94
-
95
- Pass a workspace root:
90
+ ### Create A Runtime
96
91
 
97
92
  ```ts
98
- import { createAgentHarness } from "@botbotgo/agent-harness";
93
+ import { AgentHarnessRuntime, createAgentHarness } from "@botbotgo/agent-harness";
99
94
 
100
- const harness = await createAgentHarness("/absolute/path/to/workspace");
95
+ const runtime: AgentHarnessRuntime = await createAgentHarness("/absolute/path/to/workspace");
101
96
  ```
102
97
 
103
- Or pass a prebuilt `WorkspaceBundle`:
98
+ Or:
104
99
 
105
100
  ```ts
106
- const harness = await createAgentHarness(workspaceBundle);
101
+ const runtime = await createAgentHarness(workspaceBundle);
107
102
  ```
108
103
 
109
- Implementation details:
110
-
111
- - `createAgentHarness(workspaceRoot)` loads and compiles one `WorkspaceBundle` before the runtime starts
112
- - the loader reads `config/workspace.yaml`, `config/models.yaml`, `config/agent-context.md`, and every `config/agents/*.yaml` entry file, then validates the final topology
113
- - local resource refs are hydrated after config load, so `resources/tools/`, `resources/skills/`, and agent-declared MCP servers are resolved before the harness accepts runs
114
- - after compilation, the harness initializes persistence under the resolved `runRoot`, wires the runtime adapter, starts thread-memory syncing, and starts checkpoint maintenance when configured
104
+ `createAgentHarness(workspaceRoot)` loads one `WorkspaceBundle`, resolves `resources/`, initializes persistence under `runRoot`, and starts runtime maintenance.
115
105
 
116
106
  ### Run A Request
117
107
 
118
108
  ```ts
119
109
  import { run } from "@botbotgo/agent-harness";
120
110
 
121
- const result = await run(harness, {
122
- agentId: "direct",
111
+ const result = await run(runtime, {
112
+ agentId: "orchestra",
123
113
  input: "Explain the available agents in this workspace.",
124
114
  });
125
115
  ```
126
116
 
127
- The result includes:
128
-
129
- - `threadId`
130
- - `runId`
131
- - `state`
132
- - `output`
133
-
134
- Runtime behavior:
117
+ Each run creates or continues a persisted thread. The result includes `threadId`, `runId`, `state`, and `output`.
135
118
 
136
- - every `run(...)` call creates or continues a persisted thread under `runRoot`
137
- - the harness stores thread metadata, run lifecycle, streamed events, approvals, delegations, and artifacts on disk so `getThread(...)` can reconstruct the session later
138
- - when a store is configured, the harness also mirrors thread status and open approvals into `/memories/threads/<threadId>/`
139
- - `stop(...)` should always be called so background persistence and maintenance loops shut down cleanly
140
-
141
- ### Let The Harness Choose The Host Agent
142
-
143
- Use `agentId: "auto"` when your workspace defines routing:
119
+ ### Let The Runtime Route
144
120
 
145
121
  ```ts
146
- const result = await run(harness, {
122
+ const result = await run(runtime, {
147
123
  agentId: "auto",
148
124
  input: "Inspect this repository and explain the release flow.",
149
125
  });
150
126
  ```
151
127
 
152
- Implementation details:
153
-
154
- - `agentId: "auto"` asks the runtime adapter to classify between the primary and secondary host bindings discovered from the workspace
155
- - when the run belongs to an existing thread, the router includes recent conversation turns so follow-up requests can stay on the correct lane
156
- - if no model-driven routing prompt is configured, the harness falls back to heuristic routing for obvious research or implementation-style requests
128
+ `agentId: "auto"` evaluates ordered `routing.rules` first, then falls back to `routing.defaultAgentId`, and only uses model routing when `routing.modelRouting: true`.
157
129
 
158
130
  ### Stream Output And Events
159
131
 
160
132
  ```ts
161
- const result = await run(harness, {
133
+ const result = await run(runtime, {
162
134
  agentId: "orchestra",
163
135
  input: "Inspect the workspace and explain the available tools.",
164
136
  listeners: {
@@ -172,12 +144,30 @@ const result = await run(harness, {
172
144
  });
173
145
  ```
174
146
 
147
+ The runtime emits typed lifecycle events for output, state changes, approvals, and delegations. `subscribe(...)` is a read-only observer surface.
148
+
149
+ ### Query Threads And Approvals
150
+
151
+ ```ts
152
+ import {
153
+ getApproval,
154
+ getThread,
155
+ listApprovals,
156
+ listThreads,
157
+ } from "@botbotgo/agent-harness";
158
+
159
+ const threads = await listThreads(runtime);
160
+ const thread = await getThread(runtime, threads[0]!.threadId);
161
+ const approvals = await listApprovals(runtime, { status: "pending" });
162
+ const approval = approvals[0] ? await getApproval(runtime, approvals[0].approvalId) : null;
163
+ ```
164
+
165
+ These methods return stored runtime data, not raw persistence, workspace, or backend instances.
166
+
175
167
  ### Use Skills And Local Tools
176
168
 
177
169
  `agent-harness` treats `resources/skills/` as SKILL packages and `resources/tools/` as executable local tools.
178
170
 
179
- Point agent YAML at both:
180
-
181
171
  ```yaml
182
172
  spec:
183
173
  skills:
@@ -186,17 +176,10 @@ spec:
186
176
  - ref: tool/local-toolset
187
177
  ```
188
178
 
189
- Tool implementation details:
190
-
191
- - tool modules are discovered from `resources/tools/*.js`, `resources/tools/*.mjs`, and `resources/tools/*.cjs`
192
- - the preferred format is exporting `tool({...})`; the harness also accepts exported functions plus `nameSchema`, `nameSchemaShape`, or generic `schema` metadata
193
- - when a module exports exactly one tool function, generic `schema` or `schemaShape` metadata can describe that function
194
- - keep runtime dependencies for local tools in `resources/package.json`, because the resource package is the execution boundary for those modules
179
+ Tool modules are discovered from `resources/tools/*.js`, `resources/tools/*.mjs`, and `resources/tools/*.cjs`. The preferred format is exporting `tool({...})`.
195
180
 
196
181
  ### Bridge MCP Servers Into Agents
197
182
 
198
- Use `mcpServers:` inside agent YAML to bridge MCP servers into the agent's tool list:
199
-
200
183
  ```yaml
201
184
  spec:
202
185
  mcpServers:
@@ -209,82 +192,52 @@ spec:
209
192
  token: ${DOCS_MCP_TOKEN}
210
193
  ```
211
194
 
212
- The harness discovers MCP tools, filters them through the agent config, and exposes them to the runtime like any other tool.
195
+ The runtime discovers MCP tools, filters them through agent config, and exposes them like any other tool.
213
196
 
214
- ### Expose Harness Tools As An MCP Server
215
-
216
- Use the MCP server helpers when another client should connect to the harness as an MCP server:
197
+ ### Expose Runtime Tools As An MCP Server
217
198
 
218
199
  ```ts
219
200
  import { createToolMcpServer, serveToolsOverStdio } from "@botbotgo/agent-harness";
220
201
 
221
- const server = await createToolMcpServer(harness, { agentId: "orchestra" });
222
- await serveToolsOverStdio(harness, { agentId: "orchestra" });
202
+ const server = await createToolMcpServer(runtime, { agentId: "orchestra" });
203
+ await serveToolsOverStdio(runtime, { agentId: "orchestra" });
223
204
  ```
224
205
 
225
- If you omit `serverInfo`, the harness uses `agent-harness-<agentId>` as the MCP server name and the current package version as the server version.
226
-
227
- ### Read Back Thread State
228
-
229
- ```ts
230
- import { getThread } from "@botbotgo/agent-harness";
231
-
232
- const thread = await getThread(harness, result.threadId);
233
- console.log(thread?.messages.at(-1)?.content);
234
- ```
235
-
236
- ### Subscribe To Global Events
237
-
238
- ```ts
239
- import { subscribe } from "@botbotgo/agent-harness";
240
-
241
- const unsubscribe = subscribe(harness, (event) => {
242
- console.log(event.threadId, event.runId, event.eventType);
243
- });
244
- ```
245
-
246
- ### Stop The Harness
206
+ ### Stop The Runtime
247
207
 
248
208
  ```ts
249
209
  import { stop } from "@botbotgo/agent-harness";
250
210
 
251
- await stop(harness);
211
+ await stop(runtime);
252
212
  ```
253
213
 
254
214
  ## How To Configure
255
215
 
256
216
  Core workspace files:
257
217
 
258
- - `config/workspace.yaml`: workspace-wide defaults such as `runRoot`, routing, and maintenance
218
+ - `config/workspace.yaml`: runtime defaults such as `runRoot`, routing, and maintenance
259
219
  - `config/agent-context.md`: shared bootstrap context for agents
260
220
  - `config/models.yaml`: named model presets
261
- - `config/agents/direct.yaml`: lightweight host agent
262
- - `config/agents/orchestra.yaml`: default orchestration host agent
221
+ - `config/agents/direct.yaml`: optional lightweight side-path host
222
+ - `config/agents/orchestra.yaml`: default DeepAgent execution host
263
223
  - `resources/package.json`: resource package boundary
264
224
  - `resources/tools/`: local tool modules
265
225
  - `resources/skills/`: local skills
266
226
 
267
227
  ### `config/workspace.yaml`
268
228
 
269
- Use this file for workspace-wide behavior such as:
229
+ Use this file for:
270
230
 
271
231
  - `runRoot`
272
- - routing via `routing.systemPrompt`
273
- - background checkpoint maintenance via `maintenance.checkpoints.*`
274
-
275
- Implementation details:
232
+ - ordered `routing.rules`
233
+ - `routing.systemPrompt`
234
+ - `maintenance.checkpoints.*`
276
235
 
277
- - if `runRoot` is omitted, the harness defaults to `<workspace-root>/run-data`
278
- - the resolved `runRoot` stores thread indexes, per-thread transcripts, per-run events, approvals, delegations, artifacts, and checkpoint references
279
- - checkpoint maintenance only starts when `maintenance.checkpoints.enabled: true`; for SQLite checkpoints, cleanup policies can sweep old rows and optionally `VACUUM` the database
236
+ If `runRoot` is omitted, the runtime defaults to `<workspace-root>/run-data`.
280
237
 
281
238
  ### `config/agent-context.md`
282
239
 
283
- Use this file for shared bootstrap context that agents read at construction time.
284
-
285
- Put stable project context here, not long-term mutable memory.
286
-
287
- If a runnable app workspace also includes `AGENTS.md`, treat that file as workspace-level operating guidance. It complements `config/agents/*.yaml`: `AGENTS.md` carries durable behavioral rules, while `config/agents/` defines agent topology and runtime configuration.
240
+ Use this file for shared bootstrap context that agents read at construction time. Put stable project context here, not long-term mutable memory.
288
241
 
289
242
  ### Agent YAML
290
243
 
@@ -307,21 +260,10 @@ Use `resources/` for executable extensions:
307
260
  - `resources/tools/` for local tool modules
308
261
  - `resources/skills/` for SKILL packages
309
262
 
310
- Each resource package should include its own `package.json`.
311
-
312
- Implementation details:
313
-
314
- - keep runtime extension source under `resources/`; keep tests outside the published source tree, for example under the repository `test/` folder
315
- - `resources/package.json` is the module resolution boundary used when local tools import third-party packages or skill-local scripts
316
- - SKILL packages stay file-based, so prompts, templates, helper scripts, and metadata can ship together without extra registration steps
263
+ Keep runtime extension source under `resources/`. Keep tests outside the published source tree, for example under the repository `test/` folder.
317
264
 
318
265
  ### Skills And MCP
319
266
 
320
- - Use `resources/skills/` for SKILL packages that carry reusable instructions, templates, scripts, and metadata
321
- - Use `mcpServers:` in `config/agents/*.yaml` when you want the harness to bridge external MCP tools into an agent
322
- - Use `createToolMcpServer(...)` or `serveToolsOverStdio(...)` when you want the harness itself to act as an MCP server for another client
323
-
324
- Implementation details:
325
-
326
- - agent-declared `mcpServers:` entries are hydrated into concrete MCP tool refs during workspace compilation, then validated against the collected MCP server definitions
327
- - `createToolMcpServer(...)` exposes the selected agent toolset through one MCP server surface; `serveToolsOverStdio(...)` is the stdio transport wrapper around that same server construction
267
+ - Use `resources/skills/` for reusable skill packages
268
+ - Use `mcpServers:` in `config/agents/*.yaml` to bridge external MCP tools into an agent
269
+ - Use `createToolMcpServer(...)` or `serveToolsOverStdio(...)` when you want the runtime to act as an MCP server for another client
package/dist/api.d.ts CHANGED
@@ -1,17 +1,20 @@
1
- import type { AgentHarnessHandle, RunOptions, RuntimeAdapterOptions, ThreadRecord, WorkspaceLoadOptions, WorkspaceBundle } from "./contracts/types.js";
2
- import { AgentHarness } from "./runtime/harness.js";
1
+ import type { ApprovalRecord, RunOptions, RuntimeAdapterOptions, ThreadSummary, ThreadRecord, WorkspaceLoadOptions, WorkspaceBundle } from "./contracts/types.js";
2
+ import { AgentHarnessRuntime } from "./runtime/harness.js";
3
3
  import type { ToolMcpServerOptions } from "./mcp.js";
4
+ export { AgentHarnessRuntime } from "./runtime/harness.js";
4
5
  type CreateAgentHarnessOptions = {
5
6
  load?: WorkspaceLoadOptions;
6
7
  adapter?: RuntimeAdapterOptions;
7
8
  };
8
- export declare function createAgentHarness(): Promise<AgentHarnessHandle>;
9
- export declare function createAgentHarness(workspaceRoot: string, options?: CreateAgentHarnessOptions): Promise<AgentHarnessHandle>;
10
- export declare function createAgentHarness(workspace: WorkspaceBundle, options?: CreateAgentHarnessOptions): Promise<AgentHarnessHandle>;
11
- export declare function run(harness: AgentHarnessHandle, options: RunOptions): Promise<import("./contracts/types.js").RunResult>;
12
- export declare function subscribe(harness: AgentHarnessHandle, listener: Parameters<AgentHarness["subscribe"]>[0]): () => void;
13
- export declare function getThread(harness: AgentHarnessHandle, threadId: string): Promise<ThreadRecord | null>;
14
- export declare function stop(harness: AgentHarnessHandle): Promise<void>;
15
- export declare function createToolMcpServer(harness: AgentHarnessHandle, options: ToolMcpServerOptions): Promise<import("@modelcontextprotocol/sdk/server/mcp.js").McpServer>;
16
- export declare function serveToolsOverStdio(harness: AgentHarnessHandle, options: ToolMcpServerOptions): Promise<import("@modelcontextprotocol/sdk/server/mcp.js").McpServer>;
17
- export {};
9
+ export declare function createAgentHarness(): Promise<AgentHarnessRuntime>;
10
+ export declare function createAgentHarness(workspaceRoot: string, options?: CreateAgentHarnessOptions): Promise<AgentHarnessRuntime>;
11
+ export declare function createAgentHarness(workspace: WorkspaceBundle, options?: CreateAgentHarnessOptions): Promise<AgentHarnessRuntime>;
12
+ export declare function run(runtime: AgentHarnessRuntime, options: RunOptions): Promise<import("./contracts/types.js").RunResult>;
13
+ export declare function subscribe(runtime: AgentHarnessRuntime, listener: Parameters<AgentHarnessRuntime["subscribe"]>[0]): () => void;
14
+ export declare function listThreads(runtime: AgentHarnessRuntime, filter?: Parameters<AgentHarnessRuntime["listThreads"]>[0]): Promise<ThreadSummary[]>;
15
+ export declare function getThread(runtime: AgentHarnessRuntime, threadId: string): Promise<ThreadRecord | null>;
16
+ export declare function listApprovals(runtime: AgentHarnessRuntime, filter?: Parameters<AgentHarnessRuntime["listApprovals"]>[0]): Promise<ApprovalRecord[]>;
17
+ export declare function getApproval(runtime: AgentHarnessRuntime, approvalId: string): Promise<ApprovalRecord | null>;
18
+ export declare function stop(runtime: AgentHarnessRuntime): Promise<void>;
19
+ export declare function createToolMcpServer(runtime: AgentHarnessRuntime, options: ToolMcpServerOptions): Promise<import("@modelcontextprotocol/sdk/server/mcp.js").McpServer>;
20
+ export declare function serveToolsOverStdio(runtime: AgentHarnessRuntime, options: ToolMcpServerOptions): Promise<import("@modelcontextprotocol/sdk/server/mcp.js").McpServer>;
package/dist/api.js CHANGED
@@ -1,54 +1,38 @@
1
- import { AgentHarness } from "./runtime/harness.js";
2
- import { createToolMcpServerFromHarness, serveToolsOverStdioFromHarness } from "./mcp.js";
1
+ import { AgentHarnessRuntime } from "./runtime/harness.js";
3
2
  import { loadWorkspace } from "./workspace/compile.js";
4
- const HARNESS_INSTANCE = Symbol.for("@botbotgo/agent-harness/instance");
5
- function registerHarness(harness) {
6
- const handle = { kind: "AgentHarnessHandle" };
7
- Object.defineProperty(handle, HARNESS_INSTANCE, {
8
- value: harness,
9
- enumerable: false,
10
- configurable: false,
11
- writable: false,
12
- });
13
- return Object.freeze(handle);
14
- }
15
- function requireHarness(handle) {
16
- if (handle instanceof AgentHarness) {
17
- return handle;
18
- }
19
- if (typeof handle === "object" && handle !== null && "run" in handle && "subscribe" in handle && "close" in handle) {
20
- return handle;
21
- }
22
- const harness = handle[HARNESS_INSTANCE];
23
- if (!harness) {
24
- throw new Error("Unknown or stopped AgentHarnessHandle");
25
- }
26
- return harness;
27
- }
3
+ export { AgentHarnessRuntime } from "./runtime/harness.js";
28
4
  export async function createAgentHarness(input = process.cwd(), options = {}) {
29
5
  const workspace = typeof input === "string"
30
6
  ? await loadWorkspace(input, options.load ?? {})
31
7
  : input;
32
- const harness = new AgentHarness(workspace, options.adapter ?? {});
8
+ const harness = new AgentHarnessRuntime(workspace, options.adapter ?? {});
33
9
  await harness.initialize();
34
- return registerHarness(harness);
10
+ return harness;
11
+ }
12
+ export async function run(runtime, options) {
13
+ return runtime.run(options);
14
+ }
15
+ export function subscribe(runtime, listener) {
16
+ return runtime.subscribe(listener);
17
+ }
18
+ export async function listThreads(runtime, filter) {
19
+ return runtime.listThreads(filter);
35
20
  }
36
- export async function run(harness, options) {
37
- return requireHarness(harness).run(options);
21
+ export async function getThread(runtime, threadId) {
22
+ return runtime.getThread(threadId);
38
23
  }
39
- export function subscribe(harness, listener) {
40
- return requireHarness(harness).subscribe(listener);
24
+ export async function listApprovals(runtime, filter) {
25
+ return runtime.listApprovals(filter);
41
26
  }
42
- export async function getThread(harness, threadId) {
43
- return requireHarness(harness).getThread(threadId);
27
+ export async function getApproval(runtime, approvalId) {
28
+ return runtime.getApproval(approvalId);
44
29
  }
45
- export async function stop(harness) {
46
- const instance = requireHarness(harness);
47
- return instance.close();
30
+ export async function stop(runtime) {
31
+ return runtime.stop();
48
32
  }
49
- export async function createToolMcpServer(harness, options) {
50
- return createToolMcpServerFromHarness(requireHarness(harness), options);
33
+ export async function createToolMcpServer(runtime, options) {
34
+ return runtime.createToolMcpServer(options);
51
35
  }
52
- export async function serveToolsOverStdio(harness, options) {
53
- return serveToolsOverStdioFromHarness(requireHarness(harness), options);
36
+ export async function serveToolsOverStdio(runtime, options) {
37
+ return runtime.serveToolsOverStdio(options);
54
38
  }
@@ -25,5 +25,5 @@ spec:
25
25
  # ======================
26
26
  # agent-harness Features
27
27
  # ======================
28
- # This object is packaged and referenced through retrieval-oriented builtin tools such as `builtin.build_rag_index`
29
- # and `builtin.query_rag_index`, not through `agent.modelRef`.
28
+ # This object is packaged and referenced through retrieval-oriented workspace tools such as the RAG index builder
29
+ # and query tool, not through `agent.modelRef`.
@@ -22,14 +22,48 @@ spec:
22
22
  # Value options: relative workspace path like `./.agent`, or an absolute filesystem path.
23
23
  runRoot: ./.agent
24
24
 
25
- # agent-harness feature: optional host-router prompt override used when the framework chooses between
26
- # top-level host agents such as `direct` and `orchestra`.
25
+ # agent-harness feature: optional host-router prompt override used when the runtime chooses between
26
+ # top-level host agents such as a main DeepAgent host and an optional low-latency side host.
27
27
  # Use placeholders so the same prompt can survive host renames:
28
28
  # - {{primaryAgentId}}
29
29
  # - {{primaryDescription}}
30
30
  # - {{secondaryAgentId}}
31
31
  # - {{secondaryDescription}}
32
32
  routing:
33
+ # agent-harness feature: DeepAgents-first default host selected when no explicit routing rule matches.
34
+ # Best practice is to point this at the main DeepAgent entry host and treat lighter agents as explicit opt-in.
35
+ defaultAgentId: orchestra
36
+ # agent-harness feature: optional model-driven host classification fallback.
37
+ # Keep this disabled unless you specifically need host-level model selection.
38
+ modelRouting: false
39
+ # agent-harness feature: ordered host-routing rules evaluated before model-driven classification.
40
+ # These rules only choose which host profile starts the run; DeepAgents still owns planning, tools, and long-running execution.
41
+ # The first matching rule wins. Use this when you want stable routing behavior in YAML instead of code.
42
+ #
43
+ # Supported match fields on each rule:
44
+ # - `equals`: exact request text match (string or list)
45
+ # - `startsWith`: request prefix match (string or list)
46
+ # - `contains`: substring match (string or list)
47
+ # - `regex`: regular-expression match (string or list)
48
+ # - `minLength` / `maxLength`: request text length bounds
49
+ # - `minLines` / `maxLines`: request line-count bounds
50
+ # - `hasThreadId`: require a new turn (`false`) or existing thread follow-up (`true`)
51
+ # - `caseSensitive`: default `false`
52
+ #
53
+ # Example:
54
+ # rules:
55
+ # - agentId: research-lite
56
+ # contains: ["latest", "today", "news", "最近", "最新", "新闻"]
57
+ # - agentId: orchestra
58
+ # regex:
59
+ # - "\\b(create|build|implement|fix|review|debug|inspect|analy[sz]e|download|clone)\\b"
60
+ rules:
61
+ - agentId: research-lite
62
+ contains: ["latest", "recent", "today", "current", "news", "最新", "最近", "今天", "当前", "新闻", "头条", "研究", "调研"]
63
+ - agentId: orchestra
64
+ regex:
65
+ - "\\b(create|build|implement|fix|debug|refactor|review|test|ship|release|deploy|code|bug|repo|repository|file|files|download|clone|inspect|analy[sz]e|explore)\\b"
66
+ - "(写代码|实现|修复|排查|调试|重构|评审|测试|发布|部署|仓库|代码|文件|下载|克隆|分析|检查|探索)"
33
67
  systemPrompt: |-
34
68
  You are a routing classifier for an agent harness. Reply with exactly one agent id:
35
69
  {{primaryAgentId}} or {{secondaryAgentId}}.
@@ -47,7 +81,7 @@ spec:
47
81
  When uncertain, prefer {{secondaryAgentId}}.
48
82
 
49
83
  # agent-harness feature: optional workspace-level background maintenance policies.
50
- # This is the framework-owned place to configure periodic housekeeping that should run without
84
+ # This is the runtime-owned place to configure periodic housekeeping that should run without
51
85
  # coupling cleanup to user-triggered checkpoint reads or writes.
52
86
  #
53
87
  # Current support:
@@ -183,7 +183,6 @@ export type CompiledAgentBinding = {
183
183
  export type WorkspaceBundle = {
184
184
  workspaceRoot: string;
185
185
  resourceSources: string[];
186
- builtinSources?: string[];
187
186
  refs: Map<string, WorkspaceObject | ParsedAgentObject>;
188
187
  models: Map<string, ParsedModelObject>;
189
188
  embeddings: Map<string, ParsedEmbeddingModelObject>;
@@ -196,7 +195,6 @@ export type WorkspaceBundle = {
196
195
  export type WorkspaceLoadOptions = {
197
196
  overlayRoots?: string[];
198
197
  resourceSources?: string[];
199
- builtinSources?: string[];
200
198
  };
201
199
  export type ThreadSummary = {
202
200
  agentId: string;
@@ -207,9 +205,11 @@ export type ThreadSummary = {
207
205
  status: RunState;
208
206
  };
209
207
  export type SessionRecord = ThreadSummary;
208
+ export type KnownHarnessEventType = "run.created" | "run.state.changed" | "run.resumed" | "approval.requested" | "approval.resolved" | "artifact.created" | "output.delta" | "reasoning.delta" | "runtime.synthetic_fallback";
209
+ export type HarnessEventType = KnownHarnessEventType | (string & {});
210
210
  export type HarnessEvent = {
211
211
  eventId: string;
212
- eventType: string;
212
+ eventType: HarnessEventType;
213
213
  timestamp: string;
214
214
  threadId: string;
215
215
  runId: string;
@@ -217,6 +217,17 @@ export type HarnessEvent = {
217
217
  source: "runtime" | "policy" | "surface" | "worker";
218
218
  payload: Record<string, unknown>;
219
219
  };
220
+ export type HarnessEventListener = (event: HarnessEvent) => void | Promise<void>;
221
+ export type HarnessEventProjection = {
222
+ name?: string;
223
+ shouldHandle?: (event: HarnessEvent) => boolean;
224
+ handleEvent: HarnessEventListener;
225
+ };
226
+ export type RuntimeEventSink = {
227
+ publish: (event: HarnessEvent) => void;
228
+ subscribe: (listener: HarnessEventListener) => () => void;
229
+ registerProjection: (projection: HarnessEventProjection) => () => void;
230
+ };
220
231
  export type RunResult = {
221
232
  threadId: string;
222
233
  runId: string;
@@ -236,6 +247,7 @@ export type RunListeners = {
236
247
  onToolResult?: (item: {
237
248
  toolName: string;
238
249
  output: unknown;
250
+ isError?: boolean;
239
251
  }) => void | Promise<void>;
240
252
  };
241
253
  export type MessageContentPart = {
@@ -289,6 +301,7 @@ export type HarnessStreamItem = {
289
301
  agentId: string;
290
302
  toolName: string;
291
303
  output: unknown;
304
+ isError?: boolean;
292
305
  };
293
306
  export type TranscriptMessage = {
294
307
  role: "user" | "assistant";
@@ -438,8 +451,5 @@ export type PolicyEvaluator = {
438
451
  };
439
452
  export type EventSubscriber = {
440
453
  kind: string;
441
- onEvent: (event: HarnessEvent) => void | Promise<void>;
442
- };
443
- export type AgentHarnessHandle = {
444
- readonly kind: "AgentHarnessHandle";
454
+ onEvent: HarnessEventListener;
445
455
  };
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { createAgentHarness, createToolMcpServer, getThread, run, serveToolsOverStdio, subscribe, stop } from "./api.js";
1
+ export { AgentHarnessRuntime, createAgentHarness, createToolMcpServer, getApproval, getThread, listApprovals, listThreads, run, serveToolsOverStdio, subscribe, stop, } from "./api.js";
2
2
  export type { ToolMcpServerOptions } from "./mcp.js";
3
3
  export { tool } from "./tools.js";
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- export { createAgentHarness, createToolMcpServer, getThread, run, serveToolsOverStdio, subscribe, stop } from "./api.js";
1
+ export { AgentHarnessRuntime, createAgentHarness, createToolMcpServer, getApproval, getThread, listApprovals, listThreads, run, serveToolsOverStdio, subscribe, stop, } from "./api.js";
2
2
  export { tool } from "./tools.js";
package/dist/mcp.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
2
- import type { AgentHarness } from "./runtime/harness.js";
2
+ import type { CompiledTool, ParsedToolObject } from "./contracts/types.js";
3
3
  export type ToolMcpServerOptions = {
4
4
  agentId: string;
5
5
  serverInfo?: {
@@ -8,5 +8,10 @@ export type ToolMcpServerOptions = {
8
8
  };
9
9
  includeToolNames?: string[];
10
10
  };
11
- export declare function createToolMcpServerFromHarness(harness: AgentHarness, options: ToolMcpServerOptions): Promise<McpServer>;
12
- export declare function serveToolsOverStdioFromHarness(harness: AgentHarness, options: ToolMcpServerOptions): Promise<McpServer>;
11
+ export type ToolMcpServerTool = {
12
+ compiledTool: CompiledTool;
13
+ resolvedTool: unknown;
14
+ sourceTool?: ParsedToolObject;
15
+ };
16
+ export declare function createToolMcpServerFromTools(tools: ToolMcpServerTool[], options: ToolMcpServerOptions): Promise<McpServer>;
17
+ export declare function serveToolsOverStdioFromHarness(tools: ToolMcpServerTool[], options: ToolMcpServerOptions): Promise<McpServer>;