@sema-agent/client-core 0.109.0 → 0.111.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 (236) hide show
  1. package/CHANGELOG.md +342 -0
  2. package/README.md +88 -32
  3. package/dist/abortableSleep.d.ts +7 -0
  4. package/dist/abortableSleep.js +37 -0
  5. package/dist/adapt/arms.js +45 -11
  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 +20 -15
  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/attachmentRoute.d.ts +20 -0
  16. package/dist/attachmentRoute.js +39 -0
  17. package/dist/attachmentsWireCaps.js +1 -1
  18. package/dist/builtinOutputStyles.d.ts +12 -0
  19. package/dist/builtinOutputStyles.js +147 -0
  20. package/dist/compactionStatus.d.ts +9 -0
  21. package/dist/compactionStatus.js +29 -5
  22. package/dist/controlRouter.js +2 -1
  23. package/dist/coreValuePorts.d.ts +39 -1
  24. package/dist/coreValuePorts.js +10 -0
  25. package/dist/declared/supportFloorDeclared.js +1 -1
  26. package/dist/displayUntrusted.d.ts +1 -0
  27. package/dist/displayUntrusted.js +138 -14
  28. package/dist/engineErrorCodes.d.ts +3 -0
  29. package/dist/engineErrorCodes.js +3 -0
  30. package/dist/engineHealthFacts.d.ts +20 -0
  31. package/dist/engineHealthFacts.js +42 -1
  32. package/dist/engineHealthProbeVerdict.d.ts +23 -0
  33. package/dist/engineHealthProbeVerdict.js +115 -0
  34. package/dist/engineInlineTaskStats.d.ts +4 -3
  35. package/dist/engineInlineTaskStats.js +18 -2
  36. package/dist/engineNoticeCodes.d.ts +10 -0
  37. package/dist/engineNoticeCodes.js +36 -6
  38. package/dist/engineRepoint.d.ts +147 -0
  39. package/dist/engineRepoint.js +310 -0
  40. package/dist/engineRowRef.d.ts +3 -0
  41. package/dist/engineRowRef.js +13 -1
  42. package/dist/engineSessionMessages.d.ts +2 -1
  43. package/dist/engineSessionMessages.js +5 -0
  44. package/dist/engineSwapCrossing.d.ts +57 -0
  45. package/dist/engineSwapCrossing.js +297 -0
  46. package/dist/engineUnavailable.d.ts +44 -0
  47. package/dist/engineUnavailable.js +492 -0
  48. package/dist/errorSupplementRoles.js +2 -1
  49. package/dist/eventLeg.js +3 -3
  50. package/dist/fleet/fleetProjection.js +3 -2
  51. package/dist/generated/engineFactTables.d.ts +2 -0
  52. package/dist/generated/engineFactTables.js +12 -0
  53. package/dist/generated/sdkFactTables.d.ts +2 -1
  54. package/dist/generated/sdkFactTables.js +5 -0
  55. package/dist/generated/settingsSchemaTables.d.ts +4 -0
  56. package/dist/generated/settingsSchemaTables.js +1 -0
  57. package/dist/hitl/approvalAskers.d.ts +6 -0
  58. package/dist/hitl/approvalAskers.js +30 -0
  59. package/dist/hitl/approvalCardReasons.js +6 -3
  60. package/dist/hitl/approvalDelivery.d.ts +1 -0
  61. package/dist/hitl/approvalDelivery.js +1 -1
  62. package/dist/hitl/approvalRequestFrameReading.d.ts +7 -0
  63. package/dist/hitl/approvalRequestFrameReading.js +11 -0
  64. package/dist/hitl/approvalResolution.d.ts +9 -2
  65. package/dist/hitl/approvalResolution.js +6 -1
  66. package/dist/hitl/askGateWire.js +5 -8
  67. package/dist/hitl/automaticAnswerVerdict.js +2 -2
  68. package/dist/hitl/decisionConflict.js +6 -3
  69. package/dist/hitl/decisionRefusal.d.ts +2 -0
  70. package/dist/hitl/decisionRefusal.js +8 -8
  71. package/dist/hitl/decisionRefusalCarrier.d.ts +3 -0
  72. package/dist/hitl/decisionRefusalCarrier.js +348 -0
  73. package/dist/hitl/decisionSend.d.ts +10 -0
  74. package/dist/hitl/decisionSend.js +57 -17
  75. package/dist/hitl/editedApprovalAcceptance.d.ts +25 -0
  76. package/dist/hitl/editedApprovalAcceptance.js +26 -0
  77. package/dist/hitl/elicitationRefusal.d.ts +4 -0
  78. package/dist/hitl/elicitationRefusal.js +23 -0
  79. package/dist/hitl/frameRouter.d.ts +2 -2
  80. package/dist/hitl/frameRouter.js +12 -33
  81. package/dist/hitl/gateIdentity.d.ts +5 -0
  82. package/dist/hitl/gateIdentity.js +23 -0
  83. package/dist/hitl/gateLedger.d.ts +0 -4
  84. package/dist/hitl/gateLedger.js +0 -19
  85. package/dist/hitl/hitlBridge.d.ts +7 -0
  86. package/dist/hitl/hitlBridge.js +14 -8
  87. package/dist/hitl/hitlHostSurface.d.ts +3 -1
  88. package/dist/hitl/hitlHostSurface.js +14 -4
  89. package/dist/hitl/hostWithdrawal.d.ts +15 -0
  90. package/dist/hitl/hostWithdrawal.js +38 -0
  91. package/dist/hitl/localAllowRedemption.d.ts +67 -0
  92. package/dist/hitl/localAllowRedemption.js +256 -0
  93. package/dist/hitl/parkResolver.js +32 -13
  94. package/dist/hitl/persistedRulesWire.d.ts +16 -0
  95. package/dist/hitl/persistedRulesWire.js +72 -2
  96. package/dist/hitl/planReviewWire.d.ts +3 -0
  97. package/dist/hitl/planReviewWire.js +37 -10
  98. package/dist/hitl/policyDenyCause.d.ts +1 -1
  99. package/dist/hitl/policyDenyCause.js +1 -1
  100. package/dist/hitl/resumeRunningCard.d.ts +1 -0
  101. package/dist/hitl/resumeRunningCard.js +1 -0
  102. package/dist/hitl/screenCardCarriers.d.ts +15 -0
  103. package/dist/hitl/screenCardCarriers.js +41 -0
  104. package/dist/hitl/screenDecisionCards.d.ts +98 -0
  105. package/dist/hitl/screenDecisionCards.js +362 -0
  106. package/dist/hitl/sessionPolicyWire.js +6 -4
  107. package/dist/hitl/standingRows.d.ts +4 -1
  108. package/dist/hitl/standingRows.js +33 -1
  109. package/dist/hitl/toolApprovalWire.d.ts +64 -15
  110. package/dist/hitl/toolApprovalWire.js +470 -125
  111. package/dist/hooksWireCaps.js +31 -1
  112. package/dist/hostSettingNoticeArm.d.ts +3 -0
  113. package/dist/hostSettingNoticeArm.js +12 -0
  114. package/dist/hostTurnSettings.d.ts +13 -4
  115. package/dist/hostTurnSettings.js +150 -10
  116. package/dist/humanTurnRead.js +11 -1
  117. package/dist/i18n/messages.en.d.ts +212 -0
  118. package/dist/i18n/messages.en.js +217 -5
  119. package/dist/i18n/messages.zh.js +235 -5
  120. package/dist/i18n/translate.d.ts +3 -0
  121. package/dist/i18n/translate.js +78 -10
  122. package/dist/i18n/zh.d.ts +1 -0
  123. package/dist/i18n/zh.js +1 -0
  124. package/dist/index.d.ts +56 -16
  125. package/dist/index.js +40 -12
  126. package/dist/inheritEnvCapability.js +2 -0
  127. package/dist/inputAuthor.d.ts +16 -0
  128. package/dist/inputAuthor.js +44 -0
  129. package/dist/interactiveHalt.js +2 -1
  130. package/dist/interactiveInterrupt.js +20 -2
  131. package/dist/interruptRefusalNote.d.ts +2 -0
  132. package/dist/interruptRefusalNote.js +17 -0
  133. package/dist/liveModelCatalog.d.ts +2 -0
  134. package/dist/liveModelCatalog.js +23 -9
  135. package/dist/liveQuestionStore.d.ts +4 -1
  136. package/dist/liveQuestionStore.js +12 -3
  137. package/dist/localEngineSeatReading.d.ts +2 -2
  138. package/dist/localEngineSeatReading.js +5 -3
  139. package/dist/localEngineSpawn.d.ts +0 -7
  140. package/dist/localEngineSpawn.js +0 -92
  141. package/dist/localEngineStep.d.ts +2 -2
  142. package/dist/localEngineStep.js +2 -0
  143. package/dist/mcpEngineLeg.d.ts +3 -0
  144. package/dist/mcpEngineLeg.js +38 -1
  145. package/dist/mcpPanel.js +2 -0
  146. package/dist/mcpReconnect.d.ts +9 -1
  147. package/dist/mcpReconnect.js +124 -19
  148. package/dist/mcpWireCaps.js +1 -1
  149. package/dist/model/engineModelWords.d.ts +3 -0
  150. package/dist/model/engineModelWords.js +13 -0
  151. package/dist/model/subagentModelWord.d.ts +21 -2
  152. package/dist/model/subagentModelWord.js +100 -29
  153. package/dist/modelCapabilityProbe.js +7 -43
  154. package/dist/modsFace.d.ts +8 -1
  155. package/dist/modsFace.js +27 -0
  156. package/dist/notifications.d.ts +36 -6
  157. package/dist/notifications.js +170 -20
  158. package/dist/ownKey.d.ts +6 -5
  159. package/dist/ownKey.js +31 -7
  160. package/dist/peerFrames.d.ts +40 -2
  161. package/dist/peerFrames.js +158 -3
  162. package/dist/pendingUserRow.d.ts +4 -0
  163. package/dist/pendingUserRow.js +16 -0
  164. package/dist/permissionsDeclaration.d.ts +1 -0
  165. package/dist/permissionsDeclaration.js +11 -1
  166. package/dist/planReviewCardFacts.d.ts +3 -0
  167. package/dist/planReviewCardFacts.js +52 -2
  168. package/dist/pluginHooksWire.d.ts +10 -1
  169. package/dist/pluginHooksWire.js +96 -7
  170. package/dist/printToolResultFrame.js +4 -2
  171. package/dist/promptBlockedCopy.js +11 -6
  172. package/dist/promptSuggestionBatch.d.ts +7 -0
  173. package/dist/promptSuggestionBatch.js +9 -0
  174. package/dist/promptSuggestionsTail.d.ts +39 -0
  175. package/dist/promptSuggestionsTail.js +116 -0
  176. package/dist/replayBody.js +10 -2
  177. package/dist/request/taskRequest.d.ts +5 -0
  178. package/dist/request/taskRequest.js +142 -21
  179. package/dist/requestCoordinate.d.ts +1 -0
  180. package/dist/requestCoordinate.js +13 -0
  181. package/dist/resumeRefusalCopy.d.ts +1 -3
  182. package/dist/resumeRefusalCopy.js +2 -1
  183. package/dist/retryStatus.d.ts +2 -2
  184. package/dist/retryStatus.js +2 -0
  185. package/dist/rewindArchiveReading.js +4 -4
  186. package/dist/runCancelContext.d.ts +2 -1
  187. package/dist/runCancelContext.js +1 -0
  188. package/dist/runPermissionModeSwitch.js +2 -2
  189. package/dist/scenarioRefusal.js +11 -13
  190. package/dist/scenarioSkills.js +11 -6
  191. package/dist/seam.d.ts +27 -2
  192. package/dist/seam.js +17 -1
  193. package/dist/seatContract.d.ts +189 -12
  194. package/dist/seatContract.js +401 -9
  195. package/dist/sessionBackground.js +2 -1
  196. package/dist/sessionBackgroundHandoff.js +2 -1
  197. package/dist/sessionCostReading.d.ts +70 -0
  198. package/dist/sessionCostReading.js +150 -0
  199. package/dist/sessionEngine.d.ts +2 -0
  200. package/dist/sessionEngine.js +111 -0
  201. package/dist/sessionHooksRoster.d.ts +4 -0
  202. package/dist/sessionHooksRoster.js +158 -0
  203. package/dist/sessionMemoryStatus.d.ts +2 -1
  204. package/dist/sessionMemoryStatus.js +2 -2
  205. package/dist/sessionReadRedaction.d.ts +7 -0
  206. package/dist/sessionReadRedaction.js +26 -0
  207. package/dist/sessionSyncFileHistory.d.ts +4 -0
  208. package/dist/sessionSyncFileHistory.js +27 -0
  209. package/dist/settingsHooksSalvage.js +2 -1
  210. package/dist/sseIdleTriage.d.ts +13 -1
  211. package/dist/sseIdleTriage.js +25 -6
  212. package/dist/storeDurabilityWord.d.ts +15 -0
  213. package/dist/storeDurabilityWord.js +18 -0
  214. package/dist/storePostureCapability.d.ts +7 -3
  215. package/dist/storePostureCapability.js +69 -39
  216. package/dist/subagent/engineSubagentResume.js +2 -2
  217. package/dist/subagent/engineSubagentTail.js +8 -1
  218. package/dist/subagentContentStore.d.ts +11 -0
  219. package/dist/subagentContentStore.js +28 -2
  220. package/dist/terminalStatuses.d.ts +1 -0
  221. package/dist/terminalStatuses.js +4 -1
  222. package/dist/toolResult.d.ts +1 -0
  223. package/dist/toolResult.js +2 -0
  224. package/dist/turnFailurePresentation.js +9 -2
  225. package/dist/typePins.d.ts +11 -0
  226. package/dist/usageAnalytics.d.ts +17 -0
  227. package/dist/usageAnalytics.js +44 -2
  228. package/dist/userAttachmentEnvelope.d.ts +2 -1
  229. package/dist/userAttachmentEnvelope.js +10 -0
  230. package/dist/wireErrorTriage.js +2 -1
  231. package/dist/wireFailureShape.d.ts +6 -5
  232. package/dist/wireFailureShape.js +150 -38
  233. package/dist/wireRefusalCopy.d.ts +16 -5
  234. package/dist/wireRefusalCopy.js +119 -86
  235. package/docs/INTEGRATION-CLIENTS.md +4228 -21
  236. 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
+ }
@@ -1,12 +1,13 @@
1
1
  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
- import { classifyPeerNotification, renderPeerFrameTranscriptText } from '../peerFrames.js';
5
- import { dropQueuedNotificationsForRun, freezeTaskNotificationFields, isEngineWorkflowNotified, isWorkflowCompletionCardEnqueued, markEngineWorkflowNotified, noteOwnWorkflowRun, normalizeTaskNotification, noteWorkflowCompletionCardEnqueued, renderTaskNotificationXml, taskNotificationRenderKeys } from '../notifications.js';
4
+ import { classifyPeerNotification, renderPeerFrameTranscriptText, sessionBoxNoticeOf } from '../peerFrames.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';
9
9
  import { recordEngineToolLabel } from '../engineToolLabelStore.js';
10
+ import { publishEngineInlineTaskModel } from '../engineInlineTaskStats.js';
10
11
  import { applySubagentAlias } from '../subagentContentStore.js';
11
12
  import { readAsyncLaunchedAgentReceipt } from '../toolResult.js';
12
13
  import { recordWorkflowAgentTaskId } from '../workflow.js';
@@ -15,7 +16,8 @@ import { readToolHistoryMismatchKey } from '../toolHistoryMismatch.js';
15
16
  import { isMintedRowCcError, readProviderRejectionResendKey } from '../providerRejection.js';
16
17
  import { rowKindOf } from '../rowKind.js';
17
18
  import { terminalCodedDetailOf } from '../runTerminal.js';
18
- import { contextUsageReadingOf, guardedRead, humanInputAttachmentsOf, humanInputAuthorKeys, ownSnapshotRecord, ownSnapshotWhenTyped, readOwnDataNonEmptyString, readOwnDataValue, promptManifestIdentityOfFrame, promptManifestSectionViewOf, readFrameStringKey, readFrameTrueMark, workflowCompletionExtrasOf } from '../ownKey.js';
19
+ import { contextUsageReadingOf, guardedRead, humanInputAttachmentsOf, ownSnapshotRecord, ownSnapshotWhenTyped, readOwnDataNonEmptyString, readOwnDataValue, promptManifestIdentityOfFrame, promptManifestSectionViewOf, readFrameStringKey, readFrameTrueMark, workflowCompletionExtrasOf } from '../ownKey.js';
20
+ import { humanInputAuthorKeys, runOriginKeys } from '../inputAuthor.js';
19
21
  import { CORE_USER_ATTACHMENT_LABEL_MAX } from '../generated/engineFactTables.js';
20
22
  import { ESCAPE_FACE, paintAndCap, washCredentials } from '../displayUntrusted.js';
21
23
  import { resolveEnginePanelTaskId } from '../engineAgentPanelStore.js';
@@ -328,6 +330,7 @@ const humanInputArm = function* (m) {
328
330
  ...(str(m.eventId) !== undefined ? { eventId: str(m.eventId) } : {}),
329
331
  ...humanInputAttachmentsForChrome(m),
330
332
  ...humanInputAuthorKeys(m),
333
+ ...runOriginKeys(m),
331
334
  });
332
335
  };
333
336
  function humanInputAttachmentsForChrome(m) {
@@ -524,7 +527,7 @@ const compactionStartedArm = function* (m) {
524
527
  ...(eventId !== undefined ? { eventId } : {}),
525
528
  });
526
529
  };
527
- const taskStartedArm = function* (m) {
530
+ const taskStartedArm = function* (m, { cards }) {
528
531
  const str = (v) => (typeof v === 'string' && v.length > 0 ? v : undefined);
529
532
  const num = (v) => (typeof v === 'number' && Number.isFinite(v) ? v : undefined);
530
533
  const taskId = str(m.taskId);
@@ -551,6 +554,8 @@ const taskStartedArm = function* (m) {
551
554
  const eventId = str(idSnap.eventId);
552
555
  if (agentType !== undefined && workflowRunId === undefined)
553
556
  recordFleetRowAgentType(taskId, agentType);
557
+ if (model !== undefined && parent !== undefined && workflowRunId === undefined && !cards.has(parent))
558
+ publishEngineInlineTaskModel(parent, model);
554
559
  yield chrome({
555
560
  kind: 'subagent_started',
556
561
  laneProof,
@@ -963,7 +968,7 @@ const resultArm = function* (m, { ctx, idOf, text, cards, panel, flags }) {
963
968
  if (isReplayMarked(m))
964
969
  yield chrome({ kind: 'result_replayed', laneProof: mainLane(), text: RESULT_REPLAYED_TEXT });
965
970
  };
966
- const taskNotificationArm = function* (m, { ctx, idOf, panel, inst }) {
971
+ const taskNotificationArm = function* (m, { ctx, idOf, panel, inst, pass }) {
967
972
  const n = ownSnapshotRecord(guardedRead(() => readOwnDataValue(m, 'notification'))) ?? {};
968
973
  const fields = normalizeTaskNotification(n);
969
974
  if (fields === null)
@@ -983,13 +988,18 @@ const taskNotificationArm = function* (m, { ctx, idOf, panel, inst }) {
983
988
  : {}),
984
989
  });
985
990
  }
986
- const dedupKeys = taskNotificationRenderKeys({
991
+ const peerFrame = classifyPeerNotification(n);
992
+ const baseKeys = taskNotificationRenderKeys({
987
993
  taskId,
988
994
  status: rawStatus,
989
995
  ...(typeof n.seq === 'number' || typeof n.seq === 'string' ? { seq: n.seq } : {}),
990
996
  ...(typeof n.task_type === 'string' ? { taskType: n.task_type } : {}),
991
997
  ...(fields.completionId !== undefined ? { completionId: fields.completionId } : {}),
992
998
  });
999
+ const inboxRunId = peerFrame !== null && peerFrame.lane === 'inbox_notice' ? readFrameStringKey(n, 'eventId') : undefined;
1000
+ const dedupKeys = peerFrame !== null && peerFrame.lane === 'inbox_notice'
1001
+ ? [`${baseKeys[0]}@${inboxRunId !== undefined ? `e:${inboxRunId}` : `p:${pass}`}`, ...baseKeys.slice(1)]
1002
+ : baseKeys;
993
1003
  const sameFrameSeen = inst.hasRenderedNotification(dedupKeys[0]);
994
1004
  const sameCompletionSeen = !sameFrameSeen && dedupKeys.slice(1).some((k) => inst.hasRenderedNotification(k));
995
1005
  for (const k of dedupKeys)
@@ -1005,12 +1015,13 @@ const taskNotificationArm = function* (m, { ctx, idOf, panel, inst }) {
1005
1015
  ...(typeof n.task_type === 'string' ? { taskType: n.task_type } : {}),
1006
1016
  });
1007
1017
  dropQueuedNotificationsForRun(taskId);
1018
+ if (peerFrame === null && n.task_type === 'workflow')
1019
+ settleWorkflowPointerOwed(taskId);
1008
1020
  if (n.task_type !== 'background_bash' && n.task_type !== 'monitor') {
1009
1021
  const bgSessionId = n.task_type === 'background_agent' && typeof n.sessionId === 'string' && n.sessionId.length > 0 ? n.sessionId : undefined;
1010
1022
  yield* panel.settleFromNotification(taskId, isCoreTaskNotificationTerminalNotSuccess(rawStatus), bgSessionId);
1011
1023
  }
1012
1024
  }
1013
- const peerFrame = classifyPeerNotification(n);
1014
1025
  if (peerFrame === null && n.task_type !== 'external' && isWorkflowCompletionCardEnqueued(taskId))
1015
1026
  return;
1016
1027
  if (peerFrame === null && n.task_type !== 'external')
@@ -1018,6 +1029,13 @@ const taskNotificationArm = function* (m, { ctx, idOf, panel, inst }) {
1018
1029
  const fact = peerFrame === null ? freezeTaskNotificationFields(fields) : undefined;
1019
1030
  if (sameCompletionSeen)
1020
1031
  return;
1032
+ const rowUuid = idOf(m);
1033
+ const boxNotice = peerFrame === null ? undefined : sessionBoxNoticeOf(peerFrame);
1034
+ if (boxNotice !== undefined)
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 });
1021
1039
  yield transcript({
1022
1040
  type: 'user',
1023
1041
  message: {
@@ -1029,7 +1047,7 @@ const taskNotificationArm = function* (m, { ctx, idOf, panel, inst }) {
1029
1047
  },
1030
1048
  ],
1031
1049
  },
1032
- uuid: idOf(m),
1050
+ uuid: rowUuid,
1033
1051
  session_id: ctx.sessionId,
1034
1052
  ...(fact !== undefined ? { _sema_task_notification: fact } : {}),
1035
1053
  }, ctx.now());
@@ -1041,13 +1059,26 @@ const workflowCompleteArm = function* (frame) {
1041
1059
  const runId = typeof m.runId === 'string' ? m.runId : undefined;
1042
1060
  if (runId === undefined)
1043
1061
  return;
1044
- 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
+ });
1045
1077
  return;
1078
+ }
1046
1079
  markEngineWorkflowNotified(runId);
1047
- const wfStatus = m.status === 'failed' ? 'failed' : 'completed';
1048
1080
  const wfSummary = typeof m.summary === 'string' ? m.summary : '';
1049
1081
  noteWorkflowCompletionCardEnqueued(runId);
1050
- const extras = workflowCompletionExtrasOf(m);
1051
1082
  const notification = freezeTaskNotificationFields({ taskId: runId, taskType: 'workflow', status: wfStatus, summary: wfSummary, ...(extras.completionId !== undefined ? { completionId: extras.completionId } : {}) });
1052
1083
  yield chrome({
1053
1084
  kind: 'workflow_notification_enqueue',
@@ -1059,6 +1090,9 @@ const workflowCompleteArm = function* (frame) {
1059
1090
  notification,
1060
1091
  ...(extras.diagnostics !== undefined ? { diagnostics: extras.diagnostics } : {}),
1061
1092
  });
1093
+ const truncated = resupplyTruncatedArmBody(m, 'workflow_complete', runId);
1094
+ if (truncated !== undefined)
1095
+ yield chrome({ kind: 'resupply_truncated', laneProof: mainLane(), ...truncated });
1062
1096
  };
1063
1097
  const retryStatusArm = function* (m, { ctx, flags }) {
1064
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')