@sema-agent/server 7.145.0 → 7.146.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 +492 -0
- package/USAGE.md +218 -47
- package/deploy/facts/CHANGES.json +25 -0
- package/deploy/facts/README.md +57 -0
- package/deploy/facts/lanes.json +54 -0
- package/deploy/facts/lanes.schema.json +57 -0
- package/deploy/facts/sandbox-rbac.json +113 -0
- package/deploy/facts/sandbox-rbac.schema.json +74 -0
- package/deploy/facts/sealed-key.json +9 -0
- package/deploy/facts/sealed-key.schema.json +52 -0
- package/deploy/sema-up/chart/templates/_helpers.tpl +19 -0
- package/deploy/sema-up/chart/templates/sandbox-rbac.yaml +47 -7
- package/deploy/sema-up/chart/templates/server-v4pro.yaml +4 -0
- package/deploy/sema-up/chart/templates/server.yaml +4 -0
- package/deploy/sema-up/chart/values.yaml +7 -0
- package/deploy/sema-up/stack/sema-stack-cluster.yaml +30 -14
- package/dist/adoption/import-limits.d.ts +6 -0
- package/dist/adoption/import-limits.js +7 -0
- package/dist/adoption/import.d.ts +62 -0
- package/dist/adoption/import.js +107 -0
- package/dist/adoption/wire.d.ts +52 -0
- package/dist/adoption/wire.js +9 -0
- package/dist/approval-ask-machine.d.ts +2 -2
- package/dist/approval-card.d.ts +3 -12
- package/dist/approval-card.js +0 -4
- package/dist/approval-gate-currency.d.ts +1 -1
- package/dist/approval-gate-currency.js +1 -1
- package/dist/approval-reconciler.d.ts +1 -1
- package/dist/boot/deployment-mods.d.ts +11 -1
- package/dist/boot/deployment-mods.js +15 -2
- package/dist/boot/device-lane.js +2 -0
- package/dist/boot/engine-lease.d.ts +193 -21
- package/dist/boot/engine-lease.js +146 -20
- package/dist/boot/execution-env.d.ts +4 -0
- package/dist/boot/execution-env.js +12 -0
- package/dist/boot/exit-boundary.d.ts +50 -0
- package/dist/boot/exit-boundary.js +32 -0
- package/dist/boot/exit-last.d.ts +20 -4
- package/dist/boot/exit-last.js +21 -4
- package/dist/boot/governance-seams.js +1 -0
- package/dist/boot/memory-consolidation.d.ts +29 -17
- package/dist/boot/memory-consolidation.js +26 -15
- package/dist/boot/reapers.d.ts +12 -4
- package/dist/boot/reapers.js +39 -15
- package/dist/boot/resolve-spec.d.ts +2 -0
- package/dist/boot/resolve-spec.js +38 -15
- package/dist/boot/runner-deps.js +1 -1
- package/dist/boot/session-faces.js +3 -1
- package/dist/boot/shutdown.js +27 -9
- package/dist/boot/stage-01-config.js +1 -1
- package/dist/boot/stage-03-store-backend.d.ts +1 -0
- package/dist/boot/stage-03-store-backend.js +2 -2
- package/dist/boot/stage-04-stores.d.ts +1 -0
- package/dist/boot/stage-05-execution-env.d.ts +3 -0
- package/dist/boot/stage-05-execution-env.js +3 -3
- package/dist/boot/stage-06-runners.d.ts +3 -0
- package/dist/boot/stage-06-runners.js +11 -10
- package/dist/boot/stage-07-capability-layer.d.ts +3 -0
- package/dist/boot/stage-07-capability-layer.js +7 -2
- package/dist/boot/stage-08-reapers.d.ts +3 -0
- package/dist/boot/stage-08-reapers.js +3 -3
- package/dist/boot/stage-09-leader.d.ts +3 -0
- package/dist/boot/stage-10-http-server.d.ts +3 -0
- package/dist/boot/stage-10-http-server.js +3 -2
- package/dist/boot/stores.d.ts +1 -0
- package/dist/boot/stores.js +35 -19
- package/dist/boot/workflow-orchestration.d.ts +1 -1
- package/dist/boot/workflow-orchestration.js +2 -1
- package/dist/capabilities/composite-members.d.ts +3 -1
- package/dist/capabilities/composite-members.js +3 -1
- package/dist/capabilities/scenarios.d.ts +2 -2
- package/dist/capability-facts.d.ts +18 -1
- package/dist/capability-facts.js +25 -7
- package/dist/checkpoint-ctx-seal-m28.d.ts +1 -1
- package/dist/config-catalog.js +13 -4
- package/dist/config-provider.d.ts +2 -2
- package/dist/config-types.d.ts +43 -4
- package/dist/config.d.ts +6 -1
- package/dist/config.js +67 -11
- package/dist/deleted-session-ids.d.ts +19 -0
- package/dist/deleted-session-ids.js +26 -0
- package/dist/deploy-facts.d.ts +155 -0
- package/dist/deploy-facts.js +94 -0
- package/dist/device-ws-hub.d.ts +48 -3
- package/dist/device-ws-hub.js +48 -2
- package/dist/error-code-family.d.ts +35 -0
- package/dist/error-code-family.js +26 -0
- package/dist/fleet/drain-entry.d.ts +39 -3
- package/dist/fleet/drain-entry.js +6 -0
- package/dist/fleet/fleet-bus.d.ts +2 -1
- package/dist/hooks/branch-transcript.d.ts +1 -1
- package/dist/hooks/branch-transcript.js +1 -0
- package/dist/hooks/classic-stations.d.ts +25 -8
- package/dist/hooks/classic-stations.js +29 -3
- package/dist/hooks/hook-runner.d.ts +33 -16
- package/dist/hooks/hook-runner.js +166 -73
- package/dist/hooks/hook-source.d.ts +14 -2
- package/dist/hooks/hook-source.js +8 -0
- package/dist/http/active-run-conflict.d.ts +1 -1
- package/dist/http/active-run-conflict.js +1 -1
- package/dist/http/admission.js +11 -1
- package/dist/http/checkpoint-ctx.d.ts +59 -71
- package/dist/http/checkpoint-ctx.js +34 -40
- package/dist/http/dispatch.js +18 -2
- package/dist/http/durable-run-leg.d.ts +5 -0
- package/dist/http/durable-run-leg.js +1 -0
- package/dist/http/execution-context.d.ts +4 -0
- package/dist/http/execution-context.js +9 -0
- package/dist/http/health-self-report.d.ts +6 -2
- package/dist/http/health-self-report.js +3 -2
- package/dist/http/memory-compliance-failure-reply.d.ts +1 -1
- package/dist/http/memory-compliance-failure-reply.js +2 -15
- package/dist/http/memory-control-plane-corrupt-reply.d.ts +25 -0
- package/dist/http/memory-control-plane-corrupt-reply.js +19 -0
- package/dist/http/principal-gate.d.ts +35 -12
- package/dist/http/principal-gate.js +16 -12
- package/dist/http/request-guards.d.ts +1 -1
- package/dist/http/request-guards.js +5 -5
- package/dist/http/resume-legs.d.ts +22 -0
- package/dist/http/resume-legs.js +26 -17
- package/dist/http/route-ctx.d.ts +11 -10
- package/dist/http/route-table.js +2 -0
- package/dist/http/routes/adoption.d.ts +11 -0
- package/dist/http/routes/adoption.js +80 -6
- package/dist/http/routes/agents-roster.js +1 -0
- package/dist/http/routes/approvals-assistant.js +2 -1
- package/dist/http/routes/background.js +1 -0
- package/dist/http/routes/capabilities.js +4 -1
- package/dist/http/routes/diagnostics.d.ts +9 -14
- package/dist/http/routes/diagnostics.js +10 -20
- package/dist/http/routes/engine.d.ts +31 -0
- package/dist/http/routes/engine.js +81 -0
- package/dist/http/routes/memory-bundle.js +3 -0
- package/dist/http/routes/memory-consolidation.js +3 -5
- package/dist/http/routes/memory-origin.d.ts +1 -1
- package/dist/http/routes/memory-origin.js +2 -4
- package/dist/http/routes/memory-policy.js +5 -1
- package/dist/http/routes/observability.js +3 -6
- package/dist/http/routes/runs.js +7 -3
- package/dist/http/routes/session-sync.js +12 -25
- package/dist/http/routes/sessions-list.d.ts +1 -1
- package/dist/http/routes/sessions.js +4 -0
- package/dist/http/routes/tasks.js +23 -5
- package/dist/http/routes/trace-usage.js +1 -1
- package/dist/http/run-concurrency-cap.d.ts +86 -0
- package/dist/http/run-concurrency-cap.js +54 -0
- package/dist/http/server.d.ts +15 -12
- package/dist/http/server.js +18 -3
- package/dist/http/stored-body-replay.d.ts +9 -6
- package/dist/http/stored-body-replay.js +19 -5
- package/dist/http/wire-types.d.ts +8 -3
- package/dist/json-body-limit.d.ts +8 -0
- package/dist/json-body-limit.js +2 -0
- package/dist/leader/diffout.d.ts +1 -1
- package/dist/local-data-root.d.ts +2 -2
- package/dist/memory-operator-faces.d.ts +9 -4
- package/dist/memory-scope-stores.d.ts +9 -7
- package/dist/memory-scope-stores.js +3 -14
- package/dist/memory-scope.d.ts +36 -0
- package/dist/memory-scope.js +32 -1
- package/dist/net-address.d.ts +53 -0
- package/dist/net-address.js +111 -0
- package/dist/observability/fail-open.d.ts +14 -10
- package/dist/observability/fail-open.js +14 -10
- package/dist/orchestration/workflow-notify-journal.js +2 -3
- package/dist/org-delivery-gate.js +1 -1
- package/dist/peer-directory.d.ts +6 -12
- package/dist/peer-directory.js +5 -1
- package/dist/plugins/caching-session-store.d.ts +3 -1
- package/dist/plugins/caching-session-store.js +3 -0
- package/dist/plugins/checkpoint-store-face.d.ts +426 -0
- package/dist/plugins/checkpoint-store-face.js +152 -0
- package/dist/plugins/file-run-store.d.ts +0 -6
- package/dist/plugins/file-run-store.js +1 -12
- package/dist/plugins/fork-routing-session-store.d.ts +6 -2
- package/dist/plugins/fork-routing-session-store.js +2 -2
- package/dist/plugins/imported-layer-root-retirement.d.ts +10 -8
- package/dist/plugins/local-checkpoint-store.d.ts +2 -2
- package/dist/plugins/local-checkpoint-store.js +2 -1
- package/dist/plugins/local-session-store.d.ts +28 -5
- package/dist/plugins/local-session-store.js +32 -8
- package/dist/plugins/memory-engine-pg.d.ts +29 -6
- package/dist/plugins/memory-engine-pg.js +96 -214
- package/dist/plugins/memory-engine-sql-apply.d.ts +121 -0
- package/dist/plugins/memory-engine-sql-apply.js +358 -0
- package/dist/plugins/memory-engine-tidb.d.ts +35 -9
- package/dist/plugins/memory-engine-tidb.js +97 -227
- package/dist/plugins/memory-key-guards.d.ts +1 -1
- package/dist/plugins/memory-origin-law.d.ts +3 -3
- package/dist/plugins/one-time-migrations.d.ts +32 -56
- package/dist/plugins/one-time-migrations.js +25 -117
- package/dist/plugins/permission-rule-store-file.d.ts +17 -3
- package/dist/plugins/permission-rule-store-file.js +8 -1
- package/dist/plugins/pg-pool.js +1 -1
- package/dist/plugins/pg-session-storage.d.ts +17 -4
- package/dist/plugins/pg-session-storage.js +8 -4
- package/dist/plugins/run-store-sql.js +2 -2
- package/dist/plugins/schema-ensure-legs.js +2 -2
- package/dist/plugins/session-fork.d.ts +31 -9
- package/dist/plugins/session-fork.js +3 -2
- package/dist/plugins/session-placement.d.ts +4 -2
- package/dist/plugins/sql-json-column.d.ts +5 -1
- package/dist/plugins/store-backend.d.ts +11 -8
- package/dist/plugins/store-backend.js +8 -7
- package/dist/plugins/store-contracts.d.ts +1 -11
- package/dist/plugins/store-contracts.js +0 -9
- package/dist/plugins/store-sweep.d.ts +63 -0
- package/dist/plugins/store-sweep.js +48 -0
- package/dist/plugins/tidb-pool.js +1 -1
- package/dist/plugins/tidb-session-store.d.ts +16 -3
- package/dist/plugins/tidb-session-store.js +8 -4
- package/dist/prompt-screen.d.ts +6 -9
- package/dist/prompt-screen.js +2 -5
- package/dist/rules-consent.d.ts +20 -27
- package/dist/rules-consent.js +82 -6
- package/dist/run-cancel-context.d.ts +4 -1
- package/dist/run-cancel-context.js +2 -1
- package/dist/runs.js +1 -1
- package/dist/sandbox-egress-policy.js +6 -11
- package/dist/sandbox-rbac-rules.d.ts +88 -0
- package/dist/sandbox-rbac-rules.js +80 -0
- package/dist/sealed-key-layout.d.ts +17 -0
- package/dist/sealed-key-layout.js +4 -0
- package/dist/sealed-key.js +5 -5
- package/dist/security.d.ts +38 -6
- package/dist/security.js +9 -2
- package/dist/session-notify-door.d.ts +5 -3
- package/dist/session-resident-background.d.ts +57 -0
- package/dist/session-resident-background.js +20 -0
- package/dist/session-sync-kernel.d.ts +53 -14
- package/dist/session-sync-kernel.js +70 -1
- package/dist/session-sync.d.ts +5 -3
- package/dist/session-workspace.d.ts +1 -0
- package/dist/session-workspace.js +1 -0
- package/dist/sighup-idle.d.ts +9 -7
- package/dist/sighup-idle.js +4 -5
- package/dist/spec-fields.d.ts +16 -0
- package/dist/spec-fields.js +7 -0
- package/dist/stored-request-env-credentials-m38.d.ts +3 -0
- package/dist/stored-request-env-credentials-m38.js +8 -0
- package/dist/stored-request-prompt-profile-m30.d.ts +1 -1
- package/dist/{plugins → stores-sql}/checkpoint-store-sql.d.ts +13 -427
- package/dist/{plugins → stores-sql}/checkpoint-store-sql.js +33 -194
- package/dist/{plugins → stores-sql}/mailbox-store-sql.d.ts +2 -2
- package/dist/{plugins → stores-sql}/mailbox-store-sql.js +4 -4
- package/dist/{plugins → stores-sql}/roster-store-sql.d.ts +2 -2
- package/dist/{plugins → stores-sql}/roster-store-sql.js +1 -1
- package/dist/{plugins → stores-sql}/tool-result-store-sql.d.ts +2 -2
- package/dist/{plugins → stores-sql}/tool-result-store-sql.js +6 -6
- package/dist/{plugins → stores-sql}/workflow-journal-store-sql.d.ts +7 -12
- package/dist/{plugins → stores-sql}/workflow-journal-store-sql.js +3 -8
- package/dist/task-settings.d.ts +59 -4
- package/dist/task-settings.js +50 -4
- package/dist/tool-approval.d.ts +2 -2
- package/dist/trace/core-keyset-guard.d.ts +8 -7
- package/dist/trace/engine-notice-wire.d.ts +1 -1
- package/dist/trace/engine-notice-wire.js +2 -0
- package/dist/trace/exit-seat.d.ts +6 -0
- package/dist/trace/exit-seat.js +1 -0
- package/dist/trace/project.js +9 -0
- package/dist/trace/redact.d.ts +13 -2
- package/dist/trace/redact.js +305 -24
- package/dist/trace/self-minted-wire.d.ts +326 -8
- package/dist/trace/self-minted-wire.js +125 -7
- package/dist/trace/wire-projection-faces.d.ts +1 -1
- package/dist/trace/wire-projection-faces.js +1 -1
- package/dist/usage-analytics.d.ts +4 -0
- package/package.json +12 -4
- package/scripts/drain-check-local.mjs +8 -29
- package/scripts/drain-check.mysql.sql +3 -24
- package/scripts/drain-check.pg.sql +3 -24
- package/skills/update-config.md +1 -1
- package/wire-changes/server@7.146.0.json +3221 -0
- package/dist/approval-batch-census.d.ts +0 -27
- package/dist/approval-batch-census.js +0 -27
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { createAdoptionRunner } from "../../adoption/runner.js";
|
|
2
2
|
import { AdoptionRequestSchema } from "../../adoption/wire.js";
|
|
3
3
|
import { checkAdoptionPrincipalShape, checkAdoptionWidths } from "../../adoption/plan.js";
|
|
4
|
+
import { judgeAdoptionImportBinding, readAdoptionImportBody, runAdoptionImport } from "../../adoption/import.js";
|
|
5
|
+
import { limitRefusal } from "../../limit-refusal.js";
|
|
4
6
|
import { sendJson, sendError } from "../send.js";
|
|
5
7
|
import { gatedPrincipal, explicitOperatorOk, sendOperatorPrincipalsRequired, sendPrincipalRefusal } from "../principal-gate.js";
|
|
6
8
|
import { assertNever } from "../route-ctx.js";
|
|
@@ -39,7 +41,21 @@ function sendOutcome(res, out) {
|
|
|
39
41
|
function assertNoRejectCodeLeft(unhandled) {
|
|
40
42
|
throw new Error(`adoption: unhandled reject code ${JSON.stringify(unhandled)} — the wire contract's closed set and this switch have drifted apart`);
|
|
41
43
|
}
|
|
44
|
+
function sendAdoptionStoreRequired(res) {
|
|
45
|
+
sendError(res, 501, "capability.adoption_store_required", "adoption requires a SQL store backend (DB_BACKEND=mysql|pg)");
|
|
46
|
+
}
|
|
42
47
|
export async function handleAdoption(req, res, match, ctx) {
|
|
48
|
+
switch (match.decl.id) {
|
|
49
|
+
case "adoption-submit":
|
|
50
|
+
case "adoption-detail":
|
|
51
|
+
return operatorLane(req, res, match.decl.id, match.params, ctx);
|
|
52
|
+
case "adoption-sessions-import":
|
|
53
|
+
return sourceLane(req, res, match.params, ctx);
|
|
54
|
+
default:
|
|
55
|
+
return assertNever(match.decl.id);
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async function operatorLane(req, res, id, params, ctx) {
|
|
43
59
|
const { deps } = ctx;
|
|
44
60
|
const { readJson } = ctx.helpers;
|
|
45
61
|
const principal = gatedPrincipal(req, deps.config);
|
|
@@ -59,7 +75,7 @@ export async function handleAdoption(req, res, match, ctx) {
|
|
|
59
75
|
if (!fact.available) {
|
|
60
76
|
switch (fact.why) {
|
|
61
77
|
case "adoption_store_absent":
|
|
62
|
-
|
|
78
|
+
sendAdoptionStoreRequired(res);
|
|
63
79
|
return;
|
|
64
80
|
case "operator_principals_empty":
|
|
65
81
|
sendOperatorPrincipalsRequired(res);
|
|
@@ -70,14 +86,14 @@ export async function handleAdoption(req, res, match, ctx) {
|
|
|
70
86
|
}
|
|
71
87
|
const store = fact.backend.adoptionLog();
|
|
72
88
|
const runner = createAdoptionRunner({ store, dialect: deps.backend?.kind === "pg" ? "pg" : "mysql", now: Date.now, logger: deps.logger });
|
|
73
|
-
switch (
|
|
89
|
+
switch (id) {
|
|
74
90
|
case "adoption-detail": {
|
|
75
|
-
const
|
|
76
|
-
if (
|
|
91
|
+
const adoptionId = ctx.helpers.safeDecode(params.id);
|
|
92
|
+
if (adoptionId === null) {
|
|
77
93
|
sendError(res, 400, "request.id_invalid", "invalid adoption id");
|
|
78
94
|
return;
|
|
79
95
|
}
|
|
80
|
-
const out = await runner.get(
|
|
96
|
+
const out = await runner.get(adoptionId);
|
|
81
97
|
if (!out) {
|
|
82
98
|
sendError(res, 404, "not_found.adoption", "adoption not found");
|
|
83
99
|
return;
|
|
@@ -112,11 +128,69 @@ export async function handleAdoption(req, res, match, ctx) {
|
|
|
112
128
|
return;
|
|
113
129
|
}
|
|
114
130
|
default:
|
|
115
|
-
return assertNever(
|
|
131
|
+
return assertNever(id);
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
async function sourceLane(req, res, params, ctx) {
|
|
135
|
+
const { deps } = ctx;
|
|
136
|
+
if (ctx.helpers.rateLimited(req, res))
|
|
137
|
+
return;
|
|
138
|
+
const principal = gatedPrincipal(req, deps.config);
|
|
139
|
+
if (principal === undefined) {
|
|
140
|
+
sendPrincipalRefusal(res, req, deps.config);
|
|
141
|
+
return;
|
|
142
|
+
}
|
|
143
|
+
const face = facts.adoptionSessionImport(deps);
|
|
144
|
+
if (!face.available) {
|
|
145
|
+
switch (face.why) {
|
|
146
|
+
case "adoption_store_absent":
|
|
147
|
+
sendAdoptionStoreRequired(res);
|
|
148
|
+
return;
|
|
149
|
+
case "session_import_staging_absent":
|
|
150
|
+
sendError(res, 501, "capability.session_store_required", "importing sessions requires a durable session store (DB_BACKEND=mysql|pg|local)");
|
|
151
|
+
return;
|
|
152
|
+
default:
|
|
153
|
+
return assertNever(face.why);
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
const adoptionId = ctx.helpers.safeDecode(params.id);
|
|
157
|
+
if (adoptionId === null) {
|
|
158
|
+
sendError(res, 400, "request.id_invalid", "invalid adoption id");
|
|
159
|
+
return;
|
|
160
|
+
}
|
|
161
|
+
const binding = judgeAdoptionImportBinding(await face.backend.adoptionLog().getById(adoptionId), principal);
|
|
162
|
+
switch (binding.kind) {
|
|
163
|
+
case "absent":
|
|
164
|
+
sendError(res, 404, "not_found.adoption", "adoption not found");
|
|
165
|
+
return;
|
|
166
|
+
case "not_source":
|
|
167
|
+
sendError(res, 403, "auth.adoption_source_only", "only this adoption's source principal may import sessions into it (verbatim; an operator cannot import on its behalf)");
|
|
168
|
+
return;
|
|
169
|
+
case "not_adopted":
|
|
170
|
+
sendError(res, 409, "adoption.not_adopted", "this adoption has not completed (it is still in flight, or it was rejected); sessions can be imported once the operator's adoption reaches status adopted");
|
|
171
|
+
return;
|
|
172
|
+
case "bound":
|
|
173
|
+
break;
|
|
174
|
+
default:
|
|
175
|
+
return assertNever(binding);
|
|
176
|
+
}
|
|
177
|
+
const sessions = readAdoptionImportBody(await ctx.helpers.readJson(req));
|
|
178
|
+
if (sessions === undefined) {
|
|
179
|
+
sendError(res, 400, "request.body_shape", "invalid import body — expected exactly {sessions: [...]} (the destination is the adoption's; the body cannot name one)");
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
const cap = deps.config.adoptionImportMaxSessions;
|
|
183
|
+
if (sessions.length > cap) {
|
|
184
|
+
const refusal = limitRefusal("sessions", "entries", sessions.length, cap, { tail: "split the batch (the current cap is capabilities.adoptionImport.maxSessions), or have the operator raise ADOPTION_IMPORT_MAX_SESSIONS" });
|
|
185
|
+
sendError(res, 400, "request.field_invalid", refusal.message, refusal.facts);
|
|
186
|
+
return;
|
|
116
187
|
}
|
|
188
|
+
const results = await runAdoptionImport({ adoptionId: binding.adoptionId, toPrincipal: binding.toPrincipal, maxSessionBytes: deps.config.adoptionImportMaxSessionBytes, sessionStorage: face.sessionStorage }, sessions);
|
|
189
|
+
sendJson(res, 200, { results });
|
|
117
190
|
}
|
|
118
191
|
export const ADOPTION_ROUTES = [
|
|
119
192
|
{ id: "adoption-submit", path: "/v1/adoption", credentialGated: ["POST"], methods: ["POST"] },
|
|
120
193
|
{ id: "adoption-detail", pattern: /^\/v1\/adoption\/(?<id>[^/]+)$/, label: "/v1/adoption/:id", methods: ["GET"] },
|
|
194
|
+
{ id: "adoption-sessions-import", pattern: /^\/v1\/adoption\/(?<id>[^/]+)\/sessions$/, label: "/v1/adoption/:id/sessions", credentialGated: ["POST"], methods: ["POST"] },
|
|
121
195
|
];
|
|
122
196
|
//# sourceMappingURL=adoption.js.map
|
|
@@ -3,7 +3,8 @@ import { skillCardFacts } from "../../approval-card.js";
|
|
|
3
3
|
import { hostDecisionFacts, readDecider, retiredDecisionKeyFacts, DECIDED_BY_NOT_IN_PROOF } from "../../host-decision.js";
|
|
4
4
|
import { sameExecutionRecord } from "@sema-agent/core";
|
|
5
5
|
import { findParkedAgentForCheckpoint } from "../../parked-decide.js";
|
|
6
|
-
import { DECIDED_REPLAY_SCAN_CAP
|
|
6
|
+
import { DECIDED_REPLAY_SCAN_CAP } from "../../plugins/checkpoint-store-face.js";
|
|
7
|
+
import { approvalPayloadFingerprint } from "../../plugins/approval-payload-fingerprint.js";
|
|
7
8
|
import { carriesDeploymentListQuestion, standingAnswerDurablyRecordable } from "../../tool-approval.js";
|
|
8
9
|
import { APPROVAL_GATE_KINDS } from "../../approval-content-kind.js";
|
|
9
10
|
import { isParkedRunStatus } from "../../plugins/store-contracts.js";
|
|
@@ -35,6 +35,7 @@ import * as facts from "../../capability-facts.js";
|
|
|
35
35
|
import { judgeAutoModeArming } from "../../auto-mode-face.js";
|
|
36
36
|
import { coercePermissionModeStrict, PERMISSION_MODE_WORDS, taskHooksHonored } from "../../task-settings.js";
|
|
37
37
|
import { gatedPrincipal, sendPrincipalRefusal } from "../principal-gate.js";
|
|
38
|
+
import { readAdoptionImportCapability } from "../../adoption/import.js";
|
|
38
39
|
import { headReadOf } from "../../session-incarnation.js";
|
|
39
40
|
import { callerTrust } from "../caller-trust.js";
|
|
40
41
|
import { sessionRulesNamespaceFormsHonored } from "../../session-policy-wire.js";
|
|
@@ -121,6 +122,7 @@ export async function handleCapabilities(req, res, match, ctx) {
|
|
|
121
122
|
sharedMemory: facts.sharedMemoryRead(deps).available,
|
|
122
123
|
principalInboxDelivery: facts.principalInboxDelivery(deps).available,
|
|
123
124
|
adoption: facts.adoption(deps).available,
|
|
125
|
+
adoptionImport: await readAdoptionImportCapability(facts.adoptionSessionImport(deps), gatedPrincipal(req, deps.config), deps.config),
|
|
124
126
|
memoryBundle: facts.memoryBundle(deps).available,
|
|
125
127
|
memoryCompliance: facts.memoryCompliance(deps).available,
|
|
126
128
|
memoryOrigin: facts.memoryOrigin(deps).available,
|
|
@@ -147,7 +149,7 @@ export async function handleCapabilities(req, res, match, ctx) {
|
|
|
147
149
|
scratchpadDir: true,
|
|
148
150
|
subagentSteer: facts.subagentSteer(deps).available,
|
|
149
151
|
subagentResume: facts.subagentSteer(deps).available,
|
|
150
|
-
taskSettings: { permissions: true, permissionMode: true, model: true, outputStyle: true, env: DEPLOYMENT_SHAPE_PREDICATES.callerCwd.holds(deps.config), hooks: taskHooksHonored(deps.config), pluginHooks: taskHooksHonored(deps.config), managedHookGroups: taskHooksHonored(deps.config), httpHookAllowlists: taskHooksHonored(deps.config), tightenOnlySeats: true, approvalFrameFamilies: true },
|
|
152
|
+
taskSettings: { permissions: true, permissionMode: true, model: true, outputStyle: true, env: DEPLOYMENT_SHAPE_PREDICATES.callerCwd.holds(deps.config), hooks: taskHooksHonored(deps.config), pluginHooks: taskHooksHonored(deps.config), managedHookGroups: taskHooksHonored(deps.config), httpHookAllowlists: taskHooksHonored(deps.config), tightenOnlySeats: true, approvalFrameFamilies: true, autoCompactEnabled: true },
|
|
151
153
|
settings: { permissions: { allowGrant: true, allowLayer: true, layers: true, layeredAllow: true, callerTrust: callerTrust(req, deps.config).trust } },
|
|
152
154
|
permissionModeAuto: {
|
|
153
155
|
accepted: true,
|
|
@@ -187,6 +189,7 @@ export async function handleCapabilities(req, res, match, ctx) {
|
|
|
187
189
|
mcpProbe: true,
|
|
188
190
|
mcpAssertionHeaderSent: MCP_ASSERTION_HEADER_SENT,
|
|
189
191
|
mcpTransportKinds: [...MCP_REQUEST_TRANSPORT_KINDS],
|
|
192
|
+
engine: { handover: facts.engineHandover(deps).available },
|
|
190
193
|
mcpElicitation: facts.elicitation(deps).available,
|
|
191
194
|
askUserQuestion: facts.askUserQuestion(deps).available,
|
|
192
195
|
toolApproval: facts.toolApproval(deps).available,
|
|
@@ -13,6 +13,7 @@ import { type PostureKnobReading, type PostureSource } from "../../posture-sourc
|
|
|
13
13
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
14
14
|
import type { WiringManifest } from "@sema-agent/core";
|
|
15
15
|
import { type StreamApprovalGate, type StreamApprovalGateInput } from "../../tool-approval.js";
|
|
16
|
+
import { verifiedIdentitySource } from "../principal-gate.js";
|
|
16
17
|
import type { RouteCtx, RouteMatch, RouteIdsOf } from "../route-ctx.js";
|
|
17
18
|
/** 流内审批门的读数形:上场即 `"active"`,否则是那**四**个合取项里**第一个**不满足的原因词
|
|
18
19
|
* (与 `resolveStreamApprovalGate` 同一闭集,词表**取型**自它 ⇒ 增删 reason 在此处自动跟随/编译红;
|
|
@@ -82,23 +83,17 @@ export declare function assertStaticWiringConsistent(facts: StaticWiringFacts, l
|
|
|
82
83
|
warn: (msg: string, meta?: Record<string, unknown>) => void;
|
|
83
84
|
} | undefined): StaticWiringAudit;
|
|
84
85
|
/**
|
|
85
|
-
* [ref]③ clay 裁 (b)
|
|
86
|
-
*
|
|
86
|
+
* 诊断面的**远程来源门**(单一属主,端点与测试同吃;[ref]③ clay 裁 (b) 的那只门,7.63.0 起按身份判):远程请求后面没有
|
|
87
|
+
* **验过的身份**(`verifiedIdentitySource`:service 凭据 / 鉴权桥登录令牌 / 直连门签名令牌)⇒ 拒;本机(loopback)照读。
|
|
87
88
|
*
|
|
88
|
-
*
|
|
89
|
-
*
|
|
90
|
-
*
|
|
91
|
-
* (壳缺省钉 BIND_HOST=127.0.0.1,local curl 照常),对远程侦察 fail-closed;配了 token 的部署远程读
|
|
92
|
-
* 走认证(全局门),不进本臂。
|
|
89
|
+
* 名单里的名字、单用户声明放进来的「每个调用方」,都只在这次请求带可验身份时才是身份 —— 没有凭据可验的部署上,主体头是谁都能写的
|
|
90
|
+
* 字符串,端口误暴露到公网就是侦察面(装配拓扑 / 治理姿态 / 写保护名表)。配了 service 凭据的部署上,到得了这里的请求都过了全局凭据门、
|
|
91
|
+
* 必然带着验过的身份,本判不咬;不要求静态凭据在场(鉴权桥的登录令牌就是身份)。
|
|
93
92
|
*
|
|
94
|
-
*
|
|
95
|
-
*
|
|
96
|
-
* 边界由反代+token 承担)。`remoteAddress` 缺席(socket 已断等边缘)⇒ 判拒(fail-closed,安全轴方向)。
|
|
93
|
+
* 判源 = TCP 对端地址(`req.socket.remoteAddress`),**非任何头**(XFF 类头在无反代形上是自造面;有反代的部署必然配凭据)。
|
|
94
|
+
* `remoteAddress` 缺席(socket 已断等边缘)⇒ 判拒(fail-closed)。
|
|
97
95
|
*/
|
|
98
|
-
export declare function
|
|
99
|
-
authToken?: string;
|
|
100
|
-
authTokens?: Record<string, string>;
|
|
101
|
-
}): boolean;
|
|
96
|
+
export declare function remoteWithoutVerifiedIdentity(req: IncomingMessage, config: Parameters<typeof verifiedIdentitySource>[1]): boolean;
|
|
102
97
|
export declare function handleDiagnostics(req: IncomingMessage, res: ServerResponse, match: RouteMatch<DiagnosticsRouteId>, ctx: RouteCtx): Promise<void>;
|
|
103
98
|
export declare const DIAGNOSTICS_ROUTES: readonly [{
|
|
104
99
|
readonly id: "diagnostics-wiring";
|
|
@@ -95,32 +95,22 @@ export function assertStaticWiringConsistent(facts, logger) {
|
|
|
95
95
|
}
|
|
96
96
|
return audit;
|
|
97
97
|
}
|
|
98
|
-
export function
|
|
99
|
-
|
|
100
|
-
if (anyServiceAuth)
|
|
101
|
-
return false;
|
|
102
|
-
return !isLoopbackAddress(remoteAddress);
|
|
98
|
+
export function remoteWithoutVerifiedIdentity(req, config) {
|
|
99
|
+
return !isLoopbackAddress(req.socket.remoteAddress) && verifiedIdentitySource(req, config) === undefined;
|
|
103
100
|
}
|
|
104
101
|
export async function handleDiagnostics(req, res, match, ctx) {
|
|
105
102
|
const { deps } = ctx;
|
|
106
103
|
switch (match.decl.id) {
|
|
107
104
|
case "diagnostics-wiring": {
|
|
108
|
-
if (
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
sendError(res, 403, "auth.operator_only", "wiring diagnostics are operator-only on a multi-tenant worker");
|
|
116
|
-
return;
|
|
117
|
-
}
|
|
118
|
-
if (!isLoopbackAddress(req.socket.remoteAddress) && verifiedIdentitySource(req, deps.config) === undefined) {
|
|
119
|
-
sendError(res, 403, "auth.loopback_only", "wiring diagnostics on a zero-credential deployment are readable from loopback only — configure SERVICE_AUTH_TOKEN to read remotely");
|
|
120
|
-
return;
|
|
121
|
-
}
|
|
105
|
+
if (!facts.operatorLane(deps).available) {
|
|
106
|
+
sendOperatorPrincipalsRequired(res);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
if (!explicitOperatorOk(gatedPrincipal(req, deps.config), deps.config)) {
|
|
110
|
+
sendError(res, 403, "auth.operator_only", "wiring diagnostics are operator-only");
|
|
111
|
+
return;
|
|
122
112
|
}
|
|
123
|
-
|
|
113
|
+
if (remoteWithoutVerifiedIdentity(req, deps.config)) {
|
|
124
114
|
sendError(res, 403, "auth.loopback_only", "wiring diagnostics on a zero-credential deployment are readable from loopback only — configure SERVICE_AUTH_TOKEN to read remotely");
|
|
125
115
|
return;
|
|
126
116
|
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `POST /v1/engine/handover` · `POST /v1/engine/attach` —— 附着租约的交接车道([ref] v3,「Move to background and exit」)。
|
|
3
|
+
*
|
|
4
|
+
* 一只门的两扇口:交接口置交接位(壳随后自己退出、不 SIGTERM 引擎;后台 shell 在跑时引擎不退),attach 口清位(下一只壳收回)。车道、窗、
|
|
5
|
+
* 工作谓词全在租约腿(`boot/engine-lease.ts`);本域只读写**交接门**(`drainState.engineHandover`,收尾链装配时进盒子)。
|
|
6
|
+
* · 门序:身份(多租户形的主体门,与运维口同一只铸点)→ 能力事实 `engineHandover`(与 `capabilities.engine.handover` 同读;不可用 ⇒ 501
|
|
7
|
+
* `capability.engine_handover_unavailable`,按 why 两句)→ 验型(体坏 ⇒ 400,零状态变化)→ 写门。billable=false,**不吃排空 503**
|
|
8
|
+
* (排空一开始租约腿在它的下一拍收摊,能力事实随即答 501;那一拍之内的交接 / attach 无害 —— 引擎已在退)。
|
|
9
|
+
* · 交接体只收 `{ reason: "background_exit" }`(闭集);attach 体只收空对象或空体(字面 `null` 与空体同读 —— 共用读体器的全服务律)。
|
|
10
|
+
* 非对象体 ⇒ 400 `request.invalid_json`(`not_object`)。
|
|
11
|
+
* · 能力事实读两次、是同一只函数:读体之前读一次(决定 501 先于 400),验完体、写门之前**无 await** 再读一次 —— 读体途中腿停了(停机开始)
|
|
12
|
+
* 就答 501,不拿读体之前的旧事实去写一只已不在观察的门(codex r1 [medium])。
|
|
13
|
+
* · 两口幂等:再次交接回同一个 `since`;不在交接车道时 attach 照回此刻车道(`handedOverForMs` 缺席)。
|
|
14
|
+
*/
|
|
15
|
+
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
16
|
+
import type { RouteCtx, RouteMatch, RouteIdsOf } from "../route-ctx.js";
|
|
17
|
+
export declare const ENGINE_HANDOVER_PATH = "/v1/engine/handover";
|
|
18
|
+
export declare const ENGINE_ATTACH_PATH = "/v1/engine/attach";
|
|
19
|
+
export declare function handleEngine(req: IncomingMessage, res: ServerResponse, match: RouteMatch<EngineRouteId>, ctx: RouteCtx): Promise<void>;
|
|
20
|
+
export declare const ENGINE_ROUTES: readonly [{
|
|
21
|
+
readonly id: "engine-handover";
|
|
22
|
+
readonly path: "/v1/engine/handover";
|
|
23
|
+
readonly methods: readonly ["POST"];
|
|
24
|
+
}, {
|
|
25
|
+
readonly id: "engine-attach";
|
|
26
|
+
readonly path: "/v1/engine/attach";
|
|
27
|
+
readonly methods: readonly ["POST"];
|
|
28
|
+
}];
|
|
29
|
+
type EngineRouteId = RouteIdsOf<typeof ENGINE_ROUTES>;
|
|
30
|
+
export {};
|
|
31
|
+
//# sourceMappingURL=engine.d.ts.map
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import { sendJson, sendError, sendHttpError, invalidJsonError } from "../send.js";
|
|
2
|
+
import { gatedPrincipal, sendPrincipalRefusal } from "../principal-gate.js";
|
|
3
|
+
import * as facts from "../../capability-facts.js";
|
|
4
|
+
import { HANDOVER_REASONS } from "../../boot/engine-lease.js";
|
|
5
|
+
import { assertNever } from "../route-ctx.js";
|
|
6
|
+
export const ENGINE_HANDOVER_PATH = "/v1/engine/handover";
|
|
7
|
+
export const ENGINE_ATTACH_PATH = "/v1/engine/attach";
|
|
8
|
+
const HANDOVER_REASONS_SPELLED = HANDOVER_REASONS.map((r) => `"${r}"`).join(", ");
|
|
9
|
+
const ATTACH_BODY_MESSAGE = "the attach request takes no fields (send {} or an empty body) — nothing was changed";
|
|
10
|
+
function isPlainObject(v) {
|
|
11
|
+
return typeof v === "object" && v !== null && !Array.isArray(v);
|
|
12
|
+
}
|
|
13
|
+
function readHandoverReason(body) {
|
|
14
|
+
const keys = Object.keys(body);
|
|
15
|
+
if (keys.length !== 1 || keys[0] !== "reason")
|
|
16
|
+
return undefined;
|
|
17
|
+
const reason = body.reason;
|
|
18
|
+
return HANDOVER_REASONS.find((r) => r === reason);
|
|
19
|
+
}
|
|
20
|
+
function sendHandoverUnavailable(res, why) {
|
|
21
|
+
switch (why) {
|
|
22
|
+
case "engine_handover_lane_absent":
|
|
23
|
+
sendError(res, 501, "capability.engine_handover_unavailable", "handover is not available on this engine: its attachment lease is not armed (neither ENGINE_AUTO_EXIT nor SEMA_PARENT_PID), or the deployment is multi-tenant (REQUIRE_PRINCIPAL=true) — GET /v1/capabilities reports engine.handover=false; exit and stop tasks instead");
|
|
24
|
+
return;
|
|
25
|
+
case "engine_lease_stopped":
|
|
26
|
+
sendError(res, 501, "capability.engine_handover_unavailable", "this engine is shutting down: its attachment lease has stopped observing, so there is nothing to hand over or attach to");
|
|
27
|
+
return;
|
|
28
|
+
default:
|
|
29
|
+
return assertNever(why);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export async function handleEngine(req, res, match, ctx) {
|
|
33
|
+
const { deps } = ctx;
|
|
34
|
+
if (deps.config.requirePrincipal && gatedPrincipal(req, deps.config) === undefined) {
|
|
35
|
+
sendPrincipalRefusal(res, req, deps.config);
|
|
36
|
+
return;
|
|
37
|
+
}
|
|
38
|
+
const before = facts.engineHandover(deps);
|
|
39
|
+
if (!before.available) {
|
|
40
|
+
sendHandoverUnavailable(res, before.why);
|
|
41
|
+
return;
|
|
42
|
+
}
|
|
43
|
+
const body = await ctx.helpers.readJson(req);
|
|
44
|
+
if (!isPlainObject(body)) {
|
|
45
|
+
sendHttpError(res, invalidJsonError("not_object"));
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
let write;
|
|
49
|
+
switch (match.decl.id) {
|
|
50
|
+
case "engine-handover": {
|
|
51
|
+
const reason = readHandoverReason(body);
|
|
52
|
+
if (reason === undefined) {
|
|
53
|
+
sendError(res, 400, "request.field_invalid", `the handover request must be exactly { reason } with reason one of ${HANDOVER_REASONS_SPELLED} — nothing was changed`);
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
write = (door) => door.enter(reason);
|
|
57
|
+
break;
|
|
58
|
+
}
|
|
59
|
+
case "engine-attach": {
|
|
60
|
+
if (Object.keys(body).length > 0) {
|
|
61
|
+
sendError(res, 400, "request.field_invalid", ATTACH_BODY_MESSAGE);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
write = (door) => door.attach();
|
|
65
|
+
break;
|
|
66
|
+
}
|
|
67
|
+
default:
|
|
68
|
+
return assertNever(match.decl.id);
|
|
69
|
+
}
|
|
70
|
+
const now = facts.engineHandover(deps);
|
|
71
|
+
if (!now.available) {
|
|
72
|
+
sendHandoverUnavailable(res, now.why);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
sendJson(res, 200, write(now.door));
|
|
76
|
+
}
|
|
77
|
+
export const ENGINE_ROUTES = [
|
|
78
|
+
{ id: "engine-handover", path: ENGINE_HANDOVER_PATH, methods: ["POST"] },
|
|
79
|
+
{ id: "engine-attach", path: ENGINE_ATTACH_PATH, methods: ["POST"] },
|
|
80
|
+
];
|
|
81
|
+
//# sourceMappingURL=engine.js.map
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
2
|
import { sendJson, sendError } from "../send.js";
|
|
3
3
|
import { sentMemoryStoreRefusal } from "../memory-store-refusal-reply.js";
|
|
4
|
+
import { sentControlPlaneCorrupt } from "../memory-control-plane-corrupt-reply.js";
|
|
4
5
|
import { buildOriginFencedBundle, readOriginAware } from "../../memory-origin-fence.js";
|
|
5
6
|
import { gatedPrincipal, explicitOperatorOk, sendOperatorPrincipalsRequired, sendPrincipalRefusal } from "../principal-gate.js";
|
|
6
7
|
import { assertNever } from "../route-ctx.js";
|
|
@@ -42,6 +43,8 @@ function sentClassifiedFailure(res, ctx, face, err) {
|
|
|
42
43
|
return true;
|
|
43
44
|
if (sentMemoryStoreRefusal(res, err, ctx.deps.logger))
|
|
44
45
|
return true;
|
|
46
|
+
if (sentControlPlaneCorrupt(res, err, { kind: "operator" }))
|
|
47
|
+
return true;
|
|
45
48
|
ctx.deps.logger?.warn?.(`memory_bundle_${face}_failed`, { err: String(err) });
|
|
46
49
|
return false;
|
|
47
50
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { ControlPlaneCorruptError } from "@sema-agent/core";
|
|
3
2
|
import { sendJson, sendError } from "../send.js";
|
|
4
3
|
import { sentMemoryLayerRefusal } from "../memory-layer-reply.js";
|
|
4
|
+
import { sentControlPlaneCorrupt } from "../memory-control-plane-corrupt-reply.js";
|
|
5
5
|
import { gatedPrincipal, explicitOperatorOk, sendPrincipalRefusal, sendOperatorPrincipalsRequired } from "../principal-gate.js";
|
|
6
6
|
import { assertNever } from "../route-ctx.js";
|
|
7
7
|
import * as facts from "../../capability-facts.js";
|
|
@@ -104,7 +104,7 @@ export async function handleMemoryConsolidation(req, res, match, ctx) {
|
|
|
104
104
|
const scope = "scope" in decided ? decided.scope : undefined;
|
|
105
105
|
let row;
|
|
106
106
|
try {
|
|
107
|
-
row = scope !== undefined ? faces.lastRun(scope) : undefined;
|
|
107
|
+
row = scope !== undefined ? await faces.lastRun(scope) : undefined;
|
|
108
108
|
}
|
|
109
109
|
catch (err) {
|
|
110
110
|
if (sentMemoryLayerRefusal(res, err, { kind: "operator" }))
|
|
@@ -160,10 +160,8 @@ export async function handleMemoryConsolidation(req, res, match, ctx) {
|
|
|
160
160
|
sendError(res, 409, "memory.consolidation_refused", `memory consolidation refused (${coreCode}): ${err instanceof Error ? err.message : String(err)}`);
|
|
161
161
|
return;
|
|
162
162
|
}
|
|
163
|
-
if (err
|
|
164
|
-
sendError(res, 500, "internal.memory_control_plane_corrupt", err.message);
|
|
163
|
+
if (sentControlPlaneCorrupt(res, err, { kind: "operator" }))
|
|
165
164
|
return;
|
|
166
|
-
}
|
|
167
165
|
ctx.deps.logger?.warn?.("memory_consolidation_run_failed", { scope: decided.scope, err: String(err) });
|
|
168
166
|
sendError(res, 500, "internal.error", "memory consolidation run failed");
|
|
169
167
|
}
|
|
@@ -78,7 +78,7 @@
|
|
|
78
78
|
* 分层:本模块不值 import `server.ts`(那条边闭合运行时装载环),只 `import type`。
|
|
79
79
|
*/
|
|
80
80
|
import type { IncomingMessage, ServerResponse } from "node:http";
|
|
81
|
-
import {
|
|
81
|
+
import type { OriginClearanceRow } from "@sema-agent/core";
|
|
82
82
|
import type { RouteCtx, RouteMatch, RouteIdsOf } from "../route-ctx.js";
|
|
83
83
|
export declare const MEMORY_ORIGIN_EXTERNAL_PATH = "/v1/memory/origin/external";
|
|
84
84
|
export declare const MEMORY_ORIGIN_CLEARANCES_PATH = "/v1/memory/origin/clearances";
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { z } from "zod";
|
|
2
|
-
import { ControlPlaneCorruptError } from "@sema-agent/core";
|
|
3
2
|
import { sendJson, sendError } from "../send.js";
|
|
4
3
|
import { sentMemoryStoreRefusal } from "../memory-store-refusal-reply.js";
|
|
4
|
+
import { sentControlPlaneCorrupt } from "../memory-control-plane-corrupt-reply.js";
|
|
5
5
|
import { buildOriginFence, readOriginAware } from "../../memory-origin-fence.js";
|
|
6
6
|
import { readLayerSeat, sentMemoryLayerRefusal } from "../memory-layer-reply.js";
|
|
7
7
|
import { gatedPrincipal, explicitOperatorOk, sendOperatorPrincipalsRequired, sendPrincipalRefusal } from "../principal-gate.js";
|
|
@@ -59,10 +59,8 @@ function sentClassifiedFailure(res, ctx, face, err) {
|
|
|
59
59
|
}
|
|
60
60
|
if (face !== "clearances" && sentMemoryStoreRefusal(res, err, ctx.deps.logger))
|
|
61
61
|
return true;
|
|
62
|
-
if (err
|
|
63
|
-
sendError(res, 500, "internal.memory_control_plane_corrupt", err.message);
|
|
62
|
+
if (sentControlPlaneCorrupt(res, err, { kind: "operator" }))
|
|
64
63
|
return true;
|
|
65
|
-
}
|
|
66
64
|
ctx.deps.logger?.warn?.(`memory_origin_${face}_failed`, { err: String(err) });
|
|
67
65
|
return false;
|
|
68
66
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { formatUserScope } from "@sema-agent/core";
|
|
1
|
+
import { formatUserScope, isReplicableScope } from "@sema-agent/core";
|
|
2
2
|
import { parseMemorySyncRequest } from "../../memory-sync.js";
|
|
3
3
|
import { memorySyncIdentityRule } from "../../memory-sync-identity.js";
|
|
4
4
|
import * as facts from "../../capability-facts.js";
|
|
@@ -160,6 +160,10 @@ export async function handleMemoryPolicy(req, res, match, ctx) {
|
|
|
160
160
|
sendError(res, 400, "memory_sync_invalid_scope", "missing :scope");
|
|
161
161
|
return;
|
|
162
162
|
}
|
|
163
|
+
if (!isReplicableScope(scope)) {
|
|
164
|
+
sendError(res, 400, "memory_sync_invalid_scope", "a userlocal: memory layer never leaves the store it is written in — it is not synced");
|
|
165
|
+
return;
|
|
166
|
+
}
|
|
163
167
|
if (sendScopeGateRefusal(res, await gateMemoryScope(deps, principal, scope, "write")))
|
|
164
168
|
return;
|
|
165
169
|
const body = await readJson(req);
|
|
@@ -12,12 +12,9 @@ export async function handleObservability(req, res, match, ctx) {
|
|
|
12
12
|
sendOperatorPrincipalsRequired(res);
|
|
13
13
|
return;
|
|
14
14
|
}
|
|
15
|
-
if (deps.config.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
sendError(res, 403, "auth.operator_only", "outcomes view is operator-only on a multi-tenant worker");
|
|
19
|
-
return;
|
|
20
|
-
}
|
|
15
|
+
if (!explicitOperatorOk(gatedPrincipal(req, deps.config), deps.config)) {
|
|
16
|
+
sendError(res, 403, "auth.operator_only", "the outcomes view is operator-only");
|
|
17
|
+
return;
|
|
21
18
|
}
|
|
22
19
|
if (!fact.available) {
|
|
23
20
|
switch (fact.why) {
|
package/dist/http/routes/runs.js
CHANGED
|
@@ -4,7 +4,7 @@ import { z } from "zod";
|
|
|
4
4
|
import { uuidv7, mintCheckpointToken, CheckpointError, policyCannotAnswer, validatePendingSteer, TASK_OUTPUT_REPLAY_KINDS, isSystemInjectionPriority } from "@sema-agent/core";
|
|
5
5
|
import { isTerminalRunStatus, isParkedRunStatus, runProvenElsewhere } from "../../plugins/store-contracts.js";
|
|
6
6
|
import { askOwnerAdmits, askRowCarriesOwner } from "../../plugins/approval-ask-store-sql.js";
|
|
7
|
-
import { LIVE_RUN_GATE_KINDS, TERMINAL_PARK_GATE_KINDS } from "../../plugins/checkpoint-store-
|
|
7
|
+
import { LIVE_RUN_GATE_KINDS, TERMINAL_PARK_GATE_KINDS } from "../../plugins/checkpoint-store-face.js";
|
|
8
8
|
import { redactSecrets } from "../../trace/redact.js";
|
|
9
9
|
import { isUuidV7, encodeCheckpointScope } from "../../security.js";
|
|
10
10
|
import { redactSteerIn, STEER_IN_MAX_CHARS, STEER_IN_MAX_REQUEST_CHARS } from "../../orchestration/workflow-agent-steer.js";
|
|
@@ -1578,7 +1578,7 @@ export async function handleRunVerbs(req, res, match, ctx) {
|
|
|
1578
1578
|
export async function createDurableRun(req, res, ctx, prepared, idem) {
|
|
1579
1579
|
const { deps } = ctx;
|
|
1580
1580
|
const { idemCache } = ctx.registry;
|
|
1581
|
-
const { leaseDenied, usageWindowDenied } = ctx.helpers;
|
|
1581
|
+
const { leaseDenied, usageWindowDenied, admitRun } = ctx.helpers;
|
|
1582
1582
|
const source = ctx.req.source;
|
|
1583
1583
|
const runs = facts.durableRuns(deps);
|
|
1584
1584
|
if (!runs.available) {
|
|
@@ -1600,6 +1600,9 @@ export async function createDurableRun(req, res, ctx, prepared, idem) {
|
|
|
1600
1600
|
}
|
|
1601
1601
|
if ((await leaseDenied(req, res)) || (await usageWindowDenied(req, res)))
|
|
1602
1602
|
return null;
|
|
1603
|
+
const runSlot = admitRun(req, res);
|
|
1604
|
+
if (runSlot === undefined)
|
|
1605
|
+
return null;
|
|
1603
1606
|
return await idemCache.run(idem !== undefined ? inflightKeyOf(idem, "durable", clientTaskId) : undefined, async () => {
|
|
1604
1607
|
const out = await mintAndDriveDurableRun({ deps, registry: ctx.registry, helpers: ctx.helpers, local: ctx.local, legs: ctx.legs }, runStore, {
|
|
1605
1608
|
prepared,
|
|
@@ -1609,9 +1612,10 @@ export async function createDurableRun(req, res, ctx, prepared, idem) {
|
|
|
1609
1612
|
elicitOwner: submitter ?? null,
|
|
1610
1613
|
source,
|
|
1611
1614
|
identity: runIdentityOf(req, deps.config, prepared.auth?.principal ?? null),
|
|
1615
|
+
runSlot,
|
|
1612
1616
|
});
|
|
1613
1617
|
return out.existing ? await replayOfExistingRun(out.existing, caller, "durable", deps, runStore) : out;
|
|
1614
|
-
});
|
|
1618
|
+
}).finally(() => runSlot.release());
|
|
1615
1619
|
}
|
|
1616
1620
|
function clientTaskIdOf(body) {
|
|
1617
1621
|
const raw = typeof body === "object" && body !== null ? body.taskId : undefined;
|