@botbotgo/agent-harness 0.0.50 → 0.0.51

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.
package/README.md CHANGED
@@ -6,16 +6,16 @@
6
6
 
7
7
  It is not a new agent framework. It is the runtime layer around LangChain v1 and DeepAgents that turns one workspace into one operable application runtime.
8
8
 
9
- The product boundary is:
9
+ The product boundary is simple:
10
10
 
11
11
  - LangChain v1 and DeepAgents own agent execution semantics
12
- - `agent-harness` owns application runtime semantics
12
+ - `agent-harness` owns application-level orchestration and lifecycle management
13
13
 
14
14
  That means:
15
15
 
16
16
  - public API stays small
17
- - complex assembly and policy live in YAML
18
- - runtime lifecycle stays stable even if the backend implementation changes
17
+ - complex setup and operating policy live in YAML
18
+ - runtime lifecycle stays stable even if backend implementations change
19
19
 
20
20
  What the runtime provides:
21
21
 
@@ -201,11 +201,11 @@ metadata:
201
201
  spec:
202
202
  execution:
203
203
  backend: deepagent
204
- modelRef: model/default
205
- mcpServers:
206
- - name: browser
207
- command: node
208
- args: ["./mcp-browser-server.mjs"]
204
+ modelRef: model/default
205
+ mcpServers:
206
+ - name: browser
207
+ command: node
208
+ args: ["./mcp-browser-server.mjs"]
209
209
  ```
210
210
 
211
211
  The runtime discovers MCP tools, filters them through agent configuration, and exposes them like other tools.
@@ -347,6 +347,13 @@ Use this file for named MCP server presets.
347
347
 
348
348
  Agents are always declared with `kind: Agent` and `spec.execution.backend`.
349
349
 
350
+ Use two nested sections inside each agent:
351
+
352
+ - `spec.runtime` for harness-owned runtime placement such as `spec.runtime.runRoot`
353
+ - `spec.execution` for upstream execution semantics and adapter-facing config
354
+
355
+ This keeps the public product model small while letting LangChain v1 and DeepAgents concepts pass through with minimal translation.
356
+
350
357
  Example lightweight host:
351
358
 
352
359
  ```yaml
@@ -357,10 +364,11 @@ metadata:
357
364
  spec:
358
365
  execution:
359
366
  backend: langchain-v1
360
- modelRef: model/default
361
- checkpointer:
362
- ref: checkpointer/default
363
- systemPrompt: Answer simple requests directly.
367
+ modelRef: model/default
368
+ config:
369
+ checkpointer:
370
+ ref: checkpointer/default
371
+ systemPrompt: Answer simple requests directly.
364
372
  ```
365
373
 
366
374
  Example main execution host:
@@ -373,21 +381,22 @@ metadata:
373
381
  spec:
374
382
  execution:
375
383
  backend: deepagent
376
- modelRef: model/default
377
- memory:
378
- - path: config/agent-context.md
379
- store:
380
- ref: store/default
381
- checkpointer:
382
- ref: checkpointer/default
383
- backend:
384
- kind: CompositeBackend
385
- state:
386
- kind: VfsSandbox
387
- timeout: 600
388
- routes:
389
- /memories/:
390
- kind: StoreBackend
384
+ modelRef: model/default
385
+ memory:
386
+ - path: config/agent-context.md
387
+ config:
388
+ store:
389
+ ref: store/default
390
+ checkpointer:
391
+ ref: checkpointer/default
392
+ backend:
393
+ kind: CompositeBackend
394
+ state:
395
+ kind: VfsSandbox
396
+ timeout: 600
397
+ routes:
398
+ /memories/:
399
+ kind: StoreBackend
391
400
  ```
392
401
 
393
402
  Client-configurable agent fields include:
@@ -395,21 +404,29 @@ Client-configurable agent fields include:
395
404
  - `metadata.name`
396
405
  - `metadata.description`
397
406
  - `spec.execution.backend`
398
- - `spec.modelRef`
399
- - `spec.systemPrompt`
400
- - `spec.tools`
401
- - `spec.skills`
402
- - `spec.memory`
403
- - `spec.checkpointer`
404
- - `spec.store`
405
- - `spec.backend`
406
- - `spec.middleware`
407
- - `spec.subagents`
408
- - `spec.mcpServers`
409
- - `spec.responseFormat`
410
- - `spec.contextSchema`
411
-
412
- For backend-specific agent options, prefer passing the upstream concept directly in YAML. The loader keeps a small stable product shape, but it also preserves agent-level passthrough fields so new LangChain v1 or DeepAgents parameters can flow into adapters without expanding the public API surface.
407
+ - `spec.runtime.runRoot`
408
+ - `spec.execution.modelRef`
409
+ - `spec.execution.tools`
410
+ - `spec.execution.skills`
411
+ - `spec.execution.memory`
412
+ - `spec.execution.subagents`
413
+ - `spec.execution.mcpServers`
414
+ - `spec.execution.config.systemPrompt`
415
+ - `spec.execution.config.checkpointer`
416
+ - `spec.execution.config.store`
417
+ - `spec.execution.config.backend`
418
+ - `spec.execution.config.middleware`
419
+ - `spec.execution.config.responseFormat`
420
+ - `spec.execution.config.contextSchema`
421
+ - `spec.execution.config.stateSchema`
422
+ - `spec.execution.config.interruptOn`
423
+ - `spec.execution.config.filesystem`
424
+ - `spec.execution.config.taskDescription`
425
+ - `spec.execution.config.generalPurposeAgent`
426
+ - `spec.execution.config.includeAgentName`
427
+ - `spec.execution.config.version`
428
+
429
+ For backend-specific agent options, prefer passing the upstream concept directly inside `spec.execution.config`. The loader keeps a small stable product shape, but it also preserves adapter-facing passthrough fields so new LangChain v1 or DeepAgents parameters can flow into adapters without expanding the public API surface.
413
430
 
414
431
  ### `resources/`
415
432
 
@@ -431,7 +448,6 @@ SKILL packages are discovered from `resources/skills/` and attached to agents th
431
448
  - upstream LangChain v1 and DeepAgents concepts should be expressed as directly as possible in YAML
432
449
  - recovery, approvals, threads, runs, and events are runtime concepts, not backend-specific escape hatches
433
450
  - backend implementation details should stay internal unless product requirements force exposure
434
- - application-level orchestration and lifecycle management stays in the harness
435
451
 
436
452
  In short: `agent-harness` is a public runtime contract generic enough to survive backend changes, while the deep execution semantics stay upstream.
437
453
 
@@ -9,41 +9,43 @@ metadata:
9
9
  # agent-harness feature: human-readable summary for inventory and UI.
10
10
  description: Manual low-latency host for direct answers and lightweight inventory lookup. Do not use it as the default executor for tool-heavy or specialist-shaped tasks.
11
11
  spec:
12
- execution:
13
- # Current backend adapter for this host profile.
14
- backend: langchain-v1
12
+ runtime: {}
15
13
  # =====================
16
14
  # Runtime Agent Features
17
15
  # =====================
18
- # Upstream execution feature: model ref for the underlying LLM used by the direct-response agent.
19
- # This should point at a cheap, fast, general-purpose chat model, because `direct` is intended
20
- # to be the low-latency path for simple requests.
21
- modelRef: model/default
22
- # Runtime execution feature: checkpointer config passed into the selected backend adapter.
23
- # Even the lightweight direct path can benefit from resumable state during interactive use.
24
- # Available `kind` options in this harness: `FileCheckpointer`, `MemorySaver`, `SqliteSaver`.
25
- # `path` is only used by `FileCheckpointer` and `SqliteSaver`; omit it for `MemorySaver`.
26
- checkpointer:
27
- ref: checkpointer/default
28
- # Upstream execution feature: system prompt for the lightweight direct-response host.
29
- # This prompt should keep the agent focused on:
30
- # - answering simple requests in one turn
31
- # - staying lightweight instead of planning or orchestrating
32
- # - avoiding specialist-style decomposition unless the caller explicitly switches agents
33
- #
34
- # The direct host is intentionally narrower than the orchestra host:
35
- # - `direct` is optimized for latency and straightforward completion
36
- # - `orchestra` is optimized for multi-step work, tools, delegation, and specialist use
37
- #
38
- # Keep this prompt biased toward concise, self-contained answers. If richer routing policy is
39
- # needed for choosing between host agents, configure that separately via `Runtime.spec.routing`
40
- # rather than overloading the direct host prompt with classifier behavior.
41
- systemPrompt: |-
42
- You are the direct agent.
16
+ execution:
17
+ # Current backend adapter for this host profile.
18
+ backend: langchain-v1
19
+ # Upstream execution feature: model ref for the underlying LLM used by the direct-response agent.
20
+ # This should point at a cheap, fast, general-purpose chat model, because `direct` is intended
21
+ # to be the low-latency path for simple requests.
22
+ modelRef: model/default
23
+ config:
24
+ # Runtime execution feature: checkpointer config passed into the selected backend adapter.
25
+ # Even the lightweight direct path can benefit from resumable state during interactive use.
26
+ # Available `kind` options in this harness: `FileCheckpointer`, `MemorySaver`, `SqliteSaver`.
27
+ # `path` is only used by `FileCheckpointer` and `SqliteSaver`; omit it for `MemorySaver`.
28
+ checkpointer:
29
+ ref: checkpointer/default
30
+ # Upstream execution feature: system prompt for the lightweight direct-response host.
31
+ # This prompt should keep the agent focused on:
32
+ # - answering simple requests in one turn
33
+ # - staying lightweight instead of planning or orchestrating
34
+ # - avoiding specialist-style decomposition unless the caller explicitly switches agents
35
+ #
36
+ # The direct host is intentionally narrower than the orchestra host:
37
+ # - `direct` is optimized for latency and straightforward completion
38
+ # - `orchestra` is optimized for multi-step work, tools, delegation, and specialist use
39
+ #
40
+ # Keep this prompt biased toward concise, self-contained answers. If richer routing policy is
41
+ # needed for choosing between host agents, configure that separately via `Runtime.spec.routing`
42
+ # rather than overloading the direct host prompt with classifier behavior.
43
+ systemPrompt: |-
44
+ You are the direct agent.
43
45
 
44
- This is a manual low-latency host.
45
- Answer simple requests directly.
46
- Keep the path lightweight.
47
- Do not delegate.
48
- Do not perform broad multi-step execution.
49
- Do not behave like the default execution host.
46
+ This is a manual low-latency host.
47
+ Answer simple requests directly.
48
+ Keep the path lightweight.
49
+ Do not delegate.
50
+ Do not perform broad multi-step execution.
51
+ Do not behave like the default execution host.
@@ -9,86 +9,88 @@ metadata:
9
9
  # agent-harness feature: human-readable summary for inventory and UI.
10
10
  description: Default execution host. Answer directly when possible, use local tools and skills first, and delegate only when a specialist is a better fit. Not a reflex delegation-only planner.
11
11
  spec:
12
- execution:
13
- # Current backend adapter for this host profile.
14
- backend: deepagent
12
+ runtime: {}
15
13
  # =====================
16
14
  # Runtime Agent Features
17
15
  # =====================
18
- # Upstream execution feature: model ref for the underlying LLM used by this execution host.
19
- modelRef: model/default
20
- # Runtime execution feature: checkpointer config passed into the selected backend adapter.
21
- # This persists resumable graph state for this agent.
22
- # Available `kind` options in this harness: `FileCheckpointer`, `MemorySaver`, `SqliteSaver`.
23
- # `path` is only used by `FileCheckpointer` and `SqliteSaver`; omit it for `MemorySaver`.
24
- checkpointer:
25
- # ref: checkpointer/sqlite
26
- ref: checkpointer/default
27
- memory:
28
- # Upstream execution feature: bootstrap memory sources supplied to the selected backend at construction time.
29
- # These paths resolve relative to the workspace root unless they are already absolute.
30
- # Treat this as agent-owned startup context, not as a dynamic long-term memory sink:
31
- # - keep `systemPrompt` for stable role, boundaries, and hard behavioral rules
32
- # - use `memory:` for stable project knowledge, operating conventions, and shared or agent-specific context files
33
- # - use `/memories/*` via the backend/store below for durable knowledge learned from prior runs
34
- # - use the harness checkpointer for resumable graph state for an in-flight run
35
- # Updating these files changes future agent constructions, but they are still bootstrap inputs rather than
36
- # self-updating runtime memory.
37
- - path: config/agent-context.md
38
- # Upstream execution feature: store config passed into the selected backend adapter.
39
- # In the default deepagent adapter this is the LangGraph store used by `StoreBackend` routes.
40
- # Available `kind` options in this harness: `FileStore`, `InMemoryStore`, `RedisStore`, `PostgresStore`.
41
- store:
42
- ref: store/default
43
- # Upstream execution feature: backend config passed into the selected backend adapter.
44
- # This directly defines the backend topology for this agent:
45
- # - workspace execution uses a lightweight VFS sandbox
46
- # - long-term memory under `/memories/*` uses `StoreBackend`
47
- # - `CompositeBackend` composes those backend instances together
48
- # The harness also injects a persistent file-backed store and a file-backed checkpointer so that
49
- # `/memories/*` and resumable run state survive restarts in the default setup.
50
- # Available top-level `kind` options in this harness: `CompositeBackend`, `StateBackend`, `StoreBackend`.
51
- backend:
52
- kind: CompositeBackend
53
- state:
54
- # Available state backend `kind` options today: `StateBackend`, `LocalShellBackend`, `VfsSandbox`.
55
- kind: VfsSandbox
56
- timeout: 600
57
- routes:
58
- /memories/:
59
- # Available route backend `kind` options today: `StoreBackend`.
60
- kind: StoreBackend
61
- # Upstream execution feature: system prompt for the orchestration host.
62
- # This becomes the top-level instruction block for the selected execution backend and should hold the
63
- # agent's durable role, priorities, and behavioral guardrails rather than bulky project facts.
64
- systemPrompt: |-
65
- You are the orchestra agent.
16
+ execution:
17
+ # Current backend adapter for this host profile.
18
+ backend: deepagent
19
+ # Upstream execution feature: model ref for the underlying LLM used by this execution host.
20
+ modelRef: model/default
21
+ memory:
22
+ # Upstream execution feature: bootstrap memory sources supplied to the selected backend at construction time.
23
+ # These paths resolve relative to the workspace root unless they are already absolute.
24
+ # Treat this as agent-owned startup context, not as a dynamic long-term memory sink:
25
+ # - keep `systemPrompt` for stable role, boundaries, and hard behavioral rules
26
+ # - use `memory:` for stable project knowledge, operating conventions, and shared or agent-specific context files
27
+ # - use `/memories/*` via the backend/store below for durable knowledge learned from prior runs
28
+ # - use the harness checkpointer for resumable graph state for an in-flight run
29
+ # Updating these files changes future agent constructions, but they are still bootstrap inputs rather than
30
+ # self-updating runtime memory.
31
+ - path: config/agent-context.md
32
+ config:
33
+ # Runtime execution feature: checkpointer config passed into the selected backend adapter.
34
+ # This persists resumable graph state for this agent.
35
+ # Available `kind` options in this harness: `FileCheckpointer`, `MemorySaver`, `SqliteSaver`.
36
+ # `path` is only used by `FileCheckpointer` and `SqliteSaver`; omit it for `MemorySaver`.
37
+ checkpointer:
38
+ # ref: checkpointer/sqlite
39
+ ref: checkpointer/default
40
+ # Upstream execution feature: store config passed into the selected backend adapter.
41
+ # In the default deepagent adapter this is the LangGraph store used by `StoreBackend` routes.
42
+ # Available `kind` options in this harness: `FileStore`, `InMemoryStore`, `RedisStore`, `PostgresStore`.
43
+ store:
44
+ ref: store/default
45
+ # Upstream execution feature: backend config passed into the selected backend adapter.
46
+ # This directly defines the backend topology for this agent:
47
+ # - workspace execution uses a lightweight VFS sandbox
48
+ # - long-term memory under `/memories/*` uses `StoreBackend`
49
+ # - `CompositeBackend` composes those backend instances together
50
+ # The harness also injects a persistent file-backed store and a file-backed checkpointer so that
51
+ # `/memories/*` and resumable run state survive restarts in the default setup.
52
+ # Available top-level `kind` options in this harness: `CompositeBackend`, `StateBackend`, `StoreBackend`.
53
+ backend:
54
+ kind: CompositeBackend
55
+ state:
56
+ # Available state backend `kind` options today: `StateBackend`, `LocalShellBackend`, `VfsSandbox`.
57
+ kind: VfsSandbox
58
+ timeout: 600
59
+ routes:
60
+ /memories/:
61
+ # Available route backend `kind` options today: `StoreBackend`.
62
+ kind: StoreBackend
63
+ # Upstream execution feature: system prompt for the orchestration host.
64
+ # This becomes the top-level instruction block for the selected execution backend and should hold the
65
+ # agent's durable role, priorities, and behavioral guardrails rather than bulky project facts.
66
+ systemPrompt: |-
67
+ You are the orchestra agent.
66
68
 
67
- You are the default execution host.
68
- Try to finish the request yourself before delegating.
69
- Use your own tools first when they are sufficient.
70
- Use your own skills first when they are sufficient.
71
- Delegate only when a specialist is a clearly better fit or when your own tools and skills are not enough.
72
- If neither you nor any suitable specialist can do the work, say so plainly.
69
+ You are the default execution host.
70
+ Try to finish the request yourself before delegating.
71
+ Use your own tools first when they are sufficient.
72
+ Use your own skills first when they are sufficient.
73
+ Delegate only when a specialist is a clearly better fit or when your own tools and skills are not enough.
74
+ If neither you nor any suitable specialist can do the work, say so plainly.
73
75
 
74
- Do not delegate by reflex.
75
- Do not delegate just because a task has multiple steps.
76
- Do not delegate when a direct answer or a short local tool pass is enough.
77
- Keep the critical path local when immediate progress depends on it; otherwise delegate bounded sidecar work to
78
- the most appropriate specialist.
76
+ Do not delegate by reflex.
77
+ Do not delegate just because a task has multiple steps.
78
+ Do not delegate when a direct answer or a short local tool pass is enough.
79
+ Keep the critical path local when immediate progress depends on it; otherwise delegate bounded sidecar work to
80
+ the most appropriate specialist.
79
81
 
80
- Use your own tools for lightweight discovery, inventory, and context gathering.
81
- Prefer the structured checkout, indexing, retrieval, and inventory tools that are already attached to you over
82
- ad hoc shell work when those tools are sufficient.
83
- Use the attached specialist descriptions as the source of truth for what each specialist is for.
84
- Do not delegate to a specialist whose description does not clearly match the task.
85
- Integrate specialist results into one coherent answer and do not claim checks or evidence you did not obtain.
82
+ Use your own tools for lightweight discovery, inventory, and context gathering.
83
+ Prefer the structured checkout, indexing, retrieval, and inventory tools that are already attached to you over
84
+ ad hoc shell work when those tools are sufficient.
85
+ Use the attached specialist descriptions as the source of truth for what each specialist is for.
86
+ Do not delegate to a specialist whose description does not clearly match the task.
87
+ Integrate specialist results into one coherent answer and do not claim checks or evidence you did not obtain.
86
88
 
87
- When the user asks about available tools, skills, or agents, use the attached inventory tools instead of
88
- inferring from memory.
89
+ When the user asks about available tools, skills, or agents, use the attached inventory tools instead of
90
+ inferring from memory.
89
91
 
90
- Write to `/memories/*` only when the information is durable, reusable across future runs or threads, and likely
91
- to matter again: user preferences, project conventions, confirmed decisions, reusable summaries, and stable
92
- ownership facts are good candidates.
93
- Do not store transient reasoning, temporary plans, scratch work, one-off search results, or intermediate
94
- outputs that can be cheaply recomputed.
92
+ Write to `/memories/*` only when the information is durable, reusable across future runs or threads, and likely
93
+ to matter again: user preferences, project conventions, confirmed decisions, reusable summaries, and stable
94
+ ownership facts are good candidates.
95
+ Do not store transient reasoning, temporary plans, scratch work, one-off search results, or intermediate
96
+ outputs that can be cheaply recomputed.
@@ -95,6 +95,7 @@ export type LangChainAgentParams = {
95
95
  stateSchema?: unknown;
96
96
  responseFormat?: unknown;
97
97
  contextSchema?: unknown;
98
+ filesystem?: Record<string, unknown>;
98
99
  middleware?: Array<Record<string, unknown>>;
99
100
  passthrough?: Record<string, unknown>;
100
101
  subagents?: CompiledSubAgent[];
@@ -1 +1 @@
1
- export declare const AGENT_HARNESS_VERSION = "0.0.49";
1
+ export declare const AGENT_HARNESS_VERSION = "0.0.50";
@@ -1 +1 @@
1
- export const AGENT_HARNESS_VERSION = "0.0.49";
1
+ export const AGENT_HARNESS_VERSION = "0.0.50";
@@ -1,3 +1,4 @@
1
+ import path from "node:path";
1
2
  import { Command, MemorySaver } from "@langchain/langgraph";
2
3
  import { tool as createLangChainTool } from "@langchain/core/tools";
3
4
  import { createDeepAgent, createMemoryMiddleware, createSkillsMiddleware, createSubAgentMiddleware, FilesystemBackend, } from "deepagents";
@@ -475,10 +476,20 @@ export class AgentRuntimeAdapter {
475
476
  return this.compileInterruptOn(getBindingPrimaryTools(binding), getBindingInterruptCompatibilityRules(binding));
476
477
  }
477
478
  resolveFilesystemBackend(binding) {
479
+ const filesystemConfig = getBindingLangChainParams(binding)?.filesystem;
480
+ const configuredRootDir = typeof filesystemConfig?.rootDir === "string" && filesystemConfig.rootDir.trim().length > 0
481
+ ? filesystemConfig.rootDir
482
+ : undefined;
483
+ const workspaceRoot = binding.harnessRuntime.workspaceRoot;
484
+ const rootDir = configuredRootDir
485
+ ? (path.isAbsolute(configuredRootDir) ? configuredRootDir : path.resolve(workspaceRoot ?? process.cwd(), configuredRootDir))
486
+ : workspaceRoot ?? process.cwd();
478
487
  return new FilesystemBackend({
479
- rootDir: "/",
480
- virtualMode: false,
481
- maxFileSizeMb: 10,
488
+ rootDir,
489
+ virtualMode: filesystemConfig?.virtualMode === true,
490
+ maxFileSizeMb: typeof filesystemConfig?.maxFileSizeMb === "number" && Number.isFinite(filesystemConfig.maxFileSizeMb)
491
+ ? filesystemConfig.maxFileSizeMb
492
+ : 10,
482
493
  });
483
494
  }
484
495
  async resolveLangChainAutomaticMiddleware(binding) {
@@ -245,6 +245,9 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
245
245
  stateSchema: agent.langchainAgentConfig?.stateSchema,
246
246
  responseFormat: agent.langchainAgentConfig?.responseFormat,
247
247
  contextSchema: agent.langchainAgentConfig?.contextSchema,
248
+ filesystem: typeof agent.langchainAgentConfig?.filesystem === "object" && agent.langchainAgentConfig.filesystem
249
+ ? { ...agent.langchainAgentConfig.filesystem }
250
+ : undefined,
248
251
  middleware: compileMiddlewareConfigs(agent.langchainAgentConfig?.middleware, models, agent.id),
249
252
  passthrough: typeof agent.langchainAgentConfig?.passthrough === "object" && agent.langchainAgentConfig.passthrough
250
253
  ? { ...agent.langchainAgentConfig.passthrough }
@@ -61,6 +61,11 @@ function toArray(value) {
61
61
  function asObject(value) {
62
62
  return typeof value === "object" && value ? value : undefined;
63
63
  }
64
+ function asMutableObject(value) {
65
+ return typeof value === "object" && value !== null && !Array.isArray(value)
66
+ ? { ...value }
67
+ : undefined;
68
+ }
64
69
  function normalizeCatalogSpec(document, options = {}) {
65
70
  const typed = asObject(document);
66
71
  const spec = typed?.spec;
@@ -211,9 +216,14 @@ function readCapabilities(value) {
211
216
  return Object.keys(capabilities).length > 0 ? capabilities : undefined;
212
217
  }
213
218
  function readExecutionConfig(value) {
214
- return typeof value === "object" && value !== null && !Array.isArray(value)
215
- ? { ...value }
216
- : undefined;
219
+ return asMutableObject(value);
220
+ }
221
+ function readExecutionAgentConfig(item) {
222
+ const execution = readExecutionConfig(item.execution);
223
+ return asMutableObject(execution?.config) ?? {};
224
+ }
225
+ function readRuntimeConfig(item) {
226
+ return asMutableObject(item.runtime);
217
227
  }
218
228
  function cloneConfigValue(value) {
219
229
  if (Array.isArray(value)) {
@@ -245,21 +255,42 @@ function resolveExecutionBackend(item, current) {
245
255
  }
246
256
  return undefined;
247
257
  }
248
- function readSharedAgentConfig(item) {
249
- const middleware = readMiddlewareArray(item.middleware);
250
- const passthrough = readPassthroughConfig(item, [
251
- "id",
252
- "kind",
253
- "description",
254
- "modelRef",
255
- "runRoot",
256
- "tools",
257
- "mcpServers",
258
- "skills",
259
- "memory",
260
- "subagents",
261
- "execution",
262
- "capabilities",
258
+ function readExecutionSingleRef(item, key) {
259
+ const execution = readExecutionConfig(item.execution);
260
+ return readSingleRef(execution?.[key]);
261
+ }
262
+ function readExecutionRefArray(item, key) {
263
+ const execution = readExecutionConfig(item.execution);
264
+ return readRefArray(execution?.[key]);
265
+ }
266
+ function readExecutionPathArray(item, key) {
267
+ const execution = readExecutionConfig(item.execution);
268
+ return readPathArray(execution?.[key]);
269
+ }
270
+ function readExecutionObjectArray(item, key) {
271
+ const execution = readExecutionConfig(item.execution);
272
+ return readObjectArray(execution?.[key]);
273
+ }
274
+ function readSharedAgentConfig(config) {
275
+ const middleware = readMiddlewareArray(config.middleware);
276
+ return {
277
+ ...(typeof config.systemPrompt === "string" ? { systemPrompt: config.systemPrompt } : {}),
278
+ ...((typeof config.checkpointer === "object" && config.checkpointer) || typeof config.checkpointer === "boolean"
279
+ ? { checkpointer: config.checkpointer }
280
+ : {}),
281
+ ...(typeof config.interruptOn === "object" && config.interruptOn ? { interruptOn: config.interruptOn } : {}),
282
+ ...(config.stateSchema !== undefined ? { stateSchema: config.stateSchema } : {}),
283
+ ...(config.responseFormat !== undefined ? { responseFormat: config.responseFormat } : {}),
284
+ ...(config.contextSchema !== undefined ? { contextSchema: config.contextSchema } : {}),
285
+ ...(config.includeAgentName === "inline" ? { includeAgentName: "inline" } : {}),
286
+ ...(config.version === "v1" || config.version === "v2" ? { version: config.version } : {}),
287
+ ...(typeof config.filesystem === "object" && config.filesystem ? { filesystem: config.filesystem } : {}),
288
+ ...(middleware ? { middleware } : {}),
289
+ };
290
+ }
291
+ function readLangchainAgentConfig(item) {
292
+ const config = readExecutionAgentConfig(item);
293
+ const passthrough = readPassthroughConfig(config, [
263
294
  "systemPrompt",
264
295
  "checkpointer",
265
296
  "interruptOn",
@@ -273,43 +304,48 @@ function readSharedAgentConfig(item) {
273
304
  "store",
274
305
  "taskDescription",
275
306
  "generalPurposeAgent",
307
+ "filesystem",
276
308
  ]);
277
309
  return {
278
- ...(typeof item.systemPrompt === "string" ? { systemPrompt: item.systemPrompt } : {}),
279
- ...((typeof item.checkpointer === "object" && item.checkpointer) || typeof item.checkpointer === "boolean"
280
- ? { checkpointer: item.checkpointer }
281
- : {}),
282
- ...(typeof item.interruptOn === "object" && item.interruptOn ? { interruptOn: item.interruptOn } : {}),
283
- ...(item.stateSchema !== undefined ? { stateSchema: item.stateSchema } : {}),
284
- ...(item.responseFormat !== undefined ? { responseFormat: item.responseFormat } : {}),
285
- ...(item.contextSchema !== undefined ? { contextSchema: item.contextSchema } : {}),
286
- ...(item.includeAgentName === "inline" ? { includeAgentName: "inline" } : {}),
287
- ...(item.version === "v1" || item.version === "v2" ? { version: item.version } : {}),
288
- ...(middleware ? { middleware } : {}),
310
+ ...readSharedAgentConfig(config),
311
+ ...(typeof config.store === "object" && config.store ? { store: config.store } : {}),
312
+ ...(typeof config.taskDescription === "string" && config.taskDescription.trim() ? { taskDescription: config.taskDescription } : {}),
313
+ ...(typeof config.generalPurposeAgent === "boolean" ? { generalPurposeAgent: config.generalPurposeAgent } : {}),
289
314
  ...(passthrough ? { passthrough } : {}),
290
315
  };
291
316
  }
292
- function readLangchainAgentConfig(item) {
293
- return {
294
- ...readSharedAgentConfig(item),
295
- ...(typeof item.store === "object" && item.store ? { store: item.store } : {}),
296
- ...(typeof item.taskDescription === "string" && item.taskDescription.trim() ? { taskDescription: item.taskDescription } : {}),
297
- ...(typeof item.generalPurposeAgent === "boolean" ? { generalPurposeAgent: item.generalPurposeAgent } : {}),
298
- };
299
- }
300
317
  function readDeepAgentConfig(item) {
318
+ const config = readExecutionAgentConfig(item);
319
+ const passthrough = readPassthroughConfig(config, [
320
+ "systemPrompt",
321
+ "checkpointer",
322
+ "interruptOn",
323
+ "stateSchema",
324
+ "responseFormat",
325
+ "contextSchema",
326
+ "includeAgentName",
327
+ "version",
328
+ "middleware",
329
+ "backend",
330
+ "store",
331
+ "taskDescription",
332
+ "generalPurposeAgent",
333
+ "filesystem",
334
+ ]);
301
335
  return {
302
- ...readSharedAgentConfig(item),
303
- ...(typeof item.backend === "object" && item.backend ? { backend: item.backend } : {}),
304
- ...(typeof item.store === "object" && item.store ? { store: item.store } : {}),
305
- ...(typeof item.taskDescription === "string" && item.taskDescription.trim() ? { taskDescription: item.taskDescription } : {}),
306
- ...(typeof item.generalPurposeAgent === "boolean" ? { generalPurposeAgent: item.generalPurposeAgent } : {}),
336
+ ...readSharedAgentConfig(config),
337
+ ...(typeof config.backend === "object" && config.backend ? { backend: config.backend } : {}),
338
+ ...(typeof config.store === "object" && config.store ? { store: config.store } : {}),
339
+ ...(typeof config.taskDescription === "string" && config.taskDescription.trim() ? { taskDescription: config.taskDescription } : {}),
340
+ ...(typeof config.generalPurposeAgent === "boolean" ? { generalPurposeAgent: config.generalPurposeAgent } : {}),
341
+ ...(passthrough ? { passthrough } : {}),
307
342
  };
308
343
  }
309
344
  export function parseAgentItem(item, sourcePath) {
310
- const subagentRefs = readRefArray(item.subagents);
311
- const subagentPathRefs = readPathArray(item.subagents);
345
+ const subagentRefs = readExecutionRefArray(item, "subagents");
346
+ const subagentPathRefs = readExecutionPathArray(item, "subagents");
312
347
  const executionMode = String(resolveExecutionBackend(item) ?? "deepagent");
348
+ const runtime = readRuntimeConfig(item);
313
349
  return {
314
350
  id: String(item.id),
315
351
  executionMode: executionMode,
@@ -317,12 +353,12 @@ export function parseAgentItem(item, sourcePath) {
317
353
  ? { delegation: true, memory: true }
318
354
  : { delegation: true, memory: true }),
319
355
  description: String(item.description ?? ""),
320
- modelRef: readSingleRef(item.modelRef) ?? "",
321
- runRoot: typeof item.runRoot === "string" ? item.runRoot : undefined,
322
- toolRefs: readRefArray(item.tools),
323
- mcpServers: readObjectArray(item.mcpServers),
324
- skillPathRefs: readPathArray(item.skills),
325
- memorySources: readPathArray(item.memory),
356
+ modelRef: readExecutionSingleRef(item, "modelRef") ?? "",
357
+ runRoot: typeof runtime?.runRoot === "string" ? runtime.runRoot : undefined,
358
+ toolRefs: readExecutionRefArray(item, "tools"),
359
+ mcpServers: readExecutionObjectArray(item, "mcpServers"),
360
+ skillPathRefs: readExecutionPathArray(item, "skills"),
361
+ memorySources: readExecutionPathArray(item, "memory"),
326
362
  subagentRefs,
327
363
  subagentPathRefs,
328
364
  langchainAgentConfig: readLangchainAgentConfig(item),
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botbotgo/agent-harness",
3
- "version": "0.0.50",
3
+ "version": "0.0.51",
4
4
  "description": "Workspace runtime for multi-agent applications",
5
5
  "type": "module",
6
6
  "packageManager": "npm@10.9.2",