@botbotgo/agent-harness 0.0.156 → 0.0.157

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
@@ -796,10 +796,15 @@ spec:
796
796
  rootDir: .
797
797
  virtualMode: true
798
798
  maxFileSizeMb: 10
799
+ sessionStorage:
800
+ enabled: true
801
+ rootDir: "{runRoot}/threads/{threadId}/filesystem"
799
802
  middleware: []
800
803
  systemPrompt: Answer simple requests directly.
801
804
  ```
802
805
 
806
+ When `config.filesystem.sessionStorage.enabled: true` is set for a LangChain binding, the runtime keeps one filesystem root per persisted session/thread and reuses the same runnable cache entry for repeated work on that session instead of collapsing every run onto one shared workspace directory.
807
+
803
808
  Example orchestra host:
804
809
 
805
810
  ```yaml
@@ -860,6 +865,10 @@ Primary exports:
860
865
  - `deleteSession`
861
866
  - `listApprovals`
862
867
  - `getApproval`
868
+ - `listArtifacts`
869
+ - `getArtifact`
870
+ - `exportEvaluationBundle`
871
+ - `createAcpServer`
863
872
  - `createToolMcpServer`
864
873
  - `serveToolsOverStdio`
865
874
  - `stop`
package/README.zh.md CHANGED
@@ -763,10 +763,15 @@ spec:
763
763
  rootDir: .
764
764
  virtualMode: true
765
765
  maxFileSizeMb: 10
766
+ sessionStorage:
767
+ enabled: true
768
+ rootDir: "{runRoot}/threads/{threadId}/filesystem"
766
769
  middleware: []
767
770
  systemPrompt: Answer simple requests directly.
768
771
  ```
769
772
 
773
+ 当 LangChain 绑定启用 `config.filesystem.sessionStorage.enabled: true` 时,runtime 会为每个持久化 session/thread 维护独立的 filesystem 根目录,并按 session 复用 runnable cache,而不是把所有运行都压到同一个共享工作目录里。
774
+
770
775
  orchestra 主机示例:
771
776
 
772
777
  ```yaml
@@ -827,6 +832,10 @@ spec:
827
832
  - `deleteSession`
828
833
  - `listApprovals`
829
834
  - `getApproval`
835
+ - `listArtifacts`
836
+ - `getArtifact`
837
+ - `exportEvaluationBundle`
838
+ - `createAcpServer`
830
839
  - `createToolMcpServer`
831
840
  - `serveToolsOverStdio`
832
841
  - `stop`
package/dist/acp.d.ts ADDED
@@ -0,0 +1,86 @@
1
+ import type { ArtifactRecord, HarnessEvent, RequestRecord, RunOptions, SessionRecord } from "./contracts/types.js";
2
+ import type { AgentHarnessRuntime } from "./runtime/harness.js";
3
+ import { getApproval } from "./api.js";
4
+ type JsonRpcId = string | number | null;
5
+ export type AcpJsonRpcRequest = {
6
+ jsonrpc?: "2.0";
7
+ id?: JsonRpcId;
8
+ method: string;
9
+ params?: unknown;
10
+ };
11
+ export type AcpJsonRpcError = {
12
+ jsonrpc: "2.0";
13
+ id: JsonRpcId;
14
+ error: {
15
+ code: number;
16
+ message: string;
17
+ data?: unknown;
18
+ };
19
+ };
20
+ export type AcpJsonRpcSuccess = {
21
+ jsonrpc: "2.0";
22
+ id: JsonRpcId;
23
+ result: unknown;
24
+ };
25
+ export type AcpJsonRpcResponse = AcpJsonRpcError | AcpJsonRpcSuccess;
26
+ export type AcpSessionRecord = SessionRecord;
27
+ export type AcpRequestRecord = RequestRecord;
28
+ export type AcpApproval = Awaited<ReturnType<typeof getApproval>> extends infer T ? Exclude<T, null> : never;
29
+ export type AcpArtifact = ArtifactRecord & {
30
+ content?: unknown;
31
+ };
32
+ export type AcpRunRequestParams = Omit<Extract<RunOptions, {
33
+ input: unknown;
34
+ }>, "threadId"> & {
35
+ sessionId?: string;
36
+ };
37
+ export type AcpServerCapabilities = {
38
+ sessions: {
39
+ list: true;
40
+ get: true;
41
+ };
42
+ requests: {
43
+ submit: true;
44
+ list: true;
45
+ get: true;
46
+ };
47
+ approvals: {
48
+ list: true;
49
+ get: true;
50
+ resolve: true;
51
+ };
52
+ artifacts: {
53
+ list: true;
54
+ read: true;
55
+ };
56
+ events: {
57
+ subscribe: true;
58
+ };
59
+ };
60
+ export type AcpEventNotification = {
61
+ jsonrpc: "2.0";
62
+ method: "events.runtime";
63
+ params: {
64
+ event: {
65
+ eventId: string;
66
+ eventType: string;
67
+ timestamp: string;
68
+ sessionId: string;
69
+ requestId: string;
70
+ sequence: number;
71
+ source: HarnessEvent["source"];
72
+ payload: Record<string, unknown>;
73
+ };
74
+ };
75
+ };
76
+ export declare class AgentHarnessAcpServer {
77
+ private readonly runtime;
78
+ constructor(runtime: AgentHarnessRuntime);
79
+ capabilities(): AcpServerCapabilities;
80
+ subscribe(listener: (notification: AcpEventNotification) => void): () => void;
81
+ handle(request: AcpJsonRpcRequest): Promise<AcpJsonRpcResponse | undefined>;
82
+ private methodExists;
83
+ private dispatch;
84
+ }
85
+ export declare function createAcpServer(runtime: AgentHarnessRuntime): AgentHarnessAcpServer;
86
+ export {};
package/dist/acp.js ADDED
@@ -0,0 +1,208 @@
1
+ import { getApproval, getArtifact, getRequest, getSession, listApprovals, listArtifacts, listRequests, listSessions, resolveApproval, run, } from "./api.js";
2
+ const CAPABILITIES = {
3
+ sessions: { list: true, get: true },
4
+ requests: { submit: true, list: true, get: true },
5
+ approvals: { list: true, get: true, resolve: true },
6
+ artifacts: { list: true, read: true },
7
+ events: { subscribe: true },
8
+ };
9
+ function asObject(value, method) {
10
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
11
+ throw new Error(`${method} requires an object params payload.`);
12
+ }
13
+ return value;
14
+ }
15
+ function readOptionalString(value) {
16
+ return typeof value === "string" && value.trim().length > 0 ? value.trim() : undefined;
17
+ }
18
+ function readRequiredString(value, field, method) {
19
+ const normalized = readOptionalString(value);
20
+ if (!normalized) {
21
+ throw new Error(`${method} requires ${field}.`);
22
+ }
23
+ return normalized;
24
+ }
25
+ function toNotification(event) {
26
+ return {
27
+ jsonrpc: "2.0",
28
+ method: "events.runtime",
29
+ params: {
30
+ event: {
31
+ eventId: event.eventId,
32
+ eventType: event.eventType,
33
+ timestamp: event.timestamp,
34
+ sessionId: event.threadId,
35
+ requestId: event.runId,
36
+ sequence: event.sequence,
37
+ source: event.source,
38
+ payload: event.payload,
39
+ },
40
+ },
41
+ };
42
+ }
43
+ async function readArtifactContent(runtime, params) {
44
+ const method = "artifacts.read";
45
+ const sessionId = readRequiredString(params.sessionId, "sessionId", method);
46
+ const requestId = readRequiredString(params.requestId, "requestId", method);
47
+ const artifactPath = readRequiredString(params.artifactPath, "artifactPath", method);
48
+ const listing = await listArtifacts(runtime, { sessionId, requestId });
49
+ const artifact = listing.items.find((item) => item.path === artifactPath);
50
+ if (!artifact) {
51
+ throw new Error(`Artifact not found for ${requestId}: ${artifactPath}`);
52
+ }
53
+ return {
54
+ ...artifact,
55
+ content: await getArtifact(runtime, { sessionId, requestId, artifactPath }),
56
+ };
57
+ }
58
+ export class AgentHarnessAcpServer {
59
+ runtime;
60
+ constructor(runtime) {
61
+ this.runtime = runtime;
62
+ }
63
+ capabilities() {
64
+ return CAPABILITIES;
65
+ }
66
+ subscribe(listener) {
67
+ return this.runtime.subscribe((event) => {
68
+ listener(toNotification(event));
69
+ });
70
+ }
71
+ async handle(request) {
72
+ const id = request.id ?? null;
73
+ if (!request || typeof request !== "object" || typeof request.method !== "string" || request.method.trim().length === 0) {
74
+ return {
75
+ jsonrpc: "2.0",
76
+ id,
77
+ error: {
78
+ code: -32600,
79
+ message: "Invalid JSON-RPC request.",
80
+ },
81
+ };
82
+ }
83
+ if (request.jsonrpc !== undefined && request.jsonrpc !== "2.0") {
84
+ return {
85
+ jsonrpc: "2.0",
86
+ id,
87
+ error: {
88
+ code: -32600,
89
+ message: "Only JSON-RPC 2.0 requests are supported.",
90
+ },
91
+ };
92
+ }
93
+ try {
94
+ const result = await this.dispatch(request.method, request.params);
95
+ if (request.id === undefined) {
96
+ return undefined;
97
+ }
98
+ return {
99
+ jsonrpc: "2.0",
100
+ id,
101
+ result,
102
+ };
103
+ }
104
+ catch (error) {
105
+ if (request.id === undefined) {
106
+ return undefined;
107
+ }
108
+ return {
109
+ jsonrpc: "2.0",
110
+ id,
111
+ error: {
112
+ code: this.methodExists(request.method) ? -32602 : -32601,
113
+ message: error instanceof Error ? error.message : "ACP request failed.",
114
+ },
115
+ };
116
+ }
117
+ }
118
+ methodExists(method) {
119
+ return new Set([
120
+ "capabilities.get",
121
+ "sessions.list",
122
+ "sessions.get",
123
+ "requests.submit",
124
+ "requests.list",
125
+ "requests.get",
126
+ "approvals.list",
127
+ "approvals.get",
128
+ "approvals.resolve",
129
+ "artifacts.list",
130
+ "artifacts.read",
131
+ ]).has(method);
132
+ }
133
+ async dispatch(method, params) {
134
+ switch (method) {
135
+ case "capabilities.get":
136
+ return this.capabilities();
137
+ case "sessions.list": {
138
+ const payload = params === undefined ? {} : asObject(params, method);
139
+ return listSessions(this.runtime, {
140
+ agentId: readOptionalString(payload.agentId),
141
+ });
142
+ }
143
+ case "sessions.get": {
144
+ const payload = asObject(params, method);
145
+ return getSession(this.runtime, readRequiredString(payload.sessionId, "sessionId", method));
146
+ }
147
+ case "requests.submit": {
148
+ const payload = asObject(params, method);
149
+ return run(this.runtime, {
150
+ agentId: readOptionalString(payload.agentId),
151
+ input: payload.input,
152
+ invocation: payload.invocation,
153
+ listeners: payload.listeners,
154
+ priority: typeof payload.priority === "number" ? payload.priority : undefined,
155
+ sessionId: readOptionalString(payload.sessionId),
156
+ });
157
+ }
158
+ case "requests.list": {
159
+ const payload = params === undefined ? {} : asObject(params, method);
160
+ return listRequests(this.runtime, {
161
+ agentId: readOptionalString(payload.agentId),
162
+ sessionId: readOptionalString(payload.sessionId),
163
+ state: payload.state,
164
+ });
165
+ }
166
+ case "requests.get": {
167
+ const payload = asObject(params, method);
168
+ return getRequest(this.runtime, readRequiredString(payload.requestId, "requestId", method));
169
+ }
170
+ case "approvals.list": {
171
+ const payload = params === undefined ? {} : asObject(params, method);
172
+ return listApprovals(this.runtime, {
173
+ status: payload.status,
174
+ sessionId: readOptionalString(payload.sessionId),
175
+ requestId: readOptionalString(payload.requestId),
176
+ });
177
+ }
178
+ case "approvals.get": {
179
+ const payload = asObject(params, method);
180
+ return getApproval(this.runtime, readRequiredString(payload.approvalId, "approvalId", method));
181
+ }
182
+ case "approvals.resolve": {
183
+ const payload = asObject(params, method);
184
+ return resolveApproval(this.runtime, {
185
+ approvalId: readRequiredString(payload.approvalId, "approvalId", method),
186
+ decision: payload.decision,
187
+ editedInput: payload.editedInput,
188
+ requestId: readOptionalString(payload.requestId),
189
+ sessionId: readOptionalString(payload.sessionId),
190
+ });
191
+ }
192
+ case "artifacts.list": {
193
+ const payload = asObject(params, method);
194
+ return listArtifacts(this.runtime, {
195
+ sessionId: readRequiredString(payload.sessionId, "sessionId", method),
196
+ requestId: readRequiredString(payload.requestId, "requestId", method),
197
+ });
198
+ }
199
+ case "artifacts.read":
200
+ return readArtifactContent(this.runtime, asObject(params, method));
201
+ default:
202
+ throw new Error(`Unknown ACP method: ${method}`);
203
+ }
204
+ }
205
+ }
206
+ export function createAcpServer(runtime) {
207
+ return new AgentHarnessAcpServer(runtime);
208
+ }
package/dist/api.d.ts CHANGED
@@ -1,11 +1,13 @@
1
- import type { CancelOptions, InvocationEnvelope, ListMemoriesInput, ListMemoriesResult, MemoryRecord, MemorizeInput, MemorizeResult, MessageContent, RecallInput, RecallResult, RemoveMemoryInput, RequestRecord, RequestSummary, ResumeOptions, RunDecisionOptions, RunResult, RunStartOptions, RuntimeHealthSnapshot, RuntimeAdapterOptions, SessionRecord, SessionSummary, UpdateMemoryInput, WorkspaceLoadOptions } from "./contracts/types.js";
1
+ import type { ArtifactListing, CancelOptions, InvocationEnvelope, ListMemoriesInput, ListMemoriesResult, MemoryRecord, MemorizeInput, MemorizeResult, MessageContent, RecallInput, RecallResult, RemoveMemoryInput, RequestRecord, RequestSummary, ResumeOptions, RunDecisionOptions, RunResult, RunStartOptions, RuntimeHealthSnapshot, RuntimeAdapterOptions, RuntimeEvaluationExport, RuntimeEvaluationExportInput, SessionRecord, SessionSummary, UpdateMemoryInput, WorkspaceLoadOptions } from "./contracts/types.js";
2
2
  import { AgentHarnessRuntime } from "./runtime/harness.js";
3
3
  import type { InventoryAgentRecord, InventorySkillRecord } from "./runtime/harness/system/inventory.js";
4
4
  import type { RequirementAssessmentOptions } from "./runtime/harness/system/skill-requirements.js";
5
5
  import type { ToolMcpServerOptions } from "./mcp.js";
6
+ export { AgentHarnessAcpServer, createAcpServer } from "./acp.js";
7
+ export type { AcpApproval, AcpArtifact, AcpEventNotification, AcpJsonRpcError, AcpJsonRpcRequest, AcpJsonRpcResponse, AcpJsonRpcSuccess, AcpRequestRecord, AcpRunRequestParams, AcpServerCapabilities, AcpSessionRecord, } from "./acp.js";
6
8
  export { AgentHarnessRuntime } from "./runtime/harness.js";
7
9
  export { createUpstreamTimelineReducer } from "./upstream-events.js";
8
- export type { ListMemoriesInput, ListMemoriesResult, MemoryDecision, MemoryKind, MemoryRecord, MemoryScope, MemorizeInput, MemorizeResult, RecallInput, RecallResult, RemoveMemoryInput, UpdateMemoryInput, } from "./contracts/types.js";
10
+ export type { ListMemoriesInput, ListMemoriesResult, MemoryDecision, MemoryKind, MemoryRecord, MemoryScope, MemorizeInput, MemorizeResult, RecallInput, RecallResult, RemoveMemoryInput, RuntimeEvaluationExport, RuntimeEvaluationExportInput, UpdateMemoryInput, } from "./contracts/types.js";
9
11
  type PublicApprovalRecord = {
10
12
  approvalId: string;
11
13
  pendingActionId: string;
@@ -72,7 +74,17 @@ export declare function getRequest(runtime: AgentHarnessRuntime, requestId: stri
72
74
  export declare function deleteSession(runtime: AgentHarnessRuntime, sessionId: string): Promise<boolean>;
73
75
  export declare function listApprovals(runtime: AgentHarnessRuntime, filter?: PublicApprovalFilter): Promise<PublicApprovalRecord[]>;
74
76
  export declare function getApproval(runtime: AgentHarnessRuntime, approvalId: string): Promise<PublicApprovalRecord | null>;
77
+ export declare function listArtifacts(runtime: AgentHarnessRuntime, input: {
78
+ sessionId: string;
79
+ requestId: string;
80
+ }): Promise<ArtifactListing>;
81
+ export declare function getArtifact(runtime: AgentHarnessRuntime, input: {
82
+ sessionId: string;
83
+ requestId: string;
84
+ artifactPath: string;
85
+ }): Promise<unknown>;
75
86
  export declare function getHealth(runtime: AgentHarnessRuntime): Promise<RuntimeHealthSnapshot>;
87
+ export declare function exportEvaluationBundle(runtime: AgentHarnessRuntime, input: RuntimeEvaluationExportInput): Promise<RuntimeEvaluationExport>;
76
88
  export declare function listAgentSkills(runtime: AgentHarnessRuntime, agentId: string, options?: RequirementAssessmentOptions): InventorySkillRecord[];
77
89
  export declare function getAgent(runtime: AgentHarnessRuntime, agentId: string, options?: RequirementAssessmentOptions): InventoryAgentRecord | null;
78
90
  export declare function describeInventory(runtime: AgentHarnessRuntime, options?: RequirementAssessmentOptions): {
package/dist/api.js CHANGED
@@ -1,6 +1,7 @@
1
1
  import { AgentHarnessRuntime } from "./runtime/harness.js";
2
2
  import { normalizeMessageContent } from "./utils/message-content.js";
3
3
  import { loadWorkspace } from "./workspace/compile.js";
4
+ export { AgentHarnessAcpServer, createAcpServer } from "./acp.js";
4
5
  export { AgentHarnessRuntime } from "./runtime/harness.js";
5
6
  export { createUpstreamTimelineReducer } from "./upstream-events.js";
6
7
  function toSessionSummary(summary) {
@@ -178,9 +179,18 @@ export async function getApproval(runtime, approvalId) {
178
179
  const record = await runtime.getApproval(approvalId);
179
180
  return record ? toApprovalRecord(record) : null;
180
181
  }
182
+ export async function listArtifacts(runtime, input) {
183
+ return runtime.listArtifacts(input.sessionId, input.requestId);
184
+ }
185
+ export async function getArtifact(runtime, input) {
186
+ return runtime.readArtifact(input.sessionId, input.requestId, input.artifactPath);
187
+ }
181
188
  export async function getHealth(runtime) {
182
189
  return runtime.getHealth();
183
190
  }
191
+ export async function exportEvaluationBundle(runtime, input) {
192
+ return runtime.exportEvaluationBundle(input);
193
+ }
184
194
  export function listAgentSkills(runtime, agentId, options) {
185
195
  return runtime.listAgentSkills(agentId, options);
186
196
  }
@@ -96,6 +96,24 @@ export type RuntimeSnapshotTracing = {
96
96
  tags?: string[];
97
97
  metadata?: Record<string, unknown>;
98
98
  };
99
+ export type RuntimeGovernanceRiskLevel = "low" | "medium" | "high";
100
+ export type RuntimeGovernanceToolPolicy = {
101
+ toolName: string;
102
+ toolId: string;
103
+ toolType: string;
104
+ category: "local" | "backend" | "mcp" | "provider-native";
105
+ risk: RuntimeGovernanceRiskLevel;
106
+ requiresApproval: boolean;
107
+ approvalPolicy: "explicit-hitl" | "runtime-default" | "none";
108
+ hasInputSchema: boolean;
109
+ inputRiskHints: string[];
110
+ };
111
+ export type RuntimeGovernanceBundle = {
112
+ bundleId: string;
113
+ title: string;
114
+ summary: string;
115
+ toolPolicies: RuntimeGovernanceToolPolicy[];
116
+ };
99
117
  export type RuntimeSnapshot = {
100
118
  agentId: string;
101
119
  model?: RuntimeSnapshotModel;
@@ -103,6 +121,9 @@ export type RuntimeSnapshot = {
103
121
  skills: RuntimeSnapshotSkill[];
104
122
  memory: string[];
105
123
  tracing?: RuntimeSnapshotTracing;
124
+ governance?: {
125
+ bundles: RuntimeGovernanceBundle[];
126
+ };
106
127
  };
107
128
  export type MemoryCandidate = {
108
129
  content: string;
@@ -539,6 +560,7 @@ export type SkillPackagingConvention = {
539
560
  export type PolicyDecision = {
540
561
  allowed: boolean;
541
562
  reasons: string[];
563
+ bundles?: RuntimeGovernanceBundle[];
542
564
  };
543
565
  export type PolicyEvaluator = {
544
566
  kind: string;
@@ -548,6 +570,32 @@ export type EventSubscriber = {
548
570
  kind: string;
549
571
  onEvent: HarnessEventListener;
550
572
  };
573
+ export type RuntimeEvaluationExportInput = {
574
+ sessionId: string;
575
+ requestId: string;
576
+ includeArtifacts?: boolean;
577
+ includeArtifactContents?: boolean;
578
+ expectedOutput?: string;
579
+ rubric?: string[];
580
+ tags?: string[];
581
+ metadata?: Record<string, unknown>;
582
+ };
583
+ export type RuntimeEvaluationArtifact = ArtifactRecord & {
584
+ content?: unknown;
585
+ };
586
+ export type RuntimeEvaluationExport = {
587
+ session: SessionRecord | null;
588
+ request: RequestRecord | null;
589
+ approvals: ApprovalRecord[];
590
+ transcript: TranscriptMessage[];
591
+ events: HarnessEvent[];
592
+ artifacts: RuntimeEvaluationArtifact[];
593
+ runtimeHealth: RuntimeHealthSnapshot;
594
+ expectedOutput?: string;
595
+ rubric: string[];
596
+ tags: string[];
597
+ metadata?: Record<string, unknown>;
598
+ };
551
599
  export type RuntimeInventoryContext = {
552
600
  workspace: WorkspaceBundle;
553
601
  };
package/dist/index.d.ts CHANGED
@@ -1,5 +1,6 @@
1
- export { AgentHarnessRuntime, cancelRun, createAgentHarness, createUpstreamTimelineReducer, createToolMcpServer, deleteSession, describeInventory, getAgent, getApproval, getRequest, getHealth, listMemories, getSession, listAgentSkills, listApprovals, listRequests, listSessions, memorize, normalizeUserChatInput, recall, removeMemory, resolveApproval, run, serveToolsOverStdio, subscribe, stop, updateMemory, } from "./api.js";
2
- export type { ListMemoriesInput, ListMemoriesResult, MemoryDecision, MemoryKind, MemoryRecord, MemoryScope, MemorizeInput, MemorizeResult, NormalizeUserChatInputOptions, RecallInput, RecallResult, RemoveMemoryInput, UpdateMemoryInput, UserChatInput, UserChatMessage, } from "./api.js";
1
+ export { AgentHarnessAcpServer, AgentHarnessRuntime, cancelRun, createAgentHarness, createAcpServer, createUpstreamTimelineReducer, createToolMcpServer, deleteSession, describeInventory, exportEvaluationBundle, getArtifact, getAgent, getApproval, getRequest, getHealth, listMemories, getSession, listAgentSkills, listArtifacts, listApprovals, listRequests, listSessions, memorize, normalizeUserChatInput, recall, removeMemory, resolveApproval, run, serveToolsOverStdio, subscribe, stop, updateMemory, } from "./api.js";
2
+ export type { AcpApproval, AcpArtifact, AcpEventNotification, AcpJsonRpcError, AcpJsonRpcRequest, AcpJsonRpcResponse, AcpJsonRpcSuccess, AcpRequestRecord, AcpRunRequestParams, AcpServerCapabilities, AcpSessionRecord, } from "./acp.js";
3
+ export type { ListMemoriesInput, ListMemoriesResult, MemoryDecision, MemoryKind, MemoryRecord, MemoryScope, MemorizeInput, MemorizeResult, NormalizeUserChatInputOptions, RecallInput, RecallResult, RemoveMemoryInput, RuntimeEvaluationExport, RuntimeEvaluationExportInput, UpdateMemoryInput, UserChatInput, UserChatMessage, } from "./api.js";
3
4
  export type { ToolMcpServerOptions } from "./mcp.js";
4
5
  export { tool } from "./tools.js";
5
6
  export type { UpstreamTimelineProjection, UpstreamTimelineReducer } from "./upstream-events.js";
package/dist/index.js CHANGED
@@ -1,2 +1,2 @@
1
- export { AgentHarnessRuntime, cancelRun, createAgentHarness, createUpstreamTimelineReducer, createToolMcpServer, deleteSession, describeInventory, getAgent, getApproval, getRequest, getHealth, listMemories, getSession, listAgentSkills, listApprovals, listRequests, listSessions, memorize, normalizeUserChatInput, recall, removeMemory, resolveApproval, run, serveToolsOverStdio, subscribe, stop, updateMemory, } from "./api.js";
1
+ export { AgentHarnessAcpServer, AgentHarnessRuntime, cancelRun, createAgentHarness, createAcpServer, createUpstreamTimelineReducer, createToolMcpServer, deleteSession, describeInventory, exportEvaluationBundle, getArtifact, getAgent, getApproval, getRequest, getHealth, listMemories, getSession, listAgentSkills, listArtifacts, listApprovals, listRequests, listSessions, memorize, normalizeUserChatInput, recall, removeMemory, resolveApproval, run, serveToolsOverStdio, subscribe, stop, updateMemory, } from "./api.js";
2
2
  export { tool } from "./tools.js";
@@ -1 +1 @@
1
- export declare const AGENT_HARNESS_VERSION = "0.0.155";
1
+ export declare const AGENT_HARNESS_VERSION = "0.0.156";
@@ -1 +1 @@
1
- export const AGENT_HARNESS_VERSION = "0.0.155";
1
+ export const AGENT_HARNESS_VERSION = "0.0.156";
@@ -69,6 +69,7 @@ export declare class FilePersistence implements RuntimePersistence {
69
69
  resolveApproval(threadId: string, runId: string, approvalId: string, status: InternalApprovalRecord["status"]): Promise<InternalApprovalRecord>;
70
70
  createArtifact(threadId: string, runId: string, artifact: ArtifactRecord, content: unknown): Promise<ArtifactRecord>;
71
71
  listArtifacts(threadId: string, runId: string): Promise<ArtifactListing>;
72
+ readArtifact(threadId: string, runId: string, artifactPath: string): Promise<unknown>;
72
73
  appendThreadMessage(threadId: string, message: TranscriptMessage): Promise<void>;
73
74
  listThreadMessages(threadId: string, limit?: number): Promise<TranscriptMessage[]>;
74
75
  saveRecoveryIntent(threadId: string, runId: string, intent: RecoveryIntent): Promise<void>;
@@ -328,7 +328,9 @@ export class FilePersistence {
328
328
  if (!(await fileExists(eventsDir))) {
329
329
  return [];
330
330
  }
331
- const entries = (await readdir(eventsDir)).sort();
331
+ const entries = (await readdir(eventsDir))
332
+ .filter((entry) => entry.endsWith(".json"))
333
+ .sort((left, right) => left.localeCompare(right));
332
334
  return Promise.all(entries.map((entry) => readJson(path.join(eventsDir, entry))));
333
335
  }
334
336
  async listApprovals(filter = {}) {
@@ -460,6 +462,13 @@ export class FilePersistence {
460
462
  async listArtifacts(threadId, runId) {
461
463
  return readJson(path.join(this.runDir(threadId, runId), "artifacts.json"));
462
464
  }
465
+ async readArtifact(threadId, runId, artifactPath) {
466
+ const filePath = path.join(this.runDir(threadId, runId), artifactPath);
467
+ if (!(await fileExists(filePath))) {
468
+ return null;
469
+ }
470
+ return readJson(filePath);
471
+ }
463
472
  async appendThreadMessage(threadId, message) {
464
473
  const messagesPath = path.join(this.threadDir(threadId), "messages.json");
465
474
  const current = (await fileExists(messagesPath))
@@ -120,6 +120,7 @@ export interface RuntimePersistence {
120
120
  }): Promise<void>;
121
121
  setRunState(threadId: string, runId: string, state: RunState, checkpointRef?: string | null): Promise<void>;
122
122
  appendEvent(event: HarnessEvent): Promise<void>;
123
+ listRunEvents(threadId: string, runId: string): Promise<HarnessEvent[]>;
123
124
  listSessions(filter?: ThreadSummaryFilter): Promise<ThreadSummary[]>;
124
125
  listRuns(filter?: RunSummaryFilter): Promise<RunSummary[]>;
125
126
  getRun(runId: string): Promise<RunSummary | null>;
@@ -147,6 +148,7 @@ export interface RuntimePersistence {
147
148
  resolveApproval(threadId: string, runId: string, approvalId: string, status: InternalApprovalRecord["status"]): Promise<InternalApprovalRecord>;
148
149
  createArtifact(threadId: string, runId: string, artifact: ArtifactRecord, content: unknown): Promise<ArtifactRecord>;
149
150
  listArtifacts(threadId: string, runId: string): Promise<ArtifactListing>;
151
+ readArtifact(threadId: string, runId: string, artifactPath: string): Promise<unknown>;
150
152
  appendThreadMessage(threadId: string, message: TranscriptMessage): Promise<void>;
151
153
  listThreadMessages(threadId: string, limit?: number): Promise<TranscriptMessage[]>;
152
154
  saveRecoveryIntent(threadId: string, runId: string, intent: RecoveryIntent): Promise<void>;
@@ -63,6 +63,7 @@ export declare class AgentRuntimeAdapter {
63
63
  private resolveTools;
64
64
  private getToolNameMapping;
65
65
  private resolveFilesystemBackend;
66
+ private resolveFilesystemRootDir;
66
67
  private resolveBuiltinMiddlewareBackend;
67
68
  private createDeclaredMiddlewareResolverOptions;
68
69
  private createAssemblyResolvers;
@@ -75,7 +76,10 @@ export declare class AgentRuntimeAdapter {
75
76
  private createLangChainRunnable;
76
77
  private createRunnable;
77
78
  private createDeepAgentRunnable;
78
- create(binding: CompiledAgentBinding): Promise<RunnableLike>;
79
+ private buildRunnableCacheKey;
80
+ create(binding: CompiledAgentBinding, options?: {
81
+ threadId?: string;
82
+ }): Promise<RunnableLike>;
79
83
  invoke(binding: CompiledAgentBinding, input: MessageContent, threadId: string, runId: string, resumePayload?: unknown, history?: TranscriptMessage[], options?: {
80
84
  context?: Record<string, unknown>;
81
85
  state?: Record<string, unknown>;
@@ -159,7 +159,7 @@ function shouldAttachMinimalDeepAgentBackend(binding) {
159
159
  export class AgentRuntimeAdapter {
160
160
  options;
161
161
  modelCache = new Map();
162
- runnableCache = new WeakMap();
162
+ runnableCache = new Map();
163
163
  toolNameMappingCache = new WeakMap();
164
164
  constructor(options = {}) {
165
165
  this.options = options;
@@ -213,7 +213,12 @@ export class AgentRuntimeAdapter {
213
213
  }
214
214
  }
215
215
  invalidateBindingRuntimeCaches(binding) {
216
- this.runnableCache.delete(binding);
216
+ const prefix = `${binding.agent.sourcePath}::`;
217
+ for (const key of Array.from(this.runnableCache.keys())) {
218
+ if (key.startsWith(prefix)) {
219
+ this.runnableCache.delete(key);
220
+ }
221
+ }
217
222
  this.modelCache.clear();
218
223
  }
219
224
  resolveTools(tools, binding) {
@@ -232,15 +237,19 @@ export class AgentRuntimeAdapter {
232
237
  this.toolNameMappingCache.set(binding, resolved);
233
238
  return resolved;
234
239
  }
235
- resolveFilesystemBackend(binding) {
240
+ resolveFilesystemBackend(binding, options = {}) {
236
241
  const filesystemConfig = getBindingFilesystemConfig(binding);
242
+ const sessionStorage = typeof filesystemConfig?.sessionStorage === "object" && filesystemConfig.sessionStorage
243
+ ? filesystemConfig.sessionStorage
244
+ : undefined;
237
245
  const configuredRootDir = typeof filesystemConfig?.rootDir === "string" && filesystemConfig.rootDir.trim().length > 0
238
246
  ? filesystemConfig.rootDir
239
247
  : undefined;
240
248
  const workspaceRoot = binding.harnessRuntime.workspaceRoot;
241
- const rootDir = configuredRootDir
249
+ const baseRootDir = configuredRootDir
242
250
  ? (path.isAbsolute(configuredRootDir) ? configuredRootDir : path.resolve(workspaceRoot ?? process.cwd(), configuredRootDir))
243
251
  : workspaceRoot ?? process.cwd();
252
+ const rootDir = this.resolveFilesystemRootDir(baseRootDir, binding, sessionStorage, options.threadId);
244
253
  return new FilesystemBackend({
245
254
  rootDir,
246
255
  virtualMode: filesystemConfig?.virtualMode === true,
@@ -249,6 +258,25 @@ export class AgentRuntimeAdapter {
249
258
  : 10,
250
259
  });
251
260
  }
261
+ resolveFilesystemRootDir(baseRootDir, binding, sessionStorage, threadId) {
262
+ const enabled = sessionStorage?.enabled === true;
263
+ if (!enabled || !threadId) {
264
+ return baseRootDir;
265
+ }
266
+ const workspaceRoot = binding.harnessRuntime.workspaceRoot ?? process.cwd();
267
+ const runRoot = binding.harnessRuntime.runRoot;
268
+ const configuredRootDir = typeof sessionStorage.rootDir === "string" && sessionStorage.rootDir.trim().length > 0
269
+ ? sessionStorage.rootDir.trim()
270
+ : "{runRoot}/threads/{threadId}/filesystem";
271
+ const rendered = configuredRootDir
272
+ .replaceAll("{threadId}", threadId)
273
+ .replaceAll("{sessionId}", threadId)
274
+ .replaceAll("{agentId}", binding.agent.id)
275
+ .replaceAll("{runRoot}", runRoot)
276
+ .replaceAll("{workspaceRoot}", workspaceRoot)
277
+ .replaceAll("{baseRootDir}", baseRootDir);
278
+ return path.isAbsolute(rendered) ? rendered : path.resolve(workspaceRoot, rendered);
279
+ }
252
280
  resolveBuiltinMiddlewareBackend(binding, options = {}) {
253
281
  return resolveBuiltinMiddlewareBackendHelper({
254
282
  binding,
@@ -257,7 +285,7 @@ export class AgentRuntimeAdapter {
257
285
  options,
258
286
  });
259
287
  }
260
- createDeclaredMiddlewareResolverOptions(binding) {
288
+ createDeclaredMiddlewareResolverOptions(binding, options = {}) {
261
289
  return {
262
290
  resolveModel: (model) => this.resolveModel(model),
263
291
  resolveBackend: (resolvedBinding) => {
@@ -266,7 +294,7 @@ export class AgentRuntimeAdapter {
266
294
  },
267
295
  resolveFilesystemBackend: (resolvedBinding) => {
268
296
  const targetBinding = resolvedBinding ?? binding;
269
- return targetBinding ? this.resolveFilesystemBackend(targetBinding) : undefined;
297
+ return targetBinding ? this.resolveFilesystemBackend(targetBinding, { threadId: options.threadId }) : undefined;
270
298
  },
271
299
  resolveCustom: this.options.declaredMiddlewareResolver,
272
300
  binding,
@@ -276,8 +304,8 @@ export class AgentRuntimeAdapter {
276
304
  return {
277
305
  resolveModel: (model) => this.resolveModel(model),
278
306
  resolveTools: (tools, currentBinding) => this.resolveTools(tools, currentBinding),
279
- resolveFilesystemBackend: (currentBinding) => this.resolveFilesystemBackend(currentBinding),
280
- createDeclaredMiddlewareResolverOptions: (currentBinding) => this.createDeclaredMiddlewareResolverOptions(currentBinding),
307
+ resolveFilesystemBackend: (currentBinding) => this.resolveFilesystemBackend(currentBinding, { threadId: options.threadId }),
308
+ createDeclaredMiddlewareResolverOptions: (currentBinding) => this.createDeclaredMiddlewareResolverOptions(currentBinding, options),
281
309
  resolveBuiltinMiddlewareBackend: (currentBinding, currentOptions = {}) => this.resolveBuiltinMiddlewareBackend(currentBinding, currentOptions),
282
310
  resolveSubagents: (subagents, currentBinding) => this.resolveSubagents(subagents, currentBinding),
283
311
  invokeBuiltinTaskTool: (currentBinding, toolInput, currentOptions = {}) => this.invokeBuiltinTaskTool(currentBinding, toolInput, currentOptions),
@@ -313,8 +341,8 @@ export class AgentRuntimeAdapter {
313
341
  createDeclaredMiddlewareResolverOptions: assembly.createDeclaredMiddlewareResolverOptions,
314
342
  });
315
343
  }
316
- async resolveLangChainRuntimeExtensionMiddleware(binding) {
317
- const assembly = this.createAssemblyResolvers(binding);
344
+ async resolveLangChainRuntimeExtensionMiddleware(binding, options = {}) {
345
+ const assembly = this.createAssemblyResolvers(binding, options);
318
346
  return resolveLangChainRuntimeExtensionMiddlewareHelper({
319
347
  binding,
320
348
  materializeAutomaticSummarizationMiddleware: (currentBinding) => this.materializeAutomaticSummarizationMiddleware(currentBinding),
@@ -324,14 +352,14 @@ export class AgentRuntimeAdapter {
324
352
  resolveSubagents: assembly.resolveSubagents,
325
353
  });
326
354
  }
327
- async resolveMiddleware(binding, interruptOn) {
328
- const assembly = this.createAssemblyResolvers(binding);
355
+ async resolveMiddleware(binding, interruptOn, options = {}) {
356
+ const assembly = this.createAssemblyResolvers(binding, options);
329
357
  return resolveMiddlewareHelper({
330
358
  binding,
331
359
  interruptOn,
332
360
  runtimeAdapterOptions: this.options,
333
361
  createDeclaredMiddlewareResolverOptions: assembly.createDeclaredMiddlewareResolverOptions,
334
- resolveLangChainRuntimeExtensionMiddleware: (currentBinding) => this.resolveLangChainRuntimeExtensionMiddleware(currentBinding),
362
+ resolveLangChainRuntimeExtensionMiddleware: (currentBinding) => this.resolveLangChainRuntimeExtensionMiddleware(currentBinding, options),
335
363
  });
336
364
  }
337
365
  async resolveSubagents(subagents, binding) {
@@ -354,7 +382,7 @@ export class AgentRuntimeAdapter {
354
382
  const interruptOn = resolveRunnableInterruptOn(binding);
355
383
  const resolvedModel = await this.resolveModel(primaryModel);
356
384
  const resolvedTools = this.resolveTools(primaryTools, binding);
357
- const resolvedMiddleware = await this.resolveMiddleware(binding, interruptOn);
385
+ const resolvedMiddleware = await this.resolveMiddleware(binding, interruptOn, { threadId: options.threadId });
358
386
  const resolvedCheckpointer = resolveRunnableCheckpointer(this.options, binding);
359
387
  const resolvedStore = this.options.storeResolver?.(binding);
360
388
  const model = resolvedModel;
@@ -372,12 +400,12 @@ export class AgentRuntimeAdapter {
372
400
  systemPromptOverride: options.systemPromptOverride,
373
401
  }));
374
402
  }
375
- async createRunnable(binding) {
403
+ async createRunnable(binding, options = {}) {
376
404
  if (getBindingAdapterKind(binding) === "langgraph") {
377
405
  throw new Error(`Agent ${binding.agent.id} uses removed backend langgraph; use langchain-v1 or deepagent`);
378
406
  }
379
407
  if (isLangChainBinding(binding)) {
380
- return this.createLangChainRunnable(binding);
408
+ return this.createLangChainRunnable(binding, { threadId: options.threadId });
381
409
  }
382
410
  return this.createDeepAgentRunnable(binding);
383
411
  }
@@ -425,25 +453,34 @@ export class AgentRuntimeAdapter {
425
453
  });
426
454
  return createDeepAgent(deepAgentConfig);
427
455
  }
428
- async create(binding) {
429
- const cached = this.runnableCache.get(binding);
456
+ buildRunnableCacheKey(binding, threadId) {
457
+ const filesystemConfig = getBindingFilesystemConfig(binding);
458
+ const sessionStorage = typeof filesystemConfig?.sessionStorage === "object" && filesystemConfig.sessionStorage
459
+ ? filesystemConfig.sessionStorage
460
+ : undefined;
461
+ const sessionScoped = sessionStorage?.enabled === true;
462
+ return `${binding.agent.sourcePath}::${sessionScoped ? (threadId ?? "__default__") : "__binding__"}`;
463
+ }
464
+ async create(binding, options = {}) {
465
+ const cacheKey = this.buildRunnableCacheKey(binding, options.threadId);
466
+ const cached = this.runnableCache.get(cacheKey);
430
467
  if (cached) {
431
468
  return cached;
432
469
  }
433
- const pending = this.createRunnable(binding);
434
- this.runnableCache.set(binding, pending);
470
+ const pending = this.createRunnable(binding, options);
471
+ this.runnableCache.set(cacheKey, pending);
435
472
  try {
436
473
  return await pending;
437
474
  }
438
475
  catch (error) {
439
- this.runnableCache.delete(binding);
476
+ this.runnableCache.delete(cacheKey);
440
477
  throw error;
441
478
  }
442
479
  }
443
480
  async invoke(binding, input, threadId, runId, resumePayload, history = [], options = {}) {
444
481
  const callRuntime = async (activeBinding, activeRequest) => {
445
482
  return this.invokeWithProviderRetry(activeBinding, async () => {
446
- const runnable = await this.create(activeBinding);
483
+ const runnable = await this.create(activeBinding, { threadId });
447
484
  return (await this.withTimeout(() => runnable.invoke(activeRequest, resolveLangChainInvocationConfig(activeBinding, {
448
485
  threadId,
449
486
  runId,
@@ -469,7 +506,7 @@ export class AgentRuntimeAdapter {
469
506
  invokeOptions: options,
470
507
  resolveTools: (tools, currentBinding) => this.resolveTools(tools, currentBinding),
471
508
  getToolNameMapping: (currentBinding) => this.getToolNameMapping(currentBinding),
472
- resolveBuiltinMiddlewareTools: (currentBinding, currentOptions) => this.resolveBuiltinMiddlewareTools(currentBinding, currentOptions),
509
+ resolveBuiltinMiddlewareTools: (currentBinding, currentOptions) => this.resolveBuiltinMiddlewareTools(currentBinding, { ...currentOptions, threadId }),
473
510
  callRuntimeWithToolParseRecovery,
474
511
  });
475
512
  }
@@ -494,7 +531,7 @@ export class AgentRuntimeAdapter {
494
531
  forceInvokeFallback,
495
532
  canUseDirectModelStream,
496
533
  langChainStreamModel,
497
- createRunnable: () => this.create(binding),
534
+ createRunnable: () => this.create(binding, { threadId }),
498
535
  withTimeout: (producer, timeoutMs, operation, stage) => this.withTimeout(producer, timeoutMs, operation, stage),
499
536
  iterateWithTimeout: (iterable, timeoutMs, operation, deadlineAt, deadlineTimeoutMs) => this.iterateWithTimeout(iterable, timeoutMs, operation, deadlineAt, deadlineTimeoutMs),
500
537
  invokeTimeoutMs: computeRemainingTimeoutMs(streamDeadlineAt, invokeTimeoutMs),
@@ -0,0 +1,2 @@
1
+ import type { CompiledAgentBinding, RuntimeGovernanceBundle } from "../../../contracts/types.js";
2
+ export declare function buildRuntimeGovernanceBundles(binding: CompiledAgentBinding): RuntimeGovernanceBundle[];
@@ -0,0 +1,76 @@
1
+ import { getBindingPrimaryTools } from "../../support/compiled-binding.js";
2
+ import { toolRequiresRuntimeApproval } from "../../adapter/tool/tool-hitl.js";
3
+ const WRITE_LIKE_PATTERN = /\b(write|edit|delete|create|update|append|insert|push|commit|publish|send|post|apply|merge|sync|upload|save)\b/i;
4
+ function inputHints(binding, tool) {
5
+ const hints = new Set();
6
+ const target = `${tool.name} ${tool.description}`.toLowerCase();
7
+ if (/(path|file|dir|directory|folder|workspace|repo|repository)/.test(target)) {
8
+ hints.add("filesystem-scope");
9
+ }
10
+ if (/(memory|knowledge|store|recall)/.test(target)) {
11
+ hints.add("memory-scope");
12
+ }
13
+ if (tool.config?.mcp) {
14
+ hints.add("remote-mcp");
15
+ }
16
+ if (binding.agent.executionMode === "deepagent") {
17
+ hints.add("delegated-runtime");
18
+ }
19
+ return Array.from(hints);
20
+ }
21
+ function classifyRisk(policy) {
22
+ if (policy.requiresApproval) {
23
+ return "high";
24
+ }
25
+ const target = `${policy.toolName} ${policy.description}`;
26
+ if (policy.toolType === "mcp" && WRITE_LIKE_PATTERN.test(target)) {
27
+ return "high";
28
+ }
29
+ if (policy.toolType === "backend" || policy.toolType === "mcp") {
30
+ return "medium";
31
+ }
32
+ return "low";
33
+ }
34
+ function toCategory(toolType) {
35
+ if (toolType === "mcp") {
36
+ return "mcp";
37
+ }
38
+ if (toolType === "backend") {
39
+ return "backend";
40
+ }
41
+ if (toolType === "provider") {
42
+ return "provider-native";
43
+ }
44
+ return "local";
45
+ }
46
+ export function buildRuntimeGovernanceBundles(binding) {
47
+ const toolPolicies = getBindingPrimaryTools(binding).map((tool) => {
48
+ const requiresApproval = toolRequiresRuntimeApproval(tool);
49
+ return {
50
+ toolName: tool.name,
51
+ toolId: tool.id,
52
+ toolType: tool.type,
53
+ category: toCategory(tool.type),
54
+ risk: classifyRisk({
55
+ toolType: tool.type,
56
+ requiresApproval,
57
+ toolName: tool.name,
58
+ description: tool.description,
59
+ config: tool.config,
60
+ }),
61
+ requiresApproval,
62
+ approvalPolicy: tool.hitl?.enabled === true ? "explicit-hitl" : requiresApproval ? "runtime-default" : "none",
63
+ hasInputSchema: typeof tool.inputSchemaRef === "string" && tool.inputSchemaRef.trim().length > 0,
64
+ inputRiskHints: inputHints(binding, tool),
65
+ };
66
+ });
67
+ if (toolPolicies.length === 0) {
68
+ return [];
69
+ }
70
+ return [{
71
+ bundleId: `governance/${binding.agent.id}`,
72
+ title: "Runtime tool governance",
73
+ summary: `${toolPolicies.filter((tool) => tool.requiresApproval).length} of ${toolPolicies.length} tool(s) require approval`,
74
+ toolPolicies,
75
+ }];
76
+ }
@@ -1,5 +1,6 @@
1
1
  import { readSkillMetadata } from "../../support/skill-metadata.js";
2
2
  import { getBindingMemorySources, getBindingPrimaryModel, getBindingPrimaryTools, getBindingSkills, getBindingSubagents, } from "../../support/compiled-binding.js";
3
+ import { buildRuntimeGovernanceBundles } from "./governance.js";
3
4
  function asObject(value) {
4
5
  return typeof value === "object" && value !== null ? value : null;
5
6
  }
@@ -67,6 +68,9 @@ export function buildRunRuntimeSnapshot(binding, options) {
67
68
  };
68
69
  }),
69
70
  memory: getBindingMemorySources(binding),
71
+ governance: {
72
+ bundles: buildRuntimeGovernanceBundles(binding),
73
+ },
70
74
  ...(tracing ? { tracing } : {}),
71
75
  };
72
76
  }
@@ -1,7 +1,8 @@
1
- import type { CompiledAgentBinding } from "../../../contracts/types.js";
1
+ import type { CompiledAgentBinding, RuntimeGovernanceBundle } from "../../../contracts/types.js";
2
2
  export type PolicyEngineDecision = {
3
3
  allowed: boolean;
4
4
  reasons: string[];
5
+ bundles?: RuntimeGovernanceBundle[];
5
6
  };
6
7
  export declare class PolicyEngine {
7
8
  /**
@@ -7,6 +7,7 @@ export class PolicyEngine {
7
7
  */
8
8
  evaluate(binding) {
9
9
  const reasons = [];
10
+ const bundles = [];
10
11
  let allowed = true;
11
12
  for (const evaluator of getPolicyEvaluators()) {
12
13
  const decision = evaluator.evaluate(binding);
@@ -17,8 +18,11 @@ export class PolicyEngine {
17
18
  allowed = false;
18
19
  }
19
20
  reasons.push(...decision.reasons);
21
+ if (Array.isArray(decision.bundles)) {
22
+ bundles.push(...decision.bundles);
23
+ }
20
24
  }
21
- return { allowed, reasons };
25
+ return bundles.length > 0 ? { allowed, reasons, bundles } : { allowed, reasons };
22
26
  }
23
27
  }
24
28
  export { PolicyEngine as GovernanceEngine, };
@@ -1,4 +1,4 @@
1
- import type { ApprovalRecord, CancelOptions, HarnessEvent, HarnessStreamItem, RuntimeHealthSnapshot, ListMemoriesInput, ListMemoriesResult, MessageContent, RemoveMemoryInput, RunRecord, RunStartOptions, RestartConversationOptions, RuntimeAdapterOptions, ResumeOptions, RunOptions, RunResult, RunSummary, MemoryRecord, MemorizeInput, MemorizeResult, RecallInput, RecallResult, UpdateMemoryInput, ThreadSummary, ThreadRecord, WorkspaceBundle } from "../contracts/types.js";
1
+ import type { ApprovalRecord, ArtifactListing, CancelOptions, HarnessEvent, HarnessStreamItem, RuntimeHealthSnapshot, ListMemoriesInput, ListMemoriesResult, MessageContent, RemoveMemoryInput, RunRecord, RunStartOptions, RestartConversationOptions, RuntimeAdapterOptions, RuntimeEvaluationExport, RuntimeEvaluationExportInput, ResumeOptions, RunOptions, RunResult, RunSummary, MemoryRecord, MemorizeInput, MemorizeResult, RecallInput, RecallResult, UpdateMemoryInput, ThreadSummary, ThreadRecord, WorkspaceBundle } from "../contracts/types.js";
2
2
  import { type ToolMcpServerOptions } from "../mcp.js";
3
3
  import { type InventoryAgentRecord, type InventorySkillRecord } from "./harness/system/inventory.js";
4
4
  import type { RequirementAssessmentOptions } from "./harness/system/skill-requirements.js";
@@ -82,6 +82,10 @@ export declare class AgentHarnessRuntime {
82
82
  runId?: string;
83
83
  }): Promise<ApprovalRecord[]>;
84
84
  getApproval(approvalId: string): Promise<ApprovalRecord | null>;
85
+ listArtifacts(threadId: string, runId: string): Promise<ArtifactListing>;
86
+ readArtifact(threadId: string, runId: string, artifactPath: string): Promise<unknown>;
87
+ listRunEvents(threadId: string, runId: string): Promise<HarnessEvent[]>;
88
+ exportEvaluationBundle(input: RuntimeEvaluationExportInput): Promise<RuntimeEvaluationExport>;
85
89
  listAgentSkills(agentId: string, options?: RequirementAssessmentOptions): InventorySkillRecord[];
86
90
  getAgent(agentId: string, options?: RequirementAssessmentOptions): InventoryAgentRecord | null;
87
91
  describeWorkspaceInventory(options?: RequirementAssessmentOptions): {
@@ -475,6 +475,51 @@ export class AgentHarnessRuntime {
475
475
  persistence: this.persistence,
476
476
  }, approvalId);
477
477
  }
478
+ async listArtifacts(threadId, runId) {
479
+ return this.persistence.listArtifacts(threadId, runId);
480
+ }
481
+ async readArtifact(threadId, runId, artifactPath) {
482
+ return this.persistence.readArtifact(threadId, runId, artifactPath);
483
+ }
484
+ async listRunEvents(threadId, runId) {
485
+ return this.persistence.listRunEvents(threadId, runId);
486
+ }
487
+ async exportEvaluationBundle(input) {
488
+ const thread = await this.getThread(input.sessionId);
489
+ const run = await this.getRun(input.requestId);
490
+ const approvals = await this.listApprovals({ threadId: input.sessionId, runId: input.requestId });
491
+ const transcript = await this.persistence.listThreadMessages(input.sessionId, 500);
492
+ const events = await this.persistence.listRunEvents(input.sessionId, input.requestId);
493
+ const runtimeHealth = await this.getHealth();
494
+ const artifactsListing = input.includeArtifacts === false
495
+ ? { items: [] }
496
+ : await this.persistence.listArtifacts(input.sessionId, input.requestId);
497
+ const artifacts = await Promise.all(artifactsListing.items.map(async (artifact) => ({
498
+ ...artifact,
499
+ ...(input.includeArtifactContents === true
500
+ ? { content: await this.persistence.readArtifact(input.sessionId, input.requestId, artifact.path) }
501
+ : {}),
502
+ })));
503
+ return {
504
+ session: thread ? toSessionRecord(thread) : null,
505
+ request: run ? toRequestRecord(run) : null,
506
+ approvals,
507
+ transcript,
508
+ events,
509
+ artifacts,
510
+ runtimeHealth,
511
+ ...(typeof input.expectedOutput === "string" && input.expectedOutput.trim().length > 0
512
+ ? { expectedOutput: input.expectedOutput.trim() }
513
+ : {}),
514
+ rubric: Array.isArray(input.rubric)
515
+ ? input.rubric.filter((item) => typeof item === "string" && item.trim().length > 0).map((item) => item.trim())
516
+ : [],
517
+ tags: Array.isArray(input.tags)
518
+ ? input.tags.filter((item) => typeof item === "string" && item.trim().length > 0).map((item) => item.trim())
519
+ : [],
520
+ ...(input.metadata ? { metadata: { ...input.metadata } } : {}),
521
+ };
522
+ }
478
523
  listAgentSkills(agentId, options = {}) {
479
524
  return listWorkspaceAgentSkills(this.workspace, agentId, {
480
525
  assessRequirements: isInventoryEnabled(this.workspace),
@@ -1393,3 +1438,40 @@ export class AgentHarnessRuntime {
1393
1438
  }, thread, nowMs);
1394
1439
  }
1395
1440
  }
1441
+ function toRequestSummary(summary) {
1442
+ return {
1443
+ requestId: summary.runId,
1444
+ sessionId: summary.threadId,
1445
+ agentId: summary.agentId,
1446
+ executionMode: summary.executionMode,
1447
+ adapterKind: summary.adapterKind,
1448
+ createdAt: summary.createdAt,
1449
+ updatedAt: summary.updatedAt,
1450
+ state: summary.state,
1451
+ checkpointRef: summary.checkpointRef,
1452
+ resumable: summary.resumable,
1453
+ startedAt: summary.startedAt,
1454
+ endedAt: summary.endedAt,
1455
+ lastActivityAt: summary.lastActivityAt,
1456
+ currentAgentId: summary.currentAgentId,
1457
+ delegationChain: summary.delegationChain,
1458
+ runtimeSnapshot: summary.runtimeSnapshot,
1459
+ };
1460
+ }
1461
+ function toSessionRecord(record) {
1462
+ return {
1463
+ sessionId: record.threadId,
1464
+ entryAgentId: record.entryAgentId,
1465
+ currentAgentId: record.currentAgentId,
1466
+ currentState: record.currentState,
1467
+ latestRequestId: record.latestRunId,
1468
+ createdAt: record.createdAt,
1469
+ updatedAt: record.updatedAt,
1470
+ messages: record.messages,
1471
+ requests: record.runs.map(toRequestSummary),
1472
+ pendingDecision: record.pendingDecision,
1473
+ };
1474
+ }
1475
+ function toRequestRecord(record) {
1476
+ return toRequestSummary(record);
1477
+ }
@@ -337,6 +337,12 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
337
337
  const store = resolveStoreConfig(agent, refs);
338
338
  const checkpointer = resolveCheckpointerConfig(agent, refs);
339
339
  const runtimeMemory = resolveRuntimeMemoryConfig(agent, refs);
340
+ const runtimeFilesystemDefaults = agent.executionMode === "langchain-v1"
341
+ ? asObject(runtimeDefaults?.filesystem)
342
+ : undefined;
343
+ const compiledFilesystemConfig = agent.executionMode === "langchain-v1"
344
+ ? mergeConfigObjects(runtimeFilesystemDefaults, getAgentExecutionObject(agent, "filesystem", { executionMode: "langchain-v1" }))
345
+ : undefined;
340
346
  const runRoot = typeof agent.runRoot === "string" && agent.runRoot.trim().length > 0
341
347
  ? path.resolve(workspaceRoot, agent.runRoot)
342
348
  : typeof runtimeDefaults?.runRoot === "string" && runtimeDefaults.runRoot.trim().length > 0
@@ -362,7 +368,7 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
362
368
  langchain: {
363
369
  passthrough,
364
370
  interruptOn: resolveInterruptOn(agent),
365
- filesystem: getAgentExecutionObject(agent, "filesystem", { executionMode: "langchain-v1" }),
371
+ filesystem: compiledFilesystemConfig,
366
372
  subagents: compileSubagents(agent, agents, workspaceRoot, models, tools, compiledAgentSkills, compiledAgentModel),
367
373
  memory: compiledAgentMemory,
368
374
  skills: compiledAgentSkills,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@botbotgo/agent-harness",
3
- "version": "0.0.156",
3
+ "version": "0.0.157",
4
4
  "description": "Workspace runtime for multi-agent applications",
5
5
  "type": "module",
6
6
  "packageManager": "npm@10.9.2",
@@ -28,6 +28,11 @@
28
28
  "import": "./dist/index.js",
29
29
  "default": "./dist/index.js"
30
30
  },
31
+ "./acp": {
32
+ "types": "./dist/acp.d.ts",
33
+ "import": "./dist/acp.js",
34
+ "default": "./dist/acp.js"
35
+ },
31
36
  "./tools": {
32
37
  "types": "./dist/tools.d.ts",
33
38
  "import": "./dist/tools.js",