@botbotgo/agent-harness 0.0.55 → 0.0.57

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
@@ -1,15 +1,42 @@
1
+ <p align="center">
2
+ <img src="./docs/assets/readme-icon.png" width="120" alt="botbotgo runtime icon" />
3
+ </p>
4
+
5
+ <p align="center">
6
+ <img src="./docs/assets/readme-banner.png" alt="botbotgo runtime banner" />
7
+ </p>
8
+
1
9
  # @botbotgo/agent-harness
2
10
 
11
+ <p align="center">
12
+ <strong>A workspace-shaped runtime for agent systems that need to keep running after the demo.</strong>
13
+ </p>
14
+
15
+ <p align="center">
16
+ <strong>botbotgo</strong> is the brand. <strong>agent-harness</strong> is the product.
17
+ </p>
18
+
19
+ <p align="center">
20
+ <a href="https://botbotgo.github.io/agent-harness/">Product website</a>
21
+ (static page in <code>docs/</code>, publish with GitHub Pages)
22
+ </p>
23
+
3
24
  ## Product Overview
4
25
 
5
26
  `@botbotgo/agent-harness` is a workspace-shaped application runtime for real agent products.
6
27
 
7
28
  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
29
 
30
+ The point is simple:
31
+
32
+ - Codex, Claude Code, and Cursor are products for people using agents
33
+ - LangChain v1 and DeepAgents are frameworks for defining agent execution semantics
34
+ - `agent-harness` is the runtime product layer for shipping, operating, recovering, and governing multi-agent applications
35
+
9
36
  The product boundary is strict:
10
37
 
11
38
  - LangChain v1 and DeepAgents own agent execution semantics
12
- - `agent-harness` owns application-level orchestration and lifecycle management stays in the harness
39
+ - application-level orchestration and lifecycle management stays in the harness
13
40
 
14
41
  That means:
15
42
 
@@ -18,13 +45,7 @@ That means:
18
45
  - runtime lifecycle stays stable even if backend implementations change
19
46
  - backend internals stay behind adapters
20
47
 
21
- The repository also keeps two boundary documents current:
22
-
23
- - `docs/upstream-feature-matrix.md`
24
- - `docs/product-boundary.md`
25
- - `docs/feature-checklist.md`
26
-
27
- What the runtime provides:
48
+ The runtime provides:
28
49
 
29
50
  - `createAgentHarness(workspaceRoot)`, `run(...)`, `resolveApproval(...)`, `subscribe(...)`, inspection methods, and `stop(...)`
30
51
  - YAML-defined workspace assembly for routing, models, tools, stores, backends, MCP, recovery, and maintenance
@@ -32,6 +53,40 @@ What the runtime provides:
32
53
  - local `resources/tools/` and `resources/skills/` discovery
33
54
  - persisted threads, runs, approvals, events, queue state, and recovery metadata
34
55
 
56
+ The repository-owned default config layer is intentionally full-shaped. The shipped YAML keeps explicit defaults for the important runtime and agent knobs so teams can start from concrete config instead of reverse-engineering adapter behavior from source.
57
+
58
+ The default rule is:
59
+
60
+ - if LangChain v1 or DeepAgents already has the feature, map it in YAML and adapt it internally
61
+ - do not add a new public runtime API unless the problem is truly runtime-owned
62
+
63
+ Boundary documents live in:
64
+
65
+ - `docs/upstream-feature-matrix.md`
66
+ - `docs/product-boundary.md`
67
+ - `docs/feature-checklist.md`
68
+
69
+ ## Why This Exists
70
+
71
+ Most agent demos stop at execution.
72
+
73
+ Real products need a runtime that can answer harder questions:
74
+
75
+ - Where do runs live?
76
+ - How are approvals resolved?
77
+ - What survives process restart?
78
+ - How do you inspect threads and events without exposing raw backend state?
79
+ - How do you swap backend implementations without rewriting the product model?
80
+
81
+ `agent-harness` is the layer that answers those questions without turning your application API into a mirror of LangChain v1 or DeepAgents.
82
+
83
+ ## What Makes It Different
84
+
85
+ - It treats `runs`, `threads`, `approvals`, `events`, and recovery as product concepts
86
+ - It keeps checkpoint resume system-managed instead of promoting checkpoint internals into the primary API
87
+ - It lets YAML own assembly complexity while code keeps a tiny surface
88
+ - It goes deep on runtime concerns that upstream libraries do not fully productize
89
+
35
90
  ## Quick Start
36
91
 
37
92
  Install:
@@ -82,6 +137,13 @@ try {
82
137
  }
83
138
  ```
84
139
 
140
+ If you want the shortest possible mental model:
141
+
142
+ - one workspace becomes one runtime
143
+ - YAML defines assembly and policy
144
+ - `run(runtime, { ... })` executes requests against that runtime
145
+ - the runtime owns lifecycle, inspection, and recovery
146
+
85
147
  ## Feature List
86
148
 
87
149
  - Workspace runtime for multi-agent applications
@@ -96,13 +158,12 @@ try {
96
158
  - MCP bridge support for agent-declared MCP servers
97
159
  - MCP server support for exposing harness tools outward
98
160
 
99
- ## Design Notes
161
+ ### Runtime Strengths
100
162
 
101
- - `agent-harness` is not a third agent framework
102
- - LangChain v1 and DeepAgents own agent execution semantics
103
- - `agent-harness` owns workspace assembly, runtime lifecycle, approvals, inspection, recovery, and operations
104
- - when upstream already has the feature, prefer passthrough or light YAML adaptation over a new harness abstraction
105
- - when a feature can be expressed in YAML, prefer YAML over expanding the public API
163
+ - Stable product-facing API even when backend details evolve
164
+ - Strong separation between public runtime contract and backend adapter contract
165
+ - Clear YAML ownership for routing, topology, policy, and infrastructure objects
166
+ - Better fit for long-running, approval-heavy, multi-agent products than a thin agent loop wrapper
106
167
 
107
168
  ## How To Use
108
169
 
@@ -114,7 +175,7 @@ import { AgentHarnessRuntime, createAgentHarness } from "@botbotgo/agent-harness
114
175
  const runtime: AgentHarnessRuntime = await createAgentHarness("/absolute/path/to/workspace");
115
176
  ```
116
177
 
117
- `createAgentHarness(...)` loads one workspace, resolves `resources/`, initializes persistence under `runRoot`, and starts runtime maintenance.
178
+ `createAgentHarness(...)` loads the workspace, resolves `resources/`, initializes persistence under `runRoot`, and starts runtime maintenance.
118
179
 
119
180
  ### Run A Request
120
181
 
@@ -138,7 +199,7 @@ const result = await run(runtime, {
138
199
  });
139
200
  ```
140
201
 
141
- `run(runtime, { ... })` creates or continues a persisted thread and returns `threadId`, `runId`, `state`, and a compact text `output`. Richer upstream results remain available through `outputContent`, `contentBlocks`, and `structuredResponse` without expanding the main facade.
202
+ `run(runtime, { ... })` creates or continues a persisted thread and returns `threadId`, `runId`, `state`, and compact text `output`. Richer upstream result shapes stay available through `outputContent`, `contentBlocks`, and `structuredResponse`.
142
203
 
143
204
  Use `invocation` as the runtime-facing request envelope:
144
205
 
@@ -177,7 +238,7 @@ const result = await run(runtime, {
177
238
  });
178
239
  ```
179
240
 
180
- `subscribe(...)` is a read-only observer surface over stored lifecycle events.
241
+ `subscribe(...)` is the read-only observer surface over stored lifecycle events.
181
242
 
182
243
  The runtime event stream includes:
183
244
 
@@ -213,9 +274,11 @@ if (approval) {
213
274
  }
214
275
  ```
215
276
 
216
- These methods return runtime-facing records, not raw persistence or backend checkpoint objects.
277
+ These methods return runtime-facing records, not raw checkpoint or backend objects.
278
+
279
+ ### Expose And Consume MCP
217
280
 
218
- ### Bridge MCP Servers Into Agents
281
+ Bridge MCP servers into agents:
219
282
 
220
283
  ```yaml
221
284
  apiVersion: agent-harness/v1alpha1
@@ -232,9 +295,7 @@ spec:
232
295
  args: ["./mcp-browser-server.mjs"]
233
296
  ```
234
297
 
235
- The runtime discovers MCP tools, filters them through agent configuration, and exposes them like other tools.
236
-
237
- ### Expose Runtime Tools As An MCP Server
298
+ Expose harness tools as an MCP server:
238
299
 
239
300
  ```ts
240
301
  import { createToolMcpServer, serveToolsOverStdio } from "@botbotgo/agent-harness";
@@ -256,7 +317,7 @@ await stop(runtime);
256
317
  Use Kubernetes-style YAML:
257
318
 
258
319
  - collection files use `apiVersion`, plural `kind`, and `spec: []`
259
- - single-object files use `apiVersion`, singular `kind`, `metadata`, and `spec`
320
+ - singleton files use `apiVersion`, singular `kind`, `metadata`, and `spec`
260
321
 
261
322
  Core workspace files:
262
323
 
@@ -274,19 +335,17 @@ Core workspace files:
274
335
  - `resources/tools/`
275
336
  - `resources/skills/`
276
337
 
277
- There are three configuration layers:
338
+ There are three main configuration layers:
278
339
 
279
340
  - runtime policy in `config/workspace.yaml`
280
341
  - reusable object catalogs in `config/*.yaml`
281
342
  - agent assembly in `config/agents/*.yaml`
282
343
 
283
- The repository-owned default config layer is intentionally full-shaped. The shipped YAML keeps explicit default values for the main runtime knobs so teams can start from concrete config instead of reconstructing adapter defaults from code.
284
-
285
344
  ### `config/workspace.yaml`
286
345
 
287
- Use this file for runtime-level policy shared by the whole workspace.
346
+ Use this file for workspace-wide runtime policy.
288
347
 
289
- Primary fields:
348
+ Important fields:
290
349
 
291
350
  - `runRoot`
292
351
  - `concurrency.maxConcurrentRuns`
@@ -299,13 +358,36 @@ Primary fields:
299
358
  - `recovery.resumeResumingRunsOnStartup`
300
359
  - `recovery.maxRecoveryAttempts`
301
360
 
302
- If `runRoot` is omitted, the runtime defaults to `<workspace-root>/run-data`.
361
+ `recovery.resumeResumingRunsOnStartup` keeps checkpoint resume a runtime-owned lifecycle behavior instead of exposing checkpoint orchestration as public API.
362
+
363
+ Example:
364
+
365
+ ```yaml
366
+ apiVersion: agent-harness/v1alpha1
367
+ kind: Runtime
368
+ metadata:
369
+ name: default
370
+ spec:
371
+ runRoot: ./.agent
372
+ concurrency:
373
+ maxConcurrentRuns: 3
374
+ routing:
375
+ defaultAgentId: orchestra
376
+ modelRouting: false
377
+ maintenance:
378
+ checkpoints:
379
+ enabled: true
380
+ recovery:
381
+ enabled: true
382
+ resumeResumingRunsOnStartup: true
383
+ maxRecoveryAttempts: 3
384
+ ```
303
385
 
304
386
  ### `config/agent-context.md`
305
387
 
306
- Use this file for shared bootstrap context loaded into agents at construction time.
388
+ Use this file for shared bootstrap memory loaded at agent construction time.
307
389
 
308
- Put stable project context here. Do not use it as mutable long-term memory.
390
+ Keep stable project context here. Treat it as startup context, not mutable long-term memory.
309
391
 
310
392
  ### `config/models.yaml`
311
393
 
@@ -354,7 +436,7 @@ spec:
354
436
 
355
437
  ### `config/backends.yaml`
356
438
 
357
- Use reusable DeepAgent backend presets so filesystem and long-term memory topology stays in YAML instead of application code:
439
+ Use reusable DeepAgents backend presets so filesystem and `/memories/*` topology stays in YAML:
358
440
 
359
441
  ```yaml
360
442
  apiVersion: agent-harness/v1alpha1
@@ -377,9 +459,7 @@ spec:
377
459
 
378
460
  Use this file for reusable tool objects.
379
461
 
380
- Supported tool families in the built-in runtime include function tools, backend tools, MCP tools, provider-native tools, and bundles.
381
-
382
- Provider-native tools are declared in YAML and resolved directly to upstream provider tool factories.
462
+ Built-in tool families include function tools, backend tools, MCP tools, bundles, and provider-native tools. Provider-native tools are declared in YAML and resolved directly to upstream factories.
383
463
 
384
464
  ### `config/mcp.yaml`
385
465
 
@@ -387,16 +467,14 @@ Use this file for named MCP server presets.
387
467
 
388
468
  ### `config/agents/*.yaml`
389
469
 
390
- Agents are always declared with `kind: Agent` and `spec.execution.backend`.
470
+ Agents always use `kind: Agent` plus `spec.execution.backend`.
391
471
 
392
- Use two nested sections inside each agent:
472
+ Use two nested sections:
393
473
 
394
474
  - `spec.runtime` for harness-owned runtime placement such as `spec.runtime.runRoot`
395
475
  - `spec.execution` for upstream execution semantics and adapter-facing config
396
476
 
397
- This keeps the public product model small while letting LangChain v1 and DeepAgents concepts pass through with minimal translation.
398
-
399
- Example lightweight host:
477
+ Example direct host:
400
478
 
401
479
  ```yaml
402
480
  apiVersion: agent-harness/v1alpha1
@@ -420,11 +498,15 @@ spec:
420
498
  store:
421
499
  ref: store/default
422
500
  interruptOn: {}
501
+ filesystem:
502
+ rootDir: .
503
+ virtualMode: true
504
+ maxFileSizeMb: 10
423
505
  middleware: []
424
506
  systemPrompt: Answer simple requests directly.
425
507
  ```
426
508
 
427
- Example main execution host:
509
+ Example orchestra host:
428
510
 
429
511
  ```yaml
430
512
  apiVersion: agent-harness/v1alpha1
@@ -453,36 +535,29 @@ spec:
453
535
  interruptOn: {}
454
536
  middleware: []
455
537
  generalPurposeAgent: true
456
- taskDescription: Complete delegated sidecar work and return concise results.
538
+ taskDescription: Complete delegated sidecar work and return concise results without bloating the parent context.
457
539
  ```
458
540
 
459
- For backend-specific agent options, prefer the upstream concept directly inside `spec.execution.config`. Upstream feature coverage is tracked in [docs/upstream-feature-matrix.md](docs/upstream-feature-matrix.md).
460
-
461
- ### `resources/`
462
-
463
- Use `resources/` for executable local extensions:
464
-
465
- - `resources/tools/` for tool modules
466
- - `resources/skills/` for SKILL packages
467
-
468
- Tool modules are discovered from `resources/tools/*.js`, `resources/tools/*.mjs`, and `resources/tools/*.cjs`.
541
+ For backend-specific options, prefer the upstream concept directly inside `spec.execution.config`. Upstream feature coverage is tracked in [docs/upstream-feature-matrix.md](docs/upstream-feature-matrix.md).
469
542
 
470
543
  ## Design Notes
471
544
 
545
+ - `agent-harness` is not a third agent framework
472
546
  - public runtime contract stays generic and small
473
547
  - application-level orchestration and lifecycle management stays in the harness
474
548
  - upstream LangChain v1 and DeepAgents concepts should be expressed as directly as possible in YAML
475
- - recovery, approvals, threads, runs, and events are runtime concepts, not backend-specific escape hatches
476
- - backend implementation details should stay internal unless product requirements force exposure
477
- - new LangChain v1 or DeepAgents public config should land in YAML passthrough and compatibility tests before adding new public runtime APIs
549
+ - when a feature can be expressed in YAML, prefer YAML over expanding the public API
550
+ - recovery, approvals, threads, runs, and events are runtime concepts, not backend escape hatches
551
+ - new LangChain v1 or DeepAgents config should land in YAML mapping and tests before adding public runtime APIs
478
552
 
479
- In short: `agent-harness` is a public runtime contract generic enough to survive backend changes, while the deep execution semantics stay upstream.
553
+ In short, the product model stays stable while the execution semantics remain upstream-owned.
480
554
 
481
555
  ## API Summary
482
556
 
483
557
  Primary exports:
484
558
 
485
559
  - `createAgentHarness`
560
+ - `AgentHarnessRuntime`
486
561
  - `run`
487
562
  - `resolveApproval`
488
563
  - `subscribe`
package/dist/api.d.ts CHANGED
@@ -1,5 +1,7 @@
1
1
  import type { ApprovalRecord, RunOptions, ResumeOptions, RuntimeAdapterOptions, ThreadSummary, ThreadRecord, WorkspaceLoadOptions } from "./contracts/types.js";
2
2
  import { AgentHarnessRuntime } from "./runtime/harness.js";
3
+ import type { InventoryAgentRecord, InventorySkillRecord } from "./runtime/inventory.js";
4
+ import type { RequirementAssessmentOptions } from "./runtime/skill-requirements.js";
3
5
  import type { ToolMcpServerOptions } from "./mcp.js";
4
6
  export { AgentHarnessRuntime } from "./runtime/harness.js";
5
7
  type CreateAgentHarnessOptions = {
@@ -15,6 +17,11 @@ export declare function getThread(runtime: AgentHarnessRuntime, threadId: string
15
17
  export declare function deleteThread(runtime: AgentHarnessRuntime, threadId: string): Promise<boolean>;
16
18
  export declare function listApprovals(runtime: AgentHarnessRuntime, filter?: Parameters<AgentHarnessRuntime["listApprovals"]>[0]): Promise<ApprovalRecord[]>;
17
19
  export declare function getApproval(runtime: AgentHarnessRuntime, approvalId: string): Promise<ApprovalRecord | null>;
20
+ export declare function listAgentSkills(runtime: AgentHarnessRuntime, agentId: string, options?: RequirementAssessmentOptions): InventorySkillRecord[];
21
+ export declare function describeInventory(runtime: AgentHarnessRuntime, options?: RequirementAssessmentOptions): {
22
+ workspaceRoot: string;
23
+ agents: InventoryAgentRecord[];
24
+ };
18
25
  export declare function resolveApproval(runtime: AgentHarnessRuntime, options: ResumeOptions): Promise<import("./contracts/types.js").RunResult>;
19
26
  export declare function stop(runtime: AgentHarnessRuntime): Promise<void>;
20
27
  export declare function createToolMcpServer(runtime: AgentHarnessRuntime, options: ToolMcpServerOptions): Promise<import("@modelcontextprotocol/sdk/server/mcp.js").McpServer>;
package/dist/api.js CHANGED
@@ -28,6 +28,12 @@ export async function listApprovals(runtime, filter) {
28
28
  export async function getApproval(runtime, approvalId) {
29
29
  return runtime.getApproval(approvalId);
30
30
  }
31
+ export function listAgentSkills(runtime, agentId, options) {
32
+ return runtime.listAgentSkills(agentId, options);
33
+ }
34
+ export function describeInventory(runtime, options) {
35
+ return runtime.describeWorkspaceInventory(options);
36
+ }
31
37
  export async function resolveApproval(runtime, options) {
32
38
  return runtime.resume(options);
33
39
  }
@@ -46,7 +46,25 @@ spec:
46
46
  ref: store/default
47
47
  # Upstream execution feature: no declarative HITL tool routing by default.
48
48
  interruptOn: {}
49
+ # Upstream execution feature: filesystem middleware settings for LangChain v1 agents.
50
+ # This only becomes active when `middleware` includes `{ kind: filesystem }`, or when
51
+ # automatic upstream middleware such as skills or memory need a filesystem backend.
52
+ # Keep the default root inside the workspace so file-aware middleware stays bounded.
53
+ filesystem:
54
+ rootDir: .
55
+ virtualMode: true
56
+ maxFileSizeMb: 10
49
57
  # Upstream execution feature: no extra declarative middleware beyond the runtime's automatic injections.
58
+ # Common upstream middleware kinds that this harness can compile directly from YAML:
59
+ # - `filesystem`
60
+ # - `patchToolCalls`
61
+ # - `summarization`
62
+ # - `dynamicSystemPrompt`
63
+ # - `humanInTheLoop`
64
+ # - `todoList`
65
+ # - `pii`, `piiRedaction`
66
+ #
67
+ # Keep the default empty so the lightweight direct host stays minimal.
50
68
  middleware: []
51
69
  # Upstream execution feature: system prompt for the lightweight direct-response host.
52
70
  # This prompt should keep the agent focused on:
@@ -66,6 +66,16 @@ spec:
66
66
  # Upstream execution feature: no extra declarative HITL rules by default.
67
67
  interruptOn: {}
68
68
  # Upstream execution feature: no extra declarative middleware beyond upstream deepagents defaults by default.
69
+ # Common upstream middleware kinds that this harness can compile directly from YAML:
70
+ # - `patchToolCalls`
71
+ # - `summarization`
72
+ # - `dynamicSystemPrompt`
73
+ # - `humanInTheLoop`
74
+ # - `todoList`
75
+ # - `pii`, `piiRedaction`
76
+ #
77
+ # DeepAgents already includes its own filesystem, planning, subagent, and memory semantics.
78
+ # Keep this list empty unless you are intentionally adding extra upstream middleware on top.
69
79
  middleware: []
70
80
  # Upstream execution feature: keep the built-in general-purpose subagent enabled.
71
81
  generalPurposeAgent: true
package/dist/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
- export { AgentHarnessRuntime, createAgentHarness, createToolMcpServer, deleteThread, getApproval, getThread, listApprovals, listThreads, resolveApproval, run, serveToolsOverStdio, subscribe, stop, } from "./api.js";
1
+ export { AgentHarnessRuntime, createAgentHarness, createToolMcpServer, deleteThread, describeInventory, getApproval, getThread, listAgentSkills, listApprovals, listThreads, resolveApproval, 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 { AgentHarnessRuntime, createAgentHarness, createToolMcpServer, deleteThread, getApproval, getThread, listApprovals, listThreads, resolveApproval, run, serveToolsOverStdio, subscribe, stop, } from "./api.js";
1
+ export { AgentHarnessRuntime, createAgentHarness, createToolMcpServer, deleteThread, describeInventory, getApproval, getThread, listAgentSkills, listApprovals, listThreads, resolveApproval, run, serveToolsOverStdio, subscribe, stop, } from "./api.js";
2
2
  export { tool } from "./tools.js";
@@ -1 +1 @@
1
- export declare const AGENT_HARNESS_VERSION = "0.0.54";
1
+ export declare const AGENT_HARNESS_VERSION = "0.0.56";
@@ -1 +1 @@
1
- export const AGENT_HARNESS_VERSION = "0.0.54";
1
+ export const AGENT_HARNESS_VERSION = "0.0.56";
@@ -1,4 +1,4 @@
1
- import { existsSync, mkdirSync } from "node:fs";
1
+ import { existsSync, mkdirSync, readdirSync } from "node:fs";
2
2
  import { createRequire } from "node:module";
3
3
  import path from "node:path";
4
4
  import { stat } from "node:fs/promises";
@@ -12,6 +12,7 @@ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/
12
12
  import { WebSocketClientTransport } from "@modelcontextprotocol/sdk/client/websocket.js";
13
13
  import { AGENT_HARNESS_VERSION } from "../package-version.js";
14
14
  import { isSupportedToolModulePath, loadToolModuleDefinition } from "../tool-modules.js";
15
+ import { createRuntimeEnv } from "../runtime/support/runtime-env.js";
15
16
  import { resolveIsolatedResourceModulePath } from "./isolation.js";
16
17
  import { ensureExternalResourceSource, ensureExternalSource, isExternalSourceLocator, parseExternalSourceLocator } from "./sources.js";
17
18
  const resourceDir = path.dirname(fileURLToPath(import.meta.url));
@@ -38,6 +39,33 @@ export function resolveLocalResourceProviderEntry(currentResourceDir, resolveIns
38
39
  return candidates.at(-1) ?? path.resolve(currentResourceDir, "../../../resource-package/dist/src/index.js");
39
40
  }
40
41
  const resourceProviderEntry = resolveLocalResourceProviderEntry(resourceDir);
42
+ function listVirtualRootEntries(rootDir) {
43
+ try {
44
+ return new Set(readdirSync(rootDir, { withFileTypes: true }).map((entry) => entry.name));
45
+ }
46
+ catch {
47
+ return new Set();
48
+ }
49
+ }
50
+ function normalizeVirtualExecuteCommand(command, rootDir) {
51
+ if (typeof command !== "string" || command.length === 0) {
52
+ return command;
53
+ }
54
+ const rootEntries = listVirtualRootEntries(rootDir);
55
+ if (rootEntries.size === 0) {
56
+ return command;
57
+ }
58
+ return command.replace(/(^|[\s=:(\[{,;|&])(?<quote>["']?)(?<virtualPath>\/(?:[^\s"'`;|&()<>]+))(?:\k<quote>)/g, (match, prefix, quote = "", virtualPath) => {
59
+ const normalizedVirtualPath = virtualPath.replace(/\/+/g, "/");
60
+ const segments = normalizedVirtualPath.split("/").filter((segment) => segment.length > 0);
61
+ const firstSegment = segments[0];
62
+ if (!firstSegment || !rootEntries.has(firstSegment)) {
63
+ return match;
64
+ }
65
+ const translatedPath = path.resolve(rootDir, ...segments);
66
+ return `${prefix}${quote}${translatedPath}${quote}`;
67
+ });
68
+ }
41
69
  async function loadLocalResource(entry) {
42
70
  if (!existsSync(entry)) {
43
71
  return null;
@@ -70,7 +98,11 @@ class CompatibleCompositeBackend {
70
98
  const sandboxLike = defaultBackend;
71
99
  if (typeof sandboxLike.id === "string" && typeof sandboxLike.execute === "function") {
72
100
  this.id = sandboxLike.id;
73
- this.execute = (command) => this.composite.execute(command);
101
+ const virtualCwd = typeof sandboxLike.cwd === "string" && sandboxLike.virtualMode === true ? sandboxLike.cwd : null;
102
+ this.execute =
103
+ virtualCwd
104
+ ? (command) => this.composite.execute(normalizeVirtualExecuteCommand(command, virtualCwd))
105
+ : (command) => this.composite.execute(command);
74
106
  }
75
107
  }
76
108
  lsInfo(filePath) {
@@ -116,6 +148,10 @@ function createInlineBackendResolver(workspace) {
116
148
  return workspace.workspaceRoot;
117
149
  };
118
150
  const createBackend = (kind, config, runtimeLike) => {
151
+ const configuredEnv = typeof config?.env === "object" && config.env
152
+ ? Object.fromEntries(Object.entries(config.env).filter((entry) => typeof entry[1] === "string"))
153
+ : undefined;
154
+ const inheritedEnv = config?.inheritEnv === false ? {} : process.env;
119
155
  switch (kind) {
120
156
  case "LocalShellBackend": {
121
157
  const rootDir = resolveBackendRootDir(config?.rootDir);
@@ -125,9 +161,7 @@ function createInlineBackendResolver(workspace) {
125
161
  virtualMode: config?.virtualMode === true,
126
162
  timeout: typeof config?.timeout === "number" ? config.timeout : undefined,
127
163
  maxOutputBytes: typeof config?.maxOutputBytes === "number" ? config.maxOutputBytes : undefined,
128
- env: typeof config?.env === "object" && config.env
129
- ? Object.fromEntries(Object.entries(config.env).filter((entry) => typeof entry[1] === "string"))
130
- : undefined,
164
+ env: createRuntimeEnv(configuredEnv, inheritedEnv),
131
165
  inheritEnv: config?.inheritEnv !== false,
132
166
  });
133
167
  }
@@ -139,9 +173,7 @@ function createInlineBackendResolver(workspace) {
139
173
  virtualMode: config?.virtualMode === false ? false : true,
140
174
  timeout: typeof config?.timeout === "number" ? config.timeout : undefined,
141
175
  maxOutputBytes: typeof config?.maxOutputBytes === "number" ? config.maxOutputBytes : undefined,
142
- env: typeof config?.env === "object" && config.env
143
- ? Object.fromEntries(Object.entries(config.env).filter((entry) => typeof entry[1] === "string"))
144
- : undefined,
176
+ env: createRuntimeEnv(configuredEnv, inheritedEnv),
145
177
  inheritEnv: config?.inheritEnv !== false,
146
178
  });
147
179
  }
@@ -318,7 +350,7 @@ export async function getOrCreateMcpClient(config) {
318
350
  : new StdioClientTransport({
319
351
  command: config.command ?? "",
320
352
  args: config.args,
321
- env: config.env,
353
+ env: createRuntimeEnv(config.env),
322
354
  cwd: config.cwd,
323
355
  });
324
356
  await client.connect(transport);
@@ -12,6 +12,13 @@ declare class RuntimeOperationTimeoutError extends Error {
12
12
  readonly stage: "stream" | "invoke";
13
13
  constructor(operation: string, timeoutMs: number, stage?: "stream" | "invoke");
14
14
  }
15
+ export declare function relativizeDeepAgentSkillSourcePaths(workspaceRoot: string | undefined, skillPaths: string[] | undefined): string[] | undefined;
16
+ export declare function materializeDeepAgentSkillSourcePaths(options: {
17
+ workspaceRoot?: string;
18
+ runRoot?: string;
19
+ ownerId: string;
20
+ skillPaths?: string[];
21
+ }): Promise<string[] | undefined>;
15
22
  export declare class AgentRuntimeAdapter {
16
23
  private readonly options;
17
24
  constructor(options?: RuntimeAdapterOptions);
@@ -26,6 +33,7 @@ export declare class AgentRuntimeAdapter {
26
33
  private resolveModel;
27
34
  private buildToolNameMapping;
28
35
  private buildAgentMessages;
36
+ private buildSlashCommandSkillInstruction;
29
37
  private buildInvocationRequest;
30
38
  private buildStateSnapshot;
31
39
  private buildRawModelMessages;