@sema-agent/server 7.149.0 → 7.150.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 +122 -9
- package/README.md +1 -1
- package/README.zh-CN.md +1 -1
- package/USAGE.md +39 -15
- package/dist/approval-card.d.ts +1 -1
- package/dist/approval-gate-currency.d.ts +1 -1
- package/dist/audit.d.ts +1 -1
- package/dist/audit.js +2 -2
- package/dist/background-session-reap.d.ts +1 -1
- package/dist/boot/deferred-sandbox-path-env.d.ts +5 -3
- package/dist/boot/deferred-sandbox-path-env.js +1 -2
- package/dist/boot/parked-revive-gate.d.ts +5 -5
- package/dist/boot/parked-revive-gate.js +2 -3
- package/dist/boot/resolve-spec.d.ts +4 -5
- package/dist/boot/resolve-spec.js +61 -25
- package/dist/boot/retention-lane.d.ts +1 -1
- package/dist/boot/session-faces.js +21 -21
- package/dist/boot/stage-03-store-backend.js +2 -2
- package/dist/boot/stage-06-runners.js +1 -2
- package/dist/boot/stage-07-capability-layer.js +1 -1
- package/dist/boot/stage-10-http-server.d.ts +33 -1
- package/dist/boot/stage-10-http-server.js +9 -4
- package/dist/boot/web-admin.d.ts +1 -1
- package/dist/capability-facts.d.ts +65 -56
- package/dist/capability-facts.js +42 -35
- package/dist/config-catalog.js +1 -1
- package/dist/config-types.d.ts +12 -11
- package/dist/deployment-governance.d.ts +7 -28
- package/dist/deployment-governance.js +1 -14
- package/dist/device-ws-hub.d.ts +1 -0
- package/dist/device-ws-hub.js +64 -28
- package/dist/device-ws-protocol.d.ts +20 -6
- package/dist/device-ws-protocol.js +9 -2
- package/dist/engine-identity.d.ts +7 -1
- package/dist/engine-identity.js +5 -0
- package/dist/field-conflict.d.ts +2 -2
- package/dist/fleet/engine-signal.d.ts +14 -1
- package/dist/fleet/engine-signal.js +5 -1
- package/dist/fleet/fleet-reconciler.d.ts +1 -1
- package/dist/fleet/serving-lease.d.ts +18 -3
- package/dist/fleet/serving-lease.js +81 -35
- package/dist/fleet-client.d.ts +13 -11
- package/dist/fleet-client.js +53 -33
- package/dist/history-anchor.js +1 -1
- package/dist/hitl-delivery.d.ts +1 -3
- package/dist/hitl-delivery.js +1 -1
- package/dist/http/active-run-conflict.d.ts +3 -7
- package/dist/http/active-run-conflict.js +2 -2
- package/dist/http/admission.js +2 -2
- package/dist/http/approval-sweeps.js +2 -1
- package/dist/http/caller-trust.d.ts +2 -2
- package/dist/http/caller-trust.js +3 -3
- package/dist/http/checkpoint-ctx.d.ts +18 -63
- package/dist/http/checkpoint-ctx.js +1 -24
- package/dist/http/claim-heartbeat.d.ts +4 -4
- package/dist/http/claim-heartbeat.js +3 -3
- package/dist/http/dispatch.js +2 -2
- package/dist/http/durable-run-leg.js +4 -4
- package/dist/http/owner-access.d.ts +243 -19
- package/dist/http/owner-access.js +184 -5
- package/dist/http/readiness.d.ts +4 -2
- package/dist/http/resume-ctx-read.js +16 -1
- package/dist/http/resume-legs.js +18 -14
- package/dist/http/route-ctx.d.ts +23 -11
- package/dist/http/routes/a2a-serve.js +15 -14
- package/dist/http/routes/approvals-assistant.d.ts +3 -2
- package/dist/http/routes/approvals-assistant.js +8 -9
- package/dist/http/routes/capabilities.js +4 -3
- package/dist/http/routes/config-catalog.d.ts +1 -1
- package/dist/http/routes/mcp-reconnect.js +2 -2
- package/dist/http/routes/memory-origin.d.ts +1 -1
- package/dist/http/routes/notify-wake.js +2 -3
- package/dist/http/routes/projects.d.ts +1 -0
- package/dist/http/routes/projects.js +5 -3
- package/dist/http/routes/retention-ops.d.ts +1 -1
- package/dist/http/routes/run-permission-mode.d.ts +1 -1
- package/dist/http/routes/run-permission-mode.js +2 -2
- package/dist/http/routes/runs.d.ts +1 -1
- package/dist/http/routes/runs.js +23 -30
- package/dist/http/routes/session-memory-sync.js +4 -5
- package/dist/http/routes/session-sync.js +3 -7
- package/dist/http/routes/sessions.d.ts +1 -1
- package/dist/http/routes/sessions.js +18 -44
- package/dist/http/routes/tasks.js +9 -8
- package/dist/http/routes/trace-usage.js +14 -14
- package/dist/http/routes/workflows.d.ts +1 -0
- package/dist/http/routes/workflows.js +20 -38
- package/dist/http/server.d.ts +8 -4
- package/dist/http/server.js +5 -1
- package/dist/http/stored-body-replay.d.ts +3 -24
- package/dist/http/stored-body-replay.js +2 -12
- package/dist/http/submit-ctx.d.ts +1 -2
- package/dist/http/submit-ctx.js +3 -2
- package/dist/http/submit-replay.d.ts +15 -2
- package/dist/http/submit-replay.js +10 -4
- package/dist/http/wire-types.d.ts +6 -3
- package/dist/leader/endpoint.js +9 -8
- package/dist/leg-facts.d.ts +8 -2
- package/dist/leg-facts.js +1 -0
- package/dist/mcp-authorization-face.d.ts +18 -14
- package/dist/mcp-authorization-face.js +3 -2
- package/dist/memory-store-refusal.d.ts +1 -1
- package/dist/observability/corrupt-read-seat.d.ts +1 -1
- package/dist/observability/fail-open.d.ts +5 -5
- package/dist/observability/fail-open.js +5 -5
- package/dist/observability/logger.d.ts +7 -0
- package/dist/observability/logger.js +3 -1
- package/dist/observability/run-terminal.d.ts +1 -1
- package/dist/owner-faces.d.ts +27 -3
- package/dist/owner-faces.js +2 -0
- package/dist/peer-seat.d.ts +1 -1
- package/dist/peer-seat.js +52 -59
- package/dist/plugins/exec-path-law.d.ts +34 -0
- package/dist/plugins/exec-path-law.js +13 -0
- package/dist/plugins/file-run-store.js +1 -1
- package/dist/plugins/local-checkpoint-store.d.ts +4 -1
- package/dist/plugins/local-checkpoint-store.js +3 -0
- package/dist/plugins/memory-run-store.js +1 -1
- package/dist/plugins/one-time-migrations.d.ts +74 -49
- package/dist/plugins/one-time-migrations.js +134 -69
- package/dist/plugins/pg-pool.js +4 -0
- package/dist/plugins/posix-shell-fs.js +4 -2
- package/dist/plugins/remote-env-adb.js +3 -2
- package/dist/plugins/remote-env-device.js +8 -6
- package/dist/plugins/remote-env-e2b.d.ts +3 -1
- package/dist/plugins/remote-env-e2b.js +11 -8
- package/dist/plugins/remote-env-host.d.ts +1 -1
- package/dist/plugins/remote-env-host.js +20 -11
- package/dist/plugins/remote-env-k8s.js +3 -2
- package/dist/plugins/remote-env-local-docker.js +3 -2
- package/dist/plugins/remote-env-ssh.js +4 -3
- package/dist/plugins/remote-shell.d.ts +3 -1
- package/dist/plugins/remote-shell.js +3 -3
- package/dist/plugins/replica-registration.d.ts +35 -0
- package/dist/plugins/replica-registration.js +48 -0
- package/dist/plugins/retention-lane-store-sql.d.ts +1 -1
- package/dist/plugins/run-store-sql.d.ts +1 -1
- package/dist/plugins/run-store-sql.js +2 -2
- package/dist/plugins/scenario-prefix-switch-m42.d.ts +6 -12
- package/dist/plugins/scenario-prefix-switch-m42.js +7 -5
- package/dist/plugins/schema-consistency.d.ts +7 -5
- package/dist/plugins/schema-consistency.js +29 -16
- package/dist/plugins/schema-drift-sentence.js +1 -1
- package/dist/plugins/serving-requirement.d.ts +49 -0
- package/dist/plugins/serving-requirement.js +53 -0
- package/dist/plugins/stop-then-start-sentence.d.ts +42 -3
- package/dist/plugins/stop-then-start-sentence.js +44 -0
- package/dist/plugins/store-backend.d.ts +1 -1
- package/dist/plugins/store-contracts.d.ts +12 -2
- package/dist/plugins/store-contracts.js +3 -0
- package/dist/plugins/tidb-pool.js +4 -0
- package/dist/process-instance.d.ts +3 -0
- package/dist/process-instance.js +7 -0
- package/dist/project-context.d.ts +66 -0
- package/dist/project-context.js +70 -0
- package/dist/question.d.ts +9 -21
- package/dist/question.js +28 -19
- package/dist/run-cancel-card.d.ts +1 -1
- package/dist/run-cancel-card.js +2 -1
- package/dist/security.d.ts +1 -1
- package/dist/session-agent.d.ts +1 -10
- package/dist/session-agent.js +0 -6
- package/dist/session-incarnation.d.ts +18 -4
- package/dist/session-incarnation.js +4 -1
- package/dist/session-notify-door.d.ts +4 -4
- package/dist/session-notify-door.js +5 -6
- package/dist/session-rules-seat.d.ts +4 -3
- package/dist/session-rules-seat.js +3 -11
- package/dist/session-sync.js +3 -3
- package/dist/stores-sql/checkpoint-store-sql.d.ts +21 -2
- package/dist/stores-sql/checkpoint-store-sql.js +106 -18
- package/dist/stores-sql/retention-store-sql.d.ts +1 -1
- package/dist/task-cwd.d.ts +4 -3
- package/dist/task-settings.d.ts +13 -0
- package/dist/task-settings.js +13 -7
- package/dist/tool-approval.d.ts +7 -6
- package/dist/tool-approval.js +41 -37
- package/dist/trace/engine-notice-wire.d.ts +14 -0
- package/dist/trace/engine-notice-wire.js +18 -1
- package/dist/trace/project.d.ts +4 -3
- package/dist/trace/project.js +3 -2
- package/dist/trace/projection-table.d.ts +33 -2
- package/dist/trace/self-minted-wire.d.ts +150 -17
- package/dist/trace/self-minted-wire.js +54 -16
- package/dist/trace/tool-card.d.ts +3 -0
- package/dist/trace/tool-card.js +24 -0
- package/dist/trace/tool-output-media.d.ts +2 -1
- package/dist/unattended-permission-mode.d.ts +1 -1
- package/dist/web-admin-client/apply-effective.d.ts +1 -1
- package/dist/web-admin-client/effective-keys.d.ts +1 -1
- package/dist/web-admin-client/skills-mcp.d.ts +1 -1
- package/docs/DEVICE-EXECUTOR-PROTOCOL.md +57 -29
- package/package.json +2 -2
- package/wire-changes/server@7.150.0.json +335 -0
|
@@ -14,8 +14,8 @@ import { readWritableSessionPermissionRules } from "../../session-policy-wire.js
|
|
|
14
14
|
import { sendJson, sendError, sendSessionError, sendSessionPolicyError, sseHeaders, httpErrorBody } from "../send.js";
|
|
15
15
|
import { gatedPerson, gatedSubject, sendPrincipalRefusal } from "../principal-gate.js";
|
|
16
16
|
import { personOf } from "../../owner-brands.js";
|
|
17
|
-
import {
|
|
18
|
-
import { admitSessionById, admitSessionRow, admittedAsFleet, callerEntry, callerOf, deliverVerdict, enter,
|
|
17
|
+
import { leafOfAdmittedHead, sessionFaceOfHead } from "../../session-incarnation.js";
|
|
18
|
+
import { admitSessionById, admitSessionForDeletion, admitSessionRow, admitSessionView, admittedAsFleet, callerEntry, callerOf, deliverVerdict, enter, judgeSessionById, protocolEntry, readOwnerCell, readVisibleLatestRun, refuse, sessionOwnerUnchanged } from "../owner-access.js";
|
|
19
19
|
import { assertNever } from "../route-ctx.js";
|
|
20
20
|
import * as facts from "../../capability-facts.js";
|
|
21
21
|
import { rosterAgentId } from "./agents-roster.js";
|
|
@@ -67,11 +67,9 @@ async function readLastLegMcp(deps, sessionId, entry) {
|
|
|
67
67
|
const runStore = deps.runStore;
|
|
68
68
|
if (!runStore || sessionId === null)
|
|
69
69
|
return undefined;
|
|
70
|
-
const latest = await runStore
|
|
70
|
+
const latest = await readVisibleLatestRun(entry, runStore, sessionId);
|
|
71
71
|
if (latest === undefined)
|
|
72
72
|
return undefined;
|
|
73
|
-
if (!seesRun(entry, latest.owner))
|
|
74
|
-
return undefined;
|
|
75
73
|
const events = await runStore.getEvents(latest.taskId, 0);
|
|
76
74
|
for (let i = events.length - 1; i >= 0; i--) {
|
|
77
75
|
const ev = events[i];
|
|
@@ -87,26 +85,7 @@ async function readLastLegMcp(deps, sessionId, entry) {
|
|
|
87
85
|
export async function handleSessions(req, res, match, ctx) {
|
|
88
86
|
const { deps } = ctx;
|
|
89
87
|
const { readJson, safeDecode } = ctx.helpers;
|
|
90
|
-
const readOwnedSessionView =
|
|
91
|
-
const headOf = headReadOf(deps.sessionStorage);
|
|
92
|
-
if (headOf !== undefined) {
|
|
93
|
-
const head = await readOwnerCell(entry, sessionId, () => headOf(sessionId));
|
|
94
|
-
if ((await admitSessionRow(entry, res, deps.sessionStorage, sessionId, head)) === undefined)
|
|
95
|
-
return undefined;
|
|
96
|
-
}
|
|
97
|
-
let audit;
|
|
98
|
-
try {
|
|
99
|
-
audit = await sessionAudit(sessionId, readOpts);
|
|
100
|
-
}
|
|
101
|
-
catch (e) {
|
|
102
|
-
if (headOf !== undefined)
|
|
103
|
-
throw e;
|
|
104
|
-
throw new Error(`session view read failed before ownership could be established: ${e instanceof Error ? e.message : String(e)}`, { cause: e });
|
|
105
|
-
}
|
|
106
|
-
if ((await admitSessionRow(entry, res, deps.sessionStorage, sessionId, audit)) === undefined)
|
|
107
|
-
return undefined;
|
|
108
|
-
return audit;
|
|
109
|
-
};
|
|
88
|
+
const readOwnedSessionView = (entry, sessionAudit, sessionId, readOpts) => admitSessionView(entry, res, deps.sessionStorage, sessionAudit, sessionId, readOpts);
|
|
110
89
|
const sse = ctx.local.sessions;
|
|
111
90
|
const { mcpStatusCache, a2aStatusCache } = ctx.local.sessions;
|
|
112
91
|
{
|
|
@@ -262,8 +241,8 @@ export async function handleSessions(req, res, match, ctx) {
|
|
|
262
241
|
}
|
|
263
242
|
{
|
|
264
243
|
if (match.decl.id === "session-head") {
|
|
265
|
-
const
|
|
266
|
-
if (!
|
|
244
|
+
const headFact = facts.sessionOwnership(deps);
|
|
245
|
+
if (!headFact.available) {
|
|
267
246
|
sendError(res, 501, "capability.session_store_required", "session head probe requires a durable session store (DB_BACKEND=mysql|pg|local)");
|
|
268
247
|
return;
|
|
269
248
|
}
|
|
@@ -273,8 +252,7 @@ export async function handleSessions(req, res, match, ctx) {
|
|
|
273
252
|
return;
|
|
274
253
|
}
|
|
275
254
|
const headEntry = callerEntry(req, deps, match.decl.id);
|
|
276
|
-
const
|
|
277
|
-
const admittedHead = await admitSessionRow(headEntry, res, deps.sessionStorage, headSession, headRead);
|
|
255
|
+
const admittedHead = await admitSessionById(headEntry, res, headFact.sessionStorage, headSession);
|
|
278
256
|
if (admittedHead === undefined)
|
|
279
257
|
return;
|
|
280
258
|
const leafId = leafOfAdmittedHead(admittedHead.row);
|
|
@@ -317,8 +295,6 @@ export async function handleSessions(req, res, match, ctx) {
|
|
|
317
295
|
return;
|
|
318
296
|
}
|
|
319
297
|
const evEntry = callerEntry(req, deps, match.decl.id);
|
|
320
|
-
const readHead = (id) => readOwnerCell(evEntry, id, () => evFact.sessionStorage.headOf(id));
|
|
321
|
-
const readOwner = async (id) => (await readHead(id))?.owner;
|
|
322
298
|
const watch = evFact.watch;
|
|
323
299
|
const evSession = safeDecode(match.params.sessionId);
|
|
324
300
|
if (evSession === null) {
|
|
@@ -354,7 +330,7 @@ export async function handleSessions(req, res, match, ctx) {
|
|
|
354
330
|
return;
|
|
355
331
|
}
|
|
356
332
|
sse.sseOwnerLookups++;
|
|
357
|
-
const admissionP =
|
|
333
|
+
const admissionP = judgeSessionById(evEntry, evFact.sessionStorage, evSession);
|
|
358
334
|
void admissionP.catch(() => undefined).then(() => { sse.sseOwnerLookups--; });
|
|
359
335
|
let stallTimer;
|
|
360
336
|
let admission;
|
|
@@ -381,12 +357,13 @@ export async function handleSessions(req, res, match, ctx) {
|
|
|
381
357
|
refuse(evEntry, res, "missing");
|
|
382
358
|
return;
|
|
383
359
|
}
|
|
384
|
-
|
|
360
|
+
const evAdmitted = deliverVerdict(evEntry, res, admission);
|
|
361
|
+
if (evAdmitted === undefined) {
|
|
385
362
|
cleanup();
|
|
386
363
|
return;
|
|
387
364
|
}
|
|
388
|
-
leafOfAdmittedHead(
|
|
389
|
-
const owner =
|
|
365
|
+
leafOfAdmittedHead(evAdmitted.row);
|
|
366
|
+
const owner = evAdmitted.row.owner;
|
|
390
367
|
const q = new URLSearchParams(match.search);
|
|
391
368
|
const lastLeafId = q.get("lastLeafId");
|
|
392
369
|
let first = true;
|
|
@@ -485,9 +462,9 @@ export async function handleSessions(req, res, match, ctx) {
|
|
|
485
462
|
}
|
|
486
463
|
ownerCheckPending = true;
|
|
487
464
|
ownerCheckStartedAt = Date.now();
|
|
488
|
-
void
|
|
465
|
+
void sessionOwnerUnchanged(evEntry, evFact.sessionStorage, evSession, owner).then((same) => {
|
|
489
466
|
ownerCheckPending = false;
|
|
490
|
-
if (!closed &&
|
|
467
|
+
if (!closed && !same)
|
|
491
468
|
onEnd();
|
|
492
469
|
}).catch(() => { ownerCheckPending = false; });
|
|
493
470
|
}, hbMs);
|
|
@@ -706,14 +683,11 @@ export async function handleSessions(req, res, match, ctx) {
|
|
|
706
683
|
const store = rowFact.sessionStorage;
|
|
707
684
|
const sessionId = match.params.sessionId;
|
|
708
685
|
const patchEntry = callerEntry(req, deps, match.decl.id);
|
|
709
|
-
const
|
|
710
|
-
if (
|
|
711
|
-
refuse(patchEntry, res, "missing");
|
|
686
|
+
const patchAdmitted = await admitSessionById(patchEntry, res, store, sessionId);
|
|
687
|
+
if (patchAdmitted === undefined)
|
|
712
688
|
return;
|
|
713
|
-
|
|
689
|
+
const head = patchAdmitted.row;
|
|
714
690
|
const face = sessionFaceOfHead(sessionId, head);
|
|
715
|
-
if ((await admitSessionRow(patchEntry, res, store, sessionId, face)) === undefined)
|
|
716
|
-
return;
|
|
717
691
|
leafOfAdmittedHead(head);
|
|
718
692
|
const read = readSessionRowPatch(await readJson(req));
|
|
719
693
|
if ("problem" in read) {
|
|
@@ -903,7 +877,7 @@ export async function handleSessions(req, res, match, ctx) {
|
|
|
903
877
|
sendError(res, 400, "request.id_invalid", "invalid session id (must be a canonical uuid)");
|
|
904
878
|
return;
|
|
905
879
|
}
|
|
906
|
-
const deleteAdmitted = await
|
|
880
|
+
const deleteAdmitted = await admitSessionForDeletion(deleteEntry, res, deleteFact.sessionStorage, sessionId);
|
|
907
881
|
if (deleteAdmitted === undefined)
|
|
908
882
|
return;
|
|
909
883
|
const owner = deleteAdmitted.row.owner;
|
|
@@ -21,7 +21,8 @@ import { writeLiveFrame, writeLiveHeartbeat } from "../live-frame.js";
|
|
|
21
21
|
import { contextUsageEventData, turnEndEventData, toolStartEventData, toolEndEventData, taskProgressEventData, taskStartedEventData, taskNotificationEventData, compactedEventData, diagnosticsEventData, brainStatusEventData, steeringInjectedEventData, compactionOutcomeEventData, compactionStartedEventData, workspaceChangedEventData, wiringManifestFaceEventData, toolRosterDeltaEventData, toolProgressEventData, toolDisclosureEventData, humanInputEventData, appendModelUsageDelta, attachModelUsage, createPromptManifestSeat, identityFields } from "../../trace/project.js";
|
|
22
22
|
import { cascadeConfig, fillRunPreviewOnDelivery, runMeta } from "../run-meta.js";
|
|
23
23
|
import { idemCallerOf, inflightKeyOf, submissionIdemOf } from "../idempotency.js";
|
|
24
|
-
import { isReplayedOutcome, replayedOutcome, replayOfExistingRun } from "../submit-replay.js";
|
|
24
|
+
import { answerReplay, isReplayedOutcome, replayedOutcome, replayOfExistingRun } from "../submit-replay.js";
|
|
25
|
+
import { readReplayHit, runFactsOf } from "../owner-access.js";
|
|
25
26
|
import { httpErrorCode, sendJson, sseHeaders } from "../send.js";
|
|
26
27
|
import { collectSsePreamble } from "../sse-log.js";
|
|
27
28
|
import { buildApprovalPreamble } from "../../approval-card.js";
|
|
@@ -109,12 +110,12 @@ export async function handleTasks(req, res, match, ctx) {
|
|
|
109
110
|
const idem = rawIdem ? submissionIdemOf(rawIdem, idemCallerOf(req, ctx), keyedBody) : undefined;
|
|
110
111
|
const inflightKey = idem ? inflightKeyOf(idem, "sync") : undefined;
|
|
111
112
|
const cached = inflightKey ? idemCache.peek(inflightKey) : undefined;
|
|
112
|
-
const
|
|
113
|
-
if (
|
|
114
|
-
const replay = await
|
|
115
|
-
if (liveStream && replay.status === 200) {
|
|
116
|
-
sseHeaders(res, { "x-task-id":
|
|
117
|
-
writeMetaFrame(res,
|
|
113
|
+
const keyedHit = idem && !cached && deps.runStore ? await readReplayHit(submitter, deps.config, deps.runStore, { idemKey: idem.key }, undefined) : undefined;
|
|
114
|
+
if (keyedHit && deps.runStore) {
|
|
115
|
+
const replay = await answerReplay(keyedHit, { subject: submitter, idem }, "sync", deps.runStore);
|
|
116
|
+
if (liveStream && replay.status === 200 && keyedHit.kind === "visible") {
|
|
117
|
+
sseHeaders(res, { "x-task-id": keyedHit.row.taskId });
|
|
118
|
+
writeMetaFrame(res, keyedHit.row.taskId, keyedHit.row.sessionId);
|
|
118
119
|
writeLiveFrame(res, doneFrameOfOutcome(replay));
|
|
119
120
|
res.end();
|
|
120
121
|
}
|
|
@@ -800,7 +801,7 @@ export async function handleTasks(req, res, match, ctx) {
|
|
|
800
801
|
evict();
|
|
801
802
|
if (!runRowSettled && durableTaskId && deps.runStore) {
|
|
802
803
|
try {
|
|
803
|
-
const row = await deps.runStore
|
|
804
|
+
const row = await runFactsOf(deps.runStore, durableTaskId);
|
|
804
805
|
if (row?.status === "running") {
|
|
805
806
|
const pending = await deps.checkpointStore?.findPendingTokenBySession(prepared.spec.sessionId, undefined, { axis: "run" });
|
|
806
807
|
const backstopCause = ac.cause();
|
|
@@ -9,7 +9,7 @@ import { bindSseLifecycle } from "../sse-lifecycle.js";
|
|
|
9
9
|
import { sendJson, sendError, sseHeaders, SSE_MAX_STREAM_MS, SSE_HEARTBEAT_IDLE_MS } from "../send.js";
|
|
10
10
|
import { filterFingerprint } from "../cursor-fingerprint.js";
|
|
11
11
|
import { sendUnauthorized } from "../principal-gate.js";
|
|
12
|
-
import { admitRunById, enter, entryIsFleet, readVisibleRun, routeListFilter,
|
|
12
|
+
import { admitRunById, enter, entryIsFleet, listVisibleRuns, readVisibleRun, routeListFilter, runListOwnerOf, toolResultRefOwned } from "../owner-access.js";
|
|
13
13
|
import { listFilterOf } from "../../owner-faces.js";
|
|
14
14
|
import { assertNever } from "../route-ctx.js";
|
|
15
15
|
import * as facts from "../../capability-facts.js";
|
|
@@ -42,7 +42,7 @@ export async function handleTraceUsage(req, res, match, ctx) {
|
|
|
42
42
|
const traceEntry = enter(req, res, deps, match.decl.id);
|
|
43
43
|
if (traceEntry === undefined)
|
|
44
44
|
return;
|
|
45
|
-
const
|
|
45
|
+
const traceFilter = listFilterOf(traceEntry.face, traceEntry.caller);
|
|
46
46
|
const runs = facts.durableRuns(deps);
|
|
47
47
|
if (!runs.available) {
|
|
48
48
|
sendError(res, 501, "capability.run_store_required", "trace API requires a durable run store (DB_BACKEND=mysql|pg|local)");
|
|
@@ -61,20 +61,20 @@ export async function handleTraceUsage(req, res, match, ctx) {
|
|
|
61
61
|
}
|
|
62
62
|
switch (match.decl.id) {
|
|
63
63
|
case "task-trace-list":
|
|
64
|
-
await handleTaskList(res, runStore, query,
|
|
64
|
+
await handleTaskList(res, runStore, query, traceFilter);
|
|
65
65
|
return;
|
|
66
66
|
case "task-trace-turns":
|
|
67
67
|
await handleTaskTurns(res, runStore, admittedRun, query);
|
|
68
68
|
return;
|
|
69
69
|
case "task-trace-stream":
|
|
70
|
-
await streamTaskTrace(req, res, runStore, admittedRun, match.search);
|
|
70
|
+
await streamTaskTrace(req, res, runStore, traceEntry, admittedRun, match.search);
|
|
71
71
|
return;
|
|
72
72
|
case "task-trace-artifacts":
|
|
73
73
|
await handleTaskArtifacts(res, runStore, admittedRun);
|
|
74
74
|
return;
|
|
75
75
|
case "task-tool-result": {
|
|
76
76
|
const ownedRun = admittedRun;
|
|
77
|
-
const readRun = ownedRun !== undefined ? async () => ownedRun : () => readVisibleRun(traceEntry, runStore, taskId);
|
|
77
|
+
const readRun = ownedRun !== undefined ? async () => ownedRun : async () => (await readVisibleRun(traceEntry, runStore, taskId))?.row;
|
|
78
78
|
await handleToolResult(res, deps.toolResultStore, taskId, readRun, safeDecode(match.params.ref), query);
|
|
79
79
|
return;
|
|
80
80
|
}
|
|
@@ -161,11 +161,12 @@ function decodeCursor(s, expectF) {
|
|
|
161
161
|
return undefined;
|
|
162
162
|
}
|
|
163
163
|
}
|
|
164
|
-
async function handleTaskList(res, runStore, query,
|
|
164
|
+
async function handleTaskList(res, runStore, query, filter) {
|
|
165
165
|
const status = query.get("status") ?? undefined;
|
|
166
166
|
const jobId = query.get("jobId") ?? undefined;
|
|
167
167
|
const source = query.get("source") ?? undefined;
|
|
168
|
-
const
|
|
168
|
+
const namedOwner = query.get("owner") ?? undefined;
|
|
169
|
+
const owner = runListOwnerOf(filter, namedOwner);
|
|
169
170
|
const limit = Math.min(100, Math.max(1, Number(query.get("limit") ?? 50) || 50));
|
|
170
171
|
const f = filterFingerprint([status, jobId, source, owner]);
|
|
171
172
|
const cursor = decodeCursor(query.get("cursor"), f);
|
|
@@ -173,7 +174,7 @@ async function handleTaskList(res, runStore, query, forceOwner) {
|
|
|
173
174
|
sendError(res, 400, "request.cursor_filter_mismatch", "cursor was issued under a different filter (status/jobId/source/owner) — restart from the first page without a cursor");
|
|
174
175
|
return;
|
|
175
176
|
}
|
|
176
|
-
const rows = await runStore
|
|
177
|
+
const rows = await listVisibleRuns(runStore, filter, namedOwner, { ...(status ? { status } : {}), ...(jobId ? { jobId } : {}), ...(source ? { source } : {}), ...(cursor ? { cursor } : {}), limit: limit + 1 });
|
|
177
178
|
const hasMore = rows.length > limit;
|
|
178
179
|
const page = hasMore ? rows.slice(0, limit) : rows;
|
|
179
180
|
const tasks = page.map((r) => taskSummary(r));
|
|
@@ -216,8 +217,7 @@ async function handleToolResult(res, store, taskId, readRun, ref, query) {
|
|
|
216
217
|
const run = await readRun();
|
|
217
218
|
if (!run)
|
|
218
219
|
return notFound();
|
|
219
|
-
const
|
|
220
|
-
const ownedByThisCaller = owner !== undefined && owner.sessionId === run.sessionId && (owner.taskId === undefined || owner.taskId === taskId);
|
|
220
|
+
const ownedByThisCaller = await toolResultRefOwned(store, ref, run);
|
|
221
221
|
if (!ownedByThisCaller)
|
|
222
222
|
return notFound();
|
|
223
223
|
if (!store)
|
|
@@ -240,7 +240,7 @@ async function handleTaskTurns(res, runStore, run, query) {
|
|
|
240
240
|
const nextCursor = eligible.length > limit && oldest ? String(oldest.seq) : undefined;
|
|
241
241
|
sendJson(res, 200, { turns, ...(nextCursor ? { nextCursor } : {}), retainedFrom });
|
|
242
242
|
}
|
|
243
|
-
async function streamTaskTrace(req, res, runStore, admitted, search) {
|
|
243
|
+
async function streamTaskTrace(req, res, runStore, entry, admitted, search) {
|
|
244
244
|
const taskId = admitted.taskId;
|
|
245
245
|
const lastId = Number(req.headers["last-event-id"] ?? new URLSearchParams(search).get("from") ?? 0);
|
|
246
246
|
let from = Number.isFinite(lastId) ? lastId : 0;
|
|
@@ -264,11 +264,11 @@ async function streamTaskTrace(req, res, runStore, admitted, search) {
|
|
|
264
264
|
}
|
|
265
265
|
};
|
|
266
266
|
while (!closed) {
|
|
267
|
-
const [events,
|
|
267
|
+
const [events, reread] = await Promise.all([runStore.getEvents(taskId, from), readVisibleRun(entry, runStore, taskId)]);
|
|
268
268
|
write(events);
|
|
269
|
-
if (!
|
|
269
|
+
if (!reread)
|
|
270
270
|
break;
|
|
271
|
-
const run =
|
|
271
|
+
const run = reread.row;
|
|
272
272
|
if (run.status !== "running") {
|
|
273
273
|
write(await runStore.getEvents(taskId, from));
|
|
274
274
|
if (!deliveredTerminal && isHolderDeathVerdict(run))
|
|
@@ -2,6 +2,7 @@ import type { IncomingMessage, ServerResponse } from "node:http";
|
|
|
2
2
|
import { type WorkflowRun } from "@sema-agent/core";
|
|
3
3
|
import { type Admit } from "../../trace/projection-table.js";
|
|
4
4
|
import type { RouteCtx, RouteMatch, RouteIdsOf } from "../route-ctx.js";
|
|
5
|
+
/** SVC-5 的 steer 路——`handle()` 里位置在 tasks/runs 之后(鉴权门之后),故是**独立**的域入口。 */
|
|
5
6
|
/** 路由体 = 从 `server.ts` 的 `handle()` 里**整段剪切**过来的原文(唯一改动:统一去缩进两格)。裸 `return;`
|
|
6
7
|
* = 「本域已应答」;走到函数尾才是「没匹配上」。跨域的东西一律在首行解构出来。 */
|
|
7
8
|
export declare function handleWorkflows(req: IncomingMessage, res: ServerResponse, match: RouteMatch<WorkflowsRouteId>, ctx: RouteCtx): Promise<void>;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { persistedPlaneOf } from "../../terminal.js";
|
|
2
2
|
import { z } from "zod";
|
|
3
|
-
import {
|
|
3
|
+
import { subscribeWorkflow, deriveAgentDisplayStatus, callKeyOrdinal, runParkedOf, JOURNAL_INCOMPATIBLE_ERROR_CODE, WorkflowJournalIncompatibleError } from "@sema-agent/core";
|
|
4
4
|
import { redactSteerIn, STEER_IN_MAX_CHARS, STEER_IN_MAX_REQUEST_CHARS } from "../../orchestration/workflow-agent-steer.js";
|
|
5
5
|
import { journalEntryOfCell, journalEntryPayload, journalRowPayloadOf } from "../../plugins/workflow-journal-payload.js";
|
|
6
6
|
import { redactSecrets } from "../../trace/redact.js";
|
|
@@ -10,30 +10,18 @@ import { projectByTable } from "../../trace/projection-table.js";
|
|
|
10
10
|
const JOURNAL_PROJECTION_MEMO_CAP = 1024;
|
|
11
11
|
const journalProjectionMemo = new Map();
|
|
12
12
|
import { sendJson, sendError, sseHeaders } from "../send.js";
|
|
13
|
-
import {
|
|
13
|
+
import { explicitOperatorOk } from "../principal-gate.js";
|
|
14
14
|
import { partsOf } from "../../owner-brands.js";
|
|
15
|
-
import { taskSpecIdentityOf } from "../../engine-identity.js";
|
|
16
15
|
import { assertNever } from "../route-ctx.js";
|
|
17
|
-
import {
|
|
16
|
+
import { admitWorkflowRun, enter, judgeWorkflowRun, listVisibleWorkflows, refuse } from "../owner-access.js";
|
|
18
17
|
import * as facts from "../../capability-facts.js";
|
|
19
18
|
import { steerBodyKeyIssue } from "../../request-key-closure.js";
|
|
20
|
-
function sendWorkflowAbsent(res) {
|
|
21
|
-
sendError(res, 404, "not_found.workflow", "workflow not found");
|
|
22
|
-
}
|
|
23
|
-
const WORKFLOW_SESSION_ASSERTION = {
|
|
24
|
-
"workflow-detail": { phase: "accept", label: "workflow.detail" },
|
|
25
|
-
"workflow-journal": { phase: "accept", label: "workflow.journal" },
|
|
26
|
-
"workflow-stream": { phase: "accept", label: "workflow.stream" },
|
|
27
|
-
"workflow-agent-steer": { phase: "accept", label: "workflow.agent-steer" },
|
|
28
|
-
};
|
|
29
19
|
export async function handleWorkflows(req, res, match, ctx) {
|
|
30
20
|
const { deps } = ctx;
|
|
31
21
|
{
|
|
32
|
-
const
|
|
33
|
-
if (
|
|
34
|
-
sendPrincipalRefusal(res, req, deps.config);
|
|
22
|
+
const wfEntry = enter(req, res, deps, match.decl.id);
|
|
23
|
+
if (wfEntry === undefined)
|
|
35
24
|
return;
|
|
36
|
-
}
|
|
37
25
|
let journalStore;
|
|
38
26
|
if (match.decl.id === "workflow-journal") {
|
|
39
27
|
const journalFace = facts.workflowsJournal(deps);
|
|
@@ -49,7 +37,6 @@ export async function handleWorkflows(req, res, match, ctx) {
|
|
|
49
37
|
return;
|
|
50
38
|
}
|
|
51
39
|
const runStore = runs.store;
|
|
52
|
-
const scope = taskSpecIdentityOf(subject === undefined ? undefined : partsOf(subject)).principal ?? "default";
|
|
53
40
|
const wfId = match.params.runId;
|
|
54
41
|
const isStream = match.decl.id === "workflow-stream";
|
|
55
42
|
if (match.decl.id === "workflows-list") {
|
|
@@ -57,7 +44,7 @@ export async function handleWorkflows(req, res, match, ctx) {
|
|
|
57
44
|
const statusFilter = q.get("status");
|
|
58
45
|
const limit = Math.min(100, Math.max(1, Number(q.get("limit") ?? 50) || 50));
|
|
59
46
|
const sessionFilter = q.get("session");
|
|
60
|
-
const sessionRuns = await
|
|
47
|
+
const sessionRuns = await listVisibleWorkflows(wfEntry, runStore, {
|
|
61
48
|
...(statusFilter ? { status: statusFilter } : {}),
|
|
62
49
|
limit,
|
|
63
50
|
...(sessionFilter !== null ? { session: sessionFilter } : {}),
|
|
@@ -71,15 +58,11 @@ export async function handleWorkflows(req, res, match, ctx) {
|
|
|
71
58
|
sendJson(res, 200, { workflows: redacted });
|
|
72
59
|
return;
|
|
73
60
|
}
|
|
74
|
-
const
|
|
75
|
-
if (
|
|
76
|
-
sendWorkflowAbsent(res);
|
|
77
|
-
return;
|
|
78
|
-
}
|
|
79
|
-
if (!sessionAsserted(WORKFLOW_SESSION_ASSERTION[match.decl.id], req, run.originatingSessionId, callerOf(req, deps).operator)) {
|
|
80
|
-
sendWorkflowAbsent(res);
|
|
61
|
+
const wfAdmitted = await admitWorkflowRun(wfEntry, res, runStore, wfId);
|
|
62
|
+
if (wfAdmitted === undefined)
|
|
81
63
|
return;
|
|
82
|
-
|
|
64
|
+
const run = wfAdmitted.row;
|
|
65
|
+
const scope = run.scope;
|
|
83
66
|
if (match.decl.id === "workflow-journal") {
|
|
84
67
|
if (journalStore === undefined)
|
|
85
68
|
throw new Error("workflow-journal reached without the workflowsJournal journal witness");
|
|
@@ -182,12 +165,11 @@ export async function handleWorkflowAgentSteer(req, res, match, ctx) {
|
|
|
182
165
|
sendWorkflowsUnavailable(res, runs.why);
|
|
183
166
|
return;
|
|
184
167
|
}
|
|
185
|
-
const
|
|
186
|
-
|
|
187
|
-
if (deps.config.requirePrincipal && principal === undefined) {
|
|
188
|
-
sendPrincipalRefusal(res, req, deps.config);
|
|
168
|
+
const steerEntry = enter(req, res, deps, match.decl.id);
|
|
169
|
+
if (steerEntry === undefined)
|
|
189
170
|
return;
|
|
190
|
-
|
|
171
|
+
const subject = steerEntry.caller.subject;
|
|
172
|
+
const principal = subject === undefined ? undefined : partsOf(subject).person;
|
|
191
173
|
const wfRunId = safeDecode(match.params.runId);
|
|
192
174
|
const label = safeDecode(match.params.label);
|
|
193
175
|
if (wfRunId === null || label === null) {
|
|
@@ -211,14 +193,14 @@ export async function handleWorkflowAgentSteer(req, res, match, ctx) {
|
|
|
211
193
|
return;
|
|
212
194
|
}
|
|
213
195
|
const trusted = explicitOperatorOk(principal, deps.config);
|
|
214
|
-
const
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
sendWorkflowAbsent(res);
|
|
196
|
+
const wfVerdict = await judgeWorkflowRun(steerEntry, runs.store, wfRunId);
|
|
197
|
+
if (wfVerdict === "session_mismatch") {
|
|
198
|
+
refuse(steerEntry, res, "session_mismatch");
|
|
218
199
|
return;
|
|
219
200
|
}
|
|
220
|
-
|
|
221
|
-
|
|
201
|
+
const wfRun = typeof wfVerdict === "object" ? wfVerdict.row : undefined;
|
|
202
|
+
if (!trusted && wfRun === undefined) {
|
|
203
|
+
refuse(steerEntry, res, wfVerdict === "missing" ? "missing" : "not_visible");
|
|
222
204
|
return;
|
|
223
205
|
}
|
|
224
206
|
const sendNotRunningWf = (error) => sendError(res, 409, "steering.not_running", error);
|
package/dist/http/server.d.ts
CHANGED
|
@@ -4,6 +4,7 @@ import type { SideQueryAccounting } from "../budget.js";
|
|
|
4
4
|
import type { SessionPurgeOutcome } from "../session-deletion.js";
|
|
5
5
|
import type { IncomingMessage } from "node:http";
|
|
6
6
|
import { type Runner, type RunnerDeps, type TaskSpec, type TaskResult, type WorkflowRunStore, type MemoryEntry, type MemoryExportBundle, type MemoryImportReport, type SideQuerySpec, type SideQueryResult, type Brain, type EngineNotice } from "@sema-agent/core";
|
|
7
|
+
import type { ProjectContext } from "../project-context.js";
|
|
7
8
|
import type { TaskRequestBody } from "./wire-types.js";
|
|
8
9
|
import type { ServiceConfig } from "../config-types.js";
|
|
9
10
|
import { type SessionMirrorRuling } from "../web-admin-client/facade.js";
|
|
@@ -130,7 +131,9 @@ export interface ServiceCoreDeps {
|
|
|
130
131
|
* 已过期,按新行为改。
|
|
131
132
|
* `opts.unattendedLeg`([ref] 候裁 18,codex r3 F1;[ref] ① 改形):续跑家族在 ctx 带无人值守标(`CheckpointCtx.unattendedLeg`)时递 `true` ——
|
|
132
133
|
* 装配器在**全部折叠之后**经首跑同一只合并口 `withUnattendedLeg` 重挂那条腿(`default` + 按类作答的 onAsk)。只由续跑腿
|
|
133
|
-
* 按服务端写的 ctx 位递,绝不从请求体读。
|
|
134
|
+
* 按服务端写的 ctx 位递,绝不从请求体读。
|
|
135
|
+
* `opts.projectContext`(项目上下文继承):续跑家族把提交腿冻结的那一份(`CheckpointCtx.projectContext`,服务端写)原样递回 —— 装配器在续跑腿上只重放它、不读登记簿;
|
|
136
|
+
* 新提交腿不递(装配器自己在头部判)。同样只由续跑腿按服务端写的 ctx 位递,绝不从请求体读。 */
|
|
134
137
|
/** `opts.execution`(必填):这条腿的执行上下文(`http/execution-context.ts`;只 `fresh` / `continuation` 两形,`root` 恒在)。装配器要用这条腿的根会话
|
|
135
138
|
* (场景设施的分区键、受理见证)读 `opts.execution.root` —— 它与 server 随后盖进 spec 的根是同一个值,装配器自己不写根。 */
|
|
136
139
|
/** `opts.lease`(必填):这条腿的**宿主租约** —— 装配在它之下登记本腿交给引擎的对端声明(`peerDesk.declare(草稿, opts.lease)`)。
|
|
@@ -141,6 +144,7 @@ export interface ServiceCoreDeps {
|
|
|
141
144
|
liveStream?: boolean;
|
|
142
145
|
onNotice?: (notice: EngineNotice) => void;
|
|
143
146
|
unattendedLeg?: true;
|
|
147
|
+
projectContext?: ProjectContext;
|
|
144
148
|
lease: PeerLease;
|
|
145
149
|
execution: ExecutionRoot;
|
|
146
150
|
}) => ResolvedTaskSpec | Promise<ResolvedTaskSpec>;
|
|
@@ -755,8 +759,8 @@ export interface ServiceDeploymentDeps {
|
|
|
755
759
|
* 缺席(嵌入方 / 夹具)= 两项恒 0,两个读数逐字同 7.145.x。
|
|
756
760
|
*/
|
|
757
761
|
sessionResidentBackground?: () => SessionResidentCounts;
|
|
758
|
-
/** 编排器片 2 件 3:服务租约此刻的读数(`fleet/serving-lease.ts`
|
|
759
|
-
* (非 fleet 成员 /
|
|
762
|
+
/** 编排器片 2 件 3:服务租约此刻的读数(`fleet/serving-lease.ts` 的客户端交出;唯一读者 `fleet/engine-signal.ts` 的 `memberLeaseOf` —— 引擎信号铸点
|
|
763
|
+
* 与计费准入判经它同读,只在 `config.fleetGeneration` 在场〔成员〕时读)。缺席 = 没装租约客户端(非 fleet 成员 / 测试夹具)⇒ `none`。 */
|
|
760
764
|
servingLease?: () => import("../fleet/engine-signal.js").ServingLeaseView;
|
|
761
765
|
/** boot ready 门(b):false = 布防(`CONFIG_REQUIRE_ROSTER=true`)且首次 effective pull 尚未落 roster
|
|
762
766
|
* (worker 只有占位模型)。就绪原因 `model_roster_pending`(`http/readiness.ts`):计费提交 503 + `/readyz` 503 +
|
|
@@ -800,7 +804,7 @@ export interface ServiceDeploymentDeps {
|
|
|
800
804
|
/** [ref] 追加件:`POST /v1/admin/config/refresh` 的实现面 —— 触发**一次既有**的 refresh 拍(在飞则 join)。
|
|
801
805
|
* 缺席 / 回 `"not-wired"` = 本部署没有配置管道 ⇒ 该口诚实 4xx(绝不吞成 200)。 */
|
|
802
806
|
configRefreshNow?: () => Promise<"triggered" | "not-wired" | "failed">;
|
|
803
|
-
/**
|
|
807
|
+
/** [ref] §5 S2([ref]):center **当前在管**的 ServiceConfig 键集 —— `GET /v1/config/catalog`
|
|
804
808
|
* 判 `effectiveLane`(env 占位/center 在管/默认)的 center 半场。缺席或返回 undefined = 本部署
|
|
805
809
|
* 没有配置管道(纯 env worker / 测试夹具)⇒ 目录把每条 center 腿如实标「不在管」(additive)。 */
|
|
806
810
|
webAdminManagedKeys?: () => ReadonlySet<string> | undefined;
|
package/dist/http/server.js
CHANGED
|
@@ -26,6 +26,7 @@ import { createRunConcurrencyGate, liveRunIdsOf } from "./run-concurrency-cap.js
|
|
|
26
26
|
import { sqlEngineSeatIssue } from "../sql-engine-posture.js";
|
|
27
27
|
import { parkDecisionStoreRefusal } from "../orchestration/workflow-park-decision.js";
|
|
28
28
|
import { CHECKPOINT_CTX_SEALING_REQUIRED } from "./checkpoint-ctx.js";
|
|
29
|
+
import { SERVING_LEASE_MEMBERSHIP_REQUIRED } from "../fleet/engine-signal.js";
|
|
29
30
|
import { PARKED_REVIVE_EXECUTION_SEAT_REQUIRED } from "../parked-decide.js";
|
|
30
31
|
import { a2aAudienceVerifiedSourceRefusal, operatorDeclarationRefusal } from "../config-invariants.js";
|
|
31
32
|
import { retiredServiceDepsRefusal } from "./retired-service-deps.js";
|
|
@@ -148,6 +149,8 @@ export function createHttpServer(rawDeps) {
|
|
|
148
149
|
throw new Error(`createHttpServer: ${CHECKPOINT_CTX_SEALING_REQUIRED}`);
|
|
149
150
|
if (deps.parkedReviveSurface !== undefined && deps.sessionStorage?.executionPlacement === undefined)
|
|
150
151
|
throw new Error(`createHttpServer: ${PARKED_REVIVE_EXECUTION_SEAT_REQUIRED}`);
|
|
152
|
+
if (deps.servingLease !== undefined && deps.config.fleetGeneration === undefined)
|
|
153
|
+
throw new Error(`createHttpServer: ${SERVING_LEASE_MEMBERSHIP_REQUIRED}`);
|
|
151
154
|
const idemCache = new IdempotencyCache();
|
|
152
155
|
const inflightRuns = new Map();
|
|
153
156
|
const preemptableRuns = new DrainYieldingPreemptBook(() => deps.drainState?.draining === true);
|
|
@@ -183,7 +186,7 @@ export function createHttpServer(rawDeps) {
|
|
|
183
186
|
if (deps.drainState)
|
|
184
187
|
deps.drainState.yieldInflight = () => preemptableRuns.yieldAll();
|
|
185
188
|
if (deps.hookWakeBus) {
|
|
186
|
-
|
|
189
|
+
const deliverHookWake = async (sessionId, text) => {
|
|
187
190
|
try {
|
|
188
191
|
validatePendingSteer({ text, trusted: false });
|
|
189
192
|
}
|
|
@@ -218,6 +221,7 @@ export function createHttpServer(rawDeps) {
|
|
|
218
221
|
return false;
|
|
219
222
|
}
|
|
220
223
|
};
|
|
224
|
+
deps.hookWakeBus.deliver = deliverHookWake;
|
|
221
225
|
}
|
|
222
226
|
const { quotaExceeded, ownerCostQuotaDenied, ownerFleetLeaseDenied, ownerLeaseDenied, ownerQuotaDenied, leaseDenied, usageWindowDenialFor, usageWindowDenied, rateLimited, safeDecode, readJson, readRawBody } = createRequestGuards({ deps });
|
|
223
227
|
const { prepareSpec } = createAdmission({ deps, readJson, runnerFor });
|
|
@@ -1,29 +1,9 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* 「这条停驻行的持久化体在本版上能否重放」—— **唯一**判据(四问一只,外加 `settings.env` 凭据一臂;五个问点同调:续跑驱动段 `resume-legs.ts` `resolveResumeSpecOrBlocked`、
|
|
3
|
-
* plan_review 的 prepare 段、SLA 拒扫腿的跳过臂 `approval-sweeps.ts`、终态 run 的 steer 铸唤醒卡之前 `routes/runs.ts`;`resolveSpec` 本身留作提交腿的拒点)。
|
|
4
|
-
* 四问的规则、记号、拒句与删除条件的属主 = `http/checkpoint-ctx.ts` 顶注;答复 = 那里的 `storedBodyReplayAnswer`。
|
|
5
|
-
*
|
|
6
|
-
* 为什么判据住在这里而不是 `checkpoint-ctx.ts`:模式词问要读体的**生效模式词**(`task-settings.ts` `storedBodyPermissionMode`,请求设置的解析层)与本部署此刻的
|
|
7
|
-
* **入口地板**(`runtime-governance.ts` `autonomyModeFloor`)—— 这两只属主带着配置层的包外依赖;`checkpoint-ctx.ts` 被随包的本地排空脚本经编译产物 import,
|
|
8
|
-
* 它的闭包只许 node 内建 / 引擎包根(`test/drain-check-local.test.ts` 的闭包门)。判据只有这一只,allow 读法问、工具名清单问与退役请求键问的谓词照旧住在各自属主里。
|
|
9
|
-
*/
|
|
10
|
-
import type { PermissionMode } from "@sema-agent/core";
|
|
11
|
-
import { type Autonomy } from "../runtime-governance.js";
|
|
12
1
|
import { type InertToolListEntry } from "../rule-entry-list.js";
|
|
13
2
|
import { type ExecutionConfigRootDeployment } from "../execution-config-root.js";
|
|
14
3
|
import { type UnreadMembersDeployment } from "../unread-request-members.js";
|
|
15
4
|
import { type ModelApiKeyEnvTable } from "../server-secret-env.js";
|
|
16
5
|
import { type StoredBodyReplayRefusal } from "./checkpoint-ctx.js";
|
|
17
6
|
import type { CheckpointCtx } from "./route-ctx.js";
|
|
18
|
-
/**
|
|
19
|
-
* 模式词问:本行体里的模式词能否按当前读法重放。不能 ⇔ 本部署此刻有入口地板 ∧ 行上没有当前的模式词读法记号 ∧ 体的生效词进这块地板会变
|
|
20
|
-
* (`runtime-governance.ts` `entryPermissionMode`,与提交入口的盖章同一只函数;判的是「词变不变」而不是 `clamped` —— 体无词的旧行进地板取地板本身,
|
|
21
|
-
* 那也是变)⇒ 返回拒因的两个事实(体的词、地板);能 ⇒ `undefined`。
|
|
22
|
-
*/
|
|
23
|
-
export declare function permissionModeReadingUnstated(ctx: CheckpointCtx, floor: PermissionMode | undefined): {
|
|
24
|
-
stored: PermissionMode | undefined;
|
|
25
|
-
floor: PermissionMode;
|
|
26
|
-
} | undefined;
|
|
27
7
|
/**
|
|
28
8
|
* 存体里 `settings.permissions.deny` / `ask`(规则编译器读的收紧表)有永远不生效的条目(名字层:退役名 / 短名 / 铸不出的段 / 近似名;core 的规则文法:括号 / 内容文法 / 主字段……;
|
|
29
9
|
* `~/` 形而这个部署解不出 home),或三桶里 user 层的 `/` 形规则而这个部署读不出执行环境的配置根 —— 拒点是 `applyTaskSettings`(422,在 `resolveSpec` 里),那一拍 plan_review 的一次性 nonce 已烧、终态 steer 的唤醒卡已铸、SLA 拒扫跳不过;所以预判也问一遍。
|
|
@@ -36,17 +16,16 @@ export declare function permissionModeReadingUnstated(ctx: CheckpointCtx, floor:
|
|
|
36
16
|
*/
|
|
37
17
|
export declare function ruleTablesRefusalWithoutTaskRoot(body: unknown, deployment: ExecutionConfigRootDeployment): InertToolListEntry | undefined;
|
|
38
18
|
/**
|
|
39
|
-
*
|
|
19
|
+
* 预判读的部署配置:执行车道的 home 两位(`~/` 形规则那一问)、配置根的几位(user 设置层 `/` 规则那一问)与「请求成员读不出」那一问的
|
|
40
20
|
* 租户轴 / 两只注入闸的否决位。`ServiceConfig` 结构上满足,四个问点传 `deps.config` 整份。
|
|
41
21
|
*/
|
|
42
22
|
export type StoredReplayDeployment = ExecutionConfigRootDeployment & UnreadMembersDeployment & {
|
|
43
|
-
readonly autonomy?: Autonomy | undefined;
|
|
44
23
|
/** 生效配置模型条目 name → `apiKeyEnv`(`settings.env` 凭据判据的名单一臂;缺席 = 没有模型条目,与 `serverCredentialValueSources` 的缺省同读)。 */
|
|
45
24
|
readonly modelApiKeyEnv?: ModelApiKeyEnvTable | undefined;
|
|
46
25
|
};
|
|
47
26
|
/**
|
|
48
|
-
*
|
|
49
|
-
* 任一问中都不重放,句子只需一句)。`deployment` = 本部署**此刻**的 `config`(活 config:热改即生效)
|
|
27
|
+
* 三问一只判据:不能重放 ⇒ 返回拒的那条规则;能 ⇒ `undefined`。顺序:allow 读法(体里带非空 `allow` 而写者版本证不出 ≥ 7.117.0;常设,按写者版本)→ 请求设置里的条目表(**与拒点同序**:桶门〔形 / 空串 / 超帽〕→ 工具名清单读成空〔**只问限制方向**:放行方向的存量条目读成空,续跑照旧、只留一行运维 warn〕→ 请求成员读不出〔hooks / env / MCP transport / A2A headers …,判据 `unread-request-members.ts`〕→ deny / ask 的名字层 + 规则文法)→ 体里的退役请求键(几问同中时答先中的那一问 ——
|
|
28
|
+
* 任一问中都不重放,句子只需一句)。`deployment` = 本部署**此刻**的 `config`(活 config:热改即生效):`~/` 形规则的 home 由 `executionLaneHomeDir` 算,问点都不自己算。
|
|
50
29
|
*/
|
|
51
30
|
export declare function storedBodyReplayRefusal(ctx: CheckpointCtx, deployment: StoredReplayDeployment): StoredBodyReplayRefusal | undefined;
|
|
52
31
|
//# sourceMappingURL=stored-body-replay.d.ts.map
|
|
@@ -1,7 +1,6 @@
|
|
|
1
|
-
import { REQUEST_SETTINGS_REFUSAL_PREFIX, SETTINGS_PERMISSION_BUCKETS, SETTINGS_RULE_REFUSAL_CODE, neverAutoNamesRefusal, readSettingsEnv, rulePolicyBucketsRefusal, settingsEnvCredentialIssue, settingsPermissionBucketIssue
|
|
1
|
+
import { REQUEST_SETTINGS_REFUSAL_PREFIX, SETTINGS_PERMISSION_BUCKETS, SETTINGS_RULE_REFUSAL_CODE, neverAutoNamesRefusal, readSettingsEnv, rulePolicyBucketsRefusal, settingsEnvCredentialIssue, settingsPermissionBucketIssue } from "../task-settings.js";
|
|
2
2
|
import { readTightenOnlySeats, tightenOnlySeatField, tightenOnlySeatIssue } from "../tighten-only-seats.js";
|
|
3
3
|
import { entryProblemsFacts } from "../entry-problems.js";
|
|
4
|
-
import { autonomyModeFloor, entryPermissionMode } from "../runtime-governance.js";
|
|
5
4
|
import { inertToolListEntryOf, replayInertEntry } from "../rule-entry-list.js";
|
|
6
5
|
import { executionLaneHomeDir } from "../execution-lane-caps.js";
|
|
7
6
|
import { executionConfigRootOf } from "../execution-config-root.js";
|
|
@@ -10,13 +9,7 @@ import { storedEnvCredentialsDropM38 } from "../stored-request-env-credentials-m
|
|
|
10
9
|
import { storedToolAxesRereadM19 } from "../stored-request-tool-axes-m19.js";
|
|
11
10
|
import { MAX_NAMED_MEMBERS, unreadRequestMembers, unreadRequestMembersRefusal } from "../unread-request-members.js";
|
|
12
11
|
import { serverCredentialValueSources } from "../server-secret-env.js";
|
|
13
|
-
import { allowListWriterUnproven,
|
|
14
|
-
export function permissionModeReadingUnstated(ctx, floor) {
|
|
15
|
-
if (floor === undefined || permissionModeReadingStated(ctx))
|
|
16
|
-
return undefined;
|
|
17
|
-
const stored = storedBodyPermissionMode(ctx.body);
|
|
18
|
-
return entryPermissionMode(stored, floor).effective === stored ? undefined : { stored, floor };
|
|
19
|
-
}
|
|
12
|
+
import { allowListWriterUnproven, retiredRequestKeyOf } from "./checkpoint-ctx.js";
|
|
20
13
|
const RETIRED_KEY_REWRITE_MIGRATION = { promptProfile: "M30" };
|
|
21
14
|
const BUCKET_GATE_CODE = "request.field_invalid";
|
|
22
15
|
const BUCKET_SIDE = {
|
|
@@ -87,9 +80,6 @@ export function storedBodyReplayRefusal(ctx, deployment) {
|
|
|
87
80
|
const entry = ruleTablesRefusalWithoutTaskRoot(ctx.body, deployment);
|
|
88
81
|
if (entry !== undefined)
|
|
89
82
|
return { kind: "inert_tool_list", entry };
|
|
90
|
-
const mode = permissionModeReadingUnstated(ctx, autonomyModeFloor(deployment.autonomy));
|
|
91
|
-
if (mode !== undefined)
|
|
92
|
-
return { kind: "permission_mode_reading", ...mode, ...writer };
|
|
93
83
|
const retiredKey = retiredRequestKeyOf(ctx.body);
|
|
94
84
|
if (retiredKey !== undefined)
|
|
95
85
|
return { kind: "retired_request_key", key: retiredKey, rewriteWindowEnd: migrationWindowEnd(RETIRED_KEY_REWRITE_MIGRATION[retiredKey]), ...writer };
|
|
@@ -31,7 +31,6 @@ export declare function persistSubmitCtx(store: SubmitCtxStore, deps: {
|
|
|
31
31
|
readonly logger?: Logger | undefined;
|
|
32
32
|
readonly metrics?: Metrics | undefined;
|
|
33
33
|
readonly checkpointCtxSealing?: CheckpointCtxSealer | undefined;
|
|
34
|
-
readonly instanceId?: string | undefined;
|
|
35
34
|
}, claim: {
|
|
36
35
|
readonly runStore: RunStore;
|
|
37
36
|
readonly taskId: string;
|
|
@@ -41,7 +40,7 @@ export declare function persistSubmitCtx(store: SubmitCtxStore, deps: {
|
|
|
41
40
|
* 提交腿写续跑输入的入口(三个调用点同调这一只):体与标记按受理座提交时交出的那一份定(见文件头「体里的目标按哪一份写」),只写这一笔。
|
|
42
41
|
* 写不进的处置与答复 = {@link persistSubmitCtx}(本函数只定体、不另判)。
|
|
43
42
|
*/
|
|
44
|
-
export declare function persistSubmissionCtx(store: SubmitCtxStore, deps: Parameters<typeof persistSubmitCtx>[1], claim: Parameters<typeof persistSubmitCtx>[2], prepared: Pick<PreparedTaskSubmission, "body" | "auth" | "verify" | "acceptance" | "bodyFromScreenedCtx"> & {
|
|
43
|
+
export declare function persistSubmissionCtx(store: SubmitCtxStore, deps: Parameters<typeof persistSubmitCtx>[1], claim: Parameters<typeof persistSubmitCtx>[2], prepared: Pick<PreparedTaskSubmission, "body" | "auth" | "verify" | "acceptance" | "bodyFromScreenedCtx"> & Partial<Pick<PreparedTaskSubmission, "legFacts">> & {
|
|
45
44
|
readonly spec: Pick<PreparedTaskSubmission["spec"], "sessionId" | "model">;
|
|
46
45
|
}): Promise<SubmitCtxRefusal | typeof SUBMIT_CTX_CLAIM_LOST | undefined>;
|
|
47
46
|
//# sourceMappingURL=submit-ctx.d.ts.map
|
package/dist/http/submit-ctx.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { StoreRowTooLargeError } from "../plugins/sql-errors.js";
|
|
2
2
|
import { withdrawClaimedRun } from "./claimed-run.js";
|
|
3
|
-
import {
|
|
3
|
+
import { createLegCtxClaim } from "../plugins/store-contracts.js";
|
|
4
4
|
import { buildCheckpointCtx, CheckpointCtxUnsealableError } from "./checkpoint-ctx.js";
|
|
5
5
|
import { refusalBody } from "./refusal-body.js";
|
|
6
6
|
import { limitFactsUnmeasured } from "../limit-refusal.js";
|
|
@@ -44,7 +44,7 @@ export async function persistSubmitCtx(store, deps, claim, sessionId, fields) {
|
|
|
44
44
|
let landed;
|
|
45
45
|
try {
|
|
46
46
|
const ctx = buildCheckpointCtx(fields, deps.checkpointCtxSealing, sessionId);
|
|
47
|
-
landed = await store.putCtx(sessionId, ctx, claim === undefined ? undefined :
|
|
47
|
+
landed = await store.putCtx(sessionId, ctx, claim === undefined ? undefined : createLegCtxClaim(claim.runStore, claim.taskId, claim.legId));
|
|
48
48
|
}
|
|
49
49
|
catch (err) {
|
|
50
50
|
const tooLarge = err instanceof StoreRowTooLargeError ? err : undefined;
|
|
@@ -76,6 +76,7 @@ export async function persistSubmissionCtx(store, deps, claim, prepared) {
|
|
|
76
76
|
body: screened && prepared.verify === undefined ? withheldBody(prepared.body, prepared.spec.model) : prepared.body,
|
|
77
77
|
memoryScope: prepared.auth?.memoryScope,
|
|
78
78
|
...(screened || prepared.bodyFromScreenedCtx === true ? { promptScreened: true } : {}),
|
|
79
|
+
...(prepared.legFacts?.projectContext !== undefined ? { projectContext: prepared.legFacts.projectContext } : {}),
|
|
79
80
|
writerVersion: serviceVersion(),
|
|
80
81
|
});
|
|
81
82
|
}
|