@sema-agent/client-core 0.97.1 → 0.99.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 (353) hide show
  1. package/CHANGELOG.md +607 -0
  2. package/README.md +96 -46
  3. package/dist/adapt/arms.d.ts +1 -0
  4. package/dist/adapt/arms.js +188 -53
  5. package/dist/adapt/ids.d.ts +12 -1
  6. package/dist/adapt/ids.js +59 -8
  7. package/dist/adapt/instanceLedger.d.ts +50 -0
  8. package/dist/adapt/instanceLedger.js +147 -0
  9. package/dist/adapt/panelTasks.d.ts +1 -1
  10. package/dist/adapt/panelTasks.js +2 -2
  11. package/dist/adapt/textStream.d.ts +1 -0
  12. package/dist/adapt/textStream.js +24 -7
  13. package/dist/adapt/toolCards.d.ts +27 -5
  14. package/dist/adapt/toolCards.js +39 -6
  15. package/dist/adapt/wireShapes.js +6 -2
  16. package/dist/adapt.d.ts +2 -0
  17. package/dist/adapt.js +8 -3
  18. package/dist/adapter/activeRunSelfHeal.d.ts +9 -3
  19. package/dist/adapter/activeRunSelfHeal.js +205 -313
  20. package/dist/adapter/downstream/eventToSdkMessage.d.ts +2 -5
  21. package/dist/adapter/downstream/eventToSdkMessage.js +77 -36
  22. package/dist/adapter/downstream/terminalToSdkResult.js +11 -4
  23. package/dist/adapter/downstream/turnUsageToModelUsage.d.ts +5 -2
  24. package/dist/adapter/downstream/turnUsageToModelUsage.js +2 -0
  25. package/dist/adapter/runStream.js +79 -48
  26. package/dist/adapter/types.d.ts +4 -4
  27. package/dist/adapter/types.js +2 -1
  28. package/dist/agentSession/backgroundView.js +2 -1
  29. package/dist/agentSession/engineAgentRegistryRead.d.ts +2 -2
  30. package/dist/agentSession/engineAgentRegistryRead.js +12 -13
  31. package/dist/agentSession/engineSessionBackgroundStop.js +16 -8
  32. package/dist/agentsWireCaps.d.ts +8 -11
  33. package/dist/agentsWireCaps.js +196 -194
  34. package/dist/approvalDecidedByCapability.d.ts +0 -4
  35. package/dist/approvalDecidedByCapability.js +0 -6
  36. package/dist/approvalsStreamLiveCapability.d.ts +0 -4
  37. package/dist/approvalsStreamLiveCapability.js +0 -6
  38. package/dist/assistantInbox.d.ts +34 -0
  39. package/dist/assistantInbox.js +118 -0
  40. package/dist/centerWiringCapability.js +9 -1
  41. package/dist/clientSlice.d.ts +0 -9
  42. package/dist/clientSlice.js +0 -3
  43. package/dist/cloudConfigWireCaps.d.ts +5 -3
  44. package/dist/cloudConfigWireCaps.js +106 -64
  45. package/dist/compensations.js +1 -1
  46. package/dist/connectorStatus.d.ts +21 -0
  47. package/dist/connectorStatus.js +112 -0
  48. package/dist/controlRouter.d.ts +18 -3
  49. package/dist/controlRouter.js +106 -67
  50. package/dist/coreValuePorts.d.ts +29 -4
  51. package/dist/coreValuePorts.js +10 -0
  52. package/dist/corruptSessionCopy.d.ts +2 -1
  53. package/dist/corruptSessionCopy.js +3 -3
  54. package/dist/decideReceipt.d.ts +2 -2
  55. package/dist/decideReceipt.js +5 -2
  56. package/dist/declared/supportFloorDeclared.js +3 -3
  57. package/dist/detachWire.js +3 -2
  58. package/dist/deviceExecutorManagementCapability.d.ts +0 -4
  59. package/dist/deviceExecutorManagementCapability.js +0 -6
  60. package/dist/deviceRebind.d.ts +49 -1
  61. package/dist/deviceRebind.js +221 -3
  62. package/dist/devicesFace.d.ts +34 -0
  63. package/dist/devicesFace.js +90 -0
  64. package/dist/displayUntrusted.d.ts +2 -0
  65. package/dist/displayUntrusted.js +253 -76
  66. package/dist/engineAgentAbsence.d.ts +1 -1
  67. package/dist/engineAgentPanelStore.d.ts +12 -4
  68. package/dist/engineAgentPanelStore.js +16 -11
  69. package/dist/engineCapReader.d.ts +2 -5
  70. package/dist/engineCapReader.js +8 -10
  71. package/dist/engineCapsCache.d.ts +12 -0
  72. package/dist/engineCapsCache.js +76 -18
  73. package/dist/engineCapsChange.d.ts +2 -0
  74. package/dist/engineCapsChange.js +9 -0
  75. package/dist/engineClosedSets.d.ts +1 -0
  76. package/dist/engineClosedSets.js +4 -1
  77. package/dist/engineErrorCodes.d.ts +11 -3
  78. package/dist/engineErrorCodes.js +11 -8
  79. package/dist/engineIdentity.d.ts +1 -0
  80. package/dist/engineIdentity.js +8 -0
  81. package/dist/engineRowRef.d.ts +28 -0
  82. package/dist/engineRowRef.js +114 -0
  83. package/dist/engineSessionMessages.d.ts +68 -0
  84. package/dist/engineSessionMessages.js +370 -0
  85. package/dist/engineTargetSeat.d.ts +27 -0
  86. package/dist/engineTargetSeat.js +199 -0
  87. package/dist/engineToolDirectory.d.ts +0 -9
  88. package/dist/engineToolDirectory.js +1 -94
  89. package/dist/engineUrl.d.ts +18 -0
  90. package/dist/engineUrl.js +52 -0
  91. package/dist/engineWireFor.js +3 -8
  92. package/dist/env/uiLanguage.d.ts +11 -1
  93. package/dist/env/uiLanguage.js +38 -2
  94. package/dist/eventLeg.d.ts +100 -0
  95. package/dist/eventLeg.js +305 -0
  96. package/dist/executionLaneCapability.d.ts +0 -4
  97. package/dist/executionLaneCapability.js +3 -16
  98. package/dist/fileHistoryCaptureCapability.d.ts +2 -5
  99. package/dist/fileHistoryCaptureCapability.js +13 -21
  100. package/dist/fileHistoryLegNotice.d.ts +2 -1
  101. package/dist/fileHistoryLegNotice.js +3 -3
  102. package/dist/fleet/fleetLedger.d.ts +0 -3
  103. package/dist/fleet/fleetLedger.js +21 -36
  104. package/dist/fleet/fleetProjection.d.ts +2 -2
  105. package/dist/fleet/fleetProjection.js +10 -8
  106. package/dist/frameBinding.d.ts +8 -0
  107. package/dist/frameBinding.js +35 -0
  108. package/dist/gateFailureCodes.d.ts +2 -0
  109. package/dist/gateFailureCodes.js +15 -0
  110. package/dist/gateOutcome.d.ts +3 -1
  111. package/dist/gateOutcome.js +41 -8
  112. package/dist/gateVocabulary.d.ts +10 -4
  113. package/dist/gateVocabulary.js +107 -47
  114. package/dist/generated/engineAskFaceTables.js +2 -2
  115. package/dist/generated/engineFactTables.d.ts +22 -3
  116. package/dist/generated/engineFactTables.js +51 -4
  117. package/dist/generated/engineNoticeTables.js +18 -3
  118. package/dist/generated/settingsSchemaFns.d.ts +6 -0
  119. package/dist/generated/settingsSchemaFns.js +57 -0
  120. package/dist/generated/settingsSchemaHooksClassifier.d.ts +2 -0
  121. package/dist/generated/settingsSchemaHooksClassifier.js +254 -0
  122. package/dist/generated/settingsSchemaTables.d.ts +1 -0
  123. package/dist/generated/settingsSchemaTables.js +4 -0
  124. package/dist/generated/settingsSchemaTypes.d.ts +105 -0
  125. package/dist/generated/settingsSchemaTypes.js +1 -0
  126. package/dist/generated/toolNameTables.d.ts +1 -0
  127. package/dist/generated/toolNameTables.js +1 -0
  128. package/dist/hitl/allowRuleShadow.d.ts +8 -2
  129. package/dist/hitl/allowRuleShadow.js +36 -29
  130. package/dist/hitl/approvalCardReading.d.ts +15 -0
  131. package/dist/hitl/approvalCardReading.js +154 -0
  132. package/dist/hitl/approvalCardReasons.d.ts +14 -0
  133. package/dist/hitl/approvalCardReasons.js +119 -0
  134. package/dist/hitl/approvalHolds.d.ts +50 -15
  135. package/dist/hitl/approvalHolds.js +177 -27
  136. package/dist/hitl/approvalResolution.d.ts +51 -26
  137. package/dist/hitl/approvalResolution.js +86 -122
  138. package/dist/hitl/approvalsFeed.js +6 -18
  139. package/dist/hitl/askClassPair.d.ts +2 -0
  140. package/dist/hitl/askClassPair.js +17 -0
  141. package/dist/hitl/askGateWire.d.ts +20 -2
  142. package/dist/hitl/askGateWire.js +50 -1
  143. package/dist/hitl/askParkRowRouting.d.ts +5 -0
  144. package/dist/hitl/askParkRowRouting.js +32 -1
  145. package/dist/hitl/askSettlementLine.d.ts +28 -0
  146. package/dist/hitl/askSettlementLine.js +99 -0
  147. package/dist/hitl/automaticAnswerVerdict.d.ts +3 -2
  148. package/dist/hitl/automaticAnswerVerdict.js +29 -13
  149. package/dist/hitl/crashConverged.d.ts +11 -20
  150. package/dist/hitl/crashConverged.js +56 -0
  151. package/dist/hitl/crashConvergedNotice.d.ts +6 -3
  152. package/dist/hitl/crashConvergedNotice.js +48 -24
  153. package/dist/hitl/decisionConflict.js +3 -10
  154. package/dist/hitl/decisionRefusal.d.ts +40 -1
  155. package/dist/hitl/decisionRefusal.js +199 -42
  156. package/dist/hitl/frameRouter.d.ts +5 -2
  157. package/dist/hitl/frameRouter.js +27 -24
  158. package/dist/hitl/gateLedger.d.ts +2 -0
  159. package/dist/hitl/gateLedger.js +50 -13
  160. package/dist/hitl/hitlBridge.d.ts +2 -2
  161. package/dist/hitl/hitlBridge.js +13 -10
  162. package/dist/hitl/livePendingAsk.d.ts +3 -3
  163. package/dist/hitl/livePendingAsk.js +7 -18
  164. package/dist/hitl/parkResolver.d.ts +2 -24
  165. package/dist/hitl/parkResolver.js +61 -97
  166. package/dist/hitl/persistedRulesWire.d.ts +25 -0
  167. package/dist/hitl/persistedRulesWire.js +104 -2
  168. package/dist/hitl/planReviewWire.d.ts +31 -13
  169. package/dist/hitl/planReviewWire.js +120 -78
  170. package/dist/hitl/refusedToolNameProse.d.ts +0 -1
  171. package/dist/hitl/refusedToolNameProse.js +0 -3
  172. package/dist/hitl/replayedApproval.d.ts +4 -3
  173. package/dist/hitl/replayedApproval.js +7 -4
  174. package/dist/hitl/sessionPolicyDeliverable.d.ts +2 -0
  175. package/dist/hitl/sessionPolicyDeliverable.js +48 -7
  176. package/dist/hitl/sessionPolicyWire.d.ts +34 -21
  177. package/dist/hitl/sessionPolicyWire.js +179 -70
  178. package/dist/hitl/standingRows.d.ts +20 -2
  179. package/dist/hitl/standingRows.js +69 -8
  180. package/dist/hitl/suspendedReopen.d.ts +2 -1
  181. package/dist/hitl/suspendedReopen.js +7 -10
  182. package/dist/hitl/toolApprovalWire.d.ts +103 -156
  183. package/dist/hitl/toolApprovalWire.js +661 -411
  184. package/dist/hookMatcherVerdict.d.ts +6 -1
  185. package/dist/hookMatcherVerdict.js +14 -7
  186. package/dist/hooksWireCaps.d.ts +2 -2
  187. package/dist/hooksWireCaps.js +174 -81
  188. package/dist/host.d.ts +21 -0
  189. package/dist/hostTurnSettings.d.ts +71 -0
  190. package/dist/hostTurnSettings.js +291 -0
  191. package/dist/humanTurn.d.ts +14 -1
  192. package/dist/humanTurn.js +100 -12
  193. package/dist/humanTurnRead.d.ts +2 -0
  194. package/dist/humanTurnRead.js +22 -1
  195. package/dist/i18n/messages.en.d.ts +703 -0
  196. package/dist/i18n/messages.en.js +701 -0
  197. package/dist/i18n/messages.zh.d.ts +3 -0
  198. package/dist/i18n/messages.zh.js +837 -0
  199. package/dist/i18n/translate.d.ts +25 -0
  200. package/dist/i18n/translate.js +127 -0
  201. package/dist/index.d.ts +78 -29
  202. package/dist/index.js +54 -18
  203. package/dist/inheritEnvCapability.d.ts +32 -0
  204. package/dist/inheritEnvCapability.js +104 -0
  205. package/dist/inheritEnvWire.d.ts +3 -2
  206. package/dist/inheritEnvWire.js +12 -14
  207. package/dist/interactiveHalt.js +17 -6
  208. package/dist/liveModelCatalog.d.ts +3 -3
  209. package/dist/liveModelCatalog.js +15 -13
  210. package/dist/liveQuestionStore.d.ts +2 -21
  211. package/dist/mcpLiveness.d.ts +2 -1
  212. package/dist/mcpPanel.d.ts +10 -1
  213. package/dist/mcpPanel.js +40 -13
  214. package/dist/mcpProbeCapability.d.ts +2 -1
  215. package/dist/mcpProbeCapability.js +7 -11
  216. package/dist/mcpProbeWire.d.ts +9 -2
  217. package/dist/mcpProbeWire.js +6 -1
  218. package/dist/mcpWireCaps.d.ts +47 -2
  219. package/dist/mcpWireCaps.js +164 -16
  220. package/dist/memoryEntriesWire.d.ts +4 -9
  221. package/dist/memoryEntriesWire.js +5 -10
  222. package/dist/model/modelSupplyRules.d.ts +0 -2
  223. package/dist/model/modelSupplyRules.js +3 -12
  224. package/dist/model/modelsPolicy.d.ts +0 -5
  225. package/dist/model/modelsPolicy.js +6 -36
  226. package/dist/model/onboardJudgement.d.ts +93 -0
  227. package/dist/model/onboardJudgement.js +415 -0
  228. package/dist/model/subagentModelWord.d.ts +31 -0
  229. package/dist/model/subagentModelWord.js +261 -0
  230. package/dist/model/tierVocabulary.d.ts +2 -0
  231. package/dist/model/tierVocabulary.js +17 -5
  232. package/dist/modelCapabilityProbe.d.ts +64 -0
  233. package/dist/modelCapabilityProbe.js +600 -0
  234. package/dist/modelIdentityResolvability.d.ts +3 -0
  235. package/dist/modelIdentityResolvability.js +26 -17
  236. package/dist/notifications.d.ts +6 -0
  237. package/dist/notifications.js +71 -23
  238. package/dist/outputStyleSeatCapability.d.ts +0 -3
  239. package/dist/outputStyleSeatCapability.js +0 -3
  240. package/dist/ownKey.d.ts +22 -0
  241. package/dist/ownKey.js +94 -3
  242. package/dist/panelReduce.d.ts +21 -10
  243. package/dist/panelReduce.js +728 -550
  244. package/dist/panelStateHolder.d.ts +3 -7
  245. package/dist/panelStateHolder.js +14 -130
  246. package/dist/peerLaneCapability.d.ts +0 -4
  247. package/dist/peerLaneCapability.js +0 -6
  248. package/dist/permissionRuleIssue.js +2 -0
  249. package/dist/permissionRulesWriteCapability.d.ts +2 -5
  250. package/dist/permissionRulesWriteCapability.js +8 -12
  251. package/dist/permissionWireCaps.d.ts +2 -2
  252. package/dist/permissionWireCaps.js +2 -0
  253. package/dist/permissionsAllowGrantCapability.d.ts +0 -4
  254. package/dist/permissionsAllowGrantCapability.js +0 -6
  255. package/dist/permissionsDeclaration.d.ts +0 -11
  256. package/dist/permissionsDeclaration.js +60 -53
  257. package/dist/pluginHooksWire.d.ts +46 -3
  258. package/dist/pluginHooksWire.js +219 -16
  259. package/dist/preemptWire.d.ts +44 -0
  260. package/dist/preemptWire.js +83 -0
  261. package/dist/printModelStatus.d.ts +63 -0
  262. package/dist/printModelStatus.js +155 -0
  263. package/dist/printToolResultFrame.js +15 -4
  264. package/dist/replayBody.d.ts +3 -0
  265. package/dist/replayBody.js +14 -0
  266. package/dist/request/taskRequest.d.ts +11 -6
  267. package/dist/request/taskRequest.js +112 -19
  268. package/dist/resumeRefusalCopy.d.ts +13 -9
  269. package/dist/resumeRefusalCopy.js +81 -118
  270. package/dist/retryStatus.d.ts +45 -0
  271. package/dist/retryStatus.js +185 -1
  272. package/dist/rewindArchiveCapability.d.ts +0 -4
  273. package/dist/rewindArchiveCapability.js +2 -10
  274. package/dist/rewindArchiveReading.d.ts +0 -1
  275. package/dist/rewindArchiveReading.js +0 -3
  276. package/dist/runCancelContext.d.ts +2 -1
  277. package/dist/runCancelContext.js +4 -2
  278. package/dist/runReattachPolicy.d.ts +31 -0
  279. package/dist/runReattachPolicy.js +46 -0
  280. package/dist/runTerminal.d.ts +3 -6
  281. package/dist/runTerminal.js +8 -9
  282. package/dist/sandboxWire.d.ts +3 -1
  283. package/dist/sandboxWire.js +76 -27
  284. package/dist/scenarioRefusal.d.ts +9 -0
  285. package/dist/scenarioRefusal.js +111 -0
  286. package/dist/scenarioWire.js +1 -1
  287. package/dist/seam.d.ts +48 -2
  288. package/dist/seam.js +25 -4
  289. package/dist/seatContract.d.ts +311 -18
  290. package/dist/seatContract.js +824 -100
  291. package/dist/selfOrchestrationDenial.js +7 -19
  292. package/dist/sessionIdSegment.d.ts +6 -0
  293. package/dist/sessionIdSegment.js +24 -0
  294. package/dist/sessionMemoryStatus.js +6 -11
  295. package/dist/sessionPolicyCapability.d.ts +2 -5
  296. package/dist/sessionPolicyCapability.js +8 -12
  297. package/dist/sessionSyncFileHistoryCapability.d.ts +0 -3
  298. package/dist/sessionSyncFileHistoryCapability.js +0 -3
  299. package/dist/settingsHooksSalvage.d.ts +44 -0
  300. package/dist/settingsHooksSalvage.js +211 -0
  301. package/dist/skillToolListsCapability.d.ts +2 -4
  302. package/dist/skillToolListsCapability.js +8 -9
  303. package/dist/sqlEngineCapability.d.ts +0 -4
  304. package/dist/sqlEngineCapability.js +0 -6
  305. package/dist/sseIdleTriage.js +3 -2
  306. package/dist/steerPriorityCapability.d.ts +0 -3
  307. package/dist/steerPriorityCapability.js +0 -3
  308. package/dist/streamDrainingLegs.d.ts +4 -0
  309. package/dist/streamDrainingLegs.js +6 -1
  310. package/dist/subagent/engineCompactWire.d.ts +0 -1
  311. package/dist/subagent/engineCompactWire.js +7 -5
  312. package/dist/subagent/engineSubagentResume.js +15 -9
  313. package/dist/subagent/engineTaskHandleWire.js +4 -7
  314. package/dist/subagentContentStore.d.ts +3 -0
  315. package/dist/subagentContentStore.js +22 -10
  316. package/dist/submitReopen.d.ts +24 -0
  317. package/dist/submitReopen.js +75 -0
  318. package/dist/terminalStatuses.d.ts +3 -0
  319. package/dist/terminalStatuses.js +10 -2
  320. package/dist/toolHistoryMismatch.js +3 -2
  321. package/dist/toolResult.d.ts +10 -1
  322. package/dist/toolResult.js +34 -6
  323. package/dist/toolRoster.d.ts +3 -4
  324. package/dist/toolRoster.js +21 -22
  325. package/dist/turnFailurePresentation.d.ts +39 -0
  326. package/dist/turnFailurePresentation.js +402 -0
  327. package/dist/usageAnalytics.js +6 -11
  328. package/dist/userAttachmentEnvelope.d.ts +1 -0
  329. package/dist/userAttachmentEnvelope.js +37 -7
  330. package/dist/userAttachmentSeat.d.ts +21 -0
  331. package/dist/userAttachmentSeat.js +75 -0
  332. package/dist/userInvokedSkillsCapability.d.ts +11 -4
  333. package/dist/userInvokedSkillsCapability.js +31 -10
  334. package/dist/webSearchBackendCapability.d.ts +0 -4
  335. package/dist/webSearchBackendCapability.js +0 -6
  336. package/dist/wireErrorTriage.d.ts +7 -0
  337. package/dist/wireErrorTriage.js +26 -23
  338. package/dist/wireFailureShape.d.ts +62 -5
  339. package/dist/wireFailureShape.js +106 -5
  340. package/dist/wireRefusalCopy.d.ts +25 -3
  341. package/dist/wireRefusalCopy.js +74 -80
  342. package/dist/workflowsJournalCapability.d.ts +2 -5
  343. package/dist/workflowsJournalCapability.js +8 -12
  344. package/dist/writeProtectionCapability.d.ts +0 -4
  345. package/dist/writeProtectionCapability.js +0 -6
  346. package/docs/INTEGRATION-CLIENTS.md +1775 -56
  347. package/package.json +6 -5
  348. package/dist/attachmentSeatCapability.d.ts +0 -12
  349. package/dist/attachmentSeatCapability.js +0 -23
  350. package/dist/hitl/approvalOutcomeNote.d.ts +0 -10
  351. package/dist/hitl/approvalOutcomeNote.js +0 -29
  352. package/dist/sessionReadRedactionCapability.d.ts +0 -13
  353. package/dist/sessionReadRedactionCapability.js +0 -35
@@ -1,4 +1,5 @@
1
1
  import { displayUntrusted } from './displayUntrusted.js';
2
+ import { guardedRead, readOwnDataFiniteNumber, readOwnDataNonEmptyString, readOwnDataValue } from './ownKey.js';
2
3
  export const BRAIN_STATUS_PHASES = [
3
4
  'rate_limited',
4
5
  'retrying',
@@ -25,9 +26,12 @@ export const BRAIN_STATUS_PAYLOAD_KEYS = [
25
26
  ];
26
27
  const _brainStatusKeyPin = [true, true];
27
28
  void _brainStatusKeyPin;
29
+ const RETRY_AT_SKEW_BUDGET_MS = 5_000;
28
30
  export function mapBrainStatusToRetry(p, nowMs) {
29
31
  const remainingMs = typeof p.retryInMs === 'number' ? p.retryInMs : (p.retryInSec ?? 0) * 1000;
30
- const deadline = nowMs + Math.max(0, remainingMs);
32
+ const localDeadline = nowMs + Math.max(0, remainingMs);
33
+ const producerAt = typeof p.retryAtMs === 'number' && Number.isFinite(p.retryAtMs) ? p.retryAtMs : undefined;
34
+ const deadline = producerAt !== undefined && Math.abs(producerAt - localDeadline) <= RETRY_AT_SKEW_BUDGET_MS ? producerAt : localDeadline;
31
35
  const counts = {
32
36
  ...(typeof p.attempt === 'number' ? { attempt: p.attempt } : {}),
33
37
  ...(typeof p.maxRetries === 'number' ? { maxRetries: p.maxRetries } : {}),
@@ -74,3 +78,183 @@ export function mapBrainStatusToRetry(p, nowMs) {
74
78
  return { kind: 'error', deadline, ...extra, error: { formatted: '' } };
75
79
  }
76
80
  }
81
+ export function retryStatusFromArm(arm, nowMs) {
82
+ const object = guardedRead(() => typeof arm === 'object' && arm !== null && !Array.isArray(arm));
83
+ if (object !== true || arm === null || arm === undefined)
84
+ return undefined;
85
+ const bit = (key) => guardedRead(() => readOwnDataValue(arm, key));
86
+ if (typeof bit('parentToolCallId') === 'string')
87
+ return undefined;
88
+ const num = (key) => {
89
+ const v = bit(key);
90
+ return typeof v === 'number' && Number.isFinite(v) ? v : undefined;
91
+ };
92
+ const str = (key) => {
93
+ const v = bit(key);
94
+ return typeof v === 'string' ? v : undefined;
95
+ };
96
+ const word = (key) => {
97
+ const v = str(key);
98
+ return v !== undefined && v.length > 0 ? v : undefined;
99
+ };
100
+ const [detail, retryInSec, retryInMs, attempt, maxRetries, errClass, retryAtMs, errorStatus, elapsedMs, timeoutMs, providerCondition, providerConditionSource] = [
101
+ str('detail'), num('retryInSec'), num('retryInMs'), num('attempt'), num('maxRetries'), str('errClass'), num('retryAtMs'), num('errorStatus'), num('elapsedMs'), num('timeoutMs'), word('providerCondition'), word('providerConditionSource'),
102
+ ];
103
+ const phase = str('phase');
104
+ if (phase === undefined)
105
+ return undefined;
106
+ return mapBrainStatusToRetry({
107
+ phase,
108
+ ...(detail !== undefined ? { detail } : {}),
109
+ ...(retryInSec !== undefined ? { retryInSec } : {}),
110
+ ...(retryInMs !== undefined ? { retryInMs } : {}),
111
+ ...(attempt !== undefined ? { attempt } : {}),
112
+ ...(maxRetries !== undefined ? { maxRetries } : {}),
113
+ ...(errClass !== undefined ? { errClass } : {}),
114
+ ...(retryAtMs !== undefined ? { retryAtMs } : {}),
115
+ ...(errorStatus !== undefined ? { errorStatus } : {}),
116
+ ...(elapsedMs !== undefined ? { elapsedMs } : {}),
117
+ ...(timeoutMs !== undefined ? { timeoutMs } : {}),
118
+ ...(providerCondition !== undefined ? { providerCondition } : {}),
119
+ ...(providerConditionSource !== undefined ? { providerConditionSource } : {}),
120
+ }, nowMs);
121
+ }
122
+ const WAIT_SWITCH_FRACTION = 0.5;
123
+ const CONDITION_READINGS = Object.freeze({
124
+ quota_exhausted: { clause: 'this account cannot be served by the model service until someone acts or its usage window resets', recourse: 'switch_model' },
125
+ throttled: { clause: 'the model service is rate limiting requests, which clears on its own', recourse: 'switch_model' },
126
+ overloaded: { clause: 'the model service is overloaded', recourse: 'switch_model' },
127
+ stop_other: { clause: 'the model service refused this request', resendNote: 'resending will not change it', recourse: 'fix_request' },
128
+ unknown: null,
129
+ });
130
+ function conditionReadingOf(word) {
131
+ if (word === undefined || !Object.hasOwn(CONDITION_READINGS, word))
132
+ return undefined;
133
+ return CONDITION_READINGS[word] ?? undefined;
134
+ }
135
+ function noticeNumber(carrier, key) {
136
+ return guardedRead(() => readOwnDataFiniteNumber(carrier, key));
137
+ }
138
+ function noticeText(carrier, key) {
139
+ return guardedRead(() => readOwnDataNonEmptyString(carrier, key));
140
+ }
141
+ function noticeValue(carrier, key) {
142
+ return guardedRead(() => readOwnDataValue(carrier, key));
143
+ }
144
+ function washedText(raw) {
145
+ if (raw === undefined)
146
+ return undefined;
147
+ const shown = displayUntrusted(raw);
148
+ return shown.trim() === '' ? undefined : shown;
149
+ }
150
+ function noticeCount(n) {
151
+ return n !== undefined && Number.isInteger(n) && n >= 1 ? n : undefined;
152
+ }
153
+ function noticeHttp(n) {
154
+ return n !== undefined && Number.isInteger(n) && n >= 100 && n <= 999 ? n : undefined;
155
+ }
156
+ function spanText(ms) {
157
+ const total = Math.floor(ms / 1000);
158
+ const h = Math.floor(total / 3600);
159
+ const mi = Math.floor((total % 3600) / 60);
160
+ const se = total % 60;
161
+ return h > 0 ? `${h}h ${mi}m ${se}s` : mi > 0 ? `${mi}m ${se}s` : `${se}s`;
162
+ }
163
+ function noticeAttemptTail(attempt, maxRetries) {
164
+ if (attempt !== undefined && maxRetries !== undefined)
165
+ return `, attempt ${attempt} of ${maxRetries}`;
166
+ if (attempt !== undefined)
167
+ return `, attempt ${attempt}`;
168
+ if (maxRetries !== undefined)
169
+ return `, up to ${maxRetries} ${maxRetries === 1 ? 'retry' : 'retries'}`;
170
+ return '';
171
+ }
172
+ function sealNotice(line, phase, recourse) {
173
+ return Object.freeze(recourse === undefined ? { line, phase } : { line, recourse, phase });
174
+ }
175
+ export function retryStatusNotice(status, ctx) {
176
+ const modelName = washedText(noticeText(ctx, 'modelName'))?.trim();
177
+ const prefix = modelName === undefined || modelName === '' ? '' : `${modelName}: `;
178
+ if (status === null)
179
+ return sealNotice('', 'cleared', undefined);
180
+ const armWord = noticeText(status, 'kind');
181
+ const kind = armWord === 'stalled' || armWord === 'waiting' ? armWord : 'error';
182
+ if (kind === 'waiting') {
183
+ const elapsedRaw = noticeNumber(status, 'elapsedMs');
184
+ const timeoutRaw = noticeNumber(status, 'timeoutMs');
185
+ const elapsed = elapsedRaw !== undefined && elapsedRaw >= 0 && elapsedRaw <= Number.MAX_SAFE_INTEGER ? elapsedRaw : undefined;
186
+ const ceiling = timeoutRaw !== undefined && timeoutRaw > 0 && timeoutRaw <= Number.MAX_SAFE_INTEGER ? timeoutRaw : undefined;
187
+ const progress = [...(elapsed === undefined ? [] : [`${spanText(elapsed)} so far`]), ...(ceiling === undefined ? [] : [`limit ${spanText(ceiling)}`])];
188
+ const offerSwitch = prefix !== '' && elapsed !== undefined && ceiling !== undefined && elapsed >= ceiling * WAIT_SWITCH_FRACTION;
189
+ const text = `${prefix}Waiting for the model's first token${progress.length === 0 ? '' : ` — ${progress.join(', ')}`}${offerSwitch ? '; keep waiting or switch model' : ''}`;
190
+ return sealNotice(text, 'waiting_first_token', offerSwitch ? 'switch_model' : 'wait');
191
+ }
192
+ const terminal = kind === 'error' && noticeValue(status, 'terminal') === true;
193
+ const reading = conditionReadingOf(noticeText(status, 'providerCondition'));
194
+ const http = noticeHttp(noticeNumber(status, 'errorStatus'));
195
+ const attempt = noticeCount(noticeNumber(status, 'attempt'));
196
+ const maxRetries = noticeCount(noticeNumber(status, 'maxRetries'));
197
+ const engineWords = kind === 'stalled' ? noticeText(status, 'detail') : noticeText(noticeValue(status, 'error'), 'formatted');
198
+ const httpPart = http === undefined ? '' : ` (HTTP ${http})`;
199
+ let first;
200
+ if (terminal) {
201
+ const after = attempt === undefined ? '' : ` after ${attempt} attempt${attempt === 1 ? '' : 's'}`;
202
+ const why = reading === undefined ? '' : `: ${reading.clause}${reading.resendNote === undefined ? '' : `, and ${reading.resendNote}`}`;
203
+ first = `Stopped${after}${why}${httpPart}`;
204
+ }
205
+ else {
206
+ const head = reading !== undefined ? `${reading.clause.charAt(0).toUpperCase()}${reading.clause.slice(1)}` : http !== undefined || kind === 'error' ? 'Request failed' : 'Waiting for the API response';
207
+ first = `${head}${httpPart} — ${kind === 'stalled' ? 'will retry' : 'retrying'}${noticeAttemptTail(attempt, maxRetries)}`;
208
+ }
209
+ const note = washedText(engineWords);
210
+ const serviceSide = http !== undefined && (http === 429 || (http >= 500 && http <= 599));
211
+ const knownArm = armWord === 'stalled' || armWord === 'error';
212
+ const recourse = !knownArm
213
+ ? undefined
214
+ : reading !== undefined
215
+ ? reading.recourse
216
+ : serviceSide
217
+ ? 'switch_model'
218
+ : !terminal
219
+ ? 'wait'
220
+ : undefined;
221
+ return sealNotice(`${prefix}${first}${note === undefined ? '' : ` · ${note}`}`, kind === 'stalled' ? 'reconnecting' : terminal ? 'gave_up' : 'retrying', recourse);
222
+ }
223
+ const API_ERROR_PROVIDER_TEXT_MAX = 200;
224
+ function isRecordObject(v) {
225
+ return guardedRead(() => typeof v === 'object' && v !== null && !Array.isArray(v)) === true;
226
+ }
227
+ export function apiErrorFactsOfRow(row) {
228
+ if (!isRecordObject(row))
229
+ return Object.freeze({});
230
+ const status = noticeHttp(noticeNumber(row, '_sema_api_error_status'));
231
+ const providerCondition = noticeText(row, '_sema_provider_condition');
232
+ const errorCode = noticeText(row, '_sema_api_error_code');
233
+ return Object.freeze({
234
+ ...(status !== undefined ? { status } : {}),
235
+ ...(providerCondition !== undefined ? { providerCondition } : {}),
236
+ ...(errorCode !== undefined ? { errorCode } : {}),
237
+ });
238
+ }
239
+ export function apiErrorNotice(facts, ctx) {
240
+ if (!isRecordObject(facts))
241
+ return undefined;
242
+ const status = noticeHttp(noticeNumber(facts, 'status'));
243
+ const providerCondition = noticeText(facts, 'providerCondition');
244
+ if (status === undefined && conditionReadingOf(providerCondition) === undefined)
245
+ return undefined;
246
+ const rawText = noticeText(ctx, 'providerText');
247
+ const shownText = rawText === undefined ? undefined : washedText(displayUntrusted(rawText, { max: API_ERROR_PROVIDER_TEXT_MAX }));
248
+ const terminal = {
249
+ kind: 'error',
250
+ deadline: 0,
251
+ terminal: true,
252
+ ...(status !== undefined ? { errorStatus: status } : {}),
253
+ ...(providerCondition !== undefined ? { providerCondition } : {}),
254
+ error: { formatted: shownText ?? '' },
255
+ };
256
+ const modelName = noticeText(ctx, 'modelName');
257
+ const notice = retryStatusNotice(terminal, modelName !== undefined ? { modelName } : undefined);
258
+ const recourse = status === 401 || status === 403 ? 'check_credentials' : notice.recourse;
259
+ return Object.freeze(recourse === undefined ? { line: notice.line } : { line: notice.line, recourse });
260
+ }
@@ -3,13 +3,9 @@ import type { RewindMode } from './rewindWireCaps.js';
3
3
  export { projectRewindArchiveCapability, rewindConversationAvailability } from './rewindArchiveReading.js';
4
4
  export type { RewindArchiveBit, RewindArchiveReading, RewindCodeArchive } from './rewindArchiveReading.js';
5
5
  export type RewindArchiveMode = 'both' | 'code';
6
- export declare function noteEngineCapsForRewindArchive(baseUrl: string, caps: unknown, opts?: {
7
- generation?: number;
8
- }): void;
9
6
  export declare function observedRewindArchive(baseUrl?: string | undefined): RewindArchiveReading;
10
7
  export declare function rewindCodeArchiveAvailability(reading: RewindArchiveReading, mode: RewindArchiveMode): RewindCodeArchive;
11
8
  export declare function rewindArchiveDoctorDetail(reading: RewindArchiveReading, mode: RewindArchiveMode): string;
12
9
  export declare function engineRewindRefusedNow(option: RewindMode, reading?: RewindArchiveReading): boolean;
13
10
  export declare function rewindConversationDoctorDetail(reading: RewindArchiveReading): string;
14
11
  export declare function rewindRestoreFilesEpochDetail(reading: RewindArchiveReading): string;
15
- export declare function __resetRewindArchiveReadingsForTests(): void;
@@ -1,12 +1,7 @@
1
1
  import { engineWireTarget } from './engineWireTarget.js';
2
- import { resetRewindArchiveReader, rewindArchiveReadingAt, rewindConversationAvailability, } from './rewindArchiveReading.js';
2
+ import { rewindArchiveReadingAt, rewindConversationAvailability, } from './rewindArchiveReading.js';
3
3
  import { unreadableReadingDetail } from './engineCapReader.js';
4
4
  export { projectRewindArchiveCapability, rewindConversationAvailability } from './rewindArchiveReading.js';
5
- export function noteEngineCapsForRewindArchive(baseUrl, caps, opts) {
6
- void baseUrl;
7
- void caps;
8
- void opts;
9
- }
10
5
  export function observedRewindArchive(baseUrl = engineWireTarget()?.baseUrl) {
11
6
  return rewindArchiveReadingAt(baseUrl);
12
7
  }
@@ -87,11 +82,8 @@ export function rewindRestoreFilesEpochDetail(reading) {
87
82
  case 'off':
88
83
  return 'this engine does not announce the restore-files request key, so a rewind with code restore built from this reading leaves the key out and moves the conversation only';
89
84
  case 'not_reported':
90
- return 'this engine does not report the restore-files epoch bit (older engine), so a rewind with code restore built from this reading leaves the key out and moves the conversation only';
85
+ return 'this engine does not report the restore-files epoch bit, so a rewind with code restore built from this reading leaves the key out and moves the conversation only';
91
86
  case 'malformed':
92
87
  return 'the restore-files epoch bit is reported in an unreadable shape, so a rewind with code restore built from this reading leaves the key out and moves the conversation only';
93
88
  }
94
89
  }
95
- export function __resetRewindArchiveReadingsForTests() {
96
- resetRewindArchiveReader();
97
- }
@@ -13,5 +13,4 @@ export type RewindArchiveReading = {
13
13
  export type RewindCodeArchive = 'available' | 'unavailable' | 'unknown';
14
14
  export declare function projectRewindArchiveCapability(caps: unknown): RewindArchiveReading | undefined;
15
15
  export declare function rewindArchiveReadingAt(baseUrl: string | undefined): RewindArchiveReading;
16
- export declare function resetRewindArchiveReader(): void;
17
16
  export declare function rewindConversationAvailability(reading: RewindArchiveReading): RewindCodeArchive;
@@ -41,9 +41,6 @@ const reader = createEngineCapReader({
41
41
  export function rewindArchiveReadingAt(baseUrl) {
42
42
  return reader.observed(baseUrl);
43
43
  }
44
- export function resetRewindArchiveReader() {
45
- reader.__resetForTests();
46
- }
47
44
  export function rewindConversationAvailability(reading) {
48
45
  if (reading.kind !== 'present')
49
46
  return 'unknown';
@@ -12,6 +12,7 @@ export type RunCancelContextReading = {
12
12
  };
13
13
  export declare function readRunCancelContext(record: unknown): RunCancelContextReading | undefined;
14
14
  import { type RunTerminalRead } from './runTerminal.js';
15
+ import type { AbortCause } from '@sema-agent/sdk';
15
16
  export type RunAbortCause = {
16
17
  kind: 'cancelled';
17
18
  context?: RunCancelContextView;
@@ -30,7 +31,7 @@ export type RunAbortCause = {
30
31
  export declare const RUN_CANCELLED_CODE: "cancelled";
31
32
  export declare function classifyRunAbortCause(record: unknown): RunAbortCause;
32
33
  export declare const ABORT_CAUSES: readonly ["client_disconnected", "ask_park_grace_exhausted", "cancel_verb"];
33
- export type AbortCause = (typeof ABORT_CAUSES)[number];
34
+ export type { AbortCause };
34
35
  export type AbortCauseReading = {
35
36
  readonly kind: 'known';
36
37
  readonly cause: AbortCause;
@@ -34,9 +34,9 @@ export function readRunCancelContext(record) {
34
34
  };
35
35
  }
36
36
  import { readRunTerminal } from './runTerminal.js';
37
+ import { isSdkRunLive } from './terminalStatuses.js';
37
38
  import { SDK_ABORT_CAUSES } from './generated/sdkFactTables.js';
38
39
  export const RUN_CANCELLED_CODE = 'cancelled';
39
- const LIVE_STATUSES = new Set(['running', 'queued', 'suspended', 'needs_review']);
40
40
  export function classifyRunAbortCause(record) {
41
41
  if (record === null || typeof record !== 'object')
42
42
  return { kind: 'unknown' };
@@ -53,11 +53,13 @@ export function classifyRunAbortCause(record) {
53
53
  }
54
54
  if (read !== null && read.kind === 'paused')
55
55
  return { kind: 'run_still_live', ...(status !== undefined ? { status } : {}) };
56
- if ((read === null || read.kind === 'unknown') && status !== undefined && LIVE_STATUSES.has(status))
56
+ if ((read === null || read.kind === 'unknown') && status !== undefined && isSdkRunLive(status))
57
57
  return { kind: 'run_still_live', status };
58
58
  return { kind: 'unknown', ...(read !== null ? { terminal: read.kind } : {}) };
59
59
  }
60
60
  export const ABORT_CAUSES = SDK_ABORT_CAUSES;
61
+ const _abortCauseTablePin = true;
62
+ void _abortCauseTablePin;
61
63
  function ownDataOf(o, key) {
62
64
  const d = Object.getOwnPropertyDescriptor(o, key);
63
65
  return d !== undefined && Object.hasOwn(d, 'value') ? d.value : undefined;
@@ -0,0 +1,31 @@
1
+ export declare const REATTACH_MAX_TRIES = 5;
2
+ export interface ReattachBudget {
3
+ readonly tries: number;
4
+ readonly drainingStreak: number;
5
+ readonly drainingTotal: number;
6
+ }
7
+ export declare const REATTACH_BUDGET_FRESH: ReattachBudget;
8
+ export type ReattachEvent = {
9
+ readonly cause: 'connection_lost';
10
+ readonly hasRunId: boolean;
11
+ readonly error?: object;
12
+ } | {
13
+ readonly cause: 'stream_cap';
14
+ readonly hasRunId: boolean;
15
+ } | {
16
+ readonly cause: 'stream_draining';
17
+ readonly hasRunId: boolean;
18
+ readonly frame: object;
19
+ readonly madeProgress?: boolean;
20
+ };
21
+ export type ReattachGiveUp = 'no_run_id' | 'budget_exhausted' | 'bad_input';
22
+ export type ReattachDecision = {
23
+ readonly action: 'reattach';
24
+ readonly afterMs: number;
25
+ readonly budget: ReattachBudget;
26
+ } | {
27
+ readonly action: 'give_up';
28
+ readonly reason: ReattachGiveUp;
29
+ readonly budget: ReattachBudget;
30
+ };
31
+ export declare function runReattachPolicy(budget: ReattachBudget, event: ReattachEvent): ReattachDecision;
@@ -0,0 +1,46 @@
1
+ import { STREAM_DRAINING_RECONNECT_MAX, drainingRetryDelayMs, isPreStreamDrainingReject } from './wireErrorTriage.js';
2
+ import { drainingLegStep } from './streamDrainingLegs.js';
3
+ export const REATTACH_MAX_TRIES = 5;
4
+ const DRAINING_TOTAL_MAX = REATTACH_MAX_TRIES * STREAM_DRAINING_RECONNECT_MAX;
5
+ export const REATTACH_BUDGET_FRESH = Object.freeze({ tries: 0, drainingStreak: 0, drainingTotal: 0 });
6
+ const isCount = (v) => typeof v === 'number' && Number.isSafeInteger(v) && v >= 0;
7
+ const giveUp = (reason, budget) => Object.freeze({ action: 'give_up', reason, budget });
8
+ const reattach = (afterMs, tries, drainingStreak, drainingTotal) => Object.freeze({ action: 'reattach', afterMs, budget: Object.freeze({ tries, drainingStreak, drainingTotal }) });
9
+ export function runReattachPolicy(budget, event) {
10
+ try {
11
+ if (typeof budget !== 'object' || budget === null || !isCount(budget.tries) || !isCount(budget.drainingStreak) || !isCount(budget.drainingTotal))
12
+ return giveUp('bad_input', REATTACH_BUDGET_FRESH);
13
+ if (typeof event !== 'object' || event === null || typeof event.hasRunId !== 'boolean')
14
+ return giveUp('bad_input', budget);
15
+ if (!event.hasRunId)
16
+ return giveUp('no_run_id', budget);
17
+ const { tries, drainingStreak, drainingTotal } = budget;
18
+ if (event.cause === 'connection_lost') {
19
+ if (tries >= REATTACH_MAX_TRIES)
20
+ return giveUp('budget_exhausted', budget);
21
+ const next = tries + 1;
22
+ const afterMs = isPreStreamDrainingReject(event.error) ? drainingRetryDelayMs(event.error, next - 1) : 1000 * next;
23
+ return reattach(afterMs, next, 0, drainingTotal);
24
+ }
25
+ if (event.cause === 'stream_cap') {
26
+ if (tries >= REATTACH_MAX_TRIES)
27
+ return giveUp('budget_exhausted', budget);
28
+ return reattach(0, tries + 1, 0, drainingTotal);
29
+ }
30
+ if (event.cause === 'stream_draining') {
31
+ const streak = event.madeProgress === true ? 0 : drainingStreak;
32
+ const { decision, streak: nextStreak } = drainingLegStep(streak, event.frame);
33
+ if ('reconnectAfterMs' in decision && drainingTotal < DRAINING_TOTAL_MAX)
34
+ return reattach(decision.reconnectAfterMs, tries, nextStreak, drainingTotal + 1);
35
+ if ('giveUp' in decision && decision.giveUp === 'not_draining_end')
36
+ return giveUp('bad_input', budget);
37
+ if (tries >= REATTACH_MAX_TRIES)
38
+ return giveUp('budget_exhausted', budget);
39
+ return reattach(0, tries + 1, nextStreak, drainingTotal);
40
+ }
41
+ return giveUp('bad_input', budget);
42
+ }
43
+ catch {
44
+ return giveUp('bad_input', REATTACH_BUDGET_FRESH);
45
+ }
46
+ }
@@ -1,4 +1,4 @@
1
- import type { CheckpointGate, TerminalModelOutputInvalidDetail } from '@sema-agent/sdk';
1
+ import type { CheckpointGate, PromptBlockCause, TerminalModelOutputInvalidDetail } from '@sema-agent/sdk';
2
2
  export type RunTerminalPlane = 'cause' | 'flat';
3
3
  export interface RunTerminalPause {
4
4
  gate?: CheckpointGate;
@@ -55,7 +55,7 @@ export type RunTerminalCompletedDetail = {
55
55
  word: string;
56
56
  };
57
57
  export declare const PROMPT_BLOCK_CAUSES: readonly ["block", "crashed", "timeout", "cancelled"];
58
- export type PromptBlockCause = (typeof PROMPT_BLOCK_CAUSES)[number];
58
+ export type { PromptBlockCause };
59
59
  export type RunTerminalBlockedDetail = {
60
60
  kind: 'prompt_blocked_by_hook';
61
61
  cause: PromptBlockCause;
@@ -69,9 +69,7 @@ export type RunTerminalBlockedDetail = {
69
69
  kind: 'unrecognized';
70
70
  word: string;
71
71
  };
72
- export type RunTerminalRead = RunTerminalReadArm & {
73
- readonly replay?: true;
74
- };
72
+ export type RunTerminalRead = RunTerminalReadArm;
75
73
  type RunTerminalReadArm = {
76
74
  kind: 'completed';
77
75
  plane: RunTerminalPlane;
@@ -102,4 +100,3 @@ export declare function runTerminalGateKind(read: RunTerminalRead | null): strin
102
100
  export declare function runTerminalGateToolName(read: RunTerminalRead | null): string | undefined;
103
101
  export declare function runTerminalCode(read: RunTerminalRead | null): string | undefined;
104
102
  export declare function isReviewPark(read: RunTerminalRead | null): boolean;
105
- export {};
@@ -3,6 +3,8 @@ import { isSdkRunParked } from './terminalStatuses.js';
3
3
  import { readOwnDataNonEmptyString, readOwnDataValue } from './ownKey.js';
4
4
  import { doneResultView } from './replayBody.js';
5
5
  export const PROMPT_BLOCK_CAUSES = CORE_PROMPT_BLOCK_CAUSES;
6
+ const _promptBlockTablePin = true;
7
+ void _promptBlockTablePin;
6
8
  const PROMPT_BLOCKED_BY_HOOK_DETAIL_KIND = 'prompt_blocked_by_hook';
7
9
  function str(v) {
8
10
  return typeof v === 'string' && v.length > 0 ? v : undefined;
@@ -267,8 +269,7 @@ export function readRunTerminal(result) {
267
269
  return null;
268
270
  const view = doneResultView(result);
269
271
  if (view.replay) {
270
- const inner = readRunTerminalArm(view.engine) ?? readRunTerminalArm({ status: view.row?.status, errorCode: view.row?.errorCode, errorMessage: view.row?.error });
271
- return inner === null ? null : { ...inner, replay: true };
272
+ return readRunTerminalArm(view.engine) ?? readRunTerminalArm({ status: view.row?.status, errorCode: view.row?.errorCode, errorMessage: view.row?.error });
272
273
  }
273
274
  return readRunTerminalArm(result);
274
275
  }
@@ -278,16 +279,14 @@ function readRunTerminalArm(result) {
278
279
  const r = result;
279
280
  if ('terminal' in r) {
280
281
  const t = r.terminal;
281
- if (typeof t !== 'object' || t === null || Array.isArray(t))
282
- return { kind: 'unknown', plane: 'cause' };
283
- const c = t;
284
- const kind = str(c.kind);
285
- if (kind === undefined)
286
- return { kind: 'unknown', plane: 'cause' };
282
+ const c = typeof t === 'object' && t !== null && !Array.isArray(t) ? t : undefined;
283
+ const kind = c === undefined ? undefined : str(c.kind);
287
284
  const parkWord = str(r.status);
288
285
  if (isSdkRunParked(parkWord)) {
289
- return { kind: 'paused', plane: 'cause', flatStatus: parkWord, ...(kind === 'paused' ? (pauseOf(c) ?? {}) : {}) };
286
+ return { kind: 'paused', plane: 'cause', flatStatus: parkWord, ...(c !== undefined && kind === 'paused' ? (pauseOf(c) ?? {}) : {}) };
290
287
  }
288
+ if (c === undefined || kind === undefined)
289
+ return { kind: 'unknown', plane: 'cause' };
291
290
  switch (kind) {
292
291
  case 'completed': {
293
292
  const detail = completedDetailOf(c);
@@ -23,4 +23,6 @@ export declare const SANDBOX_K8S_ONLY_400_ANCHOR = "only supported on the k8s sa
23
23
  export declare const SANDBOX_NO_IMAGE_INDEX_400_ANCHOR = "requires the image index";
24
24
  export declare const SANDBOX_NO_PUBLISHED_IMAGE_404_ANCHOR = "no published sandbox image for profile";
25
25
  export declare const SANDBOX_CASCADE_CONFLICT_400_ANCHOR = "not supported together with cascade/verify";
26
- export declare function sandboxDegradeHint(err: unknown): string | undefined;
26
+ export type SandboxHintHost = 'terminal' | 'web' | 'desktop';
27
+ export declare const SANDBOX_HINT_HOSTS: readonly SandboxHintHost[];
28
+ export declare function sandboxDegradeHint(err: unknown, host?: SandboxHintHost): string | undefined;
@@ -1,5 +1,6 @@
1
1
  import { lastFlagValue } from './argvFlagValue.js';
2
2
  import { CAPABILITY_IMAGE_INDEX_REQUIRED } from './engineErrorCodes.js';
3
+ import { THROWN_SLOT_UNREADABLE, readThrownSlot } from './wireFailureShape.js';
3
4
  const MAX_PROFILE_LEN = 128;
4
5
  const USAGE_HINT = "sema: --sandbox expects a profile name or 'auto'.\n" +
5
6
  ' --sandbox <profile> run on that sandbox image profile (k8s-lane workers; list: sema cloud images list)\n' +
@@ -46,36 +47,84 @@ export const SANDBOX_K8S_ONLY_400_ANCHOR = 'only supported on the k8s sandbox ba
46
47
  export const SANDBOX_NO_IMAGE_INDEX_400_ANCHOR = 'requires the image index';
47
48
  export const SANDBOX_NO_PUBLISHED_IMAGE_404_ANCHOR = 'no published sandbox image for profile';
48
49
  export const SANDBOX_CASCADE_CONFLICT_400_ANCHOR = 'not supported together with cascade/verify';
49
- const SANDBOX_IMAGE_INDEX_501_HINT = 'Cloud sandbox images are not available on this engine: its storage backend keeps no image index, so profiles cannot be listed or selected here.\n' +
50
- 'Use a worker backed by a SQL store (it has the image index), or re-run without --sandbox.';
51
- function imageIndexRequiredCode(err) {
50
+ export const SANDBOX_HINT_HOSTS = Object.freeze(['terminal', 'web', 'desktop']);
51
+ const SANDBOX_HINT_ARMS = Object.freeze({
52
+ imageIndexRequired501: {
53
+ fact: 'Cloud sandbox images are not available on this engine: its storage backend keeps no image index, so profiles cannot be listed or selected here.',
54
+ sep: '\n',
55
+ outlet: {
56
+ terminal: 'Use a worker backed by a SQL store (it has the image index), or re-run without --sandbox.',
57
+ graphical: 'Use a worker backed by a SQL store (it has the image index), or keep the default environment.',
58
+ },
59
+ },
60
+ k8sLaneOnly400: {
61
+ subject: { terminal: '--sandbox <profile>', graphical: 'The selected sandbox image profile' },
62
+ fact: ' only applies on k8s-lane workers; this engine runs a host/e2b sandbox lane, so the request was honestly rejected.',
63
+ sep: '\n',
64
+ outlet: {
65
+ terminal: 'Re-run without --sandbox (worker default image), or point the shell at a k8s-lane worker (sema cloud engine connect <url>).',
66
+ graphical: 'Keep the default environment, or connect to a k8s-lane worker.',
67
+ },
68
+ },
69
+ noImageIndex400: {
70
+ fact: 'This worker has no sandbox image index configured (the sema-web-admin config center is not attached), so per-task profiles cannot resolve.',
71
+ sep: '\n',
72
+ outlet: {
73
+ terminal: 'Re-run without --sandbox, or use a worker with the image index enabled.',
74
+ graphical: 'Keep the default environment, or use a worker with the image index enabled.',
75
+ },
76
+ },
77
+ noPublishedImage404: {
78
+ fact: 'No published image matches that profile for your principal.',
79
+ sep: ' ',
80
+ outlet: {
81
+ terminal: 'List what you can use: sema cloud images list',
82
+ graphical: 'Choose one of the environments that are offered instead.',
83
+ },
84
+ },
85
+ cascadeConflict400: {
86
+ subject: { terminal: '--sandbox', graphical: 'The sandbox image profile' },
87
+ fact: ' cannot combine with cascade/verify submits in v1 (the per-task image would not bind to the sub-runs).',
88
+ sep: ' ',
89
+ outlet: { terminal: 'Drop one of the two.', graphical: 'Drop one of the two.' },
90
+ },
91
+ });
92
+ function sandboxHintOf(arm, host) {
93
+ const terminal = host === undefined || host === 'terminal';
94
+ const graphical = host === 'web' || host === 'desktop';
95
+ const subject = arm.subject === undefined ? '' : terminal ? arm.subject.terminal : arm.subject.graphical;
96
+ const factSegment = `${subject}${arm.fact}`;
97
+ if (terminal)
98
+ return `${factSegment}${arm.sep}${arm.outlet.terminal}`;
99
+ if (graphical)
100
+ return `${factSegment}${arm.sep}${arm.outlet.graphical}`;
101
+ return factSegment;
102
+ }
103
+ function sandboxSlot(err, key) {
104
+ const v = readThrownSlot(err, key, 'data');
105
+ return v === THROWN_SLOT_UNREADABLE ? undefined : v;
106
+ }
107
+ export function sandboxDegradeHint(err, host) {
108
+ const status = sandboxSlot(err, 'status');
109
+ if (status === 501 && sandboxSlot(err, 'errorCode') === CAPABILITY_IMAGE_INDEX_REQUIRED)
110
+ return sandboxHintOf(SANDBOX_HINT_ARMS.imageIndexRequired501, host);
111
+ if (typeof err !== 'object' || err === null || typeof status !== 'number')
112
+ return undefined;
52
113
  try {
53
- return typeof err === 'object' && err !== null && err.errorCode === CAPABILITY_IMAGE_INDEX_REQUIRED;
114
+ const msg = err.message;
115
+ if (typeof msg !== 'string')
116
+ return undefined;
117
+ if (status === 400 && msg.includes(SANDBOX_K8S_ONLY_400_ANCHOR))
118
+ return sandboxHintOf(SANDBOX_HINT_ARMS.k8sLaneOnly400, host);
119
+ if (status === 400 && msg.includes(SANDBOX_NO_IMAGE_INDEX_400_ANCHOR))
120
+ return sandboxHintOf(SANDBOX_HINT_ARMS.noImageIndex400, host);
121
+ if (status === 404 && msg.includes(SANDBOX_NO_PUBLISHED_IMAGE_404_ANCHOR))
122
+ return sandboxHintOf(SANDBOX_HINT_ARMS.noPublishedImage404, host);
123
+ if (status === 400 && msg.includes(SANDBOX_CASCADE_CONFLICT_400_ANCHOR))
124
+ return sandboxHintOf(SANDBOX_HINT_ARMS.cascadeConflict400, host);
125
+ return undefined;
54
126
  }
55
127
  catch {
56
- return false;
57
- }
58
- }
59
- export function sandboxDegradeHint(err) {
60
- const e = err;
61
- if (e?.status === 501 && imageIndexRequiredCode(err))
62
- return SANDBOX_IMAGE_INDEX_501_HINT;
63
- if (typeof e?.status !== 'number' || typeof e?.message !== 'string')
64
128
  return undefined;
65
- const msg = e.message;
66
- if (e.status === 400 && msg.includes(SANDBOX_K8S_ONLY_400_ANCHOR)) {
67
- return ('--sandbox <profile> only applies on k8s-lane workers; this engine runs a host/e2b sandbox lane, so the request was honestly rejected.\n' +
68
- 'Re-run without --sandbox (worker default image), or point the shell at a k8s-lane worker (sema cloud engine connect <url>).');
69
- }
70
- if (e.status === 400 && msg.includes(SANDBOX_NO_IMAGE_INDEX_400_ANCHOR)) {
71
- return ('This worker has no sandbox image index configured (the sema-web-admin config center is not attached), so per-task profiles cannot resolve.\n' +
72
- 'Re-run without --sandbox, or use a worker with the image index enabled.');
73
- }
74
- if (e.status === 404 && msg.includes(SANDBOX_NO_PUBLISHED_IMAGE_404_ANCHOR)) {
75
- return 'No published image matches that profile for your principal. List what you can use: sema cloud images list';
76
- }
77
- if (e.status === 400 && msg.includes(SANDBOX_CASCADE_CONFLICT_400_ANCHOR)) {
78
- return '--sandbox cannot combine with cascade/verify submits in v1 (the per-task image would not bind to the sub-runs). Drop one of the two.';
79
129
  }
80
- return undefined;
81
130
  }
@@ -0,0 +1,9 @@
1
+ export interface ScenarioRefusalReading {
2
+ readonly errorCode?: string;
3
+ readonly error?: string;
4
+ readonly scenario?: string;
5
+ readonly source?: 'ruling' | 'deployment';
6
+ }
7
+ export declare function scenarioRefusalOf(body: object): ScenarioRefusalReading | undefined | null;
8
+ export declare function scenarioRefusalFromError(err: {} | null | undefined): ScenarioRefusalReading | null;
9
+ export declare function scenarioRefusalContent(reading: ScenarioRefusalReading): string;