@sema-agent/server 7.99.0 → 7.101.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 +35 -1
- package/README.md +12 -1
- package/README.zh-CN.md +9 -1
- package/USAGE.md +150 -56
- package/dist/approval-ask-machine.d.ts +10 -0
- package/dist/approval-ask-machine.js +3 -0
- package/dist/approval-card.d.ts +86 -1
- package/dist/approval-card.js +42 -8
- package/dist/approval-policy-settlement.d.ts +31 -0
- package/dist/approval-policy-settlement.js +16 -0
- package/dist/approval-reconciler.d.ts +8 -1
- package/dist/approval-reconciler.js +5 -4
- package/dist/approval.d.ts +44 -20
- package/dist/approval.js +14 -6
- package/dist/boot/config-center.d.ts +16 -8
- package/dist/boot/config-center.js +114 -90
- package/dist/boot/execution-env.d.ts +1 -2
- package/dist/boot/execution-env.js +21 -3
- package/dist/boot/leader.js +12 -9
- package/dist/boot/memory-consolidation.d.ts +38 -0
- package/dist/boot/memory-consolidation.js +35 -0
- package/dist/boot/parked-revive-gate.js +1 -0
- package/dist/boot/reapers.js +1 -0
- package/dist/boot/resolve-spec.d.ts +0 -1
- package/dist/boot/resolve-spec.js +28 -10
- package/dist/boot/runner-deps.d.ts +2 -2
- package/dist/boot/runner-deps.js +9 -3
- package/dist/boot/stage-02-registry-pull.js +9 -0
- package/dist/boot/stage-05-execution-env.d.ts +1 -1
- package/dist/boot/stage-06-runners.d.ts +2 -2
- package/dist/boot/stage-06-runners.js +3 -3
- package/dist/boot/stage-07-capability-layer.d.ts +2 -3
- package/dist/boot/stage-07-capability-layer.js +6 -6
- package/dist/boot/stage-08-reapers.d.ts +3 -4
- package/dist/boot/stage-08-reapers.js +2 -2
- package/dist/boot/stage-09-leader.d.ts +2 -3
- package/dist/boot/stage-10-http-server.d.ts +2 -3
- package/dist/boot/stage-10-http-server.js +2 -2
- package/dist/boot/stores.js +4 -0
- package/dist/capabilities/center-plugins.d.ts +14 -2
- package/dist/capabilities/center-plugins.js +13 -5
- package/dist/capabilities/hands-lane.js +2 -1
- package/dist/capabilities/scenarios.js +18 -5
- package/dist/capabilities/tool-defer.d.ts +2 -2
- package/dist/config-catalog.d.ts +2 -2
- package/dist/config-catalog.js +16 -15
- package/dist/config-center/apply-effective.d.ts +59 -39
- package/dist/config-center/apply-effective.js +231 -120
- package/dist/config-center/apply-ledger.d.ts +45 -16
- package/dist/config-center/apply-ledger.js +28 -18
- package/dist/config-center/facade.d.ts +12 -6
- package/dist/config-center/facade.js +2 -2
- package/dist/config-center/hot-keys-registry.d.ts +11 -4
- package/dist/config-center/hot-keys-registry.js +11 -7
- package/dist/config-center/http-client.d.ts +4 -1
- package/dist/config-center/http-client.js +15 -10
- package/dist/config-center/read-warnings.d.ts +115 -6
- package/dist/config-center/read-warnings.js +115 -5
- package/dist/config-center/restart-signal.d.ts +21 -14
- package/dist/config-center/restart-signal.js +16 -22
- package/dist/config-center/types.d.ts +9 -3
- package/dist/config-invariants.d.ts +2 -2
- package/dist/config-invariants.js +15 -0
- package/dist/config-provider.d.ts +4 -0
- package/dist/config-provider.js +64 -9
- package/dist/config-types.d.ts +57 -13
- package/dist/config.js +87 -22
- package/dist/cross-session-settings.js +1 -1
- package/dist/deployment-governance.d.ts +45 -12
- package/dist/deployment-governance.js +37 -9
- package/dist/env-name-allowlist-knobs.d.ts +37 -0
- package/dist/env-name-allowlist-knobs.js +24 -0
- package/dist/fleet-client.d.ts +2 -1
- package/dist/hooks/hook-llm.js +13 -4
- package/dist/host-lsp-manager.d.ts +41 -0
- package/dist/host-lsp-manager.js +15 -0
- package/dist/http/active-run-conflict.d.ts +2 -12
- package/dist/http/active-run-conflict.js +1 -6
- package/dist/http/admission.js +30 -7
- package/dist/http/memory-store-refusal-reply.d.ts +24 -0
- package/dist/http/memory-store-refusal-reply.js +10 -0
- package/dist/http/resume-legs.d.ts +1 -1
- package/dist/http/resume-legs.js +14 -10
- package/dist/http/route-ctx.d.ts +2 -2
- package/dist/http/routes/approvals-assistant.d.ts +1 -1
- package/dist/http/routes/approvals-assistant.js +3 -2
- package/dist/http/routes/capabilities.js +3 -3
- package/dist/http/routes/memory-bundle.js +3 -0
- package/dist/http/routes/memory-compliance.js +3 -0
- package/dist/http/routes/memory-origin.js +3 -0
- package/dist/http/routes/sessions.js +7 -0
- package/dist/http/routes/side-query.js +10 -4
- package/dist/http/routes/tasks.js +7 -6
- package/dist/http/server.d.ts +6 -5
- package/dist/http/wire-types.d.ts +6 -3
- package/dist/instruction-source-notice.d.ts +97 -0
- package/dist/instruction-source-notice.js +78 -0
- package/dist/leader/wire.d.ts +20 -12
- package/dist/leader/wire.js +7 -6
- package/dist/memory-layer-legacy-lock.d.ts +14 -0
- package/dist/memory-layer-legacy-lock.js +74 -0
- package/dist/memory-store-refusal.d.ts +37 -0
- package/dist/memory-store-refusal.js +14 -0
- package/dist/model-entry-refusal.d.ts +130 -0
- package/dist/model-entry-refusal.js +157 -0
- package/dist/model-provider.d.ts +9 -3
- package/dist/model-route-endpoint.d.ts +1 -1
- package/dist/model-select.d.ts +49 -4
- package/dist/model-select.js +48 -17
- package/dist/observability/corrupt-read-seat.d.ts +21 -4
- package/dist/observability/corrupt-read-seat.js +31 -0
- package/dist/observability/fail-open.d.ts +16 -4
- package/dist/observability/fail-open.js +16 -4
- package/dist/observability/metrics.js +1 -0
- package/dist/observability/run-terminal.js +1 -0
- package/dist/observability/secret-env-scrub.d.ts +27 -3
- package/dist/observability/secret-env-scrub.js +22 -6
- package/dist/orchestration/workflow-completion-inbox.d.ts +31 -23
- package/dist/orchestration/workflow-completion-inbox.js +8 -3
- package/dist/plugins/approval-ask-store-file.d.ts +20 -2
- package/dist/plugins/approval-ask-store-file.js +21 -3
- package/dist/plugins/approval-ask-store-memory.d.ts +2 -0
- package/dist/plugins/approval-ask-store-memory.js +39 -13
- package/dist/plugins/approval-ask-store-sql.d.ts +24 -5
- package/dist/plugins/approval-ask-store-sql.js +27 -3
- package/dist/plugins/caching-session-store.d.ts +6 -0
- package/dist/plugins/caching-session-store.js +6 -0
- package/dist/plugins/checkpoint-store-sql.d.ts +9 -3
- package/dist/plugins/checkpoint-store-sql.js +19 -2
- package/dist/plugins/local-checkpoint-store.js +2 -0
- package/dist/plugins/local-session-store.d.ts +20 -25
- package/dist/plugins/local-session-store.js +111 -64
- package/dist/plugins/mailbox-store-sql.d.ts +7 -5
- package/dist/plugins/mailbox-store-sql.js +6 -4
- package/dist/plugins/permission-rule-store-file.js +3 -2
- package/dist/plugins/pg-session-storage.d.ts +7 -0
- package/dist/plugins/pg-session-storage.js +19 -0
- package/dist/plugins/remote-env-host.d.ts +3 -1
- package/dist/plugins/remote-env-host.js +3 -6
- package/dist/plugins/sql-json-column.d.ts +16 -3
- package/dist/plugins/sql-json-column.js +15 -4
- package/dist/plugins/tidb-pool.js +5 -0
- package/dist/plugins/tidb-session-store.d.ts +13 -0
- package/dist/plugins/tidb-session-store.js +14 -0
- package/dist/plugins/web-search.d.ts +44 -23
- package/dist/plugins/web-search.js +161 -50
- package/dist/project-memory.d.ts +10 -0
- package/dist/project-memory.js +28 -14
- package/dist/run-local.d.ts +17 -15
- package/dist/run-local.js +119 -18
- package/dist/runs.js +6 -5
- package/dist/runtime-governance.d.ts +50 -3
- package/dist/runtime-governance.js +5 -0
- package/dist/sealed-key.d.ts +5 -2
- package/dist/server-secret-env.d.ts +26 -2
- package/dist/server-secret-env.js +9 -0
- package/dist/task-settings.d.ts +1 -1
- package/dist/tool-approval.d.ts +150 -28
- package/dist/tool-approval.js +150 -54
- package/dist/trace/core-keyset-guard.d.ts +30 -8
- package/dist/trace/engine-notice-wire.d.ts +27 -1
- package/dist/trace/engine-notice-wire.js +8 -0
- package/dist/trace/ledger-sink.js +2 -2
- package/dist/trace/project.d.ts +13 -0
- package/dist/trace/project.js +22 -5
- package/dist/trace/projection-drop.d.ts +2 -0
- package/dist/trace/projection-drop.js +6 -0
- package/dist/trace/sema-provenance.d.ts +4 -1
- package/dist/trace/sema-provenance.js +1 -1
- package/dist/trace/task-notification-facets.d.ts +65 -0
- package/dist/trace/task-notification-facets.js +31 -0
- package/dist/trace/wire-projection-faces.d.ts +3 -3
- package/dist/trace/wire-projection-faces.js +3 -3
- package/package.json +3 -3
package/dist/tool-approval.js
CHANGED
|
@@ -7,10 +7,12 @@ import { hasBidiControls } from "./text-bidi.js";
|
|
|
7
7
|
import { approvalPayloadFingerprint } from "./plugins/approval-payload-fingerprint.js";
|
|
8
8
|
import { createLogger } from "./observability/logger.js";
|
|
9
9
|
import { recordFailOpen } from "./observability/fail-open.js";
|
|
10
|
-
import { deriveAskId, deriveBatchId, MAX_DECISION_NOTE_CHARS } from "./approval-ask-machine.js";
|
|
11
|
-
import { ApprovalCardEnvelopeSchema, MAX_RULE_OFFERS, buildApprovalCard, buildApprovalCardEnvelope, buildApprovalRequestFrame, buildRevokeFrame, readDenialLimitFallback, readProbeCause, readReadRootCandidate, readRuleEvidence, readRuleOffersAbsence, RuleOfferRawSchema, backfillLegacyBatchMemberKind, screenUncoveredDetailSeat, } from "./approval-card.js";
|
|
12
|
-
import { projectAskTerminalClaimTruth } from "./plugins/approval-ask-store-sql.js";
|
|
10
|
+
import { deriveAskId, deriveAskScopedBatchId, deriveBatchId, MAX_DECISION_NOTE_CHARS } from "./approval-ask-machine.js";
|
|
11
|
+
import { ApprovalCardEnvelopeSchema, MAX_RULE_OFFERS, buildApprovalCard, buildApprovalCardEnvelope, buildApprovalRequestFrame, buildRevokeFrame, readDenialLimitFallback, readProbeCause, readReadRootCandidate, readRuleEvidence, readRuleOffersAbsence, readRuleOffersAbsenceSeat, readParkRowTrueSeat, RuleOfferRawSchema, backfillLegacyBatchMemberKind, screenUncoveredDetailSeat, } from "./approval-card.js";
|
|
12
|
+
import { POLICY_REFUSAL_DECISION, projectAskTerminalClaimTruth } from "./plugins/approval-ask-store-sql.js";
|
|
13
|
+
import { settleByPolicy } from "./approval-policy-settlement.js";
|
|
13
14
|
import { governanceAskMarksFor, runWithGovernanceAskScope } from "./governance-ask-marks.js";
|
|
15
|
+
import { governanceOriginOf } from "./runtime-governance.js";
|
|
14
16
|
const defaultLogger = createLogger();
|
|
15
17
|
export const APPROVAL_GATE_KINDS = ["human", "irreversible_ask"];
|
|
16
18
|
export function isApprovalGateKind(k) {
|
|
@@ -82,6 +84,24 @@ function sessionAllowKey(owner, sessionId, category) {
|
|
|
82
84
|
export function standingAnswerMayRetire(facts) {
|
|
83
85
|
return !facts.governanceForced && !facts.requiresRealApproval && !facts.mandated;
|
|
84
86
|
}
|
|
87
|
+
export function parkRowStandingAnswerFacts(pending, gate, governance) {
|
|
88
|
+
const riskDescriptor = "riskDescriptor" in gate ? gate.riskDescriptor : undefined;
|
|
89
|
+
return {
|
|
90
|
+
governanceForced: governanceOriginOf({ riskDescriptor }, governance) === true,
|
|
91
|
+
requiresRealApproval: readParkRowTrueSeat(pending, "requiresRealApproval"),
|
|
92
|
+
mandated: readParkRowTrueSeat(pending, "mandated") || mandatedFromSeat(readRuleOffersAbsenceSeat(pending)),
|
|
93
|
+
};
|
|
94
|
+
}
|
|
95
|
+
function mandatedFromSeat(seat) {
|
|
96
|
+
switch (seat.state) {
|
|
97
|
+
case "word":
|
|
98
|
+
return seat.word === "mandated";
|
|
99
|
+
case "unreadable":
|
|
100
|
+
return true;
|
|
101
|
+
case "absent":
|
|
102
|
+
return false;
|
|
103
|
+
}
|
|
104
|
+
}
|
|
85
105
|
export const PERSIST_RULE_TEXT_ERROR = `persistRule.rule must be a non-empty string of at most ${MAX_RULE_TEXT_CHARS} characters`;
|
|
86
106
|
export const PERSIST_RULE_EDITED_FLAG_ERROR = "persistRule.edited must be a boolean when present";
|
|
87
107
|
export const PERSIST_RULE_BATCH_INDEX_ERROR = "persistRule.batchOfferIndex must be a non-negative integer when present";
|
|
@@ -152,6 +172,10 @@ export function parseToolApprovalResponse(body) {
|
|
|
152
172
|
}
|
|
153
173
|
return { ok: false, error: 'decision must be one of "allow" | "allow_session" | "deny"' };
|
|
154
174
|
}
|
|
175
|
+
function unattendedRefusalReason(arm) {
|
|
176
|
+
return ("UNATTENDED_APPROVAL_POLICY=deny: this deployment declares that no one attends its approvals, so an approval " +
|
|
177
|
+
`request no one can answer is refused here instead of being parked for a person (arm: ${arm}).`);
|
|
178
|
+
}
|
|
155
179
|
function isChildAsk(req) {
|
|
156
180
|
return req.fromSubagent === true;
|
|
157
181
|
}
|
|
@@ -321,11 +345,26 @@ export class ToolApprovalCoordinator {
|
|
|
321
345
|
this.askAudit = opts?.askAudit;
|
|
322
346
|
}
|
|
323
347
|
unattendedOutcome(site) {
|
|
324
|
-
|
|
348
|
+
let outcome;
|
|
349
|
+
let outcomeWord;
|
|
350
|
+
switch (this.unattendedPolicy) {
|
|
351
|
+
case "park":
|
|
352
|
+
outcome = "unavailable";
|
|
353
|
+
outcomeWord = "unavailable";
|
|
354
|
+
break;
|
|
355
|
+
case "deny":
|
|
356
|
+
outcome = { allow: false, settledBy: POLICY_REFUSAL_DECISION.settledBy, reason: unattendedRefusalReason(site.arm) };
|
|
357
|
+
outcomeWord = "deny";
|
|
358
|
+
break;
|
|
359
|
+
default: {
|
|
360
|
+
const unreachable = this.unattendedPolicy;
|
|
361
|
+
throw new Error(`unattendedOutcome: unknown UNATTENDED_APPROVAL_POLICY word ${String(unreachable)}`);
|
|
362
|
+
}
|
|
363
|
+
}
|
|
325
364
|
defaultLogger.warn("approver_unavailable", {
|
|
326
365
|
arm: site.arm,
|
|
327
366
|
policy: this.unattendedPolicy,
|
|
328
|
-
outcome:
|
|
367
|
+
outcome: outcomeWord,
|
|
329
368
|
owner: site.owner ?? null,
|
|
330
369
|
taskId: site.taskId ?? null,
|
|
331
370
|
toolName: site.toolName ?? null,
|
|
@@ -336,6 +375,9 @@ export class ToolApprovalCoordinator {
|
|
|
336
375
|
get unattendedRoutesToPark() {
|
|
337
376
|
return this.unattendedPolicy !== "deny";
|
|
338
377
|
}
|
|
378
|
+
batchIdFor(askId, sourceTaskId, runId, legKey) {
|
|
379
|
+
return this.unattendedRoutesToPark ? deriveBatchId(sourceTaskId, runId, legKey) : deriveAskScopedBatchId(askId);
|
|
380
|
+
}
|
|
339
381
|
unattendedAskOutcome(site) {
|
|
340
382
|
return this.unattendedOutcome({
|
|
341
383
|
arm: "window_zero",
|
|
@@ -344,6 +386,32 @@ export class ToolApprovalCoordinator {
|
|
|
344
386
|
...(site.toolName !== undefined ? { toolName: site.toolName } : {}),
|
|
345
387
|
});
|
|
346
388
|
}
|
|
389
|
+
async landUnattendedOutcome(outcome, row) {
|
|
390
|
+
const store = this.askStore;
|
|
391
|
+
if (outcome === "unavailable" || !store)
|
|
392
|
+
return outcome;
|
|
393
|
+
const dispatch = (res, where) => {
|
|
394
|
+
if (res.claimed) {
|
|
395
|
+
this.settleSameAskIdParkRoute(row.askId);
|
|
396
|
+
return undefined;
|
|
397
|
+
}
|
|
398
|
+
const read = this.classifyClaimLoss(row.askId, res.current, where);
|
|
399
|
+
this.dispatchClaimTruth(row.askId, read);
|
|
400
|
+
return read;
|
|
401
|
+
};
|
|
402
|
+
let res;
|
|
403
|
+
try {
|
|
404
|
+
res = await this.withStoreDeadline(settleByPolicy(store, row, this.unattendedPolicy), "claimTerminal(unattended-fallback)", DURABLE_CALL_TIMEOUT_MS, (late) => {
|
|
405
|
+
dispatch(late, "late:unattended-fallback");
|
|
406
|
+
});
|
|
407
|
+
}
|
|
408
|
+
catch (err) {
|
|
409
|
+
this.noteStoreError(err, "claimTerminal(unattended-fallback)");
|
|
410
|
+
return outcome;
|
|
411
|
+
}
|
|
412
|
+
const read = dispatch(res, "claim:unattended-fallback");
|
|
413
|
+
return read?.kind === "decided" ? read.outcome : outcome;
|
|
414
|
+
}
|
|
347
415
|
admit(taskId, owner) {
|
|
348
416
|
if (!this.askStore)
|
|
349
417
|
return () => undefined;
|
|
@@ -657,6 +725,23 @@ export class ToolApprovalCoordinator {
|
|
|
657
725
|
for (const entry of [...entries])
|
|
658
726
|
entry.settleParkRoute();
|
|
659
727
|
}
|
|
728
|
+
dispatchClaimTruth(askId, read) {
|
|
729
|
+
switch (read.kind) {
|
|
730
|
+
case "decided":
|
|
731
|
+
this.notifyExternalDecision(askId, read.outcome);
|
|
732
|
+
return;
|
|
733
|
+
case "parked":
|
|
734
|
+
this.settleSameAskIdParkRoute(askId);
|
|
735
|
+
return;
|
|
736
|
+
case "absent":
|
|
737
|
+
case "edit-in-flight":
|
|
738
|
+
return;
|
|
739
|
+
default: {
|
|
740
|
+
const unreachable = read;
|
|
741
|
+
throw new Error(`dispatchClaimTruth: unknown recovery read ${String(unreachable)}`);
|
|
742
|
+
}
|
|
743
|
+
}
|
|
744
|
+
}
|
|
660
745
|
recordParkTombstone(approvalId, tomb) {
|
|
661
746
|
const existing = this.parkTombstones.get(approvalId);
|
|
662
747
|
if (existing !== undefined) {
|
|
@@ -901,23 +986,38 @@ export class ToolApprovalCoordinator {
|
|
|
901
986
|
let wireApprovalId = id;
|
|
902
987
|
let cardForFrame = card;
|
|
903
988
|
let persistedExpiresAtMs = expiresAtMs;
|
|
904
|
-
let
|
|
905
|
-
let
|
|
989
|
+
let lateEnsuredRow;
|
|
990
|
+
let lateTerminalRow;
|
|
991
|
+
let abandonedAs;
|
|
906
992
|
const attemptCreatedAtMs = Date.now();
|
|
907
|
-
const
|
|
993
|
+
const finishAbandonedRow = (orphan) => {
|
|
908
994
|
const store = this.askStore;
|
|
909
|
-
if (!store)
|
|
910
|
-
return;
|
|
911
|
-
void
|
|
912
|
-
|
|
913
|
-
|
|
995
|
+
if (!store || abandonedAs === undefined)
|
|
996
|
+
return undefined;
|
|
997
|
+
if (abandonedAs === "void") {
|
|
998
|
+
void store
|
|
999
|
+
.transitionAsk(orphan.askId, "STREAM_PENDING", "VOID", { updatedAtMs: Date.now() })
|
|
1000
|
+
.catch((err) => this.noteStoreError(err, "transitionAsk(abandon-late-ensure)"));
|
|
1001
|
+
return undefined;
|
|
1002
|
+
}
|
|
1003
|
+
return this.landUnattendedOutcome(abandonedAs, orphan);
|
|
1004
|
+
};
|
|
1005
|
+
const abandonRow = (handed) => {
|
|
1006
|
+
abandonedAs = handed === undefined || handed === "unavailable" ? "void" : handed;
|
|
1007
|
+
return lateEnsuredRow !== undefined ? finishAbandonedRow(lateEnsuredRow) : undefined;
|
|
1008
|
+
};
|
|
1009
|
+
const replayTerminalRow = (row) => {
|
|
1010
|
+
const replayed = replayTerminalAskRow(row);
|
|
1011
|
+
return replayed === "unavailable"
|
|
1012
|
+
? this.unattendedOutcome({ arm: "replayed_parked", taskId: origin.taskId, ...(origin.owner !== null ? { owner: origin.owner } : {}), toolName: req.toolName, reachability })
|
|
1013
|
+
: replayed;
|
|
914
1014
|
};
|
|
915
1015
|
if (this.askStore && card) {
|
|
916
1016
|
const sourceTaskId = req.sourceTaskId ?? origin.taskId;
|
|
917
1017
|
const runId = origin.taskId;
|
|
918
1018
|
const legKey = origin.legKey;
|
|
919
1019
|
askId = deriveAskId(sourceTaskId, runId, req.toolCallId, legKey, req.delegation?.parentToolCallId);
|
|
920
|
-
batchId =
|
|
1020
|
+
batchId = this.batchIdFor(askId, sourceTaskId, runId, legKey);
|
|
921
1021
|
try {
|
|
922
1022
|
const existingOrCreated = await this.withStoreDeadline(this.askStore.ensureAsk({
|
|
923
1023
|
askId,
|
|
@@ -936,16 +1036,19 @@ export class ToolApprovalCoordinator {
|
|
|
936
1036
|
expiresAtMs,
|
|
937
1037
|
createdAtMs: attemptCreatedAtMs,
|
|
938
1038
|
}), "ensureAsk", DURABLE_CALL_TIMEOUT_MS, (late) => {
|
|
939
|
-
|
|
940
|
-
|
|
941
|
-
|
|
1039
|
+
if (late.row.state !== "STREAM_PENDING") {
|
|
1040
|
+
lateTerminalRow = late.row;
|
|
1041
|
+
this.dispatchClaimTruth(late.row.askId, this.classifyClaimLoss(late.row.askId, projectAskTerminalClaimTruth(late.row), "late:ensureAsk"));
|
|
1042
|
+
return;
|
|
1043
|
+
}
|
|
1044
|
+
lateEnsuredRow = late.inserted ? { askId: late.row.askId, batchId: late.row.batchId } : undefined;
|
|
1045
|
+
if (lateEnsuredRow !== undefined)
|
|
1046
|
+
void finishAbandonedRow(lateEnsuredRow);
|
|
942
1047
|
});
|
|
1048
|
+
batchId = existingOrCreated.row.batchId;
|
|
943
1049
|
if (existingOrCreated.row.state !== "STREAM_PENDING") {
|
|
944
1050
|
releaseAdmission();
|
|
945
|
-
|
|
946
|
-
return replayed === "unavailable"
|
|
947
|
-
? this.unattendedOutcome({ arm: "replayed_parked", taskId: origin.taskId, ...(origin.owner !== null ? { owner: origin.owner } : {}), toolName: req.toolName, reachability })
|
|
948
|
-
: replayed;
|
|
1051
|
+
return replayTerminalRow(existingOrCreated.row);
|
|
949
1052
|
}
|
|
950
1053
|
const persistedEnvelope = ApprovalCardEnvelopeSchema.safeParse(existingOrCreated.row.cardJson);
|
|
951
1054
|
const maxMintableWindowMs = Math.max(effectiveWindowMs, this.unreachedTtlMs);
|
|
@@ -954,7 +1057,8 @@ export class ToolApprovalCoordinator {
|
|
|
954
1057
|
this.noteStoreError(new Error(`persisted approval row is unusable (envelopeOk=${persistedEnvelope.success}, deadlineOk=${sanePersistedDeadline}, ` +
|
|
955
1058
|
`origin=${existingOrCreated.inserted ? "row-this-call-just-inserted" : "row-hit-idempotently"})`), "ensureAsk(persisted-row-unusable)");
|
|
956
1059
|
releaseAdmission();
|
|
957
|
-
|
|
1060
|
+
const unattended = this.unattendedOutcome({ arm: "persisted_row_unusable", taskId: origin.taskId, ...(origin.owner !== null ? { owner: origin.owner } : {}), toolName: req.toolName, reachability });
|
|
1061
|
+
return existingOrCreated.inserted ? this.landUnattendedOutcome(unattended, existingOrCreated.row) : unattended;
|
|
958
1062
|
}
|
|
959
1063
|
persistedExpiresAtMs = existingOrCreated.row.expiresAtMs;
|
|
960
1064
|
wireApprovalId = persistedEnvelope.data.approvalId;
|
|
@@ -1001,7 +1105,10 @@ export class ToolApprovalCoordinator {
|
|
|
1001
1105
|
let indeterminate = true;
|
|
1002
1106
|
for (let attempt = 0; attempt <= DURABLE_CONVERGE_BACKOFF_MS.length; attempt++) {
|
|
1003
1107
|
try {
|
|
1004
|
-
|
|
1108
|
+
const confirmedRow = await this.withStoreDeadline(this.askStore.getAsk(askId), "getAsk(ensureAsk-confirm)");
|
|
1109
|
+
confirmedRowExists = confirmedRow !== null;
|
|
1110
|
+
if (confirmedRow !== null)
|
|
1111
|
+
batchId = confirmedRow.batchId;
|
|
1005
1112
|
indeterminate = false;
|
|
1006
1113
|
break;
|
|
1007
1114
|
}
|
|
@@ -1011,23 +1118,26 @@ export class ToolApprovalCoordinator {
|
|
|
1011
1118
|
await new Promise((r) => setTimeout(r, DURABLE_CONVERGE_BACKOFF_MS[attempt]).unref?.());
|
|
1012
1119
|
}
|
|
1013
1120
|
}
|
|
1121
|
+
if (lateTerminalRow !== undefined) {
|
|
1122
|
+
releaseAdmission();
|
|
1123
|
+
return replayTerminalRow(lateTerminalRow);
|
|
1124
|
+
}
|
|
1014
1125
|
if (indeterminate) {
|
|
1015
|
-
|
|
1016
|
-
|
|
1017
|
-
voidAbandonedRow(lateEnsuredAskId);
|
|
1126
|
+
const unattended = this.unattendedOutcome({ arm: "ensure_indeterminate", taskId: origin.taskId, ...(origin.owner !== null ? { owner: origin.owner } : {}), toolName: req.toolName, reachability });
|
|
1127
|
+
const landed = abandonRow(unattended);
|
|
1018
1128
|
releaseAdmission();
|
|
1019
|
-
return
|
|
1129
|
+
return landed ?? unattended;
|
|
1020
1130
|
}
|
|
1021
1131
|
if (!confirmedRowExists) {
|
|
1022
1132
|
askId = undefined;
|
|
1023
1133
|
batchId = undefined;
|
|
1024
|
-
abandonedEnsure = true;
|
|
1025
|
-
if (lateEnsuredAskId !== undefined)
|
|
1026
|
-
voidAbandonedRow(lateEnsuredAskId);
|
|
1027
1134
|
if (reachability === "unreached") {
|
|
1135
|
+
const unattended = this.unattendedOutcome({ arm: "unreached_no_row", taskId: origin.taskId, ...(origin.owner !== null ? { owner: origin.owner } : {}), toolName: req.toolName, reachability });
|
|
1136
|
+
const landed = abandonRow(unattended);
|
|
1028
1137
|
releaseAdmission();
|
|
1029
|
-
return
|
|
1138
|
+
return landed ?? unattended;
|
|
1030
1139
|
}
|
|
1140
|
+
void abandonRow(undefined);
|
|
1031
1141
|
}
|
|
1032
1142
|
}
|
|
1033
1143
|
}
|
|
@@ -1044,7 +1154,7 @@ export class ToolApprovalCoordinator {
|
|
|
1044
1154
|
let selfEntry;
|
|
1045
1155
|
let hostSettled;
|
|
1046
1156
|
let denyReasonSettled;
|
|
1047
|
-
const shapeDeny = () => {
|
|
1157
|
+
const shapeDeny = (bare) => {
|
|
1048
1158
|
if (hostSettled !== undefined || (denyReasonSettled !== undefined && denyReasonSettled !== "")) {
|
|
1049
1159
|
return {
|
|
1050
1160
|
allow: false,
|
|
@@ -1052,18 +1162,17 @@ export class ToolApprovalCoordinator {
|
|
|
1052
1162
|
...(denyReasonSettled !== undefined && denyReasonSettled !== "" ? { reason: denyReasonSettled } : {}),
|
|
1053
1163
|
};
|
|
1054
1164
|
}
|
|
1055
|
-
return
|
|
1165
|
+
return bare;
|
|
1056
1166
|
};
|
|
1057
1167
|
const shapeOutcome = (settled) => {
|
|
1058
1168
|
if (windowRouteUnavailable) {
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
: "unavailable";
|
|
1169
|
+
const unattended = this.unattendedOutcome({ arm: "window_expired", taskId: origin.taskId, ...(origin.owner !== null ? { owner: origin.owner } : {}), toolName: req.toolName, reachability });
|
|
1170
|
+
return unattended === "unavailable" ? unattended : shapeDeny(unattended);
|
|
1062
1171
|
}
|
|
1063
1172
|
if (settled.allowed) {
|
|
1064
1173
|
return settled.updatedInput !== undefined ? { allow: true, updatedInput: settled.updatedInput } : true;
|
|
1065
1174
|
}
|
|
1066
|
-
return shapeDeny();
|
|
1175
|
+
return shapeDeny(false);
|
|
1067
1176
|
};
|
|
1068
1177
|
const settle = (allowed, outcome, updatedInput, hostSettledBy, denyReason) => {
|
|
1069
1178
|
if (done)
|
|
@@ -1104,21 +1213,7 @@ export class ToolApprovalCoordinator {
|
|
|
1104
1213
|
const broadcastClaimTruth = (read) => {
|
|
1105
1214
|
if (askId === undefined)
|
|
1106
1215
|
return;
|
|
1107
|
-
|
|
1108
|
-
case "decided":
|
|
1109
|
-
this.notifyExternalDecision(askId, read.outcome);
|
|
1110
|
-
return;
|
|
1111
|
-
case "parked":
|
|
1112
|
-
this.settleSameAskIdParkRoute(askId);
|
|
1113
|
-
return;
|
|
1114
|
-
case "absent":
|
|
1115
|
-
case "edit-in-flight":
|
|
1116
|
-
return;
|
|
1117
|
-
default: {
|
|
1118
|
-
const unreachable = read;
|
|
1119
|
-
throw new Error(`broadcastClaimTruth: unknown recovery read ${String(unreachable)}`);
|
|
1120
|
-
}
|
|
1121
|
-
}
|
|
1216
|
+
this.dispatchClaimTruth(askId, read);
|
|
1122
1217
|
};
|
|
1123
1218
|
const settleFromClaimLoss = (read) => {
|
|
1124
1219
|
switch (read.kind) {
|
|
@@ -1271,7 +1366,7 @@ export class ToolApprovalCoordinator {
|
|
|
1271
1366
|
await resolveLocalOutcome({
|
|
1272
1367
|
intent: "expire",
|
|
1273
1368
|
storeLabel: "claimTerminal(window)",
|
|
1274
|
-
claim: (timeoutMs) => boundedClaim(() => store
|
|
1369
|
+
claim: (timeoutMs) => boundedClaim(() => settleByPolicy(store, { askId: pinnedAskId, batchId: pinnedBatchId }, this.unattendedPolicy), "claimTerminal(window)", timeoutMs, (late) => {
|
|
1275
1370
|
if (!late.claimed) {
|
|
1276
1371
|
lateClaimLossSettle(late.current, "expire");
|
|
1277
1372
|
return;
|
|
@@ -1459,7 +1554,7 @@ export class ToolApprovalCoordinator {
|
|
|
1459
1554
|
await resolveLocalOutcome({
|
|
1460
1555
|
intent: "unreachable",
|
|
1461
1556
|
storeLabel: "claimTerminal(emit-failed)",
|
|
1462
|
-
claim: (timeoutMs) => boundedClaim(() => store
|
|
1557
|
+
claim: (timeoutMs) => boundedClaim(() => settleByPolicy(store, { askId: pinnedAskId, batchId: pinnedBatchId }, this.unattendedPolicy), "claimTerminal(emit-failed)", timeoutMs, (late) => {
|
|
1463
1558
|
if (!late.claimed) {
|
|
1464
1559
|
lateClaimLossSettle(late.current, "unreachable");
|
|
1465
1560
|
return;
|
|
@@ -2011,6 +2106,7 @@ export class ToolApprovalCoordinator {
|
|
|
2011
2106
|
...(e.sessionId !== undefined ? { sessionId: e.sessionId } : {}),
|
|
2012
2107
|
...(e.requiresRealApproval ? { requiresRealApproval: true } : {}),
|
|
2013
2108
|
...(e.governanceForced ? { governanceForced: true } : {}),
|
|
2109
|
+
...(e.mandated ? { mandated: true } : {}),
|
|
2014
2110
|
...(e.originTaskId !== undefined ? { fromSubagent: true, originTaskId: e.originTaskId } : {}),
|
|
2015
2111
|
...(contentKind !== undefined ? { contentKind } : {}),
|
|
2016
2112
|
frame: e.frame.approvalId === id ? e.frame : { ...e.frame, approvalId: id },
|
|
@@ -17,7 +17,7 @@
|
|
|
17
17
|
* ⑨⑩([ref],2026-08-31)把两个最大的 wire 面也纳入:TaskSpec 按「server 有无写点」记 Wired/Unwired,
|
|
18
18
|
* TaskResult 按「转发/摘除」记 Forwarded/Stripped —— 谁改 resolve-spec.ts / runs.ts 的发射点谁同步本文件。
|
|
19
19
|
*/
|
|
20
|
-
import type { TaskNotificationPayload, SemaProvenance, BackgroundChildEvent, RosterEntry, AskRequest, CheckpointSummary, TaskEvent, TraceEvent, MailboxMessage, MailboxAppendMessage, TaskSpec, TaskResult, WiringManifest, GateOutcome, GateDisposition, Settlement, PausedCause, WorkflowRun, ReadRootGrantCandidate, McpReconnectResult, McpServerStatus } from "@sema-agent/core";
|
|
20
|
+
import type { TaskNotificationPayload, SemaProvenance, BackgroundChildEvent, RosterEntry, AskRequest, CheckpointSummary, PendingAction, TaskEvent, TraceEvent, MailboxMessage, MailboxAppendMessage, TaskSpec, TaskResult, WiringManifest, GateOutcome, GateDisposition, Settlement, PausedCause, WorkflowRun, ReadRootGrantCandidate, McpReconnectResult, McpServerStatus, NodeLspManagerOptions, RunnerDeps } from "@sema-agent/core";
|
|
21
21
|
import type { ToolApprovalFrame } from "../tool-approval.js";
|
|
22
22
|
/** 编译期断言:T 必须收敛到 never(有残余键 = tsc 红)。
|
|
23
23
|
* 🔴 **导出**([ref] U1/U2):本仓「词表闭集,未处置成员=编译红」的钉法只许有**一个**形 ——
|
|
@@ -25,7 +25,7 @@ import type { ToolApprovalFrame } from "../tool-approval.js";
|
|
|
25
25
|
* `type X<T extends never> = T`(抄一份就是第二个写者,两处哪天分岔谁都发现不了)。
|
|
26
26
|
* 本文件只有类型、不产 JS,所以被 `import type` 引用不新增任何运行期边。 */
|
|
27
27
|
export type AssertAllKeysHandled<T extends never> = T;
|
|
28
|
-
type NotificationProjected = "task_id" | "task_type" | "toolUseId" | "status" | "summary" | "result" | "output_file" | "usage" | "sessionId" | "seq" | "lines" | "stoppedBy" | "source" | "exitCode" | "partial" | "diagnostics" | "recentSteps" | "editedFiles" | "resumable" | "completionId" | "error" | "errorCode" | "apiFailure" | "agentMessage" | "_sema_provenance";
|
|
28
|
+
type NotificationProjected = "task_id" | "task_type" | "toolUseId" | "status" | "summary" | "result" | "output_file" | "usage" | "sessionId" | "seq" | "lines" | "stoppedBy" | "source" | "exitCode" | "partial" | "diagnostics" | "recentSteps" | "editedFiles" | "resumable" | "completionId" | "error" | "errorCode" | "apiFailure" | "agentMessage" | "_sema_provenance" | "spawnName" | "handback" | "compaction" | "resupplied" | "attempt";
|
|
29
29
|
type NotificationExcluded = (typeof import("./wire-projection-faces.js").WIRE_PROJECTION_FACES)["task_notification"]["excluded"][number];
|
|
30
30
|
type _GuardNotification = AssertAllKeysHandled<Exclude<keyof TaskNotificationPayload, NotificationProjected | NotificationExcluded>>;
|
|
31
31
|
type _GuardNotificationReverse = AssertAllKeysHandled<Exclude<NotificationProjected | NotificationExcluded, keyof TaskNotificationPayload>>;
|
|
@@ -59,8 +59,8 @@ type _GuardMailboxReverse = AssertAllKeysHandled<Exclude<MailboxProjected, keyof
|
|
|
59
59
|
type MailboxAppendProjected = "from" | "content" | "sentAt" | "hopChain" | "peerMeta";
|
|
60
60
|
type _GuardMailboxAppend = AssertAllKeysHandled<Exclude<keyof MailboxAppendMessage, MailboxAppendProjected>>;
|
|
61
61
|
type _GuardMailboxAppendReverse = AssertAllKeysHandled<Exclude<MailboxAppendProjected, keyof MailboxAppendMessage>>;
|
|
62
|
-
type WiringSectionProjected = "schemaVersion" | "leg" | "ask" | "question" | "interaction" | "elicit" | "parkLane" | "session" | "fleet" | "permissionRules" | "modelGate" | "autoMode" | "mcp" | "tools" | "hooks" | "lsp" | "writeProtection";
|
|
63
|
-
type WiringSectionExcluded = "governance" | "configFingerprint" | "autoConsolidation" | "readDeny";
|
|
62
|
+
type WiringSectionProjected = "schemaVersion" | "leg" | "ask" | "question" | "interaction" | "elicit" | "parkLane" | "session" | "fleet" | "permissionRules" | "modelGate" | "autoMode" | "mcp" | "tools" | "hooks" | "lsp" | "writeProtection" | "teamRole";
|
|
63
|
+
type WiringSectionExcluded = "governance" | "configFingerprint" | "autoConsolidation" | "readDeny" | "peerPresence" | "fileHistory";
|
|
64
64
|
type _GuardWiringSections = AssertAllKeysHandled<Exclude<keyof WiringManifest, WiringSectionProjected | WiringSectionExcluded>>;
|
|
65
65
|
type _GuardWiringSectionsReverse = AssertAllKeysHandled<Exclude<WiringSectionProjected | WiringSectionExcluded, keyof WiringManifest>>;
|
|
66
66
|
type WiringSection<K extends keyof WiringManifest> = NonNullable<WiringManifest[K]>;
|
|
@@ -130,15 +130,23 @@ type _GuardPermissionTraceReverse = AssertAllKeysHandled<Exclude<PermissionTrace
|
|
|
130
130
|
/** `T` 非 `never` 时收敛到 `never`(空集 ⇒ 残留 `"EMPTY"` ⇒ tsc 红)。 */
|
|
131
131
|
type AssertNonEmpty<T> = [T] extends [never] ? "EMPTY" : never;
|
|
132
132
|
type _GuardPermissionTraceNonEmpty = AssertAllKeysHandled<AssertNonEmpty<PermissionTraceKind>>;
|
|
133
|
-
type SummaryProjected = "sessionId" | "scope" | "createdAt" | "gateKind" | "severity" | "spentMicroUsd" | "deadline" | "hasBidiControls" | "requiresRealApproval" | "denialLimitFallback" | "origin" | "ruleStoreUnreadable";
|
|
133
|
+
type SummaryProjected = "sessionId" | "scope" | "createdAt" | "gateKind" | "severity" | "spentMicroUsd" | "deadline" | "hasBidiControls" | "requiresRealApproval" | "denialLimitFallback" | "origin" | "ruleStoreUnreadable" | "mandated";
|
|
134
134
|
type SummaryExcluded = "token" | "toolInput" | "toolName" | "toolCallId" | "preview" | "principal" | "sourceTaskId" | "contentKind" | "restoreMode" | "checkpointId" | "previewWithheld";
|
|
135
135
|
type _GuardInboxSummary = AssertAllKeysHandled<Exclude<keyof CheckpointSummary, SummaryProjected | SummaryExcluded>>;
|
|
136
136
|
type _GuardInboxSummaryReverse = AssertAllKeysHandled<Exclude<SummaryProjected | SummaryExcluded, keyof CheckpointSummary>>;
|
|
137
|
+
type ParkArmKeys = keyof Extract<PendingAction, {
|
|
138
|
+
kind: "tool_approval";
|
|
139
|
+
}>;
|
|
140
|
+
type ParkArmQueueProjected = "toolName" | "toolCallId" | "boundInputHash" | "ruleOffers" | "hasBidiControls" | keyof import("../approval-card.js").ParkRowFacts;
|
|
141
|
+
type ParkArmQueueExcluded = "kind" | "args" | "batchToolCallIds" | "completedCallIds" | "capabilityId" | "contractId" | "shapeDigest" | "implementationRevision" | "rosterDigest" | "family" | "pathTarget" | "preview" | "previewWithheld" | "execCwd" | "denialLimitFallback" | "origin" | "ruleStoreUnreadable";
|
|
142
|
+
type _GuardParkArmQueue = AssertAllKeysHandled<Exclude<ParkArmKeys, ParkArmQueueProjected | ParkArmQueueExcluded>>;
|
|
143
|
+
type _GuardParkArmQueueReverse = AssertAllKeysHandled<Exclude<ParkArmQueueProjected | ParkArmQueueExcluded, ParkArmKeys>>;
|
|
144
|
+
type _NoDoubleBookParkArmQueue = AssertAllKeysHandled<Extract<ParkArmQueueProjected, ParkArmQueueExcluded>>;
|
|
137
145
|
type TaskSpecWired = "objective" | "principal" | "images" | "sessionId" | "requireExistingSession" | "oneShot" | "clientContext" | "resumeAt" | "resumeAtMode" | "model" | "compactionModel" | "thinking" | "systemPrompt" | "appendSystemPrompt" | "promptProvider" | "memory" | "suggestNextPrompts" | "restoreFiles" | "acceptPartialRestore" | "rewindFilesTo" | "tools" | "excludeTools" | "deferTools" | "toolMaterializeStrategy" | "promptProfile" | "toolPolicy" | "onAsk" | "onQuestion" | "hooks" | "durableApproval" | "resourceSuspend" | "resilience" | "finalVerification" | "checkpointStore" | "handsReadOnly" | "memoryPersistenceCapable" | "additionalDirectories" | "additionalReadDirectories" | "enablePlanMode" | "interactiveTools" | "enableFork" | "shellGate" | "writeFace" | "mcp" | "a2a" | "skills" | "backgroundScope" | "envFacts" | "limits" | "configOverrides" | "forwardSubagentEvents" | "retainSubagentSessions" | "retainBackgroundProcesses" | "outputSchema" | "outputRetries" | "compaction" | "attachments" | "selfOrchestration" | "getApiKeyAndHeaders" | "interactionPosture" | "agents" | "approverPosture" | "taskId" | "signal" | "preemptSignal" | "modelRole" | "enableBlockedReport" | "maxSuspends" | "autoModeRequested" | "skillListingBudgetFraction" | "skillListingMaxDescChars" | "excludeAllTools";
|
|
138
|
-
type TaskSpecUnwired = "actor" | "roles" | "lspManager" | "tracer" | "readFace" | "readDenyPatterns" | "interactiveQuestionFallback" | "alwaysLoadTools" | "restoreGatedTools" | "deferSelfResolve" | "basePolicyForResumeEdit" | "lspDiagnostics" | "streamingToolExecution" | "toolResultThresholdChars";
|
|
146
|
+
type TaskSpecUnwired = "actor" | "roles" | "lspManager" | "tracer" | "readFace" | "readDenyPatterns" | "interactiveQuestionFallback" | "alwaysLoadTools" | "restoreGatedTools" | "deferSelfResolve" | "basePolicyForResumeEdit" | "lspDiagnostics" | "streamingToolExecution" | "toolResultThresholdChars" | "peerPresence" | "fileHistory";
|
|
139
147
|
type _GuardTaskSpec = AssertAllKeysHandled<Exclude<keyof TaskSpec, TaskSpecWired | TaskSpecUnwired>>;
|
|
140
148
|
type _GuardTaskSpecReverse = AssertAllKeysHandled<Exclude<TaskSpecWired | TaskSpecUnwired, keyof TaskSpec>>;
|
|
141
|
-
type TaskResultForwarded = "taskId" | "runId" | "sessionId" | "terminal" | "model" | "effectiveReasoning" | "result" | "salvagedOutput" | "remoteEnvFailures" | "apiFailure" | "retryAfterMs" | "degraded" | "structuredOutput" | "rewindNotes" | "haltedOnUserRejection" | "haltedByUser" | "strandedHumanAnswers" | "pendingApproval" | "approvalWaitedMs" | "effectiveReadFace" | "effectiveReadDenyPatterns" | "effectiveWriteFace" | "effectiveMemoryScopes" | "stats" | "editedFiles" | "responseModel";
|
|
149
|
+
type TaskResultForwarded = "taskId" | "runId" | "sessionId" | "terminal" | "model" | "effectiveReasoning" | "result" | "salvagedOutput" | "remoteEnvFailures" | "apiFailure" | "retryAfterMs" | "degraded" | "structuredOutput" | "rewindNotes" | "haltedOnUserRejection" | "haltedByUser" | "strandedHumanAnswers" | "pendingApproval" | "approvalWaitedMs" | "effectiveReadFace" | "effectiveReadDenyPatterns" | "effectiveWriteFace" | "effectiveMemoryScopes" | "stats" | "editedFiles" | "responseModel" | "compaction";
|
|
142
150
|
type TaskResultStripped = never;
|
|
143
151
|
type _GuardTaskResult = AssertAllKeysHandled<Exclude<keyof TaskResult, TaskResultForwarded | TaskResultStripped>>;
|
|
144
152
|
type _GuardTaskResultReverse = AssertAllKeysHandled<Exclude<TaskResultForwarded | TaskResultStripped, keyof TaskResult>>;
|
|
@@ -197,6 +205,13 @@ type McpListingIncompleteKeys = keyof NonNullable<McpReconnectResult["listingInc
|
|
|
197
205
|
type McpListingIncompleteProjected = "reason" | "pages" | "budgetMs" | "error";
|
|
198
206
|
type _GuardMcpListingIncomplete = AssertAllKeysHandled<Exclude<McpListingIncompleteKeys, McpListingIncompleteProjected>>;
|
|
199
207
|
type _GuardMcpListingIncompleteReverse = AssertAllKeysHandled<Exclude<McpListingIncompleteProjected, McpListingIncompleteKeys>>;
|
|
208
|
+
type LspOptionsWired = "env" | "log";
|
|
209
|
+
type LspOptionsUnwired = "onNotice" | "servers" | "spawn" | "readText" | "resolveRoot" | "warmup" | "maxSessions" | "idleTtlMs" | "diagnostics";
|
|
210
|
+
type _GuardLspOptions = AssertAllKeysHandled<Exclude<keyof NodeLspManagerOptions, LspOptionsWired | LspOptionsUnwired>>;
|
|
211
|
+
type _GuardLspOptionsReverse = AssertAllKeysHandled<Exclude<LspOptionsWired | LspOptionsUnwired, keyof NodeLspManagerOptions>>;
|
|
212
|
+
type _NoDoubleBookLspOptions = AssertAllKeysHandled<Extract<LspOptionsWired, LspOptionsUnwired>>;
|
|
213
|
+
type RunnerDepsDroppedPendingS724 = "fileHistoryCapture";
|
|
214
|
+
type _GuardFacelessRunnerDepsReverse = AssertAllKeysHandled<Exclude<RunnerDepsDroppedPendingS724, keyof RunnerDeps>>;
|
|
200
215
|
export type CoreKeysetGuards = [
|
|
201
216
|
_GuardNotification,
|
|
202
217
|
_GuardNotificationReverse,
|
|
@@ -259,6 +274,9 @@ export type CoreKeysetGuards = [
|
|
|
259
274
|
_GuardPermissionTraceNonEmpty,
|
|
260
275
|
_GuardInboxSummary,
|
|
261
276
|
_GuardInboxSummaryReverse,
|
|
277
|
+
_GuardParkArmQueue,
|
|
278
|
+
_NoDoubleBookParkArmQueue,
|
|
279
|
+
_GuardParkArmQueueReverse,
|
|
262
280
|
_GuardTaskSpec,
|
|
263
281
|
_GuardTaskSpecReverse,
|
|
264
282
|
_GuardTaskResult,
|
|
@@ -294,7 +312,11 @@ export type CoreKeysetGuards = [
|
|
|
294
312
|
_GuardMcpListingIncomplete,
|
|
295
313
|
_GuardMcpListingIncompleteReverse,
|
|
296
314
|
_GuardWiringMcpLiveness,
|
|
297
|
-
_GuardWiringMcpLivenessReverse
|
|
315
|
+
_GuardWiringMcpLivenessReverse,
|
|
316
|
+
_GuardLspOptions,
|
|
317
|
+
_NoDoubleBookLspOptions,
|
|
318
|
+
_GuardLspOptionsReverse,
|
|
319
|
+
_GuardFacelessRunnerDepsReverse
|
|
298
320
|
];
|
|
299
321
|
export {};
|
|
300
322
|
//# sourceMappingURL=core-keyset-guard.d.ts.map
|
|
@@ -16,8 +16,34 @@
|
|
|
16
16
|
* 同文件 G1 e2e 的全码扇出夹具、以及契约文档附录 D.3 那张表(含**小节标题里的码数** —— 那道门本批
|
|
17
17
|
* 刚立,立完就在下一次加码时自己咬住了)。
|
|
18
18
|
*/
|
|
19
|
-
export declare const ENGINE_NOTICE_WIRE_CODES: readonly ["memory.session_polluted", "memory.harvest_quarantined", "memory.delegation_static_mark_waived", "memory.hold_opened", "memory.hold_released", "memory.hold_disposed", "task.turn_interrupted", "steering.parked_input_blocked", "task.user_steer_undrained", "task.user_followup_undrained", "memory.capture_opted_out", "memory.capture_optout_unpersisted", "task.halt_unconsumed", "task.late_approval", "config.durable_gate_unavailable", "peer.inbound_disposition", "peer.held_settled", "peer.idle_subscription", "classifier.denial_limit", "mcp.injection_dropped", "delegation.ask_unresolvable", "task.interrupt_unconsumed"];
|
|
19
|
+
export declare const ENGINE_NOTICE_WIRE_CODES: readonly ["memory.session_polluted", "memory.harvest_quarantined", "memory.delegation_static_mark_waived", "memory.hold_opened", "memory.hold_released", "memory.hold_disposed", "task.turn_interrupted", "steering.parked_input_blocked", "task.user_steer_undrained", "task.user_followup_undrained", "memory.capture_opted_out", "memory.capture_optout_unpersisted", "task.halt_unconsumed", "task.late_approval", "config.durable_gate_unavailable", "peer.inbound_disposition", "peer.held_settled", "peer.idle_subscription", "classifier.denial_limit", "mcp.injection_dropped", "delegation.ask_unresolvable", "task.interrupt_unconsumed", "instructions.source_changed"];
|
|
20
20
|
export type EngineNoticeWireCode = (typeof ENGINE_NOTICE_WIRE_CODES)[number];
|
|
21
|
+
/**
|
|
22
|
+
* S-690 —— **本仓自铸**的通告码与它们的受众(码 / 铸点 / 受众三者的属主都是本仓)。
|
|
23
|
+
*
|
|
24
|
+
* 为什么可以有这一族:core 的 `EngineNotice.code` 刻意是开放 `string`,顶注逐字「a host forwarding its own notices
|
|
25
|
+
* through the same sink is a supported shape」—— 部署经同一只 `onNotice` 转发体投自己的通告,白名单 / 归属 / 消毒 /
|
|
26
|
+
* 隔离四件判据一个不绕。为什么受众写在这里:core 的 `NOTICE_AUDIENCE` 只收录 core 自己铸的码,对本仓的码
|
|
27
|
+
* `noticeAudienceOf` 只会读保守默认 `"operator"` —— 那是「不认识」,不是判决。顶注的「本仓不许自造第二份受众语义」
|
|
28
|
+
* 说的是 **core 的码**;本表只收 core 码册里**没有**的码,这里是它们唯一的一份受众语义。
|
|
29
|
+
*
|
|
30
|
+
* 🔴 机器门(`test/engine-notice-wire.test.ts` 的 server 自铸码属主门):① 本表的码与 core 运行期码册 `ENGINE_NOTICE_CODES`
|
|
31
|
+
* **零交集**(core 哪天铸了同名码 ⇒ 属主变成两个,当场红:销本表的行、改走 core 的受众与工厂);② 判 `"user"` 的码必须
|
|
32
|
+
* 入白名单;③ 白名单里的码,受众一律由「本表 ∪ core 注册表」给,判出来必须是 `"user"`。
|
|
33
|
+
*/
|
|
34
|
+
export declare const SERVER_NOTICE_AUDIENCE: {
|
|
35
|
+
readonly "instructions.source_changed": "user";
|
|
36
|
+
/**
|
|
37
|
+
* O2(7.101.0 合并复审)—— boot 期探测到 ≤7.30.x 引擎留下的锁住的记忆层(唯一铸点 `src/memory-layer-legacy-lock.ts`,
|
|
38
|
+
* 调用点 = `boot/stores.ts` 的 file 记忆引擎装配段)。受众 **operator**:恢复动词是运维在数据根上执行一次 `chmod -R u+w`,
|
|
39
|
+
* 而且铸在 boot 期、没有任何会话 ⇒ 不上 wire、不进白名单,只走转发体的日志终点(`engine_notice` warn)。
|
|
40
|
+
* `detail: { layers, remedy }` —— 层名(挂载面的直接子目录名)与那一句补救;条目名 / 内容不进。
|
|
41
|
+
*/
|
|
42
|
+
readonly "memory.layer_locked_legacy": "operator";
|
|
43
|
+
};
|
|
44
|
+
export type ServerNoticeCode = keyof typeof SERVER_NOTICE_AUDIENCE;
|
|
45
|
+
/** 该码是否本仓自铸(属主判据单点:门与投递面都读这一个)。 */
|
|
46
|
+
export declare function isServerNoticeCode(code: string): code is ServerNoticeCode;
|
|
21
47
|
/** 白名单谓词(单点):路由与门都读这一个,不许第二处手抄码串。 */
|
|
22
48
|
export declare function isEngineNoticeWireCode(code: string): code is EngineNoticeWireCode;
|
|
23
49
|
/**
|
|
@@ -23,7 +23,15 @@ export const ENGINE_NOTICE_WIRE_CODES = [
|
|
|
23
23
|
"mcp.injection_dropped",
|
|
24
24
|
"delegation.ask_unresolvable",
|
|
25
25
|
"task.interrupt_unconsumed",
|
|
26
|
+
"instructions.source_changed",
|
|
26
27
|
];
|
|
28
|
+
export const SERVER_NOTICE_AUDIENCE = {
|
|
29
|
+
"instructions.source_changed": "user",
|
|
30
|
+
"memory.layer_locked_legacy": "operator",
|
|
31
|
+
};
|
|
32
|
+
export function isServerNoticeCode(code) {
|
|
33
|
+
return Object.hasOwn(SERVER_NOTICE_AUDIENCE, code);
|
|
34
|
+
}
|
|
27
35
|
const WIRE_CODES = new Set(ENGINE_NOTICE_WIRE_CODES);
|
|
28
36
|
export function isEngineNoticeWireCode(code) {
|
|
29
37
|
return WIRE_CODES.has(code);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {} from "@sema-agent/core";
|
|
2
2
|
import { outwardPlane } from "../terminal.js";
|
|
3
3
|
import { modelTextEventData, toolStartEventData, toolEndEventData, taskProgressEventData, taskNotificationEventData, compactedEventData, diagnosticsEventData, brainStatusEventData, steeringInjectedEventData, compactionOutcomeEventData, workspaceChangedEventData, wiringManifestEventData, toolRosterDeltaEventData, toolDisclosureEventData, humanInputEventData, turnEndEventData, contextUsageEventData } from "./project.js";
|
|
4
|
-
import { NotifiedKeys,
|
|
4
|
+
import { NotifiedKeys, taskNotificationStreamKeyOf } from "../orchestration/workflow-completion-inbox.js";
|
|
5
5
|
import { isParkLedgerEventType } from "./ledger-events.js";
|
|
6
6
|
import { isModelSegmentBoundary, reasoningDeltaBytes, reasoningSegmentEventId } from "./model-segment.js";
|
|
7
7
|
export function createSerialLedgerAppend(appendEvent, startSeq) {
|
|
@@ -119,7 +119,7 @@ export function createLedgerSink(opts) {
|
|
|
119
119
|
break;
|
|
120
120
|
case "task_notification": {
|
|
121
121
|
const tn = ev.notification;
|
|
122
|
-
const tnKey =
|
|
122
|
+
const tnKey = taskNotificationStreamKeyOf(tn);
|
|
123
123
|
const tnPrior = tnKey !== undefined ? keys.get(tnKey) : undefined;
|
|
124
124
|
if (tnPrior === undefined || !(await tnPrior)) {
|
|
125
125
|
const write = append("task_notification", taskNotificationEventData(ev));
|
package/dist/trace/project.d.ts
CHANGED
|
@@ -422,6 +422,17 @@ export declare function taskNotificationEventData(ev: {
|
|
|
422
422
|
* `kind` 过闭集(`trace/sema-provenance.ts` 单点,park 半场同一判据);`agentType` 本 mount 恒缺席(工具无
|
|
423
423
|
* agent-type 席),在场即透传(fleet spawn 帧按 taskId 可 join 时上游给)。 */
|
|
424
424
|
_sema_provenance?: SemaProvenanceInput;
|
|
425
|
+
/** core 7.30.0 [ref] S1 / #1034 / #1036(S-616):委派终态帧三枚 facet + 重供两键 —— 判据单点在
|
|
426
|
+
* `trace/task-notification-facets.ts`(与 park 半场同一只;入参按 `unknown` 收、判过形才成 typed)。 */
|
|
427
|
+
spawnName?: string;
|
|
428
|
+
handback?: string;
|
|
429
|
+
compaction?: {
|
|
430
|
+
passes: number;
|
|
431
|
+
breakerOpen: boolean;
|
|
432
|
+
kind?: string;
|
|
433
|
+
};
|
|
434
|
+
resupplied?: boolean;
|
|
435
|
+
attempt?: number;
|
|
425
436
|
};
|
|
426
437
|
eventId?: string;
|
|
427
438
|
parentToolCallId?: string;
|
|
@@ -840,6 +851,8 @@ export declare function compactedEventData(ev: {
|
|
|
840
851
|
* 的数、post 恒是结构和 + 固定提示词开销,两者的差混坐标,实测在普通 run 上是负数)。本仓的处置因此
|
|
841
852
|
* 是**三条都逐字透传、一条都不合成**:谁要画上下文表就读 `freedTokens`,读不到就渲染 unknown。 */
|
|
842
853
|
freedTokens?: number;
|
|
854
|
+
/** core 7.30.0 #1036(S-616):这一次压缩**摘要掉**了几条之前已交给模型的跨会话消息(在场 iff ≥1)。 */
|
|
855
|
+
summarizedCrossSessionMessages?: number;
|
|
843
856
|
durationMs?: number;
|
|
844
857
|
phaseDurations?: {
|
|
845
858
|
prepareMs?: number;
|
package/dist/trace/project.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { redactErrorMessage, redactModelText } from "../observability/run-terminal.js";
|
|
2
|
-
import { MCP_DELIVERY_VERDICTS, MCP_LIVENESS_STATES, screenGateOutcome, ToolRoster, ToolRosterDelta, WRITE_PROTECTION_TARGET_VIEWS } from "@sema-agent/core";
|
|
2
|
+
import { MCP_DELIVERY_VERDICTS, MCP_LIVENESS_STATES, screenGateOutcome, TEAM_ROLES, ToolRoster, ToolRosterDelta, WRITE_PROTECTION_TARGET_VIEWS } from "@sema-agent/core";
|
|
3
3
|
import { Value } from "typebox/value";
|
|
4
4
|
import { recordFailOpen } from "../observability/fail-open.js";
|
|
5
5
|
import { redactSecrets, redactDeep } from "./redact.js";
|
|
6
6
|
import { injectionTierOrAbsent } from "./injection-tier.js";
|
|
7
7
|
import { semaProvenanceOrAbsent } from "./sema-provenance.js";
|
|
8
|
+
import { resupplyFields, terminalFrameFacetFields } from "./task-notification-facets.js";
|
|
9
|
+
import { dropProjectedFace } from "./projection-drop.js";
|
|
8
10
|
export async function appendModelUsageDelta(append, modelUsage, taskId) {
|
|
9
11
|
const delta = modelUsage?.drain(taskId);
|
|
10
12
|
if (delta) {
|
|
@@ -229,10 +231,6 @@ export function toolEndEventData(ev) {
|
|
|
229
231
|
...identityFields(ev),
|
|
230
232
|
};
|
|
231
233
|
}
|
|
232
|
-
const dropProjectedFace = (what) => {
|
|
233
|
-
recordFailOpen("server.trace.projection-input-malformed", what);
|
|
234
|
-
return undefined;
|
|
235
|
-
};
|
|
236
234
|
export function toolProgressEventData(ev) {
|
|
237
235
|
const id = typeof ev.toolCallId === "string" && ev.toolCallId !== "" ? ev.toolCallId : undefined;
|
|
238
236
|
const name = typeof ev.toolName === "string" && ev.toolName !== "" ? ev.toolName : undefined;
|
|
@@ -326,6 +324,8 @@ export function taskNotificationEventData(ev) {
|
|
|
326
324
|
const p = semaProvenanceOrAbsent(n._sema_provenance);
|
|
327
325
|
return p !== undefined ? { _sema_provenance: p } : {};
|
|
328
326
|
})(),
|
|
327
|
+
...terminalFrameFacetFields(n),
|
|
328
|
+
...resupplyFields(n),
|
|
329
329
|
...(() => {
|
|
330
330
|
const tier = injectionTierOrAbsent(ev.priority);
|
|
331
331
|
return tier !== undefined ? { priority: tier } : {};
|
|
@@ -535,9 +535,17 @@ export function wiringManifestEventData(ev) {
|
|
|
535
535
|
return { targetView };
|
|
536
536
|
})();
|
|
537
537
|
const mcp = projectWiringManifestMcpRows(m.mcp);
|
|
538
|
+
const teamRole = (() => {
|
|
539
|
+
if (m.teamRole === undefined)
|
|
540
|
+
return undefined;
|
|
541
|
+
if (!TEAM_ROLES.includes(m.teamRole))
|
|
542
|
+
return dropProjectedFace("wiring_manifest.teamRole is outside core TEAM_ROLES");
|
|
543
|
+
return m.teamRole;
|
|
544
|
+
})();
|
|
538
545
|
return {
|
|
539
546
|
...(num(m.schemaVersion) !== undefined ? { schemaVersion: m.schemaVersion } : {}),
|
|
540
547
|
...(str(legIn.kind) !== undefined ? { leg: { kind: legIn.kind } } : {}),
|
|
548
|
+
...(teamRole !== undefined ? { teamRole } : {}),
|
|
541
549
|
...(ask !== undefined ? { ask } : {}),
|
|
542
550
|
...(question !== undefined ? { question } : {}),
|
|
543
551
|
...(str(interactionIn.posture) !== undefined ? { interaction: { posture: interactionIn.posture } } : {}),
|
|
@@ -676,6 +684,15 @@ export function compactedEventData(ev) {
|
|
|
676
684
|
...(num(ev.tokensAfter) !== undefined ? { tokensAfter: num(ev.tokensAfter) } : {}),
|
|
677
685
|
...(num(ev.triggerTokensBefore) !== undefined ? { triggerTokensBefore: num(ev.triggerTokensBefore) } : {}),
|
|
678
686
|
...(num(ev.freedTokens) !== undefined ? { freedTokens: num(ev.freedTokens) } : {}),
|
|
687
|
+
...(() => {
|
|
688
|
+
const v = ev.summarizedCrossSessionMessages;
|
|
689
|
+
if (v === undefined)
|
|
690
|
+
return {};
|
|
691
|
+
if (Number.isInteger(v) && v >= 1)
|
|
692
|
+
return { summarizedCrossSessionMessages: v };
|
|
693
|
+
dropProjectedFace("compacted.summarizedCrossSessionMessages is not an integer >= 1");
|
|
694
|
+
return {};
|
|
695
|
+
})(),
|
|
679
696
|
...(num(ev.durationMs) !== undefined ? { durationMs: num(ev.durationMs) } : {}),
|
|
680
697
|
...(phaseDurations !== undefined ? { phaseDurations } : {}),
|
|
681
698
|
};
|