@sema-agent/server 7.132.0 → 7.133.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/MIGRATION.md +266 -0
- package/README.md +8 -9
- package/README.zh-CN.md +7 -6
- package/USAGE.md +174 -55
- package/deploy/sema-up/README.md +19 -1
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +5 -2
- package/deploy/sema-up/chart/templates/server.yaml +5 -2
- package/deploy/sema-up/stack/compose.yaml +3 -0
- package/deploy/sema-up/stack/sema-stack-cluster.yaml +4 -2
- package/dist/adoption/plan.d.ts +3 -2
- package/dist/adoption/plan.js +7 -5
- package/dist/adoption/runner.js +3 -10
- package/dist/adoption/sql.d.ts +3 -2
- package/dist/adoption/sql.js +3 -5
- package/dist/adoption/wire.d.ts +4 -1
- package/dist/adoption/wire.js +1 -0
- package/dist/approval-ask-audit-store.d.ts +31 -13
- package/dist/approval-ask-audit-store.js +272 -74
- package/dist/approval-ask-machine.d.ts +15 -0
- package/dist/approval-ask-machine.js +6 -0
- package/dist/approval-ask-retention.d.ts +136 -0
- package/dist/approval-ask-retention.js +102 -0
- package/dist/approval-card.d.ts +79 -19
- package/dist/approval-card.js +44 -13
- package/dist/approval-deny-reasons.d.ts +1 -1
- package/dist/approval.d.ts +9 -0
- package/dist/approval.js +24 -3
- package/dist/audit.d.ts +27 -10
- package/dist/audit.js +12 -16
- package/dist/bake-runner/main.js +3 -2
- package/dist/boot/deferred-sandbox-path-env.js +1 -1
- package/dist/boot/execution-env.js +9 -7
- package/dist/boot/execution-lane.js +11 -0
- package/dist/boot/leader.js +2 -0
- package/dist/boot/memory-boundary.js +2 -2
- package/dist/boot/memory-consolidation.d.ts +5 -4
- package/dist/boot/memory-consolidation.js +7 -6
- package/dist/boot/org-delivery.d.ts +28 -0
- package/dist/boot/org-delivery.js +20 -0
- package/dist/boot/reapers.d.ts +3 -0
- package/dist/boot/reapers.js +21 -1
- package/dist/boot/resolve-spec.d.ts +3 -0
- package/dist/boot/resolve-spec.js +60 -81
- package/dist/boot/runner-deps.js +1 -0
- package/dist/boot/session-faces.d.ts +1 -0
- package/dist/boot/session-faces.js +4 -2
- package/dist/boot/stage-02-web-admin-pull.js +4 -1
- package/dist/boot/stage-06-runners.d.ts +2 -0
- package/dist/boot/stage-06-runners.js +6 -3
- package/dist/boot/stage-07-capability-layer.d.ts +2 -0
- package/dist/boot/stage-07-capability-layer.js +24 -3
- package/dist/boot/stage-08-reapers.d.ts +2 -0
- package/dist/boot/stage-08-reapers.js +2 -2
- package/dist/boot/stage-09-leader.d.ts +3 -0
- package/dist/boot/stage-10-http-server.d.ts +3 -0
- package/dist/boot/stage-10-http-server.js +5 -6
- package/dist/boot/stores.js +2 -2
- package/dist/boot/web-admin.d.ts +4 -0
- package/dist/boot/web-admin.js +151 -63
- package/dist/boot/workflow-orchestration.d.ts +2 -0
- package/dist/boot/workflow-orchestration.js +2 -1
- package/dist/brain.js +8 -3
- package/dist/breaker-key.d.ts +6 -0
- package/dist/breaker-key.js +29 -0
- package/dist/caller-text-echo.d.ts +9 -6
- package/dist/caller-text-echo.js +8 -11
- package/dist/capabilities/center-plugins.d.ts +7 -0
- package/dist/capabilities/center-plugins.js +1 -1
- package/dist/capabilities/composite-members.d.ts +1 -1
- package/dist/capabilities/composite-members.js +1 -1
- package/dist/capabilities/execution-lane.js +2 -2
- package/dist/capabilities/hands-lane.d.ts +21 -0
- package/dist/capabilities/hands-lane.js +10 -0
- package/dist/capabilities/mcp-probe.d.ts +36 -4
- package/dist/capabilities/mcp-probe.js +27 -4
- package/dist/capabilities/scenarios.d.ts +63 -7
- package/dist/capabilities/scenarios.js +39 -7
- package/dist/capability-facts.d.ts +34 -4
- package/dist/capability-facts.js +28 -2
- package/dist/center-config-tier.d.ts +69 -0
- package/dist/center-config-tier.js +42 -0
- package/dist/checkpoint-identity.d.ts +16 -0
- package/dist/checkpoint-identity.js +19 -0
- package/dist/config-catalog.d.ts +17 -10
- package/dist/config-catalog.js +43 -28
- package/dist/config-d-migration.d.ts +3 -1
- package/dist/config-d-migration.js +2 -2
- package/dist/config-dir-trust.d.ts +114 -0
- package/dist/config-dir-trust.js +388 -0
- package/dist/config-invariants.d.ts +18 -5
- package/dist/config-invariants.js +35 -3
- package/dist/config-provider.d.ts +6 -1
- package/dist/config-provider.js +6 -2
- package/dist/config-types.d.ts +71 -14
- package/dist/config-types.js +8 -0
- package/dist/config.d.ts +13 -0
- package/dist/config.js +121 -59
- package/dist/delegated-session-owner.d.ts +185 -0
- package/dist/delegated-session-owner.js +119 -0
- package/dist/device-protocol.d.ts +5 -3
- package/dist/device-protocol.js +1 -1
- package/dist/device-ws-hub.js +21 -2
- package/dist/device-ws-protocol.d.ts +70 -6
- package/dist/device-ws-protocol.js +50 -23
- package/dist/elicitation.js +3 -2
- package/dist/entry-problems.d.ts +34 -0
- package/dist/entry-problems.js +14 -0
- package/dist/execution-lane-caps.d.ts +49 -10
- package/dist/execution-lane-caps.js +43 -4
- package/dist/field-conflict.d.ts +43 -0
- package/dist/field-conflict.js +20 -0
- package/dist/fleet/fleet-bus.d.ts +80 -6
- package/dist/fleet/fleet-bus.js +41 -9
- package/dist/hooks/classic-stations.d.ts +10 -5
- package/dist/hooks/classic-stations.js +4 -4
- package/dist/hooks/command-spawn.d.ts +57 -0
- package/dist/hooks/command-spawn.js +139 -0
- package/dist/hooks/hook-llm.js +2 -2
- package/dist/hooks/hook-runner.d.ts +127 -25
- package/dist/hooks/hook-runner.js +668 -287
- package/dist/hooks/hook-source.d.ts +44 -0
- package/dist/hooks/hook-source.js +40 -0
- package/dist/http/active-run-conflict.d.ts +5 -13
- package/dist/http/active-run-conflict.js +17 -27
- package/dist/http/admission.js +103 -60
- package/dist/http/approval-sweeps.js +55 -18
- package/dist/http/caller-trust.d.ts +77 -0
- package/dist/http/caller-trust.js +143 -0
- package/dist/http/checkpoint-ctx.d.ts +16 -16
- package/dist/http/checkpoint-ctx.js +13 -10
- package/dist/http/claimed-run.d.ts +4 -3
- package/dist/http/device-placement.d.ts +2 -4
- package/dist/http/device-placement.js +2 -1
- package/dist/http/dispatch.js +10 -4
- package/dist/http/durable-run-leg.d.ts +4 -32
- package/dist/http/durable-run-leg.js +34 -10
- package/dist/http/owner-access.d.ts +56 -0
- package/dist/http/owner-access.js +42 -0
- package/dist/http/principal-gate.d.ts +48 -23
- package/dist/http/principal-gate.js +39 -12
- package/dist/http/readiness.d.ts +11 -5
- package/dist/http/readiness.js +10 -3
- package/dist/http/request-guards.d.ts +16 -23
- package/dist/http/request-guards.js +30 -15
- package/dist/http/resume-ctx-read.d.ts +2 -5
- package/dist/http/resume-ctx-read.js +7 -4
- package/dist/http/resume-legs.d.ts +3 -4
- package/dist/http/resume-legs.js +126 -69
- package/dist/http/retired-service-deps.d.ts +43 -0
- package/dist/http/retired-service-deps.js +18 -0
- package/dist/http/route-ctx.d.ts +44 -28
- package/dist/http/route-ctx.js +4 -0
- package/dist/http/route-table.js +2 -0
- package/dist/http/routes/a2a-serve.js +3 -4
- package/dist/http/routes/admin-config-refresh.js +1 -1
- package/dist/http/routes/admin-drain.js +1 -1
- package/dist/http/routes/admin-memory-optout.js +5 -1
- package/dist/http/routes/adoption.js +2 -9
- package/dist/http/routes/approvals-assistant.js +49 -48
- package/dist/http/routes/background.js +3 -2
- package/dist/http/routes/capabilities.js +20 -4
- package/dist/http/routes/config-catalog.d.ts +3 -3
- package/dist/http/routes/config-catalog.js +1 -1
- package/dist/http/routes/devices.js +3 -17
- package/dist/http/routes/diagnostics.js +5 -1
- package/dist/http/routes/images.js +6 -7
- package/dist/http/routes/leader.js +1 -8
- package/dist/http/routes/mcp-reconnect.d.ts +1 -1
- package/dist/http/routes/mcp-reconnect.js +3 -2
- package/dist/http/routes/memory-bundle.js +1 -1
- package/dist/http/routes/memory-compliance.js +1 -1
- package/dist/http/routes/memory-consolidation.js +1 -1
- package/dist/http/routes/memory-origin.js +1 -1
- package/dist/http/routes/memory-policy.d.ts +1 -1
- package/dist/http/routes/memory-policy.js +3 -2
- package/dist/http/routes/notify-wake.js +8 -21
- package/dist/http/routes/observability.js +2 -2
- package/dist/http/routes/principal-inbox.d.ts +39 -0
- package/dist/http/routes/principal-inbox.js +76 -0
- package/dist/http/routes/retention-ops.js +2 -9
- package/dist/http/routes/rules.js +5 -18
- package/dist/http/routes/runs.d.ts +5 -0
- package/dist/http/routes/runs.js +33 -106
- package/dist/http/routes/session-sync.js +15 -28
- package/dist/http/routes/sessions.js +30 -40
- package/dist/http/routes/side-query.js +6 -4
- package/dist/http/routes/tasks.js +50 -14
- package/dist/http/routes/workflows.d.ts +351 -0
- package/dist/http/routes/workflows.js +153 -119
- package/dist/http/send.d.ts +24 -3
- package/dist/http/send.js +14 -2
- package/dist/http/server.d.ts +17 -18
- package/dist/http/server.js +15 -13
- package/dist/http/stored-body-replay.js +17 -4
- package/dist/http/submit-ctx.js +4 -3
- package/dist/http/submit-replay.d.ts +4 -3
- package/dist/http/submit-replay.js +5 -4
- package/dist/http/wire-types.d.ts +10 -7
- package/dist/index.d.ts +1 -1
- package/dist/index.js +0 -1
- package/dist/lane-home-probe.d.ts +78 -9
- package/dist/lane-home-probe.js +78 -12
- package/dist/leader/endpoint.d.ts +4 -1
- package/dist/leader/endpoint.js +11 -10
- package/dist/limit-refusal.d.ts +17 -5
- package/dist/limit-refusal.js +4 -1
- package/dist/mcp-assertion-header.d.ts +31 -10
- package/dist/mcp-assertion-header.js +10 -3
- package/dist/mcp-tool-faces.js +1 -3
- package/dist/memory-project-layer.d.ts +37 -0
- package/dist/memory-project-layer.js +46 -0
- package/dist/memory-scope.d.ts +23 -16
- package/dist/memory-scope.js +24 -8
- package/dist/memory-sync-client.d.ts +27 -13
- package/dist/memory-sync-client.js +107 -18
- package/dist/model-entry-refusal.d.ts +9 -1
- package/dist/model-entry-refusal.js +6 -1
- package/dist/model-plane-face.d.ts +51 -0
- package/dist/model-plane-face.js +24 -0
- package/dist/model-provider.d.ts +5 -0
- package/dist/model-provider.js +4 -2
- package/dist/model-route-endpoint.d.ts +8 -11
- package/dist/model-route-endpoint.js +4 -7
- package/dist/model-route-env.d.ts +22 -0
- package/dist/model-route-env.js +2 -0
- package/dist/model-route-gap.d.ts +60 -30
- package/dist/model-route-gap.js +21 -15
- package/dist/observability/corrupt-read-seat.d.ts +7 -0
- package/dist/observability/corrupt-read-seat.js +9 -0
- package/dist/observability/err-text.d.ts +6 -0
- package/dist/observability/err-text.js +18 -4
- package/dist/observability/fail-open.d.ts +35 -9
- package/dist/observability/fail-open.js +35 -9
- package/dist/observability/metrics.js +1 -0
- package/dist/observability/prompt-manifest.d.ts +3 -17
- package/dist/observability/prompt-manifest.js +45 -42
- package/dist/observability/tool-trace.js +9 -9
- package/dist/operator-ask.d.ts +10 -0
- package/dist/operator-ask.js +3 -0
- package/dist/orchestration/workflow-agent-session-index.d.ts +12 -12
- package/dist/orchestration/workflow-agent-session-index.js +9 -13
- package/dist/orchestration/workflow-completion-inbox.d.ts +42 -15
- package/dist/orchestration/workflow-completion-inbox.js +13 -0
- package/dist/orchestration/workflow-notify-journal.d.ts +13 -32
- package/dist/orchestration/workflow-notify-journal.js +27 -34
- package/dist/orchestration/workflow-park-decision.d.ts +89 -0
- package/dist/orchestration/workflow-park-decision.js +118 -0
- package/dist/org-delivery-gate.d.ts +81 -0
- package/dist/org-delivery-gate.js +59 -0
- package/dist/panel-tool-names.d.ts +23 -0
- package/dist/panel-tool-names.js +8 -0
- package/dist/parked-decide.d.ts +39 -6
- package/dist/parked-decide.js +98 -51
- package/dist/parked-revive-surface.d.ts +9 -2
- package/dist/parked-revive-surface.js +11 -8
- package/dist/permission-rule-list.d.ts +1 -1
- package/dist/permission-rule-list.js +2 -2
- package/dist/plugins/approval-ask-store-file.d.ts +16 -1
- package/dist/plugins/approval-ask-store-file.js +21 -0
- package/dist/plugins/approval-ask-store-memory.d.ts +18 -1
- package/dist/plugins/approval-ask-store-memory.js +34 -2
- package/dist/plugins/approval-ask-store-sql.d.ts +25 -0
- package/dist/plugins/approval-ask-store-sql.js +37 -1
- package/dist/plugins/blob-backend.d.ts +38 -25
- package/dist/plugins/blob-backend.js +29 -19
- package/dist/plugins/breaker-state-sql.d.ts +2 -2
- package/dist/plugins/breaker-state-sql.js +4 -4
- package/dist/plugins/caching-session-store.d.ts +3 -0
- package/dist/plugins/caching-session-store.js +3 -0
- package/dist/plugins/checkpoint-store-sql.d.ts +14 -0
- package/dist/plugins/checkpoint-store-sql.js +20 -2
- package/dist/plugins/file-history-store-sql.d.ts +5 -2
- package/dist/plugins/file-history-store-sql.js +3 -1
- package/dist/plugins/file-run-store.d.ts +5 -13
- package/dist/plugins/file-run-store.js +9 -0
- package/dist/plugins/fork-routing-session-store.d.ts +9 -1
- package/dist/plugins/fork-routing-session-store.js +12 -1
- package/dist/plugins/host-platform.d.ts +2 -0
- package/dist/plugins/host-platform.js +2 -1
- package/dist/plugins/local-checkpoint-store.d.ts +2 -0
- package/dist/plugins/local-checkpoint-store.js +6 -1
- package/dist/plugins/local-session-store.d.ts +1 -1
- package/dist/plugins/local-session-window.d.ts +39 -0
- package/dist/plugins/local-session-window.js +54 -0
- package/dist/plugins/mailbox-recipient-lifecycle.d.ts +3 -2
- package/dist/plugins/mailbox-store-sql.d.ts +30 -48
- package/dist/plugins/mailbox-store-sql.js +77 -52
- package/dist/plugins/memory-embedder-fingerprint.js +2 -1
- package/dist/plugins/memory-run-store.d.ts +5 -13
- package/dist/plugins/memory-run-store.js +8 -0
- package/dist/plugins/one-time-migrations.d.ts +110 -5
- package/dist/plugins/one-time-migrations.js +320 -8
- package/dist/plugins/org-delivery-quota-store.d.ts +123 -0
- package/dist/plugins/org-delivery-quota-store.js +228 -0
- package/dist/plugins/pg-pool.js +39 -7
- package/dist/plugins/pg-session-storage.d.ts +17 -4
- package/dist/plugins/pg-session-storage.js +29 -6
- package/dist/plugins/remote-env-adb.d.ts +6 -12
- package/dist/plugins/remote-env-adb.js +12 -2
- package/dist/plugins/remote-env-k8s.d.ts +8 -12
- package/dist/plugins/remote-env-k8s.js +23 -5
- package/dist/plugins/remote-env-local-docker.d.ts +10 -15
- package/dist/plugins/remote-env-local-docker.js +12 -9
- package/dist/plugins/remote-env-ssh.d.ts +10 -16
- package/dist/plugins/remote-env-ssh.js +17 -11
- package/dist/plugins/run-store-sql.d.ts +16 -14
- package/dist/plugins/run-store-sql.js +22 -2
- package/dist/plugins/schema-indexes.js +2 -0
- package/dist/plugins/send-user-file.js +2 -2
- package/dist/plugins/session-epoch-anchor.d.ts +32 -6
- package/dist/plugins/session-epoch-anchor.js +2 -3
- package/dist/plugins/session-store.d.ts +18 -8
- package/dist/plugins/session-store.js +15 -4
- package/dist/plugins/sql-driver.d.ts +74 -11
- package/dist/plugins/sql-driver.js +210 -12
- package/dist/plugins/sql-errors.d.ts +23 -0
- package/dist/plugins/sql-errors.js +21 -0
- package/dist/plugins/store-backend.d.ts +36 -1
- package/dist/plugins/store-backend.js +40 -14
- package/dist/plugins/store-contracts.d.ts +42 -0
- package/dist/plugins/store-contracts.js +1 -0
- package/dist/plugins/tidb-pool.d.ts +6 -1
- package/dist/plugins/tidb-pool.js +44 -10
- package/dist/plugins/tidb-session-storage.d.ts +3 -2
- package/dist/plugins/tidb-session-storage.js +2 -2
- package/dist/plugins/tidb-session-store.d.ts +24 -4
- package/dist/plugins/tidb-session-store.js +28 -4
- package/dist/plugins/workflow-journal-store-sql.d.ts +73 -19
- package/dist/plugins/workflow-journal-store-sql.js +19 -6
- package/dist/plugins/workflow-run-store-sql.d.ts +30 -8
- package/dist/plugins/workflow-run-store-sql.js +50 -9
- package/dist/posture-source.d.ts +18 -10
- package/dist/posture-source.js +4 -1
- package/dist/project-identity.d.ts +45 -6
- package/dist/project-identity.js +162 -8
- package/dist/project-layer-key.d.ts +28 -0
- package/dist/project-layer-key.js +29 -0
- package/dist/question.js +3 -2
- package/dist/read-deny-entry.d.ts +25 -0
- package/dist/read-deny-entry.js +12 -0
- package/dist/read-face-posture.d.ts +37 -11
- package/dist/read-face-posture.js +32 -3
- package/dist/request-key-closure.d.ts +7 -0
- package/dist/request-key-closure.js +9 -1
- package/dist/request-value-closure.d.ts +5 -0
- package/dist/request-value-closure.js +11 -3
- package/dist/rule-entry-list.d.ts +26 -2
- package/dist/rule-entry-list.js +72 -12
- package/dist/rules-consent.js +3 -4
- package/dist/run-acceptance.d.ts +19 -3
- package/dist/run-acceptance.js +13 -1
- package/dist/run-local.js +36 -6
- package/dist/runs.d.ts +10 -9
- package/dist/runs.js +21 -3
- package/dist/runtime-caps-resolver.d.ts +16 -6
- package/dist/runtime-caps-resolver.js +18 -5
- package/dist/sandbox-pkg-source.d.ts +19 -1
- package/dist/sandbox-pkg-source.js +29 -7
- package/dist/security.d.ts +87 -9
- package/dist/security.js +52 -9
- package/dist/session-error-wire.d.ts +19 -2
- package/dist/session-error-wire.js +5 -1
- package/dist/session-titled-frame.d.ts +33 -0
- package/dist/session-titled-frame.js +4 -0
- package/dist/session-titler.d.ts +9 -1
- package/dist/session-titler.js +15 -4
- package/dist/spec-fields.js +21 -2
- package/dist/sql-engine-posture.d.ts +3 -1
- package/dist/task-cwd.d.ts +1 -1
- package/dist/task-mcp.d.ts +3 -3
- package/dist/task-mcp.js +7 -66
- package/dist/task-settings.d.ts +89 -88
- package/dist/task-settings.js +71 -63
- package/dist/text-bidi.d.ts +0 -4
- package/dist/text-bidi.js +1 -3
- package/dist/tighten-only-seats.d.ts +150 -0
- package/dist/tighten-only-seats.js +196 -0
- package/dist/tool-approval.d.ts +303 -87
- package/dist/tool-approval.js +623 -239
- package/dist/trace/core-keyset-guard.d.ts +104 -22
- package/dist/trace/exit-seat.d.ts +28 -0
- package/dist/trace/exit-seat.js +76 -0
- package/dist/trace/ledger-events.d.ts +3 -2
- package/dist/trace/project.d.ts +80 -12
- package/dist/trace/project.js +41 -28
- package/dist/trace/projection-table.d.ts +100 -0
- package/dist/trace/projection-table.js +130 -0
- package/dist/trace/redact.d.ts +54 -0
- package/dist/trace/redact.js +778 -152
- package/dist/trace/self-minted-wire.d.ts +345 -1
- package/dist/trace/self-minted-wire.js +117 -1
- package/dist/trace/wire-projection-faces.d.ts +298 -2
- package/dist/trace/wire-projection-faces.js +154 -13
- package/dist/url-refusal.js +2 -0
- package/dist/web-admin-client/apply-effective.d.ts +12 -0
- package/dist/web-admin-client/apply-effective.js +56 -5
- package/dist/web-admin-client/facade.d.ts +1 -1
- package/dist/web-admin-client/facade.js +1 -1
- package/dist/web-admin-client/read-face.js +5 -9
- package/dist/web-admin-client/skills-mcp.js +4 -5
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +57 -9
- package/package.json +7 -3
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 请求面**来源**闭集 —— 一个 hook 组(`settings.hooks[event][i].source`)是谁写的。词表与「托管与否」的映射**只在这里**;
|
|
3
|
+
* hooks 执行器按它分车道(`hook-runner.ts` 的三相),将来请求面别处的来源键(MCP 服务器条目)读同一张词表,不另立第二份。
|
|
4
|
+
*
|
|
5
|
+
* 词表(闭集;集外词 = 形错,受理面整份拒,fail-closed;缺席 = 非托管):
|
|
6
|
+
* · `managedPolicy` —— 组织策略(托管设置)。**托管**,且是终判相。
|
|
7
|
+
* · `managedPlugin:<name>` —— 托管设置启用的插件(壳在「只许托管 hook」治理下仍保留它们)。**托管**。
|
|
8
|
+
* · `user` / `project` / `local` / `flag` —— 设置文件的各层与启动时给的 `--settings`。非托管。
|
|
9
|
+
* · `plugin:<name>` —— 用户启用的插件。非托管(来源不可信)。
|
|
10
|
+
* `<name>` 非空、至多 {@link MAX_HOOK_SOURCE_NAME_CHARS} 字;**名只留痕,不作判据**(相只看前缀)。
|
|
11
|
+
*/
|
|
12
|
+
/** 不带名的来源词 → 它跑在哪一相。`satisfies Record<…>`:加一个词不写相 = 编译红。 */
|
|
13
|
+
declare const HOOK_SOURCE_WORD_PHASE: {
|
|
14
|
+
readonly managedPolicy: "managedPolicy";
|
|
15
|
+
readonly user: "unmanaged";
|
|
16
|
+
readonly project: "unmanaged";
|
|
17
|
+
readonly local: "unmanaged";
|
|
18
|
+
readonly flag: "unmanaged";
|
|
19
|
+
};
|
|
20
|
+
/** 带名的来源前缀(`<prefix>:<name>`)→ 它跑在哪一相。 */
|
|
21
|
+
declare const HOOK_SOURCE_PREFIX_PHASE: {
|
|
22
|
+
readonly managedPlugin: "managedPlugin";
|
|
23
|
+
readonly plugin: "unmanaged";
|
|
24
|
+
};
|
|
25
|
+
type HookSourceWord = keyof typeof HOOK_SOURCE_WORD_PHASE;
|
|
26
|
+
type HookSourcePrefix = keyof typeof HOOK_SOURCE_PREFIX_PHASE;
|
|
27
|
+
/** 一个 hook 组的来源(闭集;见文件头)。 */
|
|
28
|
+
export type HookGroupSource = HookSourceWord | `${HookSourcePrefix}:${string}`;
|
|
29
|
+
/**
|
|
30
|
+
* 执行相 —— **固定次序**就是这张数组的次序:非托管 → 托管插件 → 托管策略(终判)。后一相在前一相的最终输入上跑;结果按信任序(倒序)读。
|
|
31
|
+
* 托管 = 后两相;非托管与托管各一只事件墙钟(见 `hook-runner.ts`)。
|
|
32
|
+
*/
|
|
33
|
+
export declare const HOOK_PHASES: readonly ["unmanaged", "managedPlugin", "managedPolicy"];
|
|
34
|
+
export type HookPhase = (typeof HOOK_PHASES)[number];
|
|
35
|
+
/** 来源的名的长度上限(`managedPlugin:` / `plugin:` 之后那一段)。 */
|
|
36
|
+
export declare const MAX_HOOK_SOURCE_NAME_CHARS = 128;
|
|
37
|
+
/** 受理面的读法:合形 ⇒ 来源;否则 `undefined`(调用方铸拒)。只认 own 词(`Object.hasOwn`:原型上的名字不是词表成员)。 */
|
|
38
|
+
export declare function readHookGroupSource(raw: unknown): HookGroupSource | undefined;
|
|
39
|
+
/** 来源 → 相。缺席 ⇒ 非托管(老包不带 `source`:行为与此前逐字同)。 */
|
|
40
|
+
export declare function hookPhaseOf(source: HookGroupSource | undefined): HookPhase;
|
|
41
|
+
/** 拒句里的词表(由两张表派生,不另写一份)。 */
|
|
42
|
+
export declare const HOOK_SOURCE_VOCABULARY_SENTENCE: string;
|
|
43
|
+
export {};
|
|
44
|
+
//# sourceMappingURL=hook-source.d.ts.map
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
const HOOK_SOURCE_WORD_PHASE = {
|
|
2
|
+
managedPolicy: "managedPolicy",
|
|
3
|
+
user: "unmanaged",
|
|
4
|
+
project: "unmanaged",
|
|
5
|
+
local: "unmanaged",
|
|
6
|
+
flag: "unmanaged",
|
|
7
|
+
};
|
|
8
|
+
const HOOK_SOURCE_PREFIX_PHASE = {
|
|
9
|
+
managedPlugin: "managedPlugin",
|
|
10
|
+
plugin: "unmanaged",
|
|
11
|
+
};
|
|
12
|
+
export const HOOK_PHASES = ["unmanaged", "managedPlugin", "managedPolicy"];
|
|
13
|
+
export const MAX_HOOK_SOURCE_NAME_CHARS = 128;
|
|
14
|
+
export function readHookGroupSource(raw) {
|
|
15
|
+
if (typeof raw !== "string")
|
|
16
|
+
return undefined;
|
|
17
|
+
if (Object.hasOwn(HOOK_SOURCE_WORD_PHASE, raw))
|
|
18
|
+
return raw;
|
|
19
|
+
const colon = raw.indexOf(":");
|
|
20
|
+
if (colon <= 0)
|
|
21
|
+
return undefined;
|
|
22
|
+
const prefix = raw.slice(0, colon);
|
|
23
|
+
const name = raw.slice(colon + 1);
|
|
24
|
+
if (!Object.hasOwn(HOOK_SOURCE_PREFIX_PHASE, prefix))
|
|
25
|
+
return undefined;
|
|
26
|
+
if (name.length === 0 || name.length > MAX_HOOK_SOURCE_NAME_CHARS)
|
|
27
|
+
return undefined;
|
|
28
|
+
return raw;
|
|
29
|
+
}
|
|
30
|
+
export function hookPhaseOf(source) {
|
|
31
|
+
if (source === undefined)
|
|
32
|
+
return "unmanaged";
|
|
33
|
+
if (Object.hasOwn(HOOK_SOURCE_WORD_PHASE, source))
|
|
34
|
+
return HOOK_SOURCE_WORD_PHASE[source];
|
|
35
|
+
return HOOK_SOURCE_PREFIX_PHASE[source.slice(0, source.indexOf(":"))];
|
|
36
|
+
}
|
|
37
|
+
export const HOOK_SOURCE_VOCABULARY_SENTENCE = `${Object.keys(HOOK_SOURCE_WORD_PHASE).join(" / ")}, or ${Object.keys(HOOK_SOURCE_PREFIX_PHASE)
|
|
38
|
+
.map((p) => `${p}:<name>`)
|
|
39
|
+
.join(" / ")} with a non-empty name of at most ${MAX_HOOK_SOURCE_NAME_CHARS} characters`;
|
|
40
|
+
//# sourceMappingURL=hook-source.js.map
|
|
@@ -39,16 +39,8 @@ export declare const ACTIVE_RUN_CONFLICT_BASE_TEXT = "session already has an act
|
|
|
39
39
|
* **不是** token 摘要,理由是「最需要它的投影面恰恰是拿不到 token 的那些」——本载体就是其中之一)。
|
|
40
40
|
* ⚠️ 它**不是** askId 的替代:askId 是 `approval_ask` 行的身份,checkpointId 是 checkpoint 行的身份,
|
|
41
41
|
* 两者一对多且今天仍无反查读口(那条记账原样有效,别据本键认为它已销账)。
|
|
42
|
-
*
|
|
43
|
-
*
|
|
44
|
-
* · `/v1/assistant/inbox` 读 `listByScope` ⇒ core 的 `CheckpointSummary`,**值已经在手**(core
|
|
45
|
-
* `summarizeCheckpoint` 单源投影里就带着),补它 = 那张显式白名单上加一行,零 SQL 面;
|
|
46
|
-
* · `GET /v1/approvals` 与 `/v1/approvals/stream` 读的是**本仓自己的** `PendingCheckpoint`
|
|
47
|
-
* (`checkpoint-store-sql.ts` 的 `listPending`,**按列 SELECT、刻意不拉 blob** —— 那是它避免读放大
|
|
48
|
-
* 的既定姿势),所以这一位**不在手**:要补得给 checkpoint 表反范式一列(与 `gate_kind` /
|
|
49
|
-
* `bound_input_hash` / `risk_descriptor` 同族)⇒ **SQL 面 = 双库集成门**,不是顺手一行。
|
|
50
|
-
* 补它们是另一批的事(各自过三问:谁需要跨面 join、join 不上谁受伤、补偿是什么),别在文档或消费码里
|
|
51
|
-
* 预支「两面能对上」。
|
|
42
|
+
* 7.133.0 起三条 durable 读面(运维队列行 `GET /v1/approvals` + `/v1/approvals/stream` 帧、停驻收件 `GET /v1/assistant/inbox` 行)同带这一格,
|
|
43
|
+
* 同一信任边界({@link trustedCheckpointId}),在那三面上它是 join 键(有可信值就带;缺它的行照列、键缺席 + 计数,见 `checkpoint-identity.ts`)。
|
|
52
44
|
*
|
|
53
45
|
* 🔴 **keyset 门辖域外,故在此成文**:`src/trace/core-keyset-guard.ts` 的七个面是
|
|
54
46
|
* TaskNotificationPayload / BackgroundChildEvent / RosterEntry / AskRequest+ToolApprovalFrame /
|
|
@@ -62,11 +54,11 @@ export interface PendingGateMaterial {
|
|
|
62
54
|
/** 见 {@link PendingGateMaterial} 顶注:`true` 才在场,恒不写 `false`。 */
|
|
63
55
|
governanceForced?: true;
|
|
64
56
|
/** [ref](core 5.42.0):这道 park 门的**非秘密稳定身份**(`Checkpoint.checkpointId`)。逐字过境,
|
|
65
|
-
* server 绝不自铸、绝不派生(信任边界校验见 `
|
|
57
|
+
* server 绝不自铸、绝不派生(信任边界校验见 `checkpoint-identity.ts` 的 `trustedCheckpointId`)。
|
|
66
58
|
* 🔴 **缺席是三成因合流的一个形**(R3-[low] 验真后改真 —— 此前这里只写了第一条,那是失真):
|
|
67
59
|
* ① **legacy 行**:该键诞生前 park 的(core 明写「absent ⇒ legacy row, read compatibly, no backfill」);
|
|
68
|
-
* ② **服务端校验拒绝**:行上有值但没过 `
|
|
69
|
-
*
|
|
60
|
+
* ② **服务端校验拒绝**:行上有值但没过 `trustedCheckpointId`(空串 / 超长 / 含 token) ⇒ **数据污染**;
|
|
61
|
+
* 本载体上它与 ① 同形(键缺席、不计数 —— best-effort 分诊材料),durable 读面上两者分计(`checkpoint-identity.ts` 头注);
|
|
70
62
|
* ③ **材料读取失败**:整只 `pendingGate` 都不在(那时本键连位置都没有)。
|
|
71
63
|
* ⇒ 读作「不知道这道门叫什么」,**不是**「这道门没有身份」,更**不是**「这一定是条老行」。
|
|
72
64
|
*
|
|
@@ -2,6 +2,8 @@ import { governanceOriginOf } from "../runtime-governance.js";
|
|
|
2
2
|
import { isParkedRunStatus } from "../plugins/store-contracts.js";
|
|
3
3
|
import { LIVE_RUN_GATE_KINDS } from "../plugins/checkpoint-store-sql.js";
|
|
4
4
|
import { recordFailOpen } from "../observability/fail-open.js";
|
|
5
|
+
import { refusalBody } from "./refusal-body.js";
|
|
6
|
+
import { trustedCheckpointId } from "../checkpoint-identity.js";
|
|
5
7
|
export const ACTIVE_RUN_CONFLICT_BASE_TEXT = "session already has an active run — POST /v1/runs/{activeTaskId}/cancel stops it (same-instance interactive runs abort immediately)";
|
|
6
8
|
export function resumeEntryForGate(kind, ids) {
|
|
7
9
|
switch (kind) {
|
|
@@ -18,15 +20,6 @@ export function resumeEntryForGate(kind, ids) {
|
|
|
18
20
|
return null;
|
|
19
21
|
}
|
|
20
22
|
}
|
|
21
|
-
const MAX_CHECKPOINT_ID_CHARS = 128;
|
|
22
|
-
function safeCheckpointIdOf(raw, token) {
|
|
23
|
-
if (typeof raw !== "string" || raw === "" || raw.length > MAX_CHECKPOINT_ID_CHARS)
|
|
24
|
-
return undefined;
|
|
25
|
-
const secret = token === undefined || token === null ? "" : String(token).toLowerCase();
|
|
26
|
-
if (secret !== "" && raw.toLowerCase().includes(secret))
|
|
27
|
-
return undefined;
|
|
28
|
-
return raw;
|
|
29
|
-
}
|
|
30
23
|
export function isActiveRunConflictBody(body) {
|
|
31
24
|
return typeof body === "object" && body !== null && "activeTaskId" in body && body.errorCode === "conflict.session_active_run";
|
|
32
25
|
}
|
|
@@ -42,12 +35,15 @@ export function toDoneFrameResult(body) {
|
|
|
42
35
|
...(body.pendingGate !== undefined ? { pendingGate: body.pendingGate } : {}),
|
|
43
36
|
};
|
|
44
37
|
}
|
|
38
|
+
function activeRunConflictBody(message, facts) {
|
|
39
|
+
const body = refusalBody({ errorCode: "conflict.session_active_run", message, facts });
|
|
40
|
+
if (!isActiveRunConflictBody(body))
|
|
41
|
+
throw new Error("session-active-run conflict body lost its identity keys (errorCode / activeTaskId)");
|
|
42
|
+
return body;
|
|
43
|
+
}
|
|
45
44
|
export async function buildActiveRunConflict(deps, sessionId, activeTaskId) {
|
|
46
|
-
const
|
|
47
|
-
|
|
48
|
-
errorCode: "conflict.session_active_run",
|
|
49
|
-
activeTaskId: activeTaskId ?? null,
|
|
50
|
-
};
|
|
45
|
+
const baseFacts = { activeTaskId: activeTaskId ?? null };
|
|
46
|
+
const base = activeRunConflictBody(ACTIVE_RUN_CONFLICT_BASE_TEXT, baseFacts);
|
|
51
47
|
if (!activeTaskId)
|
|
52
48
|
return base;
|
|
53
49
|
try {
|
|
@@ -60,13 +56,12 @@ export async function buildActiveRunConflict(deps, sessionId, activeTaskId) {
|
|
|
60
56
|
const updatedAtMs = row?.updatedAt !== undefined ? new Date(row.updatedAt).getTime() : Number.NaN;
|
|
61
57
|
const staleMs = (deps.runStaleSec ?? 0) * 1000;
|
|
62
58
|
const stale = staleMs > 0 && Number.isFinite(updatedAtMs) && Date.now() - updatedAtMs > staleMs;
|
|
63
|
-
return {
|
|
64
|
-
...
|
|
65
|
-
error: "session already has an active run — POST /v1/runs/{activeTaskId}/steer injects a message into the running turn (queued, applied at the next turn boundary), or POST /v1/runs/{activeTaskId}/cancel stops it (same-instance interactive runs abort immediately)",
|
|
59
|
+
return activeRunConflictBody("session already has an active run — POST /v1/runs/{activeTaskId}/steer injects a message into the running turn (queued, applied at the next turn boundary), or POST /v1/runs/{activeTaskId}/cancel stops it (same-instance interactive runs abort immediately)", {
|
|
60
|
+
...baseFacts,
|
|
66
61
|
activeTaskStatus: status,
|
|
67
62
|
...(lastAt !== undefined ? { msSinceLastActivity: Math.max(0, Date.now() - lastAt) } : {}),
|
|
68
63
|
...(stale ? { stale: true } : {}),
|
|
69
|
-
};
|
|
64
|
+
});
|
|
70
65
|
}
|
|
71
66
|
const cs = deps.checkpointStore;
|
|
72
67
|
let pendingGate;
|
|
@@ -79,7 +74,7 @@ export async function buildActiveRunConflict(deps, sessionId, activeTaskId) {
|
|
|
79
74
|
const kind = gate?.kind;
|
|
80
75
|
const decidePath = kind ? resumeEntryForGate(kind, { sessionId, taskId: activeTaskId }) : null;
|
|
81
76
|
const governanceForced = governanceOriginOf(gate, deps.governance);
|
|
82
|
-
const checkpointId =
|
|
77
|
+
const checkpointId = trustedCheckpointId(row?.checkpointId, token);
|
|
83
78
|
if (kind && decidePath) {
|
|
84
79
|
pendingGate = {
|
|
85
80
|
kind,
|
|
@@ -89,14 +84,9 @@ export async function buildActiveRunConflict(deps, sessionId, activeTaskId) {
|
|
|
89
84
|
};
|
|
90
85
|
}
|
|
91
86
|
}
|
|
92
|
-
return
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
? `session already has an active run — it is parked waiting for a decision (${status}); resolve it via POST ${pendingGate.decidePath}, or POST /v1/runs/{activeTaskId}/cancel abandons it`
|
|
96
|
-
: `session already has an active run — it is parked (${status}); POST /v1/runs/{activeTaskId}/cancel abandons it (its pending decision could not be located on this instance)`,
|
|
97
|
-
activeTaskStatus: status,
|
|
98
|
-
...(pendingGate ? { pendingGate } : {}),
|
|
99
|
-
};
|
|
87
|
+
return activeRunConflictBody(pendingGate
|
|
88
|
+
? `session already has an active run — it is parked waiting for a decision (${status}); resolve it via POST ${pendingGate.decidePath}, or POST /v1/runs/{activeTaskId}/cancel abandons it`
|
|
89
|
+
: `session already has an active run — it is parked (${status}); POST /v1/runs/{activeTaskId}/cancel abandons it (its pending decision could not be located on this instance)`, { ...baseFacts, activeTaskStatus: status, ...(pendingGate ? { pendingGate } : {}) });
|
|
100
90
|
}
|
|
101
91
|
catch {
|
|
102
92
|
recordFailOpen("server.approvals.active-run-conflict-material-unavailable");
|
package/dist/http/admission.js
CHANGED
|
@@ -1,23 +1,26 @@
|
|
|
1
1
|
import { APPROVAL_REACH, MCP_IMAGE_MAX_BASE64, isApprovalReach, isPermissionMode, isThinkingLevel, expandTiers } from "@sema-agent/core";
|
|
2
2
|
import { isAtMentionable, matchCatalogModel, refusedCatalogEntry, selectableCatalog } from "../model-select.js";
|
|
3
|
-
import { modelUnavailableMessage } from "../model-entry-refusal.js";
|
|
3
|
+
import { echoModelRef, modelUnavailableMessage } from "../model-entry-refusal.js";
|
|
4
4
|
import { HttpError, sessionIdShapeIssue } from "../security.js";
|
|
5
5
|
import { MAX_SETTINGS_OUTPUT_STYLE_CHARS, MAX_SETTINGS_ENV_VARS, MAX_SETTINGS_ENV_KEY_CHARS, MAX_SETTINGS_ENV_VALUE_CHARS, PERMISSION_MODE_WORDS, parseTaskSettings, settingsPermissionBucketIssue, skillListingBudgetFractionOk, skillListingMaxDescOk, stampEntryPermissionMode, taskHooksHonored, taskSettingsKeyIssue } from "../task-settings.js";
|
|
6
|
+
import { tightenOnlySeatIssue } from "../tighten-only-seats.js";
|
|
6
7
|
import { buildEntryModeClampNotice } from "../entry-mode-clamp-notice.js";
|
|
7
8
|
import { autonomyModeFloor } from "../runtime-governance.js";
|
|
8
9
|
import { taskBodyKeyIssue } from "../request-key-closure.js";
|
|
9
|
-
import { FILE_HISTORY_DISABLED_NO_RESTORE, fileHistoryRestoreConflict, inheritEnvFieldIssue, singleMemberOffFieldIssue } from "../request-value-closure.js";
|
|
10
|
+
import { FILE_HISTORY_DISABLED_NO_RESTORE, fileHistoryRestoreConflict, fileHistoryRestoreKeysInBody, inheritEnvFieldIssue, singleMemberOffFieldIssue } from "../request-value-closure.js";
|
|
10
11
|
import * as facts from "../capability-facts.js";
|
|
11
12
|
import { buildHooksRefusal, parseHooksConfig, hooksMatcherIssue } from "../hooks/hook-runner.js";
|
|
12
13
|
import { judgeRequestWebSearch } from "../plugins/web-search.js";
|
|
13
14
|
import { normalizeApproachNotice, skillToolListOk, unknownTaskAgentModelRef, validateTaskAgents } from "../spec-fields.js";
|
|
14
|
-
import { skillToolListsOverCap } from "../rule-entry-list.js";
|
|
15
|
-
import { limitRefusal } from "../limit-refusal.js";
|
|
16
|
-
import {
|
|
15
|
+
import { allowSelectorWarningsOf, skillToolListsOverCap } from "../rule-entry-list.js";
|
|
16
|
+
import { limitFacts, limitRefusal } from "../limit-refusal.js";
|
|
17
|
+
import { fieldConflictFacts } from "../field-conflict.js";
|
|
18
|
+
import { echoCallerText, quotedCallerText } from "../caller-text-echo.js";
|
|
17
19
|
import { MAX_ADDITIONAL_DIRS } from "../task-cwd.js";
|
|
18
20
|
import { verifyRoundsFromBody } from "./verify-rounds.js";
|
|
19
21
|
import { skillCarriesRetiredManifest } from "./retired-skill-manifest.js";
|
|
20
22
|
import { resolveDevicePlacementIntent } from "./device-placement.js";
|
|
23
|
+
import { callerTrust, requestTrustRefusal } from "./caller-trust.js";
|
|
21
24
|
import { createRunAcceptance } from "../run-acceptance.js";
|
|
22
25
|
import { sendError, sendHttpError } from "./send.js";
|
|
23
26
|
import { refuseSubmitBody } from "./request-guards.js";
|
|
@@ -27,38 +30,56 @@ const APPROVAL_REACH_WORDS = APPROVAL_REACH.map((word) => JSON.stringify(word)).
|
|
|
27
30
|
export const MAX_SKILL_CONTENT_CHARS = 1_048_576;
|
|
28
31
|
export const MAX_SYSTEM_PROMPT_CHARS = 16_384;
|
|
29
32
|
export const MAX_OUTPUT_SCHEMA_CHARS = 32_768;
|
|
33
|
+
const MAX_JOB_ID_CHARS = 64;
|
|
34
|
+
const MAX_CLIENT_TIMEZONE_CHARS = 64;
|
|
35
|
+
const MAX_CLIENT_USER_EMAIL_CHARS = 256;
|
|
36
|
+
const MAX_SANDBOX_IMAGE_PROFILE_CHARS = 128;
|
|
37
|
+
const MAX_RESUME_AT_CHARS = 64;
|
|
38
|
+
const overCharsFacts = (field, v, cap) => (typeof v === "string" && v.length > cap ? limitFacts(field, "characters", v.length, cap) : undefined);
|
|
39
|
+
const multiAttemptFields = (body) => {
|
|
40
|
+
const out = [];
|
|
41
|
+
if (body.verify === true)
|
|
42
|
+
out.push("verify");
|
|
43
|
+
if (body.cascade === true)
|
|
44
|
+
out.push("cascade");
|
|
45
|
+
return out;
|
|
46
|
+
};
|
|
30
47
|
export function validateUserSkills(skills) {
|
|
31
48
|
if (skills === undefined)
|
|
32
49
|
return null;
|
|
33
50
|
if (!Array.isArray(skills))
|
|
34
51
|
return { message: "skills must be an array of { name, description, content }" };
|
|
35
52
|
for (let k = 0; k < skills.length; k++) {
|
|
36
|
-
const shape = userSkillShapeIssue(skills[k]);
|
|
53
|
+
const shape = userSkillShapeIssue(skills[k], k);
|
|
37
54
|
if (shape !== null)
|
|
38
|
-
return
|
|
55
|
+
return shape;
|
|
39
56
|
const over = skillToolListsOverCap(skills[k], `skills[${k}]`, "top");
|
|
40
57
|
if (over !== undefined)
|
|
41
58
|
return { message: over.message, ...(over.extra !== undefined ? { facts: over.extra } : {}) };
|
|
42
59
|
}
|
|
43
60
|
return null;
|
|
44
61
|
}
|
|
45
|
-
function userSkillShapeIssue(item) {
|
|
62
|
+
function userSkillShapeIssue(item, index) {
|
|
46
63
|
if (item === null || typeof item !== "object")
|
|
47
|
-
return "each skill must be an object { name, description, content }";
|
|
64
|
+
return { message: "each skill must be an object { name, description, content }" };
|
|
48
65
|
const s = item;
|
|
49
66
|
if (typeof s["name"] !== "string" || s["name"].length === 0)
|
|
50
|
-
return "skill.name must be a non-empty string";
|
|
67
|
+
return { message: "skill.name must be a non-empty string" };
|
|
51
68
|
if (typeof s["description"] !== "string")
|
|
52
|
-
return "skill.description must be a string";
|
|
53
|
-
if (typeof s["content"] !== "string" || s["content"].length === 0 || s["content"].length > MAX_SKILL_CONTENT_CHARS)
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
69
|
+
return { message: "skill.description must be a string" };
|
|
70
|
+
if (typeof s["content"] !== "string" || s["content"].length === 0 || s["content"].length > MAX_SKILL_CONTENT_CHARS) {
|
|
71
|
+
const facts = overCharsFacts(`skills[${index}].content`, s["content"], MAX_SKILL_CONTENT_CHARS);
|
|
72
|
+
return { message: `skill.content must be a non-empty string of at most ${MAX_SKILL_CONTENT_CHARS} characters (the engine rejects skills over this size outright at load time)`, ...(facts === undefined ? {} : { facts }) };
|
|
73
|
+
}
|
|
74
|
+
if (s["baseDir"] !== undefined && !isAbsoluteHostPath(s["baseDir"])) {
|
|
75
|
+
const facts = overCharsFacts(`skills[${index}].baseDir`, s["baseDir"], ABSOLUTE_HOST_PATH_MAX);
|
|
76
|
+
return { message: `skill.baseDir must be an absolute path string of at most ${ABSOLUTE_HOST_PATH_MAX} characters with no ".." segment and no NUL byte (it is not resolved or read here — the engine only substitutes it into the skill's own text)`, ...(facts === undefined ? {} : { facts }) };
|
|
77
|
+
}
|
|
57
78
|
if (skillCarriesRetiredManifest(s))
|
|
58
|
-
return SKILL_MANIFEST_RETIRED;
|
|
79
|
+
return { message: SKILL_MANIFEST_RETIRED };
|
|
59
80
|
for (const key of ["allowedTools", "disallowedTools"]) {
|
|
60
81
|
if (s[key] !== undefined && !skillToolListOk(s[key]))
|
|
61
|
-
return `skill.${key} must be an array of strings (permission-rule spellings: a tool name, mcp__<server> / mcp__<server>__*, Bash(<prefix>:*), Read(//<dir>/**))
|
|
82
|
+
return { message: `skill.${key} must be an array of strings (permission-rule spellings: a tool name, mcp__<server> / mcp__<server>__*, Bash(<prefix>:*), Read(//<dir>/**))` };
|
|
62
83
|
}
|
|
63
84
|
return null;
|
|
64
85
|
}
|
|
@@ -72,7 +93,7 @@ function refuseUnavailableModel(res, config, field, ref) {
|
|
|
72
93
|
const hit = refusedCatalogEntry(ref, config.modelRefusals);
|
|
73
94
|
if (hit === undefined)
|
|
74
95
|
return false;
|
|
75
|
-
const message = modelUnavailableMessage(field, ref
|
|
96
|
+
const message = modelUnavailableMessage(field, ref, hit.name, hit.refusal);
|
|
76
97
|
sendError(res, 400, "request.model_unavailable", message);
|
|
77
98
|
return true;
|
|
78
99
|
}
|
|
@@ -96,7 +117,7 @@ export function createAdmission(ctx) {
|
|
|
96
117
|
{
|
|
97
118
|
const refusal = refuseSubmitBody(sqlWallsOf(deps.sqlEngine), body);
|
|
98
119
|
if (refusal !== null) {
|
|
99
|
-
const facts = { wallSource: refusal.wallSource };
|
|
120
|
+
const facts = { ...limitFacts("body", "bytes", refusal.bytes, refusal.limitBytes), wallSource: refusal.wallSource };
|
|
100
121
|
switch (refusal.wallSource) {
|
|
101
122
|
case "reported":
|
|
102
123
|
switch (refusal.by) {
|
|
@@ -149,8 +170,8 @@ export function createAdmission(ctx) {
|
|
|
149
170
|
return null;
|
|
150
171
|
}
|
|
151
172
|
}
|
|
152
|
-
if (body.jobId !== undefined && (typeof body.jobId !== "string" || body.jobId.length === 0 || body.jobId.length >
|
|
153
|
-
sendError(res, 400, "request.field_invalid", "jobId must be a non-empty string of at most 64 characters");
|
|
173
|
+
if (body.jobId !== undefined && (typeof body.jobId !== "string" || body.jobId.length === 0 || body.jobId.length > MAX_JOB_ID_CHARS)) {
|
|
174
|
+
sendError(res, 400, "request.field_invalid", "jobId must be a non-empty string of at most 64 characters", overCharsFacts("jobId", body.jobId, MAX_JOB_ID_CHARS));
|
|
154
175
|
return null;
|
|
155
176
|
}
|
|
156
177
|
{
|
|
@@ -161,7 +182,7 @@ export function createAdmission(ctx) {
|
|
|
161
182
|
}
|
|
162
183
|
}
|
|
163
184
|
if (typeof body.systemPrompt === "string" && body.systemPrompt.length > MAX_SYSTEM_PROMPT_CHARS) {
|
|
164
|
-
sendError(res, 400, "request.field_invalid", `systemPrompt must be at most ${MAX_SYSTEM_PROMPT_CHARS} characters
|
|
185
|
+
sendError(res, 400, "request.field_invalid", `systemPrompt must be at most ${MAX_SYSTEM_PROMPT_CHARS} characters`, limitFacts("systemPrompt", "characters", body.systemPrompt.length, MAX_SYSTEM_PROMPT_CHARS));
|
|
165
186
|
return null;
|
|
166
187
|
}
|
|
167
188
|
if (body.appendSystemPrompt !== undefined) {
|
|
@@ -170,7 +191,7 @@ export function createAdmission(ctx) {
|
|
|
170
191
|
return null;
|
|
171
192
|
}
|
|
172
193
|
if (body.appendSystemPrompt.length > MAX_SYSTEM_PROMPT_CHARS) {
|
|
173
|
-
sendError(res, 400, "request.field_invalid", `appendSystemPrompt must be at most ${MAX_SYSTEM_PROMPT_CHARS} characters
|
|
194
|
+
sendError(res, 400, "request.field_invalid", `appendSystemPrompt must be at most ${MAX_SYSTEM_PROMPT_CHARS} characters`, limitFacts("appendSystemPrompt", "characters", body.appendSystemPrompt.length, MAX_SYSTEM_PROMPT_CHARS));
|
|
174
195
|
return null;
|
|
175
196
|
}
|
|
176
197
|
}
|
|
@@ -203,14 +224,12 @@ export function createAdmission(ctx) {
|
|
|
203
224
|
}
|
|
204
225
|
}
|
|
205
226
|
if (typeof st.outputStyle === "string" && st.outputStyle.length > MAX_SETTINGS_OUTPUT_STYLE_CHARS) {
|
|
206
|
-
sendError(res, 400, "request.field_invalid", `settings.outputStyle must be at most ${MAX_SETTINGS_OUTPUT_STYLE_CHARS} characters
|
|
227
|
+
sendError(res, 400, "request.field_invalid", `settings.outputStyle must be at most ${MAX_SETTINGS_OUTPUT_STYLE_CHARS} characters`, limitFacts("settings.outputStyle", "characters", st.outputStyle.length, MAX_SETTINGS_OUTPUT_STYLE_CHARS));
|
|
207
228
|
return null;
|
|
208
229
|
}
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
body.appendSystemPrompt.length + 2 + st.outputStyle.length > MAX_SYSTEM_PROMPT_CHARS) {
|
|
213
|
-
sendError(res, 400, "request.field_conflict", `appendSystemPrompt + settings.outputStyle fold into one system-prompt block — combined they must be at most ${MAX_SYSTEM_PROMPT_CHARS} characters (including the 2-char joiner)`);
|
|
230
|
+
const foldedChars = typeof st.outputStyle === "string" && st.outputStyle.length > 0 && typeof body.appendSystemPrompt === "string" ? body.appendSystemPrompt.length + 2 + st.outputStyle.length : 0;
|
|
231
|
+
if (foldedChars > MAX_SYSTEM_PROMPT_CHARS) {
|
|
232
|
+
sendError(res, 400, "request.field_conflict", `appendSystemPrompt + settings.outputStyle fold into one system-prompt block — combined they must be at most ${MAX_SYSTEM_PROMPT_CHARS} characters (including the 2-char joiner)`, fieldConflictFacts("system_prompt_fold", ["appendSystemPrompt", "settings.outputStyle"], { count: foldedChars, cap: MAX_SYSTEM_PROMPT_CHARS }));
|
|
214
233
|
return null;
|
|
215
234
|
}
|
|
216
235
|
const perms = st.permissions;
|
|
@@ -225,6 +244,13 @@ export function createAdmission(ctx) {
|
|
|
225
244
|
return null;
|
|
226
245
|
}
|
|
227
246
|
}
|
|
247
|
+
{
|
|
248
|
+
const seatIssue = tightenOnlySeatIssue(st);
|
|
249
|
+
if (seatIssue) {
|
|
250
|
+
sendError(res, 400, "request.field_invalid", seatIssue.message, seatIssue.fields);
|
|
251
|
+
return null;
|
|
252
|
+
}
|
|
253
|
+
}
|
|
228
254
|
const envRaw = st.env;
|
|
229
255
|
if (envRaw !== undefined && envRaw !== null) {
|
|
230
256
|
if (typeof envRaw !== "object" || Array.isArray(envRaw)) {
|
|
@@ -233,12 +259,16 @@ export function createAdmission(ctx) {
|
|
|
233
259
|
}
|
|
234
260
|
const entries = Object.entries(envRaw);
|
|
235
261
|
if (entries.length > MAX_SETTINGS_ENV_VARS) {
|
|
236
|
-
sendError(res, 400, "request.field_invalid", `settings.env must have at most ${MAX_SETTINGS_ENV_VARS} variables
|
|
262
|
+
sendError(res, 400, "request.field_invalid", `settings.env must have at most ${MAX_SETTINGS_ENV_VARS} variables`, limitFacts("settings.env", "entries", entries.length, MAX_SETTINGS_ENV_VARS));
|
|
237
263
|
return null;
|
|
238
264
|
}
|
|
239
265
|
for (const [k, val] of entries) {
|
|
240
|
-
|
|
241
|
-
|
|
266
|
+
const keyOver = k.length > MAX_SETTINGS_ENV_KEY_CHARS;
|
|
267
|
+
const valueOver = typeof val === "string" && val.length > MAX_SETTINGS_ENV_VALUE_CHARS;
|
|
268
|
+
if (keyOver || valueOver) {
|
|
269
|
+
const field = `settings.env.${echoCallerText(k, { maxChars: MAX_SETTINGS_ENV_KEY_CHARS })}`;
|
|
270
|
+
const facts = keyOver ? limitFacts(field, "characters", k.length, MAX_SETTINGS_ENV_KEY_CHARS) : limitFacts(field, "characters", val.length, MAX_SETTINGS_ENV_VALUE_CHARS);
|
|
271
|
+
sendError(res, 400, "request.field_invalid", `settings.env keys must be ≤${MAX_SETTINGS_ENV_KEY_CHARS} chars and values ≤${MAX_SETTINGS_ENV_VALUE_CHARS} chars`, facts);
|
|
242
272
|
return null;
|
|
243
273
|
}
|
|
244
274
|
}
|
|
@@ -284,13 +314,14 @@ export function createAdmission(ctx) {
|
|
|
284
314
|
}
|
|
285
315
|
if (Array.isArray(body.images)) {
|
|
286
316
|
if (body.images.length > MAX_IMAGES_PER_REQUEST) {
|
|
287
|
-
sendError(res, 413, "request.payload_too_large", `at most ${MAX_IMAGES_PER_REQUEST} images per request
|
|
317
|
+
sendError(res, 413, "request.payload_too_large", `at most ${MAX_IMAGES_PER_REQUEST} images per request`, limitFacts("images", "entries", body.images.length, MAX_IMAGES_PER_REQUEST));
|
|
288
318
|
return null;
|
|
289
319
|
}
|
|
290
|
-
for (const img of body.images) {
|
|
320
|
+
for (const [i, img] of body.images.entries()) {
|
|
291
321
|
const data = img.data;
|
|
292
|
-
|
|
293
|
-
|
|
322
|
+
const dataBytes = typeof data === "string" ? Buffer.byteLength(data, "utf8") : 0;
|
|
323
|
+
if (dataBytes > MAX_IMAGE_BASE64_BYTES) {
|
|
324
|
+
sendError(res, 413, "request.payload_too_large", `each inline image must be at most ${MAX_IMAGE_BASE64_BYTES} base64 bytes (the engine's inline-image limit — the model API's 5 MB image cap)`, limitFacts(`images[${i}].data`, "bytes", dataBytes, MAX_IMAGE_BASE64_BYTES));
|
|
294
325
|
return null;
|
|
295
326
|
}
|
|
296
327
|
}
|
|
@@ -301,17 +332,17 @@ export function createAdmission(ctx) {
|
|
|
301
332
|
sendError(res, 400, "request.field_invalid", "clientContext must be an object");
|
|
302
333
|
return null;
|
|
303
334
|
}
|
|
304
|
-
if (cc.timeZone !== undefined && (typeof cc.timeZone !== "string" || cc.timeZone.length >
|
|
305
|
-
sendError(res, 400, "request.field_invalid", "clientContext.timeZone must be a string of at most 64 characters");
|
|
335
|
+
if (cc.timeZone !== undefined && (typeof cc.timeZone !== "string" || cc.timeZone.length > MAX_CLIENT_TIMEZONE_CHARS)) {
|
|
336
|
+
sendError(res, 400, "request.field_invalid", "clientContext.timeZone must be a string of at most 64 characters", overCharsFacts("clientContext.timeZone", cc.timeZone, MAX_CLIENT_TIMEZONE_CHARS));
|
|
306
337
|
return null;
|
|
307
338
|
}
|
|
308
|
-
if (cc.userEmail !== undefined && (typeof cc.userEmail !== "string" || cc.userEmail.length >
|
|
309
|
-
sendError(res, 400, "request.field_invalid", "clientContext.userEmail must be a string of at most 256 characters");
|
|
339
|
+
if (cc.userEmail !== undefined && (typeof cc.userEmail !== "string" || cc.userEmail.length > MAX_CLIENT_USER_EMAIL_CHARS)) {
|
|
340
|
+
sendError(res, 400, "request.field_invalid", "clientContext.userEmail must be a string of at most 256 characters", overCharsFacts("clientContext.userEmail", cc.userEmail, MAX_CLIENT_USER_EMAIL_CHARS));
|
|
310
341
|
return null;
|
|
311
342
|
}
|
|
312
343
|
}
|
|
313
|
-
if (body.sandboxImageProfile !== undefined && (typeof body.sandboxImageProfile !== "string" || body.sandboxImageProfile.length === 0 || body.sandboxImageProfile.length >
|
|
314
|
-
sendError(res, 400, "request.field_invalid", "sandboxImageProfile must be a non-empty string of at most 128 characters");
|
|
344
|
+
if (body.sandboxImageProfile !== undefined && (typeof body.sandboxImageProfile !== "string" || body.sandboxImageProfile.length === 0 || body.sandboxImageProfile.length > MAX_SANDBOX_IMAGE_PROFILE_CHARS)) {
|
|
345
|
+
sendError(res, 400, "request.field_invalid", "sandboxImageProfile must be a non-empty string of at most 128 characters", overCharsFacts("sandboxImageProfile", body.sandboxImageProfile, MAX_SANDBOX_IMAGE_PROFILE_CHARS));
|
|
315
346
|
return null;
|
|
316
347
|
}
|
|
317
348
|
if (body.capabilitiesNeeded !== undefined && (!Array.isArray(body.capabilitiesNeeded) || body.capabilitiesNeeded.some((c) => typeof c !== "string"))) {
|
|
@@ -319,11 +350,11 @@ export function createAdmission(ctx) {
|
|
|
319
350
|
return null;
|
|
320
351
|
}
|
|
321
352
|
if (Array.isArray(body.capabilitiesNeeded) && body.capabilitiesNeeded.length > 0 && (typeof body.sandboxImageProfile !== "string" || body.sandboxImageProfile.length === 0)) {
|
|
322
|
-
sendError(res, 400, "request.field_conflict", "capabilitiesNeeded requires sandboxImageProfile (it constrains the selected image)");
|
|
353
|
+
sendError(res, 400, "request.field_conflict", "capabilitiesNeeded requires sandboxImageProfile (it constrains the selected image)", fieldConflictFacts("image_profile", ["capabilitiesNeeded", "sandboxImageProfile"]));
|
|
323
354
|
return null;
|
|
324
355
|
}
|
|
325
356
|
if (typeof body.sandboxImageProfile === "string" && body.sandboxImageProfile.length > 0 && (body.cascade === true || body.verify === true)) {
|
|
326
|
-
sendError(res, 400, "request.field_conflict", "sandboxImageProfile is not supported together with cascade/verify in v1 (the per-task image would not bind to the cascade rungs / verifier sub-run)");
|
|
357
|
+
sendError(res, 400, "request.field_conflict", "sandboxImageProfile is not supported together with cascade/verify in v1 (the per-task image would not bind to the cascade rungs / verifier sub-run)", fieldConflictFacts("cascade_verify", ["sandboxImageProfile", ...multiAttemptFields(body)]));
|
|
327
358
|
return null;
|
|
328
359
|
}
|
|
329
360
|
if (body.outputSchema !== undefined) {
|
|
@@ -331,8 +362,9 @@ export function createAdmission(ctx) {
|
|
|
331
362
|
sendError(res, 400, "request.field_invalid", "outputSchema must be a JSON Schema object");
|
|
332
363
|
return null;
|
|
333
364
|
}
|
|
334
|
-
|
|
335
|
-
|
|
365
|
+
const schemaChars = JSON.stringify(body.outputSchema).length;
|
|
366
|
+
if (schemaChars > MAX_OUTPUT_SCHEMA_CHARS) {
|
|
367
|
+
sendError(res, 400, "request.field_invalid", `outputSchema must serialize to at most ${MAX_OUTPUT_SCHEMA_CHARS} characters`, limitFacts("outputSchema", "characters", schemaChars, MAX_OUTPUT_SCHEMA_CHARS));
|
|
336
368
|
return null;
|
|
337
369
|
}
|
|
338
370
|
}
|
|
@@ -341,12 +373,12 @@ export function createAdmission(ctx) {
|
|
|
341
373
|
return null;
|
|
342
374
|
}
|
|
343
375
|
if (body.resumeAt !== undefined) {
|
|
344
|
-
if (typeof body.resumeAt !== "string" || body.resumeAt.length === 0 || body.resumeAt.length >
|
|
345
|
-
sendError(res, 400, "request.field_invalid", "resumeAt must be a non-empty message eventId string (≤64 chars)");
|
|
376
|
+
if (typeof body.resumeAt !== "string" || body.resumeAt.length === 0 || body.resumeAt.length > MAX_RESUME_AT_CHARS) {
|
|
377
|
+
sendError(res, 400, "request.field_invalid", "resumeAt must be a non-empty message eventId string (≤64 chars)", overCharsFacts("resumeAt", body.resumeAt, MAX_RESUME_AT_CHARS));
|
|
346
378
|
return null;
|
|
347
379
|
}
|
|
348
380
|
if (body.verify === true || body.cascade === true) {
|
|
349
|
-
sendError(res, 400, "request.field_conflict", "resumeAt is not supported with verify or cascade (those start a fresh/replaced session)");
|
|
381
|
+
sendError(res, 400, "request.field_conflict", "resumeAt is not supported with verify or cascade (those start a fresh/replaced session)", fieldConflictFacts("cascade_verify", ["resumeAt", ...multiAttemptFields(body)]));
|
|
350
382
|
return null;
|
|
351
383
|
}
|
|
352
384
|
}
|
|
@@ -356,7 +388,7 @@ export function createAdmission(ctx) {
|
|
|
356
388
|
return null;
|
|
357
389
|
}
|
|
358
390
|
if (body.resumeAt === undefined) {
|
|
359
|
-
sendError(res, 400, "request.field_conflict", "resumeAtMode requires resumeAt (it qualifies the rewind target)");
|
|
391
|
+
sendError(res, 400, "request.field_conflict", "resumeAtMode requires resumeAt (it qualifies the rewind target)", fieldConflictFacts("resume_anchor", ["resumeAtMode", "resumeAt"]));
|
|
360
392
|
return null;
|
|
361
393
|
}
|
|
362
394
|
}
|
|
@@ -407,7 +439,7 @@ export function createAdmission(ctx) {
|
|
|
407
439
|
}
|
|
408
440
|
}
|
|
409
441
|
if (fileHistoryRestoreConflict(body)) {
|
|
410
|
-
sendError(res, 400, "request.field_conflict", FILE_HISTORY_DISABLED_NO_RESTORE);
|
|
442
|
+
sendError(res, 400, "request.field_conflict", FILE_HISTORY_DISABLED_NO_RESTORE, fieldConflictFacts("file_history_restore", ["fileHistory", ...fileHistoryRestoreKeysInBody(body)]));
|
|
411
443
|
return null;
|
|
412
444
|
}
|
|
413
445
|
if (body.requireExistingSession !== undefined && typeof body.requireExistingSession !== "boolean") {
|
|
@@ -514,7 +546,7 @@ export function createAdmission(ctx) {
|
|
|
514
546
|
if (um !== undefined && refuseUnavailableModel(res, deps.config, `agents[${um.index}].model`, um.ref))
|
|
515
547
|
return null;
|
|
516
548
|
if (um !== undefined) {
|
|
517
|
-
sendError(res, 400, "request.unknown_reference", `unknown agents[${um.index}].model "${um.ref
|
|
549
|
+
sendError(res, 400, "request.unknown_reference", `unknown agents[${um.index}].model "${echoModelRef(um.ref)}" — not in the configured catalog (a catalog name or tier word)`, { available: mentionableNames(deps.config, agentsCatalog) });
|
|
518
550
|
return null;
|
|
519
551
|
}
|
|
520
552
|
}
|
|
@@ -541,9 +573,12 @@ export function createAdmission(ctx) {
|
|
|
541
573
|
return null;
|
|
542
574
|
}
|
|
543
575
|
}
|
|
544
|
-
if (body.disableSkills === true
|
|
545
|
-
|
|
546
|
-
|
|
576
|
+
if (body.disableSkills === true) {
|
|
577
|
+
const skillSeats = [...((body.skills?.length ?? 0) > 0 ? ["skills"] : []), ...(body.agents ?? []).flatMap((a, i) => ((a.skills?.length ?? 0) > 0 ? [`agents[${i}].skills`] : []))];
|
|
578
|
+
if (skillSeats.length > 0) {
|
|
579
|
+
sendError(res, 400, "request.field_conflict", "disableSkills: true means this run installs no skill at all (not the deployment's, not the request's), so it cannot come with a non-empty skills or agents[].skills — send one or the other", fieldConflictFacts("skills_disabled", ["disableSkills", ...skillSeats]));
|
|
580
|
+
return null;
|
|
581
|
+
}
|
|
547
582
|
}
|
|
548
583
|
{
|
|
549
584
|
const v = body.userInvokedSkills;
|
|
@@ -608,7 +643,7 @@ export function createAdmission(ctx) {
|
|
|
608
643
|
if (matchCatalogModel(body.model, catalog, deps.config.modelRefusals) === undefined) {
|
|
609
644
|
if (refuseUnavailableModel(res, deps.config, "model", body.model))
|
|
610
645
|
return null;
|
|
611
|
-
sendError(res, 400, "request.unknown_reference", `unknown model "${body.model
|
|
646
|
+
sendError(res, 400, "request.unknown_reference", `unknown model "${echoModelRef(body.model)}" — not in the configured catalog (name, tier word, or id)`, { available: mentionableNames(deps.config, catalog) });
|
|
612
647
|
return null;
|
|
613
648
|
}
|
|
614
649
|
}
|
|
@@ -622,7 +657,7 @@ export function createAdmission(ctx) {
|
|
|
622
657
|
if (matchCatalogModel(body.compactionModel, catalog, deps.config.modelRefusals) === undefined) {
|
|
623
658
|
if (refuseUnavailableModel(res, deps.config, "compactionModel", body.compactionModel))
|
|
624
659
|
return null;
|
|
625
|
-
sendError(res, 400, "request.unknown_reference", `unknown compactionModel "${body.compactionModel
|
|
660
|
+
sendError(res, 400, "request.unknown_reference", `unknown compactionModel "${echoModelRef(body.compactionModel)}" — not in the configured catalog (name, tier word, or id)`, { available: mentionableNames(deps.config, catalog) });
|
|
626
661
|
return null;
|
|
627
662
|
}
|
|
628
663
|
}
|
|
@@ -663,17 +698,24 @@ export function createAdmission(ctx) {
|
|
|
663
698
|
const verify = verifyRoundsFromBody(body);
|
|
664
699
|
const cascade = body.cascade === true;
|
|
665
700
|
if (cascade && verify) {
|
|
666
|
-
sendError(res, 400, "request.field_conflict", "verify and cascade are mutually exclusive (verify = adversarial gate; cascade = cheap→strong ladder)");
|
|
701
|
+
sendError(res, 400, "request.field_conflict", "verify and cascade are mutually exclusive (verify = adversarial gate; cascade = cheap→strong ladder)", fieldConflictFacts("cascade_verify", ["verify", "cascade"]));
|
|
667
702
|
return null;
|
|
668
703
|
}
|
|
669
704
|
if (body.suggestNextPrompts && (verify || cascade)) {
|
|
670
|
-
sendError(res, 400, "request.field_conflict", "suggestNextPrompts is not supported with verify or cascade (those return a result, not a streamed run)");
|
|
705
|
+
sendError(res, 400, "request.field_conflict", "suggestNextPrompts is not supported with verify or cascade (those return a result, not a streamed run)", fieldConflictFacts("cascade_verify", ["suggestNextPrompts", ...multiAttemptFields(body)]));
|
|
671
706
|
return null;
|
|
672
707
|
}
|
|
673
708
|
if (cascade && deps.config.cascadeLadder.length === 0) {
|
|
674
709
|
sendError(res, 400, "request.precondition_unmet", "cascade requested but no ladder configured — set MODEL_CASCADE_LADDER (catalog model names, cheapest→strongest)");
|
|
675
710
|
return null;
|
|
676
711
|
}
|
|
712
|
+
{
|
|
713
|
+
const refusal = requestTrustRefusal({ permissions: parseTaskSettings(body.settings).settings?.permissions, skills: body.skills, userInvokedSkills: body.userInvokedSkills }, callerTrust(req, deps.config));
|
|
714
|
+
if (refusal !== undefined) {
|
|
715
|
+
sendError(res, 400, "request.field_invalid", refusal.message, refusal.facts);
|
|
716
|
+
return null;
|
|
717
|
+
}
|
|
718
|
+
}
|
|
677
719
|
const { body: admitted, entry: entryMode } = stampEntryPermissionMode(body, autonomyModeFloor(deps.config.autonomy));
|
|
678
720
|
try {
|
|
679
721
|
const auth = deps.authorize ? await deps.authorize({ req, body: admitted }) : undefined;
|
|
@@ -691,7 +733,8 @@ export function createAdmission(ctx) {
|
|
|
691
733
|
const acceptance = createRunAcceptance({ sessionTitler: deps.sessionTitler }, { ...(spec.sessionId ? { sessionId: spec.sessionId } : {}), objective: spec.objective, ...(model !== undefined ? { model } : {}) });
|
|
692
734
|
const clampNotice = buildEntryModeClampNotice(entryMode, spec.sessionId);
|
|
693
735
|
const pendingNotices = clampNotice !== undefined ? [clampNotice, ...engineNotices] : engineNotices;
|
|
694
|
-
|
|
736
|
+
const warnings = allowSelectorWarningsOf(admitted, spec.tools ?? []);
|
|
737
|
+
return { spec, runner: runnerFor(spec), auth, verify, cascade, jobId: admitted.jobId, body: admitted, acceptance, ...(bindingIntent === undefined ? {} : { bindingIntent }), ...(pendingNotices.length > 0 ? { engineNotices: pendingNotices } : {}), ...(warnings.length > 0 ? { warnings } : {}) };
|
|
695
738
|
}
|
|
696
739
|
catch (err) {
|
|
697
740
|
if (err instanceof HttpError) {
|