@sema-agent/server 7.77.0 → 7.78.1
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/dist/approval-card.d.ts +24 -1
- package/dist/approval-card.js +13 -0
- package/dist/boot/resolve-spec.js +3 -0
- package/dist/boot/runner-deps.js +3 -1
- package/dist/config-catalog.js +1 -0
- package/dist/config-center/read-warnings.d.ts +10 -1
- package/dist/config-center/read-warnings.js +5 -1
- package/dist/config-provider.js +2 -2
- package/dist/config-types.d.ts +13 -1
- package/dist/config.js +2 -1
- package/dist/http/routes/approvals-assistant.d.ts +22 -0
- package/dist/http/routes/approvals-assistant.js +4 -1
- package/dist/http/routes/tasks.js +14 -9
- package/dist/http/routes/workflows.js +7 -1
- package/dist/http/server.d.ts +28 -4
- package/dist/http/server.js +47 -13
- package/dist/observability/fail-open.d.ts +4 -0
- package/dist/observability/fail-open.js +4 -0
- package/dist/observability/run-terminal-log.js +1 -0
- package/dist/orchestration/workflow-agent-session-index.d.ts +7 -3
- package/dist/parked-decide.d.ts +27 -12
- package/dist/parked-decide.js +1 -1
- package/dist/plugins/workflow-run-store-sql.d.ts +7 -3
- package/dist/request-key-closure.d.ts +30 -0
- package/dist/request-key-closure.js +56 -0
- package/dist/runs.js +3 -1
- package/dist/runtime-governance.d.ts +18 -4
- package/dist/runtime-governance.js +2 -2
- package/dist/spec-fields.d.ts +3 -1
- package/dist/spec-fields.js +4 -5
- package/dist/task-settings.d.ts +18 -16
- package/dist/task-settings.js +17 -29
- package/dist/tool-approval.d.ts +35 -3
- package/dist/tool-approval.js +41 -19
- package/dist/trace/core-keyset-guard.d.ts +8 -8
- package/dist/trace/ledger-events.d.ts +7 -1
- package/dist/trace/ledger-sink.js +19 -6
- package/dist/trace/model-segment.d.ts +32 -2
- package/dist/trace/model-segment.js +16 -6
- package/dist/trace/project.d.ts +95 -3
- package/dist/trace/project.js +128 -12
- package/dist/trace/redact.js +159 -13
- package/package.json +4 -4
package/dist/tool-approval.js
CHANGED
|
@@ -8,7 +8,7 @@ import { approvalPayloadFingerprint } from "./plugins/approval-payload-fingerpri
|
|
|
8
8
|
import { createLogger } from "./observability/logger.js";
|
|
9
9
|
import { recordFailOpen } from "./observability/fail-open.js";
|
|
10
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, readRuleEvidence, readRuleOffersAbsence, RuleOfferRawSchema, backfillLegacyBatchMemberKind, screenUncoveredDetailSeat, } from "./approval-card.js";
|
|
11
|
+
import { ApprovalCardEnvelopeSchema, MAX_RULE_OFFERS, buildApprovalCard, buildApprovalCardEnvelope, buildApprovalRequestFrame, buildRevokeFrame, readDenialLimitFallback, readProbeCause, readReadRootCandidate, readRuleEvidence, readRuleOffersAbsence, RuleOfferRawSchema, backfillLegacyBatchMemberKind, screenUncoveredDetailSeat, } from "./approval-card.js";
|
|
12
12
|
import { projectAskTerminalClaimTruth } from "./plugins/approval-ask-store-sql.js";
|
|
13
13
|
import { governanceAskMarksFor, runWithGovernanceAskScope } from "./governance-ask-marks.js";
|
|
14
14
|
const defaultLogger = createLogger();
|
|
@@ -300,11 +300,29 @@ export class ToolApprovalCoordinator {
|
|
|
300
300
|
this.parkTombstonePerPrincipalMax = opts?.parkTombstonePerPrincipalMax ?? DEFAULT_PARK_TOMBSTONE_PER_PRINCIPAL_MAX;
|
|
301
301
|
this.askAudit = opts?.askAudit;
|
|
302
302
|
}
|
|
303
|
-
unattendedOutcome() {
|
|
304
|
-
|
|
303
|
+
unattendedOutcome(site) {
|
|
304
|
+
const outcome = this.unattendedPolicy === "deny" ? false : "unavailable";
|
|
305
|
+
defaultLogger.warn("approver_unavailable", {
|
|
306
|
+
arm: site.arm,
|
|
307
|
+
policy: this.unattendedPolicy,
|
|
308
|
+
outcome: outcome === false ? "deny" : "unavailable",
|
|
309
|
+
owner: site.owner ?? null,
|
|
310
|
+
taskId: site.taskId ?? null,
|
|
311
|
+
toolName: site.toolName ?? null,
|
|
312
|
+
reachability: site.reachability ?? null,
|
|
313
|
+
});
|
|
314
|
+
return outcome;
|
|
315
|
+
}
|
|
316
|
+
get unattendedRoutesToPark() {
|
|
317
|
+
return this.unattendedPolicy !== "deny";
|
|
305
318
|
}
|
|
306
|
-
unattendedAskOutcome() {
|
|
307
|
-
return this.unattendedOutcome(
|
|
319
|
+
unattendedAskOutcome(site) {
|
|
320
|
+
return this.unattendedOutcome({
|
|
321
|
+
arm: "window_zero",
|
|
322
|
+
...(site.taskId !== undefined ? { taskId: site.taskId } : {}),
|
|
323
|
+
...(site.owner !== undefined && site.owner !== null ? { owner: site.owner } : {}),
|
|
324
|
+
...(site.toolName !== undefined ? { toolName: site.toolName } : {}),
|
|
325
|
+
});
|
|
308
326
|
}
|
|
309
327
|
admit(taskId, owner) {
|
|
310
328
|
if (!this.askStore)
|
|
@@ -758,7 +776,7 @@ export class ToolApprovalCoordinator {
|
|
|
758
776
|
ask = async (req, signal) => {
|
|
759
777
|
const ctx = this.als.getStore();
|
|
760
778
|
if (!ctx)
|
|
761
|
-
return this.unattendedOutcome();
|
|
779
|
+
return this.unattendedOutcome({ arm: "no_run_context", toolName: req.toolName });
|
|
762
780
|
return this.askBroadcast({
|
|
763
781
|
taskId: ctx.taskId,
|
|
764
782
|
owner: ctx.owner,
|
|
@@ -786,11 +804,9 @@ export class ToolApprovalCoordinator {
|
|
|
786
804
|
const aliveCtxs = ctxs.filter((c) => !c.abortSignal?.aborted);
|
|
787
805
|
const reachability = aliveCtxs.length === 0 ? "unreached" : "reachable";
|
|
788
806
|
if (reachability === "unreached") {
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
if (!this.askStore)
|
|
793
|
-
return unattended;
|
|
807
|
+
if (!this.unattendedRoutesToPark || !this.askStore) {
|
|
808
|
+
return this.unattendedOutcome({ arm: "no_live_target", taskId: origin.taskId, ...(origin.owner !== null ? { owner: origin.owner } : {}), toolName: req.toolName, reachability });
|
|
809
|
+
}
|
|
794
810
|
}
|
|
795
811
|
const primary = aliveCtxs[0];
|
|
796
812
|
const governanceForced = (this.governanceAskMarks ?? governanceAskMarksFor(this.streamKey(origin.owner, origin.sessionId, origin.taskId))).isMarked(req.toolCallId);
|
|
@@ -809,7 +825,7 @@ export class ToolApprovalCoordinator {
|
|
|
809
825
|
admitMaxPerTask: this.admitMaxPerTask,
|
|
810
826
|
admitMaxPerOwner: this.admitMaxPerOwner,
|
|
811
827
|
});
|
|
812
|
-
return this.unattendedOutcome();
|
|
828
|
+
return this.unattendedOutcome({ arm: "admission_exhausted", taskId: origin.taskId, ...(origin.owner !== null ? { owner: origin.owner } : {}), toolName: req.toolName, reachability });
|
|
813
829
|
}
|
|
814
830
|
const id = uuidv7();
|
|
815
831
|
const child = isChildAsk(req);
|
|
@@ -848,6 +864,7 @@ export class ToolApprovalCoordinator {
|
|
|
848
864
|
...((a) => (a !== undefined ? { ruleOffersAbsence: a } : {}))(readRuleOffersAbsence(req)),
|
|
849
865
|
...((f) => (f !== undefined ? { denialLimitFallback: f } : {}))(readDenialLimitFallback(req)),
|
|
850
866
|
...(typeof req.ruleStoreUnreadable === "string" && req.ruleStoreUnreadable.length > 0 ? { ruleStoreUnreadable: req.ruleStoreUnreadable } : {}),
|
|
867
|
+
...((g) => (g !== undefined ? { readRootCandidate: g } : {}))(readReadRootCandidate(req)),
|
|
851
868
|
...((c) => (c !== undefined ? { probeCause: c } : {}))(readProbeCause(req)),
|
|
852
869
|
...((c) => (c !== undefined ? { ruleEvidence: c } : {}))(readRuleEvidence(req)),
|
|
853
870
|
...(bounded.omitted ? { argsOmitted: true } : { args: bounded.args }),
|
|
@@ -904,7 +921,9 @@ export class ToolApprovalCoordinator {
|
|
|
904
921
|
if (existingOrCreated.row.state !== "STREAM_PENDING") {
|
|
905
922
|
releaseAdmission();
|
|
906
923
|
const replayed = replayTerminalAskRow(existingOrCreated.row);
|
|
907
|
-
return replayed === "unavailable"
|
|
924
|
+
return replayed === "unavailable"
|
|
925
|
+
? this.unattendedOutcome({ arm: "replayed_parked", taskId: origin.taskId, ...(origin.owner !== null ? { owner: origin.owner } : {}), toolName: req.toolName, reachability })
|
|
926
|
+
: replayed;
|
|
908
927
|
}
|
|
909
928
|
const persistedEnvelope = ApprovalCardEnvelopeSchema.safeParse(existingOrCreated.row.cardJson);
|
|
910
929
|
const maxMintableWindowMs = Math.max(effectiveWindowMs, this.unreachedTtlMs);
|
|
@@ -985,7 +1004,7 @@ export class ToolApprovalCoordinator {
|
|
|
985
1004
|
voidAbandonedRow(lateEnsuredAskId);
|
|
986
1005
|
if (reachability === "unreached") {
|
|
987
1006
|
releaseAdmission();
|
|
988
|
-
return this.unattendedOutcome();
|
|
1007
|
+
return this.unattendedOutcome({ arm: "unreached_no_row", taskId: origin.taskId, ...(origin.owner !== null ? { owner: origin.owner } : {}), toolName: req.toolName, reachability });
|
|
989
1008
|
}
|
|
990
1009
|
}
|
|
991
1010
|
}
|
|
@@ -1014,8 +1033,11 @@ export class ToolApprovalCoordinator {
|
|
|
1014
1033
|
return false;
|
|
1015
1034
|
};
|
|
1016
1035
|
const shapeOutcome = (settled) => {
|
|
1017
|
-
if (windowRouteUnavailable)
|
|
1018
|
-
return this.unattendedOutcome(
|
|
1036
|
+
if (windowRouteUnavailable) {
|
|
1037
|
+
return this.unattendedOutcome({ arm: "window_expired", taskId: origin.taskId, ...(origin.owner !== null ? { owner: origin.owner } : {}), toolName: req.toolName, reachability }) === false
|
|
1038
|
+
? shapeDeny()
|
|
1039
|
+
: "unavailable";
|
|
1040
|
+
}
|
|
1019
1041
|
if (settled.allowed) {
|
|
1020
1042
|
return settled.updatedInput !== undefined ? { allow: true, updatedInput: settled.updatedInput } : true;
|
|
1021
1043
|
}
|
|
@@ -1032,7 +1054,7 @@ export class ToolApprovalCoordinator {
|
|
|
1032
1054
|
for (const [sig, fn] of abortListeners)
|
|
1033
1055
|
sig.removeEventListener("abort", fn);
|
|
1034
1056
|
this.pending.delete(id);
|
|
1035
|
-
if (windowRouteUnavailable && askId !== undefined && batchId !== undefined && this.
|
|
1057
|
+
if (windowRouteUnavailable && askId !== undefined && batchId !== undefined && this.unattendedRoutesToPark) {
|
|
1036
1058
|
this.recordParkTombstone(wireApprovalId, { kind: "park", askId, batchId, owner: origin.owner, parkedAtMs: Date.now() });
|
|
1037
1059
|
parkRouted = true;
|
|
1038
1060
|
}
|
|
@@ -1456,11 +1478,11 @@ export class ToolApprovalCoordinator {
|
|
|
1456
1478
|
.catch(() => undefined);
|
|
1457
1479
|
}
|
|
1458
1480
|
if (emitFailed)
|
|
1459
|
-
return this.unattendedOutcome();
|
|
1481
|
+
return this.unattendedOutcome({ arm: "emit_failed", taskId: origin.taskId, ...(origin.owner !== null ? { owner: origin.owner } : {}), toolName: req.toolName, reachability });
|
|
1460
1482
|
if (windowRouteUnavailable)
|
|
1461
1483
|
return shapeOutcome(settled);
|
|
1462
1484
|
if (!emitSettled && lastOutcome === "expired")
|
|
1463
|
-
return this.unattendedOutcome();
|
|
1485
|
+
return this.unattendedOutcome({ arm: "emit_unsettled", taskId: origin.taskId, ...(origin.owner !== null ? { owner: origin.owner } : {}), toolName: req.toolName, reachability });
|
|
1464
1486
|
return shapeOutcome(settled);
|
|
1465
1487
|
}
|
|
1466
1488
|
respond(id, principal, body, httpReq) {
|
|
@@ -43,14 +43,14 @@ type _GuardBgNotifReverse = AssertAllKeysHandled<Exclude<BgNotifProjected | BgNo
|
|
|
43
43
|
type RosterProjected = "name" | "agentId" | "sessionId" | "toolUseId" | "owner" | "scope" | "sessionScoped" | "rootSessionId" | "model" | "modelFallback" | "createdAt";
|
|
44
44
|
type _GuardRoster = AssertAllKeysHandled<Exclude<keyof RosterEntry, RosterProjected>>;
|
|
45
45
|
type _GuardRosterReverse = AssertAllKeysHandled<Exclude<RosterProjected, keyof RosterEntry>>;
|
|
46
|
-
type AskProjected = "toolName" | "toolCallId" | "args" | "message" | "sourceTaskId" | "fromSubagent" | "sourceAgentName" | "delegation" | "ruleOffers" | "ruleOffersAbsence" | "persistedRuleShadowed" | "probeCause" | "ruleEvidence" | "requiresRealApproval" | "denialLimitFallback" | "origin" | "ruleStoreUnreadable";
|
|
46
|
+
type AskProjected = "toolName" | "toolCallId" | "args" | "message" | "sourceTaskId" | "fromSubagent" | "sourceAgentName" | "delegation" | "ruleOffers" | "ruleOffersAbsence" | "persistedRuleShadowed" | "probeCause" | "ruleEvidence" | "requiresRealApproval" | "denialLimitFallback" | "origin" | "ruleStoreUnreadable" | "readRootCandidate";
|
|
47
47
|
type AskExcluded = "preview" | "principal" | "riskAxes" | "boundInputHash" | "isDelegatedChild" | "probeReason" | "hasBidiControls" | "previewWithheld" | "execCwd";
|
|
48
48
|
type _GuardAsk = AssertAllKeysHandled<Exclude<keyof AskRequest, AskProjected | AskExcluded>>;
|
|
49
49
|
type _GuardAskReverse = AssertAllKeysHandled<Exclude<AskProjected | AskExcluded, keyof AskRequest>>;
|
|
50
50
|
type AskFrameServerMinted = "type" | "approvalId" | "argsOmitted" | "outcome" | "governanceForced" | "expiresAtMs" | "expiresInMs" | "serverNowMs" | "parked" | "inputHasBidi";
|
|
51
51
|
type _GuardAskFrame = AssertAllKeysHandled<Exclude<keyof ToolApprovalFrame, AskProjected | AskFrameServerMinted>>;
|
|
52
52
|
type _GuardAskFrameReverse = AssertAllKeysHandled<Exclude<AskProjected | AskFrameServerMinted, keyof ToolApprovalFrame>>;
|
|
53
|
-
type TaskEventHandled = "text_delta" | "reasoning_delta" | "tool_start" | "tool_end" | "turn_end" | "compacted" | "diagnostics" | "message_committed" | "status" | "task_notification" | "task_progress" | "steering_injected" | "workspace_changed" | "done" | "context_usage" | "compaction_outcome" | "human_input" | "wiring_manifest" | "text_end" | "tool_roster_delta";
|
|
53
|
+
type TaskEventHandled = "text_delta" | "reasoning_delta" | "tool_start" | "tool_end" | "turn_end" | "compacted" | "diagnostics" | "message_committed" | "status" | "task_notification" | "task_progress" | "steering_injected" | "workspace_changed" | "done" | "context_usage" | "compaction_outcome" | "human_input" | "wiring_manifest" | "text_end" | "tool_roster_delta" | "tool_progress" | "tool_disclosure";
|
|
54
54
|
type _GuardTaskEvent = AssertAllKeysHandled<Exclude<TaskEvent["type"], TaskEventHandled>>;
|
|
55
55
|
type _GuardTaskEventReverse = AssertAllKeysHandled<Exclude<TaskEventHandled, TaskEvent["type"]>>;
|
|
56
56
|
type MailboxProjected = "seq" | "from" | "content" | "sentAt" | "hopChain" | "peerMeta";
|
|
@@ -59,7 +59,7 @@ 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";
|
|
62
|
+
type WiringSectionProjected = "schemaVersion" | "leg" | "ask" | "question" | "interaction" | "elicit" | "parkLane" | "session" | "fleet" | "permissionRules" | "modelGate" | "autoMode" | "mcp" | "tools" | "hooks" | "lsp";
|
|
63
63
|
type WiringSectionExcluded = "governance" | "configFingerprint";
|
|
64
64
|
type _GuardWiringSections = AssertAllKeysHandled<Exclude<keyof WiringManifest, WiringSectionProjected | WiringSectionExcluded>>;
|
|
65
65
|
type _GuardWiringSectionsReverse = AssertAllKeysHandled<Exclude<WiringSectionProjected | WiringSectionExcluded, keyof WiringManifest>>;
|
|
@@ -121,11 +121,11 @@ type SummaryProjected = "sessionId" | "scope" | "createdAt" | "gateKind" | "seve
|
|
|
121
121
|
type SummaryExcluded = "token" | "toolInput" | "toolName" | "toolCallId" | "preview" | "principal" | "sourceTaskId" | "contentKind" | "restoreMode" | "checkpointId" | "previewWithheld";
|
|
122
122
|
type _GuardInboxSummary = AssertAllKeysHandled<Exclude<keyof CheckpointSummary, SummaryProjected | SummaryExcluded>>;
|
|
123
123
|
type _GuardInboxSummaryReverse = AssertAllKeysHandled<Exclude<SummaryProjected | SummaryExcluded, keyof CheckpointSummary>>;
|
|
124
|
-
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" | "mcp" | "a2a" | "skills" | "backgroundScope" | "envFacts" | "limits" | "configOverrides" | "forwardSubagentEvents" | "retainSubagentSessions" | "retainBackgroundProcesses" | "outputSchema" | "outputRetries" | "compaction" | "attachments" | "selfOrchestration" | "getApiKeyAndHeaders" | "interactionPosture" | "agents" | "taskId" | "signal" | "preemptSignal" | "modelRole" | "enableBlockedReport" | "maxSuspends" | "autoModeRequested";
|
|
124
|
+
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" | "taskId" | "signal" | "preemptSignal" | "modelRole" | "enableBlockedReport" | "maxSuspends" | "autoModeRequested" | "skillListingBudgetFraction" | "skillListingMaxDescChars";
|
|
125
125
|
type TaskSpecUnwired = "excludeAllTools" | "actor" | "roles" | "lspManager" | "tracer" | "readFace" | "readDenyPatterns" | "interactiveQuestionFallback" | "alwaysLoadTools" | "restoreGatedTools" | "deferSelfResolve" | "basePolicyForResumeEdit" | "lspDiagnostics" | "streamingToolExecution" | "toolResultThresholdChars";
|
|
126
126
|
type _GuardTaskSpec = AssertAllKeysHandled<Exclude<keyof TaskSpec, TaskSpecWired | TaskSpecUnwired>>;
|
|
127
127
|
type _GuardTaskSpecReverse = AssertAllKeysHandled<Exclude<TaskSpecWired | TaskSpecUnwired, keyof TaskSpec>>;
|
|
128
|
-
type TaskResultForwarded = "taskId" | "runId" | "sessionId" | "terminal" | "model" | "effectiveReasoning" | "result" | "salvagedOutput" | "remoteEnvFailures" | "apiFailure" | "retryAfterMs" | "degraded" | "structuredOutput" | "rewindNotes" | "haltedOnUserRejection" | "haltedByUser" | "strandedHumanAnswers" | "pendingApproval" | "approvalWaitedMs" | "effectiveReadFace" | "effectiveReadDenyPatterns" | "effectiveMemoryScopes" | "stats" | "editedFiles";
|
|
128
|
+
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";
|
|
129
129
|
type TaskResultStripped = never;
|
|
130
130
|
type _GuardTaskResult = AssertAllKeysHandled<Exclude<keyof TaskResult, TaskResultForwarded | TaskResultStripped>>;
|
|
131
131
|
type _GuardTaskResultReverse = AssertAllKeysHandled<Exclude<TaskResultForwarded | TaskResultStripped, keyof TaskResult>>;
|
|
@@ -139,7 +139,7 @@ type GateOutcomeProjected = "disposition" | "settlement" | "origin";
|
|
|
139
139
|
type _GuardGateOutcome = AssertAllKeysHandled<Exclude<keyof GateOutcome, GateOutcomeProjected>>;
|
|
140
140
|
type _GuardGateOutcomeReverse = AssertAllKeysHandled<Exclude<GateOutcomeProjected, keyof GateOutcome>>;
|
|
141
141
|
type GateDispositionKeys = GateDisposition extends infer D ? (D extends object ? keyof D : never) : never;
|
|
142
|
-
type GateDispositionProjected = "kind" | "deniedBy" | "cause";
|
|
142
|
+
type GateDispositionProjected = "kind" | "deniedBy" | "cause" | "classifier";
|
|
143
143
|
type _GuardGateDisposition = AssertAllKeysHandled<Exclude<GateDispositionKeys, GateDispositionProjected>>;
|
|
144
144
|
type _GuardGateDispositionReverse = AssertAllKeysHandled<Exclude<GateDispositionProjected, GateDispositionKeys>>;
|
|
145
145
|
type SettlementProjected = "kind" | "who" | "when" | "note";
|
|
@@ -148,12 +148,12 @@ type _GuardSettlementReverse = AssertAllKeysHandled<Exclude<SettlementProjected,
|
|
|
148
148
|
type SettlementWhoProjected = "party" | "approver" | "window";
|
|
149
149
|
type _GuardSettlementWho = AssertAllKeysHandled<Exclude<SettlementWhoKeys, SettlementWhoProjected>>;
|
|
150
150
|
type _GuardSettlementWhoReverse = AssertAllKeysHandled<Exclude<SettlementWhoProjected, SettlementWhoKeys>>;
|
|
151
|
-
type WorkflowRunForwarded = "id" | "scope" | "status" | "startedAt" | "endedAt" | "createdAt" | "rev" | "parks" | "name" | "description" | "result" | "error" | "errorCode" | "agentFailures" | "stats" | "phases" | "agents" | "groups";
|
|
151
|
+
type WorkflowRunForwarded = "id" | "scope" | "status" | "startedAt" | "endedAt" | "createdAt" | "rev" | "parks" | "name" | "description" | "result" | "error" | "errorCode" | "agentFailures" | "stats" | "phases" | "agents" | "groups" | "resumeAdmissionIncomplete";
|
|
152
152
|
type WorkflowRunStripped = "sourceTaskId" | "originatingSessionId" | "effectiveArgs" | "budgetOvershoot" | "timeoutInterruption" | "resultFull" | "completionId" | "resume" | "journalSkips";
|
|
153
153
|
type _GuardWorkflowRun = AssertAllKeysHandled<Exclude<keyof WorkflowRun, WorkflowRunForwarded | WorkflowRunStripped>>;
|
|
154
154
|
type _GuardWorkflowRunReverse = AssertAllKeysHandled<Exclude<WorkflowRunForwarded | WorkflowRunStripped, keyof WorkflowRun>>;
|
|
155
155
|
type ParkRowKeys = keyof NonNullable<WorkflowRun["parks"]>[number];
|
|
156
|
-
type ParkRowProjected = "callKey" | "sessionId" | "originRunId";
|
|
156
|
+
type ParkRowProjected = "callKey" | "sessionId" | "originRunId" | "originUnconfirmed";
|
|
157
157
|
type ParkRowWithheld = "token";
|
|
158
158
|
type _GuardParkRow = AssertAllKeysHandled<Exclude<ParkRowKeys, ParkRowProjected | ParkRowWithheld>>;
|
|
159
159
|
type _NoDoubleBookParkRow = AssertAllKeysHandled<Extract<ParkRowProjected, ParkRowWithheld>>;
|
|
@@ -35,7 +35,13 @@ export type LedgerEventType = "reasoning" | "text" | "tool_start" | "tool_end" |
|
|
|
35
35
|
/** S-212(7.71.0):运行期名册变更(core 7.8.0 [ref] ⑪)。**快照语义**——`delta.roster` 是整只
|
|
36
36
|
* 变更后名册,消费端收到即整只替换,所以回放不需要任何合并;它的耐久面因此不是 `wiring_manifest.tools`
|
|
37
37
|
* 的重复,而是那份开腿快照**之后**的每一次改动(修前两条 durable 腿零 case ⇒ 回放只见开头一版)。 */
|
|
38
|
-
| "tool_roster_delta"
|
|
38
|
+
| "tool_roster_delta"
|
|
39
|
+
/** [ref](core 7.18.0):本条腿的**延迟工具普查**快照(policy / thresholdPercent? / deferred[] / activated[])。
|
|
40
|
+
* 与 `tool_roster_delta` 同判、同理由——**快照语义**(整只替换,回放零合并),而开腿那一份住在
|
|
41
|
+
* `wiring_manifest` 之后的首帧、**之后每一次激活**只活在本帧上。整帧缺席 = 这条腿什么都没延迟。
|
|
42
|
+
* 🔴 `tool_progress`([ref])**刻意不在本表**:core 的 `tool_progress.ephemeral` 契约逐字「LIVE ONLY …
|
|
43
|
+
* core never persists this frame」,与 `task_progress` / `status` 同一处置(两条 durable 腿零 case)。 */
|
|
44
|
+
| "tool_disclosure" | "human_input" | "task_progress" | "task_notification" | "turn_end"
|
|
39
45
|
/** park 行名**两个**(`appendParked(kind)` 逐字取自 `result.status`)—— 运行期闭集见
|
|
40
46
|
* {@link PARK_LEDGER_EVENT_TYPES}(本联合是它的类型面,两者由下方的双向断言锁步)。 */
|
|
41
47
|
| "suspended" | "needs_review" | "done" | "failed" | "suggestions" | "model_usage" | "prompt_assembled" | "config_assembled" | "file_link"
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { terminalProjection } from "@sema-agent/core";
|
|
2
|
-
import { modelTextEventData, toolStartEventData, toolEndEventData, taskProgressEventData, taskNotificationEventData, compactedEventData, diagnosticsEventData, brainStatusEventData, steeringInjectedEventData, compactionOutcomeEventData, workspaceChangedEventData, wiringManifestEventData, toolRosterDeltaEventData, humanInputEventData, turnEndEventData, contextUsageEventData } from "./project.js";
|
|
2
|
+
import { modelTextEventData, toolStartEventData, toolEndEventData, taskProgressEventData, taskNotificationEventData, compactedEventData, diagnosticsEventData, brainStatusEventData, steeringInjectedEventData, compactionOutcomeEventData, workspaceChangedEventData, wiringManifestEventData, toolRosterDeltaEventData, toolDisclosureEventData, humanInputEventData, turnEndEventData, contextUsageEventData } from "./project.js";
|
|
3
3
|
import { NotifiedKeys, taskNotificationStreamKey } from "../orchestration/workflow-completion-inbox.js";
|
|
4
4
|
import { isParkLedgerEventType } from "./ledger-events.js";
|
|
5
|
-
import { isModelSegmentBoundary } from "./model-segment.js";
|
|
5
|
+
import { isModelSegmentBoundary, reasoningDeltaBytes, reasoningSegmentEventId } from "./model-segment.js";
|
|
6
6
|
export function createSerialLedgerAppend(appendEvent, startSeq) {
|
|
7
7
|
let seq = startSeq;
|
|
8
8
|
let chain = Promise.resolve();
|
|
@@ -19,6 +19,7 @@ export function createLedgerSink(opts) {
|
|
|
19
19
|
let text = "";
|
|
20
20
|
let reasoning = "";
|
|
21
21
|
let textEventId;
|
|
22
|
+
let reasoningEventId;
|
|
22
23
|
const beat = (kind, statusData) => {
|
|
23
24
|
try {
|
|
24
25
|
opts.onActivity?.(kind, statusData);
|
|
@@ -34,8 +35,9 @@ export function createLedgerSink(opts) {
|
|
|
34
35
|
};
|
|
35
36
|
const flush = async () => {
|
|
36
37
|
if (reasoning) {
|
|
37
|
-
await append("reasoning", modelTextEventData({ text: reasoning }));
|
|
38
|
+
await append("reasoning", modelTextEventData({ text: reasoning, eventId: reasoningEventId }));
|
|
38
39
|
reasoning = "";
|
|
40
|
+
reasoningEventId = undefined;
|
|
39
41
|
}
|
|
40
42
|
if (text) {
|
|
41
43
|
await append("text", modelTextEventData({ text, eventId: textEventId }));
|
|
@@ -53,10 +55,15 @@ export function createLedgerSink(opts) {
|
|
|
53
55
|
textEventId ??= td.eventId;
|
|
54
56
|
break;
|
|
55
57
|
}
|
|
56
|
-
case "reasoning_delta":
|
|
57
|
-
|
|
58
|
-
|
|
58
|
+
case "reasoning_delta": {
|
|
59
|
+
const rd = ev;
|
|
60
|
+
const bytes = reasoningDeltaBytes(rd);
|
|
61
|
+
if (opts.persistThinking && bytes !== undefined) {
|
|
62
|
+
reasoning += bytes;
|
|
63
|
+
reasoningEventId ??= reasoningSegmentEventId(rd.eventId);
|
|
64
|
+
}
|
|
59
65
|
break;
|
|
66
|
+
}
|
|
60
67
|
case "tool_start":
|
|
61
68
|
await append("tool_start", toolStartEventData(ev));
|
|
62
69
|
break;
|
|
@@ -97,6 +104,12 @@ export function createLedgerSink(opts) {
|
|
|
97
104
|
await append("tool_roster_delta", rosterDelta);
|
|
98
105
|
break;
|
|
99
106
|
}
|
|
107
|
+
case "tool_disclosure": {
|
|
108
|
+
const disclosure = toolDisclosureEventData(ev);
|
|
109
|
+
if (disclosure !== undefined)
|
|
110
|
+
await append("tool_disclosure", disclosure);
|
|
111
|
+
break;
|
|
112
|
+
}
|
|
100
113
|
case "human_input":
|
|
101
114
|
await append("human_input", humanInputEventData(ev));
|
|
102
115
|
break;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type SegmentEndFields } from "./project.js";
|
|
1
2
|
/**
|
|
2
3
|
* 本帧是不是模型文本的段界。**四条消费腿共用这一只**:账本投影 switch(`trace/ledger-sink.ts`)、
|
|
3
4
|
* 顶层 live 流与转发子代腿(`http/routes/tasks.ts`)、子代 tail 面(`fleet/subagent-tail-bus.ts`)。
|
|
@@ -5,8 +6,10 @@
|
|
|
5
6
|
* (第三方 Runner 塞进来的野帧不该切走宿主的权威段)。
|
|
6
7
|
*/
|
|
7
8
|
export declare function isModelSegmentBoundary(type: string): boolean;
|
|
8
|
-
/** live 面的段末帧(`type` 即事件名;其余键由 `reasoningEndEventData` 白名单铸出)。
|
|
9
|
-
|
|
9
|
+
/** live 面的段末帧(`type` 即事件名;其余键由 `reasoningEndEventData` 白名单铸出)。
|
|
10
|
+
* 形是**声明**出来的、不是 `Record<string, unknown>`(S-334 门①):`eventId` 是本帧的续流游标,
|
|
11
|
+
* 型必须说得出口 —— live 腿的 `id:` 行取的正是它。 */
|
|
12
|
+
export type ReasoningEndFrame = SegmentEndFields & {
|
|
10
13
|
type: "reasoning_end";
|
|
11
14
|
};
|
|
12
15
|
/** 登记册**读到的全部字段**,逐个写出来(不是 `Record<string, unknown>`):`TaskEvent` 与转发腿的原始帧
|
|
@@ -48,6 +51,33 @@ export interface ReasoningSegments {
|
|
|
48
51
|
* 与账本腿 `LedgerSink.onDone → flush()` 同位同义 —— 段界表里没有终局词,终局走这扇门。 */
|
|
49
52
|
cut(match?: (ident: ReasoningStreamIdent) => boolean): ReasoningEndFrame[];
|
|
50
53
|
}
|
|
54
|
+
/**
|
|
55
|
+
* 一段推理的**段末事件 id** —— 唯一铸点,live 段末帧与账本 `reasoning` 行共用这一只。
|
|
56
|
+
*
|
|
57
|
+
* 🔴 **为什么段末帧不能沿用任何一块 delta 的 `eventId`**(S-334):SSE 的 `id:` 行是**续流游标**,
|
|
58
|
+
* 「每帧唯一」就是它的定义(消费端据它做**整帧幂等**:见过的 id 整帧丢);而本仓 live 腿的 `id:` 行
|
|
59
|
+
* 恰恰取自载荷的 `eventId`(`http/routes/tasks.ts` 的 `sseData`)。沿用段内某一块的锚 ⇒ 段末帧与那一块
|
|
60
|
+
* delta 顶着同一枚游标,消费端把**权威段**当重放帧丢弃 —— 本帧存在的唯一理由(整段脱敏后的权威副本)
|
|
61
|
+
* 当场结构性失效。「这段是从哪一帧开始攒的」不是游标要回答的问题,而「整段替换」这条消费律本来就
|
|
62
|
+
* 不需要段首锚:重连从**帧**续,不从段续。
|
|
63
|
+
*
|
|
64
|
+
* 形 = 那一枚锚 + 一个派生记号,**确定性**是它的全部要点:live 腿与账本腿各自看着同一条流、在同一个
|
|
65
|
+
* 段界上算出**同一枚**字符串,于是「同一份权威副本」在身份面也成立,而两条腿之间不需要任何传值通道
|
|
66
|
+
* ——bg / resume 两条账本腿上根本没有 live 登记册可问,靠传值就只能做成「detach 车道有、别的腿没有」
|
|
67
|
+
* 的两种账本行形。
|
|
68
|
+
*
|
|
69
|
+
* 输入 = 本段**第一块带锚**的 delta 的 `eventId`(不是「第一块」的:首块无锚不等于整段无锚,三条腿
|
|
70
|
+
* 统一用 `??=` 闩第一枚**有定义**的锚 —— 与 E18 的 `textEventId ??=` 逐字同律)。整段一块带锚的都没有
|
|
71
|
+
* ⇒ 段末 id 缺席(诚实的「无锚」,绝不合成占位 —— 与 `sseData` 的既有纪律同源:不可锚的位置不许
|
|
72
|
+
* 伪装成可锚)。
|
|
73
|
+
*/
|
|
74
|
+
export declare function reasoningSegmentEventId(anchor: unknown): string | undefined;
|
|
75
|
+
/** 一块 `reasoning_delta` 对段的**贡献字节** —— 非空串才算。账本腿与三条 live 腿共用这一只:空/坏形
|
|
76
|
+
* 增量一个字节都不贡献,既不开段也不参与闩锚 ⇒ 两面结构上不可能把锚闩在不同的帧上(`reasoning_end`
|
|
77
|
+
* 与账本 `reasoning` 行的正文早就逐字节相等,身份面随 S-334 收进同一条规则)。 */
|
|
78
|
+
export declare function reasoningDeltaBytes(ev: {
|
|
79
|
+
delta?: unknown;
|
|
80
|
+
}): string | undefined;
|
|
51
81
|
/** 「这条流属于这些子代 id 之一」—— 子代终态收段的匹配器(`task_id` 与 `sessionId` 是同一个子代的两个
|
|
52
82
|
* id 域,取并集;`undefined` 成员自动忽略)。腿上共用这一只,免得各写一遍 id 域的并集。 */
|
|
53
83
|
export declare function reasoningStreamOfTask(...ids: ReadonlyArray<string | undefined>): (ident: ReasoningStreamIdent) => boolean;
|
|
@@ -2,11 +2,18 @@ import { reasoningEndEventData } from "./project.js";
|
|
|
2
2
|
const BOUNDARY = new Set([
|
|
3
3
|
"tool_start", "tool_end", "status", "context_usage", "compacted", "diagnostics",
|
|
4
4
|
"steering_injected", "compaction_outcome", "workspace_changed", "wiring_manifest",
|
|
5
|
-
"tool_roster_delta", "human_input", "task_notification", "turn_end",
|
|
5
|
+
"tool_roster_delta", "human_input", "task_notification", "turn_end", "tool_disclosure",
|
|
6
6
|
]);
|
|
7
7
|
export function isModelSegmentBoundary(type) {
|
|
8
8
|
return BOUNDARY.has(type);
|
|
9
9
|
}
|
|
10
|
+
const REASONING_SEGMENT_ID_MARK = "~reasoning_end";
|
|
11
|
+
export function reasoningSegmentEventId(anchor) {
|
|
12
|
+
return typeof anchor === "string" && anchor.length > 0 ? `${anchor}${REASONING_SEGMENT_ID_MARK}` : undefined;
|
|
13
|
+
}
|
|
14
|
+
export function reasoningDeltaBytes(ev) {
|
|
15
|
+
return typeof ev.delta === "string" && ev.delta !== "" ? ev.delta : undefined;
|
|
16
|
+
}
|
|
10
17
|
export function reasoningStreamOfTask(...ids) {
|
|
11
18
|
const set = new Set(ids.filter((v) => typeof v === "string" && v !== ""));
|
|
12
19
|
return (ident) => (ident.sourceTaskId !== undefined && set.has(ident.sourceTaskId)) || (ident.bgAgentId !== undefined && set.has(ident.bgAgentId));
|
|
@@ -25,21 +32,24 @@ export function createReasoningSegments() {
|
|
|
25
32
|
if (seg === undefined)
|
|
26
33
|
return [];
|
|
27
34
|
open.delete(key);
|
|
28
|
-
const data = reasoningEndEventData({ ...seg.ident, eventId: seg.
|
|
35
|
+
const data = reasoningEndEventData({ ...seg.ident, eventId: seg.segmentEventId, content: seg.buf });
|
|
29
36
|
return data === null ? [] : [{ type: "reasoning_end", ...data }];
|
|
30
37
|
};
|
|
31
38
|
return {
|
|
32
39
|
onEvent: (ev) => {
|
|
33
40
|
if (ev.type === "reasoning_delta") {
|
|
34
|
-
|
|
41
|
+
const bytes = reasoningDeltaBytes(ev);
|
|
42
|
+
if (bytes === undefined)
|
|
35
43
|
return [];
|
|
36
44
|
const ident = identOf(ev);
|
|
37
45
|
const key = streamKeyOf(ident);
|
|
38
46
|
const seg = open.get(key);
|
|
39
47
|
if (seg === undefined)
|
|
40
|
-
open.set(key, { ident,
|
|
41
|
-
else
|
|
42
|
-
seg.buf +=
|
|
48
|
+
open.set(key, { ident, segmentEventId: reasoningSegmentEventId(ev.eventId), buf: bytes });
|
|
49
|
+
else {
|
|
50
|
+
seg.buf += bytes;
|
|
51
|
+
seg.segmentEventId ??= reasoningSegmentEventId(ev.eventId);
|
|
52
|
+
}
|
|
43
53
|
return [];
|
|
44
54
|
}
|
|
45
55
|
return isModelSegmentBoundary(ev.type ?? "") ? cutKey(streamKeyOf(identOf(ev))) : [];
|
package/dist/trace/project.d.ts
CHANGED
|
@@ -192,8 +192,42 @@ export declare function screenedStoredEventData(type: string, data: unknown): un
|
|
|
192
192
|
* 此前三处各自逐字透传 —— 同一份文本毫秒后在 `done.result.result` 上已脱,live 面却在凭据生成瞬间明文(B-114)。
|
|
193
193
|
* `text_delta` 仍逐字:跨 chunk 的凭据无法就地判,流式脱敏是独立设计件(S-270)。
|
|
194
194
|
* 坏形(content 非串/空串)⇒ null(丢帧,不铸「权威空段」:core 契约明言空段不发本帧,消费端收到空段会清掉已攒 delta)。
|
|
195
|
-
*
|
|
196
|
-
|
|
195
|
+
* 身份**四键**随行(live 现状带全四键,消费端可能已依赖);值经 {@link identityKey} —— 非空 string 才上 wire
|
|
196
|
+
* (S-334 起不再逐字透传:坏形身份键会在 live 写口上铸出假游标)。 */
|
|
197
|
+
export declare function textEndEventData(ev: Record<string, unknown>): SegmentEndFields | null;
|
|
198
|
+
/**
|
|
199
|
+
* live 面的**身份四键**(core `TaskEventIdentity` 全集)—— 一个属主,两处共用({@link segmentEndFields}
|
|
200
|
+
* 与 sync 腿白名单 catch-all 的 `ident`;此前是两份手抄)。与 durable 面的 {@link identityFields} 的差别
|
|
201
|
+
* **只剩键集**:那边两键(durable builder 对另两键的既定排除),这边四键(live 现状,消费端已依赖);
|
|
202
|
+
* **值判据是同一条** —— 两只都问 {@link identityKey}(非空 `string` 才上 wire,绝不强转)。
|
|
203
|
+
*
|
|
204
|
+
* 🔴 **型必须说得出口**(S-334):`eventId` 是 live 腿 SSE `id:` 行的**唯一**来源,而 `id:` 行是续流游标
|
|
205
|
+
* ——一个连值的型都说不出的键不许铸成游标。非串/空串 ⇒ 键缺席(与「无锚不发 `id:` 行」同一条纪律:
|
|
206
|
+
* 不可锚的位置绝不伪装成可锚)。转发子代腿的帧是 UNTRUSTED RAW(§E1),这一道同时是它的形判门。
|
|
207
|
+
*
|
|
208
|
+
* 🔴 **`type` 而不是 `interface`**(它与 {@link SegmentEndFields} 两处都是,别改回去):TS 只给**类型别名**
|
|
209
|
+
* 隐式索引签名,interface 没有 ⇒ 写成 interface 的话,每一个把本形交给 `Record<string, unknown>` 形参
|
|
210
|
+
* (tail 总线帧、live 帧写口)的调用点都得手抄一次 `{ ...frame }` 展开。别名让「声明出来的形」原样流经
|
|
211
|
+
* 既有写口,零调用点噪声。
|
|
212
|
+
*/
|
|
213
|
+
export type LiveEventIdentity = {
|
|
214
|
+
eventId?: string;
|
|
215
|
+
parentToolCallId?: string;
|
|
216
|
+
sourceTaskId?: string;
|
|
217
|
+
bgAgentId?: string;
|
|
218
|
+
};
|
|
219
|
+
/** 段末帧(`text_end` / `reasoning_end`)的载荷**形**(两只帧一个字节不差 —— 一个 wire 概念一份形,
|
|
220
|
+
* 消费端的读法只学一次;差别只有各自铸点的空段判据)。 */
|
|
221
|
+
export type SegmentEndFields = LiveEventIdentity & {
|
|
222
|
+
content: string;
|
|
223
|
+
};
|
|
224
|
+
/** {@link LiveEventIdentity} 的铸点。[ref] 门①:条件展开的臂逐条是直写字面量(键名对扫描器可见)。 */
|
|
225
|
+
export declare function liveIdentityFields(ev: {
|
|
226
|
+
eventId?: unknown;
|
|
227
|
+
parentToolCallId?: unknown;
|
|
228
|
+
sourceTaskId?: unknown;
|
|
229
|
+
bgAgentId?: unknown;
|
|
230
|
+
}): LiveEventIdentity;
|
|
197
231
|
/**
|
|
198
232
|
* `reasoning_end` 段末帧的**唯一**铸点(三条 live 腿共用:top stream / 转发子代腿 / 子代 tail 面)——
|
|
199
233
|
* `text_end` 的推理面孪生({@link textEndEventData}),形逐字同(共用 {@link segmentEndFields})。
|
|
@@ -210,7 +244,7 @@ export declare function textEndEventData(ev: Record<string, unknown>): Record<st
|
|
|
210
244
|
* 「整段替换已攒的 delta」—— 发一枚空白权威段 = 让消费端把已渲染的思考清成空白。坏形(`content` 非串)
|
|
211
245
|
* 同样丢帧,理由与 `text_end` 逐字同源。
|
|
212
246
|
*/
|
|
213
|
-
export declare function reasoningEndEventData(ev: Record<string, unknown>):
|
|
247
|
+
export declare function reasoningEndEventData(ev: Record<string, unknown>): SegmentEndFields | null;
|
|
214
248
|
/** The durable `tool_end` payload (shared by both append sites). E1: the model-facing `output` is UNTRUSTED RAW
|
|
215
249
|
* from core (file/shell/API bodies) — core only SIZE-bounds it (`truncated`), REDACTION is ours (same contract as
|
|
216
250
|
* `tool_start.args`); never re-fed to a model. E2: identity. Absent `output` ⇒ the tool produced no content body.
|
|
@@ -236,6 +270,63 @@ export declare function toolEndEventData(ev: {
|
|
|
236
270
|
eventId?: string;
|
|
237
271
|
parentToolCallId?: string;
|
|
238
272
|
}): Record<string, unknown>;
|
|
273
|
+
/**
|
|
274
|
+
* `tool_progress` 的白名单投影(core 7.18.0 [ref])—— 一只**仍在跑**的工具调用的存活 tick。
|
|
275
|
+
*
|
|
276
|
+
* ## 这一帧只上 live,不落账(判据是 core 的契约,不是本仓的偏好)
|
|
277
|
+
* core `@contract tool_progress.ephemeral` 逐字:「LIVE ONLY, like `task_progress`/`status`: core never
|
|
278
|
+
* persists this frame (no session-tree entry, no checkpoint state, no resume replay)」。本仓对
|
|
279
|
+
* `task_progress` / `status` 正是同一处置(两条 durable 腿零 case),本帧照抄。
|
|
280
|
+
* 另一条 core 契约把「不落账」从偏好抬成正确性:`@contract tool_progress.cadence` 逐字「A call that
|
|
281
|
+
* finishes inside one interval emits NO frame at all」⇒ **帧的缺席从来不是证据**;落账会让回放面凭空
|
|
282
|
+
* 多出一份「这只调用跑了多久」的账,而那件事的真源是 `tool_end`(core 明写 `elapsedTimeSeconds`
|
|
283
|
+
* **不等于** `tool_end` 的 duration)。
|
|
284
|
+
*
|
|
285
|
+
* ## 信任划线
|
|
286
|
+
* · `toolCallId` / `toolName` —— 引擎铸的 id 与名册里的工具名(与 `tool_start` 逐字同源)⇒ verbatim。
|
|
287
|
+
* · `elapsedTimeSeconds` —— 引擎铸的整秒,单调、一 call 一个原点 ⇒ 有限数才铸键。
|
|
288
|
+
* · `output` —— 🔴 **UNTRUSTED RAW**,core 逐字「exactly as `tool_end.output`: process output that may
|
|
289
|
+
* carry secrets, paths or PII; core bounds only its SIZE, and a consumer MUST redact before persisting
|
|
290
|
+
* or displaying it」⇒ 与 `tool_end.output` **同一只** `redactDeep`,一个字节的例外都不开。
|
|
291
|
+
* · `totalLines` / `totalBytes` —— 引擎计数;core 的缺席律逐字:三者**同进同退**(在场=「观察到了输出」,
|
|
292
|
+
* 缺席=「一个字节都没观察到」,**从不是**「与上一帧相比没变」)。所以本投影按 `output` 的在场判三者:
|
|
293
|
+
* `output` 读不出 ⇒ 三键一起缺席,不单独留下两个计数(那会把「没输出」谎报成「有输出但读不出」)。
|
|
294
|
+
*/
|
|
295
|
+
export declare function toolProgressEventData(ev: {
|
|
296
|
+
toolCallId?: unknown;
|
|
297
|
+
toolName?: unknown;
|
|
298
|
+
elapsedTimeSeconds?: unknown;
|
|
299
|
+
output?: unknown;
|
|
300
|
+
totalLines?: unknown;
|
|
301
|
+
totalBytes?: unknown;
|
|
302
|
+
eventId?: unknown;
|
|
303
|
+
parentToolCallId?: unknown;
|
|
304
|
+
}): Record<string, unknown> | undefined;
|
|
305
|
+
/**
|
|
306
|
+
* `tool_disclosure` 的白名单投影(core 7.18.0 [ref])—— 本条腿的**延迟工具普查**:哪些挂载的工具今天只是
|
|
307
|
+
* 名字占位、模型已经激活了哪些、以及是哪条策略判的。
|
|
308
|
+
*
|
|
309
|
+
* ## 三腿对称(与 `tool_roster_delta` 同判、同理由)
|
|
310
|
+
* 开腿那一刻的快照住在 `wiring_manifest` 之后的**第一帧**,而**之后每一次激活**只活在本帧上。不落账 ⇒
|
|
311
|
+
* 断线重连 / 后台跑完再回来的耐久面永远停在开腿版本,而壳正是据它判「这只工具现在还是不是占位名」。
|
|
312
|
+
* 本帧是**整只快照**语义(`deferred` / `activated` 全量,消费端整只替换),所以回放不需要合并。
|
|
313
|
+
*
|
|
314
|
+
* ## 缺席语义(core 逐字,别读错)
|
|
315
|
+
* · **整帧缺席** = 「这条腿什么都没延迟」,**不是**「这个 build 没有这个面」、也不是「未知」;
|
|
316
|
+
* · `thresholdPercent` 缺席 = `always` / `never` 两档下**根本没查过阈值**,不许读成「取了默认百分比」;
|
|
317
|
+
* · 一条 resume 腿的**首帧** `activated` 可能非空(引擎重播的),**不许**读成「这条腿激活了它们」。
|
|
318
|
+
*
|
|
319
|
+
* 成员全是闭形值(策略闭词 + 数字 + 名册里的工具名)⇒ 零脱敏,与 `tool_roster_delta` 的名册行同待遇。
|
|
320
|
+
* `policy` **不在本仓枚举**(闭集词表属主在 core;抄一份会把 core 加的新词吞成缺席)。
|
|
321
|
+
*/
|
|
322
|
+
export declare function toolDisclosureEventData(ev: {
|
|
323
|
+
policy?: unknown;
|
|
324
|
+
thresholdPercent?: unknown;
|
|
325
|
+
deferred?: unknown;
|
|
326
|
+
activated?: unknown;
|
|
327
|
+
eventId?: unknown;
|
|
328
|
+
parentToolCallId?: unknown;
|
|
329
|
+
}): Record<string, unknown> | undefined;
|
|
239
330
|
/** The `task_progress` payload (a subagent's live progress tick) — EXPLICIT WHITELIST shared by all
|
|
240
331
|
* three legs (bg runs.ts + resume append + the sync live SSE frame): taskId/parent linkage/token rollup verbatim,
|
|
241
332
|
* `name` UNTRUSTED (core sanitizes for rendering, does NOT secret-redact — a taskName can be secret-shaped) →
|
|
@@ -679,6 +770,7 @@ export declare function contextUsageEventData(ev: {
|
|
|
679
770
|
usedTokens?: unknown;
|
|
680
771
|
windowTokens?: unknown;
|
|
681
772
|
compactAtTokens?: unknown;
|
|
773
|
+
sections?: unknown;
|
|
682
774
|
eventId?: unknown;
|
|
683
775
|
parentToolCallId?: unknown;
|
|
684
776
|
}): Record<string, unknown>;
|