@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,154 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Bot recipes. Standing bots go through `bot/send` / `bot/ask` —
|
|
3
|
+
* not per-recipe catalog rows. No execute bodies.
|
|
4
|
+
*/
|
|
5
|
+
import { asSystemPrompt } from "@inhuman.tools/harness-commons";
|
|
6
|
+
import { AGENT_ASK, AGENT_SEND, BotSpec, type RecipeScope, type ReasoningEffort } from "@inhuman.tools/harness-model";
|
|
7
|
+
|
|
8
|
+
import { CallsCatalog } from "../agent-calls/types.js";
|
|
9
|
+
|
|
10
|
+
export type { RecipeScope } from "@inhuman.tools/harness-model";
|
|
11
|
+
|
|
12
|
+
export type RecipeCapability = {
|
|
13
|
+
readonly name: string;
|
|
14
|
+
readonly description?: string;
|
|
15
|
+
readonly supportsNotify?: boolean;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type CatalogRecipe = {
|
|
19
|
+
readonly spec: BotSpec;
|
|
20
|
+
readonly category: "plugin" | "internal";
|
|
21
|
+
readonly capabilities: readonly RecipeCapability[];
|
|
22
|
+
};
|
|
23
|
+
|
|
24
|
+
export function catalogRecipe(init: {
|
|
25
|
+
readonly name: string;
|
|
26
|
+
readonly category: CatalogRecipe["category"];
|
|
27
|
+
readonly recipeScope?: RecipeScope;
|
|
28
|
+
readonly keepAlive?: boolean;
|
|
29
|
+
readonly description?: string;
|
|
30
|
+
readonly instructions?: string;
|
|
31
|
+
readonly tools?: readonly string[];
|
|
32
|
+
readonly invokes?: readonly string[];
|
|
33
|
+
readonly reasoningEffort?: ReasoningEffort;
|
|
34
|
+
readonly modelPreferences?: readonly string[];
|
|
35
|
+
readonly skills?: readonly string[];
|
|
36
|
+
readonly capabilities?: readonly RecipeCapability[];
|
|
37
|
+
}): CatalogRecipe {
|
|
38
|
+
return {
|
|
39
|
+
spec: new BotSpec({
|
|
40
|
+
name: init.name,
|
|
41
|
+
recipeScope: init.recipeScope ?? "session",
|
|
42
|
+
keepAlive: init.keepAlive === true,
|
|
43
|
+
description: init.description ?? "",
|
|
44
|
+
instructions: asSystemPrompt(init.instructions ?? ""),
|
|
45
|
+
tools: init.tools ? [...init.tools] : [],
|
|
46
|
+
invokes: init.invokes ? [...init.invokes] : [],
|
|
47
|
+
reasoningEffort: init.reasoningEffort ?? null,
|
|
48
|
+
modelPreferences: init.modelPreferences ? [...init.modelPreferences] : [],
|
|
49
|
+
skills: init.skills ? [...init.skills] : [],
|
|
50
|
+
}),
|
|
51
|
+
category: init.category,
|
|
52
|
+
capabilities: init.capabilities ?? [],
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export function findRecipe(recipes: readonly CatalogRecipe[], name: string): CatalogRecipe | undefined {
|
|
57
|
+
return recipes.find((recipe) => recipe.spec.name === name);
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export function agentCallSupportsNotify(catalog: CallsCatalog, callName: string): boolean {
|
|
61
|
+
if (callName === AGENT_SEND || callName === AGENT_ASK) return true;
|
|
62
|
+
const entry = catalog.catalogEntry(callName);
|
|
63
|
+
if (entry?.packMeta?.kind === "bot-call") {
|
|
64
|
+
return entry.packMeta.supportsNotify === true;
|
|
65
|
+
}
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
/** Foreground (no recipe name) may invoke any known recipe. A worker may only invoke declared edges. */
|
|
70
|
+
export function invokeDenied(
|
|
71
|
+
recipes: readonly CatalogRecipe[],
|
|
72
|
+
invokerName: string,
|
|
73
|
+
targetName: string,
|
|
74
|
+
): string | undefined {
|
|
75
|
+
if (invokerName === "") return undefined;
|
|
76
|
+
const invoker = findRecipe(recipes, invokerName);
|
|
77
|
+
if (invoker == null) return `unknown invoker recipe ${invokerName}`;
|
|
78
|
+
if (!invoker.spec.invokes.includes(targetName)) return `${invokerName} cannot invoke ${targetName}`;
|
|
79
|
+
if (edgeCreatesCycle(recipes, invokerName, targetName)) return `invoke cycle ${invokerName} → ${targetName}`;
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/** First cycle path (including return to the start), or null if the DAG is sound. */
|
|
84
|
+
export function invokeCyclePath(recipes: readonly CatalogRecipe[]): readonly string[] | null {
|
|
85
|
+
const edges = new Map(recipes.map((recipe) => [recipe.spec.name, recipe.spec.invokes]));
|
|
86
|
+
const names = new Set(recipes.map((recipe) => recipe.spec.name));
|
|
87
|
+
const visiting = new Set<string>();
|
|
88
|
+
const seen = new Set<string>();
|
|
89
|
+
const stack: string[] = [];
|
|
90
|
+
|
|
91
|
+
const visit = (node: string): readonly string[] | null => {
|
|
92
|
+
if (visiting.has(node)) {
|
|
93
|
+
const at = stack.indexOf(node);
|
|
94
|
+
return at === -1 ? [node, node] : [...stack.slice(at), node];
|
|
95
|
+
}
|
|
96
|
+
if (seen.has(node)) return null;
|
|
97
|
+
visiting.add(node);
|
|
98
|
+
stack.push(node);
|
|
99
|
+
for (const next of edges.get(node) ?? []) {
|
|
100
|
+
if (!names.has(next)) continue;
|
|
101
|
+
const cycle = visit(next);
|
|
102
|
+
if (cycle != null) return cycle;
|
|
103
|
+
}
|
|
104
|
+
stack.pop();
|
|
105
|
+
visiting.delete(node);
|
|
106
|
+
seen.add(node);
|
|
107
|
+
return null;
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
for (const name of names) {
|
|
111
|
+
const cycle = visit(name);
|
|
112
|
+
if (cycle != null) return cycle;
|
|
113
|
+
}
|
|
114
|
+
return null;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
export function edgeCreatesCycle(recipes: readonly CatalogRecipe[], from: string, to: string): boolean {
|
|
118
|
+
if (from === to) return true;
|
|
119
|
+
return (
|
|
120
|
+
invokeCyclePath(
|
|
121
|
+
recipes.map((recipe) => {
|
|
122
|
+
if (recipe.spec.name !== from) return recipe;
|
|
123
|
+
const spec = recipe.spec;
|
|
124
|
+
return {
|
|
125
|
+
...recipe,
|
|
126
|
+
spec: new BotSpec({
|
|
127
|
+
name: spec.name,
|
|
128
|
+
description: spec.description,
|
|
129
|
+
recipeScope: spec.recipeScope,
|
|
130
|
+
keepAlive: spec.keepAlive,
|
|
131
|
+
instructions: spec.instructions,
|
|
132
|
+
tools: [...spec.tools],
|
|
133
|
+
invokes: [...spec.invokes, to],
|
|
134
|
+
reasoningEffort: spec.reasoningEffort,
|
|
135
|
+
skills: [...spec.skills],
|
|
136
|
+
modelPreferences: [...spec.modelPreferences],
|
|
137
|
+
error: spec.error,
|
|
138
|
+
}),
|
|
139
|
+
};
|
|
140
|
+
}),
|
|
141
|
+
) != null
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
export function dedupeRecipes(recipes: readonly CatalogRecipe[]): CatalogRecipe[] {
|
|
146
|
+
const seen = new Set<string>();
|
|
147
|
+
const out: CatalogRecipe[] = [];
|
|
148
|
+
for (const recipe of recipes) {
|
|
149
|
+
if (seen.has(recipe.spec.name)) continue;
|
|
150
|
+
seen.add(recipe.spec.name);
|
|
151
|
+
out.push(recipe);
|
|
152
|
+
}
|
|
153
|
+
return out;
|
|
154
|
+
}
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Catalog row identity. wireName is a model-edge projection — never durable
|
|
3
|
+
* routing. Connection tools route by connectionKey + serverToolName.
|
|
4
|
+
*/
|
|
5
|
+
import type { RuleInput } from "../context/retention/schema.js";
|
|
6
|
+
|
|
7
|
+
export type CatalogSource =
|
|
8
|
+
| { readonly kind: "pack"; readonly pluginName: string }
|
|
9
|
+
| {
|
|
10
|
+
readonly kind: "connection";
|
|
11
|
+
/** Kernel `connections` map key (slug). Lawful cross-doc pointer to ConnectionSpec. */
|
|
12
|
+
readonly connectionKey: string;
|
|
13
|
+
readonly serverToolName: string;
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
export type CatalogExecute = (
|
|
17
|
+
raw: unknown,
|
|
18
|
+
ctx: {
|
|
19
|
+
root?: string;
|
|
20
|
+
signal?: AbortSignal;
|
|
21
|
+
sessionId?: string;
|
|
22
|
+
background?: unknown;
|
|
23
|
+
catalog?: unknown;
|
|
24
|
+
onPriorContent?: (text: string | null) => void;
|
|
25
|
+
invocation?: unknown;
|
|
26
|
+
shellTailBytes?: number;
|
|
27
|
+
onTail?: (frame: { readonly text: string; readonly totalBytes: number }) => void;
|
|
28
|
+
},
|
|
29
|
+
) => Promise<unknown>;
|
|
30
|
+
|
|
31
|
+
/** `tool` is completions tools[]. `symbol` is a scheme_repl name. `both` is both. */
|
|
32
|
+
export type ToolRepresentation = "tool" | "symbol" | "both";
|
|
33
|
+
|
|
34
|
+
export type PackToolMeta =
|
|
35
|
+
| { readonly kind: "function" }
|
|
36
|
+
| {
|
|
37
|
+
readonly kind: "bot-call";
|
|
38
|
+
readonly pluginName: string;
|
|
39
|
+
readonly target: string;
|
|
40
|
+
readonly background: boolean;
|
|
41
|
+
readonly lifetime: "turn" | "call";
|
|
42
|
+
readonly show: "result" | "omit" | "turn";
|
|
43
|
+
readonly deadlineMs?: number;
|
|
44
|
+
readonly supportsNotify: boolean;
|
|
45
|
+
};
|
|
46
|
+
|
|
47
|
+
export type CatalogEntry = {
|
|
48
|
+
readonly wireName: string;
|
|
49
|
+
readonly description: string;
|
|
50
|
+
readonly parameters: Record<string, unknown>;
|
|
51
|
+
/** Catalog class: `read` | `write` | `effect` | `meta`. Missing / unknown → `effect`. */
|
|
52
|
+
readonly class: string;
|
|
53
|
+
/**
|
|
54
|
+
* Model face. Omitted is a scheme symbol and stays off completions tools[].
|
|
55
|
+
* Native tools set this on `InhumanTool`; the catalog row copies it.
|
|
56
|
+
*/
|
|
57
|
+
readonly representation?: ToolRepresentation;
|
|
58
|
+
readonly source: CatalogSource;
|
|
59
|
+
/**
|
|
60
|
+
* Pack / host plugins carry execute (InhumanTool.execute).
|
|
61
|
+
* Connection tools are projection-only — BODY is MCP PEW on the connection.
|
|
62
|
+
*/
|
|
63
|
+
readonly execute?: CatalogExecute;
|
|
64
|
+
readonly packMeta?: PackToolMeta;
|
|
65
|
+
readonly triggersReactLoop?: boolean;
|
|
66
|
+
/** Skips the license floor. Copied from the tool that declared it. */
|
|
67
|
+
readonly isSideChannel?: boolean;
|
|
68
|
+
readonly tapeHidden?: boolean;
|
|
69
|
+
/**
|
|
70
|
+
* Self-declared retention hint (e.g. ephemeral output). Narrowing only, and
|
|
71
|
+
* only for this tool's own key: it can shorten what the policy says, never lengthen it.
|
|
72
|
+
*/
|
|
73
|
+
readonly retention?: RuleInput;
|
|
74
|
+
/** Mustache the TUI paints while the call is open, after it seals, and as a caption. */
|
|
75
|
+
readonly question?: string | null;
|
|
76
|
+
readonly effect?: string | null;
|
|
77
|
+
readonly caption?: string | null;
|
|
78
|
+
/**
|
|
79
|
+
* Exam admit bag. Structural so this package does not import plugin-sdk.
|
|
80
|
+
* Plugin ExamAdmit is assignable.
|
|
81
|
+
*/
|
|
82
|
+
readonly exam?: {
|
|
83
|
+
readonly program: (state: any, input: any) => string | { readonly error: string };
|
|
84
|
+
readonly admit: (state: any, input: any) => any;
|
|
85
|
+
readonly settle?: (state: any, input: any, result: any) => any;
|
|
86
|
+
};
|
|
87
|
+
};
|
|
88
|
+
|
|
89
|
+
/** What a recipe needs to grant a wire beyond its plain tool list. */
|
|
90
|
+
export type RecipeGrantSpec = {
|
|
91
|
+
readonly recipeScope: "session" | "project" | "global";
|
|
92
|
+
readonly mcpJson: string;
|
|
93
|
+
readonly tools: readonly string[];
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Host-owned parts of the worker tool ceiling (bot-granted MCP, private plugin MCP). The ceiling
|
|
98
|
+
* itself lives in one place, `workerToolAllowed`; the host only answers these two questions.
|
|
99
|
+
*/
|
|
100
|
+
export type WorkerToolHost = {
|
|
101
|
+
/** Does the recipe grant this wire through its tool list or its `mcpJson` grants? */
|
|
102
|
+
readonly recipeGrantsWire: (catalog: object, spec: RecipeGrantSpec, wire: string, projectPath: string) => boolean;
|
|
103
|
+
/** Is this wire one of the recipe's private plugin MCP tools, not (yet) in the catalog view? */
|
|
104
|
+
readonly privateWireAllowed: (recipeName: string, wire: string, sessionRoot: object | undefined) => boolean;
|
|
105
|
+
};
|
|
106
|
+
|
|
107
|
+
export const PLAIN_WORKER_HOST: WorkerToolHost = {
|
|
108
|
+
recipeGrantsWire: (_catalog, spec, wire) => spec.tools.includes(wire),
|
|
109
|
+
privateWireAllowed: () => false,
|
|
110
|
+
};
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cancel and generic outcome stamps on the leaf. Payload construction lives
|
|
3
|
+
* in harness-model. Cancel writes `cancelled`, not `approved`. Human
|
|
4
|
+
* `approvalComment` is a `TurnApprovalNoteChunk`, not this receipt.
|
|
5
|
+
*/
|
|
6
|
+
import { ApprovableJob, applyToolOutcomeReceipt, cancelUnstarted } from "@inhuman.tools/harness-model";
|
|
7
|
+
import { action } from "mobx";
|
|
8
|
+
|
|
9
|
+
export function stampToolOutcome(leaf: ApprovableJob, text: "denied" | "cancelled", reason?: unknown): void {
|
|
10
|
+
applyToolOutcomeReceipt(leaf, text, reason);
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Unstarted (or allow-side but not yet BODY) cancel. Does not write
|
|
15
|
+
* `approved` or `orchestrationResult`.
|
|
16
|
+
*/
|
|
17
|
+
export const cancelUnstartedTool = action((leaf: ApprovableJob, reason?: unknown): void => {
|
|
18
|
+
if (leaf.completed || leaf.cancelled) return;
|
|
19
|
+
cancelUnstarted(leaf, reason);
|
|
20
|
+
});
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dist `policy.json` is the never-throwing program in policy-processor.
|
|
3
|
+
* `{kernelFsRoot}/policy.json` wins when present and non-empty.
|
|
4
|
+
*/
|
|
5
|
+
import { readFileSync } from "node:fs";
|
|
6
|
+
import { join } from "node:path";
|
|
7
|
+
|
|
8
|
+
import { reasonableDefaultsSource } from "@inhuman.tools/policy/floor";
|
|
9
|
+
|
|
10
|
+
export function distPolicySource(): string {
|
|
11
|
+
return reasonableDefaultsSource;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
function readOperatorPolicySource(kernelFsRoot: string): string | undefined {
|
|
15
|
+
try {
|
|
16
|
+
const user = readFileSync(join(kernelFsRoot, "policy.json"), "utf8");
|
|
17
|
+
if (user.trim() !== "") return user;
|
|
18
|
+
} catch {
|
|
19
|
+
/* missing operator policy is dist */
|
|
20
|
+
}
|
|
21
|
+
return undefined;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Body of the one policy program. Never throws. Missing operator → dist.
|
|
26
|
+
*/
|
|
27
|
+
export function loadPolicySource(kernelFsRoot: string): string | undefined {
|
|
28
|
+
return readOperatorPolicySource(kernelFsRoot) ?? distPolicySource();
|
|
29
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* LICENSE WHEN is the Approvable guard. Sequences typically return true;
|
|
3
|
+
* inbound Turn waits predecessors without returning false (false is deny).
|
|
4
|
+
*/
|
|
5
|
+
import { FieldAwareness } from "@here.build/plexus";
|
|
6
|
+
import {
|
|
7
|
+
ApprovableJob,
|
|
8
|
+
applyDenyReceipt,
|
|
9
|
+
SessionTurn,
|
|
10
|
+
type PermissionMode,
|
|
11
|
+
type SessionPlexus,
|
|
12
|
+
} from "@inhuman.tools/harness-model";
|
|
13
|
+
import { when } from "mobx";
|
|
14
|
+
|
|
15
|
+
function inboundPredecessorClosed(turn: SessionTurn): boolean {
|
|
16
|
+
if (!turn.inbound) return true;
|
|
17
|
+
const seen = new Set<SessionTurn>([turn]);
|
|
18
|
+
let prior = turn.turnTail;
|
|
19
|
+
while (prior instanceof SessionTurn && !seen.has(prior)) {
|
|
20
|
+
seen.add(prior);
|
|
21
|
+
if (!prior.reducerExited) return false;
|
|
22
|
+
if (!prior.inbound) break;
|
|
23
|
+
prior = prior.turnTail;
|
|
24
|
+
}
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Sequence guard: wait, then true. Never false — that would deny BODY. */
|
|
29
|
+
export function inboundTurnGuard(turn: SessionTurn): boolean | Promise<true> {
|
|
30
|
+
if (inboundPredecessorClosed(turn)) return true;
|
|
31
|
+
return (async () => {
|
|
32
|
+
await when(() => inboundPredecessorClosed(turn) || turn.cancelled || turn.completed);
|
|
33
|
+
return true as const;
|
|
34
|
+
})();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export function publishPolicyError(session: SessionPlexus, text: string | null): void {
|
|
38
|
+
try {
|
|
39
|
+
const lane = new FieldAwareness(session.awareness, "policyError");
|
|
40
|
+
if (text == null || text === "") lane.clear();
|
|
41
|
+
else lane.set(text);
|
|
42
|
+
} catch {
|
|
43
|
+
/* presence must not block the floor vote */
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/** Floor produce is policy-processor `license`. `_policy` is unused — writing it would fork the receipt. */
|
|
48
|
+
export function stampLicenseDeny(leaf: ApprovableJob, _policy: PermissionMode): void {
|
|
49
|
+
applyDenyReceipt(leaf);
|
|
50
|
+
}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unattended coded receipts. Residual ask under auto is the judge, not
|
|
3
|
+
* `policy_denied`. Operator throw is awareness + dist, not `policy_error`.
|
|
4
|
+
*/
|
|
5
|
+
import { isEvalPermissionMode, type EvalFailureCode, type EvalPermissionMode } from "@inhuman.tools/harness-model";
|
|
6
|
+
|
|
7
|
+
export function resolveEvalPermissionMode(policy: string): EvalPermissionMode | null {
|
|
8
|
+
return isEvalPermissionMode(policy) ? policy : null;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function unattendedFailureText(code: EvalFailureCode, policyId: string, reason?: string): string {
|
|
12
|
+
switch (code) {
|
|
13
|
+
case "interaction_required":
|
|
14
|
+
return `Operation requires human authorization under policy ${policyId}`;
|
|
15
|
+
case "policy_denied":
|
|
16
|
+
return `Operation denied under policy ${policyId}`;
|
|
17
|
+
case "policy_error":
|
|
18
|
+
return reason != null && reason !== ""
|
|
19
|
+
? `Policy evaluation failed under policy ${policyId}: ${reason}`
|
|
20
|
+
: `Policy evaluation failed under policy ${policyId}`;
|
|
21
|
+
case "policy_unavailable":
|
|
22
|
+
return `Policy ${policyId} is not available`;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Write seam for blobs that leave the session document. The kernel's bucket
|
|
3
|
+
* belongs to the daemon; the places that stamp a large text (a file's prior,
|
|
4
|
+
* an isolated completion's prompt, the vacuum of a stored session) put through
|
|
5
|
+
* here and never import the store. Reads go the other way, through
|
|
6
|
+
* `readBlob` in harness-provider-sdk.
|
|
7
|
+
*/
|
|
8
|
+
import { blobHeadOf, exceedsInlineMax, storedBlobJson, type BlobRef } from "@inhuman.tools/harness-model";
|
|
9
|
+
|
|
10
|
+
/** Synchronous because the stamping paths are: admit mints a job in one tick. */
|
|
11
|
+
export type BlobWriter = (bytes: Uint8Array, mime: string) => BlobRef;
|
|
12
|
+
|
|
13
|
+
/** What a `FileMutateToolJob` takes for its prior text: the text itself, or the reference to it. */
|
|
14
|
+
export type PriorProps = { readonly priorContent: string } | { readonly priorBlobJson: string };
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* What {@link externalizeText} decided for a text. `inline` is the text itself. `blob` carries what the
|
|
18
|
+
* document keeps instead: the head for the text field, and the reference (a `StoredBlob` as JSON) for the
|
|
19
|
+
* `*BlobJson` field beside it.
|
|
20
|
+
*/
|
|
21
|
+
export type TextStamp =
|
|
22
|
+
| { readonly kind: "inline"; readonly text: string }
|
|
23
|
+
| { readonly kind: "blob"; readonly head: string; readonly blobJson: string };
|
|
24
|
+
|
|
25
|
+
const TEXT_MIME = "text/plain";
|
|
26
|
+
|
|
27
|
+
let writer: BlobWriter | null = null;
|
|
28
|
+
|
|
29
|
+
/** The host that owns the bucket binds it once at boot. `null` unbinds. */
|
|
30
|
+
export function bindBlobWriter(write: BlobWriter | null): void {
|
|
31
|
+
writer = write;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Puts bytes through the bound writer and returns the reference. Throws while no writer is bound and when the
|
|
36
|
+
* bucket refuses. For a path that has no inline fallback (the vacuum moves text that is already in the
|
|
37
|
+
* document; a refused put must stop it, not pass silently). The stamping paths use {@link externalizeText}.
|
|
38
|
+
*/
|
|
39
|
+
export function writeBlob(bytes: Uint8Array, mime: string): BlobRef {
|
|
40
|
+
if (writer === null) throw new Error("no blob writer is bound");
|
|
41
|
+
return writer(bytes, mime);
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* Text within the inline limit stays inline. Larger text goes to the bucket as UTF-8 and the document keeps the
|
|
46
|
+
* reference with the head that paint and stubs read. With no writer bound, or a bucket that refuses the write,
|
|
47
|
+
* the text stays inline as it always did: a text is never lost to a full disk.
|
|
48
|
+
*/
|
|
49
|
+
export function externalizeText(text: string, mime: string = TEXT_MIME): TextStamp {
|
|
50
|
+
if (writer === null || !exceedsInlineMax(text)) return { kind: "inline", text };
|
|
51
|
+
try {
|
|
52
|
+
const ref = writer(Buffer.from(text, "utf8"), mime);
|
|
53
|
+
const head = blobHeadOf(text);
|
|
54
|
+
return { kind: "blob", head, blobJson: storedBlobJson({ ...ref, head }) };
|
|
55
|
+
} catch {
|
|
56
|
+
return { kind: "inline", text };
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
/** {@link externalizeText} in the shape a `FileMutateToolJob` takes. */
|
|
61
|
+
export function externalizePrior(text: string): PriorProps {
|
|
62
|
+
const stamp = externalizeText(text);
|
|
63
|
+
return stamp.kind === "inline" ? { priorContent: stamp.text } : { priorBlobJson: stamp.blobJson };
|
|
64
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dispatch-time extra-root flag. Human allow / remainder grant / yolo
|
|
3
|
+
* shell is this spawn, not a file-read grant. Effect bodies read it;
|
|
4
|
+
* they do not set it.
|
|
5
|
+
*/
|
|
6
|
+
import { AsyncLocalStorage } from "node:async_hooks";
|
|
7
|
+
|
|
8
|
+
const extraRootAls = new AsyncLocalStorage<boolean>();
|
|
9
|
+
|
|
10
|
+
export function runWithExtraRoot<T>(allow: boolean, fn: () => T): T {
|
|
11
|
+
return extraRootAls.run(allow, fn);
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export function extraRootAllowed(): boolean {
|
|
15
|
+
return extraRootAls.getStore() === true;
|
|
16
|
+
}
|