@sema-agent/client-core 0.110.0 → 0.112.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.
Files changed (243) hide show
  1. package/CHANGELOG.md +244 -0
  2. package/README.md +59 -18
  3. package/dist/abortableSleep.d.ts +7 -0
  4. package/dist/abortableSleep.js +37 -0
  5. package/dist/adapt/arms.js +25 -4
  6. package/dist/adapt/toolCards.d.ts +3 -1
  7. package/dist/adapt/toolCards.js +4 -2
  8. package/dist/adapter/activeRunSelfHeal.d.ts +39 -0
  9. package/dist/adapter/activeRunSelfHeal.js +171 -3
  10. package/dist/adapter/downstream/eventToSdkMessage.js +10 -10
  11. package/dist/adapter/downstream/terminalToSdkResult.d.ts +2 -0
  12. package/dist/adapter/downstream/terminalToSdkResult.js +11 -0
  13. package/dist/adapter/runStream.d.ts +5 -0
  14. package/dist/adapter/runStream.js +15 -3
  15. package/dist/agentSession/engineSessionBackgroundStop.js +2 -2
  16. package/dist/attachmentRoute.d.ts +20 -0
  17. package/dist/attachmentRoute.js +39 -0
  18. package/dist/attachmentsWireCaps.js +1 -1
  19. package/dist/builtinOutputStyles.d.ts +12 -0
  20. package/dist/builtinOutputStyles.js +147 -0
  21. package/dist/checkpointRowVerdict.d.ts +3 -0
  22. package/dist/checkpointRowVerdict.js +14 -1
  23. package/dist/compactionStatus.d.ts +9 -0
  24. package/dist/compactionStatus.js +29 -5
  25. package/dist/consoleCaPin.d.ts +136 -0
  26. package/dist/consoleCaPin.js +827 -0
  27. package/dist/controlRouter.js +2 -1
  28. package/dist/coreValuePorts.d.ts +39 -1
  29. package/dist/coreValuePorts.js +10 -0
  30. package/dist/decideReceipt.d.ts +2 -1
  31. package/dist/deviceRebind.js +3 -3
  32. package/dist/displayUntrusted.d.ts +1 -0
  33. package/dist/displayUntrusted.js +6 -0
  34. package/dist/effectiveFacts.d.ts +9 -0
  35. package/dist/effectiveFacts.js +33 -0
  36. package/dist/engineAddress.d.ts +1 -0
  37. package/dist/engineAddress.js +4 -1
  38. package/dist/engineCredentialRelease.d.ts +54 -0
  39. package/dist/engineCredentialRelease.js +146 -0
  40. package/dist/engineErrorCodes.d.ts +1 -0
  41. package/dist/engineErrorCodes.js +1 -0
  42. package/dist/engineHealthProbeVerdict.d.ts +24 -0
  43. package/dist/engineHealthProbeVerdict.js +123 -0
  44. package/dist/engineNoticeCodes.js +5 -7
  45. package/dist/engineRepoint.d.ts +12 -5
  46. package/dist/engineRepoint.js +44 -19
  47. package/dist/engineRowRef.d.ts +3 -0
  48. package/dist/engineRowRef.js +11 -1
  49. package/dist/engineSwapCrossing.d.ts +57 -0
  50. package/dist/engineSwapCrossing.js +297 -0
  51. package/dist/engineUnavailable.d.ts +45 -0
  52. package/dist/engineUnavailable.js +496 -0
  53. package/dist/engineUrl.js +4 -2
  54. package/dist/eventLeg.js +3 -3
  55. package/dist/gateFailureCodes.js +2 -2
  56. package/dist/generated/sdkFactTables.d.ts +2 -1
  57. package/dist/generated/sdkFactTables.js +14 -0
  58. package/dist/generated/settingsSchemaFns.d.ts +1 -0
  59. package/dist/generated/settingsSchemaFns.js +3 -0
  60. package/dist/generated/settingsSchemaHooksClassifier.js +38 -9
  61. package/dist/generated/settingsSchemaTables.d.ts +56 -0
  62. package/dist/generated/settingsSchemaTables.js +19 -0
  63. package/dist/generated/settingsSchemaTypes.d.ts +23 -13
  64. package/dist/generated/settingsSchemaUrlShape.d.ts +1 -0
  65. package/dist/generated/settingsSchemaUrlShape.js +17 -0
  66. package/dist/hitl/approvalDelivery.d.ts +1 -0
  67. package/dist/hitl/approvalDelivery.js +1 -1
  68. package/dist/hitl/approvalResolution.d.ts +1 -1
  69. package/dist/hitl/approvalResolution.js +2 -1
  70. package/dist/hitl/askGateWire.js +5 -6
  71. package/dist/hitl/decisionRefusal.d.ts +6 -0
  72. package/dist/hitl/decisionRefusal.js +19 -10
  73. package/dist/hitl/decisionRefusalCarrier.d.ts +3 -0
  74. package/dist/hitl/decisionRefusalCarrier.js +348 -0
  75. package/dist/hitl/decisionSend.d.ts +7 -0
  76. package/dist/hitl/decisionSend.js +34 -12
  77. package/dist/hitl/editedApprovalAcceptance.js +1 -1
  78. package/dist/hitl/elicitationRefusal.d.ts +4 -0
  79. package/dist/hitl/elicitationRefusal.js +23 -0
  80. package/dist/hitl/frameRouter.d.ts +2 -2
  81. package/dist/hitl/frameRouter.js +8 -15
  82. package/dist/hitl/gateIdentity.d.ts +5 -0
  83. package/dist/hitl/gateIdentity.js +23 -0
  84. package/dist/hitl/hitlBridge.d.ts +6 -0
  85. package/dist/hitl/hitlBridge.js +10 -4
  86. package/dist/hitl/hitlHostSurface.d.ts +2 -1
  87. package/dist/hitl/hitlHostSurface.js +7 -2
  88. package/dist/hitl/localAllowRedemption.d.ts +70 -0
  89. package/dist/hitl/localAllowRedemption.js +276 -0
  90. package/dist/hitl/parkOwnership.js +2 -1
  91. package/dist/hitl/parkResolver.js +14 -4
  92. package/dist/hitl/persistedRulesWire.d.ts +16 -0
  93. package/dist/hitl/persistedRulesWire.js +70 -0
  94. package/dist/hitl/planReviewWire.d.ts +3 -0
  95. package/dist/hitl/planReviewWire.js +23 -6
  96. package/dist/hitl/policyDenyCause.d.ts +1 -1
  97. package/dist/hitl/policyDenyCause.js +1 -1
  98. package/dist/hitl/resumeRunningCard.d.ts +1 -0
  99. package/dist/hitl/resumeRunningCard.js +1 -0
  100. package/dist/hitl/screenCardCarriers.d.ts +15 -0
  101. package/dist/hitl/screenCardCarriers.js +41 -0
  102. package/dist/hitl/screenDecisionCards.d.ts +98 -0
  103. package/dist/hitl/screenDecisionCards.js +363 -0
  104. package/dist/hitl/sessionPolicyWire.js +2 -2
  105. package/dist/hitl/standingRows.d.ts +6 -2
  106. package/dist/hitl/standingRows.js +27 -2
  107. package/dist/hitl/toolApprovalWire.d.ts +30 -8
  108. package/dist/hitl/toolApprovalWire.js +264 -121
  109. package/dist/hooksReaderGenerations.js +1 -1
  110. package/dist/hooksWireCaps.js +3 -3
  111. package/dist/hostSettingNoticeArm.d.ts +3 -0
  112. package/dist/hostSettingNoticeArm.js +12 -0
  113. package/dist/hostTurnSettings.d.ts +3 -0
  114. package/dist/hostTurnSettings.js +38 -5
  115. package/dist/humanTurnRead.js +11 -1
  116. package/dist/i18n/messages.en.d.ts +292 -0
  117. package/dist/i18n/messages.en.js +298 -7
  118. package/dist/i18n/messages.zh.js +316 -6
  119. package/dist/i18n/translate.d.ts +3 -0
  120. package/dist/i18n/translate.js +78 -10
  121. package/dist/i18n/zh.d.ts +1 -0
  122. package/dist/i18n/zh.js +1 -0
  123. package/dist/index.d.ts +71 -20
  124. package/dist/index.js +44 -13
  125. package/dist/interactiveHalt.js +2 -1
  126. package/dist/interactiveInterrupt.js +20 -2
  127. package/dist/liveModelCatalog.d.ts +4 -0
  128. package/dist/liveModelCatalog.js +12 -3
  129. package/dist/localConfig/documents.d.ts +61 -0
  130. package/dist/localConfig/documents.js +51 -0
  131. package/dist/localConfig/kernel.d.ts +149 -0
  132. package/dist/localConfig/kernel.js +597 -0
  133. package/dist/localConfig/mcp/edit.d.ts +161 -0
  134. package/dist/localConfig/mcp/edit.js +846 -0
  135. package/dist/localConfig/mcp/servers.d.ts +165 -0
  136. package/dist/localConfig/mcp/servers.js +776 -0
  137. package/dist/localConfig/mcp/views.d.ts +170 -0
  138. package/dist/localConfig/mcp/views.js +429 -0
  139. package/dist/localConfig/modelPool.d.ts +262 -0
  140. package/dist/localConfig/modelPool.js +1489 -0
  141. package/dist/localConfig/modelPoolWords.d.ts +13 -0
  142. package/dist/localConfig/modelPoolWords.js +20 -0
  143. package/dist/localConfig/receiptShape.d.ts +7 -0
  144. package/dist/localConfig/receiptShape.js +135 -0
  145. package/dist/localConfig/settingsWrite.d.ts +127 -0
  146. package/dist/localConfig/settingsWrite.js +237 -0
  147. package/dist/localConfig/skills.d.ts +124 -0
  148. package/dist/localConfig/skills.js +397 -0
  149. package/dist/localConfig/skillsWords.d.ts +10 -0
  150. package/dist/localConfig/skillsWords.js +5 -0
  151. package/dist/localEngineSeatReading.d.ts +2 -2
  152. package/dist/localEngineSeatReading.js +5 -3
  153. package/dist/localEngineSpawn.d.ts +0 -7
  154. package/dist/localEngineSpawn.js +0 -92
  155. package/dist/localEngineStep.d.ts +2 -2
  156. package/dist/localEngineStep.js +2 -0
  157. package/dist/mcpProbeWire.js +2 -1
  158. package/dist/mcpReconnect.js +3 -3
  159. package/dist/mcpWireCaps.js +1 -1
  160. package/dist/memoryVerbsWire.js +3 -2
  161. package/dist/model/engineModelWords.d.ts +3 -0
  162. package/dist/model/engineModelWords.js +13 -0
  163. package/dist/model/onboardJudgement.d.ts +14 -4
  164. package/dist/model/onboardJudgement.js +91 -139
  165. package/dist/model/subagentModelWord.d.ts +21 -2
  166. package/dist/model/subagentModelWord.js +100 -29
  167. package/dist/modelCapabilityProbe.js +3 -40
  168. package/dist/modelConfigGapNotice.d.ts +20 -0
  169. package/dist/modelConfigGapNotice.js +102 -0
  170. package/dist/modsKernelIdentity.js +2 -47
  171. package/dist/notifications.d.ts +19 -0
  172. package/dist/notifications.js +114 -12
  173. package/dist/ownKey.d.ts +7 -0
  174. package/dist/ownKey.js +71 -8
  175. package/dist/pendingUserRow.d.ts +4 -0
  176. package/dist/pendingUserRow.js +16 -0
  177. package/dist/permissionsDeclaration.d.ts +3 -1
  178. package/dist/permissionsDeclaration.js +33 -9
  179. package/dist/planReviewCardFacts.d.ts +3 -0
  180. package/dist/planReviewCardFacts.js +52 -2
  181. package/dist/pluginHooksWire.d.ts +9 -1
  182. package/dist/pluginHooksWire.js +40 -6
  183. package/dist/printToolResultFrame.js +4 -2
  184. package/dist/promptBlockedCopy.js +12 -7
  185. package/dist/promptSuggestionBatch.d.ts +7 -0
  186. package/dist/promptSuggestionBatch.js +9 -0
  187. package/dist/promptSuggestionsTail.d.ts +39 -0
  188. package/dist/promptSuggestionsTail.js +116 -0
  189. package/dist/request/taskRequest.js +10 -6
  190. package/dist/requestCoordinate.d.ts +1 -0
  191. package/dist/requestCoordinate.js +13 -0
  192. package/dist/resumeRefusalCopy.d.ts +3 -1
  193. package/dist/resumeRefusalCopy.js +12 -4
  194. package/dist/rewindArchiveReading.js +4 -4
  195. package/dist/runCancelContext.d.ts +2 -1
  196. package/dist/runCancelContext.js +1 -0
  197. package/dist/runLedgerSnapshot.js +3 -3
  198. package/dist/runPermissionModeSwitch.js +3 -4
  199. package/dist/scenarioRefusal.js +11 -13
  200. package/dist/scenarioSkills.js +11 -6
  201. package/dist/seam.d.ts +16 -2
  202. package/dist/seam.js +10 -0
  203. package/dist/seatContract.d.ts +259 -9
  204. package/dist/seatContract.js +444 -15
  205. package/dist/sessionCostReading.d.ts +70 -0
  206. package/dist/sessionCostReading.js +150 -0
  207. package/dist/sessionHooksRoster.d.ts +4 -0
  208. package/dist/sessionHooksRoster.js +158 -0
  209. package/dist/sessionIdSegment.d.ts +1 -0
  210. package/dist/sessionIdSegment.js +4 -1
  211. package/dist/sessionMemoryErase.js +2 -1
  212. package/dist/sessionMemoryStatus.js +2 -2
  213. package/dist/sessionReadRedaction.d.ts +7 -0
  214. package/dist/sessionReadRedaction.js +26 -0
  215. package/dist/sessionSyncFileHistory.js +8 -9
  216. package/dist/settingsHooksSalvage.js +2 -1
  217. package/dist/sha256Bytes.d.ts +1 -0
  218. package/dist/sha256Bytes.js +46 -0
  219. package/dist/skillOverrideChain.d.ts +83 -0
  220. package/dist/skillOverrideChain.js +378 -0
  221. package/dist/skillsWireCaps.d.ts +3 -0
  222. package/dist/skillsWireCaps.js +16 -1
  223. package/dist/sseIdleTriage.js +2 -1
  224. package/dist/storeDurabilityWord.d.ts +15 -0
  225. package/dist/storeDurabilityWord.js +18 -0
  226. package/dist/storePostureCapability.d.ts +7 -3
  227. package/dist/storePostureCapability.js +69 -39
  228. package/dist/subagent/engineSubagentResume.js +2 -2
  229. package/dist/subagent/engineSubagentTail.js +2 -1
  230. package/dist/subagentContentStore.d.ts +11 -0
  231. package/dist/subagentContentStore.js +28 -2
  232. package/dist/toolResult.d.ts +1 -0
  233. package/dist/toolResult.js +2 -0
  234. package/dist/turnFailurePresentation.js +4 -10
  235. package/dist/userAttachmentEnvelope.d.ts +2 -1
  236. package/dist/userAttachmentEnvelope.js +10 -0
  237. package/dist/wireErrorTriage.js +2 -1
  238. package/dist/wireFailureShape.d.ts +4 -0
  239. package/dist/wireFailureShape.js +141 -19
  240. package/dist/wireRefusalCopy.d.ts +6 -5
  241. package/dist/wireRefusalCopy.js +49 -92
  242. package/docs/INTEGRATION-CLIENTS.md +2718 -17
  243. package/package.json +7 -3
@@ -9,3 +9,10 @@ export type DeadlineSettled<T> = {
9
9
  kind: 'deadline';
10
10
  };
11
11
  export declare function settleWithinDeadline<T>(ms: number, run: (signal: AbortSignal) => Promise<T>): Promise<DeadlineSettled<T>>;
12
+ export interface RequestDeadline {
13
+ readonly signal: AbortSignal;
14
+ readonly expired: () => boolean;
15
+ readonly abort: () => void;
16
+ readonly race: <T>(p: Promise<T>) => Promise<T>;
17
+ }
18
+ export declare function requestDeadline(ms: number, cancel: AbortSignal | undefined): RequestDeadline;
@@ -50,3 +50,40 @@ export function settleWithinDeadline(ms, run) {
50
50
  pending.then((value) => finish({ kind: 'value', value }), (error) => finish({ kind: 'error', detail: errorDetail(error) }));
51
51
  });
52
52
  }
53
+ const MAX_TIMER_MS = 2_147_483_647;
54
+ export function requestDeadline(ms, cancel) {
55
+ const ctl = new AbortController();
56
+ const stop = new AbortController();
57
+ let expired = false;
58
+ const gone = new Promise((_resolve, reject) => {
59
+ const fire = () => reject(Object.assign(new Error('aborted'), { name: 'AbortError' }));
60
+ if (ctl.signal.aborted)
61
+ fire();
62
+ else
63
+ ctl.signal.addEventListener('abort', fire, { once: true });
64
+ });
65
+ gone.catch(() => undefined);
66
+ void abortableSleep(Math.min(ms, MAX_TIMER_MS), stop.signal).then(() => {
67
+ if (stop.signal.aborted)
68
+ return;
69
+ expired = true;
70
+ ctl.abort();
71
+ });
72
+ const onCancel = () => ctl.abort();
73
+ if (cancel !== undefined) {
74
+ if (cancel.aborted)
75
+ ctl.abort();
76
+ else
77
+ cancel.addEventListener('abort', onCancel, { once: true });
78
+ }
79
+ return {
80
+ signal: ctl.signal,
81
+ expired: () => expired,
82
+ abort: () => {
83
+ stop.abort();
84
+ cancel?.removeEventListener('abort', onCancel);
85
+ ctl.abort();
86
+ },
87
+ race: (p) => Promise.race([p, gone]),
88
+ };
89
+ }
@@ -2,7 +2,7 @@ import { ccToolDenialKindForToolEnd, gateOutcomeOf } from '../gateOutcome.js';
2
2
  import { terminalOwnerOf } from '../seam.js';
3
3
  import { isSubFlowSegmentEnd, SEGMENT_END_IDENTITY_KEYS, snapshotSegmentIdentity, snapshotIsSubFlow } from '../adapter/types.js';
4
4
  import { classifyPeerNotification, renderPeerFrameTranscriptText, sessionBoxNoticeOf } from '../peerFrames.js';
5
- import { dropQueuedNotificationsForRun, freezeTaskNotificationFields, isEngineWorkflowNotified, isWorkflowCompletionCardEnqueued, markEngineWorkflowNotified, noteOwnWorkflowRun, normalizeTaskNotification, noteWorkflowCompletionCardEnqueued, renderTaskNotificationXml, taskNotificationRenderKeys } from '../notifications.js';
5
+ import { dropQueuedNotificationsForRun, freezeTaskNotificationFields, isEngineWorkflowNotified, isWorkflowCompletionCardEnqueued, markEngineWorkflowNotified, noteOwnWorkflowRun, normalizeTaskNotification, noteWorkflowCompletionCardEnqueued, renderTaskNotificationXml, resupplyTruncatedArmBody, settleWorkflowPointerOwed, takeWorkflowPointerSupplement, taskNotificationRenderKeys } from '../notifications.js';
6
6
  import { retryStatusFromArm } from '../retryStatus.js';
7
7
  import { steeringInjectedToAttachments } from '../steering.js';
8
8
  import { projectDiagnosticsFrame } from '../diagnostics.js';
@@ -1015,6 +1015,8 @@ const taskNotificationArm = function* (m, { ctx, idOf, panel, inst, pass }) {
1015
1015
  ...(typeof n.task_type === 'string' ? { taskType: n.task_type } : {}),
1016
1016
  });
1017
1017
  dropQueuedNotificationsForRun(taskId);
1018
+ if (peerFrame === null && n.task_type === 'workflow')
1019
+ settleWorkflowPointerOwed(taskId);
1018
1020
  if (n.task_type !== 'background_bash' && n.task_type !== 'monitor') {
1019
1021
  const bgSessionId = n.task_type === 'background_agent' && typeof n.sessionId === 'string' && n.sessionId.length > 0 ? n.sessionId : undefined;
1020
1022
  yield* panel.settleFromNotification(taskId, isCoreTaskNotificationTerminalNotSuccess(rawStatus), bgSessionId);
@@ -1031,6 +1033,9 @@ const taskNotificationArm = function* (m, { ctx, idOf, panel, inst, pass }) {
1031
1033
  const boxNotice = peerFrame === null ? undefined : sessionBoxNoticeOf(peerFrame);
1032
1034
  if (boxNotice !== undefined)
1033
1035
  yield chrome({ kind: 'session_box_notice', laneProof: mainLane(), ...boxNotice, rowUuid });
1036
+ const truncated = resupplyTruncatedArmBody(n, 'task_notification', taskId);
1037
+ if (truncated !== undefined)
1038
+ yield chrome({ kind: 'resupply_truncated', laneProof: mainLane(), ...truncated });
1034
1039
  yield transcript({
1035
1040
  type: 'user',
1036
1041
  message: {
@@ -1054,13 +1059,26 @@ const workflowCompleteArm = function* (frame) {
1054
1059
  const runId = typeof m.runId === 'string' ? m.runId : undefined;
1055
1060
  if (runId === undefined)
1056
1061
  return;
1057
- if (isEngineWorkflowNotified(runId))
1062
+ const wfStatus = m.status === 'failed' ? 'failed' : 'completed';
1063
+ const extras = workflowCompletionExtrasOf(m);
1064
+ if (isEngineWorkflowNotified(runId)) {
1065
+ const supplement = takeWorkflowPointerSupplement(runId, wfStatus, extras.diagnostics, extras.completionId);
1066
+ if (supplement === undefined)
1067
+ return;
1068
+ yield chrome({
1069
+ kind: 'workflow_notification_enqueue',
1070
+ laneProof: mainLane(),
1071
+ runId,
1072
+ status: wfStatus,
1073
+ summary: supplement.summary,
1074
+ message: renderTaskNotificationXml(supplement),
1075
+ notification: supplement,
1076
+ });
1058
1077
  return;
1078
+ }
1059
1079
  markEngineWorkflowNotified(runId);
1060
- const wfStatus = m.status === 'failed' ? 'failed' : 'completed';
1061
1080
  const wfSummary = typeof m.summary === 'string' ? m.summary : '';
1062
1081
  noteWorkflowCompletionCardEnqueued(runId);
1063
- const extras = workflowCompletionExtrasOf(m);
1064
1082
  const notification = freezeTaskNotificationFields({ taskId: runId, taskType: 'workflow', status: wfStatus, summary: wfSummary, ...(extras.completionId !== undefined ? { completionId: extras.completionId } : {}) });
1065
1083
  yield chrome({
1066
1084
  kind: 'workflow_notification_enqueue',
@@ -1072,6 +1090,9 @@ const workflowCompleteArm = function* (frame) {
1072
1090
  notification,
1073
1091
  ...(extras.diagnostics !== undefined ? { diagnostics: extras.diagnostics } : {}),
1074
1092
  });
1093
+ const truncated = resupplyTruncatedArmBody(m, 'workflow_complete', runId);
1094
+ if (truncated !== undefined)
1095
+ yield chrome({ kind: 'resupply_truncated', laneProof: mainLane(), ...truncated });
1075
1096
  };
1076
1097
  const retryStatusArm = function* (m, { ctx, flags }) {
1077
1098
  const status = retryStatusFromArm(m, ctx.now());
@@ -2,6 +2,7 @@ import type { AdapterContext, AdapterOutput } from '../seam.js';
2
2
  import { structuredToToolUseResult, type ToolKillCause, type ToolResultBody } from '../toolResult.js';
3
3
  import { type Frame, type IdOf } from './ids.js';
4
4
  import type { EngineRowRef } from '../engineRowRef.js';
5
+ import { SEMA_REFUSAL_NOTED_KEY } from '../engineRowRef.js';
5
6
  import { type GateOutcomeView, type ToolInputRewriteView } from '../gateOutcome.js';
6
7
  type RichToolUseResult = NonNullable<ReturnType<typeof structuredToToolUseResult>>;
7
8
  export interface ToolResultOutcome {
@@ -37,10 +38,11 @@ export interface ToolResultRowFlagParts {
37
38
  readonly _sema_interrupted_never_started?: true;
38
39
  readonly _sema_approval_window_expired?: true;
39
40
  readonly _sema_denial_limit_window_expired?: true;
41
+ readonly [SEMA_REFUSAL_NOTED_KEY]?: true;
40
42
  readonly _sema_answered_by?: string;
41
43
  readonly _sema_rewrite?: ToolInputRewriteView;
42
44
  }
43
- export declare function toolResultRowFlagParts(arm: object | null | undefined, gate: GateOutcomeView | undefined): ToolResultRowFlagParts;
45
+ export declare function toolResultRowFlagParts(arm: object | null | undefined, gate: GateOutcomeView | undefined, denialKind: string | undefined): ToolResultRowFlagParts;
44
46
  interface ToolEndPayload {
45
47
  output?: unknown;
46
48
  structured?: unknown;
@@ -1,6 +1,7 @@
1
1
  import { deriveTranscriptId } from '../seam.js';
2
2
  import { degradedToolResultBody, detectEngineBgShellDetach, detectEngineBgShellReceipt, reportFindingsToolUseResult, structuredToToolUseResult, todoWriteToolUseResult, wireOutputToBody, } from '../toolResult.js';
3
3
  import { chrome, mainLane, transcript } from './ids.js';
4
+ import { refusalNotedOf, SEMA_REFUSAL_NOTED_KEY } from '../engineRowRef.js';
4
5
  import { flattenWireOutput } from './wireShapes.js';
5
6
  import { toolResultBlocksOf } from '../toolResultContent.js';
6
7
  import { bashExitOf, bashExitReadingFailed } from '../bashExitReading.js';
@@ -53,7 +54,7 @@ export function toolResultRowIdentity(sources, toolCallId, ctx) {
53
54
  }
54
55
  return { uuid: deriveTranscriptId({ toolCallId }, ctx) };
55
56
  }
56
- export function toolResultRowFlagParts(arm, gate) {
57
+ export function toolResultRowFlagParts(arm, gate, denialKind) {
57
58
  if (arm === null || arm === undefined)
58
59
  return {};
59
60
  const notExecuted = readFrameTrueMark(arm, 'notExecuted');
@@ -65,6 +66,7 @@ export function toolResultRowFlagParts(arm, gate) {
65
66
  ...(readFrameStringKey(arm, 'errorCode') === TOOL_END_INTERRUPTED_NEVER_STARTED ? { _sema_interrupted_never_started: true } : {}),
66
67
  ...(isApprovalWindowExpiredGate(gate) ? { _sema_approval_window_expired: true } : {}),
67
68
  ...(isDenialLimitAutoDeniedGate(gate) ? { _sema_denial_limit_window_expired: true } : {}),
69
+ ...(refusalNotedOf(denialKind, gate) ? { [SEMA_REFUSAL_NOTED_KEY]: true } : {}),
68
70
  ...(answeredBy !== undefined ? { _sema_answered_by: answeredBy } : {}),
69
71
  ...(rewrite !== undefined ? { _sema_rewrite: rewrite } : {}),
70
72
  };
@@ -126,7 +128,7 @@ export function createToolCardLedger(ctx, idOf) {
126
128
  ...toolResultEnvelopeParts(outcome),
127
129
  ...(isCcToolDenialKind(end?.denialKind) ? { _sema_denial_kind: end.denialKind } : {}),
128
130
  ...(end?.gate !== undefined ? { _sema_gate: end.gate } : {}),
129
- ...toolResultRowFlagParts(end?.closeArm, end?.gate),
131
+ ...toolResultRowFlagParts(end?.closeArm, end?.gate, end?.denialKind),
130
132
  }, ctx.now());
131
133
  }
132
134
  function* closeCard(p, end) {
@@ -94,6 +94,7 @@ export interface ActiveRunSelfHealDeps {
94
94
  submissionOrigin?: RejectedSubmissionOrigin;
95
95
  injectedCarriers?: readonly object[];
96
96
  sessionId?: string;
97
+ stillHere?: () => boolean | undefined;
97
98
  wasRecentlyTerminatedByUs?: (taskId: string) => boolean;
98
99
  interruptedSettle?: InterruptedSettleWindow;
99
100
  }
@@ -135,6 +136,14 @@ export type SelfHealOutcome = {
135
136
  kind: 'interrupted-settled';
136
137
  taskId: string;
137
138
  status: string;
139
+ } | {
140
+ kind: 'resend-withheld-left';
141
+ taskId: string;
142
+ releaseConfirmedByEngine?: true;
143
+ } | {
144
+ kind: 'resend-withheld-unconfirmed';
145
+ taskId: string;
146
+ releaseConfirmedByEngine?: true;
138
147
  } | {
139
148
  kind: 'interrupted-still-finishing';
140
149
  taskId: string;
@@ -252,6 +261,14 @@ export interface SelfHealFollowDeclaration {
252
261
  following?: boolean;
253
262
  }
254
263
  export declare function injectedResubmitAfter(outcome: SelfHealOutcome | null | undefined, runStatus: string | null | undefined): boolean;
264
+ export type InjectedResubmitWaitVerdict = 'resubmit' | 'gave-up' | 'left' | 'unconfirmed';
265
+ export interface InjectedResubmitWaitDeps extends Pick<ActiveRunSelfHealDeps, 'sessionId' | 'stillHere'> {
266
+ runs: () => DurableRunVerbs | undefined;
267
+ budgetMs?: number;
268
+ sleep?: (ms: number) => Promise<void>;
269
+ now?: () => number;
270
+ }
271
+ export declare function waitForInjectedResubmit(outcome: SelfHealOutcome | null | undefined, deps: InjectedResubmitWaitDeps): Promise<InjectedResubmitWaitVerdict>;
255
272
  export declare function readCancelRequested(body: unknown): boolean | undefined;
256
273
  export { atMostOnceFailureClass };
257
274
  export declare function clearRunningChoiceOffer(taskId: string, sessionId?: string): void;
@@ -272,6 +289,10 @@ export interface ClaimReleaseWaitDeps {
272
289
  session?: string;
273
290
  }
274
291
  export declare function waitForClaimRelease(taskId: string, deps: ClaimReleaseWaitDeps): Promise<ClaimReleaseVerdict>;
292
+ export type ConversationPresence = 'here' | 'left' | 'unconfirmed';
293
+ export declare function conversationLeftOf(deps: {
294
+ readonly stillHere?: () => boolean | undefined;
295
+ } | null | undefined): ConversationPresence;
275
296
  export declare function attemptActiveRunSelfHeal(signal: ActiveRunBusySignal, runs: DurableRunVerbs | undefined, deps?: ActiveRunSelfHealDeps): Promise<SelfHealOutcome>;
276
297
  export interface ActiveRunSelfHealCopy {
277
298
  wayOut?: string;
@@ -285,4 +306,22 @@ export interface ActiveRunSelfHealCopy {
285
306
  }
286
307
  export declare const INTERACTIVE_WAY_OUT: string;
287
308
  export declare function activeRunSelfHealRow(outcome: SelfHealOutcome, signal?: ActiveRunBusySignal | null, copy?: ActiveRunSelfHealCopy, origin?: RejectedSubmissionOrigin, follow?: SelfHealFollowDeclaration, lang?: UiLanguage): string;
309
+ export type ConversationLeftStopResult = {
310
+ kind: 'untouched';
311
+ } | {
312
+ kind: 'waiting';
313
+ certain: boolean;
314
+ } | {
315
+ kind: 'ended';
316
+ confirmedByEngine: boolean;
317
+ } | {
318
+ kind: 'nothing-to-end';
319
+ } | {
320
+ kind: 'refused';
321
+ detail: string;
322
+ } | {
323
+ kind: 'not-confirmed';
324
+ };
325
+ export declare function conversationLeftStopResultOf(outcome: SelfHealOutcome | null | undefined): ConversationLeftStopResult;
326
+ export declare function conversationLeftStopRow(result: ConversationLeftStopResult, taskId: string, copy?: ActiveRunSelfHealCopy, lang?: UiLanguage): string;
288
327
  export declare function activeRunBusyHeadlessRow(signal: ActiveRunBusySignal, copy?: ActiveRunSelfHealCopy, lang?: UiLanguage): string;
@@ -1,10 +1,12 @@
1
1
  import { abortableSleep } from '../abortableSleep.js';
2
+ import { unrefTimer } from '../unrefTimer.js';
2
3
  import { EN_MESSAGES } from '../i18n/messages.en.js';
3
4
  import { msg, renderMessage } from '../i18n/translate.js';
4
5
  import { registeredPlanReviewCardFacts } from '../planReviewCardFacts.js';
5
6
  import { DEFAULT_SESSION_KEY } from '../sessionSlot.js';
6
7
  import { ASK_PARK_AUTO_REOPEN_BLOCKS, askParkAutoReopenBlockedContent } from '../hitl/askParkAutoReopenBlock.js';
7
8
  import { corruptStoredRowContent, corruptStoredRowWhere, effectiveWireErrorCode } from '../wireErrorTriage.js';
9
+ import { STEERING_NOT_RUNNING } from '../engineErrorCodes.js';
8
10
  import { readThrownStatusSlot, slotReadOf } from '../wireFailureShape.js';
9
11
  import { checkpointDeadlineStateOf, checkpointRowBarOf, checkpointRowBarSentence, rowBarWayOutContent } from '../checkpointRowVerdict.js';
10
12
  import { guardedRead, readOwnDataNonEmptyString, readOwnDataValue } from '../ownKey.js';
@@ -76,6 +78,9 @@ export function selfHealSubmissionDisposition(outcome) {
76
78
  return 'superseded';
77
79
  case 'injected-deferred':
78
80
  return 'deferred';
81
+ case 'resend-withheld-left':
82
+ case 'resend-withheld-unconfirmed':
83
+ return 'not-delivered';
79
84
  default:
80
85
  return 'not-delivered';
81
86
  }
@@ -110,6 +115,54 @@ export function injectedResubmitAfter(outcome, runStatus) {
110
115
  return false;
111
116
  }
112
117
  }
118
+ const INJECTED_RESUBMIT_WAIT_BUDGET_MS = 30 * 60_000;
119
+ const INJECTED_RESUBMIT_READ_STEPS_MS = Object.freeze([500, 1_000, 2_000, 4_000, 8_000]);
120
+ function injectedResubmitSleep(ms) {
121
+ return new Promise((resolve) => {
122
+ unrefTimer(setTimeout(resolve, ms));
123
+ });
124
+ }
125
+ async function readDeferredRunStatus(deps, taskId) {
126
+ try {
127
+ const verbs = deps.runs();
128
+ const get = verbs?.get;
129
+ if (typeof get !== 'function')
130
+ return null;
131
+ return readStatusGuarded(await get.call(verbs, taskId, sessionOpts(deps)));
132
+ }
133
+ catch {
134
+ return null;
135
+ }
136
+ }
137
+ export async function waitForInjectedResubmit(outcome, deps) {
138
+ try {
139
+ if (typeof outcome !== 'object' || outcome === null || outcome.kind !== 'injected-deferred')
140
+ return 'gave-up';
141
+ if (typeof deps?.runs !== 'function' || typeof deps.runs()?.get !== 'function')
142
+ return 'gave-up';
143
+ const now = typeof deps.now === 'function' ? deps.now : () => Date.now();
144
+ const sleep = typeof deps.sleep === 'function' ? deps.sleep : injectedResubmitSleep;
145
+ const budgetMs = typeof deps.budgetMs === 'number' && Number.isFinite(deps.budgetMs) && deps.budgetMs >= 0 ? deps.budgetMs : INJECTED_RESUBMIT_WAIT_BUDGET_MS;
146
+ const startedAt = now();
147
+ for (let attempt = 0;; attempt++) {
148
+ const before = conversationLeftOf(deps);
149
+ if (before !== 'here')
150
+ return before;
151
+ const status = await readDeferredRunStatus(deps, outcome.taskId);
152
+ const after = conversationLeftOf(deps);
153
+ if (after !== 'here')
154
+ return after;
155
+ if (injectedResubmitAfter(outcome, status))
156
+ return 'resubmit';
157
+ if (now() - startedAt >= budgetMs)
158
+ return 'gave-up';
159
+ await sleep(INJECTED_RESUBMIT_READ_STEPS_MS[Math.min(attempt, INJECTED_RESUBMIT_READ_STEPS_MS.length - 1)] ?? 8_000);
160
+ }
161
+ }
162
+ catch {
163
+ return 'gave-up';
164
+ }
165
+ }
113
166
  const PLAN_REVIEW_CARRIER_KEY = '_sema_planReviewOutcome';
114
167
  function planReviewCarrierOf(item) {
115
168
  const meta = guardedRead(() => (typeof item === 'object' && item !== null && !Array.isArray(item) ? readOwnDataValue(item, PLAN_REVIEW_CARRIER_KEY) : undefined));
@@ -589,7 +642,40 @@ async function interruptedShortCircuitUnguarded(signal, runs, deps) {
589
642
  return { kind: 'interrupted-still-finishing', taskId, waitedMs: verdict.waitedMs };
590
643
  return null;
591
644
  }
645
+ export function conversationLeftOf(deps) {
646
+ if (typeof deps !== 'object' || deps === null)
647
+ return 'here';
648
+ let port;
649
+ try {
650
+ port = deps.stillHere;
651
+ }
652
+ catch {
653
+ return 'unconfirmed';
654
+ }
655
+ if (typeof port !== 'function')
656
+ return 'here';
657
+ try {
658
+ const answer = port.call(deps);
659
+ return answer === true ? 'here' : answer === false ? 'left' : 'unconfirmed';
660
+ }
661
+ catch {
662
+ return 'unconfirmed';
663
+ }
664
+ }
592
665
  export async function attemptActiveRunSelfHeal(signal, runs, deps) {
666
+ const outcome = await triageActiveRun(signal, runs, deps);
667
+ if (selfHealSubmissionDisposition(outcome) !== 'resending' || typeof outcome.taskId !== 'string')
668
+ return outcome;
669
+ const presence = conversationLeftOf(deps);
670
+ if (presence === 'here')
671
+ return outcome;
672
+ return {
673
+ kind: presence === 'left' ? 'resend-withheld-left' : 'resend-withheld-unconfirmed',
674
+ taskId: outcome.taskId,
675
+ ...('releaseConfirmedByEngine' in outcome && outcome.releaseConfirmedByEngine === true ? { releaseConfirmedByEngine: true } : {}),
676
+ };
677
+ }
678
+ async function triageActiveRun(signal, runs, deps) {
593
679
  const interrupted = await interruptedShortCircuit(signal, runs, deps);
594
680
  if (interrupted !== null)
595
681
  return interrupted;
@@ -989,7 +1075,7 @@ async function runningChoiceArm(taskId, status, busy, statusFromWire, runs, carr
989
1075
  const delivery = atMostOnceFailureClass(e);
990
1076
  const errorCode = failureWireCode(e);
991
1077
  let runStatus;
992
- if (delivery === 'rejected' && errorCode === STEER_NOT_RUNNING_CODE && typeof runs.get === 'function' && !probeCallerAborted()) {
1078
+ if (delivery === 'rejected' && errorCode === STEERING_NOT_RUNNING && typeof runs.get === 'function' && !probeCallerAborted()) {
993
1079
  const probe = await probeRunStatusOnce(taskId, runs, runs.get, deps);
994
1080
  if (probe.status !== null)
995
1081
  runStatus = probe.status;
@@ -1080,7 +1166,6 @@ function wakeSessionClause(copy, lang) {
1080
1166
  return say(lang, 'session.selfHeal.wakeOn.host', { where: host.trim() });
1081
1167
  return say(lang, 'session.selfHeal.wakeOn.engine');
1082
1168
  }
1083
- const STEER_NOT_RUNNING_CODE = 'steering.not_running';
1084
1169
  function decidePathClause(signal, lang) {
1085
1170
  const decidePath = signal?.pendingGate?.decidePath;
1086
1171
  if (!decidePath)
@@ -1164,6 +1249,13 @@ function injectedSubmissionRow(outcome, following = false, lang) {
1164
1249
  }
1165
1250
  if (outcome.kind === 'interrupted-still-finishing')
1166
1251
  return say(lang, 'session.selfHeal.injected.interruptedFinishing', { lead, id });
1252
+ if (outcome.kind === 'resend-withheld-left') {
1253
+ return outcome.releaseConfirmedByEngine === true
1254
+ ? say(lang, 'session.selfHeal.injected.resendWithheldLeftConfirmed', { lead, id })
1255
+ : say(lang, 'session.selfHeal.injected.resendWithheldLeftInferred', { lead, id });
1256
+ }
1257
+ if (outcome.kind === 'resend-withheld-unconfirmed')
1258
+ return say(lang, 'session.selfHeal.injected.resendWithheldUnconfirmed', { lead });
1167
1259
  switch (selfHealSubmissionDisposition(outcome)) {
1168
1260
  case 'held-for-decision':
1169
1261
  return say(lang, 'session.selfHeal.injected.heldForDecision', { lead, id });
@@ -1291,7 +1383,7 @@ function activeRunSelfHealBaseRow(outcome, wayOut, following = false, keepSessio
1291
1383
  });
1292
1384
  }
1293
1385
  case 'running-steer-failed':
1294
- if (outcome.delivery === 'rejected' && outcome.errorCode === STEER_NOT_RUNNING_CODE && outcome.runStatus !== undefined && isSdkRunTerminal(outcome.runStatus)) {
1386
+ if (outcome.delivery === 'rejected' && outcome.errorCode === STEERING_NOT_RUNNING && outcome.runStatus !== undefined && isSdkRunTerminal(outcome.runStatus)) {
1295
1387
  return say(lang, 'session.selfHeal.row.steerFailed.runEnded', { taskId: outcome.taskId, status: outcome.runStatus });
1296
1388
  }
1297
1389
  return outcome.delivery === 'rejected'
@@ -1306,6 +1398,12 @@ function activeRunSelfHealBaseRow(outcome, wayOut, following = false, keepSessio
1306
1398
  return outcome.releaseConfirmedByEngine === true
1307
1399
  ? say(lang, 'session.selfHeal.row.cancelled.confirmed', { taskId: outcome.taskId })
1308
1400
  : say(lang, 'session.selfHeal.row.cancelled.reported', { taskId: outcome.taskId });
1401
+ case 'resend-withheld-left':
1402
+ return outcome.releaseConfirmedByEngine === true
1403
+ ? say(lang, 'session.selfHeal.row.resendWithheldLeft.confirmed', { taskId: outcome.taskId })
1404
+ : say(lang, 'session.selfHeal.row.resendWithheldLeft.reported', { taskId: outcome.taskId });
1405
+ case 'resend-withheld-unconfirmed':
1406
+ return say(lang, 'session.selfHeal.row.resendWithheldUnconfirmed');
1309
1407
  case 'running-cancel-timeout': {
1310
1408
  const waited = `${String(Math.max(1, Math.round(outcome.waitedMs / 1000)))}s`;
1311
1409
  if (outcome.aborted)
@@ -1377,6 +1475,76 @@ function activeRunSelfHealBaseRow(outcome, wayOut, following = false, keepSessio
1377
1475
  });
1378
1476
  }
1379
1477
  }
1478
+ export function conversationLeftStopResultOf(outcome) {
1479
+ if (typeof outcome !== 'object' || outcome === null)
1480
+ return { kind: 'untouched' };
1481
+ switch (outcome.kind) {
1482
+ case 'running-cancelled':
1483
+ case 'stale-park-cancelled':
1484
+ case 'ask-decided-without-card':
1485
+ case 'resend-withheld-left':
1486
+ case 'resend-withheld-unconfirmed':
1487
+ return { kind: 'ended', confirmedByEngine: outcome.releaseConfirmedByEngine === true };
1488
+ case 'running-cancel-timeout':
1489
+ case 'stale-park-cancel-timeout':
1490
+ case 'ask-decided-release-unknown':
1491
+ case 'interrupted-still-finishing':
1492
+ return { kind: 'not-confirmed' };
1493
+ case 'running-cancel-failed':
1494
+ case 'stale-park-cancel-failed':
1495
+ return outcome.delivery === 'rejected' ? { kind: 'refused', detail: outcome.detail } : { kind: 'not-confirmed' };
1496
+ case 'running-settled':
1497
+ case 'running-not-found':
1498
+ case 'ask-run-not-found':
1499
+ case 'ask-run-settled':
1500
+ case 'interrupted-settled':
1501
+ return { kind: 'nothing-to-end' };
1502
+ case 'not-parked':
1503
+ return isSdkRunTerminal(outcome.status) ? { kind: 'nothing-to-end' } : { kind: 'untouched' };
1504
+ case 'ask-reopened':
1505
+ case 'plan-review-reopened':
1506
+ case 'decision-pending':
1507
+ return { kind: 'waiting', certain: true };
1508
+ case 'ask-reopen-failed':
1509
+ case 'plan-review-reopen-failed':
1510
+ return { kind: 'waiting', certain: false };
1511
+ case 'state-unknown':
1512
+ case 'stale-park-wait':
1513
+ case 'running-steered':
1514
+ case 'running-steer-failed':
1515
+ case 'running-attach':
1516
+ case 'injected-redundant':
1517
+ case 'injected-deferred':
1518
+ return { kind: 'untouched' };
1519
+ }
1520
+ }
1521
+ export function conversationLeftStopRow(result, taskId, copy, lang) {
1522
+ const endRun = endRunClause(copy, taskId, lang, 'interactive');
1523
+ try {
1524
+ switch (result.kind) {
1525
+ case 'untouched':
1526
+ break;
1527
+ case 'waiting':
1528
+ return result.certain === true
1529
+ ? say(lang, 'session.selfHeal.stopLeft.waiting.certain', { taskId })
1530
+ : say(lang, 'session.selfHeal.stopLeft.waiting.uncertain', { taskId, endRun });
1531
+ case 'ended':
1532
+ return result.confirmedByEngine === true
1533
+ ? say(lang, 'session.selfHeal.stopLeft.ended.confirmed', { taskId })
1534
+ : say(lang, 'session.selfHeal.stopLeft.ended.reported', { taskId });
1535
+ case 'nothing-to-end':
1536
+ return say(lang, 'session.selfHeal.stopLeft.nothingToEnd', { taskId });
1537
+ case 'refused':
1538
+ return say(lang, 'session.selfHeal.stopLeft.refused', { taskId, detail: typeof result.detail === 'string' ? result.detail : '', endRun });
1539
+ case 'not-confirmed':
1540
+ return say(lang, 'session.selfHeal.stopLeft.notConfirmed', { taskId, endRun });
1541
+ }
1542
+ }
1543
+ catch {
1544
+ return say(lang, 'session.selfHeal.stopLeft.untouched', { taskId, endRun });
1545
+ }
1546
+ return say(lang, 'session.selfHeal.stopLeft.untouched', { taskId, endRun });
1547
+ }
1380
1548
  export function activeRunBusyHeadlessRow(signal, copy, lang) {
1381
1549
  const override = copy?.headlessRowFor?.(signal);
1382
1550
  if (typeof override === 'string')
@@ -5,17 +5,16 @@ import { ccToolDenialKindForToolEnd, gateOutcomeOf, toolInputRewriteOf } from '.
5
5
  import { projectToolRoster, projectToolRosterDelta } from '../../toolRoster.js';
6
6
  import { projectHandsSection } from '../../handsSeam.js';
7
7
  import { readMcpAuthorization, readMcpLiveness } from '../../mcpLiveness.js';
8
- import { contextUsageReadingOf, humanInputAttachmentsOf, guardedRead, markMcpSectionDroppedNamedRows, ownSnapshotTyped, promptManifestIdentityOfFrame, promptManifestSectionViewOf, readFrameStringKey, readFrameTrueMark, readOwnDataFiniteNumber, readOwnDataNonEmptyString, workflowCompletionExtrasOf } from '../../ownKey.js';
8
+ import { contextUsageReadingOf, humanInputAttachmentsOf, guardedRead, markMcpSectionDroppedNamedRows, ownSnapshotTyped, promptManifestIdentityOfFrame, promptManifestSectionViewOf, readFrameStringKey, readFrameTrueMark, readOwnDataFiniteNumber, readOwnDataNonEmptyString, resupplyTruncatedOf, workflowCompletionExtrasOf } from '../../ownKey.js';
9
9
  import { humanInputAuthorKeys, runOriginKeys } from '../../inputAuthor.js';
10
10
  import { SEGMENT_END_IDENTITY_KEYS, eventSeq, stripToolUseSideChannels } from '../types.js';
11
+ import { promptSuggestionBatchOf } from '../../promptSuggestionBatch.js';
11
12
  import { frozenSet } from '../../frozenSet.js';
12
13
  import { isCoreWorkflowRunTerminal } from '../../terminalStatuses.js';
13
14
  import { envelopeUuidOf, mintEngineRowRef, readBoundRun, wireEventIdOf } from '../../engineRowRef.js';
14
15
  function armBody(body) {
15
16
  return body;
16
17
  }
17
- const SUGGESTION_BATCH_CAP = 8;
18
- const SUGGESTION_CHARS_CAP = 200;
19
18
  export const INTERNAL_SDK_ARM_TYPES = frozenSet([
20
19
  'tool_disclosure',
21
20
  'tool_progress',
@@ -174,6 +173,10 @@ function projectEvent(ev, ctx) {
174
173
  status: wf.status,
175
174
  summary: typeof wf.summary === 'string' ? wf.summary : '',
176
175
  ...workflowCompletionExtrasOf(wf),
176
+ ...(() => {
177
+ const t = resupplyTruncatedOf(wf);
178
+ return t === undefined ? {} : { payloadTruncated: { bytes: t.bytes, droppedKeys: [...t.droppedKeys] } };
179
+ })(),
177
180
  })));
178
181
  }
179
182
  case 'text':
@@ -403,16 +406,13 @@ function projectEvent(ev, ctx) {
403
406
  })));
404
407
  }
405
408
  case 'suggestions': {
406
- const filtered = (Array.isArray(ev.suggestions) ? ev.suggestions : []).filter((s) => typeof s === 'string' && s.trim().length > 0);
407
- const list = filtered
408
- .slice(0, SUGGESTION_BATCH_CAP)
409
- .map((s) => (s.length > SUGGESTION_CHARS_CAP ? `${s.slice(0, SUGGESTION_CHARS_CAP)}…` : s));
410
- if (list.length === 0)
409
+ const batch = promptSuggestionBatchOf(ev.suggestions);
410
+ if (batch === undefined)
411
411
  return nothing('empty_payload');
412
412
  return projected(stamp(ctx, armBody({
413
413
  type: 'prompt_suggestions',
414
- suggestions: list,
415
- ...(filtered.length > list.length ? { truncatedCount: filtered.length - list.length } : {}),
414
+ suggestions: [...batch.list],
415
+ ...(batch.truncatedCount !== undefined ? { truncatedCount: batch.truncatedCount } : {}),
416
416
  })));
417
417
  }
418
418
  case 'turn_end':
@@ -5,6 +5,7 @@ import type { SDKPermissionDenial, SDKResultError, SDKResultSuccess, TerminalRea
5
5
  import { type RunTerminalCodedDetail, type RunTerminalRead } from '../../runTerminal.js';
6
6
  import { type SemaModelUsage } from './turnUsageToModelUsage.js';
7
7
  import { type ResultLimitWord } from '../../engineErrorCodes.js';
8
+ import type { RunCostSettlement } from '../../sessionCostReading.js';
8
9
  import { type ResultWayOutFacts } from '../../providerRejection.js';
9
10
  export interface SemaFlatUsage {
10
11
  readonly inputTokens: number;
@@ -89,6 +90,7 @@ export interface RunCostFacts {
89
90
  export declare function readRunCostFacts(stats: TaskStats | undefined, observed?: {
90
91
  readonly usageMissingObserved?: boolean;
91
92
  }): RunCostFacts | undefined;
93
+ export declare function runCostSettlementOf(stats: TaskStats | undefined): Exclude<RunCostSettlement, 'awaiting'>;
92
94
  export interface ObservedTerminalParts extends PermissionDenialParts {
93
95
  readonly _sema_usage_lower_bound?: true;
94
96
  }
@@ -261,6 +261,17 @@ export function readRunCostFacts(stats, observed) {
261
261
  reconcile,
262
262
  };
263
263
  }
264
+ export function runCostSettlementOf(stats) {
265
+ try {
266
+ const facts = readRunCostFacts(stats);
267
+ if (facts === undefined)
268
+ return 'lost';
269
+ return facts.reconcile.ownMicroUsd !== undefined ? 'priced' : 'unpriced';
270
+ }
271
+ catch {
272
+ return 'lost';
273
+ }
274
+ }
264
275
  function structuredOutputParts(r) {
265
276
  const so = r.structuredOutput;
266
277
  return so !== undefined ? { structured_output: so } : {};
@@ -5,6 +5,7 @@ import type { ObservedTerminalParts } from './downstream/terminalToSdkResult.js'
5
5
  import { type ToolHistoryErrorCarrier } from '../toolHistoryMismatch.js';
6
6
  import { MODEL_OUTPUT_ERROR_PREFIX, OUTCOME_UNKNOWN_ROW_PREFIX, RUN_BLOCKED_MESSAGE_PREFIX, RUN_STOPPED_MESSAGE_PREFIX } from '../rowKind.js';
7
7
  export { MODEL_OUTPUT_ERROR_PREFIX, OUTCOME_UNKNOWN_ROW_PREFIX, RUN_BLOCKED_MESSAGE_PREFIX, RUN_STOPPED_MESSAGE_PREFIX };
8
+ import { type PlanReviewCardFacts } from '../planReviewCardFacts.js';
8
9
  export interface ActiveRunPendingGate {
9
10
  readonly kind: string | null;
10
11
  readonly decidePath: string | null;
@@ -37,5 +38,9 @@ export interface RunStreamHandle {
37
38
  latestUsageMissing?: true;
38
39
  observedTerminalParts?: () => ObservedTerminalParts;
39
40
  }
41
+ export interface PlanReviewFrameClaim {
42
+ feed(frame: {} | null | undefined): PlanReviewCardFacts | undefined;
43
+ }
44
+ export declare function openPlanReviewFrameClaim(): PlanReviewFrameClaim;
40
45
  export declare function isRunStreamActive(): boolean;
41
46
  export declare function runStream(events: AsyncIterable<AgentEvent>, ctx: EmitContext, handle?: RunStreamHandle): AsyncGenerator<SDKMessage>;
@@ -20,7 +20,7 @@ import { MODEL_OUTPUT_ERROR_PREFIX, OUTCOME_UNKNOWN_ROW_PREFIX, RUN_BLOCKED_MESS
20
20
  export { MODEL_OUTPUT_ERROR_PREFIX, OUTCOME_UNKNOWN_ROW_PREFIX, RUN_BLOCKED_MESSAGE_PREFIX, RUN_STOPPED_MESSAGE_PREFIX };
21
21
  import { ccToolDenialKindForToolEnd, gateDeniedBy, gateOutcomeOf } from '../gateOutcome.js';
22
22
  import { resumeReopenContent, resumeReopenFromError, suspendedReopenOf } from '../hitl/suspendedReopen.js';
23
- import { openPlanBodyClaimLeg, planReviewParkFacts, stepPlanBodyClaim } from '../planReviewCardFacts.js';
23
+ import { openPlanBodyClaimLeg, planReviewClaimStep } from '../planReviewCardFacts.js';
24
24
  import { isCcToolDenialKind, isCcToolDenialKindADenial, isGateDeniedByWord } from '../gateVocabulary.js';
25
25
  const ENGINE_TURN_USAGE_KEYS = Object.freeze(['inputTokens', 'totalInputTokens', 'outputTokens', 'cacheReadTokens', 'cacheWriteTokens', 'costMicroUsd']);
26
26
  const _engineTurnUsageKeysPin = true;
@@ -454,6 +454,18 @@ function wireFrameIsSubFlow(ev) {
454
454
  });
455
455
  return snap === undefined || snapshotIsSubFlow(snap);
456
456
  }
457
+ export function openPlanReviewFrameClaim() {
458
+ const leg = openPlanBodyClaimLeg();
459
+ return Object.freeze({
460
+ feed(frame) {
461
+ if (typeof frame !== 'object' || frame === null)
462
+ return undefined;
463
+ const subFlow = wireFrameIsSubFlow(frame);
464
+ const seq = guardedRead(() => eventSeq(frame));
465
+ return planReviewClaimStep(leg, frame, subFlow, seq);
466
+ },
467
+ });
468
+ }
457
469
  function withStringFailureFields(ev) {
458
470
  if (ev.type !== 'failed')
459
471
  return ev;
@@ -592,7 +604,7 @@ async function* runStreamInner(events, ctx, handle = {}) {
592
604
  }
593
605
  seen.add(seq);
594
606
  }
595
- stepPlanBodyClaim(planLeg, ev, wireSubFlow);
607
+ const planReviewAtTerminal = planReviewClaimStep(planLeg, ev, wireSubFlow, seq);
596
608
  if (ev.type === 'tool_start') {
597
609
  const callId = ev.toolCallId;
598
610
  if (typeof callId === 'string' && callId.length > 0 && !toolInputAmbiguous.has(callId)) {
@@ -855,7 +867,7 @@ async function* runStreamInner(events, ctx, handle = {}) {
855
867
  accepted: ev.type === 'done' && (doneTerminal?.kind === 'completed' || doneTerminal?.kind === 'paused'),
856
868
  }).acceptedSinceMismatch;
857
869
  }
858
- const planReview = ev.type === 'done' ? planReviewParkFacts(planLeg, engineResultOf(ev.result)) : undefined;
870
+ const planReview = planReviewAtTerminal;
859
871
  if (ev.type === 'done' && isReviewPark(doneTerminal) && ctx.emitChrome) {
860
872
  try {
861
873
  await ctx.emitChrome({ kind: 'plan_review_park', laneProof: mainLane(), result: ev.result, ...(planReview !== undefined ? { planReview } : {}) });