@sema-agent/server 7.144.0 → 7.145.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 +129 -0
- package/README.md +3 -0
- package/README.zh-CN.md +1 -0
- package/USAGE.md +16 -8
- package/dist/audit.d.ts +2 -21
- package/dist/audit.js +0 -9
- package/dist/boot/session-faces.d.ts +1 -1
- package/dist/boot/session-faces.js +3 -3
- package/dist/boot/stage-09-leader.d.ts +1 -1
- package/dist/boot/stage-10-http-server.d.ts +1 -1
- package/dist/boot/stage-10-http-server.js +2 -2
- package/dist/config-d-migration.d.ts +3 -2
- package/dist/fleet/fleet-bus.d.ts +13 -3
- package/dist/fleet/fleet-bus.js +17 -3
- package/dist/http/admission.js +2 -1
- package/dist/http/checkpoint-ctx.d.ts +1 -0
- package/dist/http/checkpoint-ctx.js +1 -0
- package/dist/http/durable-run-leg.js +7 -6
- package/dist/http/resume-legs.js +5 -3
- package/dist/http/route-ctx.d.ts +15 -0
- package/dist/http/routes/approvals-assistant.d.ts +20 -1
- package/dist/http/routes/approvals-assistant.js +27 -6
- package/dist/http/routes/rules.d.ts +1 -1
- package/dist/http/routes/rules.js +5 -2
- package/dist/http/routes/session-sync.js +12 -0
- package/dist/http/routes/tasks.js +12 -9
- package/dist/http/run-meta.d.ts +14 -7
- package/dist/http/run-meta.js +5 -2
- package/dist/http/server.d.ts +13 -5
- package/dist/http/server.js +3 -0
- package/dist/http/submit-ctx.d.ts +12 -0
- package/dist/http/submit-ctx.js +23 -0
- package/dist/observability/fail-open.d.ts +15 -3
- package/dist/observability/fail-open.js +15 -3
- package/dist/plugins/approval-ask-store-file.d.ts +16 -2
- package/dist/plugins/approval-ask-store-file.js +21 -1
- package/dist/plugins/approval-ask-store-memory.d.ts +8 -2
- package/dist/plugins/approval-ask-store-memory.js +11 -8
- package/dist/plugins/caching-session-store.d.ts +3 -0
- package/dist/plugins/caching-session-store.js +3 -0
- package/dist/plugins/checkpoint-store-sql.d.ts +29 -11
- package/dist/plugins/checkpoint-store-sql.js +38 -16
- package/dist/plugins/file-run-store.d.ts +13 -1
- package/dist/plugins/file-run-store.js +11 -1
- package/dist/plugins/local-checkpoint-store.d.ts +14 -3
- package/dist/plugins/local-checkpoint-store.js +23 -5
- package/dist/plugins/local-session-store.d.ts +52 -16
- package/dist/plugins/local-session-store.js +47 -14
- package/dist/plugins/memory-run-store.d.ts +2 -0
- package/dist/plugins/memory-run-store.js +6 -0
- package/dist/plugins/one-time-migrations.js +2 -2
- package/dist/plugins/run-store-sql.d.ts +4 -0
- package/dist/plugins/run-store-sql.js +3 -0
- package/dist/plugins/session-store.d.ts +1 -1
- package/dist/prompt-screen.d.ts +21 -0
- package/dist/prompt-screen.js +8 -0
- package/dist/rules-consent.d.ts +63 -51
- package/dist/rules-consent.js +6 -10
- package/dist/run-acceptance.d.ts +40 -10
- package/dist/run-acceptance.js +38 -5
- package/dist/runs.js +1 -1
- package/dist/security.d.ts +10 -3
- package/dist/session-agent.d.ts +39 -0
- package/dist/session-agent.js +16 -0
- package/dist/session-error-wire.d.ts +4 -4
- package/dist/trace/model-segment.d.ts +3 -2
- package/dist/trace/model-segment.js +16 -8
- package/dist/trace/redact.d.ts +66 -2
- package/dist/trace/redact.js +220 -101
- package/dist/trace/self-minted-wire.d.ts +73 -1
- package/dist/trace/self-minted-wire.js +27 -0
- package/package.json +2 -2
- package/wire-changes/server@7.145.0.json +146 -0
package/dist/fleet/fleet-bus.js
CHANGED
|
@@ -230,7 +230,7 @@ export class FleetEventBus {
|
|
|
230
230
|
}
|
|
231
231
|
export function fleetRunPublisher(bus, run) {
|
|
232
232
|
if (!bus)
|
|
233
|
-
return { onStart: () => undefined, onEvent: () => undefined, onForwardEvent: () => undefined, onTerminal: () => undefined };
|
|
233
|
+
return { onStart: () => undefined, onEvent: () => undefined, onForwardEvent: () => undefined, onTerminal: () => undefined, onNamed: () => undefined };
|
|
234
234
|
let tokens = 0;
|
|
235
235
|
const startedAt = Date.now();
|
|
236
236
|
const sessionField = run.sessionId ? { sessionId: run.sessionId } : {};
|
|
@@ -282,7 +282,14 @@ export function fleetRunPublisher(bus, run) {
|
|
|
282
282
|
};
|
|
283
283
|
return {
|
|
284
284
|
onStart() {
|
|
285
|
-
bus.publishTask({ id: run.runId, name: run.name, ...(run.description ? { description: run.description } : {}), scope: run.scope, ...sessionField, status: "running", tokens: 0, elapsedMs: 0 });
|
|
285
|
+
bus.publishTask({ id: run.runId, ...(run.name !== undefined ? { name: run.name } : {}), ...(run.description ? { description: run.description } : {}), scope: run.scope, ...sessionField, status: "running", tokens: 0, elapsedMs: 0 });
|
|
286
|
+
},
|
|
287
|
+
onNamed(name) {
|
|
288
|
+
if (settledLeg)
|
|
289
|
+
return;
|
|
290
|
+
if (bus.taskRow(run.runId) === undefined)
|
|
291
|
+
return;
|
|
292
|
+
bus.publishTask({ id: run.runId, name });
|
|
286
293
|
},
|
|
287
294
|
onEvent(ev) {
|
|
288
295
|
if (settledLeg)
|
|
@@ -595,7 +602,14 @@ export function buildRunName(preview) {
|
|
|
595
602
|
return oneLine.length > RUN_NAME_CHARS ? `${oneLine.slice(0, RUN_NAME_CHARS - 1)}…` : oneLine;
|
|
596
603
|
}
|
|
597
604
|
export function fleetRunLabels(objective) {
|
|
598
|
-
return { name: buildRunName(buildRunObjectivePreview(objective
|
|
605
|
+
return objective === undefined ? {} : { name: buildRunName(buildRunObjectivePreview(objective)) };
|
|
606
|
+
}
|
|
607
|
+
export function nameFleetRowOnDelivery(acceptance, publisher) {
|
|
608
|
+
acceptance.onDelivered("fleet-name", async (objective) => {
|
|
609
|
+
const { name } = fleetRunLabels(objective);
|
|
610
|
+
if (name !== undefined)
|
|
611
|
+
publisher.onNamed(name);
|
|
612
|
+
});
|
|
599
613
|
}
|
|
600
614
|
export function isTerminalFleetStatus(status) {
|
|
601
615
|
switch (status) {
|
package/dist/http/admission.js
CHANGED
|
@@ -24,6 +24,7 @@ import { legFactsOf } from "../leg-facts.js";
|
|
|
24
24
|
import { resolveExecutionContext, stampSpecRoot } from "./execution-context.js";
|
|
25
25
|
import { callerTrust, requestTrustRefusal } from "./caller-trust.js";
|
|
26
26
|
import { createRunAcceptance } from "../run-acceptance.js";
|
|
27
|
+
import { promptScreenDeclared } from "../prompt-screen.js";
|
|
27
28
|
import { sendError, sendHttpError } from "./send.js";
|
|
28
29
|
import { refuseSubmitBody } from "./request-guards.js";
|
|
29
30
|
import { sqlWallsOf } from "../plugins/sql-driver.js";
|
|
@@ -750,7 +751,7 @@ export function createAdmission(ctx) {
|
|
|
750
751
|
const runner = runnerFor(resolved);
|
|
751
752
|
const spec = stampSpecRoot(resolved, execution);
|
|
752
753
|
const model = modelIdOf(spec.model);
|
|
753
|
-
const acceptance = createRunAcceptance({ sessionTitler: deps.sessionTitler }, { sessionId: spec.sessionId, objective: spec.objective, ...(model !== undefined ? { model } : {}) });
|
|
754
|
+
const acceptance = createRunAcceptance({ sessionTitler: deps.sessionTitler }, { sessionId: spec.sessionId, objective: spec.objective, screened: promptScreenDeclared([deps.deploymentMods, spec.mods]), ...(model !== undefined ? { model } : {}) });
|
|
754
755
|
const clampNotice = buildEntryModeClampNotice(entryMode, spec.sessionId);
|
|
755
756
|
const pendingNotices = clampNotice !== undefined ? [clampNotice, ...engineNotices] : engineNotices;
|
|
756
757
|
const warnings = allowSelectorWarningsOf(admitted, spec.tools ?? []);
|
|
@@ -96,6 +96,7 @@ export declare function buildCheckpointCtx(fields: {
|
|
|
96
96
|
body: TaskRequestBody;
|
|
97
97
|
memoryScope?: string | undefined;
|
|
98
98
|
unattendedLeg?: true;
|
|
99
|
+
promptScreened?: true;
|
|
99
100
|
writerVersion: string;
|
|
100
101
|
}, sealer: CheckpointCtxSealer | undefined, sessionId: string): SealedCheckpointCtx;
|
|
101
102
|
/**
|
|
@@ -18,6 +18,7 @@ export function buildCheckpointCtx(fields, sealer, sessionId) {
|
|
|
18
18
|
writerVersion: fields.writerVersion,
|
|
19
19
|
...(fields.memoryScope !== undefined ? { memoryScope: fields.memoryScope } : {}),
|
|
20
20
|
...(fields.unattendedLeg === true ? { unattendedLeg: true } : {}),
|
|
21
|
+
...(fields.promptScreened === true ? { promptScreened: true } : {}),
|
|
21
22
|
...(bodyCarriesAllowList(fields.body) ? { permissionsAllowReading: "allow_layer" } : {}),
|
|
22
23
|
permissionModeReading: "entry_word",
|
|
23
24
|
};
|
|
@@ -2,8 +2,8 @@ import { uuidv7 } from "@sema-agent/core";
|
|
|
2
2
|
import { heldWorkflowParkDecisions } from "../parked-decide.js";
|
|
3
3
|
import { HEARTBEAT_MS, runInBackground } from "../runs.js";
|
|
4
4
|
import { heldFor } from "../peer-seat.js";
|
|
5
|
-
import { fleetRunPublisher, fleetRunLabels } from "../fleet/fleet-bus.js";
|
|
6
|
-
import { cascadeConfig, runMeta } from "./run-meta.js";
|
|
5
|
+
import { fleetRunPublisher, fleetRunLabels, nameFleetRowOnDelivery } from "../fleet/fleet-bus.js";
|
|
6
|
+
import { cascadeConfig, fillRunPreviewOnDelivery, runMeta } from "./run-meta.js";
|
|
7
7
|
import { declaredApprovalFrameFamilies, resolveStreamApprovalGate } from "../tool-approval.js";
|
|
8
8
|
import { buildActiveRunConflict } from "./active-run-conflict.js";
|
|
9
9
|
import { commitExecutionContext } from "./execution-context.js";
|
|
@@ -11,9 +11,8 @@ import { rootSessionAbsentAnswer } from "./execution-context.js";
|
|
|
11
11
|
import { commitSessionInheritEnv } from "./session-inherit-env.js";
|
|
12
12
|
import { clearTurnActivity, readTurnActivityMs } from "../turn-activity.js";
|
|
13
13
|
import { recordResourceWindow } from "../resource-window.js";
|
|
14
|
-
import {
|
|
14
|
+
import { persistSubmissionCtx } from "./submit-ctx.js";
|
|
15
15
|
import { releaseClaimedRun } from "./claimed-run.js";
|
|
16
|
-
import { serviceVersion } from "../service-version.js";
|
|
17
16
|
import { headReadOf } from "../session-incarnation.js";
|
|
18
17
|
import { createSessionWorkspaceRecorder, sessionWorkspaceStoreOf } from "../session-workspace.js";
|
|
19
18
|
export async function mintAndDriveDurableRun(ctx, runStore, args) {
|
|
@@ -34,6 +33,7 @@ export async function mintAndDriveDurableRun(ctx, runStore, args) {
|
|
|
34
33
|
if (!created.ok) {
|
|
35
34
|
return { status: 409, body: await buildActiveRunConflict({ runStore, checkpointStore: deps.checkpointStore, governance: deps.config, runStaleSec: deps.config.runStaleSec, turnActivity: readTurnActivityMs }, sessionId, created.activeTaskId) };
|
|
36
35
|
}
|
|
36
|
+
fillRunPreviewOnDelivery(args.prepared.acceptance, runStore, taskId);
|
|
37
37
|
const owner = args.prepared.auth?.principal ?? null;
|
|
38
38
|
const preLaunchHeartbeat = setInterval(() => {
|
|
39
39
|
void runStore.heartbeat(taskId, owner).catch(() => { deps.metrics?.inc("run_signal_poll_errors_total", { kind: "heartbeat" }); });
|
|
@@ -44,7 +44,7 @@ export async function mintAndDriveDurableRun(ctx, runStore, args) {
|
|
|
44
44
|
if (placementReject)
|
|
45
45
|
return placementReject;
|
|
46
46
|
if (deps.checkpointStore) {
|
|
47
|
-
const ctxRefusal = await
|
|
47
|
+
const ctxRefusal = await persistSubmissionCtx(deps.checkpointStore, deps, { runStore, taskId }, args.prepared);
|
|
48
48
|
if (ctxRefusal)
|
|
49
49
|
return ctxRefusal;
|
|
50
50
|
}
|
|
@@ -81,8 +81,9 @@ export async function mintAndDriveDurableRun(ctx, runStore, args) {
|
|
|
81
81
|
scope: args.fleetScope,
|
|
82
82
|
rootTaskId: taskId,
|
|
83
83
|
sessionId,
|
|
84
|
-
...fleetRunLabels(args.prepared.
|
|
84
|
+
...fleetRunLabels(args.prepared.acceptance.objectiveAtSubmit),
|
|
85
85
|
});
|
|
86
|
+
nameFleetRowOnDelivery(args.prepared.acceptance, fleetPub);
|
|
86
87
|
void heldFor(args.prepared.peerLease, () => runInBackground(args.prepared.runner, args.prepared.spec, runStore, taskId, deps.metrics, args.prepared.auth?.principal, args.prepared.verify, args.prepared.cascade ? cascadeConfig(deps.config.cascadeLadder, args.prepared.spec.limits?.maxCostUsd) : undefined, deps.instrumentDegenerate, deps.planCacheProbe, deps.config.traceThinking, inflightRuns, preemptableRuns, steerableRuns, deps.modelUsage, deps.elicitation, args.elicitOwner, captureTurnAnchor, fleetPub, captureUserMessageAnchor, deps.question, deps.workflowCompletionInbox, deps.subagentSteerRegistry, (m, x) => deps.logger?.info?.(m, x), deps.sendUserFile, deps.promptManifests, deps.toolApproval
|
|
87
88
|
? {
|
|
88
89
|
coordinator: deps.toolApproval,
|
package/dist/http/resume-legs.js
CHANGED
|
@@ -54,6 +54,7 @@ import { ASK_USER_QUESTION_TOOL_NAME, isApprovalGateKind, isEngineQuestionRow }
|
|
|
54
54
|
import { deploymentListAsks } from "../approval.js";
|
|
55
55
|
import { isParkLedgerEventType } from "../trace/ledger-events.js";
|
|
56
56
|
import { readResumeCtx, resumeCtxCorruptAnswer, resumeCtxUnsealableAnswer } from "./resume-ctx-read.js";
|
|
57
|
+
import { objectiveWithheldIn } from "./submit-ctx.js";
|
|
57
58
|
import { buildCheckpointVersionKeys, resumeBlockedByPolicyAnswer, resumeRefusalWithCard, sealCheckpointCtx, storedBodyReplayAnswer, storedBodyReplayLogFields, withPermissionModeRewritten } from "./checkpoint-ctx.js";
|
|
58
59
|
import { refusalBody, resumeRefusalFacts } from "./refusal-body.js";
|
|
59
60
|
import { storedBodyReplayRefusal } from "./stored-body-replay.js";
|
|
@@ -615,6 +616,7 @@ export function createResumeLegs(ctx) {
|
|
|
615
616
|
async function driveResumeLeg(args, onAccepted) {
|
|
616
617
|
const resumeLegStartedAt = Date.now();
|
|
617
618
|
const { runner: legRunner, token, sessionId, principal, fleetScope, taskConfig, resumeObjective, outcome, verifyRounds, resumeCtx, execution } = args;
|
|
619
|
+
const heldObjective = objectiveWithheldIn(resumeCtx.ctx) ? undefined : resumeObjective;
|
|
618
620
|
const reparkStatus = outcome.gate === "plan_review" ? "needs_review" : "suspended";
|
|
619
621
|
const commitResumeCtx = () => Promise.resolve().then(() => deps.checkpointStore.putCtx(resumeCtx.sessionId, sealCheckpointCtx({ ...resumeCtx.ctx, writerVersion: serviceVersion() }, deps.checkpointCtxSealing, resumeCtx.sessionId))).catch((e) => {
|
|
620
622
|
deps.metrics?.inc("resume_ctx_not_persisted_total");
|
|
@@ -653,7 +655,7 @@ export function createResumeLegs(ctx) {
|
|
|
653
655
|
const created = await deps.runStore.createRun(freshId, sessionId, principal ?? null, deps.instanceId ?? "default", {
|
|
654
656
|
source: args.mintFreshRun.source,
|
|
655
657
|
identity: args.mintFreshRun.identity,
|
|
656
|
-
objectivePreview: buildRunObjectivePreview(
|
|
658
|
+
objectivePreview: heldObjective === undefined ? null : buildRunObjectivePreview(heldObjective),
|
|
657
659
|
});
|
|
658
660
|
if (created.existing) {
|
|
659
661
|
throw new Error(`wake fresh run: createRun observed an existing row for the freshly minted taskId ${freshId} (no idempotency key was sent) — refusing to treat it as a busy session`);
|
|
@@ -670,7 +672,7 @@ export function createResumeLegs(ctx) {
|
|
|
670
672
|
freshRunClaimed = true;
|
|
671
673
|
}
|
|
672
674
|
const fleetPub = taskId && deps.fleetBus
|
|
673
|
-
? fleetRunPublisher(deps.fleetBus, { runId: taskId, scope: fleetScope, rootTaskId: taskId, sessionId, ...fleetRunLabels(
|
|
675
|
+
? fleetRunPublisher(deps.fleetBus, { runId: taskId, scope: fleetScope, rootTaskId: taskId, sessionId, ...fleetRunLabels(heldObjective) })
|
|
674
676
|
: undefined;
|
|
675
677
|
const resumeTaskConfig = taskId ? { ...taskConfig, taskId } : taskConfig;
|
|
676
678
|
if (deps.toolApproval && taskId) {
|
|
@@ -1429,7 +1431,7 @@ export function createResumeLegs(ctx) {
|
|
|
1429
1431
|
const { spec, engineNotices } = resolved;
|
|
1430
1432
|
const hostSpec = { ...spec, objective };
|
|
1431
1433
|
const out = await mintAndDriveDurableRun(routeCtxBase, deps.runStore, {
|
|
1432
|
-
prepared: { spec: hostSpec, runner: resolved.runner, legFacts: resolved.legFacts, auth, body: ctx.body, acceptance: createRunAcceptance({}, { objective }), peerLease: resolved.peerLease, execution: resolved.execution, ...(engineNotices.length > 0 ? { engineNotices } : {}) },
|
|
1434
|
+
prepared: { spec: hostSpec, runner: resolved.runner, legFacts: resolved.legFacts, auth, body: ctx.body, ...(objectiveWithheldIn(ctx) ? { bodyFromScreenedCtx: true } : {}), acceptance: createRunAcceptance({}, { objective, screened: false }), peerLease: resolved.peerLease, execution: resolved.execution, ...(engineNotices.length > 0 ? { engineNotices } : {}) },
|
|
1433
1435
|
fleetScope: resumeFleetScope(req, auth),
|
|
1434
1436
|
elicitOwner: principal ?? null,
|
|
1435
1437
|
source: "workflow_parked_decide",
|
package/dist/http/route-ctx.d.ts
CHANGED
|
@@ -146,6 +146,12 @@ export interface PreparedTaskSubmission {
|
|
|
146
146
|
* 判的是**这一次提交**的体:幂等重放从 run 记录答,不重判、不带。
|
|
147
147
|
*/
|
|
148
148
|
warnings?: readonly EntryProblem[];
|
|
149
|
+
/**
|
|
150
|
+
* `body` 是从一份标着 `promptScreened` 的续跑输入里取回的存量体(今天唯一的这种提交 = `/decide` 的宿主新 turn:这一跑的目标是本服务铸的指路文本,
|
|
151
|
+
* 体是宿主会话自己的那一份)⇒ 这一跑新写的续跑输入照样标上(`submit-ctx.ts` `persistSubmissionCtx`)。体里的目标不是这一跑的目标,
|
|
152
|
+
* 它能不能展示在它第一次落盘时就定了,这一跑的受理座答不了。缺席 = 体是这次请求自己的,标不标由受理座定。
|
|
153
|
+
*/
|
|
154
|
+
bodyFromScreenedCtx?: true;
|
|
149
155
|
/**
|
|
150
156
|
* 这次执行的**执行上下文**(唯一解析器 `http/execution-context.ts` `resolveExecutionContext` 的产物:根 · 住客 · 放置态 · 车道 · device 车道的设备意图)。
|
|
151
157
|
* 提交门在装配之前铸(fresh);`/decide` 的宿主新 turn 交续跑折叠器铸的那一只(continuation)。每个 `runStore.createRun(` 成功点**必须**把它交给
|
|
@@ -208,6 +214,15 @@ export interface CheckpointCtx {
|
|
|
208
214
|
* 缺席 = 本版之前写下的行(不回填):那一码的体不带两键,如实不猜。不是一次性迁移 —— 这一格是常设的事实位,没有删除条件。
|
|
209
215
|
*/
|
|
210
216
|
writerVersion?: string;
|
|
217
|
+
/**
|
|
218
|
+
* 体里的目标**不是可展示的那一份**:写这份续跑输入的提交腿上装着 prompt 屏(判据 `prompt-screen.ts` 的 `promptScreenDeclared`),
|
|
219
|
+
* 体里的 `objective` 不是引擎交付的文本 —— 留空,或 verify 形为验证器留着的请求原文(律的属主 = `run-acceptance.ts`「交付的是哪一份」;
|
|
220
|
+
* 写法与那条 P-DEBT 见 `submit-ctx.ts` 头注)。**服务端写、不来自请求体**(与 {@link unattendedLeg} 同为 `body` 的兄弟键)。
|
|
221
|
+
* 读者只有一只:`submit-ctx.ts` 的 `objectiveWithheldIn`(续跑腿的两张展示面 —— wake 新行的预览、fleet 行名 —— 经它问,在场 ⇒ 缺席)。
|
|
222
|
+
* 写点:`buildCheckpointCtx`(提交腿那一笔,经 `persistSubmissionCtx`;体从一份标着它的续跑输入里取回时照样标上);续跑腿的写回传原 ctx / 其展开 ⇒ 标随行。
|
|
223
|
+
* 缺席 = 体里的目标就是交付的那一份(腿上没有屏)。
|
|
224
|
+
*/
|
|
225
|
+
promptScreened?: true;
|
|
211
226
|
}
|
|
212
227
|
/**
|
|
213
228
|
* `/decide` 第三条车道交给宿主投递腿(wake:`DriveResumeArgs` / fresh:`DurableRunLegArgs`)的**一件**:这一跑在内存里带着的决定,
|
|
@@ -7,6 +7,7 @@ import { type GateIntentView } from "../../approval.js";
|
|
|
7
7
|
import { type RouteCtx, type RouteDecl, type RouteMatch, type RouteIdsOf } from "../route-ctx.js";
|
|
8
8
|
import { type KeyClosureIssue } from "../../request-key-closure.js";
|
|
9
9
|
import { type PeerInboundPendingRow } from "../../peer-inbound-face.js";
|
|
10
|
+
import { type PlacementReadingSessionStore, type SessionAgent } from "../../session-agent.js";
|
|
10
11
|
/** 族的成员 = 路由表行 id(改名 / 删行 ⇒ 下表的键当场编译红)。 */
|
|
11
12
|
export type DecisionDoorId = Extract<ApprovalsAssistantRouteId, "approval-decide" | "assistant-task-plan-review">;
|
|
12
13
|
/** 一道门的静态描述 —— 只写**这道门自己**的东西;路径、路径段、别门的键一概不在这里写(从来源读)。 */
|
|
@@ -104,6 +105,19 @@ export type QuestionAnswerCheck = {
|
|
|
104
105
|
*/
|
|
105
106
|
export declare function checkQuestionAnswer(v: unknown): QuestionAnswerCheck;
|
|
106
107
|
export declare function handleApprovalsAssistant(req: IncomingMessage, res: ServerResponse, match: RouteMatch<ApprovalsAssistantRouteId>, ctx: RouteCtx): Promise<void>;
|
|
108
|
+
/** `listPending()` 的行形(两条 durable 读面共用;从 store 的返回类型取,不手抄)。 */
|
|
109
|
+
type PendingRow = Awaited<ReturnType<CheckpointStoreFull["listPending"]>>[number];
|
|
110
|
+
/**
|
|
111
|
+
* 两条 durable 读面共用的行形 —— 行 + [ref]② 追加的**出身格**(派生位,不是列)+ [ref] 行族词(`checkpoint`)+ [ref] 行的会话在委派树里的位置 `agent`
|
|
112
|
+
* (会话视图 `GET /v1/sessions/:id` 体顶层的同名键,同一只读口 `readSessionAgent`;在场 ⇔ 这一次列表读到行的会话是一只 placed 委派子代,见 {@link projectDurableQueue})。
|
|
113
|
+
* 导出只为自铸登记表按键绑型(`trace/self-minted-wire.ts` 的 `approvalQueueRowAgent`)。
|
|
114
|
+
*/
|
|
115
|
+
export type PendingRowForWire = PendingRow & {
|
|
116
|
+
kind: "checkpoint";
|
|
117
|
+
governanceForced?: true;
|
|
118
|
+
rememberRefused?: true;
|
|
119
|
+
agent?: SessionAgent;
|
|
120
|
+
};
|
|
107
121
|
/**
|
|
108
122
|
* 🔴 [ref]-2 / [ref]②:两条 durable 读面(`GET /v1/approvals` + `/v1/approvals/stream`)的**唯一**
|
|
109
123
|
* 投影 —— 脱敏([ref] 件4)+ 出身归因([ref] 的另一半)一次做完。
|
|
@@ -145,7 +159,12 @@ live: Pick<ToolApprovalCoordinator, "listLivePending"> | undefined,
|
|
|
145
159
|
* (`pending` / `resolved`):两族同一扇决断口,帧上的 `kind` 判别。`undefined` = 本腿没有这一半场(流字节只差每帧的 `kind`)。
|
|
146
160
|
* 位置在 `scope` 之前、与 `live` 并列:每个生产调用点都必须表态。
|
|
147
161
|
*/
|
|
148
|
-
peerInbound: (() => readonly PeerInboundPendingRow[]) | undefined,
|
|
162
|
+
peerInbound: (() => readonly PeerInboundPendingRow[]) | undefined,
|
|
163
|
+
/**
|
|
164
|
+
* 🔴 [ref]:停驻行 `agent` 的会话店面 —— 与 `GET /v1/approvals` 同一只(`deps.sessionStorage`),经同一只整批投影 {@link projectDurableQueue}。
|
|
165
|
+
* `undefined` / 店不交 `placementOf` = 这台部署不存委派元组 ⇒ 没有一帧带 `agent`(帧字节与 [ref] 之前逐字相同)。位置在 `scope` 之前、与 `live` 并列:每个生产调用点都必须表态。
|
|
166
|
+
*/
|
|
167
|
+
sessions: PlacementReadingSessionStore | undefined, scope: string | undefined,
|
|
149
168
|
/** [ref]②:出身归因的部署侧一半 + 三张审批名单(问的属主)。缺席 ⇒ 归不出治理出身(键缺席,与 best-effort 同方向)、没有一行读作
|
|
150
169
|
* 部署名单的问(记不住,方向是多问)。**位置在 `pollMs` 之前**是刻意的:`pollMs` 只有测试传,而本参数是每个生产调用点都必须给的那一个。 */
|
|
151
170
|
governance?: PendingProjectionDeployment, pollMs?: number): Promise<void>;
|
|
@@ -36,6 +36,7 @@ import { seatText } from "../../trace/exit-seat.js";
|
|
|
36
36
|
import { approvalQueueKindOfDoorId } from "../../approval-queue-kind.js";
|
|
37
37
|
import { defaultPeerInboundFace, parsePeerInboundId, peerBoxScope } from "../../peer-inbound-face.js";
|
|
38
38
|
import { RESUME_RESTATABLE_KEYS, readResumeRestatement } from "../resume-restatement.js";
|
|
39
|
+
import { readSessionAgent } from "../../session-agent.js";
|
|
39
40
|
const DECIDE_BODY_DECLARED_KEYS = [
|
|
40
41
|
"answer", "boundCallId", "boundInputHash", "checkpointToken", "decidedBy", "decidedVia", "decision", "feedback", "reason", "remember", "updatedInput",
|
|
41
42
|
...RESUME_RESTATABLE_KEYS,
|
|
@@ -315,7 +316,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
|
|
|
315
316
|
if (match.decl.id === "approvals-stream") {
|
|
316
317
|
const ownerParam = operator ? (new URLSearchParams(match.search).get("owner") ?? undefined) : undefined;
|
|
317
318
|
const scope = operator ? ownerParam : ownScope;
|
|
318
|
-
await streamApprovals(req, res, cs, deps.toolApproval, peerInboundRowsFor(defaultPeerInboundFace, principal, ownerParam), scope, deps.config);
|
|
319
|
+
await streamApprovals(req, res, cs, deps.toolApproval, peerInboundRowsFor(defaultPeerInboundFace, principal, ownerParam), deps.sessionStorage, scope, deps.config);
|
|
319
320
|
return;
|
|
320
321
|
}
|
|
321
322
|
if (match.decl.id === "approvals-list") {
|
|
@@ -331,7 +332,7 @@ export async function handleApprovalsAssistant(req, res, match, ctx) {
|
|
|
331
332
|
sendApprovalsReadFailure(req, res, deps.logger, err);
|
|
332
333
|
return;
|
|
333
334
|
}
|
|
334
|
-
const pending = [...
|
|
335
|
+
const pending = [...(await projectDurableQueue(durableRows, deps.config, deps.sessionStorage)), ...peerInboundRowsFor(defaultPeerInboundFace, principal, ownerParam)()];
|
|
335
336
|
sendJson(res, 200, {
|
|
336
337
|
pending,
|
|
337
338
|
serverNowMs: Date.now(),
|
|
@@ -1036,7 +1037,7 @@ function peerInboundRowsFor(face, principal, operatorOwnerParam) {
|
|
|
1036
1037
|
const scope = peerBoxScope(principal);
|
|
1037
1038
|
return () => face.list(scope);
|
|
1038
1039
|
}
|
|
1039
|
-
function projectPendingForWire(row, deployment) {
|
|
1040
|
+
function projectPendingForWire(row, deployment, agent) {
|
|
1040
1041
|
const governance = deployment;
|
|
1041
1042
|
const redacted = redactPendingDisclosures(row);
|
|
1042
1043
|
const governanceForced = governanceOriginOf({ riskDescriptor: row.riskDescriptor ?? undefined }, governance);
|
|
@@ -1049,7 +1050,27 @@ function projectPendingForWire(row, deployment) {
|
|
|
1049
1050
|
classes: row.classes,
|
|
1050
1051
|
deploymentListQuestion,
|
|
1051
1052
|
});
|
|
1052
|
-
return { kind: "checkpoint", ...redacted, ...(governanceForced ? { governanceForced } : {}), ...(rememberRefused ? { rememberRefused: true } : {}) };
|
|
1053
|
+
return { kind: "checkpoint", ...redacted, ...(governanceForced ? { governanceForced } : {}), ...(rememberRefused ? { rememberRefused: true } : {}), ...(agent !== undefined ? { agent } : {}) };
|
|
1054
|
+
}
|
|
1055
|
+
async function projectDurableQueue(rows, deployment, sessions) {
|
|
1056
|
+
const agents = await sessionAgentsOf(rows.map((r) => r.sessionId), sessions);
|
|
1057
|
+
return rows.map((r) => projectPendingForWire(r, deployment, agents.get(r.sessionId)));
|
|
1058
|
+
}
|
|
1059
|
+
async function sessionAgentsOf(sessionIds, sessions) {
|
|
1060
|
+
const out = new Map();
|
|
1061
|
+
if (sessions?.placementOf === undefined)
|
|
1062
|
+
return out;
|
|
1063
|
+
await Promise.all([...new Set(sessionIds)].map(async (sessionId) => {
|
|
1064
|
+
try {
|
|
1065
|
+
const agent = await readSessionAgent(sessions, sessionId);
|
|
1066
|
+
if (agent !== undefined)
|
|
1067
|
+
out.set(sessionId, agent);
|
|
1068
|
+
}
|
|
1069
|
+
catch (err) {
|
|
1070
|
+
recordFailOpen("server.approvals.queue-row-agent-unreadable", `session ${JSON.stringify(sessionId)}: ${seatText("operator-log-text", err instanceof Error ? err.message : String(err))}`);
|
|
1071
|
+
}
|
|
1072
|
+
}));
|
|
1073
|
+
return out;
|
|
1053
1074
|
}
|
|
1054
1075
|
function createSseDeltaLane(res, spec) {
|
|
1055
1076
|
let prev = new Map();
|
|
@@ -1068,7 +1089,7 @@ function createSseDeltaLane(res, spec) {
|
|
|
1068
1089
|
},
|
|
1069
1090
|
};
|
|
1070
1091
|
}
|
|
1071
|
-
export async function streamApprovals(req, res, cs, live, peerInbound, scope, governance, pollMs = APPROVALS_STREAM_POLL_MS) {
|
|
1092
|
+
export async function streamApprovals(req, res, cs, live, peerInbound, sessions, scope, governance, pollMs = APPROVALS_STREAM_POLL_MS) {
|
|
1072
1093
|
const keyOf = (p) => {
|
|
1073
1094
|
switch (p.kind) {
|
|
1074
1095
|
case "checkpoint":
|
|
@@ -1118,7 +1139,7 @@ export async function streamApprovals(req, res, cs, live, peerInbound, scope, go
|
|
|
1118
1139
|
while (!closed) {
|
|
1119
1140
|
let snapshot;
|
|
1120
1141
|
try {
|
|
1121
|
-
const pending = [...(await cs.listPending(scope)
|
|
1142
|
+
const pending = [...(await projectDurableQueue(await cs.listPending(scope), governance, sessions)), ...(peerInbound?.() ?? [])];
|
|
1122
1143
|
snapshot = { pending, livePending: live ? live.listLivePending(scope) : [] };
|
|
1123
1144
|
}
|
|
1124
1145
|
catch (err) {
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*
|
|
4
4
|
* POST /v1/rules → 写一条**收紧**规则(deny/ask)进 durable 分区,单步、无票仪式
|
|
5
5
|
* POST /v1/rules/cc-import/prepare → 预览 + 一张**一次性、principal 绑定、有期、载荷绑定**的票
|
|
6
|
-
* POST /v1/rules/cc-import/redeem → 原子消费票 → confirm → 批量兑付进店
|
|
6
|
+
* POST /v1/rules/cc-import/redeem → 原子消费票 → confirm → 批量兑付进店 → 回执 `{ members, rev }`(与 local-import 口同一张,{@link sendImportReceipt})
|
|
7
7
|
* GET /v1/rules → 列出自己名下**活着**的规则(keyset 分页,游标绑 rev)
|
|
8
8
|
* DELETE /v1/rules → 按 (rule, scope) 内容撤销,**恒经** core `removePersistedRule`
|
|
9
9
|
*
|
|
@@ -159,7 +159,7 @@ export async function handleRules(req, res, match, ctx) {
|
|
|
159
159
|
}
|
|
160
160
|
const redeemed = await lane.redeemLocalImport(principal, parsed.data.ticket);
|
|
161
161
|
if (redeemed.ok) {
|
|
162
|
-
|
|
162
|
+
sendImportReceipt(res, redeemed.outcome);
|
|
163
163
|
return;
|
|
164
164
|
}
|
|
165
165
|
logger.info("local rule import ticket refused", { reason: redeemed.reason, detail: redeemed.detail, retryable: redeemed.reason !== "ticket-unusable" && redeemed.reason !== "in-flight" && redeemed.retryable === true });
|
|
@@ -218,7 +218,10 @@ export async function handleRules(req, res, match, ctx) {
|
|
|
218
218
|
sendError(res, 404, "not_found.rule_ticket", "no such import ticket");
|
|
219
219
|
return;
|
|
220
220
|
}
|
|
221
|
-
|
|
221
|
+
sendImportReceipt(res, redeemed.outcome);
|
|
222
|
+
}
|
|
223
|
+
function sendImportReceipt(res, outcome) {
|
|
224
|
+
sendJson(res, 200, { members: outcome.members, rev: outcome.rev });
|
|
222
225
|
}
|
|
223
226
|
function resolveTargetPrincipal(requested, caller, config) {
|
|
224
227
|
if (requested === undefined || requested === caller)
|
|
@@ -7,6 +7,8 @@ import * as facts from "../../capability-facts.js";
|
|
|
7
7
|
import { classifySyncRelationshipByIds, readImportAnchors, SyncConflictError } from "../../session-sync-kernel.js";
|
|
8
8
|
import { isUuidShape, legacyUnownedSessionOk, sessionOwnerCellOf } from "../../security.js";
|
|
9
9
|
import { sendJson, sendError, sendSessionError, sendSessionPolicyError, logRequestError, msg } from "../send.js";
|
|
10
|
+
import { StampedSessionArchiveError } from "../../session-error-wire.js";
|
|
11
|
+
import { readSessionAgent } from "../../session-agent.js";
|
|
10
12
|
import { buildDisplaySafeUrl } from "../../trace/redact.js";
|
|
11
13
|
import { storeFaultClassOf } from "../../plugins/store-fault.js";
|
|
12
14
|
import { fleetViewOf, gatedPrincipal, explicitOperatorOk, sendUnauthorized, sessionCallerOf } from "../principal-gate.js";
|
|
@@ -359,6 +361,16 @@ export async function handleSessionSync(req, res, match, ctx) {
|
|
|
359
361
|
const dstIds = (await sessionStorage.listEntryIds?.(sessionId)) ?? null;
|
|
360
362
|
const relA = classifySyncRelationshipByIds(entryIds, dstIds);
|
|
361
363
|
if ((relA.relation === "fork" || relA.relation === "stale") && resolution !== "overwrite-dst") {
|
|
364
|
+
if (sessionStorage.assertArchiveAnonymous !== undefined && (await readSessionAgent(sessionStorage, sessionId)) === undefined) {
|
|
365
|
+
try {
|
|
366
|
+
await sessionStorage.assertArchiveAnonymous(sessionId);
|
|
367
|
+
}
|
|
368
|
+
catch (e) {
|
|
369
|
+
if (e instanceof StampedSessionArchiveError && sendSessionError(res, e, "import"))
|
|
370
|
+
return;
|
|
371
|
+
throw e;
|
|
372
|
+
}
|
|
373
|
+
}
|
|
362
374
|
sendError(res, 409, "conflict", "sync conflict", { relation: relA });
|
|
363
375
|
return;
|
|
364
376
|
}
|
|
@@ -5,7 +5,7 @@ import { graftParkToolCallId, markChildrenStoppedByUserOnAbort, syncRefusalHttpS
|
|
|
5
5
|
import { atHostBoundary, sealResultForExit, outwardPlane } from "../../terminal.js";
|
|
6
6
|
import { voidVerifierPauseCard } from "../../verifier-pause-card.js";
|
|
7
7
|
import { withPrincipal } from "../../observability/principal-context.js";
|
|
8
|
-
import { fleetRunPublisher, fleetRunLabels, fleetRunResiduals } from "../../fleet/fleet-bus.js";
|
|
8
|
+
import { fleetRunPublisher, fleetRunLabels, fleetRunResiduals, nameFleetRowOnDelivery } from "../../fleet/fleet-bus.js";
|
|
9
9
|
import { defaultSubagentTailBus } from "../../fleet/subagent-tail-bus.js";
|
|
10
10
|
import { createLiveModelText, modelStreamOfTask } from "../../trace/model-segment.js";
|
|
11
11
|
import { emitPendingWorkflowCompletions, taskNotificationInboxEntry, taskNotificationStreamKeyOf, NotifiedKeys } from "../../orchestration/workflow-completion-inbox.js";
|
|
@@ -17,7 +17,7 @@ import { recordResourceWindow } from "../../resource-window.js";
|
|
|
17
17
|
import { redactSecrets } from "../../trace/redact.js";
|
|
18
18
|
import { writeLiveFrame, writeLiveHeartbeat } from "../live-frame.js";
|
|
19
19
|
import { contextUsageEventData, turnEndEventData, toolStartEventData, toolEndEventData, taskProgressEventData, taskStartedEventData, taskNotificationEventData, compactedEventData, diagnosticsEventData, brainStatusEventData, steeringInjectedEventData, compactionOutcomeEventData, compactionStartedEventData, workspaceChangedEventData, wiringManifestFaceEventData, toolRosterDeltaEventData, toolProgressEventData, toolDisclosureEventData, humanInputEventData, appendModelUsageDelta, attachModelUsage, liveIdentityFields } from "../../trace/project.js";
|
|
20
|
-
import { cascadeConfig, runMeta } from "../run-meta.js";
|
|
20
|
+
import { cascadeConfig, fillRunPreviewOnDelivery, runMeta } from "../run-meta.js";
|
|
21
21
|
import { idemCallerOf, inflightKeyOf, submissionIdemOf } from "../idempotency.js";
|
|
22
22
|
import { replayOfExistingRun } from "../submit-replay.js";
|
|
23
23
|
import { httpErrorCode, sendJson, sendError, sseHeaders } from "../send.js";
|
|
@@ -33,8 +33,7 @@ import { failOpenTagForDroppedFrame, recordFailOpen } from "../../observability/
|
|
|
33
33
|
import { buildSyncSubmitBody } from "../sync-submit-body.js";
|
|
34
34
|
import { assertNever } from "../route-ctx.js";
|
|
35
35
|
import * as facts from "../../capability-facts.js";
|
|
36
|
-
import {
|
|
37
|
-
import { serviceVersion } from "../../service-version.js";
|
|
36
|
+
import { persistSubmissionCtx } from "../submit-ctx.js";
|
|
38
37
|
import { withModelReachScope } from "../../model-reach-scope.js";
|
|
39
38
|
import { createInstructionSelectionLeg } from "../../instruction-selection.js";
|
|
40
39
|
import { fieldConflictFacts } from "../../field-conflict.js";
|
|
@@ -326,9 +325,10 @@ export async function handleTasks(req, res, match, ctx) {
|
|
|
326
325
|
return placementReject;
|
|
327
326
|
}
|
|
328
327
|
durableTaskId = tid;
|
|
328
|
+
fillRunPreviewOnDelivery(prepared.acceptance, deps.runStore, tid);
|
|
329
329
|
}
|
|
330
330
|
if (deps.checkpointStore) {
|
|
331
|
-
const ctxRefusal = await
|
|
331
|
+
const ctxRefusal = await persistSubmissionCtx(deps.checkpointStore, deps, durableTaskId !== undefined && deps.runStore ? { runStore: deps.runStore, taskId: durableTaskId } : undefined, prepared);
|
|
332
332
|
if (ctxRefusal) {
|
|
333
333
|
writeLiveFrame(res, { type: "done", result: doneResultOfOutcome(ctxRefusal) });
|
|
334
334
|
return ctxRefusal;
|
|
@@ -361,8 +361,10 @@ export async function handleTasks(req, res, match, ctx) {
|
|
|
361
361
|
let fleetPub;
|
|
362
362
|
try {
|
|
363
363
|
fleetPub = durableTaskId
|
|
364
|
-
? fleetRunPublisher(deps.fleetBus, { runId: durableTaskId, scope: gatedPrincipal(req, deps.config) ?? "default", rootTaskId: durableTaskId, sessionId: prepared.spec.sessionId, ...fleetRunLabels(prepared.
|
|
364
|
+
? fleetRunPublisher(deps.fleetBus, { runId: durableTaskId, scope: gatedPrincipal(req, deps.config) ?? "default", rootTaskId: durableTaskId, sessionId: prepared.spec.sessionId, ...fleetRunLabels(prepared.acceptance.objectiveAtSubmit) })
|
|
365
365
|
: undefined;
|
|
366
|
+
if (fleetPub)
|
|
367
|
+
nameFleetRowOnDelivery(prepared.acceptance, fleetPub);
|
|
366
368
|
}
|
|
367
369
|
catch (e) {
|
|
368
370
|
if (durableHeartbeat)
|
|
@@ -499,7 +501,7 @@ export async function handleTasks(req, res, match, ctx) {
|
|
|
499
501
|
userMsgEntryId = promptEntryId;
|
|
500
502
|
const causeAtDone = ev.type === "done" ? ac.cause() : undefined;
|
|
501
503
|
await deps.userInputLedger?.observeLegEvent(liveStream, ev);
|
|
502
|
-
prepared.acceptance.observe(ev);
|
|
504
|
+
await prepared.acceptance.observe(ev);
|
|
503
505
|
await liveWorkspace.observe(ev);
|
|
504
506
|
if (ev.type === "done") {
|
|
505
507
|
finalResult = await mintSubmitExitResult(ev.result, deps.checkpointStore);
|
|
@@ -894,9 +896,10 @@ export async function handleTasks(req, res, match, ctx) {
|
|
|
894
896
|
if (placementReject)
|
|
895
897
|
return placementReject;
|
|
896
898
|
durableTaskId = tid;
|
|
899
|
+
fillRunPreviewOnDelivery(prepared.acceptance, deps.runStore, tid);
|
|
897
900
|
}
|
|
898
901
|
if (deps.checkpointStore) {
|
|
899
|
-
const ctxRefusal = await
|
|
902
|
+
const ctxRefusal = await persistSubmissionCtx(deps.checkpointStore, deps, durableTaskId !== undefined && deps.runStore ? { runStore: deps.runStore, taskId: durableTaskId } : undefined, prepared);
|
|
900
903
|
if (ctxRefusal)
|
|
901
904
|
return ctxRefusal;
|
|
902
905
|
}
|
|
@@ -940,7 +943,7 @@ export async function handleTasks(req, res, match, ctx) {
|
|
|
940
943
|
const syncWorkspace = createSessionWorkspaceRecorder(sessionWorkspaceStoreOf(deps.sessionStorage), prepared.legFacts?.sessionWitness);
|
|
941
944
|
for await (const ev of stream) {
|
|
942
945
|
observeSyncLegEvent(ev);
|
|
943
|
-
prepared.acceptance.observe(ev);
|
|
946
|
+
await prepared.acceptance.observe(ev);
|
|
944
947
|
await syncWorkspace.observe(ev);
|
|
945
948
|
}
|
|
946
949
|
return stream.result();
|
package/dist/http/run-meta.d.ts
CHANGED
|
@@ -1,21 +1,28 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* [ref] A9 装配缝的一片小叶子 ——
|
|
2
|
+
* [ref] A9 装配缝的一片小叶子 —— 提交路径共用的三只小件(run 行元数据 + run 行预览的补写口 + cascade 配置)。
|
|
3
3
|
*
|
|
4
|
-
* 为什么单独成文件:`runMeta`
|
|
5
|
-
* 挂在任一域模块上都会造出 routes/* 互相值 import
|
|
4
|
+
* 为什么单独成文件:`runMeta` 与预览补写口被 tasks 与 runs **两个**域模块调用,`cascadeConfig` 同理(还被测试直接引)。
|
|
5
|
+
* 挂在任一域模块上都会造出 routes/* 互相值 import 的第二条边;它们只依赖入参(受理座 / run 店两只口)+ 预览读法叶子,
|
|
6
6
|
* 所以正确归处是叶子。server.ts 转出口 `cascadeConfig` 以保住既有 import 点。
|
|
7
7
|
*/
|
|
8
|
-
import type {
|
|
8
|
+
import type { CascadeConfig } from "@sema-agent/core";
|
|
9
|
+
import type { RunAcceptance } from "../run-acceptance.js";
|
|
10
|
+
import type { RunStore } from "../plugins/store-backend.js";
|
|
9
11
|
/** The denormalized run-row metadata captured at submit: correlation (jobId), credential-derived source,
|
|
10
|
-
* and a redacted objective glance for lists. One place so the three submit paths can't drift.
|
|
12
|
+
* and a redacted objective glance for lists. One place so the three submit paths can't drift.
|
|
13
|
+
*
|
|
14
|
+
* 预览只取受理座交出的、提交那一刻就知道的交付文本(律的属主 = `run-acceptance.ts`「交付的是哪一份」):腿上没有 prompt 屏 ⇒ 交付的就是请求原文,
|
|
15
|
+
* 建行即写;腿上有屏 ⇒ 建行**不写**(列 NULL = 没建过预览),引擎交付可写的那一份时经 {@link fillRunPreviewOnDelivery} 补写一次。本函数不读请求体。 */
|
|
11
16
|
export declare function runMeta(prepared: {
|
|
12
17
|
jobId?: string;
|
|
13
|
-
|
|
18
|
+
acceptance: Pick<RunAcceptance, "objectiveAtSubmit">;
|
|
14
19
|
}, source: string | null): {
|
|
15
20
|
jobId: string | null;
|
|
16
21
|
source: string | null;
|
|
17
|
-
objectivePreview: string;
|
|
22
|
+
objectivePreview: string | null;
|
|
18
23
|
};
|
|
24
|
+
/** 腿上有屏时 run 行预览的补写口(建行之后、起跑之前登记):交付的那一份 → 同一只读法 → 店的写一次口(列已有值则不动)。腿上没有屏 ⇒ 受理座永不调它。 */
|
|
25
|
+
export declare function fillRunPreviewOnDelivery(acceptance: Pick<RunAcceptance, "onDelivered">, runStore: Pick<RunStore, "fillObjectivePreview">, taskId: string): void;
|
|
19
26
|
/** Build the cascade config from the operator ladder. Default gate = `status==="completed"` (escalate
|
|
20
27
|
* on a cheap-rung failure); cost-ceiling from the task's budget bounds the cold-rerun tax. */
|
|
21
28
|
export declare function cascadeConfig(ladder: readonly string[], maxCostUsd?: number): CascadeConfig;
|
package/dist/http/run-meta.js
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
1
|
import { buildRunObjectivePreview } from "../user-authored-text.js";
|
|
2
2
|
export function runMeta(prepared, source) {
|
|
3
|
-
const
|
|
3
|
+
const delivered = prepared.acceptance.objectiveAtSubmit;
|
|
4
4
|
return {
|
|
5
5
|
jobId: prepared.jobId ?? null,
|
|
6
6
|
source,
|
|
7
|
-
objectivePreview: buildRunObjectivePreview(
|
|
7
|
+
objectivePreview: delivered === undefined ? null : buildRunObjectivePreview(delivered),
|
|
8
8
|
};
|
|
9
9
|
}
|
|
10
|
+
export function fillRunPreviewOnDelivery(acceptance, runStore, taskId) {
|
|
11
|
+
acceptance.onDelivered("run-preview", (objective) => runStore.fillObjectivePreview(taskId, buildRunObjectivePreview(objective)));
|
|
12
|
+
}
|
|
10
13
|
export function cascadeConfig(ladder, maxCostUsd) {
|
|
11
14
|
return {
|
|
12
15
|
ladder: ladder.map((model) => ({ model })),
|
package/dist/http/server.d.ts
CHANGED
|
@@ -2,7 +2,7 @@ import http from "node:http";
|
|
|
2
2
|
import type { MemoryComplianceFaces, MemoryOriginFaces, SessionMemoryStatusFace } from "../memory-operator-faces.js";
|
|
3
3
|
import type { SideQueryAccounting } from "../budget.js";
|
|
4
4
|
import type { IncomingMessage } from "node:http";
|
|
5
|
-
import { type Runner, type TaskSpec, type TaskResult, type WorkflowRunStore, type MemoryEntry, type MemoryExportBundle, type MemoryImportReport, type ConsolidationRunReceipt, type ConsolidationDriverRunRow, type SideQuerySpec, type SideQueryResult, type Brain, type EngineNotice } from "@sema-agent/core";
|
|
5
|
+
import { type Runner, type RunnerDeps, type TaskSpec, type TaskResult, type WorkflowRunStore, type MemoryEntry, type MemoryExportBundle, type MemoryImportReport, type ConsolidationRunReceipt, type ConsolidationDriverRunRow, type SideQuerySpec, type SideQueryResult, type Brain, type EngineNotice } from "@sema-agent/core";
|
|
6
6
|
import type { TaskRequestBody } from "./wire-types.js";
|
|
7
7
|
import type { ServiceConfig } from "../config-types.js";
|
|
8
8
|
import { type SessionMirrorRuling } from "../web-admin-client/facade.js";
|
|
@@ -65,7 +65,7 @@ export interface RequestAuth {
|
|
|
65
65
|
* 平铺形的直接后果 = main.ts 一个上千行的装配字面量,键与键之间没有任何「属于同一件事」的编译期表达,
|
|
66
66
|
* 键落错家/从未接线只能靠源码钉逐个盯(1.300/1.301/1.304/1.307/1.310 五起真缺陷都是这个病族)。
|
|
67
67
|
*
|
|
68
|
-
* 药:七个**窄**接口 +
|
|
68
|
+
* 药:七个**窄**接口 + 顶层必填件(今天九件)。装配点按组构造(每组一个带类型标注的中间 const ⇒ 受 TS 多余
|
|
69
69
|
* 属性检查保护),键放错组当场编译红。
|
|
70
70
|
*
|
|
71
71
|
* 兼容形(本批**不动消费点**):`ServiceDeps` = 平铺视图 ∩ 组槽。旧的平铺构造(96 个测试文件 +
|
|
@@ -73,8 +73,8 @@ export interface RequestAuth {
|
|
|
73
73
|
* 入口摊平回平铺视图,server.ts 内的 ~700 处 `deps.x` 消费点原样保留。消费点迁移是后批的事——
|
|
74
74
|
* 一步到位需要同批改 ~700 处 src + ~800 处 test 键位,与「先立形、后搬家」相比没有额外收益。
|
|
75
75
|
*/
|
|
76
|
-
/** createHttpServer
|
|
77
|
-
*
|
|
76
|
+
/** createHttpServer 的**必填九件**——引擎、部署配置、提交的身份与根会话(authorizer)、请求→TaskSpec 的映射、选路席、side-query 执行席、读口场景门、对端座的 desk、部署座的 mod 注册。
|
|
77
|
+
* 九者恒在场,故留在顶层(不进任何可选组):没有它们 server 根本起不来,包一层可选组只会把编译期
|
|
78
78
|
* 错误推迟到运行期(本仓 E-HIGH-1 病族的成因就是「可选键从未接线、编译期无声」)。 */
|
|
79
79
|
export interface ServiceCoreDeps {
|
|
80
80
|
runner: Runner;
|
|
@@ -172,6 +172,14 @@ export interface ServiceCoreDeps {
|
|
|
172
172
|
* 🔴 **必填**:没有 MCP / A2A 凭据的嵌入也给一只 `createPeerDesk()`(零 IO)—— 一个部署只有一张登记表,缺席不是「没有座」的另一种读法。
|
|
173
173
|
*/
|
|
174
174
|
peerDesk: PeerDesk;
|
|
175
|
+
/**
|
|
176
|
+
* 部署座的 mod 注册(`RunnerDeps.mods`:这个部署每只 Runner 都带的同一份;起服第五段装配口 `assembleDeploymentMods` 交回,装配点把同一个值交给 Runner 与这里)。
|
|
177
|
+
* 本层只问它一件事:这条腿上有没有 prompt 屏(`prompt-screen.ts` 的 `promptScreenDeclared`,读注册**声明**的事件,连同任务座 `TaskSpec.mods`)——
|
|
178
|
+
* 有屏 ⇒ 受理座把目标落盘(run 行预览 · 续跑体 · 会话标题 · fleet 行名)推迟到引擎原样交付之后(读法全文 `run-acceptance.ts`「交付的是哪一份」)。
|
|
179
|
+
* 🔴 **必填**:缺席若读成「没有屏」,装了屏的部署会把屏前文本落进上面四处,而且谁也看不见 —— 机密轴上没有静默的那一侧。没有 mod 的嵌入显式传 `[]`;
|
|
180
|
+
* 与交给 Runner 的必须是同一个值(两处不同 = 嵌入方的装配错,本层读不出来)。
|
|
181
|
+
*/
|
|
182
|
+
deploymentMods: NonNullable<RunnerDeps["mods"]>;
|
|
175
183
|
}
|
|
176
184
|
/** **durable 持久面**:每个键 present ⇔ 对应路由/能力位在场,absent ⇒ 501(诚实缺席),
|
|
177
185
|
* 绝不静默降级。装配点 = main.ts 的 store backend 开箱段。 */
|
|
@@ -880,7 +888,7 @@ export interface ServiceDepGroups {
|
|
|
880
888
|
deployment?: ServiceDeploymentDeps;
|
|
881
889
|
knobs?: ServiceKnobDeps;
|
|
882
890
|
}
|
|
883
|
-
/** 平铺视图 =
|
|
891
|
+
/** 平铺视图 = 必填九件 + 其余七组的全可选并集。**派生**自组接口,故与分组形永不漂。 */
|
|
884
892
|
export type FlatServiceDeps = ServiceCoreDeps & Partial<ServiceStoreDeps & ServiceCoordinatorDeps & ServiceSeamDeps & ServiceObservabilityDeps & ServiceGovernanceDeps & ServiceDeploymentDeps & ServiceKnobDeps>;
|
|
885
893
|
/** createHttpServer 的入参:两形皆可(平铺=存量,分组=推荐)。同名键两形都给时,**顶层显式键赢**
|
|
886
894
|
* (含显式 `undefined`)——一处装配点只该用一形,混用时以肉眼最近的那个为准。 */
|
package/dist/http/server.js
CHANGED
|
@@ -66,6 +66,9 @@ export function createHttpServer(rawDeps) {
|
|
|
66
66
|
if (typeof deps.authorize !== "function") {
|
|
67
67
|
throw new Error("createHttpServer: the authorize seat is required — it is the only resolver of a submission's root session; pass `createAuthorizer(config, runner.sessions)` for a single-user embedding; refusing to start rather than run submissions on a root nobody attested");
|
|
68
68
|
}
|
|
69
|
+
if (!Array.isArray(deps.deploymentMods)) {
|
|
70
|
+
throw new Error("createHttpServer: the deploymentMods seat is required — it is how the server learns whether a prompt screen runs on its legs (the same registrations the Runners carry as `mods`); pass `[]` for an embedding without mods; refusing to start rather than store objective text before the screen decides");
|
|
71
|
+
}
|
|
69
72
|
{
|
|
70
73
|
const retired = retiredServiceDepsRefusal(deps);
|
|
71
74
|
if (retired !== undefined)
|
|
@@ -3,6 +3,9 @@ import type { Logger } from "../observability/logger.js";
|
|
|
3
3
|
import type { Metrics } from "../observability/metrics.js";
|
|
4
4
|
import { buildCheckpointCtx, type CheckpointCtxSealer, type SealedCheckpointCtx } from "./checkpoint-ctx.js";
|
|
5
5
|
import { type RefusalBody } from "./refusal-body.js";
|
|
6
|
+
import type { CheckpointCtx, PreparedTaskSubmission } from "./route-ctx.js";
|
|
7
|
+
/** 这份续跑输入里体的目标是不是**不可展示**的那一份(`CheckpointCtx.promptScreened` 在场)。读续跑体目标的展示面只经这一只问;落盘的 JSON 逐位判形,不信型面。 */
|
|
8
|
+
export declare function objectiveWithheldIn(ctx: Pick<CheckpointCtx, "promptScreened">): boolean;
|
|
6
9
|
/** 写不进的那一种可答复的结局(各腿把它交回自己的出口:同步 / durable 腿直接回,活流腿编码成终帧)。 */
|
|
7
10
|
export interface SubmitCtxRefusal {
|
|
8
11
|
readonly status: 413 | 409;
|
|
@@ -23,4 +26,13 @@ export declare function persistSubmitCtx(store: {
|
|
|
23
26
|
readonly runStore: RunStore;
|
|
24
27
|
readonly taskId: string;
|
|
25
28
|
} | undefined, sessionId: string, fields: Parameters<typeof buildCheckpointCtx>[0]): Promise<SubmitCtxRefusal | undefined>;
|
|
29
|
+
/**
|
|
30
|
+
* 提交腿写续跑输入的入口(三个调用点同调这一只):体与标记按受理座提交时交出的那一份定(见文件头「体里的目标按哪一份写」),只写这一笔。
|
|
31
|
+
* 写不进的处置与答复 = {@link persistSubmitCtx}(本函数只定体、不另判)。
|
|
32
|
+
*/
|
|
33
|
+
export declare function persistSubmissionCtx(store: {
|
|
34
|
+
putCtx(sessionId: string, ctx: SealedCheckpointCtx): Promise<void>;
|
|
35
|
+
}, deps: Parameters<typeof persistSubmitCtx>[1], claim: Parameters<typeof persistSubmitCtx>[2], prepared: Pick<PreparedTaskSubmission, "body" | "auth" | "verify" | "acceptance" | "bodyFromScreenedCtx"> & {
|
|
36
|
+
readonly spec: Pick<PreparedTaskSubmission["spec"], "sessionId" | "model">;
|
|
37
|
+
}): Promise<SubmitCtxRefusal | undefined>;
|
|
26
38
|
//# sourceMappingURL=submit-ctx.d.ts.map
|