@sema-agent/server 7.132.0 → 7.134.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 +353 -0
- package/README.md +8 -9
- package/README.zh-CN.md +7 -6
- package/USAGE.md +301 -64
- package/deploy/sema-up/README.md +35 -1
- package/deploy/sema-up/chart/Chart.yaml +1 -1
- package/deploy/sema-up/chart/templates/NOTES.txt +15 -0
- package/deploy/sema-up/chart/templates/_helpers.tpl +129 -0
- package/deploy/sema-up/chart/templates/sealed-key.yaml +24 -0
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +19 -2
- package/deploy/sema-up/chart/templates/server.yaml +19 -2
- package/deploy/sema-up/chart/values-full-single.yaml +5 -1
- package/deploy/sema-up/chart/values.yaml +34 -0
- 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 +32 -14
- 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 +83 -23
- package/dist/approval-card.js +45 -15
- package/dist/approval-content-kind.d.ts +5 -2
- package/dist/approval-content-kind.js +16 -3
- package/dist/approval-deny-reasons.d.ts +1 -1
- package/dist/approval-gate-currency.d.ts +72 -0
- package/dist/approval-gate-currency.js +94 -0
- package/dist/approval.d.ts +15 -0
- package/dist/approval.js +55 -17
- package/dist/audit.d.ts +27 -10
- package/dist/audit.js +12 -16
- package/dist/bake-runner/main.js +3 -2
- package/dist/boot/coordinators.d.ts +6 -1
- package/dist/boot/coordinators.js +6 -3
- 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.d.ts +2 -0
- package/dist/boot/leader.js +4 -1
- 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/read-deny-anchor-audit.js +2 -2
- 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.d.ts +18 -5
- package/dist/boot/runner-deps.js +10 -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 +6 -3
- package/dist/boot/stage-06-runners.js +20 -4
- package/dist/boot/stage-07-capability-layer.d.ts +4 -1
- package/dist/boot/stage-07-capability-layer.js +24 -3
- package/dist/boot/stage-08-reapers.d.ts +4 -1
- package/dist/boot/stage-08-reapers.js +2 -2
- package/dist/boot/stage-09-leader.d.ts +5 -1
- package/dist/boot/stage-09-leader.js +2 -2
- package/dist/boot/stage-10-http-server.d.ts +5 -1
- package/dist/boot/stage-10-http-server.js +6 -6
- package/dist/boot/stores.d.ts +8 -0
- package/dist/boot/stores.js +10 -14
- package/dist/boot/web-admin.d.ts +10 -0
- package/dist/boot/web-admin.js +162 -65
- 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/budget.js +5 -1
- package/dist/caller-text-echo.d.ts +11 -6
- package/dist/caller-text-echo.js +10 -12
- package/dist/canonical-json.d.ts +2 -41
- package/dist/canonical-json.js +2 -13
- 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 +29 -6
- package/dist/capabilities/scenarios.d.ts +63 -7
- package/dist/capabilities/scenarios.js +39 -7
- package/dist/capability-facts.d.ts +36 -4
- package/dist/capability-facts.js +30 -4
- package/dist/center-config-tier.d.ts +69 -0
- package/dist/center-config-tier.js +42 -0
- package/dist/checkpoint-ctx-seal-m28.d.ts +42 -0
- package/dist/checkpoint-ctx-seal-m28.js +19 -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 +44 -0
- package/dist/field-conflict.js +21 -0
- package/dist/file-history-disclosure.d.ts +34 -5
- package/dist/file-history-disclosure.js +2 -2
- package/dist/fleet/fleet-bus.d.ts +84 -6
- package/dist/fleet/fleet-bus.js +42 -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 +111 -60
- package/dist/http/approval-sweeps.js +58 -19
- package/dist/http/caller-trust.d.ts +77 -0
- package/dist/http/caller-trust.js +143 -0
- package/dist/http/checkpoint-ctx.d.ts +173 -18
- package/dist/http/checkpoint-ctx.js +171 -12
- 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 +13 -7
- package/dist/http/durable-run-leg.d.ts +4 -32
- package/dist/http/durable-run-leg.js +37 -12
- package/dist/http/idempotency.d.ts +2 -2
- package/dist/http/idempotency.js +2 -2
- package/dist/http/owner-access.d.ts +56 -0
- package/dist/http/owner-access.js +42 -0
- package/dist/http/principal-gate.d.ts +78 -27
- package/dist/http/principal-gate.js +64 -14
- package/dist/http/readiness.d.ts +11 -5
- package/dist/http/readiness.js +10 -3
- package/dist/http/refusal-body.d.ts +12 -0
- package/dist/http/refusal-body.js +11 -0
- package/dist/http/request-guards.d.ts +16 -32
- package/dist/http/request-guards.js +31 -30
- package/dist/http/resume-ctx-read.d.ts +50 -6
- package/dist/http/resume-ctx-read.js +33 -7
- package/dist/http/resume-legs.d.ts +5 -5
- package/dist/http/resume-legs.js +163 -91
- 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 -37
- 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/agents-roster.js +2 -3
- package/dist/http/routes/approvals-assistant.js +91 -56
- 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.d.ts +3 -3
- package/dist/http/routes/diagnostics.js +6 -2
- package/dist/http/routes/fleet.js +4 -4
- 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.d.ts +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 +9 -22
- package/dist/http/routes/runs.d.ts +5 -0
- package/dist/http/routes/runs.js +63 -115
- package/dist/http/routes/session-sync.d.ts +3 -2
- package/dist/http/routes/session-sync.js +53 -48
- package/dist/http/routes/sessions-list.d.ts +1 -1
- package/dist/http/routes/sessions-list.js +3 -4
- package/dist/http/routes/sessions.js +33 -43
- package/dist/http/routes/side-query.js +6 -4
- package/dist/http/routes/tasks.js +71 -30
- package/dist/http/routes/trace-usage.js +7 -9
- package/dist/http/routes/workflows.d.ts +351 -0
- package/dist/http/routes/workflows.js +153 -119
- package/dist/http/run-declared-families.d.ts +16 -0
- package/dist/http/run-declared-families.js +12 -0
- package/dist/http/send.d.ts +24 -3
- package/dist/http/send.js +14 -2
- package/dist/http/server.d.ts +23 -18
- package/dist/http/server.js +20 -15
- package/dist/http/stored-body-replay.js +17 -4
- package/dist/http/submit-ctx.d.ts +4 -3
- package/dist/http/submit-ctx.js +23 -6
- package/dist/http/submit-replay.d.ts +4 -3
- package/dist/http/submit-replay.js +5 -4
- package/dist/http/wire-types.d.ts +17 -10
- package/dist/index.d.ts +3 -1
- package/dist/index.js +1 -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/leader/wire.d.ts +4 -0
- package/dist/leader/wire.js +8 -7
- package/dist/limit-refusal.d.ts +17 -5
- package/dist/limit-refusal.js +4 -1
- package/dist/main.js +1 -1
- package/dist/mcp-assertion-header.d.ts +31 -10
- package/dist/mcp-assertion-header.js +10 -3
- package/dist/memory-origin-fence.js +2 -2
- 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-compat.d.ts +1 -1
- 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 +22 -25
- package/dist/observability/prompt-manifest.js +54 -50
- package/dist/observability/tool-trace.js +9 -10
- 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 +119 -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 +43 -11
- package/dist/parked-decide.js +100 -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/permission-rule-vocab.d.ts +1 -23
- package/dist/permission-rule-vocab.js +0 -13
- 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/approval-payload-fingerprint.d.ts +14 -6
- package/dist/plugins/approval-payload-fingerprint.js +1 -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 +4 -1
- package/dist/plugins/caching-session-store.js +7 -3
- package/dist/plugins/checkpoint-store-sql.d.ts +36 -1
- package/dist/plugins/checkpoint-store-sql.js +65 -3
- 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 +15 -2
- package/dist/plugins/local-checkpoint-store.js +32 -1
- package/dist/plugins/local-session-store.d.ts +13 -10
- package/dist/plugins/local-session-store.js +23 -14
- package/dist/plugins/local-session-window.d.ts +45 -0
- package/dist/plugins/local-session-window.js +38 -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 +121 -5
- package/dist/plugins/one-time-migrations.js +332 -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/permission-rule-store-file.js +10 -6
- package/dist/plugins/permission-rule-store-sql.js +8 -8
- package/dist/plugins/pg-pool.js +39 -7
- package/dist/plugins/pg-session-storage.d.ts +18 -5
- package/dist/plugins/pg-session-storage.js +68 -23
- package/dist/plugins/remote-env-adb.d.ts +6 -12
- package/dist/plugins/remote-env-adb.js +12 -2
- package/dist/plugins/remote-env-device.d.ts +14 -7
- package/dist/plugins/remote-env-device.js +23 -15
- 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-ownership.d.ts +11 -0
- package/dist/plugins/session-ownership.js +11 -0
- package/dist/plugins/session-placement.d.ts +12 -14
- package/dist/plugins/session-placement.js +2 -15
- 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 +25 -5
- package/dist/plugins/tidb-session-store.js +67 -21
- 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-tool-axes.d.ts +12 -0
- package/dist/request-tool-axes.js +20 -0
- 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 +37 -6
- package/dist/runs.d.ts +12 -10
- package/dist/runs.js +25 -6
- 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/sealed-key.d.ts +32 -0
- package/dist/sealed-key.js +55 -1
- package/dist/security.d.ts +95 -15
- package/dist/security.js +52 -9
- package/dist/session-error-wire.d.ts +31 -7
- package/dist/session-error-wire.js +9 -2
- package/dist/session-sync-kernel.d.ts +37 -10
- package/dist/session-sync-kernel.js +10 -0
- 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-a2a.js +4 -3
- package/dist/task-cwd.d.ts +1 -1
- package/dist/task-mcp.d.ts +5 -5
- package/dist/task-mcp.js +27 -74
- package/dist/task-settings.d.ts +93 -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 +451 -136
- package/dist/tool-approval.js +733 -256
- package/dist/tool-rule-names.d.ts +6 -0
- package/dist/trace/core-keyset-guard.d.ts +108 -25
- package/dist/trace/exit-seat.d.ts +40 -0
- package/dist/trace/exit-seat.js +130 -0
- package/dist/trace/ledger-events.d.ts +6 -3
- package/dist/trace/project.d.ts +98 -13
- package/dist/trace/project.js +57 -32
- package/dist/trace/projection-table.d.ts +100 -0
- package/dist/trace/projection-table.js +130 -0
- package/dist/trace/redact.d.ts +57 -0
- package/dist/trace/redact.js +962 -168
- package/dist/trace/self-minted-wire.d.ts +349 -1
- package/dist/trace/self-minted-wire.js +118 -1
- package/dist/trace/wire-projection-faces.d.ts +304 -2
- package/dist/trace/wire-projection-faces.js +160 -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.d.ts +1 -1
- package/dist/web-admin-client/skills-mcp.js +6 -8
- package/dist/web-admin-client/types.d.ts +1 -1
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +57 -9
- package/package.json +8 -4
- package/scripts/drain-check-local.mjs +34 -2
- package/scripts/drain-check.mysql.sql +20 -2
- package/scripts/drain-check.pg.sql +20 -2
- package/dist/mcp-tool-faces.d.ts +0 -69
- package/dist/mcp-tool-faces.js +0 -106
|
@@ -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,27 @@
|
|
|
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";
|
|
7
|
+
import { approvalFrameFamiliesIssue } from "../tool-approval.js";
|
|
6
8
|
import { buildEntryModeClampNotice } from "../entry-mode-clamp-notice.js";
|
|
7
9
|
import { autonomyModeFloor } from "../runtime-governance.js";
|
|
8
10
|
import { taskBodyKeyIssue } from "../request-key-closure.js";
|
|
9
|
-
import { FILE_HISTORY_DISABLED_NO_RESTORE, fileHistoryRestoreConflict, inheritEnvFieldIssue, singleMemberOffFieldIssue } from "../request-value-closure.js";
|
|
11
|
+
import { FILE_HISTORY_DISABLED_NO_RESTORE, fileHistoryRestoreConflict, fileHistoryRestoreKeysInBody, inheritEnvFieldIssue, singleMemberOffFieldIssue } from "../request-value-closure.js";
|
|
10
12
|
import * as facts from "../capability-facts.js";
|
|
11
13
|
import { buildHooksRefusal, parseHooksConfig, hooksMatcherIssue } from "../hooks/hook-runner.js";
|
|
12
14
|
import { judgeRequestWebSearch } from "../plugins/web-search.js";
|
|
13
15
|
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 {
|
|
16
|
+
import { allowSelectorWarningsOf, skillToolListsOverCap } from "../rule-entry-list.js";
|
|
17
|
+
import { limitFacts, limitRefusal } from "../limit-refusal.js";
|
|
18
|
+
import { fieldConflictFacts } from "../field-conflict.js";
|
|
19
|
+
import { echoCallerText, quotedCallerText } from "../caller-text-echo.js";
|
|
17
20
|
import { MAX_ADDITIONAL_DIRS } from "../task-cwd.js";
|
|
18
21
|
import { verifyRoundsFromBody } from "./verify-rounds.js";
|
|
19
22
|
import { skillCarriesRetiredManifest } from "./retired-skill-manifest.js";
|
|
20
23
|
import { resolveDevicePlacementIntent } from "./device-placement.js";
|
|
24
|
+
import { callerTrust, requestTrustRefusal } from "./caller-trust.js";
|
|
21
25
|
import { createRunAcceptance } from "../run-acceptance.js";
|
|
22
26
|
import { sendError, sendHttpError } from "./send.js";
|
|
23
27
|
import { refuseSubmitBody } from "./request-guards.js";
|
|
@@ -27,38 +31,56 @@ const APPROVAL_REACH_WORDS = APPROVAL_REACH.map((word) => JSON.stringify(word)).
|
|
|
27
31
|
export const MAX_SKILL_CONTENT_CHARS = 1_048_576;
|
|
28
32
|
export const MAX_SYSTEM_PROMPT_CHARS = 16_384;
|
|
29
33
|
export const MAX_OUTPUT_SCHEMA_CHARS = 32_768;
|
|
34
|
+
const MAX_JOB_ID_CHARS = 64;
|
|
35
|
+
const MAX_CLIENT_TIMEZONE_CHARS = 64;
|
|
36
|
+
const MAX_CLIENT_USER_EMAIL_CHARS = 256;
|
|
37
|
+
const MAX_SANDBOX_IMAGE_PROFILE_CHARS = 128;
|
|
38
|
+
const MAX_RESUME_AT_CHARS = 64;
|
|
39
|
+
const overCharsFacts = (field, v, cap) => (typeof v === "string" && v.length > cap ? limitFacts(field, "characters", v.length, cap) : undefined);
|
|
40
|
+
const multiAttemptFields = (body) => {
|
|
41
|
+
const out = [];
|
|
42
|
+
if (body.verify === true)
|
|
43
|
+
out.push("verify");
|
|
44
|
+
if (body.cascade === true)
|
|
45
|
+
out.push("cascade");
|
|
46
|
+
return out;
|
|
47
|
+
};
|
|
30
48
|
export function validateUserSkills(skills) {
|
|
31
49
|
if (skills === undefined)
|
|
32
50
|
return null;
|
|
33
51
|
if (!Array.isArray(skills))
|
|
34
52
|
return { message: "skills must be an array of { name, description, content }" };
|
|
35
53
|
for (let k = 0; k < skills.length; k++) {
|
|
36
|
-
const shape = userSkillShapeIssue(skills[k]);
|
|
54
|
+
const shape = userSkillShapeIssue(skills[k], k);
|
|
37
55
|
if (shape !== null)
|
|
38
|
-
return
|
|
56
|
+
return shape;
|
|
39
57
|
const over = skillToolListsOverCap(skills[k], `skills[${k}]`, "top");
|
|
40
58
|
if (over !== undefined)
|
|
41
59
|
return { message: over.message, ...(over.extra !== undefined ? { facts: over.extra } : {}) };
|
|
42
60
|
}
|
|
43
61
|
return null;
|
|
44
62
|
}
|
|
45
|
-
function userSkillShapeIssue(item) {
|
|
63
|
+
function userSkillShapeIssue(item, index) {
|
|
46
64
|
if (item === null || typeof item !== "object")
|
|
47
|
-
return "each skill must be an object { name, description, content }";
|
|
65
|
+
return { message: "each skill must be an object { name, description, content }" };
|
|
48
66
|
const s = item;
|
|
49
67
|
if (typeof s["name"] !== "string" || s["name"].length === 0)
|
|
50
|
-
return "skill.name must be a non-empty string";
|
|
68
|
+
return { message: "skill.name must be a non-empty string" };
|
|
51
69
|
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
|
-
|
|
70
|
+
return { message: "skill.description must be a string" };
|
|
71
|
+
if (typeof s["content"] !== "string" || s["content"].length === 0 || s["content"].length > MAX_SKILL_CONTENT_CHARS) {
|
|
72
|
+
const facts = overCharsFacts(`skills[${index}].content`, s["content"], MAX_SKILL_CONTENT_CHARS);
|
|
73
|
+
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 }) };
|
|
74
|
+
}
|
|
75
|
+
if (s["baseDir"] !== undefined && !isAbsoluteHostPath(s["baseDir"])) {
|
|
76
|
+
const facts = overCharsFacts(`skills[${index}].baseDir`, s["baseDir"], ABSOLUTE_HOST_PATH_MAX);
|
|
77
|
+
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 }) };
|
|
78
|
+
}
|
|
57
79
|
if (skillCarriesRetiredManifest(s))
|
|
58
|
-
return SKILL_MANIFEST_RETIRED;
|
|
80
|
+
return { message: SKILL_MANIFEST_RETIRED };
|
|
59
81
|
for (const key of ["allowedTools", "disallowedTools"]) {
|
|
60
82
|
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>/**))
|
|
83
|
+
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
84
|
}
|
|
63
85
|
return null;
|
|
64
86
|
}
|
|
@@ -72,7 +94,7 @@ function refuseUnavailableModel(res, config, field, ref) {
|
|
|
72
94
|
const hit = refusedCatalogEntry(ref, config.modelRefusals);
|
|
73
95
|
if (hit === undefined)
|
|
74
96
|
return false;
|
|
75
|
-
const message = modelUnavailableMessage(field, ref
|
|
97
|
+
const message = modelUnavailableMessage(field, ref, hit.name, hit.refusal);
|
|
76
98
|
sendError(res, 400, "request.model_unavailable", message);
|
|
77
99
|
return true;
|
|
78
100
|
}
|
|
@@ -96,7 +118,7 @@ export function createAdmission(ctx) {
|
|
|
96
118
|
{
|
|
97
119
|
const refusal = refuseSubmitBody(sqlWallsOf(deps.sqlEngine), body);
|
|
98
120
|
if (refusal !== null) {
|
|
99
|
-
const facts = { wallSource: refusal.wallSource };
|
|
121
|
+
const facts = { ...limitFacts("body", "bytes", refusal.bytes, refusal.limitBytes), wallSource: refusal.wallSource };
|
|
100
122
|
switch (refusal.wallSource) {
|
|
101
123
|
case "reported":
|
|
102
124
|
switch (refusal.by) {
|
|
@@ -149,8 +171,8 @@ export function createAdmission(ctx) {
|
|
|
149
171
|
return null;
|
|
150
172
|
}
|
|
151
173
|
}
|
|
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");
|
|
174
|
+
if (body.jobId !== undefined && (typeof body.jobId !== "string" || body.jobId.length === 0 || body.jobId.length > MAX_JOB_ID_CHARS)) {
|
|
175
|
+
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
176
|
return null;
|
|
155
177
|
}
|
|
156
178
|
{
|
|
@@ -161,7 +183,7 @@ export function createAdmission(ctx) {
|
|
|
161
183
|
}
|
|
162
184
|
}
|
|
163
185
|
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
|
|
186
|
+
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
187
|
return null;
|
|
166
188
|
}
|
|
167
189
|
if (body.appendSystemPrompt !== undefined) {
|
|
@@ -170,7 +192,7 @@ export function createAdmission(ctx) {
|
|
|
170
192
|
return null;
|
|
171
193
|
}
|
|
172
194
|
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
|
|
195
|
+
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
196
|
return null;
|
|
175
197
|
}
|
|
176
198
|
}
|
|
@@ -203,14 +225,12 @@ export function createAdmission(ctx) {
|
|
|
203
225
|
}
|
|
204
226
|
}
|
|
205
227
|
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
|
|
228
|
+
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
229
|
return null;
|
|
208
230
|
}
|
|
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)`);
|
|
231
|
+
const foldedChars = typeof st.outputStyle === "string" && st.outputStyle.length > 0 && typeof body.appendSystemPrompt === "string" ? body.appendSystemPrompt.length + 2 + st.outputStyle.length : 0;
|
|
232
|
+
if (foldedChars > MAX_SYSTEM_PROMPT_CHARS) {
|
|
233
|
+
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
234
|
return null;
|
|
215
235
|
}
|
|
216
236
|
const perms = st.permissions;
|
|
@@ -225,6 +245,20 @@ export function createAdmission(ctx) {
|
|
|
225
245
|
return null;
|
|
226
246
|
}
|
|
227
247
|
}
|
|
248
|
+
{
|
|
249
|
+
const seatIssue = tightenOnlySeatIssue(st);
|
|
250
|
+
if (seatIssue) {
|
|
251
|
+
sendError(res, 400, "request.field_invalid", seatIssue.message, seatIssue.fields);
|
|
252
|
+
return null;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
{
|
|
256
|
+
const familiesIssue = approvalFrameFamiliesIssue(st);
|
|
257
|
+
if (familiesIssue) {
|
|
258
|
+
sendError(res, 400, "request.field_invalid", familiesIssue.message, familiesIssue.fields);
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
}
|
|
228
262
|
const envRaw = st.env;
|
|
229
263
|
if (envRaw !== undefined && envRaw !== null) {
|
|
230
264
|
if (typeof envRaw !== "object" || Array.isArray(envRaw)) {
|
|
@@ -233,12 +267,16 @@ export function createAdmission(ctx) {
|
|
|
233
267
|
}
|
|
234
268
|
const entries = Object.entries(envRaw);
|
|
235
269
|
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
|
|
270
|
+
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
271
|
return null;
|
|
238
272
|
}
|
|
239
273
|
for (const [k, val] of entries) {
|
|
240
|
-
|
|
241
|
-
|
|
274
|
+
const keyOver = k.length > MAX_SETTINGS_ENV_KEY_CHARS;
|
|
275
|
+
const valueOver = typeof val === "string" && val.length > MAX_SETTINGS_ENV_VALUE_CHARS;
|
|
276
|
+
if (keyOver || valueOver) {
|
|
277
|
+
const field = `settings.env.${echoCallerText(k, { maxChars: MAX_SETTINGS_ENV_KEY_CHARS })}`;
|
|
278
|
+
const facts = keyOver ? limitFacts(field, "characters", k.length, MAX_SETTINGS_ENV_KEY_CHARS) : limitFacts(field, "characters", val.length, MAX_SETTINGS_ENV_VALUE_CHARS);
|
|
279
|
+
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
280
|
return null;
|
|
243
281
|
}
|
|
244
282
|
}
|
|
@@ -284,13 +322,14 @@ export function createAdmission(ctx) {
|
|
|
284
322
|
}
|
|
285
323
|
if (Array.isArray(body.images)) {
|
|
286
324
|
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
|
|
325
|
+
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
326
|
return null;
|
|
289
327
|
}
|
|
290
|
-
for (const img of body.images) {
|
|
328
|
+
for (const [i, img] of body.images.entries()) {
|
|
291
329
|
const data = img.data;
|
|
292
|
-
|
|
293
|
-
|
|
330
|
+
const dataBytes = typeof data === "string" ? Buffer.byteLength(data, "utf8") : 0;
|
|
331
|
+
if (dataBytes > MAX_IMAGE_BASE64_BYTES) {
|
|
332
|
+
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
333
|
return null;
|
|
295
334
|
}
|
|
296
335
|
}
|
|
@@ -301,17 +340,17 @@ export function createAdmission(ctx) {
|
|
|
301
340
|
sendError(res, 400, "request.field_invalid", "clientContext must be an object");
|
|
302
341
|
return null;
|
|
303
342
|
}
|
|
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");
|
|
343
|
+
if (cc.timeZone !== undefined && (typeof cc.timeZone !== "string" || cc.timeZone.length > MAX_CLIENT_TIMEZONE_CHARS)) {
|
|
344
|
+
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
345
|
return null;
|
|
307
346
|
}
|
|
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");
|
|
347
|
+
if (cc.userEmail !== undefined && (typeof cc.userEmail !== "string" || cc.userEmail.length > MAX_CLIENT_USER_EMAIL_CHARS)) {
|
|
348
|
+
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
349
|
return null;
|
|
311
350
|
}
|
|
312
351
|
}
|
|
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");
|
|
352
|
+
if (body.sandboxImageProfile !== undefined && (typeof body.sandboxImageProfile !== "string" || body.sandboxImageProfile.length === 0 || body.sandboxImageProfile.length > MAX_SANDBOX_IMAGE_PROFILE_CHARS)) {
|
|
353
|
+
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
354
|
return null;
|
|
316
355
|
}
|
|
317
356
|
if (body.capabilitiesNeeded !== undefined && (!Array.isArray(body.capabilitiesNeeded) || body.capabilitiesNeeded.some((c) => typeof c !== "string"))) {
|
|
@@ -319,11 +358,11 @@ export function createAdmission(ctx) {
|
|
|
319
358
|
return null;
|
|
320
359
|
}
|
|
321
360
|
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)");
|
|
361
|
+
sendError(res, 400, "request.field_conflict", "capabilitiesNeeded requires sandboxImageProfile (it constrains the selected image)", fieldConflictFacts("image_profile", ["capabilitiesNeeded", "sandboxImageProfile"]));
|
|
323
362
|
return null;
|
|
324
363
|
}
|
|
325
364
|
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)");
|
|
365
|
+
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
366
|
return null;
|
|
328
367
|
}
|
|
329
368
|
if (body.outputSchema !== undefined) {
|
|
@@ -331,8 +370,9 @@ export function createAdmission(ctx) {
|
|
|
331
370
|
sendError(res, 400, "request.field_invalid", "outputSchema must be a JSON Schema object");
|
|
332
371
|
return null;
|
|
333
372
|
}
|
|
334
|
-
|
|
335
|
-
|
|
373
|
+
const schemaChars = JSON.stringify(body.outputSchema).length;
|
|
374
|
+
if (schemaChars > MAX_OUTPUT_SCHEMA_CHARS) {
|
|
375
|
+
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
376
|
return null;
|
|
337
377
|
}
|
|
338
378
|
}
|
|
@@ -341,12 +381,12 @@ export function createAdmission(ctx) {
|
|
|
341
381
|
return null;
|
|
342
382
|
}
|
|
343
383
|
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)");
|
|
384
|
+
if (typeof body.resumeAt !== "string" || body.resumeAt.length === 0 || body.resumeAt.length > MAX_RESUME_AT_CHARS) {
|
|
385
|
+
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
386
|
return null;
|
|
347
387
|
}
|
|
348
388
|
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)");
|
|
389
|
+
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
390
|
return null;
|
|
351
391
|
}
|
|
352
392
|
}
|
|
@@ -356,7 +396,7 @@ export function createAdmission(ctx) {
|
|
|
356
396
|
return null;
|
|
357
397
|
}
|
|
358
398
|
if (body.resumeAt === undefined) {
|
|
359
|
-
sendError(res, 400, "request.field_conflict", "resumeAtMode requires resumeAt (it qualifies the rewind target)");
|
|
399
|
+
sendError(res, 400, "request.field_conflict", "resumeAtMode requires resumeAt (it qualifies the rewind target)", fieldConflictFacts("resume_anchor", ["resumeAtMode", "resumeAt"]));
|
|
360
400
|
return null;
|
|
361
401
|
}
|
|
362
402
|
}
|
|
@@ -407,7 +447,7 @@ export function createAdmission(ctx) {
|
|
|
407
447
|
}
|
|
408
448
|
}
|
|
409
449
|
if (fileHistoryRestoreConflict(body)) {
|
|
410
|
-
sendError(res, 400, "request.field_conflict", FILE_HISTORY_DISABLED_NO_RESTORE);
|
|
450
|
+
sendError(res, 400, "request.field_conflict", FILE_HISTORY_DISABLED_NO_RESTORE, fieldConflictFacts("file_history_restore", ["fileHistory", ...fileHistoryRestoreKeysInBody(body)]));
|
|
411
451
|
return null;
|
|
412
452
|
}
|
|
413
453
|
if (body.requireExistingSession !== undefined && typeof body.requireExistingSession !== "boolean") {
|
|
@@ -514,7 +554,7 @@ export function createAdmission(ctx) {
|
|
|
514
554
|
if (um !== undefined && refuseUnavailableModel(res, deps.config, `agents[${um.index}].model`, um.ref))
|
|
515
555
|
return null;
|
|
516
556
|
if (um !== undefined) {
|
|
517
|
-
sendError(res, 400, "request.unknown_reference", `unknown agents[${um.index}].model "${um.ref
|
|
557
|
+
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
558
|
return null;
|
|
519
559
|
}
|
|
520
560
|
}
|
|
@@ -541,9 +581,12 @@ export function createAdmission(ctx) {
|
|
|
541
581
|
return null;
|
|
542
582
|
}
|
|
543
583
|
}
|
|
544
|
-
if (body.disableSkills === true
|
|
545
|
-
|
|
546
|
-
|
|
584
|
+
if (body.disableSkills === true) {
|
|
585
|
+
const skillSeats = [...((body.skills?.length ?? 0) > 0 ? ["skills"] : []), ...(body.agents ?? []).flatMap((a, i) => ((a.skills?.length ?? 0) > 0 ? [`agents[${i}].skills`] : []))];
|
|
586
|
+
if (skillSeats.length > 0) {
|
|
587
|
+
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]));
|
|
588
|
+
return null;
|
|
589
|
+
}
|
|
547
590
|
}
|
|
548
591
|
{
|
|
549
592
|
const v = body.userInvokedSkills;
|
|
@@ -608,7 +651,7 @@ export function createAdmission(ctx) {
|
|
|
608
651
|
if (matchCatalogModel(body.model, catalog, deps.config.modelRefusals) === undefined) {
|
|
609
652
|
if (refuseUnavailableModel(res, deps.config, "model", body.model))
|
|
610
653
|
return null;
|
|
611
|
-
sendError(res, 400, "request.unknown_reference", `unknown model "${body.model
|
|
654
|
+
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
655
|
return null;
|
|
613
656
|
}
|
|
614
657
|
}
|
|
@@ -622,7 +665,7 @@ export function createAdmission(ctx) {
|
|
|
622
665
|
if (matchCatalogModel(body.compactionModel, catalog, deps.config.modelRefusals) === undefined) {
|
|
623
666
|
if (refuseUnavailableModel(res, deps.config, "compactionModel", body.compactionModel))
|
|
624
667
|
return null;
|
|
625
|
-
sendError(res, 400, "request.unknown_reference", `unknown compactionModel "${body.compactionModel
|
|
668
|
+
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
669
|
return null;
|
|
627
670
|
}
|
|
628
671
|
}
|
|
@@ -663,17 +706,24 @@ export function createAdmission(ctx) {
|
|
|
663
706
|
const verify = verifyRoundsFromBody(body);
|
|
664
707
|
const cascade = body.cascade === true;
|
|
665
708
|
if (cascade && verify) {
|
|
666
|
-
sendError(res, 400, "request.field_conflict", "verify and cascade are mutually exclusive (verify = adversarial gate; cascade = cheap→strong ladder)");
|
|
709
|
+
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
710
|
return null;
|
|
668
711
|
}
|
|
669
712
|
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)");
|
|
713
|
+
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
714
|
return null;
|
|
672
715
|
}
|
|
673
716
|
if (cascade && deps.config.cascadeLadder.length === 0) {
|
|
674
717
|
sendError(res, 400, "request.precondition_unmet", "cascade requested but no ladder configured — set MODEL_CASCADE_LADDER (catalog model names, cheapest→strongest)");
|
|
675
718
|
return null;
|
|
676
719
|
}
|
|
720
|
+
{
|
|
721
|
+
const refusal = requestTrustRefusal({ permissions: parseTaskSettings(body.settings).settings?.permissions, skills: body.skills, userInvokedSkills: body.userInvokedSkills }, callerTrust(req, deps.config));
|
|
722
|
+
if (refusal !== undefined) {
|
|
723
|
+
sendError(res, 400, "request.field_invalid", refusal.message, refusal.facts);
|
|
724
|
+
return null;
|
|
725
|
+
}
|
|
726
|
+
}
|
|
677
727
|
const { body: admitted, entry: entryMode } = stampEntryPermissionMode(body, autonomyModeFloor(deps.config.autonomy));
|
|
678
728
|
try {
|
|
679
729
|
const auth = deps.authorize ? await deps.authorize({ req, body: admitted }) : undefined;
|
|
@@ -691,7 +741,8 @@ export function createAdmission(ctx) {
|
|
|
691
741
|
const acceptance = createRunAcceptance({ sessionTitler: deps.sessionTitler }, { ...(spec.sessionId ? { sessionId: spec.sessionId } : {}), objective: spec.objective, ...(model !== undefined ? { model } : {}) });
|
|
692
742
|
const clampNotice = buildEntryModeClampNotice(entryMode, spec.sessionId);
|
|
693
743
|
const pendingNotices = clampNotice !== undefined ? [clampNotice, ...engineNotices] : engineNotices;
|
|
694
|
-
|
|
744
|
+
const warnings = allowSelectorWarningsOf(admitted, spec.tools ?? []);
|
|
745
|
+
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
746
|
}
|
|
696
747
|
catch (err) {
|
|
697
748
|
if (err instanceof HttpError) {
|