@sema-agent/server 7.130.0 → 7.132.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 +396 -0
- package/README.md +13 -6
- package/README.zh-CN.md +9 -5
- package/USAGE.md +187 -50
- package/dist/approval-card.d.ts +3 -1
- package/dist/approval-card.js +2 -3
- package/dist/audit.d.ts +7 -10
- package/dist/audit.js +4 -1
- package/dist/auth-bridge.d.ts +4 -0
- package/dist/auth-bridge.js +10 -11
- package/dist/bench/s1/live-deps.js +2 -0
- package/dist/boot/deployment-mods.d.ts +31 -0
- package/dist/boot/deployment-mods.js +26 -0
- package/dist/boot/execution-env.d.ts +1 -1
- package/dist/boot/execution-env.js +19 -6
- package/dist/boot/memory-boundary.d.ts +2 -2
- package/dist/boot/read-deny-anchor-audit.d.ts +17 -0
- package/dist/boot/read-deny-anchor-audit.js +36 -0
- package/dist/boot/resolve-spec.d.ts +1 -5
- package/dist/boot/resolve-spec.js +56 -61
- package/dist/boot/runner-deps.d.ts +19 -8
- package/dist/boot/runner-deps.js +14 -2
- package/dist/boot/session-faces.d.ts +1 -7
- package/dist/boot/stage-02-web-admin-pull.js +9 -1
- package/dist/boot/stage-03-store-backend.d.ts +1 -1
- package/dist/boot/stage-03-store-backend.js +2 -2
- package/dist/boot/stage-04-stores.d.ts +1 -1
- package/dist/boot/stage-05-execution-env.d.ts +4 -4
- package/dist/boot/stage-05-execution-env.js +7 -10
- package/dist/boot/stage-06-runners.d.ts +2 -2
- package/dist/boot/stage-06-runners.js +5 -4
- package/dist/boot/stage-07-capability-layer.d.ts +2 -2
- package/dist/boot/stage-07-capability-layer.js +3 -3
- package/dist/boot/stage-08-reapers.d.ts +2 -2
- package/dist/boot/stage-09-leader.d.ts +3 -9
- package/dist/boot/stage-10-http-server.d.ts +3 -9
- package/dist/boot/stage-10-http-server.js +12 -10
- package/dist/boot/stores.d.ts +1 -1
- package/dist/boot/stores.js +5 -6
- package/dist/boot/web-admin.d.ts +0 -3
- package/dist/boot/web-admin.js +35 -35
- package/dist/brain.js +17 -22
- package/dist/budget.js +5 -4
- package/dist/caller-text-echo.d.ts +20 -0
- package/dist/caller-text-echo.js +24 -0
- package/dist/capabilities/brand-identity.d.ts +26 -0
- package/dist/capabilities/brand-identity.js +27 -0
- package/dist/capabilities/builtin-tools.js +2 -1
- package/dist/capabilities/center-plugins.js +1 -1
- package/dist/capabilities/center-prompts.d.ts +32 -59
- package/dist/capabilities/center-prompts.js +18 -32
- package/dist/capabilities/composite-members.d.ts +1 -0
- package/dist/capabilities/composite-members.js +1 -0
- package/dist/capabilities/engine-capabilities.js +2 -1
- package/dist/capabilities/hands-lane.d.ts +9 -6
- package/dist/capabilities/hands-lane.js +3 -3
- package/dist/capabilities/host-tool-names.d.ts +17 -0
- package/dist/capabilities/host-tool-names.js +15 -0
- package/dist/capabilities/mcp-probe.d.ts +14 -1
- package/dist/capabilities/mcp-probe.js +22 -133
- package/dist/capabilities/repo-tools.js +4 -3
- package/dist/capabilities/scenarios.d.ts +42 -47
- package/dist/capabilities/scenarios.js +19 -35
- package/dist/capabilities/select-environment-tool.js +2 -1
- package/dist/capabilities/send-user-file-tool.d.ts +0 -1
- package/dist/capabilities/send-user-file-tool.js +2 -2
- package/dist/capabilities/skills.d.ts +19 -4
- package/dist/capabilities/skills.js +30 -10
- package/dist/capabilities/tool-defer.js +2 -1
- package/dist/config-catalog.js +22 -11
- package/dist/config-invariants.js +2 -2
- package/dist/config-lkg.d.ts +9 -9
- package/dist/config-lkg.js +20 -4
- package/dist/config-provider.d.ts +3 -1
- package/dist/config-provider.js +14 -6
- package/dist/config-types.d.ts +13 -9
- package/dist/config.d.ts +2 -2
- package/dist/config.js +34 -20
- package/dist/device-ws-protocol.d.ts +1 -1
- package/dist/device-ws-protocol.js +1 -0
- package/dist/elicitation.d.ts +7 -0
- package/dist/elicitation.js +20 -5
- package/dist/env-name-allowlist-knobs.d.ts +12 -2
- package/dist/env-name-allowlist-knobs.js +5 -4
- package/dist/exec-bounds.d.ts +15 -3
- package/dist/exec-bounds.js +4 -0
- package/dist/execution-lane-caps.d.ts +9 -2
- package/dist/execution-lane-caps.js +11 -0
- package/dist/hooks/classic-stations.d.ts +86 -0
- package/dist/hooks/classic-stations.js +27 -0
- package/dist/hooks/hook-llm.d.ts +8 -5
- package/dist/hooks/hook-llm.js +80 -37
- package/dist/hooks/hook-runner.d.ts +273 -75
- package/dist/hooks/hook-runner.js +293 -317
- package/dist/http/admission.d.ts +8 -2
- package/dist/http/admission.js +103 -59
- package/dist/http/approval-sweeps.js +59 -18
- package/dist/http/checkpoint-ctx.d.ts +36 -18
- package/dist/http/checkpoint-ctx.js +14 -10
- package/dist/http/claimed-run.d.ts +13 -0
- package/dist/http/claimed-run.js +15 -0
- package/dist/http/device-placement.js +5 -10
- package/dist/http/dispatch.d.ts +0 -4
- package/dist/http/dispatch.js +6 -10
- package/dist/http/durable-run-leg.d.ts +2 -1
- package/dist/http/durable-run-leg.js +5 -3
- package/dist/http/health-self-report.d.ts +7 -5
- package/dist/http/health-self-report.js +4 -18
- package/dist/http/principal-gate.d.ts +23 -6
- package/dist/http/principal-gate.js +24 -5
- package/dist/http/refusal-body.d.ts +21 -0
- package/dist/http/refusal-body.js +4 -0
- package/dist/http/request-guards.d.ts +27 -0
- package/dist/http/request-guards.js +24 -3
- package/dist/http/resume-legs.d.ts +25 -0
- package/dist/http/resume-legs.js +48 -26
- package/dist/http/routes/approvals-assistant.js +1 -1
- package/dist/http/routes/capabilities.js +7 -17
- package/dist/http/routes/diagnostics.js +1 -1
- package/dist/http/routes/rules.js +2 -2
- package/dist/http/routes/runs.js +13 -17
- package/dist/http/routes/session-sync.js +4 -2
- package/dist/http/routes/sessions.js +23 -11
- package/dist/http/routes/shared-memory.js +2 -13
- package/dist/http/routes/side-query.js +2 -3
- package/dist/http/routes/tasks.js +34 -19
- package/dist/http/scenario-read-face.d.ts +14 -0
- package/dist/http/scenario-read-face.js +5 -0
- package/dist/http/send.d.ts +13 -1
- package/dist/http/send.js +12 -1
- package/dist/http/server.d.ts +37 -23
- package/dist/http/server.js +30 -4
- package/dist/http/stored-body-replay.d.ts +10 -3
- package/dist/http/stored-body-replay.js +27 -6
- package/dist/http/submit-ctx.d.ts +25 -0
- package/dist/http/submit-ctx.js +39 -0
- package/dist/http/wire-types.d.ts +18 -5
- package/dist/index.d.ts +3 -2
- package/dist/index.js +3 -2
- package/dist/lane-home-probe.d.ts +43 -0
- package/dist/lane-home-probe.js +35 -0
- package/dist/limit-refusal.d.ts +47 -0
- package/dist/limit-refusal.js +12 -0
- package/dist/main.js +1 -1
- package/dist/mcp-assertion-header.d.ts +3 -11
- package/dist/mcp-assertion-header.js +3 -9
- package/dist/mcp-tool-faces.d.ts +5 -0
- package/dist/mcp-tool-faces.js +5 -1
- package/dist/memory-scope.d.ts +1 -1
- package/dist/model-entry-refusal.d.ts +1 -7
- package/dist/model-provider.d.ts +39 -12
- package/dist/model-provider.js +19 -2
- package/dist/model-route-endpoint.d.ts +52 -12
- package/dist/model-route-endpoint.js +48 -26
- package/dist/model-route-gap.d.ts +5 -4
- package/dist/model-route-gap.js +1 -1
- package/dist/model-select.d.ts +58 -0
- package/dist/model-select.js +31 -0
- package/dist/namespaced-rule-name.d.ts +7 -4
- package/dist/namespaced-rule-name.js +4 -3
- package/dist/observability/cost-taxonomy.d.ts +7 -7
- package/dist/observability/fail-open.d.ts +53 -12
- package/dist/observability/fail-open.js +47 -7
- package/dist/observability/metrics.js +3 -1
- package/dist/observability/prompt-manifest.d.ts +47 -82
- package/dist/observability/prompt-manifest.js +119 -17
- package/dist/observability/run-terminal.js +14 -6
- package/dist/observability/secret-env-scrub.d.ts +13 -1
- package/dist/observability/secret-env-scrub.js +13 -1
- package/dist/observability/tool-trace.d.ts +16 -21
- package/dist/observability/tool-trace.js +51 -42
- package/dist/per-task-image.d.ts +7 -1
- package/dist/per-task-image.js +3 -3
- package/dist/plain-string-record.d.ts +25 -0
- package/dist/plain-string-record.js +32 -0
- package/dist/plugins/blob-backend.d.ts +68 -13
- package/dist/plugins/blob-backend.js +53 -10
- package/dist/plugins/checkpoint-store-sql.d.ts +14 -4
- package/dist/plugins/checkpoint-store-sql.js +39 -26
- package/dist/plugins/k8s-bg-scripts.d.ts +11 -0
- package/dist/plugins/k8s-bg-scripts.js +22 -0
- package/dist/plugins/local-checkpoint-store.js +5 -2
- package/dist/plugins/local-session-store.js +3 -3
- package/dist/plugins/one-time-migrations.d.ts +147 -91
- package/dist/plugins/one-time-migrations.js +372 -208
- package/dist/plugins/permission-rule-store-sql.d.ts +13 -7
- package/dist/plugins/permission-rule-store-sql.js +4 -18
- package/dist/plugins/pg-session-storage.d.ts +4 -5
- package/dist/plugins/pg-session-storage.js +7 -17
- package/dist/plugins/remote-env-adb.d.ts +6 -0
- package/dist/plugins/remote-env-adb.js +9 -4
- package/dist/plugins/remote-env-device.js +3 -0
- package/dist/plugins/remote-env-e2b.d.ts +1 -1
- package/dist/plugins/remote-env-e2b.js +21 -9
- package/dist/plugins/remote-env-host.d.ts +9 -9
- package/dist/plugins/remote-env-host.js +10 -32
- package/dist/plugins/remote-env-k8s.d.ts +95 -26
- package/dist/plugins/remote-env-k8s.js +265 -90
- package/dist/plugins/remote-env-local-docker.d.ts +20 -1
- package/dist/plugins/remote-env-local-docker.js +77 -9
- package/dist/plugins/remote-env-ssh.d.ts +15 -0
- package/dist/plugins/remote-env-ssh.js +109 -3
- package/dist/plugins/remote-shell.d.ts +0 -1
- package/dist/plugins/remote-shell.js +1 -2
- package/dist/plugins/retention-store-sql.js +6 -2
- package/dist/plugins/schema-consistency.d.ts +54 -0
- package/dist/plugins/schema-consistency.js +52 -0
- package/dist/plugins/session-epoch-anchor.d.ts +13 -0
- package/dist/plugins/session-epoch-anchor.js +23 -0
- package/dist/plugins/shared-memory-store-sql.d.ts +9 -3
- package/dist/plugins/shared-memory-store-sql.js +5 -16
- package/dist/plugins/sql-driver.d.ts +141 -0
- package/dist/plugins/sql-driver.js +115 -1
- package/dist/plugins/sql-errors.d.ts +41 -0
- package/dist/plugins/sql-errors.js +36 -0
- package/dist/plugins/store-backend.js +2 -1
- package/dist/plugins/tidb-session-storage.d.ts +7 -11
- package/dist/plugins/tidb-session-storage.js +6 -16
- package/dist/plugins/tidb-session-store.js +1 -1
- package/dist/prompts-domain-validate.d.ts +17 -61
- package/dist/prompts-domain-validate.js +9 -119
- package/dist/question.d.ts +18 -9
- package/dist/question.js +21 -13
- package/dist/request-key-closure.d.ts +4 -4
- package/dist/request-key-closure.js +18 -13
- package/dist/rule-entry-list.d.ts +134 -24
- package/dist/rule-entry-list.js +162 -30
- package/dist/run-local.d.ts +3 -3
- package/dist/run-local.js +26 -25
- package/dist/runs.d.ts +48 -2
- package/dist/runs.js +61 -2
- package/dist/server-secret-env.d.ts +44 -18
- package/dist/server-secret-env.js +49 -8
- package/dist/session-incarnation.d.ts +15 -5
- package/dist/session-incarnation.js +16 -9
- package/dist/session-titler.js +12 -2
- package/dist/spec-fields.d.ts +34 -18
- package/dist/spec-fields.js +46 -53
- package/dist/sql-engine-posture.d.ts +29 -4
- package/dist/sql-engine-posture.js +36 -1
- package/dist/stored-request-hooks-m20.d.ts +23 -0
- package/dist/stored-request-hooks-m20.js +124 -0
- package/dist/stored-request-tool-axes-m19.d.ts +20 -5
- package/dist/stored-request-tool-axes-m19.js +30 -2
- package/dist/task-a2a.d.ts +9 -1
- package/dist/task-a2a.js +73 -47
- package/dist/task-mcp.d.ts +54 -102
- package/dist/task-mcp.js +194 -92
- package/dist/task-settings.d.ts +47 -25
- package/dist/task-settings.js +46 -61
- package/dist/text-bidi.d.ts +3 -46
- package/dist/text-bidi.js +3 -3
- package/dist/tool-approval.d.ts +1 -1
- package/dist/trace/core-keyset-guard.d.ts +24 -4
- package/dist/trace/engine-notice-wire.d.ts +11 -3
- package/dist/trace/engine-notice-wire.js +8 -1
- package/dist/trace/ledger-events.d.ts +3 -1
- package/dist/trace/ledger-sink.d.ts +29 -0
- package/dist/trace/ledger-sink.js +15 -1
- package/dist/trace/model-segment.js +1 -1
- package/dist/trace/project.d.ts +25 -6
- package/dist/trace/project.js +68 -22
- package/dist/trace/wire-projection-faces.d.ts +80 -2
- package/dist/trace/wire-projection-faces.js +23 -1
- package/dist/user-authored-text.d.ts +7 -0
- package/dist/user-authored-text.js +3 -0
- package/dist/web-admin-client/apply-effective.js +10 -5
- package/dist/web-admin-client/candidate-gate.d.ts +6 -6
- package/dist/web-admin-client/candidate-gate.js +3 -3
- package/dist/web-admin-client/http-client.js +0 -6
- package/dist/web-admin-client/read-warnings.d.ts +13 -0
- package/dist/web-admin-client/read-warnings.js +10 -0
- package/dist/web-admin-client/skills-mcp.d.ts +3 -0
- package/dist/web-admin-client/skills-mcp.js +9 -6
- package/dist/web-admin-client/types.d.ts +3 -4
- package/dist/workspace-cache.d.ts +35 -0
- package/dist/workspace-cache.js +36 -0
- package/dist/workspace-space.d.ts +3 -2
- package/dist/workspace-space.js +2 -0
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +8 -1
- package/package.json +4 -4
- package/scripts/drain-check-local.mjs +37 -3
- package/scripts/drain-check.mysql.sql +30 -2
- package/scripts/drain-check.pg.sql +29 -2
- package/dist/capabilities/memory-notice.d.ts +0 -138
- package/dist/capabilities/memory-notice.js +0 -64
- package/dist/capabilities/prompt.d.ts +0 -17
- package/dist/capabilities/prompt.js +0 -6
- package/dist/mcp-content-origin.d.ts +0 -34
- package/dist/mcp-content-origin.js +0 -10
- package/dist/tool-axis-words.d.ts +0 -27
- package/dist/tool-axis-words.js +0 -9
- package/dist/wire-name-bound.d.ts +0 -14
- package/dist/wire-name-bound.js +0 -13
|
@@ -22,7 +22,7 @@ import { callGrantBindingOf, questionGrantBindingOf } from "../../standing-answe
|
|
|
22
22
|
import { sendResumeOutcome } from "../route-ctx.js";
|
|
23
23
|
import { assertNever } from "../route-ctx.js";
|
|
24
24
|
import * as facts from "../../capability-facts.js";
|
|
25
|
-
import { readResumeCtx
|
|
25
|
+
import { readResumeCtx } from "../resume-ctx-read.js";
|
|
26
26
|
import { recordFailOpen } from "../../observability/fail-open.js";
|
|
27
27
|
import { MAX_KEY_ECHO, keyClosureClause, scanKeyClosure } from "../../request-key-closure.js";
|
|
28
28
|
const DECIDE_BODY_DECLARED_KEYS = [
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { PERMISSION_MODES, expandTiers, reasoningEffortLevelsOf, routePairingStatus } from "@sema-agent/core";
|
|
2
|
-
import { modelImageInput, isAtMentionable, selectableCatalog } from "../../model-select.js";
|
|
1
|
+
import { PERMISSION_MODES, USER_ATTACHMENT_SEAT, expandTiers, reasoningEffortLevelsOf, routePairingStatus } from "@sema-agent/core";
|
|
2
|
+
import { modelImageInput, modelReasoningDecl, isAtMentionable, selectableCatalog } from "../../model-select.js";
|
|
3
3
|
import { buildDroppedEntriesWire } from "../../web-admin-client/read-warnings.js";
|
|
4
4
|
import { buildCandidateRejectedWire } from "../../web-admin-client/candidate-gate.js";
|
|
5
5
|
import { modelKeyPoisonOf, resolveModelApiKey } from "../../key-resolver.js";
|
|
@@ -12,6 +12,7 @@ import { DEVICE_PROTOCOL_VERSION, DEVICE_WS_PATH } from "../../device-ws-protoco
|
|
|
12
12
|
import { a2aInjectionHonored } from "../../task-a2a.js";
|
|
13
13
|
import { buildEmptyMcpProbeFace, buildMcpInjectionRefusal, buildMcpProbeCacheKey, buildMcpProbeInflightRefusal, buildMcpProbeRateKey, buildMcpProbeRateRefusal, createMcpProbeLocal, buildMcpProbeDeclarationRefusal, buildMcpProbeIncompleteRefusal, McpProbeIncomplete, MCP_PROBE_HTTP_STATUS, MCP_PROBE_MAX_INFLIGHT, MCP_PROBE_VERDICT_TIMEOUT_MS, createMcpProbeWalk, readMcpProbeBody, } from "../../capabilities/mcp-probe.js";
|
|
14
14
|
import { mcpForScenario } from "../../web-admin-client/facade.js";
|
|
15
|
+
import { sendScenarioNotFound } from "../scenario-read-face.js";
|
|
15
16
|
import { sendJson, sendError } from "../send.js";
|
|
16
17
|
import { assertNever } from "../route-ctx.js";
|
|
17
18
|
import { fileHistoryCaptureOf } from "../../file-history-capture.js";
|
|
@@ -44,9 +45,6 @@ function retentionAdvertisement(config) {
|
|
|
44
45
|
export function createCapabilitiesLocal() {
|
|
45
46
|
return { mcpProbe: createMcpProbeLocal() };
|
|
46
47
|
}
|
|
47
|
-
function sendScenarioNotFound(res) {
|
|
48
|
-
sendError(res, 404, "scenario_not_found", "scenario not found");
|
|
49
|
-
}
|
|
50
48
|
export async function handleCapabilities(req, res, match, ctx) {
|
|
51
49
|
const { deps } = ctx;
|
|
52
50
|
switch (match.decl.id) {
|
|
@@ -94,7 +92,7 @@ export async function handleCapabilities(req, res, match, ctx) {
|
|
|
94
92
|
memory: false,
|
|
95
93
|
memoryWrite: false,
|
|
96
94
|
memoryEngine: projectMemoryEngineCapability(deps.memoryPosture),
|
|
97
|
-
store: projectStoreCapability(deps.storePosture ?? { declared: deps.config.dbBackend, backend: "memory" }, deps.
|
|
95
|
+
store: projectStoreCapability(deps.storePosture ?? { declared: deps.config.dbBackend, backend: "memory" }, deps.sqlEngine?.facts),
|
|
98
96
|
centerWiring: deps.centerWiring?.(gatedPrincipal(req, deps.config)),
|
|
99
97
|
webSearch: projectWebSearchCapability(deps.webSearchProvider),
|
|
100
98
|
sessionBackgroundable: facts.durableRuns(deps).available,
|
|
@@ -149,6 +147,7 @@ export async function handleCapabilities(req, res, match, ctx) {
|
|
|
149
147
|
disableSkills: true,
|
|
150
148
|
userInvokedSkills: true,
|
|
151
149
|
skillToolLists: true,
|
|
150
|
+
userAttachments: USER_ATTACHMENT_SEAT,
|
|
152
151
|
projectContext: cwdHonored(deps.config),
|
|
153
152
|
callerCwd: cwdHonored(deps.config) || deviceCwdHonored(deps.config),
|
|
154
153
|
taskWriteFaceOpen: taskWriteFaceRefusal(deps.config) === undefined && autonomyKeepsOpenWriteFace(deps.config.autonomy),
|
|
@@ -225,16 +224,7 @@ export async function handleCapabilities(req, res, match, ctx) {
|
|
|
225
224
|
sendError(res, 400, "request.field_invalid", "scenario must be given at most once (omit it to read this deployment's default scenario)");
|
|
226
225
|
return;
|
|
227
226
|
}
|
|
228
|
-
const
|
|
229
|
-
let scenarioName;
|
|
230
|
-
if (requestedScenario === undefined)
|
|
231
|
-
scenarioName = deps.config.defaultScenario;
|
|
232
|
-
else if (deps.scenarioGate === undefined) {
|
|
233
|
-
sendScenarioNotFound(res);
|
|
234
|
-
return;
|
|
235
|
-
}
|
|
236
|
-
else
|
|
237
|
-
scenarioName = await deps.scenarioGate(principal, requestedScenario);
|
|
227
|
+
const scenarioName = await deps.scenarioGate(principal, scenarioParams[0]);
|
|
238
228
|
await serveMcpProbeFace(res, ctx, principal, mcpForScenario(deps.config.mcpServers, scenarioName) ?? [], "deployment");
|
|
239
229
|
return;
|
|
240
230
|
}
|
|
@@ -265,7 +255,7 @@ export async function handleCapabilities(req, res, match, ctx) {
|
|
|
265
255
|
name,
|
|
266
256
|
id: m.id,
|
|
267
257
|
provider: m.provider,
|
|
268
|
-
reasoning: m
|
|
258
|
+
...(modelReasoningDecl(m) !== undefined ? { reasoning: modelReasoningDecl(m) } : {}),
|
|
269
259
|
...(modelImageInput(m) !== "undeclared" ? { vision: modelImageInput(m) === "yes" } : {}),
|
|
270
260
|
...(m.contextWindow ? { contextWindow: m.contextWindow } : {}),
|
|
271
261
|
...(m.maxTokens ? { maxOutputTokens: m.maxTokens } : {}),
|
|
@@ -109,7 +109,7 @@ export async function handleDiagnostics(req, res, match, ctx) {
|
|
|
109
109
|
sendJson(res, 200, {
|
|
110
110
|
static: deps.staticWiring,
|
|
111
111
|
memoryPosture: deps.memoryPosture ?? null,
|
|
112
|
-
sqlEngine: deps.
|
|
112
|
+
sqlEngine: deps.sqlEngine?.facts ?? null,
|
|
113
113
|
writeProtection: deps.writeProtection ?? null,
|
|
114
114
|
readFace: buildReadFaceWiring(deps.config),
|
|
115
115
|
executionLane: projectExecutionLaneCapability(deps.config),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { sendJson, sendError,
|
|
2
|
+
import { sendJson, sendError, sendHttpError } from "../send.js";
|
|
3
3
|
import { gatedPrincipal, explicitOperatorOk, sendOperatorPrincipalsRequired, sendUnauthorized } from "../principal-gate.js";
|
|
4
4
|
import { assertNever } from "../route-ctx.js";
|
|
5
5
|
import * as facts from "../../capability-facts.js";
|
|
@@ -113,7 +113,7 @@ export async function handleRules(req, res, match, ctx) {
|
|
|
113
113
|
}
|
|
114
114
|
catch (err) {
|
|
115
115
|
if (err instanceof HttpError && err.status !== 400) {
|
|
116
|
-
|
|
116
|
+
sendHttpError(res, err);
|
|
117
117
|
return;
|
|
118
118
|
}
|
|
119
119
|
sendError(res, 400, "request.body_shape", "body must be valid JSON");
|
package/dist/http/routes/runs.js
CHANGED
|
@@ -17,7 +17,7 @@ import { ASK_DECISION_CONSUMER_ABSENT, outcomeOfDecidedRow, resolveStreamApprova
|
|
|
17
17
|
import { MAX_DECISION_NOTE_CHARS } from "../../approval-ask-machine.js";
|
|
18
18
|
import { causeOfAskRow } from "../../approval-deny-reasons.js";
|
|
19
19
|
import { normalizeRunEventType, screenedStoredEventData } from "../../trace/project.js";
|
|
20
|
-
import { sendJson, sendError,
|
|
20
|
+
import { sendJson, sendError, sendHttpError, sseHeaders } from "../send.js";
|
|
21
21
|
import { mintCancelledResult } from "../../run-cancel-context.js";
|
|
22
22
|
import { acceptedInputKindOf } from "../../user-input-ledger.js";
|
|
23
23
|
import { INJECTION_TIERS } from "../../trace/injection-tier.js";
|
|
@@ -405,7 +405,7 @@ export async function handleRuns(req, res, match, ctx) {
|
|
|
405
405
|
}
|
|
406
406
|
catch (e) {
|
|
407
407
|
if (e instanceof HttpError) {
|
|
408
|
-
|
|
408
|
+
sendHttpError(res, e);
|
|
409
409
|
return;
|
|
410
410
|
}
|
|
411
411
|
sendError(res, 400, "request.invalid_json", "invalid JSON body");
|
|
@@ -632,7 +632,7 @@ export async function handleRuns(req, res, match, ctx) {
|
|
|
632
632
|
mintResult.noResumeCtx = true;
|
|
633
633
|
return;
|
|
634
634
|
}
|
|
635
|
-
const unservable = storedBodyReplayRefusal(resumeRead.ctx, deps.config
|
|
635
|
+
const unservable = storedBodyReplayRefusal(resumeRead.ctx, deps.config);
|
|
636
636
|
if (unservable !== undefined) {
|
|
637
637
|
mintResult.unservable = unservable;
|
|
638
638
|
return;
|
|
@@ -693,7 +693,7 @@ export async function handleRuns(req, res, match, ctx) {
|
|
|
693
693
|
}
|
|
694
694
|
if (mintResult.unservable !== undefined) {
|
|
695
695
|
deps.logger?.warn?.("steer_wake_park_refused_stored_body", { taskId, sessionId: run.sessionId, ...storedBodyReplayLogFields(mintResult.unservable) });
|
|
696
|
-
const { status, body: { error, errorCode, ...rest } } = storedBodyReplayAnswer(mintResult.unservable, serviceVersion());
|
|
696
|
+
const { status, body: { error, errorCode, ...rest } } = storedBodyReplayAnswer(mintResult.unservable, serviceVersion(), false);
|
|
697
697
|
sendError(res, status, errorCode, error, rest);
|
|
698
698
|
return;
|
|
699
699
|
}
|
|
@@ -730,7 +730,7 @@ export async function handleRuns(req, res, match, ctx) {
|
|
|
730
730
|
}
|
|
731
731
|
catch (e) {
|
|
732
732
|
if (e instanceof HttpError) {
|
|
733
|
-
|
|
733
|
+
sendHttpError(res, e);
|
|
734
734
|
return;
|
|
735
735
|
}
|
|
736
736
|
sendError(res, 400, "request.invalid_json", "invalid JSON body");
|
|
@@ -743,10 +743,6 @@ export async function handleRuns(req, res, match, ctx) {
|
|
|
743
743
|
}
|
|
744
744
|
const interruptBody = interruptNormalized;
|
|
745
745
|
const interruptBare = !("text" in interruptBody);
|
|
746
|
-
if (interruptBare && Object.keys(interruptBody).length > 0) {
|
|
747
|
-
sendError(res, 400, "request.body_shape", "body must be {} (bare halt: cut the in-flight turn and stop the run at this boundary) or { text: string (non-empty) } (cut + steer: the text reaches the model after the cut)");
|
|
748
|
-
return;
|
|
749
|
-
}
|
|
750
746
|
let text = "";
|
|
751
747
|
if (!interruptBare) {
|
|
752
748
|
if (typeof interruptBody.text !== "string" || interruptBody.text.length === 0) {
|
|
@@ -754,11 +750,11 @@ export async function handleRuns(req, res, match, ctx) {
|
|
|
754
750
|
return;
|
|
755
751
|
}
|
|
756
752
|
text = interruptBody.text;
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
753
|
+
}
|
|
754
|
+
const keyIssue = steerBodyKeyIssue(interruptBody, "interrupt");
|
|
755
|
+
if (keyIssue) {
|
|
756
|
+
sendError(res, 400, "request.body_shape", keyIssue.message, { unknownKeys: keyIssue.unknownKeys, unsupportedKeys: keyIssue.unsupportedKeys });
|
|
757
|
+
return;
|
|
762
758
|
}
|
|
763
759
|
const interruptIdemRaw = headerStr(req.headers["idempotency-key"]);
|
|
764
760
|
const interruptInputId = interruptIdemRaw ? `idem-${idemKeyOf(interruptIdemRaw, idemCallerOf(req, ctx), "run").slice(0, 32)}` : uuidv7();
|
|
@@ -897,7 +893,7 @@ export async function handleRuns(req, res, match, ctx) {
|
|
|
897
893
|
}
|
|
898
894
|
catch (e) {
|
|
899
895
|
if (e instanceof HttpError) {
|
|
900
|
-
|
|
896
|
+
sendHttpError(res, e);
|
|
901
897
|
return;
|
|
902
898
|
}
|
|
903
899
|
sendError(res, 400, "request.invalid_json", "invalid JSON body");
|
|
@@ -948,7 +944,7 @@ export async function handleRuns(req, res, match, ctx) {
|
|
|
948
944
|
}
|
|
949
945
|
catch (e) {
|
|
950
946
|
if (e instanceof HttpError) {
|
|
951
|
-
|
|
947
|
+
sendHttpError(res, e);
|
|
952
948
|
return;
|
|
953
949
|
}
|
|
954
950
|
sendError(res, 400, "request.invalid_json", "invalid JSON body");
|
|
@@ -1174,7 +1170,7 @@ export async function handleRunVerbs(req, res, match, ctx) {
|
|
|
1174
1170
|
}
|
|
1175
1171
|
catch (e) {
|
|
1176
1172
|
if (e instanceof HttpError) {
|
|
1177
|
-
|
|
1173
|
+
sendHttpError(res, e);
|
|
1178
1174
|
return;
|
|
1179
1175
|
}
|
|
1180
1176
|
sendError(res, 400, "request.invalid_json", "invalid JSON body");
|
|
@@ -6,6 +6,7 @@ import { exportSessionManifest, fileHistoryImportFace, replayFileHistory, replay
|
|
|
6
6
|
import * as facts from "../../capability-facts.js";
|
|
7
7
|
import { classifySyncRelationshipByIds, SyncConflictError } from "../../session-sync-kernel.js";
|
|
8
8
|
import { isUuidShape } from "../../security.js";
|
|
9
|
+
import { sqlBlobCapRefusalText } from "../../plugins/blob-backend.js";
|
|
9
10
|
import { sendJson, sendError, sendSessionError, sendSessionPolicyError, msg } from "../send.js";
|
|
10
11
|
import { buildDisplaySafeUrl } from "../../trace/redact.js";
|
|
11
12
|
import { gatedPrincipal, explicitOperatorOk, sendUnauthorized } from "../principal-gate.js";
|
|
@@ -186,8 +187,9 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
186
187
|
}
|
|
187
188
|
const fs = blobs.historyStore;
|
|
188
189
|
const body = await readRawBody(req, SYNC_BLOB_MAX_BYTES);
|
|
189
|
-
|
|
190
|
-
|
|
190
|
+
const sqlCap = deps.snapshotBlobSqlCap?.();
|
|
191
|
+
if (sqlCap !== undefined && body.byteLength > sqlCap.capBytes) {
|
|
192
|
+
sendError(res, 413, "blob_too_large_for_sql", sqlBlobCapRefusalText(body.byteLength, sqlCap), { wallSource: sqlCap.source });
|
|
191
193
|
return;
|
|
192
194
|
}
|
|
193
195
|
if (createHash("sha256").update(body).digest("hex") !== hash) {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SessionError, materializeA2aTools, materializeMcpTools, sanitizePathComponent } from "@sema-agent/core";
|
|
2
2
|
import { a2aForScenario, mcpForScenario } from "../../web-admin-client/facade.js";
|
|
3
|
-
import { isUuidShape, legacyUnownedSessionOk } from "../../security.js";
|
|
3
|
+
import { HttpError, isUuidShape, legacyUnownedSessionOk } from "../../security.js";
|
|
4
4
|
import { windowMessages, truncateMessageBlobs, redactSessionViewForRead } from "../../audit.js";
|
|
5
5
|
import { redactSecrets } from "../../trace/redact.js";
|
|
6
6
|
import { recordFailOpen } from "../../observability/fail-open.js";
|
|
@@ -8,7 +8,7 @@ import { MCP_DIAL_DEADLINE_MS, raceDeadline } from "../mcp-dial-deadline.js";
|
|
|
8
8
|
import { sentMemoryComplianceFailure } from "../memory-compliance-failure-reply.js";
|
|
9
9
|
import { MAX_SETTINGS_OUTPUT_STYLE_CHARS, MAX_SETTINGS_ENV_VARS, MAX_SETTINGS_ENV_KEY_CHARS, MAX_SETTINGS_ENV_VALUE_CHARS } from "../../task-settings.js";
|
|
10
10
|
import { readWritableSessionPermissionRules } from "../../session-policy-wire.js";
|
|
11
|
-
import { sendJson, sendError, sendSessionError, sendSessionPolicyError, sseHeaders } from "../send.js";
|
|
11
|
+
import { sendJson, sendError, sendSessionError, sendSessionPolicyError, sseHeaders, httpErrorBody } from "../send.js";
|
|
12
12
|
import { gatedPrincipal, explicitOperatorOk, sessionOwnerReadable, sendPrincipalRefusal, sendUnauthorized } from "../principal-gate.js";
|
|
13
13
|
import { assertNever, SESSION_NOT_FOUND_MESSAGE } from "../route-ctx.js";
|
|
14
14
|
import * as facts from "../../capability-facts.js";
|
|
@@ -54,7 +54,7 @@ async function readLastLegMcp(deps, sessionId, principal) {
|
|
|
54
54
|
const latest = await runStore.latestRunForSession(sessionId);
|
|
55
55
|
if (latest === undefined)
|
|
56
56
|
return undefined;
|
|
57
|
-
if (!sessionOwnerReadable(principal, latest.owner, deps
|
|
57
|
+
if (!sessionOwnerReadable(principal, latest.owner, deps) && !explicitOperatorOk(principal, deps.config.operatorPrincipals))
|
|
58
58
|
return undefined;
|
|
59
59
|
const events = await runStore.getEvents(latest.taskId, 0);
|
|
60
60
|
for (let i = events.length - 1; i >= 0; i--) {
|
|
@@ -144,10 +144,21 @@ export async function handleSessions(req, res, match, ctx) {
|
|
|
144
144
|
return;
|
|
145
145
|
}
|
|
146
146
|
const lastLegMcp = await lastLegMcpFor(deps, safeDecode(match.params.sessionId), principal);
|
|
147
|
-
const
|
|
148
|
-
|
|
147
|
+
const ledgerHalf = lastLegMcp === undefined ? {} : { lastLegMcp };
|
|
148
|
+
let scenarioName;
|
|
149
|
+
try {
|
|
150
|
+
scenarioName = await deps.scenarioGate(principal, undefined);
|
|
151
|
+
}
|
|
152
|
+
catch (e) {
|
|
153
|
+
if (!(e instanceof HttpError))
|
|
154
|
+
throw e;
|
|
155
|
+
sendJson(res, 200, { asOf: new Date().toISOString(), ...ledgerHalf, scenarioRefusal: httpErrorBody(e) });
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
const specs = mcpForScenario(deps.config.mcpServers, scenarioName);
|
|
159
|
+
const cacheKey = `${scenarioName}::${principal ?? ""}`;
|
|
149
160
|
if (!specs || specs.length === 0) {
|
|
150
|
-
sendJson(res, 200, { servers: [], asOf: new Date().toISOString(), ...
|
|
161
|
+
sendJson(res, 200, { servers: [], asOf: new Date().toISOString(), ...ledgerHalf });
|
|
151
162
|
return;
|
|
152
163
|
}
|
|
153
164
|
const cached = mcpStatusCache.get(cacheKey);
|
|
@@ -179,23 +190,24 @@ export async function handleSessions(req, res, match, ctx) {
|
|
|
179
190
|
})();
|
|
180
191
|
mcpStatusCache.set(cacheKey, { at: Date.now(), panel });
|
|
181
192
|
}
|
|
182
|
-
sendJson(res, 200, { ...(await mcpStatusCache.get(cacheKey).panel), ...
|
|
193
|
+
sendJson(res, 200, { ...(await mcpStatusCache.get(cacheKey).panel), ...ledgerHalf });
|
|
183
194
|
return;
|
|
184
195
|
}
|
|
185
196
|
}
|
|
186
197
|
{
|
|
187
198
|
if (match.decl.id === "session-a2a") {
|
|
188
|
-
|
|
199
|
+
const principal = gatedPrincipal(req, deps.config);
|
|
200
|
+
if (deps.config.requirePrincipal && !principal) {
|
|
189
201
|
sendPrincipalRefusal(res, req, deps.config);
|
|
190
202
|
return;
|
|
191
203
|
}
|
|
192
|
-
const
|
|
204
|
+
const scenarioName = await deps.scenarioGate(principal, undefined);
|
|
205
|
+
const specs = a2aForScenario(deps.config.a2aPeers, scenarioName);
|
|
193
206
|
if (!specs || specs.length === 0) {
|
|
194
207
|
sendJson(res, 200, { peers: [], asOf: new Date().toISOString() });
|
|
195
208
|
return;
|
|
196
209
|
}
|
|
197
|
-
const
|
|
198
|
-
const cacheKey = `${deps.config.defaultScenario}::${principal ?? ""}`;
|
|
210
|
+
const cacheKey = `${scenarioName}::${principal ?? ""}`;
|
|
199
211
|
const cached = a2aStatusCache.get(cacheKey);
|
|
200
212
|
if (!cached || Date.now() - cached.at > A2A_STATUS_TTL_MS) {
|
|
201
213
|
if (a2aStatusCache.size > 1024)
|
|
@@ -1,21 +1,10 @@
|
|
|
1
|
-
import { SHARED_MEMORY_READ_CAP_BYTES, SharedMemoryStoreError } from "@sema-agent/core";
|
|
1
|
+
import { isSharedMemoryDocumentPath, SHARED_MEMORY_READ_CAP_BYTES, SharedMemoryStoreError } from "@sema-agent/core";
|
|
2
2
|
import { sendJson, sendError } from "../send.js";
|
|
3
3
|
import { gatedPrincipal, sendUnauthorized } from "../principal-gate.js";
|
|
4
4
|
import { assertNever } from "../route-ctx.js";
|
|
5
5
|
import * as facts from "../../capability-facts.js";
|
|
6
6
|
const RETRY_AFTER_SEC = 10;
|
|
7
7
|
const HTTP_LIST_LIMIT = 100;
|
|
8
|
-
const FORBIDDEN_PATH_CHARS = /[\p{Cc}\p{Cf}\p{Co}\p{Cn}\p{Default_Ignorable_Code_Point}\u2028\u2029\\]/u;
|
|
9
|
-
const DOCUMENT_SUFFIXES = [".md", ".txt", ".json", ".jsonl"];
|
|
10
|
-
function isDocumentPath(path) {
|
|
11
|
-
if (!path.startsWith("/") || FORBIDDEN_PATH_CHARS.test(path))
|
|
12
|
-
return false;
|
|
13
|
-
const segments = path.slice(1).split("/");
|
|
14
|
-
const last = segments.at(-1);
|
|
15
|
-
if (last === undefined || !segments.every((s) => s !== "" && !s.startsWith(".")))
|
|
16
|
-
return false;
|
|
17
|
-
return DOCUMENT_SUFFIXES.some((s) => last.endsWith(s));
|
|
18
|
-
}
|
|
19
8
|
function refuseStore(res) {
|
|
20
9
|
sendError(res, 404, "not_found.shared_memory_store", "not found");
|
|
21
10
|
}
|
|
@@ -120,7 +109,7 @@ export async function handleSharedMemory(req, res, match, ctx) {
|
|
|
120
109
|
return;
|
|
121
110
|
}
|
|
122
111
|
const path = query.get("path");
|
|
123
|
-
if (path === null || path === "" || !
|
|
112
|
+
if (path === null || path === "" || !isSharedMemoryDocumentPath(path)) {
|
|
124
113
|
sendError(res, 400, "request.query_invalid", "missing or malformed ?path= (absolute, .md/.txt/.json/.jsonl)");
|
|
125
114
|
return;
|
|
126
115
|
}
|
|
@@ -4,7 +4,7 @@ import { isAtMentionable, matchCatalogModel, refusedCatalogEntry, selectableCata
|
|
|
4
4
|
import { modelUnavailableMessage } from "../../model-entry-refusal.js";
|
|
5
5
|
import { redactSecrets } from "../../trace/redact.js";
|
|
6
6
|
import { admitProviderEcho, redactErrorMessage } from "../../observability/run-terminal.js";
|
|
7
|
-
import { sendJson, sendError,
|
|
7
|
+
import { sendJson, sendError, sendHttpError, msg } from "../send.js";
|
|
8
8
|
import { gatedPrincipal, sendPrincipalRefusal } from "../principal-gate.js";
|
|
9
9
|
import { assertNever } from "../route-ctx.js";
|
|
10
10
|
const CORE_PREFLIGHT_VALIDATION_PREFIXES = ["Unknown model ref ", "No model for role "];
|
|
@@ -50,8 +50,7 @@ export async function handleSideQuery(req, res, match, ctx) {
|
|
|
50
50
|
body = raw;
|
|
51
51
|
}
|
|
52
52
|
catch (e) {
|
|
53
|
-
|
|
54
|
-
sendError(res, he.status, httpErrorCode(he.status, he.code), he.message);
|
|
53
|
+
sendHttpError(res, e instanceof HttpError ? e : new HttpError(400, msg(e)));
|
|
55
54
|
return;
|
|
56
55
|
}
|
|
57
56
|
if (!Array.isArray(body.messages) || body.messages.length === 0) {
|
|
@@ -1,20 +1,20 @@
|
|
|
1
1
|
import { redactErrorMessage, redactHead, redactTerminalResult } from "../../observability/run-terminal.js";
|
|
2
2
|
import { runWithVerification, runCascade, taskNotificationDedupKey, uuidv7 } from "@sema-agent/core";
|
|
3
|
-
import { graftParkToolCallId, markChildrenStoppedByUserOnAbort, syncRefusalHttpStatus, releaseKeyIfZeroWorkRefusal, HEARTBEAT_MS } from "../../runs.js";
|
|
3
|
+
import { graftParkToolCallId, markChildrenStoppedByUserOnAbort, syncRefusalHttpStatus, zeroWorkRefusalFacts, releaseKeyIfZeroWorkRefusal, createPromptCommitReader, HEARTBEAT_MS } from "../../runs.js";
|
|
4
4
|
import { sealResultForExit, outwardPlane } from "../../terminal.js";
|
|
5
5
|
import { withPrincipal } from "../../observability/principal-context.js";
|
|
6
6
|
import { fleetRunPublisher, fleetRunLabels, fleetRunResiduals, isFleetAgentTerminalNotification } from "../../fleet/fleet-bus.js";
|
|
7
7
|
import { defaultSubagentTailBus } from "../../fleet/subagent-tail-bus.js";
|
|
8
8
|
import { createReasoningSegments, reasoningStreamOfTask } from "../../trace/model-segment.js";
|
|
9
9
|
import { emitPendingWorkflowCompletions, taskNotificationInboxEntry, taskNotificationStreamKeyOf, NotifiedKeys } from "../../orchestration/workflow-completion-inbox.js";
|
|
10
|
-
import { createLedgerSink } from "../../trace/ledger-sink.js";
|
|
10
|
+
import { createLedgerSink, createLedgerTwinEmit } from "../../trace/ledger-sink.js";
|
|
11
11
|
import { registerEngineNoticeLeg } from "../../trace/engine-notice-wire.js";
|
|
12
12
|
import { clearTurnActivity, readTurnActivityMs, recordTurnActivity } from "../../turn-activity.js";
|
|
13
13
|
import { buildCancelledLedgerRow, createRunAbort, mintCancelledResult } from "../../run-cancel-context.js";
|
|
14
14
|
import { recordResourceWindow } from "../../resource-window.js";
|
|
15
15
|
import { redactSecrets } from "../../trace/redact.js";
|
|
16
16
|
import { liveToolEndForBacklog } from "../../trace/tool-output-media.js";
|
|
17
|
-
import { contextUsageEventData, turnEndEventData, toolStartEventData, toolEndEventData, taskProgressEventData, taskStartedEventData, taskNotificationEventData, compactedEventData, diagnosticsEventData, brainStatusEventData, steeringInjectedEventData, compactionOutcomeEventData, workspaceChangedEventData, wiringManifestFaceEventData, toolRosterDeltaEventData, toolProgressEventData, toolDisclosureEventData, humanInputEventData, appendModelUsageDelta, attachModelUsage, textEndEventData, liveIdentityFields } from "../../trace/project.js";
|
|
17
|
+
import { contextUsageEventData, turnEndEventData, toolStartEventData, toolEndEventData, taskProgressEventData, taskStartedEventData, taskNotificationEventData, compactedEventData, diagnosticsEventData, brainStatusEventData, steeringInjectedEventData, compactionOutcomeEventData, compactionStartedEventData, workspaceChangedEventData, wiringManifestFaceEventData, toolRosterDeltaEventData, toolProgressEventData, toolDisclosureEventData, humanInputEventData, appendModelUsageDelta, attachModelUsage, textEndEventData, liveIdentityFields } from "../../trace/project.js";
|
|
18
18
|
import { cascadeConfig, runMeta } from "../run-meta.js";
|
|
19
19
|
import { idemCallerOf, inflightKeyOf, submissionIdemOf } from "../idempotency.js";
|
|
20
20
|
import { replayOfExistingRun } from "../submit-replay.js";
|
|
@@ -30,7 +30,7 @@ import { failOpenTagForDroppedFrame, recordFailOpen } from "../../observability/
|
|
|
30
30
|
import { buildSyncSubmitBody } from "../sync-submit-body.js";
|
|
31
31
|
import { assertNever } from "../route-ctx.js";
|
|
32
32
|
import * as facts from "../../capability-facts.js";
|
|
33
|
-
import {
|
|
33
|
+
import { persistSubmitCtx } from "../submit-ctx.js";
|
|
34
34
|
import { serviceVersion } from "../../service-version.js";
|
|
35
35
|
import { withModelReachScope } from "../../model-reach-scope.js";
|
|
36
36
|
import { createInstructionSelectionLeg } from "../../instruction-selection.js";
|
|
@@ -249,6 +249,7 @@ export async function handleTasks(req, res, match, ctx) {
|
|
|
249
249
|
let durableHeartbeat;
|
|
250
250
|
const cancelledResult = (errorMessage, cause) => mintCancelledResult({ taskId: durableTaskId ?? "", sessionId: prepared.spec.sessionId ?? "", startedAtMs: streamLegStartedAt, message: errorMessage, cause });
|
|
251
251
|
let userMsgEntryId;
|
|
252
|
+
const promptCommit = createPromptCommitReader();
|
|
252
253
|
let anchorPut = false;
|
|
253
254
|
const putRewindAnchor = () => {
|
|
254
255
|
if (anchorPut || !userMsgEntryId || !durableTaskId || !prepared.spec.sessionId || !deps.resumeAnchorStore)
|
|
@@ -285,14 +286,18 @@ export async function handleTasks(req, res, match, ctx) {
|
|
|
285
286
|
}
|
|
286
287
|
durableTaskId = tid;
|
|
287
288
|
}
|
|
289
|
+
if (deps.checkpointStore && prepared.spec.sessionId) {
|
|
290
|
+
const ctxRefusal = await persistSubmitCtx(deps.checkpointStore, deps, durableTaskId !== undefined && deps.runStore ? { runStore: deps.runStore, taskId: durableTaskId } : undefined, prepared.spec.sessionId, { body: prepared.body, memoryScope: prepared.auth?.memoryScope, writerVersion: serviceVersion() });
|
|
291
|
+
if (ctxRefusal) {
|
|
292
|
+
sseData(res, { type: "done", result: doneResultOfOutcome(ctxRefusal) });
|
|
293
|
+
return ctxRefusal;
|
|
294
|
+
}
|
|
295
|
+
}
|
|
288
296
|
commitSessionInheritEnv(deps, prepared.spec.sessionId, prepared.body);
|
|
289
297
|
if (prepared.spec.sessionId)
|
|
290
298
|
markChildrenStoppedByUserOnAbort(ac.signal, durableTaskId ?? prepared.spec.sessionId, prepared.auth?.principal);
|
|
291
299
|
let ledgerSink;
|
|
292
300
|
let ledgerTerminal = false;
|
|
293
|
-
if (deps.checkpointStore && prepared.spec.sessionId) {
|
|
294
|
-
await deps.checkpointStore.putCtx(prepared.spec.sessionId, buildCheckpointCtx({ body: prepared.body, memoryScope: prepared.auth?.memoryScope, writerVersion: serviceVersion() }));
|
|
295
|
-
}
|
|
296
301
|
if (durableTaskId && deps.runStore) {
|
|
297
302
|
const rs = deps.runStore;
|
|
298
303
|
const tid = durableTaskId;
|
|
@@ -457,8 +462,9 @@ export async function handleTasks(req, res, match, ctx) {
|
|
|
457
462
|
break;
|
|
458
463
|
for (const end of ev.type === "done" ? [...childReasoning.cut(), ...topReasoning.cut()] : topReasoning.onEvent(ev))
|
|
459
464
|
sseData(res, end);
|
|
460
|
-
|
|
461
|
-
|
|
465
|
+
const promptEntryId = promptCommit(ev);
|
|
466
|
+
if (promptEntryId !== undefined)
|
|
467
|
+
userMsgEntryId = promptEntryId;
|
|
462
468
|
const causeAtDone = ev.type === "done" ? ac.cause() : undefined;
|
|
463
469
|
await deps.userInputLedger?.observeLegEvent(liveStream, ev);
|
|
464
470
|
prepared.acceptance.observe(ev);
|
|
@@ -539,6 +545,9 @@ export async function handleTasks(req, res, match, ctx) {
|
|
|
539
545
|
else if (ev.type === "compaction_outcome") {
|
|
540
546
|
sseData(res, { type: "compaction_outcome", ...compactionOutcomeEventData(ev) });
|
|
541
547
|
}
|
|
548
|
+
else if (ev.type === "compaction_started") {
|
|
549
|
+
sseData(res, { type: "compaction_started", ...compactionStartedEventData(ev) });
|
|
550
|
+
}
|
|
542
551
|
else if (ev.type === "wiring_manifest") {
|
|
543
552
|
const wiringFace = wiringManifestFaceEventData(ev, wiringOperatorFace, instructionLeg.segment());
|
|
544
553
|
wiringReceipt ??= wiringFace;
|
|
@@ -594,6 +603,14 @@ export async function handleTasks(req, res, match, ctx) {
|
|
|
594
603
|
}
|
|
595
604
|
res.write(`event: ${frame.type}\ndata: ${JSON.stringify(frame)}\n\n`);
|
|
596
605
|
};
|
|
606
|
+
const faceAlive = () => !res.writableEnded && !res.destroyed;
|
|
607
|
+
const emitElicitation = createLedgerTwinEmit({ sink: ledgerSink, writeLive: emitAsk, liveReachable: faceAlive });
|
|
608
|
+
const writeQuestionLive = (frame) => {
|
|
609
|
+
if (!faceAlive())
|
|
610
|
+
throw new Error("live stream ended — question frame undeliverable");
|
|
611
|
+
emitAsk(frame);
|
|
612
|
+
};
|
|
613
|
+
const emitQuestion = createLedgerTwinEmit({ sink: ledgerSink, writeLive: writeQuestionLive, liveReachable: faceAlive });
|
|
597
614
|
await emitPendingWorkflowCompletions(deps.workflowCompletionInbox, prepared.spec.sessionId, askOwner, (frame) => {
|
|
598
615
|
if (closed || res.writableEnded || res.destroyed)
|
|
599
616
|
throw new Error("stream ended before the completion frame was written");
|
|
@@ -604,15 +621,10 @@ export async function handleTasks(req, res, match, ctx) {
|
|
|
604
621
|
sseData(res, frame);
|
|
605
622
|
}, { route: "sync-stream-open", connection: "live-sse", log: (m, x) => deps.logger?.info?.(m, x) });
|
|
606
623
|
const withElicit = deps.elicitation
|
|
607
|
-
? () => deps.elicitation.runWithContext({ taskId: askTaskId, owner: askOwner, emit:
|
|
624
|
+
? () => deps.elicitation.runWithContext({ taskId: askTaskId, owner: askOwner, emit: emitElicitation, abortSignal: ac.signal }, streamBody)
|
|
608
625
|
: streamBody;
|
|
609
|
-
const emitQuestion = (frame) => {
|
|
610
|
-
if (res.writableEnded || res.destroyed)
|
|
611
|
-
throw new Error("live stream ended — question frame undeliverable");
|
|
612
|
-
emitAsk(frame);
|
|
613
|
-
};
|
|
614
626
|
const withQuestion = () => deps.question
|
|
615
|
-
? deps.question.runWithContext({ taskId: askTaskId, owner: askOwner, emit: emitQuestion, abortSignal: ac.signal, deliverable:
|
|
627
|
+
? deps.question.runWithContext({ taskId: askTaskId, owner: askOwner, emit: emitQuestion, abortSignal: ac.signal, deliverable: faceAlive }, withElicit)
|
|
616
628
|
: withElicit();
|
|
617
629
|
const emitApproval = (frame) => {
|
|
618
630
|
if (res.writableEnded || res.destroyed)
|
|
@@ -852,10 +864,12 @@ export async function handleTasks(req, res, match, ctx) {
|
|
|
852
864
|
return { status: placementReject.status, body: devicePlacementErrorBody(placementReject) };
|
|
853
865
|
durableTaskId = tid;
|
|
854
866
|
}
|
|
855
|
-
commitSessionInheritEnv(deps, prepared.spec.sessionId, prepared.body);
|
|
856
867
|
if (deps.checkpointStore && prepared.spec.sessionId) {
|
|
857
|
-
await deps.checkpointStore.
|
|
868
|
+
const ctxRefusal = await persistSubmitCtx(deps.checkpointStore, deps, durableTaskId !== undefined && deps.runStore ? { runStore: deps.runStore, taskId: durableTaskId } : undefined, prepared.spec.sessionId, { body: prepared.body, memoryScope: prepared.auth?.memoryScope, writerVersion: serviceVersion() });
|
|
869
|
+
if (ctxRefusal)
|
|
870
|
+
return ctxRefusal;
|
|
858
871
|
}
|
|
872
|
+
commitSessionInheritEnv(deps, prepared.spec.sessionId, prepared.body);
|
|
859
873
|
const syncCancelCtrl = createRunAbort();
|
|
860
874
|
if (prepared.spec.sessionId)
|
|
861
875
|
markChildrenStoppedByUserOnAbort(syncCancelCtrl.signal, durableTaskId ?? prepared.spec.sessionId, prepared.auth?.principal);
|
|
@@ -928,7 +942,8 @@ export async function handleTasks(req, res, match, ctx) {
|
|
|
928
942
|
const retryAfterSec = resumeAtPlane.errorCode === "memory.admission_required" && result.retryAfterMs !== undefined
|
|
929
943
|
? Math.max(1, Math.ceil(result.retryAfterMs / 1000))
|
|
930
944
|
: undefined;
|
|
931
|
-
|
|
945
|
+
const refusalFacts = zeroWorkRefusalFacts(redactTerminalResult(sealResultForExit(result)).terminal);
|
|
946
|
+
return { status: resumeAtStatus, body: { errorCode: resumeAtPlane.errorCode, error: redactErrorMessage(resumeAtPlane.errorMessage) ?? "resume-at failed", ...(retryAfterSec !== undefined ? { retryAfterSec } : {}), ...refusalFacts } };
|
|
932
947
|
}
|
|
933
948
|
const exitResult = await mintSubmitExitResult(result, deps.checkpointStore);
|
|
934
949
|
const syncPlane = outwardPlane(result.terminal);
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 「本部署没有这个场景」的唯一答复(A9 叶:只依赖 `send.ts`)—— 场景详情读面(`GET /v1/capabilities/scenarios/:name`,名字不在 `scenarioDetails` 里)答它。
|
|
3
|
+
*
|
|
4
|
+
* 回答「此主体在此场景能看见哪些 MCP 服务器 / A2A 对端」的读口不经过这里:它们的场景名只由 `deps.scenarioGate` 给
|
|
5
|
+
* (`ServiceCoreDeps` 的必填件,`capabilities/scenarios.ts` `createScenarioGate` 铸的那一只),点名与缺席都问,拒就是门的 typed 错 —— 读口没有第二个场景名来源。
|
|
6
|
+
*/
|
|
7
|
+
import type { ServerResponse } from "node:http";
|
|
8
|
+
/**
|
|
9
|
+
* 「本部署没有这个场景」的唯一答复。一句话、一个码,不各写一份。
|
|
10
|
+
* [ref] 信封统一:本答复曾是全站唯一对象形 error(`{error:{code}}`)——SDK toApiError 对它特判过一轮 TypeError 加固;统一为「字符串 error + 顶层 errorCode」邻位形
|
|
11
|
+
* (cancel/decide 同款),机器判据保留。
|
|
12
|
+
*/
|
|
13
|
+
export declare function sendScenarioNotFound(res: ServerResponse): void;
|
|
14
|
+
//# sourceMappingURL=scenario-read-face.d.ts.map
|
package/dist/http/send.d.ts
CHANGED
|
@@ -9,6 +9,8 @@
|
|
|
9
9
|
*/
|
|
10
10
|
import type { ServerResponse } from "node:http";
|
|
11
11
|
import { type SessionErrorFace } from "../session-error-wire.js";
|
|
12
|
+
import type { HttpError } from "../security.js";
|
|
13
|
+
import { type Refusal, type RefusalBody } from "./refusal-body.js";
|
|
12
14
|
/**
|
|
13
15
|
* [ref](黑板 [ref]②)—— 一条响应「是 SSE 流」的**在场标记**。
|
|
14
16
|
*
|
|
@@ -69,11 +71,21 @@ export declare function sendJson(res: ServerResponse, status: number, body: unkn
|
|
|
69
71
|
* change), not a new response shape. Sites where the two machine-code channels genuinely disagree, or
|
|
70
72
|
* where `error`/`errorCode` aren't cleanly separable from the rest of the body, are left on raw
|
|
71
73
|
* `sendJson` (see the A6 migration notes for the callers still doing that on purpose). */
|
|
72
|
-
export declare function sendError(res: ServerResponse, status: number, errorCode: string, message: string, extra?: Record<string, unknown
|
|
74
|
+
export declare function sendError(res: ServerResponse, status: number, errorCode: string, message: string, extra?: Readonly<Record<string, unknown>>): void;
|
|
73
75
|
/** B7([ref] lens1 §C3):`HttpError` 的兜底 catch-all 站点没有自己的语义分支——`err.code` 在 42 个
|
|
74
76
|
* throw 点里只有 3 个带。为了让「errorCode 恒在」在这些站点也成立(而不是靠豁免表放行),按**状态码**
|
|
75
77
|
* 给一个诚实的粗码:它只声明「这类拒绝」,不冒充比 throw 点更细的语义。带 `code` 的 throw 点原样优先。 */
|
|
76
78
|
export declare function httpErrorCode(status: number, code?: string): string;
|
|
79
|
+
/**
|
|
80
|
+
* 一只 `HttpError` 读成 {@link Refusal}:码经 {@link httpErrorCode}(带码的 throw 原样优先,否则按状态给粗码),句 = `message`,机读事实 = `extra`
|
|
81
|
+
* (如场景门的 `detail: { scenario, source }`、条数帽的 `field` / `reason` / `count` / `cap`)。**拆 `HttpError` 的唯一一处** —— 别的站点自己拆
|
|
82
|
+
* `status` / `code` / `message` 拼体就丢了 `extra`(`test/refusal-one-composer.test.ts` 的静态门钉着)。
|
|
83
|
+
*/
|
|
84
|
+
export declare function httpErrorRefusal(e: HttpError): Refusal;
|
|
85
|
+
/** 一只 `HttpError` 的拒体成员 = {@link refusalBody}({@link httpErrorRefusal})。 */
|
|
86
|
+
export declare function httpErrorBody(e: HttpError): RefusalBody;
|
|
87
|
+
/** 整面拒:状态 = `e.status`,体 = {@link httpErrorBody}。手里拿着一只 `HttpError` 的路由站点一律调它。 */
|
|
88
|
+
export declare function sendHttpError(res: ServerResponse, e: HttpError): void;
|
|
77
89
|
/**
|
|
78
90
|
* 🔴 B1 / S-535 —— `SessionPolicyError` → 应答,经 {@link sessionPolicyErrorHttp} 那**一只**映射
|
|
79
91
|
* (`src/session-policy-wire.ts`)。回 `true` = 已应答,调用点 `return`。
|
package/dist/http/send.js
CHANGED
|
@@ -2,6 +2,7 @@ import { SessionError, SessionPolicyError } from "@sema-agent/core";
|
|
|
2
2
|
import { sessionPolicyErrorFacts, sessionPolicyErrorHttp, sessionPolicyErrorSentence } from "../session-policy-wire.js";
|
|
3
3
|
import { sessionErrorHttp } from "../session-error-wire.js";
|
|
4
4
|
import { redactErrorMessage } from "../observability/run-terminal.js";
|
|
5
|
+
import { refusalBody } from "./refusal-body.js";
|
|
5
6
|
export const SSE_RESPONSE_MARK = Symbol("sema.http.sse-response");
|
|
6
7
|
export function isSseResponse(res) {
|
|
7
8
|
return res[SSE_RESPONSE_MARK] === true;
|
|
@@ -31,7 +32,7 @@ export function sendJson(res, status, body) {
|
|
|
31
32
|
res.end(JSON.stringify(body));
|
|
32
33
|
}
|
|
33
34
|
export function sendError(res, status, errorCode, message, extra) {
|
|
34
|
-
sendJson(res, status, {
|
|
35
|
+
sendJson(res, status, refusalBody(extra === undefined ? { errorCode, message } : { errorCode, message, facts: extra }));
|
|
35
36
|
}
|
|
36
37
|
export function httpErrorCode(status, code) {
|
|
37
38
|
if (code)
|
|
@@ -48,6 +49,16 @@ export function httpErrorCode(status, code) {
|
|
|
48
49
|
default: return status >= 500 ? "internal.error" : "request.rejected";
|
|
49
50
|
}
|
|
50
51
|
}
|
|
52
|
+
export function httpErrorRefusal(e) {
|
|
53
|
+
const errorCode = httpErrorCode(e.status, e.code);
|
|
54
|
+
return e.extra === undefined ? { errorCode, message: e.message } : { errorCode, message: e.message, facts: e.extra };
|
|
55
|
+
}
|
|
56
|
+
export function httpErrorBody(e) {
|
|
57
|
+
return refusalBody(httpErrorRefusal(e));
|
|
58
|
+
}
|
|
59
|
+
export function sendHttpError(res, e) {
|
|
60
|
+
sendJson(res, e.status, httpErrorBody(e));
|
|
61
|
+
}
|
|
51
62
|
export function sendSessionPolicyError(res, e, sentencePrefix = "") {
|
|
52
63
|
if (!(e instanceof SessionPolicyError))
|
|
53
64
|
return false;
|