@sema-agent/client-core 0.112.1 → 0.113.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 (178) hide show
  1. package/CHANGELOG.md +130 -0
  2. package/README.md +36 -23
  3. package/dist/adapt/arms.js +7 -1
  4. package/dist/adapt/textStream.d.ts +2 -0
  5. package/dist/adapt/textStream.js +27 -1
  6. package/dist/adapter/activeRunSelfHeal.d.ts +7 -5
  7. package/dist/adapter/activeRunSelfHeal.js +38 -66
  8. package/dist/adapter/downstream/eventToSdkMessage.js +4 -0
  9. package/dist/adapter/downstream/terminalToSdkResult.d.ts +8 -0
  10. package/dist/adapter/downstream/terminalToSdkResult.js +36 -1
  11. package/dist/adapter/runStream.d.ts +2 -12
  12. package/dist/adapter/runStream.js +46 -19
  13. package/dist/agentSession/engineAgentRegistryRead.js +2 -1
  14. package/dist/agentSession/engineSessionBackgroundStop.js +2 -2
  15. package/dist/attachmentOutcome.d.ts +35 -0
  16. package/dist/attachmentOutcome.js +192 -0
  17. package/dist/attachmentPathPlan.d.ts +67 -0
  18. package/dist/attachmentPathPlan.js +203 -0
  19. package/dist/attachmentRoute.d.ts +9 -1
  20. package/dist/attachmentRoute.js +23 -2
  21. package/dist/declared/supportFloorDeclared.d.ts +1 -1
  22. package/dist/declared/supportFloorDeclared.js +1 -0
  23. package/dist/deviceRebind.js +2 -3
  24. package/dist/displayUntrusted.js +126 -19
  25. package/dist/engineAddress.d.ts +1 -1
  26. package/dist/engineAddress.js +9 -6
  27. package/dist/engineErrorCodes.d.ts +3 -0
  28. package/dist/engineErrorCodes.js +4 -0
  29. package/dist/engineNoticeCodes.d.ts +34 -4
  30. package/dist/engineNoticeCodes.js +133 -6
  31. package/dist/engineUnavailable.d.ts +4 -2
  32. package/dist/engineUnavailable.js +99 -17
  33. package/dist/fleet/fleetLedger.d.ts +9 -3
  34. package/dist/fleet/fleetLedger.js +112 -16
  35. package/dist/fleet/fleetProjection.d.ts +5 -0
  36. package/dist/fleet/fleetProjection.js +9 -1
  37. package/dist/gateVocabulary.d.ts +7 -0
  38. package/dist/gateVocabulary.js +40 -14
  39. package/dist/generated/engineFactTables.d.ts +4 -2
  40. package/dist/generated/engineFactTables.js +198 -2
  41. package/dist/generated/engineNoticeTables.js +56 -8
  42. package/dist/generated/settingsSchemaFns.d.ts +7 -0
  43. package/dist/generated/settingsSchemaFns.js +11 -0
  44. package/dist/generated/settingsSchemaHash.d.ts +1 -0
  45. package/dist/generated/settingsSchemaHash.js +58 -0
  46. package/dist/generated/settingsSchemaOwnKeyRead.js +6 -1
  47. package/dist/generated/settingsSchemaTables.d.ts +3 -2
  48. package/dist/generated/settingsSchemaTables.js +14 -0
  49. package/dist/generated/settingsSchemaTightenVerdict.d.ts +1 -0
  50. package/dist/generated/settingsSchemaTightenVerdict.js +125 -0
  51. package/dist/headlessPermissionModeWire.d.ts +7 -2
  52. package/dist/headlessPermissionModeWire.js +77 -8
  53. package/dist/hitl/approvalDecisionDoor.d.ts +24 -0
  54. package/dist/hitl/approvalDecisionDoor.js +77 -0
  55. package/dist/hitl/approvalDelivery.d.ts +6 -0
  56. package/dist/hitl/approvalDelivery.js +57 -7
  57. package/dist/hitl/approvalResolution.d.ts +6 -3
  58. package/dist/hitl/approvalResolution.js +24 -2
  59. package/dist/hitl/approvalsFeed.js +1 -1
  60. package/dist/hitl/automaticAnswerVerdict.d.ts +1 -1
  61. package/dist/hitl/decisionSend.d.ts +7 -4
  62. package/dist/hitl/decisionSend.js +90 -41
  63. package/dist/hitl/frameRouter.d.ts +3 -3
  64. package/dist/hitl/frameRouter.js +5 -0
  65. package/dist/hitl/hitlHostSurface.d.ts +3 -2
  66. package/dist/hitl/hitlHostSurface.js +5 -3
  67. package/dist/hitl/legacyApprovalShapes.d.ts +142 -0
  68. package/dist/hitl/legacyApprovalShapes.js +1 -0
  69. package/dist/hitl/livePendingAsk.d.ts +4 -4
  70. package/dist/hitl/livePendingAsk.js +5 -3
  71. package/dist/hitl/parkResolver.js +1 -1
  72. package/dist/hitl/persistedRulesWire.js +2 -2
  73. package/dist/hitl/planReviewCard.d.ts +2 -1
  74. package/dist/hitl/planReviewCard.js +64 -1
  75. package/dist/hitl/planReviewWire.d.ts +30 -0
  76. package/dist/hitl/planReviewWire.js +204 -65
  77. package/dist/hitl/sessionPolicyWire.js +16 -7
  78. package/dist/hitl/subagentSource.d.ts +1 -0
  79. package/dist/hitl/subagentSource.js +11 -0
  80. package/dist/hitl/toolApprovalWire.d.ts +34 -10
  81. package/dist/hitl/toolApprovalWire.js +182 -33
  82. package/dist/hookMatcherVerdict.d.ts +2 -1
  83. package/dist/hookMatcherVerdict.js +3 -2
  84. package/dist/hooksReaderGenerations.d.ts +8 -0
  85. package/dist/hooksReaderGenerations.js +49 -0
  86. package/dist/hooksWireCaps.js +43 -18
  87. package/dist/hostSettingsSource.d.ts +1 -1
  88. package/dist/hostSettingsSource.js +2 -2
  89. package/dist/hostTurnSettings.d.ts +2 -2
  90. package/dist/hostTurnSettings.js +87 -47
  91. package/dist/humanTurn.d.ts +2 -1
  92. package/dist/humanTurn.js +44 -13
  93. package/dist/humanTurnRead.d.ts +7 -0
  94. package/dist/humanTurnRead.js +23 -14
  95. package/dist/humanTurnSentences.js +3 -0
  96. package/dist/i18n/messages.en.d.ts +91 -5
  97. package/dist/i18n/messages.en.js +98 -12
  98. package/dist/i18n/messages.zh.js +108 -15
  99. package/dist/index.d.ts +29 -15
  100. package/dist/index.js +17 -9
  101. package/dist/liveModelCatalog.js +1 -0
  102. package/dist/liveQuestionStore.d.ts +2 -0
  103. package/dist/liveQuestionStore.js +7 -2
  104. package/dist/localConfig/kernel.d.ts +2 -1
  105. package/dist/localConfig/kernel.js +12 -18
  106. package/dist/localConfig/mcp/edit.js +25 -27
  107. package/dist/localConfig/mcp/servers.js +5 -8
  108. package/dist/localConfig/modelPool.d.ts +6 -1
  109. package/dist/localConfig/modelPool.js +104 -27
  110. package/dist/localConfig/modelPoolWords.d.ts +2 -0
  111. package/dist/localConfig/modelPoolWords.js +1 -0
  112. package/dist/localConfig/settingsWrite.js +1 -14
  113. package/dist/localConfig/skills.js +9 -16
  114. package/dist/localEngineSpawn.d.ts +29 -1
  115. package/dist/localEngineSpawn.js +62 -1
  116. package/dist/mcpLiveness.d.ts +1 -1
  117. package/dist/mcpProbeWire.js +2 -2
  118. package/dist/mcpReconnect.js +2 -2
  119. package/dist/model/catalogLoader.js +3 -17
  120. package/dist/model/onboardJudgement.d.ts +8 -0
  121. package/dist/model/onboardJudgement.js +8 -3
  122. package/dist/model/onboardSteps.d.ts +19 -0
  123. package/dist/model/onboardSteps.js +76 -0
  124. package/dist/notifications.js +6 -0
  125. package/dist/ownKey.d.ts +4 -0
  126. package/dist/ownKey.js +61 -0
  127. package/dist/pathShape.d.ts +14 -0
  128. package/dist/pathShape.js +44 -0
  129. package/dist/planReviewCardFacts.d.ts +3 -0
  130. package/dist/planReviewCardFacts.js +20 -3
  131. package/dist/pluginHooksWire.d.ts +20 -8
  132. package/dist/pluginHooksWire.js +204 -86
  133. package/dist/prepareRefusal.d.ts +2 -0
  134. package/dist/prepareRefusal.js +11 -1
  135. package/dist/request/taskRequest.js +3 -1
  136. package/dist/resultFrameKeys.d.ts +1 -0
  137. package/dist/resultFrameKeys.js +3 -0
  138. package/dist/resumeRefusalCopy.js +3 -1
  139. package/dist/retryStatus.d.ts +11 -1
  140. package/dist/retryStatus.js +15 -4
  141. package/dist/runTerminal.d.ts +1 -0
  142. package/dist/runTerminal.js +15 -1
  143. package/dist/sdkWireTransit.d.ts +1 -1
  144. package/dist/seatContract.d.ts +12 -3
  145. package/dist/seatContract.js +24 -13
  146. package/dist/sessionEngine.js +1 -1
  147. package/dist/sessionHooksRoster.js +8 -6
  148. package/dist/sessionIdSegment.d.ts +0 -1
  149. package/dist/sessionIdSegment.js +1 -3
  150. package/dist/sessionMemoryErase.js +2 -2
  151. package/dist/sessionMemoryStatus.js +2 -1
  152. package/dist/sessionOccupant.d.ts +29 -0
  153. package/dist/sessionOccupant.js +78 -0
  154. package/dist/settingsHooksSalvage.d.ts +4 -1
  155. package/dist/settingsHooksSalvage.js +22 -9
  156. package/dist/skillOverrideChain.d.ts +3 -0
  157. package/dist/skillOverrideChain.js +31 -4
  158. package/dist/skillsWireCaps.d.ts +16 -2
  159. package/dist/skillsWireCaps.js +47 -20
  160. package/dist/subagent/agentStateDetail.js +32 -8
  161. package/dist/subagent/engineCompactWire.js +48 -36
  162. package/dist/subagent/engineDelegatedPrompt.d.ts +3 -2
  163. package/dist/subagent/engineDelegatedPrompt.js +65 -28
  164. package/dist/subagentEditOutcomes.d.ts +9 -0
  165. package/dist/subagentEditOutcomes.js +43 -0
  166. package/dist/supportFloor.d.ts +2 -1
  167. package/dist/supportFloor.js +1 -1
  168. package/dist/toolResult.js +4 -2
  169. package/dist/toolRoster.d.ts +1 -0
  170. package/dist/toolRoster.js +1 -0
  171. package/dist/usageAnalytics.js +2 -1
  172. package/dist/userAttachmentEnvelope.d.ts +11 -0
  173. package/dist/userAttachmentEnvelope.js +7 -2
  174. package/dist/userAttachmentSeat.d.ts +7 -1
  175. package/dist/userAttachmentSeat.js +44 -7
  176. package/dist/wiringInstructionsAttribution.js +8 -2
  177. package/docs/INTEGRATION-CLIENTS.md +1588 -16
  178. package/package.json +5 -5
@@ -16,7 +16,7 @@ import { readToolHistoryMismatchKey } from '../toolHistoryMismatch.js';
16
16
  import { isMintedRowCcError, readProviderRejectionResendKey } from '../providerRejection.js';
17
17
  import { rowKindOf } from '../rowKind.js';
18
18
  import { terminalCodedDetailOf } from '../runTerminal.js';
19
- import { contextUsageReadingOf, guardedRead, humanInputAttachmentsOf, ownSnapshotRecord, ownSnapshotWhenTyped, readOwnDataNonEmptyString, readOwnDataValue, promptManifestIdentityOfFrame, promptManifestSectionViewOf, readFrameStringKey, readFrameTrueMark, workflowCompletionExtrasOf } from '../ownKey.js';
19
+ import { contextUsageReadingOf, guardedRead, humanInputAttachmentsOf, ownSnapshotRecord, ownSnapshotWhenTyped, readOwnDataNonEmptyString, readOwnDataValue, promptManifestIdentityOfFrame, promptManifestSectionViewOf, readFrameEntryIdList, readFrameStringKey, readFrameTrueMark, workflowCompletionExtrasOf } from '../ownKey.js';
20
20
  import { humanInputAuthorKeys, runOriginKeys } from '../inputAuthor.js';
21
21
  import { CORE_USER_ATTACHMENT_LABEL_MAX } from '../generated/engineFactTables.js';
22
22
  import { ESCAPE_FACE, paintAndCap, washCredentials } from '../displayUntrusted.js';
@@ -926,6 +926,9 @@ const resultArm = function* (m, { ctx, idOf, text, cards, panel, flags }) {
926
926
  const errorEnvelope = typeof m.subtype === 'string' && m.subtype.startsWith(ERROR_SUBTYPE_PREFIX);
927
927
  const terminalText = salvaged !== undefined ? salvaged : !errorEnvelope && typeof m.result === 'string' ? m.result : '';
928
928
  const committed = text.lastCommittedAnswerText;
929
+ const namedEntryIds = readFrameEntryIdList(m, '_sema_result_entry_ids');
930
+ const lastTwoOnScreen = text.lastTwoCommittedAnswerText;
931
+ const twoLinkChainOnScreen = namedEntryIds !== undefined && namedEntryIds.length === 2 && lastTwoOnScreen !== undefined && lastTwoOnScreen.trim() === terminalText.trim();
929
932
  const terminalIdentity = messageIdentityOf(m, ctx);
930
933
  const emitTerminal = function* (body, tag) {
931
934
  yield transcript({
@@ -947,6 +950,8 @@ const resultArm = function* (m, { ctx, idOf, text, cards, panel, flags }) {
947
950
  }
948
951
  else if (terminalText.length === 0) {
949
952
  }
953
+ else if (twoLinkChainOnScreen) {
954
+ }
950
955
  else if (committed.trim() === terminalText.trim()) {
951
956
  }
952
957
  else if (prefixOf(terminalText, committed) !== null) {
@@ -965,6 +970,7 @@ const resultArm = function* (m, { ctx, idOf, text, cards, panel, flags }) {
965
970
  resultLength: terminalText.length,
966
971
  });
967
972
  }
973
+ text.endRunScope();
968
974
  if (isReplayMarked(m))
969
975
  yield chrome({ kind: 'result_replayed', laneProof: mainLane(), text: RESULT_REPLAYED_TEXT });
970
976
  };
@@ -33,6 +33,8 @@ export interface TextStream {
33
33
  readonly emittedAssistantText: boolean;
34
34
  readonly committedAnswerText: string;
35
35
  readonly lastCommittedAnswerText: string;
36
+ readonly lastTwoCommittedAnswerText: string | undefined;
37
+ endRunScope(): void;
36
38
  beginAssistantMessage(): void;
37
39
  closeSegmentAuthorityWindowOnNextText(): void;
38
40
  replaceThinkingSegment(content: string, anchor?: Frame): ThinkingSegmentReplacement;
@@ -28,6 +28,10 @@ export function createTextStream(ctx, idOf) {
28
28
  let emittedAssistantText = false;
29
29
  let committedText = '';
30
30
  let previousCommittedText = '';
31
+ let olderCommittedText = '';
32
+ let closedTextMessagesInRun = 0;
33
+ let runBooksRewritten = false;
34
+ let currentFromClosedRun = false;
31
35
  let committedTextRows = [];
32
36
  let messageSerial = 0;
33
37
  let textPending = '';
@@ -294,6 +298,8 @@ export function createTextStream(ctx, idOf) {
294
298
  }
295
299
  booksSynced = syncedBook !== null;
296
300
  }
301
+ if (booksSynced)
302
+ runBooksRewritten = true;
297
303
  if (booksSynced && answer.endsWith(liveSegment)) {
298
304
  answer = answer.slice(0, answer.length - liveSegment.length) + content;
299
305
  }
@@ -316,6 +322,7 @@ export function createTextStream(ctx, idOf) {
316
322
  if (committedPrefixDiverged) {
317
323
  if (committedText.endsWith(livePrefix)) {
318
324
  committedText = committedText.slice(0, committedText.length - livePrefix.length) + content;
325
+ runBooksRewritten = true;
319
326
  }
320
327
  }
321
328
  else {
@@ -437,8 +444,13 @@ export function createTextStream(ctx, idOf) {
437
444
  },
438
445
  beginAssistantMessage: () => {
439
446
  messageSerial += 1;
440
- if (carriesAnswerText(committedText))
447
+ if (carriesAnswerText(committedText)) {
448
+ olderCommittedText = previousCommittedText;
441
449
  previousCommittedText = committedText;
450
+ if (!currentFromClosedRun)
451
+ closedTextMessagesInRun += 1;
452
+ }
453
+ currentFromClosedRun = false;
442
454
  committedText = '';
443
455
  previousSegmentCommitted += segmentCommitted;
444
456
  segmentCommitted = '';
@@ -452,6 +464,20 @@ export function createTextStream(ctx, idOf) {
452
464
  get lastCommittedAnswerText() {
453
465
  return carriesAnswerText(committedText) ? committedText : previousCommittedText;
454
466
  },
467
+ get lastTwoCommittedAnswerText() {
468
+ if (runBooksRewritten || currentFromClosedRun)
469
+ return undefined;
470
+ const currentCarries = carriesAnswerText(committedText);
471
+ if (closedTextMessagesInRun + (currentCarries ? 1 : 0) < 2)
472
+ return undefined;
473
+ return currentCarries ? previousCommittedText + committedText : olderCommittedText + previousCommittedText;
474
+ },
475
+ endRunScope: () => {
476
+ closedTextMessagesInRun = 0;
477
+ olderCommittedText = '';
478
+ runBooksRewritten = false;
479
+ currentFromClosedRun = committedText.length > 0;
480
+ },
455
481
  get emittedAssistantText() {
456
482
  return emittedAssistantText;
457
483
  },
@@ -54,7 +54,12 @@ export type ReopenCardVerdict = {
54
54
  firstSight: boolean;
55
55
  presented?: boolean;
56
56
  };
57
- export declare const PLAN_REVIEW_REOPEN_REFUSALS: readonly ["invalid_call", "no_delivery_path", "not_presented", "gate_record_gone", "internal_error"];
57
+ export interface PlanReviewReopenCallOptions {
58
+ trigger?: PlanReviewReopenTrigger;
59
+ checkpointId?: string;
60
+ stillHere?: () => boolean | undefined;
61
+ }
62
+ export declare const PLAN_REVIEW_REOPEN_REFUSALS: readonly ["invalid_call", "no_delivery_path", "not_presented", "gate_record_gone", "internal_error", "conversation_left", "conversation_unconfirmed"];
58
63
  export type PlanReviewReopenRefusal = (typeof PLAN_REVIEW_REOPEN_REFUSALS)[number];
59
64
  export interface RunningChoiceRequest {
60
65
  taskId: string;
@@ -78,10 +83,7 @@ export interface ActiveRunSelfHealDeps {
78
83
  listOwnedPendingApprovals?: (opts?: {
79
84
  signal?: AbortSignal;
80
85
  }) => Promise<number>;
81
- reopenPlanReview?: (taskId: string, opts?: {
82
- trigger?: PlanReviewReopenTrigger;
83
- checkpointId?: string;
84
- }) => ReopenCardVerdict | Promise<ReopenCardVerdict>;
86
+ reopenPlanReview?: (taskId: string, opts?: PlanReviewReopenCallOptions) => ReopenCardVerdict | Promise<ReopenCardVerdict>;
85
87
  reopenAskPark?: (taskId: string, opts?: {
86
88
  trigger?: PlanReviewReopenTrigger;
87
89
  }) => Promise<ReopenCardVerdict>;
@@ -7,9 +7,10 @@ import { DEFAULT_SESSION_KEY } from '../sessionSlot.js';
7
7
  import { ASK_PARK_AUTO_REOPEN_BLOCKS, askParkAutoReopenBlockedContent } from '../hitl/askParkAutoReopenBlock.js';
8
8
  import { corruptStoredRowContent, corruptStoredRowWhere, effectiveWireErrorCode } from '../wireErrorTriage.js';
9
9
  import { STEERING_NOT_RUNNING } from '../engineErrorCodes.js';
10
+ import { endRunClauseOf as endRunClause, gateKindPhraseOf as gateKindPhrase, governanceOriginClauseOf as governanceOriginClause, sessionBusyRowOf } from '../sessionOccupant.js';
10
11
  import { readThrownStatusSlot, slotReadOf } from '../wireFailureShape.js';
11
12
  import { checkpointDeadlineStateOf, checkpointRowBarOf, checkpointRowBarSentence, rowBarWayOutContent } from '../checkpointRowVerdict.js';
12
- import { guardedRead, readOwnDataNonEmptyString, readOwnDataValue } from '../ownKey.js';
13
+ import { guardedRead, hostPresenceOf, readOwnDataNonEmptyString, readOwnDataValue } from '../ownKey.js';
13
14
  import { steerBodyOf, UNOBSERVED_STEER_PRIORITY } from '../controlRouter.js';
14
15
  import { atMostOnceFailureClass } from '../atMostOnce.js';
15
16
  import { readSteerReceipt } from '../steerReceipt.js';
@@ -52,7 +53,7 @@ export const PLAN_REVIEW_STATES = Object.freeze(['needs_review']);
52
53
  export const ASK_PARK_STATES = Object.freeze(['suspended']);
53
54
  export const RUNNING_STATES = Object.freeze(['running']);
54
55
  export const CLAIM_HELD_STATES = SDK_RUN_LIVE_STATUSES;
55
- export const PLAN_REVIEW_REOPEN_REFUSALS = Object.freeze(['invalid_call', 'no_delivery_path', 'not_presented', 'gate_record_gone', 'internal_error']);
56
+ export const PLAN_REVIEW_REOPEN_REFUSALS = Object.freeze(['invalid_call', 'no_delivery_path', 'not_presented', 'gate_record_gone', 'internal_error', 'conversation_left', 'conversation_unconfirmed']);
56
57
  export function selfHealSubmissionDisposition(outcome) {
57
58
  switch (outcome.kind) {
58
59
  case 'decision-pending':
@@ -642,25 +643,10 @@ async function interruptedShortCircuitUnguarded(signal, runs, deps) {
642
643
  return { kind: 'interrupted-still-finishing', taskId, waitedMs: verdict.waitedMs };
643
644
  return null;
644
645
  }
646
+ const _conversationPresencePin = [true, true];
647
+ void _conversationPresencePin;
645
648
  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
- }
649
+ return hostPresenceOf(deps);
664
650
  }
665
651
  export async function attemptActiveRunSelfHeal(signal, runs, deps) {
666
652
  const outcome = await triageActiveRun(signal, runs, deps);
@@ -743,10 +729,20 @@ async function triageActiveRun(signal, runs, deps) {
743
729
  }
744
730
  return { kind: 'not-parked', taskId, status, ...triageGate };
745
731
  }
732
+ function stillHereForwardOf(deps) {
733
+ let port;
734
+ try {
735
+ port = deps?.stillHere;
736
+ }
737
+ catch {
738
+ return { stillHere: () => undefined };
739
+ }
740
+ return port === undefined ? {} : { stillHere: port };
741
+ }
746
742
  async function planVerdict(taskId, deps, checkpointId) {
747
743
  try {
748
744
  const trigger = planReviewReopenTriggerFor(deps?.submissionOrigin);
749
- const second = { ...(trigger !== undefined ? { trigger } : {}), ...(checkpointId !== undefined && checkpointId.length > 0 ? { checkpointId } : {}) };
745
+ const second = { ...(trigger !== undefined ? { trigger } : {}), ...(checkpointId !== undefined && checkpointId.length > 0 ? { checkpointId } : {}), ...stillHereForwardOf(deps) };
750
746
  const verdict = Object.keys(second).length === 0 ? deps?.reopenPlanReview?.(taskId) : deps?.reopenPlanReview?.(taskId, second);
751
747
  return snapshotReopenVerdict(await verdict);
752
748
  }
@@ -1133,25 +1129,6 @@ async function routeFreshNonRunning(fresh, taskId, busy, runs, deps, carrierVerd
1133
1129
  }
1134
1130
  export const INTERACTIVE_WAY_OUT = EN_MESSAGES['session.selfHeal.wayOut.interactive'];
1135
1131
  const say = (lang, key, params) => renderMessage(msg(key, params), lang);
1136
- function gateKindPhrase(kind, lang) {
1137
- return kind ? say(lang, 'session.selfHeal.gate.kind', { kind }) : say(lang, 'session.selfHeal.gate.generic');
1138
- }
1139
- function endRunClause(copy, taskId, lang, face = 'headless') {
1140
- let host;
1141
- try {
1142
- host = copy?.endRun;
1143
- }
1144
- catch {
1145
- host = undefined;
1146
- }
1147
- const phrase = typeof host === 'string' ? host.trim().replace(/[\s.;。;!!??]+$/u, '') : '';
1148
- if (/[\p{L}\p{N}]/u.test(phrase))
1149
- return phrase;
1150
- if (face === 'interactive') {
1151
- return taskId ? say(lang, 'session.selfHeal.endRun.engineInteractive', { taskId }) : say(lang, 'session.selfHeal.endRun.engineInteractive.noId');
1152
- }
1153
- return say(lang, 'session.selfHeal.endRun.engine', { cancelPath: `POST /v1/runs/${taskId ? taskId : '<id>'}/cancel` });
1154
- }
1155
1132
  function wakeSessionClause(copy, lang) {
1156
1133
  let host;
1157
1134
  try {
@@ -1172,9 +1149,6 @@ function decidePathClause(signal, lang) {
1172
1149
  return '';
1173
1150
  return say(lang, 'session.selfHeal.decidePathClause', { gate: gateKindPhrase(signal?.pendingGate?.kind, lang), decidePath });
1174
1151
  }
1175
- function governanceOriginClause(signal, lang) {
1176
- return signal?.pendingGate?.governanceForced === true ? say(lang, 'session.selfHeal.governanceOrigin') : '';
1177
- }
1178
1152
  function lastActivityClause(signal, lang) {
1179
1153
  const ms = signal?.msSinceLastActivity;
1180
1154
  if (typeof ms !== 'number' || !Number.isFinite(ms) || ms < 0)
@@ -1182,6 +1156,12 @@ function lastActivityClause(signal, lang) {
1182
1156
  const human = ms < 120_000 ? `${String(Math.max(1, Math.round(ms / 1000)))}s` : `${String(Math.round(ms / 60_000))}m`;
1183
1157
  return say(lang, 'session.selfHeal.lastActivity', { ago: human });
1184
1158
  }
1159
+ function conversationRefusalOf(outcome) {
1160
+ if (outcome.decisionInFlight === true || outcome.dismissedByUser === true || outcome.noPresentationSurface === true)
1161
+ return undefined;
1162
+ const cause = outcome.reopenRefusal;
1163
+ return cause === 'conversation_left' || cause === 'conversation_unconfirmed' ? cause : undefined;
1164
+ }
1185
1165
  export function activeRunSelfHealRow(outcome, signal, copy, origin, follow, lang) {
1186
1166
  const override = copy?.rowFor?.(outcome, signal);
1187
1167
  if (typeof override === 'string')
@@ -1193,7 +1173,8 @@ export function activeRunSelfHealRow(outcome, signal, copy, origin, follow, lang
1193
1173
  const keep = (outcome.kind === 'plan-review-reopen-failed' || outcome.kind === 'ask-reopen-failed') &&
1194
1174
  outcome.decisionInFlight !== true &&
1195
1175
  outcome.pendingRowGone !== true &&
1196
- (outcome.kind !== 'plan-review-reopen-failed' || outcome.dismissedByUser !== true)
1176
+ (outcome.kind !== 'plan-review-reopen-failed' || outcome.dismissedByUser !== true) &&
1177
+ (outcome.kind !== 'plan-review-reopen-failed' || conversationRefusalOf(outcome) === undefined)
1197
1178
  ? keepSessionWayOutOf(copy)
1198
1179
  : null;
1199
1180
  const base = activeRunSelfHealBaseRow(outcome, copy?.wayOut ?? say(lang, 'session.selfHeal.wayOut.interactive'), following, keep, engineDecide, lang, copy);
@@ -1226,6 +1207,13 @@ function injectedSubmissionRow(outcome, following = false, lang) {
1226
1207
  if (outcome.kind === 'plan-review-reopen-failed' && outcome.dismissedByUser === true) {
1227
1208
  return say(lang, 'session.selfHeal.injected.dismissedPlan', { lead, id, closed: msg('session.selfHeal.userClosedCardNotPutBack') });
1228
1209
  }
1210
+ if (outcome.kind === 'plan-review-reopen-failed') {
1211
+ const gone = conversationRefusalOf(outcome);
1212
+ if (gone === 'conversation_left')
1213
+ return say(lang, 'session.selfHeal.injected.planReopenConversationLeft', { lead, id });
1214
+ if (gone === 'conversation_unconfirmed')
1215
+ return say(lang, 'session.selfHeal.injected.planReopenConversationUnconfirmed', { lead, id });
1216
+ }
1229
1217
  if (outcome.kind === 'running-steered' && outcome.delivery === 'queued') {
1230
1218
  const queuedOn = msg('session.selfHeal.injected.queuedOn', { lead, id });
1231
1219
  const reopened = reopenedOfOutcome(outcome);
@@ -1341,6 +1329,11 @@ function activeRunSelfHealBaseRow(outcome, wayOut, following = false, keepSessio
1341
1329
  if (outcome.dismissedByUser === true) {
1342
1330
  return say(lang, 'session.selfHeal.row.planReopenFailed.dismissed', { taskId: outcome.taskId, closed: msg('session.selfHeal.userClosedCardNotPutBack') });
1343
1331
  }
1332
+ const gone = conversationRefusalOf(outcome);
1333
+ if (gone === 'conversation_left')
1334
+ return say(lang, 'session.selfHeal.row.planReopenFailed.conversationLeft', { taskId: outcome.taskId });
1335
+ if (gone === 'conversation_unconfirmed')
1336
+ return say(lang, 'session.selfHeal.row.planReopenFailed.conversationUnconfirmed', { taskId: outcome.taskId });
1344
1337
  const viaEngine = engineDecide && outcome.decidePath ? msg('session.selfHeal.viaEngine', { decidePath: outcome.decidePath }) : '';
1345
1338
  const noView = outcome.noPresentationSurface === true ? msg('session.selfHeal.noCardView.afterColon') : '';
1346
1339
  return keepSessionWayOut !== null
@@ -1549,26 +1542,5 @@ export function activeRunBusyHeadlessRow(signal, copy, lang) {
1549
1542
  const override = copy?.headlessRowFor?.(signal);
1550
1543
  if (typeof override === 'string')
1551
1544
  return override;
1552
- const activeTaskId = signal.activeTaskId;
1553
- const handle = activeTaskId ? msg('session.selfHeal.handle.run', { taskId: activeTaskId }) : '';
1554
- const endRun = endRunClause(copy, activeTaskId, lang);
1555
- const status = signal.activeTaskStatus;
1556
- const decidePath = signal.pendingGate?.decidePath ?? null;
1557
- const hostFresh = copy?.freshSession ?? undefined;
1558
- const freshSession = hostFresh ?? say(lang, 'session.selfHeal.freshSession.default');
1559
- if (decidePath) {
1560
- return say(lang, 'session.selfHeal.headless.decide', {
1561
- handle,
1562
- status: status ? msg('session.selfHeal.headless.status', { status }) : '',
1563
- gate: gateKindPhrase(signal.pendingGate?.kind, lang),
1564
- decidePath,
1565
- endRun,
1566
- freshSession,
1567
- governance: governanceOriginClause(signal, lang),
1568
- });
1569
- }
1570
- if (status)
1571
- return say(lang, 'session.selfHeal.headless.statusOnly', { handle, status, endRun, freshSession });
1572
- const startOver = hostFresh !== undefined ? `${hostFresh.charAt(0).toUpperCase()}${hostFresh.slice(1)}` : say(lang, 'session.selfHeal.freshSession.defaultCapitalized');
1573
- return say(lang, 'session.selfHeal.headless.neverReleased', { handle, startOver, endRun });
1545
+ return sessionBusyRowOf(signal, 'scripted', copy, lang);
1574
1546
  }
@@ -298,6 +298,8 @@ function projectEvent(ev, ctx) {
298
298
  const sleptMs = sleptMsRaw !== undefined && sleptMsRaw >= 0 ? sleptMsRaw : undefined;
299
299
  const waitSegment = readFrameStringKey(ev, 'waitSegment');
300
300
  const seat = readFrameStringKey(ev, 'seat');
301
+ const providerMessage = readFrameStringKey(ev, 'providerMessage');
302
+ const judgedToolCallId = readFrameStringKey(ev, 'toolCallId');
301
303
  return projected(stamp(ctx, armBody({
302
304
  type: 'retry_status',
303
305
  phase: ev.phase,
@@ -316,6 +318,8 @@ function projectEvent(ev, ctx) {
316
318
  ...(sleptMs !== undefined ? { sleptMs } : {}),
317
319
  ...(waitSegment !== undefined ? { waitSegment } : {}),
318
320
  ...(seat !== undefined ? { seat } : {}),
321
+ ...(providerMessage !== undefined ? { providerMessage } : {}),
322
+ ...(judgedToolCallId !== undefined ? { toolCallId: judgedToolCallId } : {}),
319
323
  ...(typeof ev.eventId === 'string' ? { eventId: ev.eventId } : {}),
320
324
  ...(typeof ev.parentToolCallId === 'string' ? { parentToolCallId: ev.parentToolCallId } : {}),
321
325
  })));
@@ -91,6 +91,14 @@ export declare function readRunCostFacts(stats: TaskStats | undefined, observed?
91
91
  readonly usageMissingObserved?: boolean;
92
92
  }): RunCostFacts | undefined;
93
93
  export declare function runCostSettlementOf(stats: TaskStats | undefined): Exclude<RunCostSettlement, 'awaiting'>;
94
+ export type ResultIntake = {
95
+ readonly committed: true;
96
+ readonly sessionId: string;
97
+ readonly entryId: string;
98
+ } | {
99
+ readonly committed: false;
100
+ };
101
+ export declare function resultIntakeOf(frame: object | null | undefined): ResultIntake | undefined;
94
102
  export interface ObservedTerminalParts extends PermissionDenialParts {
95
103
  readonly _sema_usage_lower_bound?: true;
96
104
  }
@@ -1,6 +1,6 @@
1
1
  import { isCcToolDenialKind, isCcToolDenialKindADenial, isGateDeniedByWord } from '../../gateVocabulary.js';
2
2
  import { stamp } from '../types.js';
3
- import { guardedRead, putOwnKey, readFrameStringKey, readOwnDataFiniteNumber, readOwnDataNonEmptyString, readOwnDataValue } from '../../ownKey.js';
3
+ import { guardedRead, putOwnKey, readFrameEntryIdList, readFrameStringKey, readOwnDataFiniteNumber, readOwnDataNonEmptyString, readOwnDataValue } from '../../ownKey.js';
4
4
  import { REDACTION_MARKER_PREFIX, washCredentials } from '../../displayUntrusted.js';
5
5
  import { readEffectiveReasoning, readEffectiveMemoryScopes } from '../../effectiveFacts.js';
6
6
  import { isReviewPark, readRunTerminal, runTerminalCode, runTerminalCodedDetail, runTerminalGateToolName, } from '../../runTerminal.js';
@@ -276,14 +276,42 @@ function structuredOutputParts(r) {
276
276
  const so = r.structuredOutput;
277
277
  return so !== undefined ? { structured_output: so } : {};
278
278
  }
279
+ const _intakeCoversCore = true;
280
+ const _intakeCoveredByCore = true;
281
+ void _intakeCoversCore;
282
+ void _intakeCoveredByCore;
283
+ function intakeOf(v) {
284
+ try {
285
+ if (typeof v !== 'object' || v === null || Array.isArray(v))
286
+ return undefined;
287
+ const committed = readOwnDataValue(v, 'committed');
288
+ if (committed === false)
289
+ return Object.freeze({ committed: false });
290
+ if (committed !== true)
291
+ return undefined;
292
+ const sessionId = readOwnDataNonEmptyString(v, 'sessionId');
293
+ const entryId = readOwnDataNonEmptyString(v, 'entryId');
294
+ return sessionId !== undefined && entryId !== undefined ? Object.freeze({ committed: true, sessionId, entryId }) : undefined;
295
+ }
296
+ catch {
297
+ return undefined;
298
+ }
299
+ }
300
+ export function resultIntakeOf(frame) {
301
+ return intakeOf(guardedRead(() => readOwnDataValue(frame, '_sema_intake')));
302
+ }
279
303
  function effectiveFactParts(rec) {
280
304
  const reasoning = readEffectiveReasoning(rec.effectiveReasoning);
281
305
  const scopes = readEffectiveMemoryScopes(rec.effectiveMemoryScopes);
282
306
  const responseModel = rec.responseModel;
307
+ const intake = intakeOf(guardedRead(() => readOwnDataValue(rec, 'intake')));
308
+ const turnAbortedBy = readFrameStringKey(rec, 'turnAbortedBy');
283
309
  return {
284
310
  ...(reasoning !== undefined ? { _sema_effective_reasoning: reasoning } : {}),
285
311
  ...(scopes !== undefined ? { _sema_effective_memory_scopes: scopes } : {}),
286
312
  ...(typeof responseModel === 'string' && responseModel.length > 0 ? { _sema_response_model: responseModel } : {}),
313
+ ...(intake !== undefined ? { _sema_intake: intake } : {}),
314
+ ...(turnAbortedBy !== undefined ? { _sema_turn_aborted_by: turnAbortedBy } : {}),
287
315
  };
288
316
  }
289
317
  function reemitEffectiveFacts(f) {
@@ -291,6 +319,8 @@ function reemitEffectiveFacts(f) {
291
319
  ...(f?._sema_effective_reasoning !== undefined ? { _sema_effective_reasoning: f._sema_effective_reasoning } : {}),
292
320
  ...(f?._sema_effective_memory_scopes !== undefined ? { _sema_effective_memory_scopes: f._sema_effective_memory_scopes } : {}),
293
321
  ...(f?._sema_response_model !== undefined ? { _sema_response_model: f._sema_response_model } : {}),
322
+ ...(f?._sema_intake !== undefined ? { _sema_intake: f._sema_intake } : {}),
323
+ ...(f?._sema_turn_aborted_by !== undefined ? { _sema_turn_aborted_by: f._sema_turn_aborted_by } : {}),
294
324
  };
295
325
  const _keySetPin = true;
296
326
  void _keySetPin;
@@ -597,6 +627,10 @@ const PRINT_ARM_UNKNOWN_READING = Object.freeze({ arm: PRINT_ARM_UNKNOWN_OUTCOME
597
627
  function selectedModelParts(model) {
598
628
  return typeof model === 'string' && model.length > 0 ? { _sema_selected_model: model } : {};
599
629
  }
630
+ function resultEntryIdsParts(r) {
631
+ const ids = readFrameEntryIdList(r, 'resultEntryIds');
632
+ return ids !== undefined ? { _sema_result_entry_ids: ids } : {};
633
+ }
600
634
  function salvagedTextOf(r) {
601
635
  const salvagedOutput = r.salvagedOutput;
602
636
  return typeof r.result === 'string' && r.result.trim().length > 0
@@ -831,6 +865,7 @@ function doneToSdkResultBody(ev, ctx, observed) {
831
865
  ...effectiveFactParts(rec),
832
866
  ...nestedUsageByTaskParts(stats, observed?.nestedUsageByTask),
833
867
  ...selectedModelParts(r.model),
868
+ ...resultEntryIdsParts(r),
834
869
  });
835
870
  }
836
871
  export function failedToSdkResult(ev, ctx, observed) {
@@ -2,23 +2,13 @@ import type { AgentEvent } from '@sema-agent/sdk';
2
2
  import { type SDKMessage, type EmitContext, type ModelUsage } from './types.js';
3
3
  import { type EngineTurnUsage } from './downstream/turnUsageToModelUsage.js';
4
4
  import type { ObservedTerminalParts } from './downstream/terminalToSdkResult.js';
5
+ import { type ActiveRunBusySignal, type ActiveRunPendingGate } from '../sessionOccupant.js';
5
6
  import { type ToolHistoryErrorCarrier } from '../toolHistoryMismatch.js';
6
7
  import { MODEL_OUTPUT_ERROR_PREFIX, OUTCOME_UNKNOWN_ROW_PREFIX, RUN_BLOCKED_MESSAGE_PREFIX, RUN_STOPPED_MESSAGE_PREFIX } from '../rowKind.js';
7
8
  export { MODEL_OUTPUT_ERROR_PREFIX, OUTCOME_UNKNOWN_ROW_PREFIX, RUN_BLOCKED_MESSAGE_PREFIX, RUN_STOPPED_MESSAGE_PREFIX };
8
9
  import { type PlanReviewCardFacts } from '../planReviewCardFacts.js';
9
- export interface ActiveRunPendingGate {
10
- readonly kind: string | null;
11
- readonly decidePath: string | null;
12
- readonly governanceForced?: true;
13
- readonly checkpointId?: string;
14
- }
10
+ export type { ActiveRunBusySignal, ActiveRunPendingGate };
15
11
  export declare function pendingGateIsProvablyDifferent(prev: ActiveRunPendingGate | null | undefined, next: ActiveRunPendingGate | null | undefined): boolean;
16
- export interface ActiveRunBusySignal {
17
- readonly activeTaskId: string | null;
18
- readonly activeTaskStatus: string | null;
19
- readonly pendingGate: ActiveRunPendingGate | null;
20
- readonly msSinceLastActivity?: number;
21
- }
22
12
  export declare function activeRunBusySignal(ev: unknown): ActiveRunBusySignal | null;
23
13
  export declare function isGovernanceStopRowText(text: string): boolean;
24
14
  export declare function isModelOutputErrorText(text: string): boolean;
@@ -5,6 +5,7 @@ import { terminalPartsOfObserved, readRunCostFacts, terminalToSdkResult, TOOL_IN
5
5
  import { terminalRunIdOf, terminalUuidOf } from '../engineRowRef.js';
6
6
  import { publishSubagentContentEvent, subagentContentEventOf } from '../subagentContentStore.js';
7
7
  import { OUTPUT_INVALID, activeRunBusyCarrierOf, classifyActiveRunBusy, isCorruptSessionCode, isLimitsExceededCode } from '../engineErrorCodes.js';
8
+ import { sessionBusyRowOf, sessionOccupantOf } from '../sessionOccupant.js';
8
9
  import { doneResultView, isReplayedTerminal, terminalLayerOf } from '../replayBody.js';
9
10
  import { carriesAnswerText, guardedRead, readFrameStringKey } from '../ownKey.js';
10
11
  import { ccErrorOfProviderStatus } from '../providerRejection.js';
@@ -16,7 +17,7 @@ import { parkHeldCallIdOf } from '../engineRowRef.js';
16
17
  import { providerRejectionResend } from '../providerRejection.js';
17
18
  import { displayUntrusted, washCredentials } from '../displayUntrusted.js';
18
19
  import { runBlockedText } from '../promptBlockedCopy.js';
19
- import { MODEL_OUTPUT_ERROR_PREFIX, OUTCOME_UNKNOWN_ROW_PREFIX, RUN_BLOCKED_MESSAGE_PREFIX, RUN_STOPPED_MESSAGE_PREFIX, SESSION_BUSY_ROW_LEAD, legacyRowKindOfText, } from '../rowKind.js';
20
+ import { MODEL_OUTPUT_ERROR_PREFIX, OUTCOME_UNKNOWN_ROW_PREFIX, RUN_BLOCKED_MESSAGE_PREFIX, RUN_STOPPED_MESSAGE_PREFIX, legacyRowKindOfText, } from '../rowKind.js';
20
21
  export { MODEL_OUTPUT_ERROR_PREFIX, OUTCOME_UNKNOWN_ROW_PREFIX, RUN_BLOCKED_MESSAGE_PREFIX, RUN_STOPPED_MESSAGE_PREFIX };
21
22
  import { ccToolDenialKindForToolEnd, gateDeniedBy, gateOutcomeOf } from '../gateOutcome.js';
22
23
  import { resumeReopenContent, resumeReopenFromError, suspendedReopenOf } from '../hitl/suspendedReopen.js';
@@ -75,12 +76,15 @@ export function pendingGateIsProvablyDifferent(prev, next) {
75
76
  return a !== b;
76
77
  }
77
78
  export function activeRunBusySignal(ev) {
78
- const read = busyReadOfFrame(ev);
79
+ const read = busyReadOfFrame(busyFrameSnapshotOf(ev));
79
80
  if (read === null || !read.cls.busy)
80
81
  return null;
81
- const { carrier, cls } = read;
82
- const status = carrier.activeTaskStatus;
83
- const rawGate = carrier.pendingGate;
82
+ return busySignalOfRead(read);
83
+ }
84
+ function busySignalOfRead(read) {
85
+ const { cls } = read;
86
+ const status = read.status;
87
+ const rawGate = read.pendingGate;
84
88
  let pendingGate = null;
85
89
  if (typeof rawGate === 'object' && rawGate !== null) {
86
90
  const k = rawGate.kind;
@@ -94,14 +98,24 @@ export function activeRunBusySignal(ev) {
94
98
  ...(typeof cp === 'string' && cp.length > 0 ? { checkpointId: cp } : {}),
95
99
  };
96
100
  }
97
- const msIdle = carrier.msSinceLastActivity;
101
+ const msIdle = read.msSinceLastActivity;
98
102
  return {
99
103
  activeTaskId: cls.handle,
100
104
  activeTaskStatus: typeof status === 'string' && status.length > 0 ? status : null,
101
105
  pendingGate,
106
+ occupancy: read.occupancy,
102
107
  ...(typeof msIdle === 'number' && Number.isFinite(msIdle) && msIdle >= 0 ? { msSinceLastActivity: msIdle } : {}),
103
108
  };
104
109
  }
110
+ function busySignalForRow(read, cls) {
111
+ const bare = { activeTaskId: cls.handle, activeTaskStatus: null, pendingGate: null, occupancy: 'unreadable' };
112
+ try {
113
+ return read !== null ? busySignalOfRead(read) : bare;
114
+ }
115
+ catch {
116
+ return bare;
117
+ }
118
+ }
105
119
  function busyReadOfFrame(ev, doneTerminal, preReadActiveTaskId) {
106
120
  const carrier = activeRunBusyCarrierOf(ev);
107
121
  if (carrier === null)
@@ -111,7 +125,24 @@ function busyReadOfFrame(ev, doneTerminal, preReadActiveTaskId) {
111
125
  const flatCode = typeof carrier.errorCode === 'string' ? carrier.errorCode : undefined;
112
126
  const activeTaskId = preReadActiveTaskId !== undefined ? preReadActiveTaskId.value : carrier.activeTaskId;
113
127
  const cls = classifyActiveRunBusy({ errorCode: (isDone ? runTerminalCode(terminal) : undefined) ?? flatCode, activeTaskId });
114
- return { carrier, cls };
128
+ if (!cls.busy)
129
+ return { cls, occupancy: 'unreadable', status: undefined, pendingGate: undefined, msSinceLastActivity: undefined };
130
+ const status = ownDataBit(carrier, 'activeTaskStatus');
131
+ const stale = ownDataBit(carrier, 'stale');
132
+ return {
133
+ cls,
134
+ occupancy: sessionOccupantOf(activeTaskId === null || typeof activeTaskId === 'string' ? activeTaskId : undefined, typeof status === 'string' ? status : undefined, stale === true),
135
+ status,
136
+ pendingGate: ownDataBit(carrier, 'pendingGate'),
137
+ msSinceLastActivity: ownDataBit(carrier, 'msSinceLastActivity'),
138
+ };
139
+ }
140
+ function busyFrameSnapshotOf(ev) {
141
+ if (typeof ev !== 'object' || ev === null)
142
+ return ev;
143
+ if (ev.type !== 'done')
144
+ return ev;
145
+ return { type: 'done', result: ev.result };
115
146
  }
116
147
  export function isGovernanceStopRowText(text) {
117
148
  return legacyRowKindOfText(text) === 'governance_stop';
@@ -236,7 +267,8 @@ function terminalFactOf(ev, doneTerminal) {
236
267
  };
237
268
  }
238
269
  function terminalRowFacts(ev) {
239
- const doneTerminal = ev.type === 'done' ? readRunTerminal(ev.result) : null;
270
+ const result = ev.type === 'done' ? ev.result : undefined;
271
+ const doneTerminal = ev.type === 'done' ? readRunTerminal(result) : null;
240
272
  const errTextRaw = ev.type === 'failed'
241
273
  ? (ev.errorMessage ?? ev.errorCode ?? 'run failed')
242
274
  : doneTerminal?.kind === 'failed'
@@ -246,15 +278,15 @@ function terminalRowFacts(ev) {
246
278
  : null;
247
279
  const errText = errTextRaw === '' ? null : errTextRaw;
248
280
  if (errText === null)
249
- return { doneTerminal, errText, activeTaskId: undefined, busy: { busy: false, handle: null }, governance: false };
250
- const activeTaskId = (ev.type === 'done' ? ev.result?.activeTaskId : undefined) ??
251
- (ev.type === 'failed' ? ev.activeTaskId : undefined);
252
- const busy = busyReadOfFrame(ev, doneTerminal, { value: activeTaskId })?.cls ?? { busy: false, handle: null };
281
+ return { doneTerminal, errText, activeTaskId: undefined, busy: { busy: false, handle: null }, busyRead: null, governance: false };
282
+ const activeTaskId = ev.type === 'done' ? result?.activeTaskId : ev.activeTaskId;
283
+ const busyRead = busyReadOfFrame(ev.type === 'done' ? { type: 'done', result } : ev, doneTerminal, { value: activeTaskId });
284
+ const busy = busyRead?.cls ?? { busy: false, handle: null };
253
285
  const governance = isGovernanceTerminal({
254
286
  status: ev.type === 'failed' ? undefined : doneTerminal?.kind === 'blocked' ? 'blocked' : undefined,
255
287
  errorCode: ev.type === 'failed' ? ev.errorCode : runTerminalCode(doneTerminal),
256
288
  });
257
- return { doneTerminal, errText, activeTaskId, busy, governance };
289
+ return { doneTerminal, errText, activeTaskId, busy, busyRead, governance };
258
290
  }
259
291
  const PROVIDER_REJECTED_DETAIL = 'provider_rejected';
260
292
  function ownDataBit(o, k) {
@@ -812,14 +844,9 @@ async function* runStreamInner(events, ctx, handle = {}) {
812
844
  const maxTokHint = /max_tokens/i.test(errText)
813
845
  ? '\nyour provider caps max_tokens lower — lower it in /model (press m, or M to type a value)'
814
846
  : '';
815
- const busyHandle = busy.handle;
816
847
  const arm = terminalRowArmOf(rowFacts);
817
848
  const rowText = arm === 'busy'
818
- ? `${SESSION_BUSY_ROW_LEAD}${busyHandle ? ` (run ${busyHandle})` : ''} that ` +
819
- `has not been released, so this message was NOT sent. Nothing releases it on its own — ` +
820
- (ctx.lane === 'print' || ctx.lane === 'utility'
821
- ? `cancel that run (POST /v1/runs/${busyHandle ?? '<id>'}/cancel), or start a new session.`
822
- : `end ${busyHandle ? `run ${busyHandle}` : 'that run'} on the engine, or start a new session.`)
849
+ ? sessionBusyRowOf(busySignalForRow(rowFacts.busyRead, busy), ctx.lane === 'print' || ctx.lane === 'utility' ? 'scripted' : 'interactive')
823
850
  : arm === 'governance'
824
851
  ?
825
852
  `${isGovernanceStopRowText(errText) ? errText : `${RUN_STOPPED_MESSAGE_PREFIX}: ${errText}`}${maxTokHint}`
@@ -3,6 +3,7 @@ import { hostLog } from '../host.js';
3
3
  import { isSessionIdPathSegment } from '../sessionIdSegment.js';
4
4
  import { engineCapNestedValue } from '../engineCapsCache.js';
5
5
  import { guardedRead, readOwnDataValue } from '../ownKey.js';
6
+ import { ROUTE_NOT_FOUND } from '../engineErrorCodes.js';
6
7
  const unavailable = (why) => ({
7
8
  kind: 'unavailable',
8
9
  why,
@@ -123,7 +124,7 @@ async function readOnce(client, sessionId, capsBaseUrl, opts) {
123
124
  }
124
125
  catch (e) {
125
126
  const { code, status } = errCodes(e);
126
- if (status === 404 && code === 'not_found.route')
127
+ if (status === 404 && code === ROUTE_NOT_FOUND)
127
128
  return unavailable('route_absent');
128
129
  if (status === 501 && code === 'capability.session_ownership_required')
129
130
  return unavailable('ownership_required');
@@ -1,5 +1,5 @@
1
1
  import { engineCapNestedValue } from '../engineCapsCache.js';
2
- import { LIMIT_RATE_EXCEEDED, isStatusDerivedCoarseCode } from '../engineErrorCodes.js';
2
+ import { LIMIT_RATE_EXCEEDED, ROUTE_NOT_FOUND, isStatusDerivedCoarseCode } from '../engineErrorCodes.js';
3
3
  import { clientHasVerbs, engineWireFor, INJECTED_WIRE_SETTLE_MS, noAnswerDetailFrom, sendOnce, settleInjected } from '../engineWireFor.js';
4
4
  import { engineWireDebugEnabled } from '../engineWireTarget.js';
5
5
  import { hostLog } from '../host.js';
@@ -133,7 +133,7 @@ function refusedWhyOf(rawCode, status) {
133
133
  return 'ownership_required';
134
134
  if (code === 'not_found.session')
135
135
  return 'session_not_found';
136
- if (code === 'not_found.route')
136
+ if (code === ROUTE_NOT_FOUND)
137
137
  return 'route_absent';
138
138
  if (code === LIMIT_RATE_EXCEEDED)
139
139
  return 'rate_limited';