@inhuman.tools/turn 0.0.0-stage → 0.1.0
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/LICENSE.md +7 -0
- package/dist/agent-calls/acceptance.d.ts +12 -0
- package/dist/agent-calls/acceptance.d.ts.map +1 -0
- package/dist/agent-calls/acceptance.js +64 -0
- package/dist/agent-calls/acceptance.js.map +1 -0
- package/dist/agent-calls/callbacks.d.ts +14 -0
- package/dist/agent-calls/callbacks.d.ts.map +1 -0
- package/dist/agent-calls/callbacks.js +59 -0
- package/dist/agent-calls/callbacks.js.map +1 -0
- package/dist/agent-calls/delivery.d.ts +7 -0
- package/dist/agent-calls/delivery.d.ts.map +1 -0
- package/dist/agent-calls/delivery.js +16 -0
- package/dist/agent-calls/delivery.js.map +1 -0
- package/dist/agent-calls/index.d.ts +7 -0
- package/dist/agent-calls/index.d.ts.map +1 -0
- package/dist/agent-calls/index.js +6 -0
- package/dist/agent-calls/index.js.map +1 -0
- package/dist/agent-calls/operator.d.ts +21 -0
- package/dist/agent-calls/operator.d.ts.map +1 -0
- package/dist/agent-calls/operator.js +78 -0
- package/dist/agent-calls/operator.js.map +1 -0
- package/dist/agent-calls/runtime.d.ts +99 -0
- package/dist/agent-calls/runtime.d.ts.map +1 -0
- package/dist/agent-calls/runtime.js +245 -0
- package/dist/agent-calls/runtime.js.map +1 -0
- package/dist/agent-calls/types.d.ts +31 -0
- package/dist/agent-calls/types.d.ts.map +1 -0
- package/dist/agent-calls/types.js +2 -0
- package/dist/agent-calls/types.js.map +1 -0
- package/dist/context/compact-floors.d.ts +43 -0
- package/dist/context/compact-floors.d.ts.map +1 -0
- package/dist/context/compact-floors.js +52 -0
- package/dist/context/compact-floors.js.map +1 -0
- package/dist/context/compact.d.ts +42 -0
- package/dist/context/compact.d.ts.map +1 -0
- package/dist/context/compact.js +155 -0
- package/dist/context/compact.js.map +1 -0
- package/dist/context/delivery.d.ts +13 -0
- package/dist/context/delivery.d.ts.map +1 -0
- package/dist/context/delivery.js +6 -0
- package/dist/context/delivery.js.map +1 -0
- package/dist/context/history.d.ts +66 -0
- package/dist/context/history.d.ts.map +1 -0
- package/dist/context/history.js +573 -0
- package/dist/context/history.js.map +1 -0
- package/dist/context/index.d.ts +10 -0
- package/dist/context/index.d.ts.map +1 -0
- package/dist/context/index.js +10 -0
- package/dist/context/index.js.map +1 -0
- package/dist/context/observations.d.ts +7 -0
- package/dist/context/observations.d.ts.map +1 -0
- package/dist/context/observations.js +11 -0
- package/dist/context/observations.js.map +1 -0
- package/dist/context/retention/defaults.d.ts +10 -0
- package/dist/context/retention/defaults.d.ts.map +1 -0
- package/dist/context/retention/defaults.js +47 -0
- package/dist/context/retention/defaults.js.map +1 -0
- package/dist/context/retention/index.d.ts +14 -0
- package/dist/context/retention/index.d.ts.map +1 -0
- package/dist/context/retention/index.js +21 -0
- package/dist/context/retention/index.js.map +1 -0
- package/dist/context/retention/narrow.d.ts +22 -0
- package/dist/context/retention/narrow.d.ts.map +1 -0
- package/dist/context/retention/narrow.js +140 -0
- package/dist/context/retention/narrow.js.map +1 -0
- package/dist/context/retention/render.d.ts +37 -0
- package/dist/context/retention/render.d.ts.map +1 -0
- package/dist/context/retention/render.js +149 -0
- package/dist/context/retention/render.js.map +1 -0
- package/dist/context/retention/resolve.d.ts +51 -0
- package/dist/context/retention/resolve.d.ts.map +1 -0
- package/dist/context/retention/resolve.js +254 -0
- package/dist/context/retention/resolve.js.map +1 -0
- package/dist/context/retention/schema.d.ts +345 -0
- package/dist/context/retention/schema.d.ts.map +1 -0
- package/dist/context/retention/schema.js +149 -0
- package/dist/context/retention/schema.js.map +1 -0
- package/dist/context/retention/stamp.d.ts +25 -0
- package/dist/context/retention/stamp.d.ts.map +1 -0
- package/dist/context/retention/stamp.js +103 -0
- package/dist/context/retention/stamp.js.map +1 -0
- package/dist/context/retention/step.d.ts +33 -0
- package/dist/context/retention/step.d.ts.map +1 -0
- package/dist/context/retention/step.js +74 -0
- package/dist/context/retention/step.js.map +1 -0
- package/dist/context/retention/view.d.ts +57 -0
- package/dist/context/retention/view.d.ts.map +1 -0
- package/dist/context/retention/view.js +121 -0
- package/dist/context/retention/view.js.map +1 -0
- package/dist/context/squeeze.d.ts +45 -0
- package/dist/context/squeeze.d.ts.map +1 -0
- package/dist/context/squeeze.js +182 -0
- package/dist/context/squeeze.js.map +1 -0
- package/dist/context/tools.d.ts +16 -0
- package/dist/context/tools.d.ts.map +1 -0
- package/dist/context/tools.js +73 -0
- package/dist/context/tools.js.map +1 -0
- package/dist/context/transcript.d.ts +151 -0
- package/dist/context/transcript.d.ts.map +1 -0
- package/dist/context/transcript.js +659 -0
- package/dist/context/transcript.js.map +1 -0
- package/dist/policy-processor/bypass.d.ts +95 -0
- package/dist/policy-processor/bypass.d.ts.map +1 -0
- package/dist/policy-processor/bypass.js +188 -0
- package/dist/policy-processor/bypass.js.map +1 -0
- package/dist/policy-processor/classifier.d.ts +47 -0
- package/dist/policy-processor/classifier.d.ts.map +1 -0
- package/dist/policy-processor/classifier.js +671 -0
- package/dist/policy-processor/classifier.js.map +1 -0
- package/dist/policy-processor/cluster.d.ts +7 -0
- package/dist/policy-processor/cluster.d.ts.map +1 -0
- package/dist/policy-processor/cluster.js +32 -0
- package/dist/policy-processor/cluster.js.map +1 -0
- package/dist/policy-processor/evidence.d.ts +26 -0
- package/dist/policy-processor/evidence.d.ts.map +1 -0
- package/dist/policy-processor/evidence.js +204 -0
- package/dist/policy-processor/evidence.js.map +1 -0
- package/dist/policy-processor/explain.d.ts +59 -0
- package/dist/policy-processor/explain.d.ts.map +1 -0
- package/dist/policy-processor/explain.js +224 -0
- package/dist/policy-processor/explain.js.map +1 -0
- package/dist/policy-processor/index.d.ts +6 -0
- package/dist/policy-processor/index.d.ts.map +1 -0
- package/dist/policy-processor/index.js +6 -0
- package/dist/policy-processor/index.js.map +1 -0
- package/dist/policy-processor/license.d.ts +23 -0
- package/dist/policy-processor/license.d.ts.map +1 -0
- package/dist/policy-processor/license.js +47 -0
- package/dist/policy-processor/license.js.map +1 -0
- package/dist/policy-processor/peel-cwd.d.ts +2 -0
- package/dist/policy-processor/peel-cwd.d.ts.map +1 -0
- package/dist/policy-processor/peel-cwd.js +2 -0
- package/dist/policy-processor/peel-cwd.js.map +1 -0
- package/dist/policy-processor/real-path.d.ts +7 -0
- package/dist/policy-processor/real-path.d.ts.map +1 -0
- package/dist/policy-processor/real-path.js +42 -0
- package/dist/policy-processor/real-path.js.map +1 -0
- package/dist/policy-processor/scope.d.ts +111 -0
- package/dist/policy-processor/scope.d.ts.map +1 -0
- package/dist/policy-processor/scope.js +629 -0
- package/dist/policy-processor/scope.js.map +1 -0
- package/dist/policy-processor/self-protect.d.ts +10 -0
- package/dist/policy-processor/self-protect.d.ts.map +1 -0
- package/dist/policy-processor/self-protect.js +48 -0
- package/dist/policy-processor/self-protect.js.map +1 -0
- package/dist/policy-processor/soft-deny.d.ts +75 -0
- package/dist/policy-processor/soft-deny.d.ts.map +1 -0
- package/dist/policy-processor/soft-deny.js +185 -0
- package/dist/policy-processor/soft-deny.js.map +1 -0
- package/dist/policy-processor/unattended-guard.d.ts +28 -0
- package/dist/policy-processor/unattended-guard.d.ts.map +1 -0
- package/dist/policy-processor/unattended-guard.js +145 -0
- package/dist/policy-processor/unattended-guard.js.map +1 -0
- package/dist/session/cancel.d.ts +14 -0
- package/dist/session/cancel.d.ts.map +1 -0
- package/dist/session/cancel.js +32 -0
- package/dist/session/cancel.js.map +1 -0
- package/dist/session/commands.d.ts +41 -0
- package/dist/session/commands.d.ts.map +1 -0
- package/dist/session/commands.js +241 -0
- package/dist/session/commands.js.map +1 -0
- package/dist/session/compact-actor.d.ts +23 -0
- package/dist/session/compact-actor.d.ts.map +1 -0
- package/dist/session/compact-actor.js +91 -0
- package/dist/session/compact-actor.js.map +1 -0
- package/dist/session/compact-env.d.ts +54 -0
- package/dist/session/compact-env.d.ts.map +1 -0
- package/dist/session/compact-env.js +345 -0
- package/dist/session/compact-env.js.map +1 -0
- package/dist/session/compact.d.ts +42 -0
- package/dist/session/compact.d.ts.map +1 -0
- package/dist/session/compact.js +68 -0
- package/dist/session/compact.js.map +1 -0
- package/dist/session/index.d.ts +9 -0
- package/dist/session/index.d.ts.map +1 -0
- package/dist/session/index.js +8 -0
- package/dist/session/index.js.map +1 -0
- package/dist/session/park.d.ts +16 -0
- package/dist/session/park.d.ts.map +1 -0
- package/dist/session/park.js +73 -0
- package/dist/session/park.js.map +1 -0
- package/dist/session/side-channel-reminder.d.ts +41 -0
- package/dist/session/side-channel-reminder.d.ts.map +1 -0
- package/dist/session/side-channel-reminder.js +132 -0
- package/dist/session/side-channel-reminder.js.map +1 -0
- package/dist/session/types.d.ts +44 -0
- package/dist/session/types.d.ts.map +1 -0
- package/dist/session/types.js +2 -0
- package/dist/session/types.js.map +1 -0
- package/dist/tool-catalog/catalog.d.ts +77 -0
- package/dist/tool-catalog/catalog.d.ts.map +1 -0
- package/dist/tool-catalog/catalog.js +380 -0
- package/dist/tool-catalog/catalog.js.map +1 -0
- package/dist/tool-catalog/index.d.ts +4 -0
- package/dist/tool-catalog/index.d.ts.map +1 -0
- package/dist/tool-catalog/index.js +3 -0
- package/dist/tool-catalog/index.js.map +1 -0
- package/dist/tool-catalog/recipes.d.ts +36 -0
- package/dist/tool-catalog/recipes.d.ts.map +1 -0
- package/dist/tool-catalog/recipes.js +121 -0
- package/dist/tool-catalog/recipes.js.map +1 -0
- package/dist/tool-catalog/types.d.ts +103 -0
- package/dist/tool-catalog/types.d.ts.map +1 -0
- package/dist/tool-catalog/types.js +5 -0
- package/dist/tool-catalog/types.js.map +1 -0
- package/dist/tool-runtime/approval/approved.d.ts +13 -0
- package/dist/tool-runtime/approval/approved.d.ts.map +1 -0
- package/dist/tool-runtime/approval/approved.js +20 -0
- package/dist/tool-runtime/approval/approved.js.map +1 -0
- package/dist/tool-runtime/approval/dist.d.ts +6 -0
- package/dist/tool-runtime/approval/dist.d.ts.map +1 -0
- package/dist/tool-runtime/approval/dist.js +28 -0
- package/dist/tool-runtime/approval/dist.js.map +1 -0
- package/dist/tool-runtime/approval/inbound.d.ts +7 -0
- package/dist/tool-runtime/approval/inbound.d.ts.map +1 -0
- package/dist/tool-runtime/approval/inbound.js +48 -0
- package/dist/tool-runtime/approval/inbound.js.map +1 -0
- package/dist/tool-runtime/approval/unattended.d.ts +8 -0
- package/dist/tool-runtime/approval/unattended.d.ts.map +1 -0
- package/dist/tool-runtime/approval/unattended.js +23 -0
- package/dist/tool-runtime/approval/unattended.js.map +1 -0
- package/dist/tool-runtime/blob-port.d.ts +46 -0
- package/dist/tool-runtime/blob-port.d.ts.map +1 -0
- package/dist/tool-runtime/blob-port.js +47 -0
- package/dist/tool-runtime/blob-port.js.map +1 -0
- package/dist/tool-runtime/extra-root.d.ts +3 -0
- package/dist/tool-runtime/extra-root.d.ts.map +1 -0
- package/dist/tool-runtime/extra-root.js +14 -0
- package/dist/tool-runtime/extra-root.js.map +1 -0
- package/dist/tool-runtime/handler.d.ts +29 -0
- package/dist/tool-runtime/handler.d.ts.map +1 -0
- package/dist/tool-runtime/handler.js +460 -0
- package/dist/tool-runtime/handler.js.map +1 -0
- package/dist/tool-runtime/index.d.ts +14 -0
- package/dist/tool-runtime/index.d.ts.map +1 -0
- package/dist/tool-runtime/index.js +14 -0
- package/dist/tool-runtime/index.js.map +1 -0
- package/dist/tool-runtime/peel.d.ts +19 -0
- package/dist/tool-runtime/peel.d.ts.map +1 -0
- package/dist/tool-runtime/peel.js +74 -0
- package/dist/tool-runtime/peel.js.map +1 -0
- package/dist/tool-runtime/plugin-context.d.ts +13 -0
- package/dist/tool-runtime/plugin-context.d.ts.map +1 -0
- package/dist/tool-runtime/plugin-context.js +55 -0
- package/dist/tool-runtime/plugin-context.js.map +1 -0
- package/dist/tool-runtime/recall.d.ts +18 -0
- package/dist/tool-runtime/recall.d.ts.map +1 -0
- package/dist/tool-runtime/recall.js +100 -0
- package/dist/tool-runtime/recall.js.map +1 -0
- package/dist/tool-runtime/run-system-tool.d.ts +13 -0
- package/dist/tool-runtime/run-system-tool.d.ts.map +1 -0
- package/dist/tool-runtime/run-system-tool.js +230 -0
- package/dist/tool-runtime/run-system-tool.js.map +1 -0
- package/dist/tool-runtime/tool-error.d.ts +6 -0
- package/dist/tool-runtime/tool-error.d.ts.map +1 -0
- package/dist/tool-runtime/tool-error.js +6 -0
- package/dist/tool-runtime/tool-error.js.map +1 -0
- package/dist/tool-runtime/worker-tools.d.ts +8 -0
- package/dist/tool-runtime/worker-tools.d.ts.map +1 -0
- package/dist/tool-runtime/worker-tools.js +65 -0
- package/dist/tool-runtime/worker-tools.js.map +1 -0
- package/dist/tool-runtime/write-admit.d.ts +21 -0
- package/dist/tool-runtime/write-admit.d.ts.map +1 -0
- package/dist/tool-runtime/write-admit.js +89 -0
- package/dist/tool-runtime/write-admit.js.map +1 -0
- package/package.json +114 -3
- package/policy/auto-mode-ask.scm +201 -0
- package/policy/bypass-detect.prompt +55 -0
- package/policy/classifier-bash-incomplete.prompt +46 -0
- package/policy/classifier-bash.prompt +45 -0
- package/policy/classifier-mcp.prompt +45 -0
- package/policy/classifier-read.prompt +44 -0
- package/policy/classifier-write-outside.prompt +46 -0
- package/policy/classifier-write-risky.prompt +45 -0
- package/policy/classifier-write-workspace.prompt +46 -0
- package/policy/classifier-write.prompt +45 -0
- package/policy/soft-deny-round1.prompt +51 -0
- package/policy/soft-deny-round2.prompt +60 -0
- package/src/agent-calls/acceptance.ts +71 -0
- package/src/agent-calls/callbacks.ts +75 -0
- package/src/agent-calls/delivery.ts +15 -0
- package/src/agent-calls/index.ts +16 -0
- package/src/agent-calls/operator.ts +99 -0
- package/src/agent-calls/runtime.ts +310 -0
- package/src/agent-calls/types.ts +33 -0
- package/src/context/compact-floors.ts +76 -0
- package/src/context/compact.ts +176 -0
- package/src/context/delivery.ts +15 -0
- package/src/context/history.ts +725 -0
- package/src/context/index.ts +35 -0
- package/src/context/observations.ts +13 -0
- package/src/context/retention/defaults.ts +58 -0
- package/src/context/retention/index.ts +45 -0
- package/src/context/retention/narrow.ts +123 -0
- package/src/context/retention/render.ts +177 -0
- package/src/context/retention/resolve.ts +306 -0
- package/src/context/retention/schema.ts +173 -0
- package/src/context/retention/stamp.ts +121 -0
- package/src/context/retention/step.ts +85 -0
- package/src/context/retention/view.ts +161 -0
- package/src/context/squeeze.ts +218 -0
- package/src/context/tools.ts +92 -0
- package/src/context/transcript.ts +705 -0
- package/src/policy-processor/README.md +43 -0
- package/src/policy-processor/bypass.ts +246 -0
- package/src/policy-processor/classifier.ts +711 -0
- package/src/policy-processor/cluster.ts +31 -0
- package/src/policy-processor/evidence.ts +214 -0
- package/src/policy-processor/explain.ts +310 -0
- package/src/policy-processor/index.ts +6 -0
- package/src/policy-processor/license.ts +45 -0
- package/src/policy-processor/peel-cwd.ts +1 -0
- package/src/policy-processor/real-path.ts +41 -0
- package/src/policy-processor/scope.ts +655 -0
- package/src/policy-processor/self-protect.ts +46 -0
- package/src/policy-processor/soft-deny.ts +225 -0
- package/src/policy-processor/unattended-guard.ts +158 -0
- package/src/session/cancel.ts +34 -0
- package/src/session/commands.ts +292 -0
- package/src/session/compact-actor.ts +132 -0
- package/src/session/compact-env.ts +539 -0
- package/src/session/compact.ts +95 -0
- package/src/session/index.ts +18 -0
- package/src/session/park.ts +73 -0
- package/src/session/side-channel-reminder.ts +148 -0
- package/src/session/types.ts +50 -0
- package/src/tool-catalog/catalog.ts +282 -0
- package/src/tool-catalog/index.ts +26 -0
- package/src/tool-catalog/recipes.ts +154 -0
- package/src/tool-catalog/types.ts +110 -0
- package/src/tool-runtime/approval/approved.ts +20 -0
- package/src/tool-runtime/approval/dist.ts +29 -0
- package/src/tool-runtime/approval/inbound.ts +50 -0
- package/src/tool-runtime/approval/unattended.ts +24 -0
- package/src/tool-runtime/blob-port.ts +64 -0
- package/src/tool-runtime/extra-root.ts +16 -0
- package/src/tool-runtime/handler.ts +576 -0
- package/src/tool-runtime/index.ts +21 -0
- package/src/tool-runtime/peel.ts +91 -0
- package/src/tool-runtime/plugin-context.ts +68 -0
- package/src/tool-runtime/recall.ts +104 -0
- package/src/tool-runtime/run-system-tool.ts +273 -0
- package/src/tool-runtime/tool-error.ts +6 -0
- package/src/tool-runtime/worker-tools.ts +76 -0
- package/src/tool-runtime/write-admit.ts +90 -0
- package/README.md +0 -3
|
@@ -0,0 +1,576 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Project-bound mint of one model tool_call. Does not execute.
|
|
3
|
+
* Connection-sourced names are MCPToolJob; write_file / edit_file are
|
|
4
|
+
* FileMutateToolJob; pack / unknown are SystemToolJob.
|
|
5
|
+
* `agentCallFromWire` mints `agent__ask` / `agent__send`. `admit` wraps it; the turn calls it directly.
|
|
6
|
+
* Both append onto `AdmitContext.parent` when the caller passes one. They do not enqueue.
|
|
7
|
+
* Bot-call pack tools and standing bot invocations mint BotCallJob.
|
|
8
|
+
* `scheme_repl` is a ProgrammaticJob bag. Inner admits reuse this door.
|
|
9
|
+
*/
|
|
10
|
+
import { createHash } from "node:crypto";
|
|
11
|
+
|
|
12
|
+
import {
|
|
13
|
+
AgentCallJob,
|
|
14
|
+
BotCallJob,
|
|
15
|
+
CallJob,
|
|
16
|
+
AgentCallbackJob,
|
|
17
|
+
AgentMessageJob,
|
|
18
|
+
AgentNotifyJob,
|
|
19
|
+
AGENT_ASK,
|
|
20
|
+
AGENT_MESSAGE,
|
|
21
|
+
AGENT_NOTIFY,
|
|
22
|
+
AGENT_RESPOND,
|
|
23
|
+
AGENT_SEND,
|
|
24
|
+
AGENT_VOID,
|
|
25
|
+
CallDelivery,
|
|
26
|
+
CONTEXT_NEED_TOOL_NAME,
|
|
27
|
+
ContextNeedToolJob,
|
|
28
|
+
FailureOutcome,
|
|
29
|
+
FileMutateToolJob,
|
|
30
|
+
MCPToolJob,
|
|
31
|
+
McpToolExpectation,
|
|
32
|
+
mcpToolListHas,
|
|
33
|
+
parseWebExtractArgs,
|
|
34
|
+
parseWebSearchArgs,
|
|
35
|
+
ProgrammaticJob,
|
|
36
|
+
SCHEME_REPL_TOOL_NAME,
|
|
37
|
+
SCHEME_WATCH_TOOL_NAME,
|
|
38
|
+
SessionRoot,
|
|
39
|
+
SessionTurn,
|
|
40
|
+
storageIncludingOffTape,
|
|
41
|
+
SystemToolJob,
|
|
42
|
+
ToolCallJob,
|
|
43
|
+
WEB_EXTRACT_TOOL_NAME,
|
|
44
|
+
WEB_SEARCH_TOOL_NAME,
|
|
45
|
+
WebExtractExpectation,
|
|
46
|
+
WebExtractToolJob,
|
|
47
|
+
WebSearchExpectation,
|
|
48
|
+
WebSearchToolJob,
|
|
49
|
+
writePluginMeta,
|
|
50
|
+
} from "@inhuman.tools/harness-model";
|
|
51
|
+
import { parseJsonRecord } from "@inhuman.tools/harness-model/json-record";
|
|
52
|
+
import type { ToolCall } from "@inhuman.tools/tool-call-normalize";
|
|
53
|
+
|
|
54
|
+
import { externalizePrior } from "./blob-port.js";
|
|
55
|
+
import { peelAgentCallArgs, requestIdOf } from "./peel.js";
|
|
56
|
+
import { workerToolAllowed } from "./worker-tools.js";
|
|
57
|
+
import { lineStartOfSpan, writeFileAdmitSnap } from "./write-admit.js";
|
|
58
|
+
import { policyOfTurn, stampJobRetention } from "../context/retention/index.js";
|
|
59
|
+
import { peelShellCwd } from "../policy-processor/peel-cwd.js";
|
|
60
|
+
import { agentCallSupportsNotify, type CatalogEntry, type KernelToolCatalog } from "../tool-catalog/index.js";
|
|
61
|
+
|
|
62
|
+
/** Catalog face the handler proxies to. A kernel host satisfies this. */
|
|
63
|
+
export type ToolCallKernel = {
|
|
64
|
+
readonly catalog: KernelToolCatalog;
|
|
65
|
+
};
|
|
66
|
+
|
|
67
|
+
export type AdmitContext = {
|
|
68
|
+
readonly session?: SessionRoot;
|
|
69
|
+
readonly originTurn?: SessionTurn;
|
|
70
|
+
readonly loadAgentCall?: (uuid: string) => CallJob | undefined;
|
|
71
|
+
/**
|
|
72
|
+
* Receives the job before admit returns. A reachable child can start, so pass
|
|
73
|
+
* this only for a call that may start.
|
|
74
|
+
*/
|
|
75
|
+
readonly parent?: { registerJob(child: AdmittedCall): void };
|
|
76
|
+
};
|
|
77
|
+
|
|
78
|
+
type CatalogWithInstall = KernelToolCatalog & {
|
|
79
|
+
readonly pluginInstall?: {
|
|
80
|
+
readonly plugins: ReadonlyMap<string, { readonly definition: unknown }>;
|
|
81
|
+
};
|
|
82
|
+
};
|
|
83
|
+
|
|
84
|
+
function pluginRevision(catalog: KernelToolCatalog, pluginName: string): string {
|
|
85
|
+
const record = (catalog as CatalogWithInstall).pluginInstall?.plugins.get(pluginName);
|
|
86
|
+
if (record == null) return "";
|
|
87
|
+
return createHash("sha256").update(JSON.stringify(record.definition)).digest("hex").slice(0, 16);
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function asRecord(value: unknown): Record<string, unknown> | null {
|
|
91
|
+
if (value == null || typeof value !== "object" || Array.isArray(value)) return null;
|
|
92
|
+
return value as Record<string, unknown>;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function stamp(argsJson: string): { background?: true; walkBoundary?: true } {
|
|
96
|
+
const parsed = parseJsonRecord(argsJson === "" ? "{}" : argsJson);
|
|
97
|
+
if (parsed != null && parsed.background === true) {
|
|
98
|
+
return { background: true, walkBoundary: true };
|
|
99
|
+
}
|
|
100
|
+
return {};
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/** The prior text as job props: inline while small, a blob reference once it passes the inline limit. */
|
|
104
|
+
function priorProps(text: string | null): { readonly priorContent?: string; readonly priorBlobJson?: string } {
|
|
105
|
+
return text === null ? {} : externalizePrior(text);
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function catalogFlags(entry: CatalogEntry | undefined): {
|
|
109
|
+
readonly triggersReactLoop: boolean;
|
|
110
|
+
readonly tapeHidden: boolean;
|
|
111
|
+
readonly isSideChannel: boolean;
|
|
112
|
+
} {
|
|
113
|
+
return {
|
|
114
|
+
triggersReactLoop: entry?.triggersReactLoop ?? true,
|
|
115
|
+
tapeHidden: entry?.tapeHidden ?? false,
|
|
116
|
+
isSideChannel: entry?.isSideChannel === true,
|
|
117
|
+
};
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
function sealedValidateDoor(toolCallId: string, argsJson: string, text: string, entry?: CatalogEntry): ProgrammaticJob {
|
|
121
|
+
return new ProgrammaticJob({
|
|
122
|
+
toolCallId,
|
|
123
|
+
argsJson,
|
|
124
|
+
completed: true,
|
|
125
|
+
outcomeJson: JSON.stringify({ ok: false, text }),
|
|
126
|
+
...catalogFlags(entry),
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function admitExam(call: ToolCall, ctx: AdmitContext, entry: CatalogEntry): ProgrammaticJob {
|
|
131
|
+
const toolCallId = call.id;
|
|
132
|
+
const argsJson = call.function.arguments;
|
|
133
|
+
const exam = entry.exam;
|
|
134
|
+
if (exam == null) return sealedValidateDoor(toolCallId, argsJson, "exam admit missing", entry);
|
|
135
|
+
if (ctx.session == null) {
|
|
136
|
+
return sealedValidateDoor(toolCallId, argsJson, `${call.function.name}: missing session`, entry);
|
|
137
|
+
}
|
|
138
|
+
let raw: unknown;
|
|
139
|
+
try {
|
|
140
|
+
raw = JSON.parse(argsJson === "" ? "{}" : argsJson);
|
|
141
|
+
} catch {
|
|
142
|
+
return sealedValidateDoor(toolCallId, argsJson, `${call.function.name}: arguments were not valid JSON`, entry);
|
|
143
|
+
}
|
|
144
|
+
const input = asRecord(raw);
|
|
145
|
+
if (input == null) {
|
|
146
|
+
return sealedValidateDoor(toolCallId, argsJson, `${call.function.name}: arguments must be a JSON object`, entry);
|
|
147
|
+
}
|
|
148
|
+
const pluginId = entry.source.kind === "pack" ? entry.source.pluginName : "";
|
|
149
|
+
const storage = ctx.originTurn == null ? ctx.session.storageAfter : storageIncludingOffTape(ctx.originTurn);
|
|
150
|
+
const prefix = pluginId === "" ? {} : (storage[pluginId] ?? {});
|
|
151
|
+
const program = exam.program(prefix, input);
|
|
152
|
+
if (typeof program !== "string") {
|
|
153
|
+
return sealedValidateDoor(toolCallId, argsJson, program.error, entry);
|
|
154
|
+
}
|
|
155
|
+
// The exam bag is executed as a scheme_repl program, so `description` is
|
|
156
|
+
// required at the door. The tool name is the honest one-line label — it is
|
|
157
|
+
// also the renderer's fallback when a description is absent.
|
|
158
|
+
const frozen = JSON.stringify({
|
|
159
|
+
...input,
|
|
160
|
+
expr: program,
|
|
161
|
+
description: call.function.name,
|
|
162
|
+
});
|
|
163
|
+
const bag = new ProgrammaticJob({
|
|
164
|
+
toolCallId,
|
|
165
|
+
toolName: call.function.name,
|
|
166
|
+
argsJson: frozen,
|
|
167
|
+
...stamp(frozen),
|
|
168
|
+
...catalogFlags(entry),
|
|
169
|
+
});
|
|
170
|
+
if (bag.background && bag.toolCallId.trim() !== "") {
|
|
171
|
+
bag.outcomeSnap ??= { ok: true, value: { job_id: bag.toolCallId, background: true } };
|
|
172
|
+
}
|
|
173
|
+
ctx.originTurn?.pushChild(bag);
|
|
174
|
+
const action = exam.admit(prefix, input);
|
|
175
|
+
let jobUuid = "";
|
|
176
|
+
try {
|
|
177
|
+
jobUuid = bag.uuid;
|
|
178
|
+
} catch {
|
|
179
|
+
jobUuid = "";
|
|
180
|
+
}
|
|
181
|
+
const actionRec = asRecord(action);
|
|
182
|
+
writePluginMeta(bag, pluginId, actionRec == null ? action : { ...actionRec, jobUuid }, true);
|
|
183
|
+
return bag;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
function rejectedComms(
|
|
187
|
+
kind: "callback" | "notify",
|
|
188
|
+
toolCallId: string,
|
|
189
|
+
name: string,
|
|
190
|
+
argsJson: string,
|
|
191
|
+
text: string,
|
|
192
|
+
): AgentCallbackJob | AgentNotifyJob {
|
|
193
|
+
const props = {
|
|
194
|
+
toolCallId,
|
|
195
|
+
name,
|
|
196
|
+
argsJson,
|
|
197
|
+
regenerateable: false as const,
|
|
198
|
+
humanApprove: false as const,
|
|
199
|
+
outcomeJson: JSON.stringify({ ok: false, text }),
|
|
200
|
+
completed: true,
|
|
201
|
+
};
|
|
202
|
+
return kind === "callback" ? new AgentCallbackJob(props) : new AgentNotifyJob(props);
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
export type AdmittedCall = ToolCallJob | ProgrammaticJob;
|
|
206
|
+
|
|
207
|
+
function appendJob<T extends AdmittedCall>(ctx: AdmitContext, job: T): T {
|
|
208
|
+
ctx.parent?.registerJob(job);
|
|
209
|
+
return job;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
function ceilingJob(call: ToolCall): SystemToolJob {
|
|
213
|
+
return new SystemToolJob({
|
|
214
|
+
toolCallId: call.id,
|
|
215
|
+
name: call.function.name,
|
|
216
|
+
argsJson: call.function.arguments,
|
|
217
|
+
humanApprove: false,
|
|
218
|
+
completed: true,
|
|
219
|
+
outcomeJson: JSON.stringify({
|
|
220
|
+
ok: false,
|
|
221
|
+
text: "outside worker tool ceiling",
|
|
222
|
+
}),
|
|
223
|
+
});
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
/** Standing bot or owned child from an `agent__ask` / `agent__send` wire. Unknown recipes seal the ceiling. */
|
|
227
|
+
export function agentCallFromWire(
|
|
228
|
+
call: ToolCall,
|
|
229
|
+
catalog: KernelToolCatalog,
|
|
230
|
+
ctx: AdmitContext = {},
|
|
231
|
+
): BotCallJob | AgentCallJob | SystemToolJob {
|
|
232
|
+
const name = call.function.name;
|
|
233
|
+
if (ctx.session != null && !workerToolAllowed(catalog, ctx.session.agent.spec.name, name, ctx.session)) {
|
|
234
|
+
return appendJob(ctx, ceilingJob(call));
|
|
235
|
+
}
|
|
236
|
+
const peeled = peelAgentCallArgs(call.function.arguments);
|
|
237
|
+
const spec = parseJsonRecord(peeled.argsJson)?.spec;
|
|
238
|
+
// Select the explicit child or bot node at admission;
|
|
239
|
+
// downstream execution is selected by the resulting class, not oneShot/catalog state.
|
|
240
|
+
if (!peeled.oneShot && typeof spec === "string" && spec.trim() !== "") {
|
|
241
|
+
return appendJob(
|
|
242
|
+
ctx,
|
|
243
|
+
new BotCallJob({
|
|
244
|
+
toolCallId: call.id,
|
|
245
|
+
name,
|
|
246
|
+
argsJson: peeled.argsJson,
|
|
247
|
+
botName: spec.trim(),
|
|
248
|
+
voidLegal: name === AGENT_SEND ? peeled.voidLegal : false,
|
|
249
|
+
readonly: peeled.readonly,
|
|
250
|
+
responseSchema: peeled.responseSchema,
|
|
251
|
+
...stamp(peeled.argsJson),
|
|
252
|
+
}),
|
|
253
|
+
);
|
|
254
|
+
}
|
|
255
|
+
return appendJob(
|
|
256
|
+
ctx,
|
|
257
|
+
new AgentCallJob({
|
|
258
|
+
toolCallId: call.id,
|
|
259
|
+
name,
|
|
260
|
+
argsJson: peeled.argsJson,
|
|
261
|
+
regenerateable: false,
|
|
262
|
+
voidLegal: name === AGENT_SEND ? peeled.voidLegal : false,
|
|
263
|
+
readonly: peeled.readonly,
|
|
264
|
+
responseSchema: peeled.responseSchema,
|
|
265
|
+
constitution: peeled.constitution,
|
|
266
|
+
faceName: peeled.faceName,
|
|
267
|
+
tools: peeled.tools,
|
|
268
|
+
inheritCallerTools: peeled.inheritCallerTools,
|
|
269
|
+
reasoningEffort: peeled.reasoningEffort,
|
|
270
|
+
...stamp(peeled.argsJson),
|
|
271
|
+
}),
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
export class ToolCallHandler {
|
|
276
|
+
constructor(readonly kernel: ToolCallKernel) {}
|
|
277
|
+
|
|
278
|
+
admit(call: ToolCall, catalog: KernelToolCatalog = this.kernel.catalog, ctx: AdmitContext = {}): AdmittedCall {
|
|
279
|
+
const job = this.#admit(call, catalog, ctx);
|
|
280
|
+
// R2: the horizon is resolved once, here, from the turn's R1 policy and the catalog as it is now.
|
|
281
|
+
const entry = catalog.catalogEntry(call.function.name) ?? this.kernel.catalog.catalogEntry(call.function.name);
|
|
282
|
+
const turn = ctx.originTurn ?? ctx.session?.head ?? null;
|
|
283
|
+
stampJobRetention(job, policyOfTurn(turn instanceof SessionTurn ? turn : null), {
|
|
284
|
+
...(entry?.class === undefined ? {} : { entryClass: entry.class }),
|
|
285
|
+
...(entry?.retention === undefined ? {} : { hint: entry.retention }),
|
|
286
|
+
});
|
|
287
|
+
return job;
|
|
288
|
+
}
|
|
289
|
+
|
|
290
|
+
#admit(call: ToolCall, catalog: KernelToolCatalog, ctx: AdmitContext): AdmittedCall {
|
|
291
|
+
const place = <T extends AdmittedCall>(job: T): T => appendJob(ctx, job);
|
|
292
|
+
const toolCallId = call.id;
|
|
293
|
+
const name = call.function.name;
|
|
294
|
+
const argsJson = call.function.arguments;
|
|
295
|
+
if (ctx.session != null && !workerToolAllowed(catalog, ctx.session.agent.spec.name, name, ctx.session)) {
|
|
296
|
+
return place(ceilingJob(call));
|
|
297
|
+
}
|
|
298
|
+
if (name === SCHEME_REPL_TOOL_NAME || name === SCHEME_WATCH_TOOL_NAME) {
|
|
299
|
+
const flagged =
|
|
300
|
+
name === SCHEME_WATCH_TOOL_NAME ? { background: true as const, walkBoundary: true as const } : stamp(argsJson);
|
|
301
|
+
const job = new ProgrammaticJob({
|
|
302
|
+
toolName: name,
|
|
303
|
+
toolCallId,
|
|
304
|
+
argsJson,
|
|
305
|
+
...flagged,
|
|
306
|
+
});
|
|
307
|
+
if (job.background && job.toolCallId.trim() !== "") {
|
|
308
|
+
job.outcomeSnap ??= { ok: true, value: { job_id: job.toolCallId, background: true } };
|
|
309
|
+
}
|
|
310
|
+
return place(job);
|
|
311
|
+
}
|
|
312
|
+
const viewEntry = catalog.catalogEntry(name);
|
|
313
|
+
const kernelEntry = this.kernel.catalog.catalogEntry(name);
|
|
314
|
+
const entry = viewEntry ?? kernelEntry ?? catalog.privateWorkerEntries.find((row) => row.wireName === name);
|
|
315
|
+
const regenerateable = viewEntry?.class === "read";
|
|
316
|
+
if (entry?.exam != null) {
|
|
317
|
+
return place(admitExam(call, ctx, entry));
|
|
318
|
+
}
|
|
319
|
+
if (entry?.packMeta?.kind === "bot-call") {
|
|
320
|
+
const meta = entry.packMeta;
|
|
321
|
+
const recipe = catalog.recipe(meta.target);
|
|
322
|
+
const known = recipe != null;
|
|
323
|
+
const revision = pluginRevision(catalog, meta.pluginName);
|
|
324
|
+
const peeled = peelAgentCallArgs(argsJson);
|
|
325
|
+
const job = new BotCallJob({
|
|
326
|
+
toolCallId,
|
|
327
|
+
name,
|
|
328
|
+
argsJson: peeled.argsJson,
|
|
329
|
+
botName: meta.target,
|
|
330
|
+
regenerateable: false,
|
|
331
|
+
voidLegal: peeled.voidLegal,
|
|
332
|
+
readonly: peeled.readonly,
|
|
333
|
+
responseSchema: peeled.responseSchema,
|
|
334
|
+
contributionPluginName: meta.pluginName,
|
|
335
|
+
contributionBotName: meta.target,
|
|
336
|
+
contributionRevision: revision,
|
|
337
|
+
...(meta.background ? { background: true, walkBoundary: true } : stamp(argsJson)),
|
|
338
|
+
...(known
|
|
339
|
+
? {}
|
|
340
|
+
: {
|
|
341
|
+
outcome: new FailureOutcome({
|
|
342
|
+
code: "unknown_recipe",
|
|
343
|
+
message: "unknown recipe",
|
|
344
|
+
}),
|
|
345
|
+
completed: true,
|
|
346
|
+
}),
|
|
347
|
+
});
|
|
348
|
+
if (known && meta.lifetime != null) job.delivery = new CallDelivery({ lifetime: meta.lifetime });
|
|
349
|
+
return place(job);
|
|
350
|
+
}
|
|
351
|
+
if (entry?.source.kind === "connection") {
|
|
352
|
+
const hidden = viewEntry == null && !catalog.privateWorkerEntries.some((row) => row.wireName === name);
|
|
353
|
+
const blocked =
|
|
354
|
+
ctx.session != null &&
|
|
355
|
+
mcpToolListHas(ctx.session.toolBlocklist, entry.source.connectionKey, entry.source.serverToolName);
|
|
356
|
+
if (hidden || blocked) {
|
|
357
|
+
return place(
|
|
358
|
+
new MCPToolJob({
|
|
359
|
+
toolCallId,
|
|
360
|
+
name,
|
|
361
|
+
argsJson,
|
|
362
|
+
regenerateable: false,
|
|
363
|
+
connectionKey: entry.source.connectionKey,
|
|
364
|
+
serverToolName: entry.source.serverToolName,
|
|
365
|
+
expectation: new McpToolExpectation({
|
|
366
|
+
connectionId: entry.source.connectionKey,
|
|
367
|
+
serverToolName: entry.source.serverToolName,
|
|
368
|
+
argsJson,
|
|
369
|
+
}),
|
|
370
|
+
humanApprove: false,
|
|
371
|
+
completed: true,
|
|
372
|
+
outcomeJson: JSON.stringify({
|
|
373
|
+
ok: false,
|
|
374
|
+
text: `unknown MCP tool "${entry.source.serverToolName}"`,
|
|
375
|
+
}),
|
|
376
|
+
}),
|
|
377
|
+
);
|
|
378
|
+
}
|
|
379
|
+
return place(
|
|
380
|
+
new MCPToolJob({
|
|
381
|
+
toolCallId,
|
|
382
|
+
name,
|
|
383
|
+
argsJson,
|
|
384
|
+
regenerateable,
|
|
385
|
+
connectionKey: entry.source.connectionKey,
|
|
386
|
+
serverToolName: entry.source.serverToolName,
|
|
387
|
+
expectation: new McpToolExpectation({
|
|
388
|
+
connectionId: entry.source.connectionKey,
|
|
389
|
+
serverToolName: entry.source.serverToolName,
|
|
390
|
+
argsJson,
|
|
391
|
+
}),
|
|
392
|
+
}),
|
|
393
|
+
);
|
|
394
|
+
}
|
|
395
|
+
if (name === AGENT_ASK || name === AGENT_SEND) {
|
|
396
|
+
return agentCallFromWire(call, catalog, ctx);
|
|
397
|
+
}
|
|
398
|
+
const requestId = requestIdOf(argsJson);
|
|
399
|
+
const ownsOpen = ctx.session != null && requestId !== "" && ctx.session.agentCallbacks[requestId] != null;
|
|
400
|
+
if (name === AGENT_RESPOND || name === AGENT_VOID) {
|
|
401
|
+
if (ownsOpen) {
|
|
402
|
+
return place(
|
|
403
|
+
new AgentCallbackJob({
|
|
404
|
+
toolCallId,
|
|
405
|
+
name,
|
|
406
|
+
argsJson,
|
|
407
|
+
regenerateable: false,
|
|
408
|
+
...stamp(argsJson),
|
|
409
|
+
}),
|
|
410
|
+
);
|
|
411
|
+
}
|
|
412
|
+
return place(rejectedComms("callback", toolCallId, name, argsJson, "no open callback"));
|
|
413
|
+
}
|
|
414
|
+
if (name === AGENT_NOTIFY) {
|
|
415
|
+
const open = ownsOpen && ctx.loadAgentCall != null ? ctx.loadAgentCall(requestId) : undefined;
|
|
416
|
+
if (open != null && agentCallSupportsNotify(catalog, open.name)) {
|
|
417
|
+
return place(
|
|
418
|
+
new AgentNotifyJob({
|
|
419
|
+
toolCallId,
|
|
420
|
+
name,
|
|
421
|
+
argsJson,
|
|
422
|
+
regenerateable: false,
|
|
423
|
+
...stamp(argsJson),
|
|
424
|
+
}),
|
|
425
|
+
);
|
|
426
|
+
}
|
|
427
|
+
return place(rejectedComms("notify", toolCallId, name, argsJson, "no open notify"));
|
|
428
|
+
}
|
|
429
|
+
if (name === AGENT_MESSAGE) {
|
|
430
|
+
return place(
|
|
431
|
+
new AgentMessageJob({
|
|
432
|
+
toolCallId,
|
|
433
|
+
name,
|
|
434
|
+
argsJson,
|
|
435
|
+
regenerateable: false,
|
|
436
|
+
...stamp(argsJson),
|
|
437
|
+
}),
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
if (name === CONTEXT_NEED_TOOL_NAME) {
|
|
441
|
+
return place(
|
|
442
|
+
new ContextNeedToolJob({
|
|
443
|
+
toolCallId,
|
|
444
|
+
name,
|
|
445
|
+
argsJson,
|
|
446
|
+
regenerateable: false,
|
|
447
|
+
...stamp(argsJson),
|
|
448
|
+
...catalogFlags(entry),
|
|
449
|
+
}),
|
|
450
|
+
);
|
|
451
|
+
}
|
|
452
|
+
if (name === WEB_SEARCH_TOOL_NAME) {
|
|
453
|
+
const parsed = parseWebSearchArgs(argsJson);
|
|
454
|
+
return place(
|
|
455
|
+
new WebSearchToolJob({
|
|
456
|
+
toolCallId,
|
|
457
|
+
name,
|
|
458
|
+
argsJson,
|
|
459
|
+
regenerateable: false,
|
|
460
|
+
expectation: new WebSearchExpectation({
|
|
461
|
+
connectionId: WEB_SEARCH_TOOL_NAME,
|
|
462
|
+
query: parsed.query,
|
|
463
|
+
limit: parsed.limit,
|
|
464
|
+
}),
|
|
465
|
+
...stamp(argsJson),
|
|
466
|
+
}),
|
|
467
|
+
);
|
|
468
|
+
}
|
|
469
|
+
if (name === WEB_EXTRACT_TOOL_NAME) {
|
|
470
|
+
const parsed = parseWebExtractArgs(argsJson);
|
|
471
|
+
return place(
|
|
472
|
+
new WebExtractToolJob({
|
|
473
|
+
toolCallId,
|
|
474
|
+
name,
|
|
475
|
+
argsJson,
|
|
476
|
+
regenerateable: false,
|
|
477
|
+
expectation: new WebExtractExpectation({
|
|
478
|
+
connectionId: WEB_EXTRACT_TOOL_NAME,
|
|
479
|
+
url: parsed.url,
|
|
480
|
+
charLimit: parsed.charLimit,
|
|
481
|
+
}),
|
|
482
|
+
...stamp(argsJson),
|
|
483
|
+
}),
|
|
484
|
+
);
|
|
485
|
+
}
|
|
486
|
+
const fileRoot = ctx.session?.path.trim() ?? "";
|
|
487
|
+
const fileSnap =
|
|
488
|
+
(name === "write_file" || name === "edit_file") && fileRoot !== ""
|
|
489
|
+
? writeFileAdmitSnap(fileRoot, argsJson)
|
|
490
|
+
: null;
|
|
491
|
+
let oldString = "";
|
|
492
|
+
if (name === "edit_file") {
|
|
493
|
+
const parsed = parseJsonRecord(argsJson === "" ? "{}" : argsJson);
|
|
494
|
+
const old = parsed == null ? undefined : parsed.old_string;
|
|
495
|
+
if (typeof old === "string") oldString = old;
|
|
496
|
+
}
|
|
497
|
+
const priorLineStart =
|
|
498
|
+
name === "edit_file" && fileSnap?.priorContent != null ? lineStartOfSpan(fileSnap.priorContent, oldString) : null;
|
|
499
|
+
let shellArgsJson = argsJson;
|
|
500
|
+
let shellRefuse: string | undefined;
|
|
501
|
+
if (name === "shell") {
|
|
502
|
+
const parsed = parseJsonRecord(argsJson === "" ? "{}" : argsJson);
|
|
503
|
+
if (parsed != null) {
|
|
504
|
+
const command = parsed.command;
|
|
505
|
+
if (typeof command === "string" && command !== "") {
|
|
506
|
+
const cwdArg = typeof parsed.cwd === "string" ? parsed.cwd : undefined;
|
|
507
|
+
const peeled = peelShellCwd(command, cwdArg);
|
|
508
|
+
if (peeled !== null && peeled.command === "") {
|
|
509
|
+
shellRefuse = "cwd only; use the cwd arg on the next call";
|
|
510
|
+
} else if (peeled !== null) {
|
|
511
|
+
shellArgsJson = JSON.stringify({
|
|
512
|
+
...parsed,
|
|
513
|
+
cwd: peeled.cwd,
|
|
514
|
+
command: peeled.command,
|
|
515
|
+
});
|
|
516
|
+
}
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
}
|
|
520
|
+
if (shellRefuse !== undefined) {
|
|
521
|
+
return place(
|
|
522
|
+
new SystemToolJob({
|
|
523
|
+
toolCallId,
|
|
524
|
+
name,
|
|
525
|
+
argsJson: shellArgsJson,
|
|
526
|
+
regenerateable: false,
|
|
527
|
+
completed: true,
|
|
528
|
+
outcomeJson: JSON.stringify({ ok: false, text: shellRefuse }),
|
|
529
|
+
}),
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
if (name === "write_file" || name === "edit_file") {
|
|
533
|
+
if (name === "write_file" && fileSnap?.refuse != null) {
|
|
534
|
+
return place(
|
|
535
|
+
new FileMutateToolJob({
|
|
536
|
+
toolCallId,
|
|
537
|
+
name,
|
|
538
|
+
argsJson,
|
|
539
|
+
regenerateable: false,
|
|
540
|
+
completed: true,
|
|
541
|
+
existed: fileSnap.existed,
|
|
542
|
+
...priorProps(fileSnap.priorContent),
|
|
543
|
+
outcomeJson: JSON.stringify({ ok: false, text: fileSnap.refuse }),
|
|
544
|
+
}),
|
|
545
|
+
);
|
|
546
|
+
}
|
|
547
|
+
const prior =
|
|
548
|
+
fileSnap == null
|
|
549
|
+
? {}
|
|
550
|
+
: {
|
|
551
|
+
...(fileSnap.existed === null ? {} : { existed: fileSnap.existed }),
|
|
552
|
+
...priorProps(fileSnap.priorContent),
|
|
553
|
+
...(priorLineStart == null ? {} : { priorLineStart }),
|
|
554
|
+
};
|
|
555
|
+
return place(
|
|
556
|
+
new FileMutateToolJob({
|
|
557
|
+
toolCallId,
|
|
558
|
+
name,
|
|
559
|
+
argsJson,
|
|
560
|
+
regenerateable,
|
|
561
|
+
...catalogFlags(entry),
|
|
562
|
+
...prior,
|
|
563
|
+
}),
|
|
564
|
+
);
|
|
565
|
+
}
|
|
566
|
+
return place(
|
|
567
|
+
new SystemToolJob({
|
|
568
|
+
toolCallId,
|
|
569
|
+
name,
|
|
570
|
+
argsJson: shellArgsJson,
|
|
571
|
+
regenerateable,
|
|
572
|
+
...catalogFlags(entry),
|
|
573
|
+
}),
|
|
574
|
+
);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
export {
|
|
2
|
+
bindBlobWriter,
|
|
3
|
+
externalizePrior,
|
|
4
|
+
externalizeText,
|
|
5
|
+
writeBlob,
|
|
6
|
+
type BlobWriter,
|
|
7
|
+
type PriorProps,
|
|
8
|
+
type TextStamp,
|
|
9
|
+
} from "./blob-port.js";
|
|
10
|
+
export { extraRootAllowed } from "./extra-root.js";
|
|
11
|
+
export { peelAgentCallArgs } from "./peel.js";
|
|
12
|
+
export { agentCallFromWire, ToolCallHandler } from "./handler.js";
|
|
13
|
+
export { executeSystemTool, sealToolCall } from "./run-system-tool.js";
|
|
14
|
+
export { CONTEXT_RECALL_TOOL_NAME, recallContext } from "./recall.js";
|
|
15
|
+
export { ToolError } from "./tool-error.js";
|
|
16
|
+
export { workerToolAllowed } from "./worker-tools.js";
|
|
17
|
+
export { isModelOriginContext, pluginCallContextOf } from "./plugin-context.js";
|
|
18
|
+
export { cancelUnstartedTool } from "./approval/approved.js";
|
|
19
|
+
export { distPolicySource, loadPolicySource } from "./approval/dist.js";
|
|
20
|
+
export { inboundTurnGuard, publishPolicyError, stampLicenseDeny } from "./approval/inbound.js";
|
|
21
|
+
export { resolveEvalPermissionMode, unattendedFailureText } from "./approval/unattended.js";
|
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Drop ask flags from the message bag so dumps stay message-only.
|
|
3
|
+
*/
|
|
4
|
+
import { asSystemPrompt, type SystemPrompt } from "@inhuman.tools/harness-commons";
|
|
5
|
+
import { parseJsonRecord } from "@inhuman.tools/harness-model/json-record";
|
|
6
|
+
import { agentCallBagSchema, requestIdBagSchema } from "@inhuman.tools/harness-model/schemas";
|
|
7
|
+
import { reasoningEffortOf, type ReasoningEffort } from "@inhuman.tools/harness-model/session";
|
|
8
|
+
|
|
9
|
+
const EMPTY_PEEL = {
|
|
10
|
+
voidLegal: true,
|
|
11
|
+
readonly: false,
|
|
12
|
+
responseSchema: null,
|
|
13
|
+
oneShot: false,
|
|
14
|
+
constitution: asSystemPrompt(""),
|
|
15
|
+
faceName: "",
|
|
16
|
+
tools: [] as const,
|
|
17
|
+
inheritCallerTools: false,
|
|
18
|
+
reasoningEffort: null,
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
const PEELED_KEYS = [
|
|
22
|
+
"voidLegal",
|
|
23
|
+
"readonly",
|
|
24
|
+
"responseSchema",
|
|
25
|
+
"responseSchemaJson",
|
|
26
|
+
"oneShot",
|
|
27
|
+
"constitution",
|
|
28
|
+
"name",
|
|
29
|
+
"tools",
|
|
30
|
+
"inheritCallerTools",
|
|
31
|
+
"reasoningEffort",
|
|
32
|
+
] as const;
|
|
33
|
+
|
|
34
|
+
function responseSchemaOf(rec: {
|
|
35
|
+
readonly responseSchemaJson?: unknown;
|
|
36
|
+
readonly responseSchema?: unknown;
|
|
37
|
+
}): Record<string, unknown> | null {
|
|
38
|
+
const text =
|
|
39
|
+
typeof rec.responseSchemaJson === "string"
|
|
40
|
+
? rec.responseSchemaJson
|
|
41
|
+
: typeof rec.responseSchema === "string"
|
|
42
|
+
? rec.responseSchema
|
|
43
|
+
: null;
|
|
44
|
+
if (text != null) {
|
|
45
|
+
const trimmed = text.trim();
|
|
46
|
+
return trimmed === "" ? null : parseJsonRecord(trimmed);
|
|
47
|
+
}
|
|
48
|
+
if (rec.responseSchema == null || typeof rec.responseSchema !== "object" || Array.isArray(rec.responseSchema)) {
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
return parseJsonRecord(JSON.stringify(rec.responseSchema));
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
export function peelAgentCallArgs(argsJson: string): {
|
|
55
|
+
readonly argsJson: string;
|
|
56
|
+
readonly voidLegal: boolean;
|
|
57
|
+
readonly readonly: boolean;
|
|
58
|
+
readonly responseSchema: Record<string, unknown> | null;
|
|
59
|
+
readonly oneShot: boolean;
|
|
60
|
+
readonly constitution: SystemPrompt;
|
|
61
|
+
readonly faceName: string;
|
|
62
|
+
readonly tools: readonly string[];
|
|
63
|
+
readonly inheritCallerTools: boolean;
|
|
64
|
+
readonly reasoningEffort: ReasoningEffort | null;
|
|
65
|
+
} {
|
|
66
|
+
const parsed = agentCallBagSchema.safeParse(parseJsonRecord(argsJson === "" ? "{}" : argsJson));
|
|
67
|
+
if (!parsed.success) return { argsJson, ...EMPTY_PEEL };
|
|
68
|
+
const rec = parsed.data;
|
|
69
|
+
const rest: Record<string, unknown> = { ...rec };
|
|
70
|
+
for (const key of PEELED_KEYS) delete rest[key];
|
|
71
|
+
const tools = Array.isArray(rec.tools)
|
|
72
|
+
? rec.tools.filter((row): row is string => typeof row === "string" && row.trim() !== "").map((row) => row.trim())
|
|
73
|
+
: [];
|
|
74
|
+
return {
|
|
75
|
+
argsJson: JSON.stringify(rest),
|
|
76
|
+
voidLegal: rec.voidLegal !== false,
|
|
77
|
+
readonly: rec.readonly === true,
|
|
78
|
+
responseSchema: responseSchemaOf(rec),
|
|
79
|
+
oneShot: rec.oneShot === true,
|
|
80
|
+
constitution: asSystemPrompt(typeof rec.constitution === "string" ? rec.constitution : ""),
|
|
81
|
+
faceName: typeof rec.name === "string" ? rec.name.trim() : "",
|
|
82
|
+
tools,
|
|
83
|
+
inheritCallerTools: rec.inheritCallerTools === true,
|
|
84
|
+
reasoningEffort: reasoningEffortOf(rec.reasoningEffort),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export function requestIdOf(argsJson: unknown): string {
|
|
89
|
+
const parsed = requestIdBagSchema.safeParse(argsJson);
|
|
90
|
+
return parsed.success ? (parsed.data.requestId ?? "") : "";
|
|
91
|
+
}
|