@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
@@ -1,13 +1,13 @@
1
1
  import { capForDisplay } from './fleetTaskDesc.js';
2
+ import { STEERING_NOT_RUNNING } from './engineErrorCodes.js';
2
3
  import { ownDataField } from './ownKey.js';
3
4
  import { isSessionIdPathSegment } from './sessionIdSegment.js';
4
- import { inSlotReadOf, inValueOf } from './wireFailureShape.js';
5
+ import { inSlotReadOf, inValueOf, slotReadOf } from './wireFailureShape.js';
5
6
  import { readMcpAuthorization } from './mcpLiveness.js';
7
+ import { msg, renderMessage } from './i18n/translate.js';
6
8
  export const MCP_RECONNECT_OUTCOMES = Object.freeze(['accepted', 'refused', 'unsupported']);
7
- export const MCP_RECONNECT_TRANSACTION_NOTICE = 'Reconnecting closes the current connection before dialing again. On a healthy server this is a transaction, ' +
8
- 'not a refresh: a failed re-dial leaves the server down and withdraws its tools from the model until a later re-dial succeeds.';
9
- export const MCP_RECONNECT_UNSETTLED_NOTICE = 'The MCP re-dial did not settle within the time this request waits, so there is no result yet: the re-dial was not cancelled and may still be running. ' +
10
- "Check the server's state before re-dialing it again — a second request that arrives after the dial has settled closes the connection and dials once more.";
9
+ export const MCP_RECONNECT_TRANSACTION_NOTICE = renderMessage(msg('session.mcpReconnect.transaction'));
10
+ export const MCP_RECONNECT_UNSETTLED_NOTICE = renderMessage(msg('session.mcpReconnect.unsettled'));
11
11
  const UNSETTLED_CODE = 'state.mcp_reconnect_unsettled';
12
12
  const _sdkClientIsAnInjection = [true];
13
13
  void _sdkClientIsAnInjection;
@@ -141,7 +141,7 @@ export function classifyMcpReconnectFailure(e) {
141
141
  return unsettledVerdict(e);
142
142
  if (code === 'steering.invalid_content')
143
143
  return { kind: 'invalid' };
144
- if (code === 'steering.not_running')
144
+ if (code === STEERING_NOT_RUNNING)
145
145
  return { kind: 'not_running' };
146
146
  if (typeof code === 'string' && code.startsWith('capability.'))
147
147
  return { kind: 'unsupported', reason: 'capability' };
@@ -196,23 +196,128 @@ export function projectMcpReconnectCapability(caps) {
196
196
  return undefined;
197
197
  }
198
198
  }
199
- export function mcpReconnectOutcomeDetail(view) {
199
+ function reasonTailOf(reason, lang) {
200
+ return reason === undefined ? '' : renderMessage(msg('session.mcpReconnect.reasonTail', { reason }), lang);
201
+ }
202
+ function outcomeSentence(f, lang) {
203
+ switch (f.outcome) {
204
+ case 'accepted':
205
+ return renderMessage(msg(f.toolCount === 1 ? 'session.mcpReconnect.accepted.one' : 'session.mcpReconnect.accepted.other', { server: f.name, toolCount: f.toolCount, added: f.added, removed: f.removed }), lang);
206
+ case 'refused': {
207
+ const why = reasonTailOf(f.reason, lang);
208
+ if (f.roster === undefined)
209
+ return renderMessage(msg('session.mcpReconnect.refused.untouched', { server: f.name, why }), lang);
210
+ if (f.roster === 0)
211
+ return renderMessage(msg('session.mcpReconnect.refused.noTools', { server: f.name, why }), lang);
212
+ return renderMessage(msg(f.roster === 1 ? 'session.mcpReconnect.refused.listed.one' : 'session.mcpReconnect.refused.listed.other', { server: f.name, toolCount: f.roster, why }), lang);
213
+ }
214
+ case 'unsupported':
215
+ return renderMessage(msg('session.mcpReconnect.undeclared', { server: f.name, why: reasonTailOf(f.reason, lang) }), lang);
216
+ }
217
+ }
218
+ export function mcpReconnectOutcomeDetail(view, lang) {
200
219
  const name = capForDisplay(view.server, RECONNECT_WORD_MAX);
201
220
  switch (view.outcome) {
202
221
  case 'accepted':
203
- return `MCP server ${name} was re-dialed: ${view.toolCount} tool${view.toolCount === 1 ? '' : 's'} mounted for this run (${view.added.length} added, ${view.removed.length} removed)`;
222
+ return outcomeSentence({ outcome: 'accepted', name, toolCount: view.toolCount, added: view.added.length, removed: view.removed.length }, lang);
223
+ case 'refused':
224
+ return outcomeSentence({ outcome: 'refused', name, roster: view.toolNames?.length, reason: view.reason }, lang);
225
+ case 'unsupported':
226
+ return outcomeSentence({ outcome: 'unsupported', name, reason: view.reason }, lang);
227
+ }
228
+ }
229
+ function verdictDetailKey(kind) {
230
+ switch (kind) {
231
+ case 'not_running':
232
+ return 'session.mcpReconnect.notRunning';
233
+ case 'unsupported':
234
+ return 'session.mcpReconnect.unsupported';
235
+ case 'not_found':
236
+ return 'session.mcpReconnect.notFound';
237
+ case 'invalid':
238
+ return 'session.mcpReconnect.invalid';
239
+ case 'failed':
240
+ return 'session.mcpReconnect.failed';
241
+ case 'no_session':
242
+ return 'session.mcpReconnect.noSession';
243
+ case 'unavailable':
244
+ return 'session.mcpReconnect.unavailable';
245
+ case 'unsettled':
246
+ return 'session.mcpReconnect.unsettled';
247
+ default:
248
+ return undefined;
249
+ }
250
+ }
251
+ function fieldOf(o, key) {
252
+ const s = slotReadOf(o, key);
253
+ return s.presence === 'present' ? { kind: 'value', value: s.value } : s.presence === 'absent' ? { kind: 'absent' } : { kind: 'unreadable' };
254
+ }
255
+ function okOutcomeFactsOf(verdict, server) {
256
+ const slot = fieldOf(verdict, 'result');
257
+ if (slot.kind !== 'value')
258
+ return undefined;
259
+ const r = slot.value;
260
+ if (r === null || typeof r !== 'object' || Array.isArray(r))
261
+ return undefined;
262
+ const outcome = fieldOf(r, 'outcome');
263
+ const echoed = fieldOf(r, 'server');
264
+ if (outcome.kind !== 'value' || echoed.kind !== 'value' || echoed.value !== server)
265
+ return undefined;
266
+ const rs = fieldOf(r, 'reason');
267
+ if (rs.kind === 'unreadable' || (rs.kind === 'value' && typeof rs.value !== 'string'))
268
+ return undefined;
269
+ const reason = rs.kind === 'value' ? rs.value : undefined;
270
+ const name = capForDisplay(server, RECONNECT_WORD_MAX);
271
+ switch (outcome.value) {
272
+ case 'unsupported':
273
+ return { outcome: 'unsupported', name, reason };
274
+ case 'accepted': {
275
+ const toolCount = fieldOf(r, 'toolCount');
276
+ const added = fieldOf(r, 'added');
277
+ const removed = fieldOf(r, 'removed');
278
+ if (toolCount.kind !== 'value' || added.kind !== 'value' || removed.kind !== 'value')
279
+ return undefined;
280
+ const n = toolCount.value;
281
+ const addedList = stringList(added.value);
282
+ const removedList = stringList(removed.value);
283
+ if (typeof n !== 'number' || !Number.isInteger(n) || n < 0 || addedList === undefined || removedList === undefined)
284
+ return undefined;
285
+ return { outcome: 'accepted', name, toolCount: n, added: addedList.length, removed: removedList.length };
286
+ }
204
287
  case 'refused': {
205
- const why = view.reason !== undefined ? ` — ${view.reason}` : '';
206
- if (view.toolNames === undefined) {
207
- return `MCP server ${name} was NOT re-dialed; its connection and tools were left untouched${why}`;
208
- }
209
- if (view.toolNames.length === 0) {
210
- return `MCP server ${name} was NOT re-dialed; this run's tool list has no tools from it right now (the dial failed, or this run's tool settings let none of its tools through)${why}`;
211
- }
212
- return `MCP server ${name} was NOT re-dialed; the engine reports ${view.toolNames.length} tool${view.toolNames.length === 1 ? '' : 's'} for it after this attempt${why}`;
288
+ const names = fieldOf(r, 'toolNames');
289
+ if (names.kind === 'unreadable')
290
+ return undefined;
291
+ if (names.kind === 'absent')
292
+ return { outcome: 'refused', name, roster: undefined, reason };
293
+ const roster = stringList(names.value);
294
+ if (roster === undefined)
295
+ return undefined;
296
+ return { outcome: 'refused', name, roster: roster.length, reason };
213
297
  }
214
- case 'unsupported':
215
- return (`This run declared no MCP servers, so there is nothing to re-dial (${name} is not part of this run)` +
216
- (view.reason !== undefined ? ` — ${view.reason}` : ''));
298
+ default:
299
+ return undefined;
300
+ }
301
+ }
302
+ export function mcpReconnectVerdictDetail(verdict, server, lang) {
303
+ try {
304
+ if (verdict === null || typeof verdict !== 'object')
305
+ return undefined;
306
+ const kindSlot = slotReadOf(verdict, 'kind');
307
+ if (kindSlot.presence !== 'present' || typeof kindSlot.value !== 'string')
308
+ return undefined;
309
+ if (!nonEmpty(server))
310
+ return undefined;
311
+ if (kindSlot.value === 'ok') {
312
+ const facts = okOutcomeFactsOf(verdict, server);
313
+ return facts === undefined ? undefined : outcomeSentence(facts, lang);
314
+ }
315
+ const key = verdictDetailKey(kindSlot.value);
316
+ if (key === undefined)
317
+ return undefined;
318
+ return renderMessage(msg(key, { server: capForDisplay(server, RECONNECT_WORD_MAX) }), lang);
319
+ }
320
+ catch {
321
+ return undefined;
217
322
  }
218
323
  }
@@ -448,6 +448,6 @@ export function mcpAssertionHeaderNotSentNotice(specs) {
448
448
  const parts = distinct.slice(0, ASSERTION_NOTICE_NAMES_SHOWN).map((x) => `"${x}"`);
449
449
  if (distinct.length > ASSERTION_NOTICE_NAMES_SHOWN)
450
450
  parts.push(`+${distinct.length - ASSERTION_NOTICE_NAMES_SHOWN} more`);
451
- return (`MCP servers that declare an assertion header (assertionHeader): ${parts.join(', ')} — server versions up to 7.147.0 accept this setting but do not send the header, ` +
451
+ return (`MCP servers that declare an assertion header (assertionHeader): ${parts.join(', ')} — server versions up to 7.148.0 accept this setting but do not send the header, ` +
452
452
  'and this client cannot tell whether the engine it uses sends it; a connector that requires the header will refuse requests from these servers');
453
453
  }
@@ -0,0 +1,3 @@
1
+ export type EngineModelWordKind = 'tier' | 'cc-alias' | 'best' | 'default';
2
+ export declare const ENGINE_MODEL_WORDS: readonly string[];
3
+ export declare function engineModelWordKindOf(word: string): EngineModelWordKind | undefined;
@@ -0,0 +1,13 @@
1
+ import { CC_TIER_ALIASES, TIER_ORDER } from './tierVocabulary.js';
2
+ export const ENGINE_MODEL_WORDS = Object.freeze([...TIER_ORDER, ...Object.keys(CC_TIER_ALIASES), 'best', 'default']);
3
+ export function engineModelWordKindOf(word) {
4
+ if (typeof word !== 'string')
5
+ return undefined;
6
+ if (TIER_ORDER.includes(word))
7
+ return 'tier';
8
+ if (Object.hasOwn(CC_TIER_ALIASES, word))
9
+ return 'cc-alias';
10
+ if (word === 'best')
11
+ return 'best';
12
+ return word === 'default' ? 'default' : undefined;
13
+ }
@@ -1,9 +1,9 @@
1
1
  import { type LiveModelCatalog } from '../liveModelCatalog.js';
2
2
  import type { UiLanguage } from '../env/uiLanguage.js';
3
- export type SubagentModelWordKind = 'inherit' | 'catalog' | 'tier' | 'cc-alias' | 'best' | 'model-id' | 'passthrough' | 'catalog-unknown' | 'ambiguous' | 'unbound';
3
+ export type SubagentModelWordKind = 'inherit' | 'catalog' | 'tier' | 'cc-alias' | 'best' | 'default' | 'model-id' | 'passthrough' | 'catalog-unknown' | 'ambiguous' | 'unbound';
4
4
  export type SubagentModelWordProblem = 'tiers-inert' | 'chain-unbound' | 'binding-not-in-catalog';
5
5
  export interface SubagentModelLocalEngine {
6
- readonly engine: 'started-by-this-process';
6
+ readonly engine: 'reads-this-config' | 'started-by-this-process';
7
7
  readonly tiers: Readonly<Record<string, string>> | undefined;
8
8
  readonly pool?: readonly {
9
9
  readonly name: string;
@@ -29,3 +29,22 @@ export interface SubagentModelWordReading {
29
29
  }
30
30
  export declare function resolveSubagentModelWord(input: SubagentModelWordInput | null | undefined): SubagentModelWordReading;
31
31
  export declare function subagentModelWordProblemLine(word: string, reading: SubagentModelWordReading, lang?: UiLanguage): string | undefined;
32
+ export declare function subagentModelCallRefusalReason(word: string, reading: SubagentModelWordReading, lang?: UiLanguage): string | undefined;
33
+ export type SubagentModelAdmission = {
34
+ readonly verdict: 'accepted';
35
+ readonly why: 'not_sent';
36
+ } | {
37
+ readonly verdict: 'accepted';
38
+ readonly why: 'served';
39
+ readonly model: string;
40
+ } | {
41
+ readonly verdict: 'refused';
42
+ readonly why: 'not_listed' | 'not_served' | 'disabled';
43
+ readonly model: string;
44
+ } | {
45
+ readonly verdict: 'unknown';
46
+ readonly why: 'catalog_absent' | 'catalog_unreadable' | 'catalog_incomplete' | 'reserved_word';
47
+ readonly model: string;
48
+ };
49
+ export declare function subagentModelAdmissionOf(input: SubagentModelWordInput | null | undefined): SubagentModelAdmission;
50
+ export declare function subagentModelAdmissionLine(word: string, admission: SubagentModelAdmission, lang?: UiLanguage): string | undefined;
@@ -1,8 +1,10 @@
1
1
  import { CC_TIER_ALIASES, TIER_ORDER } from './tierVocabulary.js';
2
- import { liveModelRowsOf } from '../liveModelCatalog.js';
2
+ import { ENGINE_MODEL_WORDS, engineModelWordKindOf } from './engineModelWords.js';
3
+ import { liveModelRowsOf, modelAcceptanceOf } from '../liveModelCatalog.js';
3
4
  import { quoteUntrustedForSentence } from '../displayUntrusted.js';
4
5
  import { msg, renderMessage } from '../i18n/translate.js';
5
- const STARTED_BY_THIS_PROCESS = 'started-by-this-process';
6
+ const READS_THIS_CONFIG = 'reads-this-config';
7
+ const LEGACY_LOCAL_ENGINE_WORD = 'started-by-this-process';
6
8
  function ownData(v, key) {
7
9
  if (v === null || typeof v !== 'object')
8
10
  return undefined;
@@ -46,7 +48,8 @@ function localOf(input) {
46
48
  const local = ownData(input, 'local');
47
49
  if (local === null || typeof local !== 'object')
48
50
  return undefined;
49
- return ownData(local, 'engine') === STARTED_BY_THIS_PROCESS ? local : undefined;
51
+ const engine = ownData(local, 'engine');
52
+ return engine === READS_THIS_CONFIG || engine === LEGACY_LOCAL_ENGINE_WORD ? local : undefined;
50
53
  }
51
54
  function catalogOf(input, local) {
52
55
  const live = ownData(input, 'liveCatalog');
@@ -115,14 +118,7 @@ function tiersOf(local) {
115
118
  }
116
119
  return out;
117
120
  }
118
- const BUILTIN_VOCAB = [...TIER_ORDER, ...Object.keys(CC_TIER_ALIASES), 'best'];
119
- function builtinKindOf(w) {
120
- if (TIER_ORDER.includes(w))
121
- return 'tier';
122
- if (Object.hasOwn(CC_TIER_ALIASES, w))
123
- return 'cc-alias';
124
- return w === 'best' ? 'best' : undefined;
125
- }
121
+ const builtinKindOf = engineModelWordKindOf;
126
122
  class BrokenBinding {
127
123
  }
128
124
  function landingOf(word, kind, tiers, cat) {
@@ -203,21 +199,22 @@ function resolveIn(input) {
203
199
  return { kind, model: w, landing: { name: l.name, via: l.via, source: 'local-config' }, label: `${l.name} (${label})` };
204
200
  };
205
201
  const asCatalog = (name) => ({ kind: 'catalog', model: name, label: name });
202
+ const asDefault = (w) => ({ kind: 'default', model: w, label: w });
203
+ const vocab = (w, b) => (b === 'default' ? asDefault(w) : tierClass(w, b));
206
204
  const classify = (k) => {
207
205
  if (cat?.nameSet.has(k))
208
206
  return asCatalog(k);
209
- const b = builtinKindOf(k);
210
- return tierClass(k, b ?? 'tier');
207
+ return vocab(k, builtinKindOf(k) ?? 'tier');
211
208
  };
212
209
  if (cat?.nameSet.has(word))
213
210
  return freezeReading(asCatalog(word));
214
211
  const exact = builtinKindOf(word);
215
212
  if (exact !== undefined)
216
- return freezeReading(tierClass(word, exact));
213
+ return freezeReading(vocab(word, exact));
217
214
  if (tiers?.has(word))
218
215
  return freezeReading(tierClass(word, 'tier'));
219
216
  const lower = word.toLowerCase();
220
- const space = new Set([...(cat?.names ?? []), ...BUILTIN_VOCAB, ...customTierKeys]);
217
+ const space = new Set([...(cat?.names ?? []), ...ENGINE_MODEL_WORDS, ...customTierKeys]);
221
218
  const ciMatches = [...space].filter((k) => k.toLowerCase() === lower);
222
219
  if (builtinKindOf(lower) !== undefined) {
223
220
  return freezeReading(ciMatches.length === 1 ? classify(ciMatches[0]) : { kind: 'ambiguous' });
@@ -241,21 +238,95 @@ export function resolveSubagentModelWord(input) {
241
238
  return freezeReading(word === '' ? { kind: 'inherit' } : { kind: 'catalog-unknown', model: word, label: word });
242
239
  }
243
240
  }
244
- export function subagentModelWordProblemLine(word, reading, lang) {
245
- const ref = problemRefOf(word, reading);
246
- return ref === undefined ? undefined : renderMessage(ref, lang);
247
- }
248
- function problemRefOf(word, reading) {
241
+ function wordCauseOf(reading) {
249
242
  const kind = ownData(reading, 'kind');
250
- if (kind !== 'unbound' && kind !== 'ambiguous')
251
- return undefined;
252
- const quoted = quoteUntrustedForSentence(typeof word === 'string' ? word.trim() : '', 80) ?? '""';
253
243
  if (kind === 'ambiguous')
254
- return msg('model.subagent.ambiguous', { word: quoted });
244
+ return 'ambiguous';
245
+ if (kind !== 'unbound')
246
+ return undefined;
255
247
  const problem = ownData(reading, 'problem');
256
- if (problem === 'tiers-inert')
257
- return msg('model.subagent.tiersInert', { word: quoted });
258
- if (problem === 'binding-not-in-catalog')
259
- return msg('model.subagent.bindingNotInCatalog', { word: quoted });
260
- return msg('model.subagent.chainUnbound', { word: quoted });
248
+ return problem === 'tiers-inert' || problem === 'binding-not-in-catalog' ? problem : 'chain-unbound';
249
+ }
250
+ const PROBLEM_LINE_KEYS = Object.freeze({
251
+ ambiguous: 'model.subagent.ambiguous',
252
+ 'tiers-inert': 'model.subagent.tiersInert',
253
+ 'chain-unbound': 'model.subagent.chainUnbound',
254
+ 'binding-not-in-catalog': 'model.subagent.bindingNotInCatalog',
255
+ });
256
+ const CALL_REFUSAL_KEYS = Object.freeze({
257
+ ambiguous: 'model.subagent.call.ambiguous',
258
+ 'tiers-inert': 'model.subagent.call.tiersInert',
259
+ 'chain-unbound': 'model.subagent.call.chainUnbound',
260
+ 'binding-not-in-catalog': 'model.subagent.call.bindingNotInCatalog',
261
+ });
262
+ const WORD_SHOWN_MAX = 80;
263
+ function quotedWord(word) {
264
+ return quoteUntrustedForSentence(typeof word === 'string' ? word.trim() : '', WORD_SHOWN_MAX) ?? '""';
265
+ }
266
+ export function subagentModelWordProblemLine(word, reading, lang) {
267
+ const cause = wordCauseOf(reading);
268
+ return cause === undefined ? undefined : renderMessage(msg(PROBLEM_LINE_KEYS[cause], { word: quotedWord(word) }), lang);
269
+ }
270
+ export function subagentModelCallRefusalReason(word, reading, lang) {
271
+ try {
272
+ const cause = wordCauseOf(reading);
273
+ if (cause === undefined)
274
+ return undefined;
275
+ const label = ownData(reading, 'label');
276
+ const tier = typeof label === 'string' && label.trim() !== '' ? label : word;
277
+ return renderMessage(msg(CALL_REFUSAL_KEYS[cause], { word: quotedWord(word), tier: quotedWord(tier) }), lang);
278
+ }
279
+ catch {
280
+ return undefined;
281
+ }
282
+ }
283
+ const notSent = () => Object.freeze({ verdict: 'accepted', why: 'not_sent' });
284
+ const isVocabKind = (k) => k === 'tier' || k === 'cc-alias' || k === 'best' || k === 'default';
285
+ function admissionIn(input) {
286
+ const reading = resolveIn(input);
287
+ const model = reading.model;
288
+ if (model === undefined)
289
+ return notSent();
290
+ const live = ownData(input, 'liveCatalog');
291
+ if (live === undefined || live === null)
292
+ return Object.freeze({ verdict: 'unknown', why: 'catalog_absent', model });
293
+ const a = modelAcceptanceOf(model, live);
294
+ if (a.verdict === 'accepted')
295
+ return Object.freeze({ verdict: 'accepted', why: 'served', model });
296
+ if (a.verdict === 'refused') {
297
+ if (a.why === 'not_at_mentionable')
298
+ return Object.freeze({ verdict: 'accepted', why: 'served', model });
299
+ if (a.why === 'disabled')
300
+ return Object.freeze({ verdict: 'refused', why: 'disabled', model });
301
+ return Object.freeze({ verdict: 'refused', why: isVocabKind(reading.kind) ? 'not_served' : 'not_listed', model });
302
+ }
303
+ return Object.freeze({ verdict: 'unknown', why: a.why === 'model_absent' ? 'catalog_unreadable' : a.why, model });
304
+ }
305
+ export function subagentModelAdmissionOf(input) {
306
+ try {
307
+ return admissionIn(input);
308
+ }
309
+ catch {
310
+ const w = ownData(input, 'word');
311
+ const word = typeof w === 'string' ? w.trim() : '';
312
+ return word === '' ? notSent() : Object.freeze({ verdict: 'unknown', why: 'catalog_unreadable', model: word });
313
+ }
314
+ }
315
+ const ADMISSION_LINE_KEYS = Object.freeze({
316
+ not_listed: 'model.subagent.refused.notListed',
317
+ not_served: 'model.subagent.refused.notServed',
318
+ disabled: 'model.subagent.refused.disabled',
319
+ });
320
+ export function subagentModelAdmissionLine(word, admission, lang) {
321
+ try {
322
+ if (ownData(admission, 'verdict') !== 'refused')
323
+ return undefined;
324
+ const why = ownData(admission, 'why');
325
+ if (why !== 'not_listed' && why !== 'not_served' && why !== 'disabled')
326
+ return undefined;
327
+ return renderMessage(msg(ADMISSION_LINE_KEYS[why], { word: quotedWord(word) }), lang);
328
+ }
329
+ catch {
330
+ return undefined;
331
+ }
261
332
  }
@@ -1,5 +1,5 @@
1
1
  import { displayUntrusted } from './displayUntrusted.js';
2
- import { abortableSleep } from './abortableSleep.js';
2
+ import { requestDeadline } from './abortableSleep.js';
3
3
  import { causeSlotProtected, walkCauseChain } from './engineWireFor.js';
4
4
  import { readThrownSlot } from './wireFailureShape.js';
5
5
  import { guardedRead, readOwnDataValue } from './ownKey.js';
@@ -128,15 +128,16 @@ export async function probeModelCapability(entry, send) {
128
128
  evidence: { baseline, attempts, lowEffortAccepted: !low.refused },
129
129
  };
130
130
  }
131
+ const _capabilityBitsPin = true;
132
+ void _capabilityBitsPin;
131
133
  export function applyProbeToEntry(entry, result) {
132
134
  if (result.verdict === 'inconclusive')
133
135
  return entry;
134
136
  const compatIn = typeof entry.compat === 'object' && entry.compat !== null && !Array.isArray(entry.compat)
135
137
  ? entry.compat
136
138
  : undefined;
137
- if (result.verdict === 'no_reasoning') {
138
- return { ...entry, reasoning: false };
139
- }
139
+ if (result.verdict === 'no_reasoning')
140
+ return entry;
140
141
  if (result.verdict === 'disabled_via' && typeof result.thinkingFormat === 'string') {
141
142
  return { ...entry, reasoning: true, compat: { ...compatIn, thinkingFormat: result.thinkingFormat } };
142
143
  }
@@ -521,45 +522,8 @@ function shownCause(e, redact) {
521
522
  const shown = displayUntrusted(masked, { max: 160 });
522
523
  return shown.trim() === '' ? undefined : shown;
523
524
  }
524
- const MAX_TIMER_MS = 2_147_483_647;
525
- function probeDeadline(ms, cancel) {
526
- const ctl = new AbortController();
527
- const stop = new AbortController();
528
- let expired = false;
529
- const gone = new Promise((_resolve, reject) => {
530
- const fire = () => reject(Object.assign(new Error('aborted'), { name: 'AbortError' }));
531
- if (ctl.signal.aborted)
532
- fire();
533
- else
534
- ctl.signal.addEventListener('abort', fire, { once: true });
535
- });
536
- gone.catch(() => undefined);
537
- void abortableSleep(Math.min(ms, MAX_TIMER_MS), stop.signal).then(() => {
538
- if (stop.signal.aborted)
539
- return;
540
- expired = true;
541
- ctl.abort();
542
- });
543
- const onCancel = () => ctl.abort();
544
- if (cancel !== undefined) {
545
- if (cancel.aborted)
546
- ctl.abort();
547
- else
548
- cancel.addEventListener('abort', onCancel, { once: true });
549
- }
550
- return {
551
- signal: ctl.signal,
552
- expired: () => expired,
553
- abort: () => {
554
- stop.abort();
555
- cancel?.removeEventListener('abort', onCancel);
556
- ctl.abort();
557
- },
558
- race: (p) => Promise.race([p, gone]),
559
- };
560
- }
561
525
  async function getCatalogText(fetchIt, url, headers, timeoutMs, cancel) {
562
- const d = probeDeadline(timeoutMs, cancel);
526
+ const d = requestDeadline(timeoutMs, cancel);
563
527
  try {
564
528
  const res = await d.race(fetchIt(url, { method: 'GET', headers, signal: d.signal }));
565
529
  let text = '';
@@ -576,7 +540,7 @@ async function getCatalogText(fetchIt, url, headers, timeoutMs, cancel) {
576
540
  }
577
541
  }
578
542
  async function postForFirstToken(fetchIt, api, url, path, headers, body, deadlineMs, cancel, now, redact) {
579
- const d = probeDeadline(deadlineMs, cancel);
543
+ const d = requestDeadline(deadlineMs, cancel);
580
544
  const startedAt = now();
581
545
  try {
582
546
  const res = await d.race(fetchIt(url, { method: 'POST', headers, body, signal: d.signal }));
@@ -1,8 +1,15 @@
1
- import type { WiringManifestModRefusedView } from './adapter/downstream/eventToSdkMessage.js';
1
+ import type { WiringManifestModRefusedView, WiringManifestModView } from './adapter/downstream/eventToSdkMessage.js';
2
+ import type { SessionModsView } from './seatContract.js';
3
+ import type { DeviceUnreadable } from './deviceRebind.js';
2
4
  import type { EngineNoticeChromeEvent } from './seam.js';
3
5
  import type { UiLanguage } from './env/uiLanguage.js';
6
+ import { type ApprovalRequestedBy } from './hitl/approvalAskers.js';
4
7
  export declare const MOD_LOADER_VERBS: readonly ["list", "load", "unload", "status"];
5
8
  export type ModLoaderVerb = (typeof MOD_LOADER_VERBS)[number];
6
9
  export declare function readModRegistrationRefusedNotice(ev: EngineNoticeChromeEvent): WiringManifestModRefusedView | undefined;
10
+ export declare function sessionModsOf(manifest: {
11
+ readonly mods?: readonly WiringManifestModView[];
12
+ } | null | undefined): SessionModsView | DeviceUnreadable;
7
13
  export declare function modCardSentence(input: object | null | undefined, lang?: UiLanguage): string | undefined;
14
+ export declare function approvalRequestedBySentence(by: ApprovalRequestedBy | null | undefined, lang?: UiLanguage): string | undefined;
8
15
  export declare function modLoaderFailureSentence(name: string, error: unknown, lang?: UiLanguage): string;
package/dist/modsFace.js CHANGED
@@ -4,6 +4,7 @@ import { displayUntrusted } from './displayUntrusted.js';
4
4
  import { WIRE_FAILURE_UNRENDERABLE_TEXT, wireFailureTextsOf } from './wireFailureShape.js';
5
5
  import { gateOutcomeOf, isDeniedGate, rewriteExtensionNamesOf, toolInputRewriteOf } from './gateOutcome.js';
6
6
  import { guardedRead, readOwnDataNonEmptyString, readOwnDataValue, toolResultBlockOf } from './ownKey.js';
7
+ import { requestedByViewOf } from './hitl/approvalAskers.js';
7
8
  const isCardRecordObject = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
8
9
  export const MOD_LOADER_VERBS = Object.freeze(['list', 'load', 'unload', 'status']);
9
10
  const modRowOf = (r) => modRowsOf([r])?.[0];
@@ -21,6 +22,18 @@ export function readModRegistrationRefusedNotice(ev) {
21
22
  return undefined;
22
23
  }
23
24
  }
25
+ export function sessionModsOf(manifest) {
26
+ try {
27
+ if (!isCardRecordObject(manifest))
28
+ return sessionModsUnreadable();
29
+ const rows = modRowsOf(readOwnDataValue(manifest, 'mods'));
30
+ return rows === undefined ? sessionModsUnreadable() : Object.freeze({ rows: Object.freeze(rows.slice()) });
31
+ }
32
+ catch {
33
+ return sessionModsUnreadable();
34
+ }
35
+ }
36
+ const sessionModsUnreadable = () => Object.freeze({ kind: 'unreadable', why: renderMessage(msg('config.mods.session.unreadable')) });
24
37
  const MOD_NAME_SHOWN_MAX = 64;
25
38
  const MOD_REASON_SHOWN_MAX = 160;
26
39
  const shownName = (s) => displayUntrusted(s, { blanks: true, max: MOD_NAME_SHOWN_MAX });
@@ -54,6 +67,20 @@ export function modCardSentence(input, lang) {
54
67
  return undefined;
55
68
  }
56
69
  }
70
+ export function approvalRequestedBySentence(by, lang) {
71
+ try {
72
+ const view = requestedByViewOf(by);
73
+ if (view === undefined)
74
+ return undefined;
75
+ const name = shownName(view.name);
76
+ if (name.trim() === '')
77
+ return undefined;
78
+ return renderMessage(msg('config.mods.request.by', { by: name }), lang);
79
+ }
80
+ catch {
81
+ return undefined;
82
+ }
83
+ }
57
84
  export function modLoaderFailureSentence(name, error, lang) {
58
85
  const shown = guardedRead(() => (typeof name === 'string' ? shownName(name) : undefined)) ?? '';
59
86
  const { reason } = wireFailureTextsOf(error);
@@ -1,4 +1,5 @@
1
1
  import type { PlanReviewOutcomeMeta } from './hitl/planReviewWire.js';
2
+ import type { UiLanguage } from './env/uiLanguage.js';
2
3
  import type { SubmissionKind } from './request/submissionIdentity.js';
3
4
  export interface TaskNotificationFields {
4
5
  taskId: string;
@@ -9,6 +10,7 @@ export interface TaskNotificationFields {
9
10
  outputFile?: string;
10
11
  diagnostics?: string;
11
12
  result?: string;
13
+ error?: string;
12
14
  stoppedBy?: string;
13
15
  partial?: boolean;
14
16
  exitCode?: number;
@@ -86,6 +88,19 @@ export declare function installNotificationQueuePort(port: NotificationQueuePort
86
88
  export declare function notificationQueuePortMisses(): number;
87
89
  export declare function _resetNotificationQueuePortForTest(): void;
88
90
  export declare function enqueuePlanReviewOutcome(value: string, meta?: PlanReviewOutcomeMeta): boolean;
91
+ export type ResupplyTruncatedSource = 'task_notification' | 'workflow_complete';
92
+ export declare function resupplyTruncatedSentence(facts: {
93
+ readonly bytes: number;
94
+ readonly droppedKeys: readonly string[];
95
+ } | null | undefined, lang?: UiLanguage): string | undefined;
96
+ export interface ResupplyTruncatedArmBody {
97
+ readonly source: ResupplyTruncatedSource;
98
+ readonly taskId: string;
99
+ readonly bytes: number;
100
+ readonly droppedKeys: readonly string[];
101
+ readonly text: string;
102
+ }
103
+ export declare function resupplyTruncatedArmBody(carrier: object | null | undefined, source: ResupplyTruncatedSource, taskId: string): ResupplyTruncatedArmBody | undefined;
89
104
  export declare function dropQueuedNotificationsForRun(taskId: string): number;
90
105
  export declare function markEngineWorkflowNotified(runId: string): void;
91
106
  export declare function isEngineWorkflowNotified(runId: string): boolean;
@@ -93,11 +108,22 @@ export declare function noteWorkflowCompletionCardEnqueued(runId: string): void;
93
108
  export declare function listNotifiedRuns(): string[];
94
109
  export declare function listWorkflowCompletionCardsEnqueued(): string[];
95
110
  export declare function isWorkflowCompletionCardEnqueued(runId: string): boolean;
96
- type WorkflowStatusProbe = (runId: string) => Promise<{
97
- terminal: boolean;
98
- status: 'completed' | 'failed';
99
- summary: string;
100
- } | null>;
111
+ export type WorkflowRunReader = (runId: string) => Promise<unknown>;
112
+ export type WorkflowRunTerminalReading = {
113
+ readonly state: 'running';
114
+ } | {
115
+ readonly state: 'awaiting approval';
116
+ } | {
117
+ readonly state: 'completed' | 'failed';
118
+ readonly result?: string;
119
+ readonly error?: string;
120
+ readonly pointer: 'absent';
121
+ readonly truncated?: true;
122
+ } | {
123
+ readonly state: 'unknown';
124
+ readonly why: 'body_unreadable' | 'status_unreadable' | 'status_unrecognized';
125
+ };
126
+ export declare function workflowRunTerminalReadingOf(body: unknown): WorkflowRunTerminalReading;
101
127
  export declare function outstandingWorkflowCount(): number;
102
128
  export declare function outstandingDeliverableWorkflowCount(): number;
103
129
  export declare function subscribeOutstandingWorkflows(listener: () => void): () => void;
@@ -111,7 +137,7 @@ export interface NotificationDropCounters {
111
137
  bgWatchCollectedUnprobed: number;
112
138
  }
113
139
  export declare function notificationDropCounters(): NotificationDropCounters;
114
- export declare function installWorkflowStatusProbe(probe: WorkflowStatusProbe): void;
140
+ export declare function installWorkflowRunReader(reader: WorkflowRunReader | null): void;
115
141
  type BgTaskStatusProbe = (taskId: string) => Promise<{
116
142
  terminal: boolean;
117
143
  status: string;
@@ -129,6 +155,7 @@ export interface EngineWorkflowCompletion {
129
155
  status: 'completed' | 'failed';
130
156
  summary: string;
131
157
  completionId?: string;
158
+ diagnostics?: string;
132
159
  }
133
160
  export declare function enqueueBgChildNotification(raw: {
134
161
  taskId: string;
@@ -138,6 +165,9 @@ export declare function enqueueBgChildNotification(raw: {
138
165
  completionId?: string;
139
166
  }): void;
140
167
  export declare function enqueueEngineWorkflowNotification(raw: EngineWorkflowCompletion): void;
168
+ export declare function workflowRecordRefOf(diagnostics: string | undefined): string | undefined;
169
+ export declare function takeWorkflowPointerSupplement(runId: string, status: string, diagnostics: string | undefined, completionId?: string): Readonly<TaskNotificationFields> | undefined;
170
+ export declare function settleWorkflowPointerOwed(runId: string): void;
141
171
  export declare function _resetEngineTaskNotificationForTest(): void;
142
172
  export declare function _tickWatchOnceForTest(nowMs?: number): Promise<void>;
143
173
  export declare function _setWatcherTimingForTest(o: {