@botbotgo/agent-harness 0.0.428 → 0.0.430
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 +2 -2
- package/README.zh.md +2 -2
- package/dist/package-version.d.ts +1 -1
- package/dist/package-version.js +1 -1
- package/dist/runtime/adapter/middleware-assembly.js +49 -15
- package/dist/runtime/adapter/tool/tool-hitl.js +10 -11
- package/dist/runtime/harness/run/governance.js +5 -9
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -191,7 +191,7 @@ The public API spans a full product runtime—persistent records, memory and evi
|
|
|
191
191
|
- **Frontend/client entrypoints:** `createAgentHarnessClient`, `createInProcessHarnessClient`, `createAcpHarnessClient`, `createAcpStdioHarnessClient`, `createAcpHttpHarnessClient`, and `HarnessClient` let product shells consume the runtime through one reusable client layer instead of re-binding runtime calls per UI. `request(...)` is the streamed request entrypoint; `subscribe(...)` is the runtime lifecycle observer surface.
|
|
192
192
|
- **Runtime memory and evidence:** `memorize`, `recall`, `listMemories`, memory policy hooks, `recordArtifact`, `listArtifacts`, `getArtifact`, `exportEvaluationBundle`, `replayEvaluationBundle`, and request/session evidence export helpers.
|
|
193
193
|
- **Protocol and transport surfaces:** `createAcpServer`, `createAcpStdioClient`, `serveAcpStdio`, `serveAcpHttp`, `serveA2aHttp`, `serveAgUiHttp`, and `createRuntimeMcpServer` / `serveRuntimeMcpOverStdio`.
|
|
194
|
-
- **Governed workspace runtime:** YAML-owned routing, concurrency, maintenance, MCP policy, runtime governance bundles, and approval defaults for sensitive memory or
|
|
194
|
+
- **Governed workspace runtime:** YAML-owned routing, concurrency, maintenance, MCP policy, runtime governance bundles, and approval defaults for sensitive memory or MCP tools with declared write access.
|
|
195
195
|
- **Policy-shaped approvals:** governed tools can stay on manual review, auto-approve, or auto-reject / deny-and-continue modes while the runtime keeps one inspectable governance decision surface.
|
|
196
196
|
|
|
197
197
|
If you integrate external clients, treat `deepagents-acp` as the primary protocol direction: clients connect through that surface while `agent-harness` keeps persistence, recovery, approvals, and operator control on the runtime side.
|
|
@@ -208,7 +208,7 @@ What you get on day one:
|
|
|
208
208
|
- a runtime that keeps `requests`, `sessions`, `approvals`, and `events` as inspectable product records
|
|
209
209
|
- a recovery path that survives interruption, restart, and operator decisions
|
|
210
210
|
- stable request correlation and continuity metadata so operators can join one persisted request to logs, traces, and fallback transitions
|
|
211
|
-
- approval defaults for sensitive durable memory writes and write
|
|
211
|
+
- approval defaults for sensitive durable memory writes and MCP tools with declared write access instead of relying on tool names or descriptions to imply governance
|
|
212
212
|
- one workspace-shaped assembly model instead of app-specific runtime glue
|
|
213
213
|
- one stable runtime contract even when execution backends change underneath
|
|
214
214
|
|
package/README.zh.md
CHANGED
|
@@ -187,7 +187,7 @@ durable memory 的写入现在也会在模型做 mutation reconciliation 之前
|
|
|
187
187
|
- **前端/client 入口:** `createAgentHarnessClient`、`createInProcessHarnessClient`、`createAcpHarnessClient`、`createAcpStdioHarnessClient`、`createAcpHttpHarnessClient` 与 `HarnessClient` 让产品壳层可以复用同一套 runtime 接入层,而不是每个 UI 各自重新绑定运行时调用。`request(...)` 负责流式 request;`subscribe(...)` 负责 runtime 生命周期事件。
|
|
188
188
|
- **运行时 memory 与证据能力:** `memorize`、`recall`、`listMemories`、memory policy hooks、`recordArtifact`、`listArtifacts`、`getArtifact`、`exportEvaluationBundle`、`replayEvaluationBundle`,以及 request / session 级证据导出辅助函数。
|
|
189
189
|
- **协议与传输层:** `createAcpServer`、`createAcpStdioClient`、`serveAcpStdio`、`serveAcpHttp`、`serveA2aHttp`、`serveAgUiHttp`,以及 `createRuntimeMcpServer` / `serveRuntimeMcpOverStdio`。
|
|
190
|
-
- **受治理的工作区运行时:** 由 YAML 持有的路由、并发、维护、MCP 策略、runtime governance bundles,以及针对敏感 memory
|
|
190
|
+
- **受治理的工作区运行时:** 由 YAML 持有的路由、并发、维护、MCP 策略、runtime governance bundles,以及针对敏感 memory 或声明了写入访问的 MCP 工具的默认审批门槛。
|
|
191
191
|
- **策略化审批:** 受治理工具现在既可以走人工审批,也可以走 `auto-approve`、`auto-reject` 或 `deny-and-continue`,同时继续保留统一可检查的治理决策面。
|
|
192
192
|
|
|
193
193
|
若你的产品需要对接外部客户端,可从本节理解边界:`deepagents-acp` 是主要的外部协议接入方向;持久化、恢复、审批与运行控制仍由 `agent-harness` 在运行时侧承担。
|
|
@@ -204,7 +204,7 @@ durable memory 的写入现在也会在模型做 mutation reconciliation 之前
|
|
|
204
204
|
- 把 `requests`、`sessions`、`approvals`、`events` 作为可查询产品记录保存下来的 runtime
|
|
205
205
|
- 能跨中断、重启和人工决策继续推进的恢复路径
|
|
206
206
|
- 稳定的 request 关联与连续性元数据,让一次持久化请求能和日志、trace、fallback 过程对齐
|
|
207
|
-
- 对敏感 durable memory
|
|
207
|
+
- 对敏感 durable memory 写入和声明了写入访问的 MCP 工具默认走审批,而不是从工具名称或 description 里推断治理责任
|
|
208
208
|
- 一个工作区形态的装配模型,而不是每个应用各写一套运行时胶水
|
|
209
209
|
- 即使底层 execution backend 变化,也尽量保持稳定的 runtime 契约
|
|
210
210
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export declare const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export declare const AGENT_HARNESS_VERSION = "0.0.430";
|
|
2
2
|
export declare const AGENT_HARNESS_RELEASE_DATE = "2026-05-03";
|
package/dist/package-version.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export const AGENT_HARNESS_VERSION = "0.0.
|
|
1
|
+
export const AGENT_HARNESS_VERSION = "0.0.430";
|
|
2
2
|
export const AGENT_HARNESS_RELEASE_DATE = "2026-05-03";
|
|
@@ -180,19 +180,52 @@ function extractUrls(value) {
|
|
|
180
180
|
return [...new Set((value.match(/https?:\/\/[^\s<>"')\]}]+/giu) ?? [])
|
|
181
181
|
.map((url) => url.replace(/[.,;:!?]+$/u, "")))];
|
|
182
182
|
}
|
|
183
|
-
function
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
183
|
+
function readSchemaObjectShape(schema) {
|
|
184
|
+
if (!isRecord(schema)) {
|
|
185
|
+
return undefined;
|
|
186
|
+
}
|
|
187
|
+
if (isRecord(schema.properties)) {
|
|
188
|
+
return schema.properties;
|
|
189
|
+
}
|
|
190
|
+
const candidates = [
|
|
191
|
+
schema._def?.shape,
|
|
192
|
+
schema._zod?.def?.shape,
|
|
193
|
+
schema.def?.shape,
|
|
194
|
+
];
|
|
195
|
+
for (const candidate of candidates) {
|
|
196
|
+
const shape = typeof candidate === "function" ? candidate() : candidate;
|
|
197
|
+
if (isRecord(shape)) {
|
|
198
|
+
return shape;
|
|
199
|
+
}
|
|
200
|
+
}
|
|
201
|
+
return undefined;
|
|
202
|
+
}
|
|
203
|
+
function buildUrlSourceArgs(urls) {
|
|
204
|
+
return urls.map((url) => ({ type: "url", url, timeoutMs: 30000 }));
|
|
205
|
+
}
|
|
206
|
+
function buildEvidenceToolArgs(tool, taskText, evidenceText = taskText) {
|
|
207
|
+
const urls = extractUrls(evidenceText);
|
|
208
|
+
if (urls.length === 0) {
|
|
209
|
+
return {};
|
|
210
|
+
}
|
|
211
|
+
const shape = readSchemaObjectShape(tool.schema);
|
|
212
|
+
if (!shape) {
|
|
213
|
+
return {};
|
|
214
|
+
}
|
|
215
|
+
const args = {};
|
|
216
|
+
if ("sources" in shape) {
|
|
217
|
+
args.sources = buildUrlSourceArgs(urls);
|
|
218
|
+
}
|
|
219
|
+
if ("url" in shape) {
|
|
220
|
+
args.url = urls[0];
|
|
221
|
+
}
|
|
222
|
+
if ("urls" in shape) {
|
|
223
|
+
args.urls = urls;
|
|
224
|
+
}
|
|
225
|
+
if ("question" in shape) {
|
|
226
|
+
args.question = taskText.trim() || evidenceText.trim();
|
|
194
227
|
}
|
|
195
|
-
return
|
|
228
|
+
return args;
|
|
196
229
|
}
|
|
197
230
|
function resolveCommittedEvidenceTools(input) {
|
|
198
231
|
const availableTools = readResolvedEvidenceTools(input.resolvedTools)
|
|
@@ -200,15 +233,16 @@ function resolveCommittedEvidenceTools(input) {
|
|
|
200
233
|
if (availableTools.length === 0) {
|
|
201
234
|
return [];
|
|
202
235
|
}
|
|
203
|
-
const stateText = `${input.taskText}\n${stringifyTaskState(readMessages(input.result))}
|
|
236
|
+
const stateText = `${input.taskText}\n${stringifyTaskState(readMessages(input.result))}`;
|
|
237
|
+
const selectionText = stateText.toLowerCase();
|
|
204
238
|
const selected = [];
|
|
205
239
|
for (const tool of availableTools) {
|
|
206
|
-
if (!
|
|
240
|
+
if (!selectionText.includes(tool.name.toLowerCase())) {
|
|
207
241
|
continue;
|
|
208
242
|
}
|
|
209
243
|
selected.push({
|
|
210
244
|
tool,
|
|
211
|
-
args: buildEvidenceToolArgs(tool, stateText),
|
|
245
|
+
args: buildEvidenceToolArgs(tool, input.taskText, stateText),
|
|
212
246
|
});
|
|
213
247
|
}
|
|
214
248
|
if (selected.length > 0) {
|
|
@@ -6,7 +6,6 @@ const PATH_LIKE_INPUT_KEYS = new Set(["path", "root", "dir", "directory", "cwd"]
|
|
|
6
6
|
const ROOT_SCOPING_INPUT_KEYS = new Set(["root", "dir", "directory", "cwd"]);
|
|
7
7
|
const SENSITIVE_MEMORY_LEVELS = new Set(["high", "sensitive", "restricted", "secret", "confidential"]);
|
|
8
8
|
const NON_THREAD_MEMORY_SCOPES = new Set(["workspace", "agent", "user", "project"]);
|
|
9
|
-
const WRITE_LIKE_REMOTE_TOOL_PATTERN = /\b(write|edit|delete|create|update|append|insert|push|commit|publish|send|post|apply|merge|sync|upload|save)\b/i;
|
|
10
9
|
function asRecord(value) {
|
|
11
10
|
return typeof value === "object" && value !== null && !Array.isArray(value)
|
|
12
11
|
? value
|
|
@@ -59,16 +58,16 @@ function requiresApprovalForHighRiskMcpWrite(compiledTool) {
|
|
|
59
58
|
return true;
|
|
60
59
|
}
|
|
61
60
|
const mcpConfig = asRecord(compiledTool.config?.mcp);
|
|
62
|
-
const
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
return
|
|
61
|
+
const mcpServer = asRecord(compiledTool.config?.mcpServer);
|
|
62
|
+
const access = asString(mcpServer?.access ?? mcpConfig?.access);
|
|
63
|
+
const approvalPolicy = asString(mcpServer?.approvalPolicy ?? mcpConfig?.approvalPolicy);
|
|
64
|
+
if (approvalPolicy === "always") {
|
|
65
|
+
return true;
|
|
66
|
+
}
|
|
67
|
+
if (approvalPolicy === "never") {
|
|
68
|
+
return false;
|
|
69
|
+
}
|
|
70
|
+
return access === "read-write";
|
|
72
71
|
}
|
|
73
72
|
function matchesGovernanceToolPolicy(rule, compiledTool) {
|
|
74
73
|
const match = asRecord(rule.match) ?? rule;
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { getBindingPrimaryTools } from "../../support/compiled-binding.js";
|
|
2
2
|
import { resolveToolApprovalDecisionMode } from "../../adapter/tool/tool-hitl.js";
|
|
3
3
|
import { compiledToolHasInputSchema } from "../tool-schema.js";
|
|
4
|
-
const WRITE_LIKE_PATTERN = /\b(write|edit|delete|create|update|append|insert|push|commit|publish|send|post|apply|merge|sync|upload|save)\b/i;
|
|
5
4
|
function inputHints(binding, tool) {
|
|
6
5
|
const hints = new Set();
|
|
7
6
|
const target = `${tool.name} ${tool.description}`.toLowerCase();
|
|
@@ -29,10 +28,6 @@ function classifyRisk(policy) {
|
|
|
29
28
|
if (policy.mcpAccess === "read-write" || policy.promptInjectionRisk === "medium") {
|
|
30
29
|
return "medium";
|
|
31
30
|
}
|
|
32
|
-
const target = `${policy.toolName} ${policy.description}`;
|
|
33
|
-
if (policy.toolType === "mcp" && WRITE_LIKE_PATTERN.test(target)) {
|
|
34
|
-
return "high";
|
|
35
|
-
}
|
|
36
31
|
if (policy.toolType === "backend" || policy.toolType === "mcp") {
|
|
37
32
|
return "medium";
|
|
38
33
|
}
|
|
@@ -200,12 +195,13 @@ function applyRemoteMcpGovernance(binding, policies) {
|
|
|
200
195
|
export function buildRuntimeGovernanceBundles(binding) {
|
|
201
196
|
const toolPolicies = applyGovernanceOverrides(binding, applyRemoteMcpGovernance(binding, getBindingPrimaryTools(binding).map((tool) => {
|
|
202
197
|
const remoteMcp = readRemoteMcpMetadata(tool);
|
|
203
|
-
const
|
|
198
|
+
const remoteMcpWriteAccess = tool.type === "mcp" && remoteMcp.access === "read-write";
|
|
204
199
|
const derivedDecisionMode = resolveToolApprovalDecisionMode(tool, binding);
|
|
205
200
|
const requiresApproval = derivedDecisionMode === "manual" ||
|
|
206
201
|
remoteMcp.trustTier === "untrusted" ||
|
|
207
202
|
remoteMcp.approvalPolicy === "always" ||
|
|
208
|
-
(remoteMcp.approvalPolicy === "write" &&
|
|
203
|
+
(remoteMcp.approvalPolicy === "write" && remoteMcpWriteAccess) ||
|
|
204
|
+
remoteMcpWriteAccess ||
|
|
209
205
|
remoteMcp.tenantScope === "cross-tenant";
|
|
210
206
|
const decisionMode = requiresApproval
|
|
211
207
|
? (derivedDecisionMode === "none" ? "manual" : derivedDecisionMode)
|
|
@@ -216,9 +212,9 @@ export function buildRuntimeGovernanceBundles(binding) {
|
|
|
216
212
|
? "cross-tenant-mcp-access"
|
|
217
213
|
: remoteMcp.approvalPolicy === "always"
|
|
218
214
|
? "remote-mcp-approval-policy"
|
|
219
|
-
: remoteMcp.approvalPolicy === "write" &&
|
|
215
|
+
: remoteMcp.approvalPolicy === "write" && remoteMcpWriteAccess
|
|
220
216
|
? "high-risk-mcp-write"
|
|
221
|
-
:
|
|
217
|
+
: remoteMcpWriteAccess
|
|
222
218
|
? "high-risk-mcp-write"
|
|
223
219
|
: undefined;
|
|
224
220
|
const inputRiskHints = inputHints(binding, tool);
|