@botbotgo/agent-harness 0.0.159 → 0.0.161
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 +12 -0
- package/README.zh.md +12 -0
- package/dist/api.d.ts +13 -2
- package/dist/api.js +20 -0
- package/dist/cli.d.ts +9 -1
- package/dist/cli.js +99 -1
- package/dist/contracts/runtime.d.ts +53 -0
- package/dist/contracts/workspace.d.ts +1 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +1 -1
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/protocol/acp/http.d.ts +20 -0
- package/dist/protocol/acp/http.js +130 -0
- package/dist/protocol/acp/stdio.d.ts +11 -0
- package/dist/protocol/acp/stdio.js +69 -0
- package/dist/runtime/harness/run/governance.js +61 -2
- package/dist/runtime/harness/system/policy-engine.js +29 -0
- package/dist/runtime/harness.d.ts +4 -1
- package/dist/runtime/harness.js +88 -0
- package/dist/workspace/agent-binding-compiler.js +2 -0
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -881,8 +881,14 @@ Primary exports:
|
|
|
881
881
|
- `getApproval`
|
|
882
882
|
- `listArtifacts`
|
|
883
883
|
- `getArtifact`
|
|
884
|
+
- `listRunEvents`
|
|
885
|
+
- `exportRunPackage`
|
|
886
|
+
- `exportSessionPackage`
|
|
884
887
|
- `exportEvaluationBundle`
|
|
888
|
+
- `replayEvaluationBundle`
|
|
885
889
|
- `createAcpServer`
|
|
890
|
+
- `serveAcpHttp`
|
|
891
|
+
- `serveAcpStdio`
|
|
886
892
|
- `createToolMcpServer`
|
|
887
893
|
- `serveToolsOverStdio`
|
|
888
894
|
- `stop`
|
|
@@ -899,3 +905,9 @@ Inspection helpers:
|
|
|
899
905
|
- `exportFlowGraphToSequenceMermaid(...)` renders the same inspection graph as a Mermaid sequence diagram. By default it emits only user-defined participants and calls, while `view: "debug"` includes runtime participants and lifecycle messages.
|
|
900
906
|
|
|
901
907
|
These helpers are visualization and inspection utilities. They do not introduce a canonical harness-owned execution protocol.
|
|
908
|
+
|
|
909
|
+
ACP transport notes:
|
|
910
|
+
|
|
911
|
+
- `serveAcpStdio(runtime)` exposes newline-delimited JSON-RPC over stdio for local IDE, CLI, or subprocess clients.
|
|
912
|
+
- `serveAcpHttp(runtime)` exposes JSON-RPC over HTTP plus SSE runtime events so remote operator surfaces can connect without importing the runtime in-process.
|
|
913
|
+
- `exportRunPackage(...)` and `exportSessionPackage(...)` package stable runtime records, transcript, approvals, events, and artifacts for operator tooling without reaching into persistence internals.
|
package/README.zh.md
CHANGED
|
@@ -840,8 +840,14 @@ spec:
|
|
|
840
840
|
- `getApproval`
|
|
841
841
|
- `listArtifacts`
|
|
842
842
|
- `getArtifact`
|
|
843
|
+
- `listRunEvents`
|
|
844
|
+
- `exportRunPackage`
|
|
845
|
+
- `exportSessionPackage`
|
|
843
846
|
- `exportEvaluationBundle`
|
|
847
|
+
- `replayEvaluationBundle`
|
|
844
848
|
- `createAcpServer`
|
|
849
|
+
- `serveAcpHttp`
|
|
850
|
+
- `serveAcpStdio`
|
|
845
851
|
- `createToolMcpServer`
|
|
846
852
|
- `serveToolsOverStdio`
|
|
847
853
|
- `stop`
|
|
@@ -858,3 +864,9 @@ Inspection 辅助工具:
|
|
|
858
864
|
- `exportFlowGraphToSequenceMermaid(...)` 可把同一份 inspection graph 导出为 Mermaid sequence diagram。默认只输出用户定义的参与者与调用;传 `view: "debug"` 才会包含 runtime participant 与生命周期消息。
|
|
859
865
|
|
|
860
866
|
这些 helper 只用于可视化与检查,不代表新的 harness 官方执行协议。
|
|
867
|
+
|
|
868
|
+
ACP transport 说明:
|
|
869
|
+
|
|
870
|
+
- `serveAcpStdio(runtime)` 提供基于 stdio 的 newline-delimited JSON-RPC,适合本地 IDE、CLI 或子进程客户端。
|
|
871
|
+
- `serveAcpHttp(runtime)` 提供基于 HTTP 的 JSON-RPC 与 SSE runtime events,适合远程 operator surface 或独立控制面接入。
|
|
872
|
+
- `exportRunPackage(...)` 与 `exportSessionPackage(...)` 可把稳定 runtime 记录、transcript、approvals、events 和 artifacts 打包给 operator tooling,而不必直接访问 persistence 内部实现。
|
package/dist/api.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
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";
|
|
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, RuntimeEvaluationReplayInput, RuntimeEvaluationReplayResult, RuntimeRunPackage, RuntimeRunPackageInput, RuntimeSessionPackage, RuntimeSessionPackageInput, 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";
|
|
@@ -8,7 +8,9 @@ export type { AcpApproval, AcpArtifact, AcpEventNotification, AcpJsonRpcError, A
|
|
|
8
8
|
export { AgentHarnessRuntime } from "./runtime/harness.js";
|
|
9
9
|
export { buildFlowGraph, exportFlowGraphToMermaid, exportFlowGraphToSequenceMermaid } from "./flow/index.js";
|
|
10
10
|
export { createUpstreamTimelineReducer } from "./upstream-events.js";
|
|
11
|
-
export type { ListMemoriesInput, ListMemoriesResult, MemoryDecision, MemoryKind, MemoryRecord, MemoryScope, MemorizeInput, MemorizeResult, RecallInput, RecallResult, RemoveMemoryInput, RuntimeEvaluationExport, RuntimeEvaluationExportInput, UpdateMemoryInput, } from "./contracts/types.js";
|
|
11
|
+
export type { ListMemoriesInput, ListMemoriesResult, MemoryDecision, MemoryKind, MemoryRecord, MemoryScope, MemorizeInput, MemorizeResult, RecallInput, RecallResult, RemoveMemoryInput, RuntimeEvaluationExport, RuntimeEvaluationExportInput, RuntimeEvaluationReplayInput, RuntimeEvaluationReplayResult, RuntimeRunPackage, RuntimeRunPackageInput, RuntimeSessionPackage, RuntimeSessionPackageInput, UpdateMemoryInput, } from "./contracts/types.js";
|
|
12
|
+
export type { AcpHttpServer, AcpHttpServerOptions } from "./protocol/acp/http.js";
|
|
13
|
+
export type { AcpStdioServer, AcpStdioServerOptions } from "./protocol/acp/stdio.js";
|
|
12
14
|
type PublicApprovalRecord = {
|
|
13
15
|
approvalId: string;
|
|
14
16
|
pendingActionId: string;
|
|
@@ -84,8 +86,17 @@ export declare function getArtifact(runtime: AgentHarnessRuntime, input: {
|
|
|
84
86
|
requestId: string;
|
|
85
87
|
artifactPath: string;
|
|
86
88
|
}): Promise<unknown>;
|
|
89
|
+
export declare function listRunEvents(runtime: AgentHarnessRuntime, input: {
|
|
90
|
+
sessionId: string;
|
|
91
|
+
requestId: string;
|
|
92
|
+
}): Promise<import("./contracts/runtime.js").HarnessEvent[]>;
|
|
87
93
|
export declare function getHealth(runtime: AgentHarnessRuntime): Promise<RuntimeHealthSnapshot>;
|
|
94
|
+
export declare function exportRunPackage(runtime: AgentHarnessRuntime, input: RuntimeRunPackageInput): Promise<RuntimeRunPackage>;
|
|
95
|
+
export declare function exportSessionPackage(runtime: AgentHarnessRuntime, input: RuntimeSessionPackageInput): Promise<RuntimeSessionPackage>;
|
|
88
96
|
export declare function exportEvaluationBundle(runtime: AgentHarnessRuntime, input: RuntimeEvaluationExportInput): Promise<RuntimeEvaluationExport>;
|
|
97
|
+
export declare function replayEvaluationBundle(runtime: AgentHarnessRuntime, input: RuntimeEvaluationReplayInput): Promise<RuntimeEvaluationReplayResult>;
|
|
98
|
+
export declare function serveAcpStdio(runtime: AgentHarnessRuntime, options?: import("./protocol/acp/stdio.js").AcpStdioServerOptions): import("./protocol/acp/stdio.js").AcpStdioServer;
|
|
99
|
+
export declare function serveAcpHttp(runtime: AgentHarnessRuntime, options?: import("./protocol/acp/http.js").AcpHttpServerOptions): Promise<import("./protocol/acp/http.js").AcpHttpServer>;
|
|
89
100
|
export declare function listAgentSkills(runtime: AgentHarnessRuntime, agentId: string, options?: RequirementAssessmentOptions): InventorySkillRecord[];
|
|
90
101
|
export declare function getAgent(runtime: AgentHarnessRuntime, agentId: string, options?: RequirementAssessmentOptions): InventoryAgentRecord | null;
|
|
91
102
|
export declare function describeInventory(runtime: AgentHarnessRuntime, options?: RequirementAssessmentOptions): {
|
package/dist/api.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { AgentHarnessRuntime } from "./runtime/harness.js";
|
|
2
|
+
import { serveAcpOverHttp } from "./protocol/acp/http.js";
|
|
3
|
+
import { serveAcpOverStdio } from "./protocol/acp/stdio.js";
|
|
2
4
|
import { normalizeMessageContent } from "./utils/message-content.js";
|
|
3
5
|
import { loadWorkspace } from "./workspace/compile.js";
|
|
4
6
|
export { AgentHarnessAcpServer, createAcpServer } from "./acp.js";
|
|
@@ -186,12 +188,30 @@ export async function listArtifacts(runtime, input) {
|
|
|
186
188
|
export async function getArtifact(runtime, input) {
|
|
187
189
|
return runtime.readArtifact(input.sessionId, input.requestId, input.artifactPath);
|
|
188
190
|
}
|
|
191
|
+
export async function listRunEvents(runtime, input) {
|
|
192
|
+
return runtime.listRunEvents(input.sessionId, input.requestId);
|
|
193
|
+
}
|
|
189
194
|
export async function getHealth(runtime) {
|
|
190
195
|
return runtime.getHealth();
|
|
191
196
|
}
|
|
197
|
+
export async function exportRunPackage(runtime, input) {
|
|
198
|
+
return runtime.exportRunPackage(input);
|
|
199
|
+
}
|
|
200
|
+
export async function exportSessionPackage(runtime, input) {
|
|
201
|
+
return runtime.exportSessionPackage(input);
|
|
202
|
+
}
|
|
192
203
|
export async function exportEvaluationBundle(runtime, input) {
|
|
193
204
|
return runtime.exportEvaluationBundle(input);
|
|
194
205
|
}
|
|
206
|
+
export async function replayEvaluationBundle(runtime, input) {
|
|
207
|
+
return runtime.replayEvaluationBundle(input);
|
|
208
|
+
}
|
|
209
|
+
export function serveAcpStdio(runtime, options) {
|
|
210
|
+
return serveAcpOverStdio(runtime, options);
|
|
211
|
+
}
|
|
212
|
+
export async function serveAcpHttp(runtime, options) {
|
|
213
|
+
return serveAcpOverHttp(runtime, options);
|
|
214
|
+
}
|
|
195
215
|
export function listAgentSkills(runtime, agentId, options) {
|
|
196
216
|
return runtime.listAgentSkills(agentId, options);
|
|
197
217
|
}
|
package/dist/cli.d.ts
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
import { createAgentHarness } from "./api.js";
|
|
3
|
+
import { serveAcpOverHttp } from "./protocol/acp/http.js";
|
|
4
|
+
import { serveAcpOverStdio } from "./protocol/acp/stdio.js";
|
|
2
5
|
type CliIo = {
|
|
3
6
|
cwd?: string;
|
|
4
7
|
stdout?: (message: string) => void;
|
|
5
8
|
stderr?: (message: string) => void;
|
|
6
9
|
};
|
|
7
|
-
|
|
10
|
+
type CliDeps = {
|
|
11
|
+
createAgentHarness?: typeof createAgentHarness;
|
|
12
|
+
serveAcpOverHttp?: typeof serveAcpOverHttp;
|
|
13
|
+
serveAcpOverStdio?: typeof serveAcpOverStdio;
|
|
14
|
+
};
|
|
15
|
+
export declare function runCli(argv: string[], io?: CliIo, deps?: CliDeps): Promise<number>;
|
|
8
16
|
export {};
|
package/dist/cli.js
CHANGED
|
@@ -1,10 +1,14 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { pathToFileURL } from "node:url";
|
|
4
|
+
import { createAgentHarness } from "./api.js";
|
|
4
5
|
import { initProject } from "./init-project.js";
|
|
6
|
+
import { serveAcpOverHttp } from "./protocol/acp/http.js";
|
|
7
|
+
import { serveAcpOverStdio } from "./protocol/acp/stdio.js";
|
|
5
8
|
function renderUsage() {
|
|
6
9
|
return `Usage:
|
|
7
10
|
agent-harness init <project-name> [--template deep-research|single-agent] [--provider <provider>] [--model <model>] [--with-web-search|--no-web-search]
|
|
11
|
+
agent-harness acp serve [--workspace <path>] [--transport stdio|http] [--host <hostname>] [--port <port>]
|
|
8
12
|
`;
|
|
9
13
|
}
|
|
10
14
|
function isTemplate(value) {
|
|
@@ -46,11 +50,68 @@ function parseInitOptions(args) {
|
|
|
46
50
|
}
|
|
47
51
|
return { options };
|
|
48
52
|
}
|
|
49
|
-
|
|
53
|
+
function parseAcpServeOptions(args) {
|
|
54
|
+
let workspaceRoot;
|
|
55
|
+
let transport = "stdio";
|
|
56
|
+
let hostname;
|
|
57
|
+
let port;
|
|
58
|
+
for (let index = 0; index < args.length; index += 1) {
|
|
59
|
+
const arg = args[index];
|
|
60
|
+
if (arg === "--workspace") {
|
|
61
|
+
const value = args[index + 1];
|
|
62
|
+
if (!value) {
|
|
63
|
+
return { transport, error: "Missing value for --workspace" };
|
|
64
|
+
}
|
|
65
|
+
workspaceRoot = value;
|
|
66
|
+
index += 1;
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
if (arg === "--transport") {
|
|
70
|
+
const value = args[index + 1];
|
|
71
|
+
if (!value) {
|
|
72
|
+
return { transport, hostname, port, error: "Missing value for --transport" };
|
|
73
|
+
}
|
|
74
|
+
if (value !== "stdio" && value !== "http") {
|
|
75
|
+
return { transport, hostname, port, error: `Unsupported ACP transport: ${value}` };
|
|
76
|
+
}
|
|
77
|
+
transport = value;
|
|
78
|
+
index += 1;
|
|
79
|
+
continue;
|
|
80
|
+
}
|
|
81
|
+
if (arg === "--host") {
|
|
82
|
+
const value = args[index + 1];
|
|
83
|
+
if (!value) {
|
|
84
|
+
return { transport, hostname, port, error: "Missing value for --host" };
|
|
85
|
+
}
|
|
86
|
+
hostname = value;
|
|
87
|
+
index += 1;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (arg === "--port") {
|
|
91
|
+
const value = args[index + 1];
|
|
92
|
+
if (!value) {
|
|
93
|
+
return { transport, hostname, port, error: "Missing value for --port" };
|
|
94
|
+
}
|
|
95
|
+
const parsedPort = Number.parseInt(value, 10);
|
|
96
|
+
if (!Number.isFinite(parsedPort) || parsedPort < 0) {
|
|
97
|
+
return { transport, hostname, port, error: `Invalid ACP port: ${value}` };
|
|
98
|
+
}
|
|
99
|
+
port = parsedPort;
|
|
100
|
+
index += 1;
|
|
101
|
+
continue;
|
|
102
|
+
}
|
|
103
|
+
return { transport, hostname, port, error: `Unknown option: ${arg}` };
|
|
104
|
+
}
|
|
105
|
+
return { workspaceRoot, transport, hostname, port };
|
|
106
|
+
}
|
|
107
|
+
export async function runCli(argv, io = {}, deps = {}) {
|
|
50
108
|
const cwd = io.cwd ?? process.cwd();
|
|
51
109
|
const stdout = io.stdout ?? ((message) => process.stdout.write(message));
|
|
52
110
|
const stderr = io.stderr ?? ((message) => process.stderr.write(message));
|
|
53
111
|
const [command, projectName, ...rest] = argv;
|
|
112
|
+
const createHarness = deps.createAgentHarness ?? createAgentHarness;
|
|
113
|
+
const serveAcpHttp = deps.serveAcpOverHttp ?? serveAcpOverHttp;
|
|
114
|
+
const serveAcp = deps.serveAcpOverStdio ?? serveAcpOverStdio;
|
|
54
115
|
if (command === "init") {
|
|
55
116
|
if (!projectName?.trim()) {
|
|
56
117
|
stderr(renderUsage());
|
|
@@ -81,6 +142,43 @@ export async function runCli(argv, io = {}) {
|
|
|
81
142
|
return 1;
|
|
82
143
|
}
|
|
83
144
|
}
|
|
145
|
+
if (command === "acp") {
|
|
146
|
+
const [subcommand, ...subcommandArgs] = [projectName, ...rest];
|
|
147
|
+
if (subcommand !== "serve") {
|
|
148
|
+
stderr(renderUsage());
|
|
149
|
+
return 1;
|
|
150
|
+
}
|
|
151
|
+
const parsed = parseAcpServeOptions(subcommandArgs);
|
|
152
|
+
if (parsed.error) {
|
|
153
|
+
stderr(`${parsed.error}\n`);
|
|
154
|
+
stderr(renderUsage());
|
|
155
|
+
return 1;
|
|
156
|
+
}
|
|
157
|
+
try {
|
|
158
|
+
const runtime = await createHarness(path.resolve(cwd, parsed.workspaceRoot ?? "."));
|
|
159
|
+
const workspacePath = path.resolve(cwd, parsed.workspaceRoot ?? ".");
|
|
160
|
+
if (parsed.transport === "http") {
|
|
161
|
+
const server = await serveAcpHttp(runtime, {
|
|
162
|
+
hostname: parsed.hostname,
|
|
163
|
+
port: parsed.port,
|
|
164
|
+
});
|
|
165
|
+
stderr(`Serving ACP over http from ${workspacePath} at ${server.rpcUrl} (events ${server.eventsUrl})\n`);
|
|
166
|
+
await server.completed;
|
|
167
|
+
}
|
|
168
|
+
else {
|
|
169
|
+
stderr(`Serving ACP over stdio from ${workspacePath}\n`);
|
|
170
|
+
const server = serveAcp(runtime);
|
|
171
|
+
await server.completed;
|
|
172
|
+
}
|
|
173
|
+
await runtime.stop();
|
|
174
|
+
return 0;
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
178
|
+
stderr(`${message}\n`);
|
|
179
|
+
return 1;
|
|
180
|
+
}
|
|
181
|
+
}
|
|
84
182
|
stderr(renderUsage());
|
|
85
183
|
return 1;
|
|
86
184
|
}
|
|
@@ -593,6 +593,11 @@ export type RuntimeEvaluationArtifact = ArtifactRecord & {
|
|
|
593
593
|
export type RuntimeEvaluationExport = {
|
|
594
594
|
session: SessionRecord | null;
|
|
595
595
|
request: RequestRecord | null;
|
|
596
|
+
runRequest: {
|
|
597
|
+
input: MessageContent;
|
|
598
|
+
invocation?: InvocationEnvelope;
|
|
599
|
+
priority?: number;
|
|
600
|
+
} | null;
|
|
596
601
|
approvals: ApprovalRecord[];
|
|
597
602
|
transcript: TranscriptMessage[];
|
|
598
603
|
events: HarnessEvent[];
|
|
@@ -603,6 +608,54 @@ export type RuntimeEvaluationExport = {
|
|
|
603
608
|
tags: string[];
|
|
604
609
|
metadata?: Record<string, unknown>;
|
|
605
610
|
};
|
|
611
|
+
export type RuntimeEvaluationReplayInput = {
|
|
612
|
+
bundle: RuntimeEvaluationExport;
|
|
613
|
+
agentId?: string;
|
|
614
|
+
sessionId?: string;
|
|
615
|
+
invocation?: InvocationEnvelope;
|
|
616
|
+
};
|
|
617
|
+
export type RuntimeEvaluationReplayResult = {
|
|
618
|
+
request: {
|
|
619
|
+
agentId: string;
|
|
620
|
+
input: MessageContent;
|
|
621
|
+
invocation?: InvocationEnvelope;
|
|
622
|
+
sessionId?: string;
|
|
623
|
+
};
|
|
624
|
+
result: RunResult;
|
|
625
|
+
assertions: {
|
|
626
|
+
expectedOutputMatched?: boolean;
|
|
627
|
+
};
|
|
628
|
+
};
|
|
629
|
+
export type RuntimeRunPackageInput = {
|
|
630
|
+
sessionId: string;
|
|
631
|
+
requestId: string;
|
|
632
|
+
includeArtifacts?: boolean;
|
|
633
|
+
includeArtifactContents?: boolean;
|
|
634
|
+
includeRuntimeHealth?: boolean;
|
|
635
|
+
};
|
|
636
|
+
export type RuntimeRunPackage = {
|
|
637
|
+
session: SessionRecord | null;
|
|
638
|
+
request: RequestRecord | null;
|
|
639
|
+
approvals: ApprovalRecord[];
|
|
640
|
+
transcript: TranscriptMessage[];
|
|
641
|
+
events: HarnessEvent[];
|
|
642
|
+
artifacts: RuntimeEvaluationArtifact[];
|
|
643
|
+
runtimeHealth?: RuntimeHealthSnapshot;
|
|
644
|
+
};
|
|
645
|
+
export type RuntimeSessionPackageInput = {
|
|
646
|
+
sessionId: string;
|
|
647
|
+
includeArtifacts?: boolean;
|
|
648
|
+
includeArtifactContents?: boolean;
|
|
649
|
+
includeRuntimeHealth?: boolean;
|
|
650
|
+
};
|
|
651
|
+
export type RuntimeSessionPackage = {
|
|
652
|
+
session: SessionRecord | null;
|
|
653
|
+
requests: RequestRecord[];
|
|
654
|
+
approvals: ApprovalRecord[];
|
|
655
|
+
transcript: TranscriptMessage[];
|
|
656
|
+
runs: RuntimeRunPackage[];
|
|
657
|
+
runtimeHealth?: RuntimeHealthSnapshot;
|
|
658
|
+
};
|
|
606
659
|
export type RuntimeInventoryContext = {
|
|
607
660
|
workspace: WorkspaceBundle;
|
|
608
661
|
};
|
|
@@ -234,6 +234,7 @@ export type CompiledAgentBinding = {
|
|
|
234
234
|
workspaceRoot?: string;
|
|
235
235
|
capabilities?: RuntimeCapabilities;
|
|
236
236
|
resilience?: Record<string, unknown>;
|
|
237
|
+
governance?: Record<string, unknown>;
|
|
237
238
|
deepagent?: {
|
|
238
239
|
description?: string;
|
|
239
240
|
passthrough?: Record<string, unknown>;
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
-
export { AgentHarnessAcpServer, AgentHarnessRuntime, buildFlowGraph, 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, exportFlowGraphToMermaid, exportFlowGraphToSequenceMermaid, } from "./api.js";
|
|
1
|
+
export { AgentHarnessAcpServer, AgentHarnessRuntime, buildFlowGraph, cancelRun, createAgentHarness, createAcpServer, createUpstreamTimelineReducer, createToolMcpServer, deleteSession, describeInventory, exportEvaluationBundle, exportRunPackage, exportSessionPackage, replayEvaluationBundle, getArtifact, getAgent, getApproval, getRequest, getHealth, listMemories, listRunEvents, getSession, listAgentSkills, listArtifacts, listApprovals, listRequests, listSessions, memorize, normalizeUserChatInput, recall, removeMemory, resolveApproval, run, serveAcpHttp, serveAcpStdio, serveToolsOverStdio, subscribe, stop, updateMemory, exportFlowGraphToMermaid, exportFlowGraphToSequenceMermaid, } from "./api.js";
|
|
2
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
|
+
export type { ListMemoriesInput, ListMemoriesResult, MemoryDecision, MemoryKind, MemoryRecord, MemoryScope, MemorizeInput, MemorizeResult, NormalizeUserChatInputOptions, RecallInput, RecallResult, RemoveMemoryInput, RuntimeEvaluationExport, RuntimeEvaluationExportInput, RuntimeEvaluationReplayInput, RuntimeEvaluationReplayResult, RuntimeRunPackage, RuntimeRunPackageInput, RuntimeSessionPackage, RuntimeSessionPackageInput, UpdateMemoryInput, UserChatInput, UserChatMessage, } from "./api.js";
|
|
4
4
|
export type { BuildFlowGraphInput, FlowEdge, FlowEdgeKind, FlowGraph, FlowGraphMermaidOptions, FlowGraphSequenceMermaidOptions, FlowGroup, FlowGroupKind, FlowNode, FlowNodeKind, FlowNodeLayer, FlowNodeStatus, } from "./flow/index.js";
|
|
5
|
+
export type { AcpHttpServer, AcpHttpServerOptions, AcpStdioServer, AcpStdioServerOptions } from "./api.js";
|
|
5
6
|
export type { ToolMcpServerOptions } from "./mcp.js";
|
|
6
7
|
export { tool } from "./tools.js";
|
|
7
8
|
export type { UpstreamTimelineProjection, UpstreamTimelineReducer } from "./upstream-events.js";
|
package/dist/index.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { AgentHarnessAcpServer, AgentHarnessRuntime, buildFlowGraph, 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, exportFlowGraphToMermaid, exportFlowGraphToSequenceMermaid, } from "./api.js";
|
|
1
|
+
export { AgentHarnessAcpServer, AgentHarnessRuntime, buildFlowGraph, cancelRun, createAgentHarness, createAcpServer, createUpstreamTimelineReducer, createToolMcpServer, deleteSession, describeInventory, exportEvaluationBundle, exportRunPackage, exportSessionPackage, replayEvaluationBundle, getArtifact, getAgent, getApproval, getRequest, getHealth, listMemories, listRunEvents, getSession, listAgentSkills, listArtifacts, listApprovals, listRequests, listSessions, memorize, normalizeUserChatInput, recall, removeMemory, resolveApproval, run, serveAcpHttp, serveAcpStdio, serveToolsOverStdio, subscribe, stop, updateMemory, exportFlowGraphToMermaid, exportFlowGraphToSequenceMermaid, } from "./api.js";
|
|
2
2
|
export { tool } from "./tools.js";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export declare const AGENT_HARNESS_VERSION = "0.0.160";
|
package/dist/package-version.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export const AGENT_HARNESS_VERSION = "0.0.160";
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { type Server } from "node:http";
|
|
2
|
+
import type { AgentHarnessRuntime } from "../../runtime/harness.js";
|
|
3
|
+
export type AcpHttpServerOptions = {
|
|
4
|
+
hostname?: string;
|
|
5
|
+
port?: number;
|
|
6
|
+
rpcPath?: string;
|
|
7
|
+
eventsPath?: string;
|
|
8
|
+
};
|
|
9
|
+
export type AcpHttpServer = {
|
|
10
|
+
hostname: string;
|
|
11
|
+
port: number;
|
|
12
|
+
rpcPath: string;
|
|
13
|
+
eventsPath: string;
|
|
14
|
+
rpcUrl: string;
|
|
15
|
+
eventsUrl: string;
|
|
16
|
+
completed: Promise<void>;
|
|
17
|
+
close: () => Promise<void>;
|
|
18
|
+
};
|
|
19
|
+
export declare function serveAcpOverHttp(runtime: AgentHarnessRuntime, options?: AcpHttpServerOptions): Promise<AcpHttpServer>;
|
|
20
|
+
export type { Server as AcpHttpNodeServer };
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { createServer } from "node:http";
|
|
2
|
+
import { createAcpServer } from "../../acp.js";
|
|
3
|
+
function normalizePath(value, fallback) {
|
|
4
|
+
const source = typeof value === "string" && value.trim().length > 0 ? value.trim() : fallback;
|
|
5
|
+
return source.startsWith("/") ? source : `/${source}`;
|
|
6
|
+
}
|
|
7
|
+
function writeJson(response, statusCode, payload) {
|
|
8
|
+
response.statusCode = statusCode;
|
|
9
|
+
response.setHeader("content-type", "application/json; charset=utf-8");
|
|
10
|
+
response.end(JSON.stringify(payload));
|
|
11
|
+
}
|
|
12
|
+
function readRequestBody(request) {
|
|
13
|
+
return new Promise((resolve, reject) => {
|
|
14
|
+
const chunks = [];
|
|
15
|
+
request.on("data", (chunk) => {
|
|
16
|
+
chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
|
|
17
|
+
});
|
|
18
|
+
request.on("end", () => {
|
|
19
|
+
resolve(Buffer.concat(chunks).toString("utf8"));
|
|
20
|
+
});
|
|
21
|
+
request.on("error", reject);
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
export async function serveAcpOverHttp(runtime, options = {}) {
|
|
25
|
+
const hostname = options.hostname?.trim() || "127.0.0.1";
|
|
26
|
+
const port = typeof options.port === "number" && Number.isFinite(options.port) ? options.port : 0;
|
|
27
|
+
const rpcPath = normalizePath(options.rpcPath, "/rpc");
|
|
28
|
+
const eventsPath = normalizePath(options.eventsPath, "/events");
|
|
29
|
+
const server = createAcpServer(runtime);
|
|
30
|
+
const eventSubscribers = new Set();
|
|
31
|
+
const unsubscribe = server.subscribe((notification) => {
|
|
32
|
+
const payload = `data: ${JSON.stringify(notification)}\n\n`;
|
|
33
|
+
for (const response of Array.from(eventSubscribers)) {
|
|
34
|
+
if (response.writableEnded || response.destroyed) {
|
|
35
|
+
eventSubscribers.delete(response);
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
response.write(payload);
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
const httpServer = createServer(async (request, response) => {
|
|
42
|
+
try {
|
|
43
|
+
const requestUrl = new URL(request.url ?? "/", `http://${hostname}`);
|
|
44
|
+
if (request.method === "GET" && requestUrl.pathname === eventsPath) {
|
|
45
|
+
response.statusCode = 200;
|
|
46
|
+
response.setHeader("content-type", "text/event-stream; charset=utf-8");
|
|
47
|
+
response.setHeader("cache-control", "no-cache, no-transform");
|
|
48
|
+
response.setHeader("connection", "keep-alive");
|
|
49
|
+
response.write(": connected\n\n");
|
|
50
|
+
eventSubscribers.add(response);
|
|
51
|
+
request.on("close", () => {
|
|
52
|
+
eventSubscribers.delete(response);
|
|
53
|
+
response.end();
|
|
54
|
+
});
|
|
55
|
+
return;
|
|
56
|
+
}
|
|
57
|
+
if (request.method === "POST" && requestUrl.pathname === rpcPath) {
|
|
58
|
+
const body = await readRequestBody(request);
|
|
59
|
+
let payload;
|
|
60
|
+
try {
|
|
61
|
+
payload = JSON.parse(body);
|
|
62
|
+
}
|
|
63
|
+
catch {
|
|
64
|
+
writeJson(response, 400, {
|
|
65
|
+
jsonrpc: "2.0",
|
|
66
|
+
id: null,
|
|
67
|
+
error: {
|
|
68
|
+
code: -32700,
|
|
69
|
+
message: "Invalid JSON payload.",
|
|
70
|
+
},
|
|
71
|
+
});
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
const rpcResponse = await server.handle(payload);
|
|
75
|
+
if (!rpcResponse) {
|
|
76
|
+
response.statusCode = 204;
|
|
77
|
+
response.end();
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
writeJson(response, 200, rpcResponse);
|
|
81
|
+
return;
|
|
82
|
+
}
|
|
83
|
+
writeJson(response, 404, {
|
|
84
|
+
error: "Not Found",
|
|
85
|
+
rpcPath,
|
|
86
|
+
eventsPath,
|
|
87
|
+
});
|
|
88
|
+
}
|
|
89
|
+
catch (error) {
|
|
90
|
+
writeJson(response, 500, {
|
|
91
|
+
error: error instanceof Error ? error.message : "ACP HTTP transport failed.",
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
const completed = new Promise((resolve, reject) => {
|
|
96
|
+
httpServer.once("close", resolve);
|
|
97
|
+
httpServer.once("error", reject);
|
|
98
|
+
});
|
|
99
|
+
await new Promise((resolve, reject) => {
|
|
100
|
+
httpServer.listen(port, hostname, () => resolve());
|
|
101
|
+
httpServer.once("error", reject);
|
|
102
|
+
});
|
|
103
|
+
const address = httpServer.address();
|
|
104
|
+
const resolvedPort = typeof address === "object" && address ? address.port : port;
|
|
105
|
+
return {
|
|
106
|
+
hostname,
|
|
107
|
+
port: resolvedPort,
|
|
108
|
+
rpcPath,
|
|
109
|
+
eventsPath,
|
|
110
|
+
rpcUrl: `http://${hostname}:${resolvedPort}${rpcPath}`,
|
|
111
|
+
eventsUrl: `http://${hostname}:${resolvedPort}${eventsPath}`,
|
|
112
|
+
completed,
|
|
113
|
+
close: async () => {
|
|
114
|
+
unsubscribe();
|
|
115
|
+
for (const response of Array.from(eventSubscribers)) {
|
|
116
|
+
response.end();
|
|
117
|
+
}
|
|
118
|
+
eventSubscribers.clear();
|
|
119
|
+
await new Promise((resolve, reject) => {
|
|
120
|
+
httpServer.close((error) => {
|
|
121
|
+
if (error) {
|
|
122
|
+
reject(error);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
resolve();
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
},
|
|
129
|
+
};
|
|
130
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Readable, Writable } from "node:stream";
|
|
2
|
+
import type { AgentHarnessRuntime } from "../../runtime/harness.js";
|
|
3
|
+
export type AcpStdioServerOptions = {
|
|
4
|
+
input?: Readable;
|
|
5
|
+
output?: Writable;
|
|
6
|
+
};
|
|
7
|
+
export type AcpStdioServer = {
|
|
8
|
+
completed: Promise<void>;
|
|
9
|
+
close: () => Promise<void>;
|
|
10
|
+
};
|
|
11
|
+
export declare function serveAcpOverStdio(runtime: AgentHarnessRuntime, options?: AcpStdioServerOptions): AcpStdioServer;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { createInterface } from "node:readline";
|
|
2
|
+
import { createAcpServer } from "../../acp.js";
|
|
3
|
+
function writeJsonLine(output, payload) {
|
|
4
|
+
return new Promise((resolve, reject) => {
|
|
5
|
+
output.write(`${JSON.stringify(payload)}\n`, (error) => {
|
|
6
|
+
if (error) {
|
|
7
|
+
reject(error);
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
resolve();
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
}
|
|
14
|
+
export function serveAcpOverStdio(runtime, options = {}) {
|
|
15
|
+
const input = options.input ?? process.stdin;
|
|
16
|
+
const output = options.output ?? process.stdout;
|
|
17
|
+
const server = createAcpServer(runtime);
|
|
18
|
+
const unsubscribe = server.subscribe((notification) => {
|
|
19
|
+
void writeJsonLine(output, notification);
|
|
20
|
+
});
|
|
21
|
+
const lineReader = createInterface({
|
|
22
|
+
input,
|
|
23
|
+
crlfDelay: Infinity,
|
|
24
|
+
});
|
|
25
|
+
const completed = (async () => {
|
|
26
|
+
try {
|
|
27
|
+
for await (const line of lineReader) {
|
|
28
|
+
const trimmed = line.trim();
|
|
29
|
+
if (trimmed.length === 0) {
|
|
30
|
+
continue;
|
|
31
|
+
}
|
|
32
|
+
let request;
|
|
33
|
+
try {
|
|
34
|
+
request = JSON.parse(trimmed);
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
await writeJsonLine(output, {
|
|
38
|
+
jsonrpc: "2.0",
|
|
39
|
+
id: null,
|
|
40
|
+
error: {
|
|
41
|
+
code: -32700,
|
|
42
|
+
message: "Invalid JSON payload.",
|
|
43
|
+
},
|
|
44
|
+
});
|
|
45
|
+
continue;
|
|
46
|
+
}
|
|
47
|
+
const response = await server.handle(request);
|
|
48
|
+
if (response) {
|
|
49
|
+
await writeJsonLine(output, response);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
finally {
|
|
54
|
+
unsubscribe();
|
|
55
|
+
lineReader.close();
|
|
56
|
+
}
|
|
57
|
+
})();
|
|
58
|
+
return {
|
|
59
|
+
completed,
|
|
60
|
+
close: async () => {
|
|
61
|
+
unsubscribe();
|
|
62
|
+
lineReader.close();
|
|
63
|
+
if (typeof input.destroy === "function") {
|
|
64
|
+
input.destroy();
|
|
65
|
+
}
|
|
66
|
+
await completed.catch(() => undefined);
|
|
67
|
+
},
|
|
68
|
+
};
|
|
69
|
+
}
|
|
@@ -43,8 +43,67 @@ function toCategory(toolType) {
|
|
|
43
43
|
}
|
|
44
44
|
return "local";
|
|
45
45
|
}
|
|
46
|
+
function asObject(value) {
|
|
47
|
+
return typeof value === "object" && value !== null && !Array.isArray(value) ? value : null;
|
|
48
|
+
}
|
|
49
|
+
function readStringArray(value) {
|
|
50
|
+
return Array.isArray(value)
|
|
51
|
+
? value.filter((item) => typeof item === "string" && item.trim().length > 0).map((item) => item.trim())
|
|
52
|
+
: [];
|
|
53
|
+
}
|
|
54
|
+
function readRisk(value) {
|
|
55
|
+
return value === "low" || value === "medium" || value === "high" ? value : undefined;
|
|
56
|
+
}
|
|
57
|
+
function readApprovalPolicy(value) {
|
|
58
|
+
return value === "explicit-hitl" || value === "runtime-default" || value === "none" ? value : undefined;
|
|
59
|
+
}
|
|
60
|
+
function matchesToolPolicy(rule, policy) {
|
|
61
|
+
const match = asObject(rule.match) ?? rule;
|
|
62
|
+
const toolName = typeof match.toolName === "string" ? match.toolName.trim() : undefined;
|
|
63
|
+
const category = typeof match.category === "string" ? match.category.trim() : undefined;
|
|
64
|
+
const toolType = typeof match.toolType === "string" ? match.toolType.trim() : undefined;
|
|
65
|
+
return (!toolName || toolName === policy.toolName)
|
|
66
|
+
&& (!category || category === policy.category)
|
|
67
|
+
&& (!toolType || toolType === policy.toolType);
|
|
68
|
+
}
|
|
69
|
+
function applyGovernanceOverrides(binding, policies) {
|
|
70
|
+
const governance = asObject(binding.harnessRuntime.governance);
|
|
71
|
+
const overrides = Array.isArray(governance?.toolPolicies) ? governance.toolPolicies : [];
|
|
72
|
+
if (overrides.length === 0) {
|
|
73
|
+
return policies;
|
|
74
|
+
}
|
|
75
|
+
return policies.map((policy) => {
|
|
76
|
+
const merged = { ...policy };
|
|
77
|
+
for (const rule of overrides) {
|
|
78
|
+
const typedRule = asObject(rule);
|
|
79
|
+
if (!typedRule || !matchesToolPolicy(typedRule, merged)) {
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
const overrideRisk = readRisk(typedRule.risk);
|
|
83
|
+
const overrideApprovalPolicy = readApprovalPolicy(typedRule.approvalPolicy);
|
|
84
|
+
const overrideRequiresApproval = typeof typedRule.requiresApproval === "boolean" ? typedRule.requiresApproval : undefined;
|
|
85
|
+
if (overrideRisk) {
|
|
86
|
+
merged.risk = overrideRisk;
|
|
87
|
+
}
|
|
88
|
+
if (overrideRequiresApproval !== undefined) {
|
|
89
|
+
merged.requiresApproval = overrideRequiresApproval;
|
|
90
|
+
}
|
|
91
|
+
if (overrideApprovalPolicy) {
|
|
92
|
+
merged.approvalPolicy = overrideApprovalPolicy;
|
|
93
|
+
}
|
|
94
|
+
else if (overrideRequiresApproval === true && merged.approvalPolicy === "none") {
|
|
95
|
+
merged.approvalPolicy = "runtime-default";
|
|
96
|
+
}
|
|
97
|
+
const extraHints = readStringArray(typedRule.inputRiskHints);
|
|
98
|
+
if (extraHints.length > 0) {
|
|
99
|
+
merged.inputRiskHints = Array.from(new Set([...merged.inputRiskHints, ...extraHints]));
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
return merged;
|
|
103
|
+
});
|
|
104
|
+
}
|
|
46
105
|
export function buildRuntimeGovernanceBundles(binding) {
|
|
47
|
-
const toolPolicies = getBindingPrimaryTools(binding).map((tool) => {
|
|
106
|
+
const toolPolicies = applyGovernanceOverrides(binding, getBindingPrimaryTools(binding).map((tool) => {
|
|
48
107
|
const requiresApproval = toolRequiresRuntimeApproval(tool);
|
|
49
108
|
return {
|
|
50
109
|
toolName: tool.name,
|
|
@@ -63,7 +122,7 @@ export function buildRuntimeGovernanceBundles(binding) {
|
|
|
63
122
|
hasInputSchema: typeof tool.inputSchemaRef === "string" && tool.inputSchemaRef.trim().length > 0,
|
|
64
123
|
inputRiskHints: inputHints(binding, tool),
|
|
65
124
|
};
|
|
66
|
-
});
|
|
125
|
+
}));
|
|
67
126
|
if (toolPolicies.length === 0) {
|
|
68
127
|
return [];
|
|
69
128
|
}
|
|
@@ -9,6 +9,35 @@ export class PolicyEngine {
|
|
|
9
9
|
const reasons = [];
|
|
10
10
|
const bundles = [];
|
|
11
11
|
let allowed = true;
|
|
12
|
+
const governance = typeof binding.harnessRuntime.governance === "object" && binding.harnessRuntime.governance
|
|
13
|
+
? binding.harnessRuntime.governance
|
|
14
|
+
: undefined;
|
|
15
|
+
const denyConfig = typeof governance?.deny === "object" && governance.deny
|
|
16
|
+
? governance.deny
|
|
17
|
+
: undefined;
|
|
18
|
+
if (denyConfig) {
|
|
19
|
+
const deniedNames = new Set(Array.isArray(denyConfig.toolNames)
|
|
20
|
+
? denyConfig.toolNames.filter((item) => typeof item === "string" && item.trim().length > 0).map((item) => item.trim())
|
|
21
|
+
: []);
|
|
22
|
+
const deniedCategories = new Set(Array.isArray(denyConfig.categories)
|
|
23
|
+
? denyConfig.categories.filter((item) => typeof item === "string" && item.trim().length > 0).map((item) => item.trim())
|
|
24
|
+
: []);
|
|
25
|
+
const tools = binding.execution?.params?.tools ?? binding.langchainAgentParams?.tools ?? binding.deepAgentParams?.tools ?? [];
|
|
26
|
+
const blocked = tools.filter((tool) => {
|
|
27
|
+
const category = tool.type === "mcp"
|
|
28
|
+
? "mcp"
|
|
29
|
+
: tool.type === "backend"
|
|
30
|
+
? "backend"
|
|
31
|
+
: tool.type === "provider"
|
|
32
|
+
? "provider-native"
|
|
33
|
+
: "local";
|
|
34
|
+
return deniedNames.has(tool.name) || deniedCategories.has(category);
|
|
35
|
+
});
|
|
36
|
+
if (blocked.length > 0) {
|
|
37
|
+
allowed = false;
|
|
38
|
+
reasons.push(`runtime governance denied tool access: ${blocked.map((tool) => tool.name).join(", ")}`);
|
|
39
|
+
}
|
|
40
|
+
}
|
|
12
41
|
for (const evaluator of getPolicyEvaluators()) {
|
|
13
42
|
const decision = evaluator.evaluate(binding);
|
|
14
43
|
if (!decision) {
|
|
@@ -1,4 +1,4 @@
|
|
|
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";
|
|
1
|
+
import type { ApprovalRecord, ArtifactListing, CancelOptions, HarnessEvent, HarnessStreamItem, RuntimeHealthSnapshot, ListMemoriesInput, ListMemoriesResult, MessageContent, RemoveMemoryInput, RunRecord, RunStartOptions, RestartConversationOptions, RuntimeAdapterOptions, RuntimeEvaluationExport, RuntimeEvaluationExportInput, RuntimeEvaluationReplayInput, RuntimeEvaluationReplayResult, RuntimeRunPackage, RuntimeRunPackageInput, RuntimeSessionPackage, RuntimeSessionPackageInput, 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";
|
|
@@ -85,7 +85,10 @@ export declare class AgentHarnessRuntime {
|
|
|
85
85
|
listArtifacts(threadId: string, runId: string): Promise<ArtifactListing>;
|
|
86
86
|
readArtifact(threadId: string, runId: string, artifactPath: string): Promise<unknown>;
|
|
87
87
|
listRunEvents(threadId: string, runId: string): Promise<HarnessEvent[]>;
|
|
88
|
+
exportRunPackage(input: RuntimeRunPackageInput): Promise<RuntimeRunPackage>;
|
|
89
|
+
exportSessionPackage(input: RuntimeSessionPackageInput): Promise<RuntimeSessionPackage>;
|
|
88
90
|
exportEvaluationBundle(input: RuntimeEvaluationExportInput): Promise<RuntimeEvaluationExport>;
|
|
91
|
+
replayEvaluationBundle(input: RuntimeEvaluationReplayInput): Promise<RuntimeEvaluationReplayResult>;
|
|
89
92
|
listAgentSkills(agentId: string, options?: RequirementAssessmentOptions): InventorySkillRecord[];
|
|
90
93
|
getAgent(agentId: string, options?: RequirementAssessmentOptions): InventoryAgentRecord | null;
|
|
91
94
|
describeWorkspaceInventory(options?: RequirementAssessmentOptions): {
|
package/dist/runtime/harness.js
CHANGED
|
@@ -484,9 +484,54 @@ export class AgentHarnessRuntime {
|
|
|
484
484
|
async listRunEvents(threadId, runId) {
|
|
485
485
|
return this.persistence.listRunEvents(threadId, runId);
|
|
486
486
|
}
|
|
487
|
+
async exportRunPackage(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 artifactsListing = input.includeArtifacts === false
|
|
494
|
+
? { items: [] }
|
|
495
|
+
: await this.persistence.listArtifacts(input.sessionId, input.requestId);
|
|
496
|
+
const artifacts = await Promise.all(artifactsListing.items.map(async (artifact) => ({
|
|
497
|
+
...artifact,
|
|
498
|
+
...(input.includeArtifactContents === true
|
|
499
|
+
? { content: await this.persistence.readArtifact(input.sessionId, input.requestId, artifact.path) }
|
|
500
|
+
: {}),
|
|
501
|
+
})));
|
|
502
|
+
return {
|
|
503
|
+
session: thread ? toSessionRecord(thread) : null,
|
|
504
|
+
request: run ? toRequestRecord(run) : null,
|
|
505
|
+
approvals,
|
|
506
|
+
transcript,
|
|
507
|
+
events,
|
|
508
|
+
artifacts,
|
|
509
|
+
...(input.includeRuntimeHealth === false ? {} : { runtimeHealth: await this.getHealth() }),
|
|
510
|
+
};
|
|
511
|
+
}
|
|
512
|
+
async exportSessionPackage(input) {
|
|
513
|
+
const thread = await this.getThread(input.sessionId);
|
|
514
|
+
const runIds = Array.from(new Set((thread?.runs ?? []).map((item) => item.runId)));
|
|
515
|
+
const runs = await Promise.all(runIds.map((requestId) => this.exportRunPackage({
|
|
516
|
+
sessionId: input.sessionId,
|
|
517
|
+
requestId,
|
|
518
|
+
includeArtifacts: input.includeArtifacts,
|
|
519
|
+
includeArtifactContents: input.includeArtifactContents,
|
|
520
|
+
includeRuntimeHealth: false,
|
|
521
|
+
})));
|
|
522
|
+
return {
|
|
523
|
+
session: thread ? toSessionRecord(thread) : null,
|
|
524
|
+
requests: runs.map((item) => item.request).filter((item) => Boolean(item)),
|
|
525
|
+
approvals: await this.listApprovals({ threadId: input.sessionId }),
|
|
526
|
+
transcript: await this.persistence.listThreadMessages(input.sessionId, 500),
|
|
527
|
+
runs,
|
|
528
|
+
...(input.includeRuntimeHealth === false ? {} : { runtimeHealth: await this.getHealth() }),
|
|
529
|
+
};
|
|
530
|
+
}
|
|
487
531
|
async exportEvaluationBundle(input) {
|
|
488
532
|
const thread = await this.getThread(input.sessionId);
|
|
489
533
|
const run = await this.getRun(input.requestId);
|
|
534
|
+
const runRequest = await this.persistence.getRunRequest(input.sessionId, input.requestId);
|
|
490
535
|
const approvals = await this.listApprovals({ threadId: input.sessionId, runId: input.requestId });
|
|
491
536
|
const transcript = await this.persistence.listThreadMessages(input.sessionId, 500);
|
|
492
537
|
const events = await this.persistence.listRunEvents(input.sessionId, input.requestId);
|
|
@@ -503,6 +548,13 @@ export class AgentHarnessRuntime {
|
|
|
503
548
|
return {
|
|
504
549
|
session: thread ? toSessionRecord(thread) : null,
|
|
505
550
|
request: run ? toRequestRecord(run) : null,
|
|
551
|
+
runRequest: runRequest
|
|
552
|
+
? {
|
|
553
|
+
input: runRequest.input,
|
|
554
|
+
...(runRequest.invocation ? { invocation: runRequest.invocation } : {}),
|
|
555
|
+
...(typeof runRequest.priority === "number" ? { priority: runRequest.priority } : {}),
|
|
556
|
+
}
|
|
557
|
+
: (deriveRunRequestFromTranscript(transcript, input.requestId) ?? null),
|
|
506
558
|
approvals,
|
|
507
559
|
transcript,
|
|
508
560
|
events,
|
|
@@ -520,6 +572,36 @@ export class AgentHarnessRuntime {
|
|
|
520
572
|
...(input.metadata ? { metadata: { ...input.metadata } } : {}),
|
|
521
573
|
};
|
|
522
574
|
}
|
|
575
|
+
async replayEvaluationBundle(input) {
|
|
576
|
+
const replayAgentId = input.agentId ?? input.bundle.request?.agentId ?? input.bundle.session?.entryAgentId;
|
|
577
|
+
if (!replayAgentId) {
|
|
578
|
+
throw new Error("Evaluation replay requires an agentId on the replay input or exported bundle.");
|
|
579
|
+
}
|
|
580
|
+
const replayRequest = input.bundle.runRequest ?? deriveRunRequestFromTranscript(input.bundle.transcript, input.bundle.request?.requestId);
|
|
581
|
+
if (!replayRequest) {
|
|
582
|
+
throw new Error("Evaluation replay requires bundle.runRequest from exportEvaluationBundle.");
|
|
583
|
+
}
|
|
584
|
+
const invocation = input.invocation ?? replayRequest.invocation;
|
|
585
|
+
const result = await this.run({
|
|
586
|
+
agentId: replayAgentId,
|
|
587
|
+
input: replayRequest.input,
|
|
588
|
+
...(input.sessionId ? { threadId: input.sessionId } : {}),
|
|
589
|
+
...(invocation ? { invocation } : {}),
|
|
590
|
+
});
|
|
591
|
+
const expected = typeof input.bundle.expectedOutput === "string" ? input.bundle.expectedOutput.trim() : "";
|
|
592
|
+
return {
|
|
593
|
+
request: {
|
|
594
|
+
agentId: replayAgentId,
|
|
595
|
+
input: replayRequest.input,
|
|
596
|
+
...(invocation ? { invocation } : {}),
|
|
597
|
+
...(input.sessionId ? { sessionId: input.sessionId } : {}),
|
|
598
|
+
},
|
|
599
|
+
result,
|
|
600
|
+
assertions: {
|
|
601
|
+
...(expected.length > 0 ? { expectedOutputMatched: result.output.includes(expected) } : {}),
|
|
602
|
+
},
|
|
603
|
+
};
|
|
604
|
+
}
|
|
523
605
|
listAgentSkills(agentId, options = {}) {
|
|
524
606
|
return listWorkspaceAgentSkills(this.workspace, agentId, {
|
|
525
607
|
assessRequirements: isInventoryEnabled(this.workspace),
|
|
@@ -1475,3 +1557,9 @@ function toSessionRecord(record) {
|
|
|
1475
1557
|
function toRequestRecord(record) {
|
|
1476
1558
|
return toRequestSummary(record);
|
|
1477
1559
|
}
|
|
1560
|
+
function deriveRunRequestFromTranscript(transcript, runId) {
|
|
1561
|
+
const candidate = [...transcript]
|
|
1562
|
+
.reverse()
|
|
1563
|
+
.find((message) => message.role === "user" && (!runId || message.runId === runId));
|
|
1564
|
+
return candidate ? { input: candidate.content } : null;
|
|
1565
|
+
}
|
|
@@ -340,6 +340,7 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
|
|
|
340
340
|
const runtimeFilesystemDefaults = agent.executionMode === "langchain-v1"
|
|
341
341
|
? asObject(runtimeDefaults?.filesystem)
|
|
342
342
|
: undefined;
|
|
343
|
+
const runtimeGovernanceDefaults = asObject(runtimeDefaults?.governance);
|
|
343
344
|
const compiledFilesystemConfig = agent.executionMode === "langchain-v1"
|
|
344
345
|
? mergeConfigObjects(runtimeFilesystemDefaults, getAgentExecutionObject(agent, "filesystem", { executionMode: "langchain-v1" }))
|
|
345
346
|
: undefined;
|
|
@@ -355,6 +356,7 @@ export function compileBinding(workspaceRoot, agent, agents, referencedSubagentI
|
|
|
355
356
|
workspaceRoot,
|
|
356
357
|
capabilities: inferAgentCapabilities(agent),
|
|
357
358
|
resilience,
|
|
359
|
+
...(runtimeGovernanceDefaults ? { governance: runtimeGovernanceDefaults } : {}),
|
|
358
360
|
...(agent.executionMode === "deepagent"
|
|
359
361
|
? {
|
|
360
362
|
deepagent: {
|