@sema-agent/core 7.52.0 → 7.54.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/CHANGELOG.md +470 -0
- package/LICENSE +3 -1
- package/README.md +3 -1
- package/dist/agents/cross-session-envelope.d.ts +8 -0
- package/dist/agents/cross-session-envelope.js +6 -0
- package/dist/agents/cross-session-judge.d.ts +21 -1
- package/dist/agents/cross-session-judge.js +8 -0
- package/dist/agents/cross-session-ref.d.ts +5 -0
- package/dist/agents/cross-session-ref.js +1 -0
- package/dist/agents/org-delivery-gate.d.ts +122 -0
- package/dist/agents/org-delivery-gate.js +69 -0
- package/dist/agents/peer-held-queue.d.ts +9 -4
- package/dist/agents/peer-held-queue.js +6 -5
- package/dist/agents/peer-session-drain.d.ts +35 -6
- package/dist/agents/peer-session-drain.js +271 -182
- package/dist/agents/read-inbox-tool.d.ts +7 -0
- package/dist/agents/read-inbox-tool.js +5 -1
- package/dist/agents/send-message-tool.js +3 -4
- package/dist/agents/subagent.d.ts +6 -5
- package/dist/agents/subagent.js +117 -83
- package/dist/agents/tool-filter.d.ts +25 -4
- package/dist/agents/tool-filter.js +13 -3
- package/dist/brain/anthropic.d.ts +6 -1
- package/dist/brain/anthropic.js +4 -4
- package/dist/brain/model-presets.js +2 -1
- package/dist/brain/route-adjudicator.d.ts +6 -0
- package/dist/brain/routing.d.ts +24 -1
- package/dist/brain/routing.js +54 -19
- package/dist/brain/timeout.js +5 -4
- package/dist/core/a2a.d.ts +5 -2
- package/dist/core/a2a.js +33 -14
- package/dist/core/allow-entry.d.ts +3 -1
- package/dist/core/allow-entry.js +3 -2
- package/dist/core/approval-object.d.ts +87 -0
- package/dist/core/approval-object.js +85 -0
- package/dist/core/arg-summary.d.ts +3 -2
- package/dist/core/arg-summary.js +17 -11
- package/dist/core/ask-origin.d.ts +43 -27
- package/dist/core/ask-origin.js +20 -11
- package/dist/core/ask-question.d.ts +0 -1
- package/dist/core/ask-question.js +4 -67
- package/dist/core/ask-unresolvable-notice.d.ts +3 -2
- package/dist/core/auto-compaction.d.ts +106 -50
- package/dist/core/auto-compaction.js +69 -53
- package/dist/core/auto-mode-prompt.d.ts +4 -2
- package/dist/core/auto-mode-prompt.js +4 -3
- package/dist/core/canonical-json.d.ts +69 -0
- package/dist/core/canonical-json.js +130 -8
- package/dist/core/checkpoint-requirements.d.ts +13 -7
- package/dist/core/checkpoint-requirements.js +4 -1
- package/dist/core/checkpoint-store.d.ts +60 -36
- package/dist/core/checkpoint-store.js +7 -6
- package/dist/core/child-clamp-seats.d.ts +45 -6
- package/dist/core/child-clamp-seats.js +56 -4
- package/dist/core/compliance.js +3 -1
- package/dist/core/consolidate-scope.d.ts +1 -1
- package/dist/core/cross-boundary-taint.d.ts +213 -0
- package/dist/core/cross-boundary-taint.js +196 -0
- package/dist/core/decision-receipt.d.ts +44 -1
- package/dist/core/decision-receipt.js +16 -0
- package/dist/core/effective-path-target.d.ts +28 -6
- package/dist/core/effective-path-target.js +28 -2
- package/dist/core/engine-notice.d.ts +47 -4
- package/dist/core/engine-notice.js +17 -1
- package/dist/core/engine-storage-backend.d.ts +73 -0
- package/dist/core/engine-storage-backend.js +1 -0
- package/dist/core/file-history-store.d.ts +6 -2
- package/dist/core/file-history-store.js +1 -0
- package/dist/core/gate-fold.js +13 -4
- package/dist/core/gate-lanes.js +41 -34
- package/dist/core/gate-outcome.d.ts +18 -9
- package/dist/core/governance-codes.d.ts +9 -2
- package/dist/core/governance-codes.js +9 -0
- package/dist/core/hands-band-screen.d.ts +7 -0
- package/dist/core/hands-band-screen.js +32 -0
- package/dist/core/hooks.d.ts +21 -19
- package/dist/core/hooks.js +6 -5
- package/dist/core/locked-config.d.ts +110 -31
- package/dist/core/locked-config.js +155 -42
- package/dist/core/lsp.d.ts +1 -1
- package/dist/core/mcp-probe.js +1 -1
- package/dist/core/mcp-server-spec.d.ts +152 -17
- package/dist/core/mcp-server-spec.js +223 -40
- package/dist/core/mcp.d.ts +21 -14
- package/dist/core/mcp.js +59 -54
- package/dist/core/memory-engine/engine.d.ts +14 -19
- package/dist/core/memory-engine/engine.js +9 -6
- package/dist/core/memory-engine/export-bundle.d.ts +1 -1
- package/dist/core/memory-engine/export-bundle.js +1 -1
- package/dist/core/memory-engine/file-backend.d.ts +2 -6
- package/dist/core/memory-engine/file-backend.js +1 -12
- package/dist/core/memory.d.ts +3 -3
- package/dist/core/mode-policy.d.ts +16 -26
- package/dist/core/mode-policy.js +5 -18
- package/dist/core/mods/kernel/dispatch.js +13 -15
- package/dist/core/mods/kernel/events.d.ts +9 -6
- package/dist/core/mods/kernel/events.js +2 -2
- package/dist/core/mods/kernel/receive.d.ts +41 -11
- package/dist/core/mods/kernel/receive.js +124 -54
- package/dist/core/mods/kernel/site-rules.d.ts +80 -15
- package/dist/core/mods/kernel/site-rules.js +232 -40
- package/dist/core/mods/stations.d.ts +0 -6
- package/dist/core/mods/stations.js +0 -7
- package/dist/core/mounted-mcp.d.ts +57 -0
- package/dist/core/mounted-mcp.js +71 -2
- package/dist/core/own-property-receipt.d.ts +13 -0
- package/dist/core/own-property-receipt.js +3 -1
- package/dist/core/parent-spec-seat.d.ts +12 -15
- package/dist/core/parent-spec-seat.js +14 -6
- package/dist/core/pause-registry.d.ts +35 -1
- package/dist/core/pause-registry.js +10 -0
- package/dist/core/permission-rule-consent.d.ts +18 -5
- package/dist/core/permission-rule-consent.js +13 -8
- package/dist/core/permission-rule-model.d.ts +87 -15
- package/dist/core/permission-rule-model.js +87 -8
- package/dist/core/permission-rule-org.d.ts +200 -33
- package/dist/core/permission-rule-org.js +217 -91
- package/dist/core/permission-rule-session.js +2 -2
- package/dist/core/permission-rule-store.d.ts +8 -0
- package/dist/core/permission-rule-store.js +1 -0
- package/dist/core/permission-rule-sync.js +3 -2
- package/dist/core/permission-rules.d.ts +7 -1
- package/dist/core/permission-rules.js +37 -8
- package/dist/core/read-only-shell.d.ts +1 -1
- package/dist/core/read-only-shell.js +30 -9
- package/dist/core/remote-env.d.ts +41 -1
- package/dist/core/remote-env.js +18 -0
- package/dist/core/resume-startup-cause.d.ts +18 -0
- package/dist/core/resume-startup-cause.js +12 -0
- package/dist/core/retention.js +7 -2
- package/dist/core/retired-keys.d.ts +8 -2
- package/dist/core/retired-keys.js +12 -1
- package/dist/core/roles.js +60 -10
- package/dist/core/rule-lane-reads.js +1 -1
- package/dist/core/runner/approval-feedback.d.ts +46 -0
- package/dist/core/runner/approval-feedback.js +41 -0
- package/dist/core/runner/compaction-call-options.d.ts +3 -3
- package/dist/core/runner/compaction-call-options.js +2 -2
- package/dist/core/runner/contracts.d.ts +34 -41
- package/dist/core/runner/cross-boundary-lane.d.ts +87 -0
- package/dist/core/runner/cross-boundary-lane.js +190 -0
- package/dist/core/runner/decide-continuation.d.ts +4 -4
- package/dist/core/runner/decide-continuation.js +3 -1
- package/dist/core/runner/gate-exit.d.ts +32 -12
- package/dist/core/runner/gate-exit.js +77 -34
- package/dist/core/runner/inherited-ask-grants.js +2 -2
- package/dist/core/runner/mcp-redial.d.ts +52 -10
- package/dist/core/runner/mcp-redial.js +38 -9
- package/dist/core/runner/permission-rule-lanes.d.ts +5 -2
- package/dist/core/runner/permission-rule-lanes.js +22 -10
- package/dist/core/runner/person-path-rows.d.ts +5 -3
- package/dist/core/runner/person-path-rows.js +2 -2
- package/dist/core/runner/prepare-acquire-reconcile.d.ts +3 -4
- package/dist/core/runner/prepare-acquire-reconcile.js +3 -3
- package/dist/core/runner/prepare-ask-lane.js +3 -3
- package/dist/core/runner/prepare-caps-and-workflow.d.ts +6 -5
- package/dist/core/runner/prepare-caps-and-workflow.js +3 -3
- package/dist/core/runner/prepare-config-doors.d.ts +58 -15
- package/dist/core/runner/prepare-config-doors.js +167 -146
- package/dist/core/runner/prepare-context-lane.js +6 -3
- package/dist/core/runner/prepare-defer-classify.js +4 -7
- package/dist/core/runner/prepare-delegation-surface.d.ts +5 -4
- package/dist/core/runner/prepare-delegation-surface.js +8 -7
- package/dist/core/runner/prepare-execution-env.d.ts +1 -2
- package/dist/core/runner/prepare-execution-env.js +2 -1
- package/dist/core/runner/prepare-gate-stations.d.ts +2 -0
- package/dist/core/runner/prepare-gate-stations.js +4 -3
- package/dist/core/runner/prepare-hands-readface.d.ts +3 -3
- package/dist/core/runner/prepare-hands-readface.js +3 -2
- package/dist/core/runner/prepare-inherited-gate.d.ts +2 -0
- package/dist/core/runner/prepare-inherited-gate.js +3 -2
- package/dist/core/runner/prepare-listings.d.ts +1 -1
- package/dist/core/runner/prepare-listings.js +4 -2
- package/dist/core/runner/prepare-memory-engine-session.d.ts +0 -6
- package/dist/core/runner/prepare-memory-engine-session.js +19 -6
- package/dist/core/runner/prepare-memory.d.ts +3 -2
- package/dist/core/runner/prepare-memory.js +6 -2
- package/dist/core/runner/prepare-offload-wrappers.d.ts +4 -4
- package/dist/core/runner/prepare-offload-wrappers.js +2 -1
- package/dist/core/runner/prepare-park-ask.d.ts +1 -1
- package/dist/core/runner/prepare-park-ask.js +9 -3
- package/dist/core/runner/prepare-policy-chain.d.ts +1 -1
- package/dist/core/runner/prepare-policy-chain.js +14 -19
- package/dist/core/runner/prepare-project-context.d.ts +1 -1
- package/dist/core/runner/prepare-project-context.js +6 -4
- package/dist/core/runner/prepare-prompt-assembly.d.ts +1 -1
- package/dist/core/runner/prepare-prompt-assembly.js +20 -16
- package/dist/core/runner/prepare-prompt-inputs.d.ts +12 -6
- package/dist/core/runner/prepare-prompt-inputs.js +6 -3
- package/dist/core/runner/prepare-protocol-tools.d.ts +7 -5
- package/dist/core/runner/prepare-protocol-tools.js +19 -12
- package/dist/core/runner/prepare-question-face.d.ts +4 -2
- package/dist/core/runner/prepare-question-face.js +4 -3
- package/dist/core/runner/prepare-safety-scan.d.ts +7 -2
- package/dist/core/runner/prepare-safety-scan.js +34 -27
- package/dist/core/runner/prepare-suspend-saga.d.ts +2 -2
- package/dist/core/runner/prepare-suspend-saga.js +6 -2
- package/dist/core/runner/prepare-task.js +22 -19
- package/dist/core/runner/prepare-turn-wiring.d.ts +10 -5
- package/dist/core/runner/prepare-turn-wiring.js +14 -49
- package/dist/core/runner/prepare-wiring-manifest.d.ts +10 -5
- package/dist/core/runner/prepare-wiring-manifest.js +9 -6
- package/dist/core/runner/prepare-workspace-restore.js +2 -2
- package/dist/core/runner/resume-admission.d.ts +4 -1
- package/dist/core/runner/resume-admission.js +16 -14
- package/dist/core/runner/resume-apply.js +4 -4
- package/dist/core/runner/resume-internals-and-config.d.ts +3 -3
- package/dist/core/runner/resume-internals-and-config.js +3 -8
- package/dist/core/runner/resume-policy-outcome.d.ts +2 -2
- package/dist/core/runner/resume-policy-outcome.js +18 -15
- package/dist/core/runner/resume-preflight.js +2 -2
- package/dist/core/runner/resume-review-outcome.js +3 -3
- package/dist/core/runner/retired-runner-deps.d.ts +5 -6
- package/dist/core/runner/retired-runner-deps.js +1 -4
- package/dist/core/runner/run-leg.js +97 -43
- package/dist/core/runner/run-recovery-lanes.js +5 -3
- package/dist/core/runner/run-settle-and-teardown.js +2 -0
- package/dist/core/runner/run-terminal-adoption.js +21 -9
- package/dist/core/runner/run-turn-boundary.js +9 -3
- package/dist/core/runner/runtask.js +1 -1
- package/dist/core/runner/session-file-state-replay.d.ts +5 -2
- package/dist/core/runner/session-file-state-replay.js +3 -2
- package/dist/core/runner/skills-seat.d.ts +15 -0
- package/dist/core/runner/skills-seat.js +57 -0
- package/dist/core/runner/stream-steer-verb.js +2 -2
- package/dist/core/runner/sub-agent-deny-lists.d.ts +13 -11
- package/dist/core/runner/sub-agent-deny-lists.js +7 -5
- package/dist/core/runner/synthetic-tools.d.ts +5 -2
- package/dist/core/runner/synthetic-tools.js +2 -12
- package/dist/core/runner/tool-face-overlay.d.ts +24 -6
- package/dist/core/runner/tool-face-overlay.js +24 -15
- package/dist/core/runner-deps.d.ts +37 -22
- package/dist/core/session-policy-store.d.ts +19 -0
- package/dist/core/session-policy-store.js +22 -2
- package/dist/core/session-store.d.ts +35 -16
- package/dist/core/session-store.js +20 -12
- package/dist/core/{shell-lexer.d.ts → shell-run-candidates.d.ts} +36 -12
- package/dist/core/{shell-lexer.js → shell-run-candidates.js} +145 -225
- package/dist/core/shell-wrapper-table.d.ts +5 -3
- package/dist/core/shell-wrapper-table.js +1 -1
- package/dist/core/store-contracts/checkpoint-store-contract.js +2 -2
- package/dist/core/store-contracts/mailbox-store-contract.js +13 -0
- package/dist/core/store-contracts/session-store-contract.d.ts +49 -0
- package/dist/core/store-contracts/session-store-contract.js +639 -0
- package/dist/core/store-contracts/session-store-incarnation-contract.d.ts +12 -0
- package/dist/core/store-contracts/session-store-incarnation-contract.js +5 -2
- package/dist/core/task-event.d.ts +44 -6
- package/dist/core/task-notification.js +2 -2
- package/dist/core/task-registry-agent.js +1 -0
- package/dist/core/task-registry-shared.d.ts +5 -0
- package/dist/core/task-registry.d.ts +7 -0
- package/dist/core/task-registry.js +17 -0
- package/dist/core/task-result.d.ts +1 -1
- package/dist/core/task-spec.d.ts +7 -7
- package/dist/core/tighten-task-spec.d.ts +6 -4
- package/dist/core/tighten-task-spec.js +2 -2
- package/dist/core/tool-catalog-entries.d.ts +1 -1
- package/dist/core/tool-catalog-entries.js +52 -52
- package/dist/core/tool-face-reader.d.ts +49 -0
- package/dist/core/tool-face-reader.js +94 -0
- package/dist/core/tool-face.d.ts +17 -8
- package/dist/core/tool-face.js +1 -0
- package/dist/core/tool-policy.d.ts +67 -23
- package/dist/core/tool-policy.js +72 -60
- package/dist/core/tool-roster.d.ts +46 -28
- package/dist/core/tool-roster.js +91 -14
- package/dist/core/tool-spec-members.js +2 -2
- package/dist/core/tool-spec.d.ts +20 -4
- package/dist/core/tools.js +2 -0
- package/dist/core/trace.d.ts +24 -2
- package/dist/core/types.d.ts +3 -3
- package/dist/core/types.js +1 -1
- package/dist/core/untrusted-text.d.ts +23 -0
- package/dist/core/untrusted-text.js +10 -10
- package/dist/core/user-attachment.d.ts +56 -2
- package/dist/core/user-attachment.js +139 -56
- package/dist/core/wiring-manifest.d.ts +4 -2
- package/dist/engine/compaction/compaction.d.ts +2 -2
- package/dist/engine/compaction/utils.d.ts +2 -2
- package/dist/engine/harness/agent-harness.js +2 -1
- package/dist/engine/harness/types.d.ts +10 -4
- package/dist/engine/llm/types.d.ts +7 -2
- package/dist/engine/llm/types.js +2 -1
- package/dist/engine/loop/agent-loop.d.ts +12 -1
- package/dist/engine/loop/agent-loop.js +17 -5
- package/dist/engine/loop/types.d.ts +7 -1
- package/dist/engine/session/repo-utils.d.ts +5 -0
- package/dist/engine/session/repo-utils.js +9 -0
- package/dist/engine/session/storage-base.js +2 -2
- package/dist/index.d.ts +37 -17
- package/dist/index.js +31 -14
- package/dist/internal/harness.d.ts +1 -0
- package/dist/internal/harness.js +1 -0
- package/dist/internal/llm.d.ts +1 -1
- package/dist/internal/llm.js +1 -1
- package/dist/orchestration/goal.d.ts +24 -1
- package/dist/orchestration/goal.js +3 -2
- package/dist/orchestration/run-workflow-tool.d.ts +3 -0
- package/dist/orchestration/run-workflow-tool.js +1 -0
- package/dist/orchestration/workflow-governance.d.ts +1 -1
- package/dist/orchestration/workflow.d.ts +3 -0
- package/dist/orchestration/workflow.js +2 -1
- package/dist/prompt-assembly/artifact-store.d.ts +44 -9
- package/dist/prompt-assembly/artifact-store.js +38 -12
- package/dist/prompt-assembly/artifact.d.ts +12 -11
- package/dist/prompt-assembly/artifact.js +52 -21
- package/dist/prompt-assembly/assemble.d.ts +2 -0
- package/dist/prompt-assembly/assemble.js +2 -1
- package/dist/prompt-assembly/catalog/index.js +2 -1
- package/dist/prompt-assembly/catalog/memory.d.ts +13 -0
- package/dist/prompt-assembly/catalog/memory.js +6 -0
- package/dist/prompt-assembly/catalog/schema.d.ts +19 -2
- package/dist/prompt-assembly/catalog/schema.js +3 -0
- package/dist/prompt-assembly/composer.d.ts +2 -0
- package/dist/prompt-assembly/composer.js +1 -1
- package/dist/prompt-assembly/overlay.d.ts +21 -11
- package/dist/prompt-assembly/overlay.js +57 -19
- package/dist/prompt-assembly/select.d.ts +21 -6
- package/dist/prompt-assembly/select.js +41 -4
- package/dist/prompts/default.d.ts +1 -12
- package/dist/prompts/default.js +0 -3
- package/dist/shell/lex.d.ts +87 -8
- package/dist/shell/lex.js +283 -49
- package/dist/stores/file/index.d.ts +8 -6
- package/dist/stores/file/permission-rule-store.d.ts +1 -1
- package/dist/stores/file/permission-rule-store.js +2 -1
- package/dist/tools/artifact/artifact-tool.js +14 -3
- package/dist/tools/fs/bash-program-position.d.ts +3 -15
- package/dist/tools/fs/bash-program-position.js +3 -10
- package/dist/tools/fs/bash-readonly-classifier.js +2 -0
- package/dist/tools/fs/fs-bash.d.ts +3 -3
- package/dist/tools/fs/fs-bash.js +72 -101
- package/dist/tools/fs/fs-read.d.ts +12 -0
- package/dist/tools/fs/fs-read.js +10 -9
- package/dist/tools/fs/fs-shared.d.ts +27 -31
- package/dist/tools/fs/fs-shared.js +12 -15
- package/dist/tools/fs/fs-write.js +1 -1
- package/dist/tools/fs/index.js +2 -2
- package/dist/tools/fs/read-deny-home.d.ts +1 -1
- package/dist/tools/fs/read-deny-home.js +5 -4
- package/dist/tools/fs/read-deny.d.ts +16 -3
- package/dist/tools/fs/read-deny.js +12 -9
- package/dist/tools/fs/safety.d.ts +7 -6
- package/dist/tools/fs/shell-read-bindings.d.ts +5 -3
- package/dist/tools/fs/shell-read-bindings.js +15 -16
- package/dist/tools/fs/shell-read-device.js +1 -1
- package/dist/tools/fs/shell-read-plan.js +36 -47
- package/dist/tools/fs/shell-read-word.d.ts +1 -6
- package/dist/tools/fs/shell-read-word.js +2 -20
- package/dist/tools/fs/shell-reentry-text.js +1 -1
- package/dist/tools/web.d.ts +2 -2
- package/package.json +4 -1
- package/test/export-surface.snapshot.json +5651 -5457
- package/wire-changes/core@7.53.0.json +1968 -0
- package/wire-changes/core@7.54.0.json +2870 -0
- package/dist/core/shell-scan.d.ts +0 -60
- package/dist/core/shell-scan.js +0 -183
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createHash } from "node:crypto";
|
|
2
2
|
import { canonicalize, UNCANONICALIZABLE } from "../core/canonical-json.js";
|
|
3
|
+
import { SPAWNER_SURFACE_LEG_KINDS } from "../core/tool-face.js";
|
|
3
4
|
import { ruleSpellingOf } from "../core/permission-rule-syntax.js";
|
|
4
5
|
import { TOOL_CATALOG_ENTRIES } from "../core/tool-catalog-entries.js";
|
|
5
6
|
import { isNamespacedCoveringRuleName, namespacedRuleNameCovers } from "../core/namespaced-rule-name.js";
|
|
@@ -118,7 +119,10 @@ export function listReaches(reach, tool) {
|
|
|
118
119
|
}
|
|
119
120
|
return false;
|
|
120
121
|
}
|
|
121
|
-
const PROTOCOL_ROWS = Object.freeze(TOOL_CATALOG_ENTRIES.flatMap((e) => (e.protocol !== undefined ? [Object.freeze({ name: e.name, legs: e.protocol
|
|
122
|
+
const PROTOCOL_ROWS = Object.freeze(TOOL_CATALOG_ENTRIES.flatMap((e) => (e.protocol !== undefined ? [Object.freeze({ name: e.name, legs: e.protocol })] : [])));
|
|
123
|
+
export function protocolRowUnderCeiling(rowLegs) {
|
|
124
|
+
return rowLegs.some((l) => SPAWNER_SURFACE_LEG_KINDS.includes(l));
|
|
125
|
+
}
|
|
122
126
|
export function protocolToolNames(legs) {
|
|
123
127
|
return [...new Set(PROTOCOL_ROWS.filter((r) => r.legs.some((l) => legs.includes(l))).map((r) => r.name))];
|
|
124
128
|
}
|
|
@@ -147,7 +151,7 @@ export function compileToolSelector(layers, legs = []) {
|
|
|
147
151
|
const kept = Object.freeze([...layers]);
|
|
148
152
|
const compiled = kept.map((l) => (isToolSelectorLayer(l) ? { allow: readAllowedToolList(l.allow), deny: readDeniedToolList(l.deny) } : NO_TOOL_LAYER));
|
|
149
153
|
const admittedBy = (ls, tool) => ls.every((l) => (l.allow === undefined || listReaches(l.allow, tool)) && !listReaches(l.deny, tool));
|
|
150
|
-
const protocol = new Map(PROTOCOL_ROWS.filter((r) => r.legs.some((l) => legs.includes(l))).map((r) => [r.name, r.
|
|
154
|
+
const protocol = new Map(PROTOCOL_ROWS.filter((r) => r.legs.some((l) => legs.includes(l))).map((r) => [r.name, protocolRowUnderCeiling(r.legs)]));
|
|
151
155
|
return Object.freeze({
|
|
152
156
|
layers: kept,
|
|
153
157
|
admits: (tool) => {
|
|
@@ -167,6 +171,12 @@ export function compileToolSelector(layers, legs = []) {
|
|
|
167
171
|
},
|
|
168
172
|
});
|
|
169
173
|
}
|
|
174
|
+
export function valveLeaves(spec, selector) {
|
|
175
|
+
return spec.excludeAllTools === true ? () => false : (tool) => selector.admits(tool);
|
|
176
|
+
}
|
|
177
|
+
export function valveLeavesPeer(spec, selector) {
|
|
178
|
+
return spec.excludeAllTools === true ? () => false : (prefix) => selector.admitsPeer(prefix);
|
|
179
|
+
}
|
|
170
180
|
export function deniedProtocolTools(layers, legs) {
|
|
171
181
|
const denies = layers.map((l) => readDeniedToolList(isToolSelectorLayer(l) ? l.deny : undefined));
|
|
172
182
|
const own = denies.slice(-1);
|
|
@@ -176,7 +186,7 @@ export function deniedProtocolTools(layers, legs) {
|
|
|
176
186
|
const reached = (ds) => ds.some((d) => listReaches(d, { name: r.name }));
|
|
177
187
|
if (reached(own))
|
|
178
188
|
hits.set(`own:${r.name}`, { name: r.name, own: true });
|
|
179
|
-
if (!r.
|
|
189
|
+
if (!protocolRowUnderCeiling(r.legs) && reached(inherited))
|
|
180
190
|
hits.set(`inherited:${r.name}`, { name: r.name, own: false });
|
|
181
191
|
}
|
|
182
192
|
return [...hits.values()];
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Brain } from "../core/types.js";
|
|
2
2
|
import { type StreamEngineConfig } from "./stream-engine.js";
|
|
3
3
|
export interface AnthropicBrainConfig extends StreamEngineConfig {
|
|
4
|
-
/** Base URL of the Anthropic(-compatible) API. Default
|
|
4
|
+
/** Base URL of the Anthropic(-compatible) API. Default {@link ANTHROPIC_DEFAULT_BASE_URL}. Overridden by model.baseUrl. */
|
|
5
5
|
baseUrl?: string;
|
|
6
6
|
/** API key (`x-api-key`). Overridden by per-call options.apiKey / getApiKeyAndHeaders. */
|
|
7
7
|
apiKey?: string;
|
|
@@ -35,6 +35,11 @@ export interface AnthropicBrainConfig extends StreamEngineConfig {
|
|
|
35
35
|
*/
|
|
36
36
|
thinkingBudgetTokens?: number;
|
|
37
37
|
}
|
|
38
|
+
/** This lane's own default endpoint: where a request goes when neither the entry nor the config names a root,
|
|
39
|
+
* and so the root a key on the config is paired with when the config declares none. Exported so that every place that
|
|
40
|
+
* names the Anthropic API's own root — the {@link fable5Model} preset, a host's disclosure of where a default request
|
|
41
|
+
* lands — reads this one spelling. */
|
|
42
|
+
export declare const ANTHROPIC_DEFAULT_BASE_URL = "https://api.anthropic.com";
|
|
38
43
|
/**
|
|
39
44
|
* Create a Brain for the Anthropic Messages API (`/v1/messages`) with **prompt caching** and
|
|
40
45
|
* **extended-thinking replay**. Translates the unified Context into an Anthropic request and the
|
package/dist/brain/anthropic.js
CHANGED
|
@@ -226,7 +226,7 @@ function closeToolUseBlock(acc, responseIds, closed) {
|
|
|
226
226
|
acc.closedTc = { type: "toolCall", id: engineId, ...(wireId !== engineId ? { wireId } : {}), name: acc.toolName, arguments: args };
|
|
227
227
|
return acc.closedTc;
|
|
228
228
|
}
|
|
229
|
-
const
|
|
229
|
+
export const ANTHROPIC_DEFAULT_BASE_URL = "https://api.anthropic.com";
|
|
230
230
|
const ANTHROPIC_KEY_HEADER = "x-api-key";
|
|
231
231
|
export function createAnthropicBrain(given = {}) {
|
|
232
232
|
const config = brainConfigSnapshot(given, "createAnthropicBrain config");
|
|
@@ -248,7 +248,7 @@ export function createAnthropicBrain(given = {}) {
|
|
|
248
248
|
stallTimeouts: options?.stallTimeouts,
|
|
249
249
|
buildRequest: (overrides) => {
|
|
250
250
|
const routed = { id: model.id, baseUrl: model.baseUrl };
|
|
251
|
-
const { root, origin: rootOrigin } = resolveRequestRootOf(routed.baseUrl, config.baseUrl,
|
|
251
|
+
const { root, origin: rootOrigin } = resolveRequestRootOf(routed.baseUrl, config.baseUrl, ANTHROPIC_DEFAULT_BASE_URL);
|
|
252
252
|
const modelHeaders = headerBagOnce(model.headers);
|
|
253
253
|
const optionsHeaders = headerBagOnce(options?.headers);
|
|
254
254
|
const routeCredential = resolveRouteCredential({
|
|
@@ -259,7 +259,7 @@ export function createAnthropicBrain(given = {}) {
|
|
|
259
259
|
configHeaders: config.headers,
|
|
260
260
|
keyHeader: ANTHROPIC_KEY_HEADER,
|
|
261
261
|
});
|
|
262
|
-
const routeAdmission = admitRouteRequest(routed, routeCredential, { baseUrl: config.baseUrl, laneDefault:
|
|
262
|
+
const routeAdmission = admitRouteRequest(routed, routeCredential, { baseUrl: config.baseUrl, laneDefault: ANTHROPIC_DEFAULT_BASE_URL });
|
|
263
263
|
const apiKey = routeCredential.apiKey;
|
|
264
264
|
const nonEmptyBlocks = context.systemBlocks?.filter((b) => b.text.length > 0);
|
|
265
265
|
const system = nonEmptyBlocks?.length
|
|
@@ -772,5 +772,5 @@ export function createAnthropicBrain(given = {}) {
|
|
|
772
772
|
},
|
|
773
773
|
});
|
|
774
774
|
};
|
|
775
|
-
return { stream, adjudicateRoute: createBrainRouteJudge({ ...config, laneDefault:
|
|
775
|
+
return { stream, adjudicateRoute: createBrainRouteJudge({ ...config, laneDefault: ANTHROPIC_DEFAULT_BASE_URL, keyHeader: ANTHROPIC_KEY_HEADER }) };
|
|
776
776
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { catalogText } from "../prompt-assembly/catalog/index.js";
|
|
2
|
+
import { ANTHROPIC_DEFAULT_BASE_URL } from "./anthropic.js";
|
|
2
3
|
export const FABLE_5_COMPAT = {
|
|
3
4
|
thinkingMode: "adaptive",
|
|
4
5
|
effortLevels: ["low", "medium", "high", "xhigh", "max"],
|
|
@@ -15,7 +16,7 @@ export function fable5Model(overrides = {}) {
|
|
|
15
16
|
name: "Claude Fable 5",
|
|
16
17
|
api: "anthropic-messages",
|
|
17
18
|
provider: "anthropic",
|
|
18
|
-
baseUrl:
|
|
19
|
+
baseUrl: ANTHROPIC_DEFAULT_BASE_URL,
|
|
19
20
|
reasoning: true,
|
|
20
21
|
defaultThinking: "high",
|
|
21
22
|
input: ["text", "image"],
|
|
@@ -218,6 +218,12 @@ export declare function routeRefusalError(verdict: Extract<RouteAdjudication, {
|
|
|
218
218
|
* nothing. A credential is bound to the origin it was first SENT to, never to one it was only judged for. The request's
|
|
219
219
|
* halves (the entry's id and root, the brain's root and lane default) are read ONCE, here: both judgments and the binding
|
|
220
220
|
* are of the request this build is sending, whatever the caller's objects say by the time it is committed.
|
|
221
|
+
*
|
|
222
|
+
* Exported from the package root for a HOST that sends a request itself (its own `fetch`, outside a first-party brain): it
|
|
223
|
+
* passes this same gate, so the binding does not depend on who sends first. Resolve the credential with
|
|
224
|
+
* {@link resolveRouteCredential} (a credential built by hand carries no identity: it is judged and binds nothing), call this
|
|
225
|
+
* before building, and run the admission it returns immediately before the request goes out; a refusal is the very error a
|
|
226
|
+
* first-party brain throws for the same request. {@link adjudicateModelRoute} stays the read: it judges and binds nothing.
|
|
221
227
|
*/
|
|
222
228
|
export declare function admitRouteRequest(model: Pick<Model, "id" | "baseUrl">, credential: RouteCredential, config: RoutePairingConfig): () => void;
|
|
223
229
|
/**
|
package/dist/brain/routing.d.ts
CHANGED
|
@@ -5,9 +5,31 @@ export interface RoutingBrainOptions {
|
|
|
5
5
|
/** Brain used when no route matches. If omitted, an unmatched model yields an error. */
|
|
6
6
|
fallback?: Brain;
|
|
7
7
|
}
|
|
8
|
+
/** The two `Model` fields a route can be named by — a catalog entry that carries only a provider word is as good a subject as a whole `Model`. */
|
|
9
|
+
type RouteWords = {
|
|
10
|
+
readonly provider?: string | undefined;
|
|
11
|
+
readonly api?: string | undefined;
|
|
12
|
+
};
|
|
13
|
+
/**
|
|
14
|
+
* THE judge of which line serves a model: the model's route word (`provider`, or `api` when `by` says so) IF the route table
|
|
15
|
+
* has an OWN route under that word, else `undefined` — the fallback (the deployment's gateway) serves it. A word the model
|
|
16
|
+
* carries without a route, and a model with no string word at all, both answer `undefined`: a route that is not mounted is
|
|
17
|
+
* not a line, whatever the model says.
|
|
18
|
+
*
|
|
19
|
+
* `routes` is the route TABLE itself — the very object a host hands {@link createRoutingBrain}, which asks this function for
|
|
20
|
+
* every request — so the judge and the router answer from one reading of one table, whatever its shape. The question is
|
|
21
|
+
* `Object.hasOwn(routes, word)`: it evaluates no entry and lists no keys, so a non-enumerable own route is a route, a lazily
|
|
22
|
+
* keyed table is asked about the one name it is asked about, and a name the table only inherits (`constructor`, `__proto__`)
|
|
23
|
+
* is not a route. The judge never reads a route's value: a route mounted under the word IS the line, and when its value is not
|
|
24
|
+
* a brain the router fails that request on that line (an error terminal naming the route) rather than moving it to the
|
|
25
|
+
* fallback — so the line this answers is the line the request was sent to, either way. A table that cannot answer the question
|
|
26
|
+
* (it is not an object, or its trap throws) throws here, and the router fails the request with an error terminal.
|
|
27
|
+
*/
|
|
28
|
+
export declare function brainLaneOf(model: RouteWords, routes: Readonly<Record<string, unknown>>, by?: NonNullable<RoutingBrainOptions["by"]>): string | undefined;
|
|
8
29
|
/**
|
|
9
30
|
* Route to different brains by a Model field (default `model.provider`). Lets one Runner serve
|
|
10
|
-
* multiple providers/gateways; compose with `createFailoverBrain` for per-route failover.
|
|
31
|
+
* multiple providers/gateways; compose with `createFailoverBrain` for per-route failover. Which route serves a
|
|
32
|
+
* model is {@link brainLaneOf}'s answer.
|
|
11
33
|
*
|
|
12
34
|
* @example
|
|
13
35
|
* createRoutingBrain({
|
|
@@ -16,3 +38,4 @@ export interface RoutingBrainOptions {
|
|
|
16
38
|
* }, { fallback: createOpenAIBrain({ baseUrl: VLLM }) });
|
|
17
39
|
*/
|
|
18
40
|
export declare function createRoutingBrain(routes: Record<string, Brain>, opts?: RoutingBrainOptions): Brain;
|
|
41
|
+
export {};
|
package/dist/brain/routing.js
CHANGED
|
@@ -1,42 +1,77 @@
|
|
|
1
1
|
import { createAssistantMessageEventStream, } from "../internal/llm.js";
|
|
2
2
|
import { ZERO_USAGE } from "./errors.js";
|
|
3
|
-
function errorMessage(
|
|
3
|
+
function errorMessage(who, text) {
|
|
4
4
|
return {
|
|
5
5
|
role: "assistant",
|
|
6
6
|
content: [{ type: "text", text: "" }],
|
|
7
|
-
api:
|
|
8
|
-
provider:
|
|
9
|
-
model:
|
|
7
|
+
api: who.api,
|
|
8
|
+
provider: who.provider,
|
|
9
|
+
model: who.id,
|
|
10
10
|
stopReason: "error",
|
|
11
11
|
errorMessage: text,
|
|
12
12
|
usage: ZERO_USAGE,
|
|
13
13
|
timestamp: Date.now(),
|
|
14
14
|
};
|
|
15
15
|
}
|
|
16
|
+
const BLANK_IDENTITY = { api: "", provider: "", id: "" };
|
|
17
|
+
function spelled(word) {
|
|
18
|
+
return (typeof word === "object" && word !== null) || typeof word === "function" ? `[${typeof word}]` : String(word);
|
|
19
|
+
}
|
|
20
|
+
function routeKeyOf(model, by) {
|
|
21
|
+
return by === "api" ? model.api : model.provider;
|
|
22
|
+
}
|
|
23
|
+
function isBrain(value) {
|
|
24
|
+
return value !== null && typeof value === "object" && typeof value.stream === "function";
|
|
25
|
+
}
|
|
26
|
+
export function brainLaneOf(model, routes, by = "provider") {
|
|
27
|
+
const word = routeKeyOf(model, by);
|
|
28
|
+
return typeof word === "string" && Object.hasOwn(routes, word) ? word : undefined;
|
|
29
|
+
}
|
|
16
30
|
export function createRoutingBrain(routes, opts = {}) {
|
|
17
31
|
const by = opts.by ?? "provider";
|
|
18
32
|
const resolveTarget = (model) => {
|
|
19
|
-
const
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
return matched ?? opts.fallback;
|
|
33
|
+
const lane = brainLaneOf(model, routes, by);
|
|
34
|
+
if (lane === undefined)
|
|
35
|
+
return { target: opts.fallback };
|
|
36
|
+
const routed = routes[lane];
|
|
37
|
+
return isBrain(routed) ? { target: routed } : { broken: `route ${by}="${lane}" is mounted but its value is not a brain` };
|
|
25
38
|
};
|
|
26
39
|
const stream = (model, context, options) => {
|
|
27
|
-
const
|
|
28
|
-
const target = resolveTarget(model);
|
|
29
|
-
if (!target) {
|
|
40
|
+
const reject = (text, named) => {
|
|
30
41
|
const out = createAssistantMessageEventStream();
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
reason: "error",
|
|
34
|
-
|
|
35
|
-
|
|
42
|
+
try {
|
|
43
|
+
const wordOf = (field) => (field === by && named !== undefined ? named.value : model[field]);
|
|
44
|
+
out.push({ type: "error", reason: "error", error: errorMessage({ api: wordOf("api"), provider: wordOf("provider"), id: wordOf("id") }, text) });
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
out.push({ type: "error", reason: "error", error: errorMessage(BLANK_IDENTITY, `${text} (the model's own words could not be read either)`) });
|
|
48
|
+
}
|
|
36
49
|
return out;
|
|
50
|
+
};
|
|
51
|
+
let word;
|
|
52
|
+
try {
|
|
53
|
+
word = { value: routeKeyOf(model, by) };
|
|
37
54
|
}
|
|
55
|
+
catch {
|
|
56
|
+
return reject(`createRoutingBrain: the model's ${by} could not be read`);
|
|
57
|
+
}
|
|
58
|
+
const named = word.value;
|
|
59
|
+
const asked = { api: named, provider: named };
|
|
60
|
+
let resolved;
|
|
61
|
+
try {
|
|
62
|
+
resolved = resolveTarget(asked);
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return reject(`createRoutingBrain: the route table threw while ${by}="${spelled(named)}" was looked up`, word);
|
|
66
|
+
}
|
|
67
|
+
const target = "target" in resolved ? resolved.target : undefined;
|
|
68
|
+
if (!target)
|
|
69
|
+
return reject("broken" in resolved ? `createRoutingBrain: ${resolved.broken}` : `createRoutingBrain: no brain for ${by}="${spelled(named)}"`, word);
|
|
38
70
|
return target.stream(model, context, options);
|
|
39
71
|
};
|
|
40
|
-
const adjudicateRoute = (model, perModelAuth) =>
|
|
72
|
+
const adjudicateRoute = (model, perModelAuth) => {
|
|
73
|
+
const resolved = resolveTarget(model);
|
|
74
|
+
return "target" in resolved ? resolved.target?.adjudicateRoute?.(model, perModelAuth) : undefined;
|
|
75
|
+
};
|
|
41
76
|
return { stream, adjudicateRoute };
|
|
42
77
|
}
|
package/dist/brain/timeout.js
CHANGED
|
@@ -1,14 +1,15 @@
|
|
|
1
|
+
import { describeRejectedValue } from "../core/tool-search-setting.js";
|
|
1
2
|
export const MAX_TIMER_DELAY_MS = 2_147_483_647;
|
|
2
3
|
export function resolveStallTimeoutMs(value, knob) {
|
|
3
4
|
if (value === undefined)
|
|
4
5
|
return undefined;
|
|
5
6
|
if (!Number.isFinite(value) || value < 0) {
|
|
6
|
-
const e = new Error(`${knob} must be a non-negative finite number of milliseconds (got ${
|
|
7
|
+
const e = new Error(`${knob} must be a non-negative finite number of milliseconds (got ${describeRejectedValue(value)})`);
|
|
7
8
|
e.code = "config.stall_timeout_invalid";
|
|
8
9
|
throw e;
|
|
9
10
|
}
|
|
10
11
|
if (value > MAX_TIMER_DELAY_MS) {
|
|
11
|
-
const e = new Error(`${knob} must not exceed ${MAX_TIMER_DELAY_MS}ms (~24.8 days) — a host timer truncates a larger delay and fires immediately, so this watchdog would abort every call instead of tolerating a long one (got ${
|
|
12
|
+
const e = new Error(`${knob} must not exceed ${MAX_TIMER_DELAY_MS}ms (~24.8 days) — a host timer truncates a larger delay and fires immediately, so this watchdog would abort every call instead of tolerating a long one (got ${describeRejectedValue(value)}). Pass 0 to disable it.`);
|
|
12
13
|
e.code = "config.stall_timeout_invalid";
|
|
13
14
|
throw e;
|
|
14
15
|
}
|
|
@@ -112,12 +113,12 @@ export function resolveBrainCallGuardrailMs(knob) {
|
|
|
112
113
|
if (knob === false || knob === 0)
|
|
113
114
|
return undefined;
|
|
114
115
|
if (typeof knob !== "number" || !Number.isFinite(knob) || knob < 0) {
|
|
115
|
-
const e = new Error(`brainCallGuardrailMs must be a positive number of milliseconds, 0, or false (got ${
|
|
116
|
+
const e = new Error(`brainCallGuardrailMs must be a positive number of milliseconds, 0, or false (got ${describeRejectedValue(knob)})`);
|
|
116
117
|
e.code = "config.brain_call_guardrail_invalid";
|
|
117
118
|
throw e;
|
|
118
119
|
}
|
|
119
120
|
if (knob > MAX_TIMER_DELAY_MS) {
|
|
120
|
-
const e = new Error(`brainCallGuardrailMs must not exceed ${MAX_TIMER_DELAY_MS}ms (~24.8 days) — a host timer truncates a larger delay and fires immediately, so the backstop would abort every model call (got ${
|
|
121
|
+
const e = new Error(`brainCallGuardrailMs must not exceed ${MAX_TIMER_DELAY_MS}ms (~24.8 days) — a host timer truncates a larger delay and fires immediately, so the backstop would abort every model call (got ${describeRejectedValue(knob)}). Pass false or 0 to turn the backstop off.`);
|
|
121
122
|
e.code = "config.brain_call_guardrail_invalid";
|
|
122
123
|
throw e;
|
|
123
124
|
}
|
package/dist/core/a2a.d.ts
CHANGED
|
@@ -69,8 +69,11 @@ export interface MaterializedA2a {
|
|
|
69
69
|
/** One entry per DECLARED peer, in declaration order, ready or failed — the declaration as this materialization read it once. */
|
|
70
70
|
statuses: A2aPeerStatus[];
|
|
71
71
|
/** Re-read one peer's card (or every declared peer) and re-derive its tools. Unlike the MCP refresh
|
|
72
|
-
* this dials nothing new — every A2A call is a fresh request anyway — so a peer
|
|
73
|
-
* prepare time can genuinely recover here.
|
|
72
|
+
* this dials nothing new — every A2A call is a fresh request anyway — so a peer whose card or network
|
|
73
|
+
* failed at prepare time can genuinely recover here. The DECLARATION is not re-read: a refresh works
|
|
74
|
+
* from the copy this materialization took and judged — the members too (`headers`, `allowSkills`,
|
|
75
|
+
* `toolAxes` are copied, not shared) — so a declaration refused then is refused again and a caller
|
|
76
|
+
* rewriting its object afterwards, by replacing a member or by editing one in place, changes nothing. */
|
|
74
77
|
refresh: (peer?: string) => Promise<A2aRefreshResult[]>;
|
|
75
78
|
/**
|
|
76
79
|
* Task teardown. There is no socket to close (every call is its own request), so what this owns is the
|
package/dist/core/a2a.js
CHANGED
|
@@ -5,8 +5,10 @@ import { assertEndpointBound, redirectPolicy, resolveProtocolHttpHeaders, underD
|
|
|
5
5
|
import { describeHttpTransportFailure } from "./mcp-failure.js";
|
|
6
6
|
import { findNamespacePrefixCollision, mintNamespacePrefix, mintNamespacedToolName } from "./protocol-naming.js";
|
|
7
7
|
import { A2A_NAMESPACE } from "./protocol-table.js";
|
|
8
|
+
import { judgeEntryToolAxes, refusedDeclarer, snapshotDeclaredEntry } from "./locked-config.js";
|
|
8
9
|
import { delimitUntrusted, inlineUntrusted } from "./untrusted-text.js";
|
|
9
10
|
import { thrownText } from "./thrown-value.js";
|
|
11
|
+
import { boundaryFlowFace } from "./cross-boundary-taint.js";
|
|
10
12
|
const A2A_REQUEST_TIMEOUT_MS = 30_000;
|
|
11
13
|
const A2A_CARD_TIMEOUT_MS = 10_000;
|
|
12
14
|
const A2A_CALL_TOTAL_TIMEOUT_MS = 10 * 60_000;
|
|
@@ -540,25 +542,40 @@ function buildSkillTool(spec, t, skill, lifecycle) {
|
|
|
540
542
|
},
|
|
541
543
|
};
|
|
542
544
|
}
|
|
543
|
-
|
|
544
|
-
|
|
545
|
+
function declaredPeerOf(declared, index) {
|
|
546
|
+
let snapshot;
|
|
547
|
+
try {
|
|
548
|
+
snapshot = snapshotDeclaredEntry(declared, "a2a");
|
|
549
|
+
}
|
|
550
|
+
catch (err) {
|
|
551
|
+
return { spec: { name: refusedDeclarer(err) ?? `(peer #${index + 1}, name unreadable)` }, refusal: err };
|
|
552
|
+
}
|
|
553
|
+
const judged = judgeEntryToolAxes(snapshot, "a2a");
|
|
554
|
+
return judged.ok ? { spec: judged.entry } : { spec: snapshot, refusal: judged.error };
|
|
555
|
+
}
|
|
556
|
+
async function materializePeer(peer, principal, lifecycle, signal) {
|
|
557
|
+
if ("refusal" in peer)
|
|
558
|
+
throw peer.refusal;
|
|
559
|
+
const { spec } = peer;
|
|
560
|
+
const declaredAxes = spec.toolAxes;
|
|
545
561
|
const headers = resolveProtocolHttpHeaders(A2A_NAMESPACE.id, spec, principal);
|
|
546
562
|
const discovery = { peer: spec.name, endpoint: spec.url, headers };
|
|
547
563
|
const card = readCard(spec.name, await discoverCardBody(spec, discovery, signal), spec.url);
|
|
548
564
|
assertEndpointBound(A2A_NAMESPACE.id, spec.name, card.endpoint, spec.cardUrl === undefined ? [spec.url] : [spec.url, spec.cardUrl], headers);
|
|
549
565
|
const transport = { peer: spec.name, endpoint: card.endpoint, headers };
|
|
550
566
|
const tools = [];
|
|
551
|
-
const
|
|
567
|
+
const skillAxes = [];
|
|
552
568
|
for (const skill of card.skills) {
|
|
553
569
|
if (spec.allowSkills !== undefined && !spec.allowSkills.includes(skill.id))
|
|
554
570
|
continue;
|
|
555
|
-
const
|
|
571
|
+
const declared = declaredAxes?.[skill.id];
|
|
572
|
+
const tool = { ...buildSkillTool(spec, transport, skill, lifecycle), ...boundaryFlowFace(declared) };
|
|
556
573
|
tools.push(tool);
|
|
557
|
-
|
|
574
|
+
skillAxes.push(a2aAxisFor(tool.name, declared));
|
|
558
575
|
}
|
|
559
576
|
return {
|
|
560
577
|
tools,
|
|
561
|
-
axes,
|
|
578
|
+
axes: skillAxes,
|
|
562
579
|
status: {
|
|
563
580
|
name: spec.name,
|
|
564
581
|
status: "ready",
|
|
@@ -576,8 +593,9 @@ function asPeerWarning(spec, err) {
|
|
|
576
593
|
return warning;
|
|
577
594
|
}
|
|
578
595
|
export async function materializeA2aTools(specs, principal, signal) {
|
|
579
|
-
|
|
580
|
-
|
|
596
|
+
const peers = specs.map((spec, index) => declaredPeerOf(spec, index));
|
|
597
|
+
if (peers.length > 0) {
|
|
598
|
+
const collision = findNamespacePrefixCollision(A2A_NAMESPACE, peers.map((p) => p.spec.name));
|
|
581
599
|
if (collision) {
|
|
582
600
|
const [a, b] = collision.peers;
|
|
583
601
|
const e = new Error(a === b
|
|
@@ -592,9 +610,9 @@ export async function materializeA2aTools(specs, principal, signal) {
|
|
|
592
610
|
const toolAxes = [];
|
|
593
611
|
const warnings = [];
|
|
594
612
|
const statuses = [];
|
|
595
|
-
const settled = await Promise.allSettled(
|
|
596
|
-
for (let i = 0; i <
|
|
597
|
-
const spec =
|
|
613
|
+
const settled = await Promise.allSettled(peers.map((peer) => materializePeer(peer, principal, lifecycle, signal)));
|
|
614
|
+
for (let i = 0; i < peers.length; i++) {
|
|
615
|
+
const spec = peers[i].spec;
|
|
598
616
|
const outcome = settled[i];
|
|
599
617
|
if (outcome.status === "fulfilled") {
|
|
600
618
|
tools.push(...outcome.value.tools);
|
|
@@ -613,12 +631,13 @@ export async function materializeA2aTools(specs, principal, signal) {
|
|
|
613
631
|
statuses,
|
|
614
632
|
refresh: async (peer) => {
|
|
615
633
|
const prefixOf = (name) => mintNamespacePrefix(A2A_NAMESPACE, name);
|
|
616
|
-
const targets = peer !== undefined ?
|
|
634
|
+
const targets = peer !== undefined ? peers.filter((p) => p.spec.name === peer) : peers;
|
|
617
635
|
if (peer !== undefined && targets.length === 0) {
|
|
618
636
|
return [{ peer, prefix: prefixOf(peer), status: "failed", toolCount: 0, added: [], removed: [], error: "no peer of that name is declared for this task" }];
|
|
619
637
|
}
|
|
620
638
|
const results = [];
|
|
621
|
-
for (const
|
|
639
|
+
for (const target of targets) {
|
|
640
|
+
const { spec } = target;
|
|
622
641
|
const prefix = prefixOf(spec.name);
|
|
623
642
|
if (lifecycle.disposed) {
|
|
624
643
|
results.push({ peer: spec.name, prefix, status: "disposed", toolCount: 0, added: [], removed: [] });
|
|
@@ -626,7 +645,7 @@ export async function materializeA2aTools(specs, principal, signal) {
|
|
|
626
645
|
}
|
|
627
646
|
const previous = statuses.find((s) => s.name === spec.name)?.toolNames ?? [];
|
|
628
647
|
try {
|
|
629
|
-
const fresh = await materializePeer(
|
|
648
|
+
const fresh = await materializePeer(target, principal, lifecycle, signal);
|
|
630
649
|
const names = fresh.tools.map((t) => t.name);
|
|
631
650
|
results.push({
|
|
632
651
|
peer: spec.name,
|
|
@@ -163,7 +163,8 @@ export declare function uncoveredCommandSegment(rows: readonly AllowEntryRow[],
|
|
|
163
163
|
* segment covered by a row — or, for a `grant` list, read-only by itself); deny: a row whose program run the call performs (the
|
|
164
164
|
* wide tightening reading; a call that cannot be read against the row is refused too). PATH — the persisted path adjudication
|
|
165
165
|
* (allow: the narrow reading, every view of the target inside what the row names; deny: any view reaching it). NAME / DOMAIN —
|
|
166
|
-
* the one predicate of each (the name the call names, the host it fetches)
|
|
166
|
+
* the one predicate of each (the name the call names, the host it fetches); a keyed tool's call naming no value for its key is
|
|
167
|
+
* refused by a deny list's row of the key and granted by no allow row (the persisted walk's reading, `keyedValueAbsentReason`).
|
|
167
168
|
*/
|
|
168
169
|
export declare function judgeAllowEntries<R extends AllowEntryRow>(rows: readonly R[], req: ToolCallRequest, behavior: "allow" | "deny", ctx: AllowEntryJudgeContext, posture?: AdmissionPosture): readonly R[] | undefined;
|
|
169
170
|
/** The allow rows of a list, as the allow layer reads them in `mode`: the strip applied BEFORE the match (in `auto`). */
|
|
@@ -275,6 +276,7 @@ export declare const SHADOW_REASON: Readonly<{
|
|
|
275
276
|
readonly denial_limit_fallback: "the auto-mode classifier refused too many calls in a row, so a person decides";
|
|
276
277
|
readonly classifier_no_ruling: "the auto-mode classifier could not judge this call, so a person decides";
|
|
277
278
|
readonly requires_user_interaction: "this tool's server declares that a call must be put to a person";
|
|
279
|
+
readonly cross_boundary: string;
|
|
278
280
|
readonly operator_forced: "this call arrived already marked as requiring confirmation (an earlier layer of this run, or the task that delegated it, judged it so) — it is cleared by confirming this call, never by a standing allow rule";
|
|
279
281
|
readonly shell_floor: string;
|
|
280
282
|
readonly target_unresolved: string;
|
package/dist/core/allow-entry.js
CHANGED
|
@@ -4,7 +4,7 @@ import { parsePermissionRule, ruleSpellingOf } from "./permission-rule-syntax.js
|
|
|
4
4
|
import { judgeRuleToolName, splitNamespacedName } from "./tool-name-aliases.js";
|
|
5
5
|
import { catalogToolNames, isShellFaceToolName } from "./tool-registry.js";
|
|
6
6
|
import { ALLOW_RULE_MEMBERS } from "./allow-rule-shadow.js";
|
|
7
|
-
import { COMMAND_RULE_TOOL, adjudicatePersistedDomainRules, adjudicatePersistedNameRules, commandCoverageOf, domainRuleSubjectOf, laneToolNamesOf, nameRuleSubjectOf, parseRuleText, programRunReachOf, ruleToolGrammarOf } from "./permission-rule-model.js";
|
|
7
|
+
import { COMMAND_RULE_TOOL, adjudicatePersistedDomainRules, adjudicatePersistedNameRules, commandCoverageOf, domainRuleSubjectOf, laneToolNamesOf, nameRuleSubjectOf, noticeRuleText, parseRuleText, programRunReachOf, ruleToolGrammarOf } from "./permission-rule-model.js";
|
|
8
8
|
import { pathRuleLaneAnswer } from "./runner/permission-rule-lanes.js";
|
|
9
9
|
import { callTargetReadingOf } from "./effective-path-target.js";
|
|
10
10
|
import { splitShellCompoundSegments } from "../tools/fs/bash-readonly-classifier.js";
|
|
@@ -363,6 +363,7 @@ export const SHADOW_REASON = Object.freeze({
|
|
|
363
363
|
denial_limit_fallback: "the auto-mode classifier refused too many calls in a row, so a person decides",
|
|
364
364
|
classifier_no_ruling: "the auto-mode classifier could not judge this call, so a person decides",
|
|
365
365
|
requires_user_interaction: "this tool's server declares that a call must be put to a person",
|
|
366
|
+
cross_boundary: mandateDisclosureOf("cross_boundary_taint"),
|
|
366
367
|
operator_forced: "this call arrived already marked as requiring confirmation (an earlier layer of this run, or the task that delegated it, judged it so) — it is cleared by confirming this call, never by a standing allow rule",
|
|
367
368
|
shell_floor: mandateDisclosureOf("operator_always"),
|
|
368
369
|
target_unresolved: mandateDisclosureOf("target_unresolved"),
|
|
@@ -462,6 +463,6 @@ export function allowedToolsNotGrantedNotice(inert, sessionId) {
|
|
|
462
463
|
message: `${inert.length} allowed-tools entr${inert.length === 1 ? "y grants" : "ies grant"} or refuse${inert.length === 1 ? "s" : ""} nothing — ${shown.join("; ")}${rest > 0 ? `; and ${rest} more` : ""}. ` +
|
|
463
464
|
"A list holding `*` voids the list, `mcp__*` names no server, a rule the grammar refuses (`grammar`) or one on a tool with no such rule form (`content_unsupported`: an allow by path is an `Edit(…)` or `Read(…)` rule) grants nothing, and a tool name must be spelled as the tool is mounted; name the tools (or `mcp__<server>`) instead." +
|
|
464
465
|
(refusing ? " Such an entry in a disallowed-tools list keeps its Skill from activating: a refusal that reads as nothing is not dropped." : ""),
|
|
465
|
-
detail: { ...(sessionId !== undefined ? { sessionId } : {}), entries: inert.map((e) => ({ ...e })) },
|
|
466
|
+
detail: { ...(sessionId !== undefined ? { sessionId } : {}), entries: inert.map((e) => ({ ...e, entry: noticeRuleText(e.entry) })) },
|
|
466
467
|
};
|
|
467
468
|
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import type { PendingAction } from "./checkpoint-store.js";
|
|
2
|
+
import type { CallTargetReading } from "./effective-path-target.js";
|
|
3
|
+
import { type SkillGrantSource } from "./skill-grant.js";
|
|
4
|
+
import type { ToolCallPathTarget, ToolFamily } from "./tool-face.js";
|
|
5
|
+
import { type ToolRosterEntry } from "./tool-roster.js";
|
|
6
|
+
type ParkedApproval = Extract<PendingAction, {
|
|
7
|
+
kind: "tool_approval";
|
|
8
|
+
}>;
|
|
9
|
+
/** The readings of a call's path slot a target is bound under ({@link CallTargetReading}'s two directions). */
|
|
10
|
+
export declare const APPROVAL_TARGET_ROLES: readonly ["protective", "declared"];
|
|
11
|
+
export type ApprovalTargetRole = (typeof APPROVAL_TARGET_ROLES)[number];
|
|
12
|
+
/** The row's `targets` member: per role, the location the target RESOLVED to when the card was asked (the canonical
|
|
13
|
+
* view of that reading), or `null` when the environment was asked and did not answer — an unresolved target binds
|
|
14
|
+
* "unresolved", so a later resolution is a move. A role the environment was not asked about is absent; a row with no
|
|
15
|
+
* such role carries none. */
|
|
16
|
+
export type ApprovalTargets = {
|
|
17
|
+
readonly [R in ApprovalTargetRole]?: string | null;
|
|
18
|
+
};
|
|
19
|
+
/** The tool member as the row carries it: every member optional (a row is read, never trusted to be whole). */
|
|
20
|
+
export interface ApprovalTool {
|
|
21
|
+
readonly capabilityId?: string;
|
|
22
|
+
readonly contractId?: string;
|
|
23
|
+
readonly shapeDigest?: string;
|
|
24
|
+
readonly implementationRevision?: string;
|
|
25
|
+
readonly family?: ToolFamily;
|
|
26
|
+
readonly pathTarget?: ToolCallPathTarget;
|
|
27
|
+
}
|
|
28
|
+
export interface ApprovalObject {
|
|
29
|
+
/** Absent on a row minted before the identity members (all four absent): such a row binds the tool's name alone. */
|
|
30
|
+
readonly tool?: ApprovalTool;
|
|
31
|
+
/** The row's member as stored — read, validated, by the judge. */
|
|
32
|
+
readonly targets?: unknown;
|
|
33
|
+
readonly grants?: string;
|
|
34
|
+
}
|
|
35
|
+
/** The view of one parked approval's object. */
|
|
36
|
+
export declare function approvalObjectOf(row: ParkedApproval): ApprovalObject;
|
|
37
|
+
/** The `targets` member of a reading: per role, the canonical view, or `null` for a view the environment was asked for
|
|
38
|
+
* and did not answer; nothing when no role was read either way (or no reading was taken). The park mints it from the
|
|
39
|
+
* gate's reading of the parked bytes; the execution station reads the bytes that will run the same way. */
|
|
40
|
+
export declare function approvalTargetsOf(reading: CallTargetReading | undefined): {
|
|
41
|
+
targets?: ApprovalTargets;
|
|
42
|
+
};
|
|
43
|
+
/** Where a resume judges the object: before the claim (the decided bytes), before the session is touched (the live
|
|
44
|
+
* tool), right before the execution (the tool as mounted then — a host's re-dial can replace it between the two — and the
|
|
45
|
+
* bytes that will run, after every station that can rewrite them). */
|
|
46
|
+
export type ApprovalStation = "claim" | "session" | "execution";
|
|
47
|
+
export type ApprovalMember = "tool" | "targets" | "grants";
|
|
48
|
+
/** THE table: the members each station judges. */
|
|
49
|
+
export declare const APPROVAL_STATION_MEMBERS: {
|
|
50
|
+
readonly [S in ApprovalStation]: readonly ApprovalMember[];
|
|
51
|
+
};
|
|
52
|
+
/** What a station does with a mismatch: refuse with the row still pending (before the claim), reopen it for the
|
|
53
|
+
* original tool, or veto the call (not run, approval spent). */
|
|
54
|
+
export type ApprovalDisposition = "refuse_pending" | "reopen" | "veto";
|
|
55
|
+
export interface ApprovalMismatch {
|
|
56
|
+
readonly member: ApprovalMember;
|
|
57
|
+
readonly disposition: ApprovalDisposition;
|
|
58
|
+
/** The machine word: the reopen codes, `resume.target_moved` on a moved face or target (the vetoed call's
|
|
59
|
+
* `tool_end.errorCode`); absent on a grants veto. */
|
|
60
|
+
readonly code?: "resume.tool_unavailable" | "resume.tool_contract_mismatch" | "resume.target_moved" | "checkpoint.invalid_outcome";
|
|
61
|
+
readonly message: string;
|
|
62
|
+
}
|
|
63
|
+
/** What the station holds of the live call. */
|
|
64
|
+
export interface LiveApprovalObject {
|
|
65
|
+
/** session / execution: the live roster row the leg would run the call as — `undefined` when the tool is not mounted. */
|
|
66
|
+
readonly tool?: ToolRosterEntry | undefined;
|
|
67
|
+
/** claim / execution: the bytes the station judges, the skills this resume serves and the Skill tool's wire name. */
|
|
68
|
+
readonly args?: unknown;
|
|
69
|
+
readonly skills?: readonly SkillGrantSource[];
|
|
70
|
+
readonly skillToolName?: string;
|
|
71
|
+
/** execution: the reading of the bytes that will run, taken at this station (`undefined`: none could be taken). */
|
|
72
|
+
readonly targetReading?: CallTargetReading | undefined;
|
|
73
|
+
/** execution: the bytes the decision rewrote the call to, as the tool reads them; absent when it rewrote nothing. When
|
|
74
|
+
* the row's binding does not cover them ({@link licenseCovers}, the one judge of "are these the approved bytes") the
|
|
75
|
+
* person approved bytes whose target the row never recorded, and the targets member is not judged. */
|
|
76
|
+
readonly decided?: unknown;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* THE judge of a parked approval at one station: `"match"`, or the first member the table names for the station that
|
|
80
|
+
* the live call does not match, with its disposition. Absence is read per member: a tool member with no identity
|
|
81
|
+
* binds the name alone, and one with SOME identity members is a replacement (never a pre-identity row); a grants
|
|
82
|
+
* member is judged whenever the call would activate a skill (a row with no digest cannot cover one); a targets member
|
|
83
|
+
* is judged unless the decision rewrote the bytes to ones the row's binding does not cover, and one that is not a whole
|
|
84
|
+
* role → location record is damage.
|
|
85
|
+
*/
|
|
86
|
+
export declare function judgeApprovalObject(row: ParkedApproval, live: LiveApprovalObject, station: ApprovalStation): "match" | ApprovalMismatch;
|
|
87
|
+
export {};
|