@sema-agent/client-core 0.99.0 → 0.101.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 (374) hide show
  1. package/CHANGELOG.md +572 -0
  2. package/README.md +174 -114
  3. package/dist/adapt/arms.js +109 -50
  4. package/dist/adapt/panelTasks.d.ts +2 -1
  5. package/dist/adapt/panelTasks.js +32 -9
  6. package/dist/adapt/textStream.d.ts +1 -1
  7. package/dist/adapt/textStream.js +58 -32
  8. package/dist/adapt/toolCards.js +9 -8
  9. package/dist/adapt.js +7 -1
  10. package/dist/adapter/activeRunSelfHeal.d.ts +31 -2
  11. package/dist/adapter/activeRunSelfHeal.js +162 -13
  12. package/dist/adapter/downstream/eventToSdkMessage.d.ts +25 -6
  13. package/dist/adapter/downstream/eventToSdkMessage.js +157 -20
  14. package/dist/adapter/downstream/terminalToSdkResult.d.ts +60 -1
  15. package/dist/adapter/downstream/terminalToSdkResult.js +219 -39
  16. package/dist/adapter/downstream/wiringManifestView.d.ts +3 -1
  17. package/dist/adapter/downstream/wiringManifestView.js +1 -0
  18. package/dist/adapter/runStream.d.ts +4 -4
  19. package/dist/adapter/runStream.js +184 -42
  20. package/dist/adapter/types.d.ts +2 -0
  21. package/dist/agentsWireCaps.d.ts +9 -7
  22. package/dist/agentsWireCaps.js +101 -17
  23. package/dist/approvalDecidedByCapability.js +2 -2
  24. package/dist/approvalFrameFamilies.d.ts +33 -0
  25. package/dist/approvalFrameFamilies.js +120 -0
  26. package/dist/approvalsStreamLiveCapability.js +2 -2
  27. package/dist/attachmentsWireCaps.js +41 -13
  28. package/dist/callerCwdCapability.js +2 -2
  29. package/dist/centerWiringCapability.js +2 -2
  30. package/dist/clockReading.d.ts +2 -0
  31. package/dist/clockReading.js +4 -0
  32. package/dist/cloudConfigWireCaps.d.ts +28 -5
  33. package/dist/cloudConfigWireCaps.js +334 -103
  34. package/dist/compactionStatus.d.ts +34 -0
  35. package/dist/compactionStatus.js +196 -0
  36. package/dist/coreValuePorts.d.ts +12 -2
  37. package/dist/coreValuePorts.js +9 -0
  38. package/dist/decideFailureNote.js +8 -6
  39. package/dist/decideReceipt.js +2 -2
  40. package/dist/deviceExecutorManagementCapability.js +2 -2
  41. package/dist/deviceFlowPolling.js +1 -1
  42. package/dist/disableSkillsWire.d.ts +1 -1
  43. package/dist/disableSkillsWire.js +4 -3
  44. package/dist/displayUntrusted.d.ts +1 -0
  45. package/dist/displayUntrusted.js +215 -13
  46. package/dist/engineAgentPanelStore.d.ts +7 -4
  47. package/dist/engineCapReader.js +1 -1
  48. package/dist/engineConfigDrift.js +1 -1
  49. package/dist/engineErrorCodes.d.ts +23 -6
  50. package/dist/engineErrorCodes.js +36 -11
  51. package/dist/engineGenerationConvergence.d.ts +39 -0
  52. package/dist/engineGenerationConvergence.js +95 -0
  53. package/dist/engineGenerationPort.d.ts +61 -0
  54. package/dist/engineGenerationPort.js +144 -0
  55. package/dist/engineHealthFacts.d.ts +23 -0
  56. package/dist/engineHealthFacts.js +92 -0
  57. package/dist/engineIdentity.d.ts +4 -0
  58. package/dist/engineIdentity.js +11 -0
  59. package/dist/engineNoticeCodes.d.ts +2 -5
  60. package/dist/engineRowRef.js +4 -0
  61. package/dist/engineSessionMessages.js +2 -2
  62. package/dist/engineToolDirectory.d.ts +3 -0
  63. package/dist/engineToolDirectory.js +6 -4
  64. package/dist/engineWireFor.d.ts +99 -0
  65. package/dist/engineWireFor.js +248 -6
  66. package/dist/engineWireTarget.d.ts +1 -0
  67. package/dist/engineWireTarget.js +8 -0
  68. package/dist/env/uiLanguage.js +1 -1
  69. package/dist/errorSupplementRoles.d.ts +3 -0
  70. package/dist/errorSupplementRoles.js +37 -0
  71. package/dist/eventLeg.d.ts +1 -7
  72. package/dist/eventLeg.js +7 -8
  73. package/dist/executionLaneCapability.js +2 -2
  74. package/dist/fileHistoryCaptureCapability.d.ts +0 -3
  75. package/dist/fileHistoryCaptureCapability.js +3 -7
  76. package/dist/finalVerifyWire.d.ts +6 -3
  77. package/dist/finalVerifyWire.js +6 -23
  78. package/dist/flagInput.d.ts +4 -0
  79. package/dist/flagInput.js +24 -0
  80. package/dist/fleet/fleetLedger.js +5 -2
  81. package/dist/fleet/fleetProjection.d.ts +1 -0
  82. package/dist/fleet/fleetProjection.js +15 -2
  83. package/dist/gateVocabulary.js +3 -0
  84. package/dist/generated/engineFactTables.d.ts +7 -2
  85. package/dist/generated/engineFactTables.js +79 -0
  86. package/dist/generated/engineNoticeTables.js +15 -0
  87. package/dist/generated/settingsSchemaActiveTiers.d.ts +1 -0
  88. package/dist/generated/settingsSchemaActiveTiers.js +14 -0
  89. package/dist/generated/settingsSchemaCallerTextEcho.d.ts +1 -0
  90. package/dist/generated/settingsSchemaCallerTextEcho.js +8 -0
  91. package/dist/generated/settingsSchemaControlAndBidi.d.ts +1 -0
  92. package/dist/generated/settingsSchemaControlAndBidi.js +8 -0
  93. package/dist/generated/settingsSchemaDefaultModel.d.ts +11 -0
  94. package/dist/generated/settingsSchemaDefaultModel.js +25 -0
  95. package/dist/generated/settingsSchemaFns.d.ts +66 -0
  96. package/dist/generated/settingsSchemaFns.js +38 -0
  97. package/dist/generated/settingsSchemaMcpRequestEntry.d.ts +1 -0
  98. package/dist/generated/settingsSchemaMcpRequestEntry.js +156 -0
  99. package/dist/generated/settingsSchemaSafetyMergeSpec.d.ts +1 -0
  100. package/dist/generated/settingsSchemaSafetyMergeSpec.js +95 -0
  101. package/dist/generated/settingsSchemaSettingsSources.d.ts +1 -0
  102. package/dist/generated/settingsSchemaSettingsSources.js +58 -0
  103. package/dist/generated/settingsSchemaTables.d.ts +3 -0
  104. package/dist/generated/settingsSchemaTables.js +18 -0
  105. package/dist/generated/settingsSchemaTypes.d.ts +28 -0
  106. package/dist/generated/settingsSchemaUrlPattern.d.ts +1 -0
  107. package/dist/generated/settingsSchemaUrlPattern.js +183 -0
  108. package/dist/headlessPermissionModeWire.d.ts +18 -2
  109. package/dist/headlessPermissionModeWire.js +30 -19
  110. package/dist/hitl/allowRuleShadow.js +9 -7
  111. package/dist/hitl/approvalCardReading.d.ts +3 -0
  112. package/dist/hitl/approvalCardReading.js +17 -0
  113. package/dist/hitl/approvalCardReasons.js +2 -2
  114. package/dist/hitl/approvalCompleteParked.js +1 -1
  115. package/dist/hitl/approvalDelivery.d.ts +87 -0
  116. package/dist/hitl/approvalDelivery.js +193 -0
  117. package/dist/hitl/approvalHolds.d.ts +14 -0
  118. package/dist/hitl/approvalHolds.js +41 -0
  119. package/dist/hitl/approvalResolution.d.ts +11 -0
  120. package/dist/hitl/approvalResolution.js +50 -11
  121. package/dist/hitl/askClassPair.d.ts +8 -2
  122. package/dist/hitl/askClassPair.js +31 -4
  123. package/dist/hitl/askParkAutoReopenBlock.d.ts +30 -0
  124. package/dist/hitl/askParkAutoReopenBlock.js +117 -0
  125. package/dist/hitl/askParkRowRouting.js +4 -1
  126. package/dist/hitl/attributionLadder.d.ts +62 -0
  127. package/dist/hitl/attributionLadder.js +138 -0
  128. package/dist/hitl/automaticAnswerVerdict.d.ts +6 -1
  129. package/dist/hitl/automaticAnswerVerdict.js +46 -11
  130. package/dist/hitl/crashConverged.js +2 -2
  131. package/dist/hitl/decisionConflict.d.ts +6 -2
  132. package/dist/hitl/decisionConflict.js +24 -9
  133. package/dist/hitl/decisionLedger.d.ts +55 -0
  134. package/dist/hitl/decisionLedger.js +156 -0
  135. package/dist/hitl/decisionRefusal.d.ts +21 -10
  136. package/dist/hitl/decisionRefusal.js +100 -55
  137. package/dist/hitl/decisionSend.d.ts +116 -0
  138. package/dist/hitl/decisionSend.js +563 -0
  139. package/dist/hitl/frameRouter.d.ts +1 -0
  140. package/dist/hitl/frameRouter.js +9 -2
  141. package/dist/hitl/hitlBridge.d.ts +18 -6
  142. package/dist/hitl/hitlBridge.js +59 -43
  143. package/dist/hitl/livePendingAsk.js +4 -3
  144. package/dist/hitl/noAllowCause.js +1 -1
  145. package/dist/hitl/parkResolver.js +3 -2
  146. package/dist/hitl/persistedRulesWire.js +1 -0
  147. package/dist/hitl/planReviewWire.d.ts +4 -0
  148. package/dist/hitl/planReviewWire.js +104 -106
  149. package/dist/hitl/resumeRunningCard.d.ts +3 -2
  150. package/dist/hitl/resumeRunningCard.js +17 -11
  151. package/dist/hitl/sessionPolicyDeliverable.d.ts +5 -2
  152. package/dist/hitl/sessionPolicyDeliverable.js +65 -35
  153. package/dist/hitl/sessionPolicyWire.d.ts +13 -3
  154. package/dist/hitl/sessionPolicyWire.js +81 -16
  155. package/dist/hitl/standingRows.js +1 -1
  156. package/dist/hitl/toolApprovalWire.d.ts +9 -10
  157. package/dist/hitl/toolApprovalWire.js +103 -151
  158. package/dist/hookMatcherVerdict.d.ts +2 -0
  159. package/dist/hookMatcherVerdict.js +12 -0
  160. package/dist/hooksCompactTransition.d.ts +19 -0
  161. package/dist/hooksCompactTransition.js +41 -0
  162. package/dist/hooksWireCaps.d.ts +1 -1
  163. package/dist/hooksWireCaps.js +202 -203
  164. package/dist/host.d.ts +1 -14
  165. package/dist/host.js +0 -8
  166. package/dist/hostCallbackGuard.d.ts +1 -0
  167. package/dist/hostCallbackGuard.js +1 -1
  168. package/dist/hostSettingsSource.d.ts +172 -0
  169. package/dist/hostSettingsSource.js +675 -0
  170. package/dist/hostTurnSettings.d.ts +114 -19
  171. package/dist/hostTurnSettings.js +966 -68
  172. package/dist/httpHookPolicy.d.ts +37 -0
  173. package/dist/httpHookPolicy.js +176 -0
  174. package/dist/humanTurn.d.ts +4 -2
  175. package/dist/humanTurn.js +40 -10
  176. package/dist/humanTurnRead.js +4 -3
  177. package/dist/humanTurnSentences.d.ts +10 -0
  178. package/dist/humanTurnSentences.js +74 -0
  179. package/dist/i18n/messages.en.d.ts +313 -0
  180. package/dist/i18n/messages.en.js +326 -13
  181. package/dist/i18n/messages.zh.js +341 -13
  182. package/dist/i18n/translate.js +3 -3
  183. package/dist/index.d.ts +85 -15
  184. package/dist/index.js +53 -12
  185. package/dist/inheritEnvCapability.d.ts +4 -1
  186. package/dist/inheritEnvCapability.js +38 -17
  187. package/dist/inheritEnvWire.d.ts +2 -1
  188. package/dist/inheritEnvWire.js +11 -5
  189. package/dist/injectionLaneNotice.d.ts +5 -0
  190. package/dist/injectionLaneNotice.js +46 -0
  191. package/dist/interactiveToolsWire.d.ts +4 -2
  192. package/dist/interactiveToolsWire.js +5 -5
  193. package/dist/jsonFaithful.d.ts +20 -0
  194. package/dist/jsonFaithful.js +152 -0
  195. package/dist/limitsWire.d.ts +7 -2
  196. package/dist/limitsWire.js +19 -13
  197. package/dist/liveInitToolFace.d.ts +6 -1
  198. package/dist/liveInitToolFace.js +5 -3
  199. package/dist/liveModelCatalog.d.ts +22 -0
  200. package/dist/liveModelCatalog.js +132 -18
  201. package/dist/mcpPanel.js +3 -1
  202. package/dist/mcpProbeCapability.js +2 -2
  203. package/dist/mcpReconnect.js +2 -2
  204. package/dist/mcpStatusSupersetKeys.d.ts +24 -0
  205. package/dist/mcpStatusSupersetKeys.js +45 -0
  206. package/dist/mcpToolToggles.d.ts +6 -0
  207. package/dist/mcpToolToggles.js +47 -0
  208. package/dist/mcpWireCaps.d.ts +48 -4
  209. package/dist/mcpWireCaps.js +338 -99
  210. package/dist/mcpWireTransport.d.ts +4 -0
  211. package/dist/mcpWireTransport.js +18 -0
  212. package/dist/memoryComplianceCapability.js +2 -2
  213. package/dist/memoryOriginCapability.js +2 -2
  214. package/dist/model/catalogDefault.d.ts +24 -0
  215. package/dist/model/catalogDefault.js +4 -0
  216. package/dist/model/liveCatalogShape.js +5 -4
  217. package/dist/model/modelsPolicy.js +4 -3
  218. package/dist/model/onboardJudgement.d.ts +1 -0
  219. package/dist/model/onboardJudgement.js +1 -1
  220. package/dist/model/subagentModelWord.js +2 -2
  221. package/dist/modelCapabilityProbe.d.ts +2 -1
  222. package/dist/modelCapabilityProbe.js +16 -15
  223. package/dist/modelIdentityResolvability.d.ts +12 -1
  224. package/dist/modelIdentityResolvability.js +69 -28
  225. package/dist/modsKernelIdentity.d.ts +10 -0
  226. package/dist/modsKernelIdentity.js +103 -0
  227. package/dist/modsKernelTransit.d.ts +8 -0
  228. package/dist/modsKernelTransit.js +6 -0
  229. package/dist/notifications.d.ts +30 -12
  230. package/dist/notifications.js +241 -53
  231. package/dist/outputStyleSeatCapability.js +2 -2
  232. package/dist/ownKey.d.ts +37 -0
  233. package/dist/ownKey.js +238 -2
  234. package/dist/panelReduce.d.ts +5 -0
  235. package/dist/panelReduce.js +45 -13
  236. package/dist/panelStateHolder.d.ts +1 -0
  237. package/dist/panelStateHolder.js +10 -1
  238. package/dist/peerFrames.d.ts +1 -1
  239. package/dist/peerFrames.js +6 -2
  240. package/dist/peerLaneCapability.js +2 -2
  241. package/dist/permissionModesCapability.js +4 -4
  242. package/dist/permissionRuleIssue.d.ts +2 -1
  243. package/dist/permissionRuleIssue.js +24 -21
  244. package/dist/permissionRulesWriteCapability.js +2 -2
  245. package/dist/permissionsAllowGrantCapability.js +2 -2
  246. package/dist/permissionsDeclaration.d.ts +43 -4
  247. package/dist/permissionsDeclaration.js +102 -35
  248. package/dist/pluginHooksWire.d.ts +20 -4
  249. package/dist/pluginHooksWire.js +101 -60
  250. package/dist/prepareRefusal.d.ts +9 -0
  251. package/dist/prepareRefusal.js +90 -0
  252. package/dist/printInitToolFace.js +2 -2
  253. package/dist/printModelStatus.js +1 -1
  254. package/dist/projectMemory.d.ts +32 -0
  255. package/dist/projectMemory.js +70 -0
  256. package/dist/promptBlockedCopy.d.ts +2 -1
  257. package/dist/promptBlockedCopy.js +2 -1
  258. package/dist/promptDelivery.d.ts +23 -3
  259. package/dist/promptDelivery.js +169 -30
  260. package/dist/providerRejection.d.ts +19 -1
  261. package/dist/providerRejection.js +75 -4
  262. package/dist/queuedDelivery.d.ts +48 -0
  263. package/dist/queuedDelivery.js +233 -0
  264. package/dist/reattachWindow.d.ts +94 -0
  265. package/dist/reattachWindow.js +127 -0
  266. package/dist/request/printNotification.d.ts +1 -1
  267. package/dist/request/printNotification.js +5 -1
  268. package/dist/request/submissionIdentity.d.ts +37 -0
  269. package/dist/request/submissionIdentity.js +65 -0
  270. package/dist/request/taskRequest.d.ts +22 -14
  271. package/dist/request/taskRequest.js +312 -202
  272. package/dist/resultFrameKeys.d.ts +1 -0
  273. package/dist/resultFrameKeys.js +4 -1
  274. package/dist/resumeRefusalCopy.d.ts +3 -1
  275. package/dist/resumeRefusalCopy.js +22 -4
  276. package/dist/retryStatus.d.ts +26 -0
  277. package/dist/retryStatus.js +133 -28
  278. package/dist/rewindArchiveCapability.js +2 -2
  279. package/dist/rewindEngineAction.d.ts +2 -0
  280. package/dist/rewindEngineAction.js +23 -1
  281. package/dist/rowKind.d.ts +36 -0
  282. package/dist/rowKind.js +97 -0
  283. package/dist/ruleCompileVerdict.d.ts +18 -0
  284. package/dist/ruleCompileVerdict.js +67 -2
  285. package/dist/ruleReadings.d.ts +58 -0
  286. package/dist/ruleReadings.js +132 -0
  287. package/dist/ruleRefusalSentence.d.ts +8 -0
  288. package/dist/ruleRefusalSentence.js +64 -0
  289. package/dist/runCancelContext.d.ts +0 -1
  290. package/dist/runCancelContext.js +1 -2
  291. package/dist/runTerminal.d.ts +5 -0
  292. package/dist/runTerminal.js +52 -17
  293. package/dist/sandboxWire.d.ts +3 -2
  294. package/dist/sandboxWire.js +59 -27
  295. package/dist/scenarioRefusal.d.ts +2 -1
  296. package/dist/scenarioRefusal.js +6 -6
  297. package/dist/scenarioSkills.d.ts +20 -0
  298. package/dist/scenarioSkills.js +72 -0
  299. package/dist/scenarioWire.d.ts +5 -2
  300. package/dist/scenarioWire.js +9 -9
  301. package/dist/sealedKeyCapability.js +2 -2
  302. package/dist/seam.d.ts +26 -9
  303. package/dist/seam.js +44 -4
  304. package/dist/seatContract.d.ts +62 -9
  305. package/dist/seatContract.js +70 -25
  306. package/dist/selfOrchestrationDenial.js +1 -1
  307. package/dist/sessionPolicyCapability.js +2 -2
  308. package/dist/sessionRulesChildrenReadLive.d.ts +6 -0
  309. package/dist/sessionRulesChildrenReadLive.js +5 -0
  310. package/dist/sessionRulesNamespaceFormsCapability.d.ts +12 -0
  311. package/dist/sessionRulesNamespaceFormsCapability.js +29 -0
  312. package/dist/sessionSyncFileHistoryCapability.js +2 -2
  313. package/dist/settingsCredentialKeyPaths.d.ts +8 -0
  314. package/dist/settingsCredentialKeyPaths.js +274 -0
  315. package/dist/settingsHooksSalvage.d.ts +1 -0
  316. package/dist/settingsHooksSalvage.js +7 -1
  317. package/dist/settingsLayerAdmission.d.ts +4 -0
  318. package/dist/settingsLayerAdmission.js +16 -0
  319. package/dist/skillToolListsCapability.js +6 -5
  320. package/dist/skillsWireCaps.d.ts +14 -3
  321. package/dist/skillsWireCaps.js +48 -18
  322. package/dist/slashCommandGate.d.ts +24 -0
  323. package/dist/slashCommandGate.js +74 -0
  324. package/dist/slashCommandTable.d.ts +14 -0
  325. package/dist/slashCommandTable.js +99 -0
  326. package/dist/sqlEngineCapability.js +2 -2
  327. package/dist/steerPriorityCapability.js +2 -2
  328. package/dist/storePostureCapability.js +2 -2
  329. package/dist/subagent/agentStateDetail.js +1 -1
  330. package/dist/subagent/engineDelegatedPrompt.d.ts +9 -0
  331. package/dist/subagent/engineDelegatedPrompt.js +38 -7
  332. package/dist/subagent/engineRowStopGate.js +2 -2
  333. package/dist/subagent/engineSubagentResume.js +3 -3
  334. package/dist/subagent/engineTaskHandleWire.d.ts +1 -0
  335. package/dist/subagent/engineTaskHandleWire.js +10 -0
  336. package/dist/subagentContentStore.d.ts +1 -0
  337. package/dist/subagentContentStore.js +135 -27
  338. package/dist/submitFailure.d.ts +8 -0
  339. package/dist/submitFailure.js +17 -0
  340. package/dist/supportFloor.d.ts +1 -0
  341. package/dist/supportFloor.js +7 -0
  342. package/dist/terminationIntent.d.ts +55 -0
  343. package/dist/terminationIntent.js +352 -0
  344. package/dist/toolHistoryMismatch.d.ts +8 -0
  345. package/dist/toolHistoryMismatch.js +37 -6
  346. package/dist/toolResult.d.ts +13 -3
  347. package/dist/toolResult.js +158 -9
  348. package/dist/toolResultContent.d.ts +13 -0
  349. package/dist/toolResultContent.js +82 -7
  350. package/dist/toolRoster.d.ts +18 -0
  351. package/dist/toolRoster.js +64 -0
  352. package/dist/toolsFlagNames.d.ts +8 -0
  353. package/dist/toolsFlagNames.js +110 -0
  354. package/dist/turnFailurePresentation.js +41 -96
  355. package/dist/usageLimitAutoResume.d.ts +74 -0
  356. package/dist/usageLimitAutoResume.js +227 -0
  357. package/dist/userAttachmentEnvelope.js +1 -1
  358. package/dist/userAttachmentSeat.js +5 -5
  359. package/dist/userInvokedSkillsCapability.js +2 -2
  360. package/dist/webSearchBackendCapability.js +2 -2
  361. package/dist/wireErrorTriage.js +99 -50
  362. package/dist/wireFailureShape.d.ts +25 -1
  363. package/dist/wireFailureShape.js +92 -5
  364. package/dist/wireRefusalCopy.d.ts +75 -18
  365. package/dist/wireRefusalCopy.js +532 -148
  366. package/dist/wiringFleetDoctor.d.ts +3 -0
  367. package/dist/wiringFleetDoctor.js +21 -0
  368. package/dist/workflow.d.ts +2 -1
  369. package/dist/workflow.js +38 -1
  370. package/dist/workflowClient.d.ts +2 -7
  371. package/dist/workflowsJournalCapability.js +2 -2
  372. package/dist/writeProtectionCapability.js +2 -2
  373. package/docs/INTEGRATION-CLIENTS.md +1013 -190
  374. package/package.json +15 -4
@@ -7,10 +7,12 @@ import { enqueuePlanReviewOutcome } from '../notifications.js';
7
7
  import { corruptStoredRowContent, corruptStoredRowWhere } from '../wireErrorTriage.js';
8
8
  import { decideFailureNote } from '../decideFailureNote.js';
9
9
  import { wireFailureTextsOf } from '../wireFailureShape.js';
10
- import { readOwnDataNonEmptyString, readOwnDataValue } from '../ownKey.js';
10
+ import { appendOwnElement, readOwnDataNonEmptyString, readOwnDataValue } from '../ownKey.js';
11
11
  import { checkpointUnsupportedVersionContent, checkpointUnsupportedVersionFromError, resumeContextUnavailableContent, resumeContextUnavailableFromError } from '../resumeRefusalCopy.js';
12
12
  import { REQUEST_FIELD_CONFLICT } from '../engineErrorCodes.js';
13
13
  import { refusalDeliveryOf } from './decisionRefusal.js';
14
+ import { directFailureVerdictOf, directSafetyStopOf } from './approvalResolution.js';
15
+ import { __resetDecisionLedgerForTests, decisionInFlightOf, decisionKeyInFlight, decisionLedgerKeysOf, decisionOpsWithKey, decisionReadMark, dropDecisionOp, latestDecisionHandedMark, markLatestDecisionNotApplied, openDecisionOp, planDecisionKey, readMarkOf, settleDecisionOp, settleDecisionOpsOnGateLeft, } from './decisionLedger.js';
14
16
  import { denyReasonForWire, isPlanReviewModeAfter } from './hitlBridge.js';
15
17
  import { planReviewQuestionId, REOPEN_ID_TAIL, taskIdFromPlanReviewQuestionId } from './gateIdentity.js';
16
18
  import { notePlanReviewAnswered, notePlanReviewAnsweredFor, planReviewArmedKeyFor, waitForGateArmedFor, wasGateArmedFor, } from './armedGateRegistry.js';
@@ -25,12 +27,8 @@ export const PLAN_REVIEW_APPROVE_MANUAL_LABEL = 'Yes, and manually approve edits
25
27
  const APPROVE_LABEL = PLAN_REVIEW_APPROVE_LABEL;
26
28
  const REJECT_LABEL = PLAN_REVIEW_REJECT_LABEL;
27
29
  const LEGACY_TWO_CHOICE_LABELS = Object.freeze([PLAN_REVIEW_APPROVE_LABEL, PLAN_REVIEW_REJECT_LABEL]);
28
- const ALL_KNOWN_LABELS = Object.freeze([
29
- PLAN_REVIEW_APPROVE_AUTO_LABEL,
30
- PLAN_REVIEW_APPROVE_MANUAL_LABEL,
31
- PLAN_REVIEW_APPROVE_LABEL,
32
- PLAN_REVIEW_REJECT_LABEL,
33
- ]);
30
+ const THREE_CHOICE_LABELS = Object.freeze([PLAN_REVIEW_APPROVE_AUTO_LABEL, PLAN_REVIEW_APPROVE_MANUAL_LABEL, PLAN_REVIEW_REJECT_LABEL]);
31
+ const ANY_CARD_SHAPE_LABELS = Object.freeze([PLAN_REVIEW_APPROVE_AUTO_LABEL, PLAN_REVIEW_APPROVE_MANUAL_LABEL, PLAN_REVIEW_APPROVE_LABEL, PLAN_REVIEW_REJECT_LABEL]);
34
32
  export function planReviewDecisionFromAnswer(answer, shownLabels = LEGACY_TWO_CHOICE_LABELS) {
35
33
  const { choice } = readPlanReviewAnswer(answer, shownLabels);
36
34
  if (choice === 'dismissed')
@@ -100,7 +98,7 @@ export function notePlanReviewAnsweredIfDecisive(questionId, answer) {
100
98
  notePlanReviewAnsweredIfDecisiveFor(DEFAULT_SESSION_KEY, questionId, answer);
101
99
  }
102
100
  function notePlanReviewAnsweredIfDecisiveFor(sessionKey, questionId, answer) {
103
- if (planReviewDecisionFromAnswer(answer ?? { answers: [] }, ALL_KNOWN_LABELS) === 'dismissed')
101
+ if (planReviewDecisionFromAnswer(answer ?? { answers: [] }, planReviewShownLabelsOf(questionId) ?? ANY_CARD_SHAPE_LABELS) === 'dismissed')
104
102
  return;
105
103
  notePlanReviewAnsweredFor(sessionKey, questionId);
106
104
  const taskId = typeof questionId === 'string' ? taskIdFromPlanReviewQuestionId(questionId) : undefined;
@@ -275,7 +273,7 @@ function ownElementsOf(v, max) {
275
273
  const n = Math.min(v.length, max);
276
274
  const out = [];
277
275
  for (let i = 0; i < n; i++)
278
- out.push(readOwnDataValue(v, String(i)));
276
+ appendOwnElement(out, readOwnDataValue(v, String(i)));
279
277
  return out;
280
278
  }
281
279
  function offeredModeFromLabels(card) {
@@ -332,6 +330,33 @@ export function planReviewOfferedModeOf(card) {
332
330
  return 'unknown';
333
331
  }
334
332
  }
333
+ export function planReviewShownLabelsOf(questionId) {
334
+ try {
335
+ if (typeof questionId !== 'string')
336
+ return undefined;
337
+ const recorded = offeredModeByQuestionId.get(questionId);
338
+ if (recorded !== undefined)
339
+ return recorded ? THREE_CHOICE_LABELS : LEGACY_TWO_CHOICE_LABELS;
340
+ for (const t of armedPlanReviewTaskIds) {
341
+ if (planReviewQuestionId(t) === questionId)
342
+ return offerModeAfterByTask.get(t) === true ? THREE_CHOICE_LABELS : LEGACY_TWO_CHOICE_LABELS;
343
+ }
344
+ if (taskIdFromPlanReviewQuestionId(questionId) === undefined)
345
+ return undefined;
346
+ return questionId.includes(REOPEN_ID_TAIL) ? LEGACY_TWO_CHOICE_LABELS : undefined;
347
+ }
348
+ catch {
349
+ return undefined;
350
+ }
351
+ }
352
+ export function planReviewAnswerChoiceOf(questionId, answer) {
353
+ const shown = planReviewShownLabelsOf(questionId);
354
+ return shown === undefined ? 'dismissed' : planReviewChoiceFromAnswer(answer, shown);
355
+ }
356
+ export function planReviewAnswerDecisionOf(questionId, answer) {
357
+ const shown = planReviewShownLabelsOf(questionId);
358
+ return shown === undefined ? 'dismissed' : planReviewDecisionFromAnswer(answer, shown);
359
+ }
335
360
  export function armPlanReviewApproval(result, sessionKey, opts) {
336
361
  let armedTaskId;
337
362
  try {
@@ -377,10 +402,9 @@ export function armPlanReviewApproval(result, sessionKey, opts) {
377
402
  offerModeAfterByTask.delete(taskId);
378
403
  const questionId = planReviewQuestionId(taskId);
379
404
  const unregister = registerLocalQuestionResponder(questionId, async (_id, answer) => {
405
+ const choice = planReviewAnswerChoiceOf(questionId, answer);
380
406
  unregister();
381
407
  armedPlanReviewTaskIds.delete(taskId);
382
- const shown = planReviewCardOptions(offerModeAfterByTask.get(taskId) === true).map(o => o.label);
383
- const choice = planReviewChoiceFromAnswer(answer, shown);
384
408
  if (choice === 'dismissed') {
385
409
  notePlanReviewUserDismissalFor(DEFAULT_SESSION_KEY, taskId, opts?.readGateInstanceKeys, questionId);
386
410
  return { ok: true };
@@ -457,42 +481,21 @@ function usablePlanReviewWireClient(client) {
457
481
  return clientHasVerbs(client, [['assistant', 'planReview'], ['runs', 'get']]);
458
482
  }
459
483
  const PLAN_REVIEW_INJECTED_REPULL_TIMEOUT_MS = 15_000;
460
- const planReviewDecisionOps = [];
461
- const MAX_PLAN_REVIEW_DECISION_OPS = 32;
462
- let planReviewLedgerClock = 0;
463
- let decideDispatchSeq = 0;
464
- function planReviewOpsOf(taskId) {
465
- return planReviewDecisionOps.filter((op) => op.taskId === taskId);
466
- }
467
- function settlePlanReviewDecisionOp(op, by) {
468
- if (op.settledAt !== null)
469
- return;
470
- op.settledAt = ++planReviewLedgerClock;
471
- op.settler = by;
472
- }
473
- function pushPlanReviewDecisionOp(op) {
474
- planReviewDecisionOps.push(op);
475
- while (planReviewDecisionOps.length > MAX_PLAN_REVIEW_DECISION_OPS) {
476
- let victim = planReviewDecisionOps.findIndex((o) => o.settledAt !== null && !o.ownCallOpen);
477
- if (victim < 0)
478
- victim = planReviewDecisionOps.findIndex((o) => o !== op && o.phase === 'handed');
479
- if (victim < 0)
480
- break;
481
- planReviewDecisionOps.splice(victim, 1);
482
- }
484
+ function planReviewLedgerKeys(taskId) {
485
+ return taskId === '' ? [planDecisionKey('')] : decisionLedgerKeysOf({ taskId, planTaskId: taskId });
483
486
  }
484
- function dropPlanReviewDecisionOp(op) {
485
- const i = planReviewDecisionOps.indexOf(op);
486
- if (i >= 0)
487
- planReviewDecisionOps.splice(i, 1);
487
+ function planReviewOpsOf(taskId) {
488
+ return decisionOpsWithKey('plan_review', planDecisionKey(taskId));
488
489
  }
490
+ let decideDispatchSeq = 0;
489
491
  function claimablePlanReviewDecisionOp(taskId) {
490
- const open = planReviewDecisionOps.find((o) => o.taskId === taskId && o.phase === 'handed' && o.settledAt === null);
492
+ const ops = planReviewOpsOf(taskId);
493
+ const open = ops.find((o) => o.phase === 'handed' && o.settledAt === null);
491
494
  if (open !== undefined)
492
495
  return open;
493
496
  let leftBehind;
494
- for (const o of planReviewDecisionOps) {
495
- if (o.taskId !== taskId || o.phase !== 'handed' || o.settler !== 'gate_left')
497
+ for (const o of ops) {
498
+ if (o.phase !== 'handed' || o.settler !== 'gate_left')
496
499
  continue;
497
500
  if (leftBehind === undefined || o.handedAt > leftBehind.handedAt)
498
501
  leftBehind = o;
@@ -502,62 +505,47 @@ function claimablePlanReviewDecisionOp(taskId) {
502
505
  export function notePlanReviewDecisionHandedOver(taskId) {
503
506
  if (typeof taskId !== 'string' || taskId === '')
504
507
  return null;
505
- if (planReviewDecisionOps.some((op) => op.taskId === taskId && op.settledAt === null))
508
+ if (planReviewOpsOf(taskId).some((op) => op.settledAt === null))
506
509
  return null;
507
- const op = { taskId, handedAt: ++planReviewLedgerClock, settledAt: null, settler: null, phase: 'handed', notApplied: false, ownCallOpen: false };
508
- pushPlanReviewDecisionOp(op);
510
+ const op = openDecisionOp('plan_review', planReviewLedgerKeys(taskId), 'handed', false);
509
511
  return {
510
512
  settle: () => {
511
513
  if (op.phase !== 'handed')
512
514
  return;
513
- settlePlanReviewDecisionOp(op, 'host');
515
+ settleDecisionOp(op, 'host');
514
516
  },
515
517
  revoke: () => {
516
518
  if (op.phase !== 'handed' || op.settledAt !== null)
517
519
  return;
518
- dropPlanReviewDecisionOp(op);
520
+ dropDecisionOp(op);
519
521
  },
520
522
  };
521
523
  }
522
524
  export function planReviewPendingReadMark() {
523
- return ++planReviewLedgerClock;
525
+ return decisionReadMark();
524
526
  }
525
527
  export function planReviewDecisionInFlight(taskId, pendingReadStartedAt) {
526
528
  if (typeof taskId !== 'string' || taskId === '')
527
529
  return false;
528
- const mark = typeof pendingReadStartedAt === 'number' && Number.isFinite(pendingReadStartedAt) ? pendingReadStartedAt : undefined;
529
- return planReviewDecisionOps.some((op) => op.taskId === taskId && (op.settledAt === null || (mark !== undefined && op.settledAt > mark && !op.notApplied)));
530
+ return decisionKeyInFlight(planDecisionKey(taskId), readMarkOf(pendingReadStartedAt));
530
531
  }
531
532
  export function notePlanReviewDecisionNotApplied(taskId) {
532
533
  if (typeof taskId !== 'string' || taskId === '')
533
534
  return;
534
- const ops = planReviewOpsOf(taskId);
535
- if (ops.some((op) => op.settledAt === null))
536
- return;
537
- let latest;
538
- for (const op of ops)
539
- if (latest === undefined || op.handedAt > latest.handedAt)
540
- latest = op;
541
- if (latest !== undefined)
542
- latest.notApplied = true;
535
+ markLatestDecisionNotApplied('plan_review', planDecisionKey(taskId));
543
536
  }
544
537
  export function notePlanReviewGateLeft(taskId) {
545
538
  if (typeof taskId !== 'string' || taskId === '')
546
539
  return;
547
- for (const op of planReviewOpsOf(taskId))
548
- settlePlanReviewDecisionOp(op, 'gate_left');
540
+ settleDecisionOpsOnGateLeft('plan_review', planDecisionKey(taskId));
549
541
  }
550
542
  export function latestPlanReviewDecisionMark(taskId) {
551
543
  if (typeof taskId !== 'string' || taskId === '')
552
544
  return null;
553
- let mark = null;
554
- for (const op of planReviewOpsOf(taskId))
555
- if (mark === null || op.handedAt > mark)
556
- mark = op.handedAt;
557
- return mark;
545
+ return latestDecisionHandedMark('plan_review', planDecisionKey(taskId));
558
546
  }
559
547
  export function __resetPlanReviewDecisionLatchForTests() {
560
- planReviewDecisionOps.length = 0;
548
+ __resetDecisionLedgerForTests('plan_review');
561
549
  }
562
550
  export async function decidePlanReview(taskId, decision, permissionModeAfter, opts) {
563
551
  return decidePlanReviewFor(taskId, decision, permissionModeAfter, opts, parkedGateIdentityOf(opts));
@@ -574,22 +562,22 @@ function planReviewSettledVerdict(r) {
574
562
  const status = r.postStatus ?? r.bodyStatus;
575
563
  const gateMoved = r.gateBefore !== undefined && r.gateAfter !== undefined && r.gateAfter !== r.gateBefore;
576
564
  if (r.reparked)
577
- return status !== 'completed' && !gateMoved ? { effect: 'still_parked', proven: true } : { effect: 'unconfirmed', proven: false };
565
+ return status !== 'completed' && !gateMoved ? 'still_parked' : 'unconfirmed';
578
566
  if (status === 'completed')
579
- return { effect: 'took_effect', proven: false };
567
+ return 'took_effect';
580
568
  const newGateHasCard = () => {
581
569
  const leg = durableDecideLegOf({ gateKind: r.gateKindAfter ?? null });
582
570
  return leg === 'approval' || leg === 'plan_review';
583
571
  };
584
572
  if (status === 'suspended' && r.postStatus === 'suspended' && newGateHasCard())
585
- return { effect: 'advanced', proven: false };
573
+ return 'advanced';
586
574
  if (status === 'needs_review' && r.postStatus === 'needs_review' && r.gateBefore !== undefined && r.gateAfter !== undefined) {
587
575
  if (r.gateAfter === r.gateBefore)
588
- return { effect: 'still_parked', proven: true };
576
+ return 'still_parked';
589
577
  if (newGateHasCard())
590
- return { effect: 'advanced', proven: false };
578
+ return 'advanced';
591
579
  }
592
- return { effect: 'unconfirmed', proven: false };
580
+ return 'unconfirmed';
593
581
  }
594
582
  function bodyWordOf(body, key) {
595
583
  try {
@@ -609,14 +597,13 @@ function bodySaysReparked(body) {
609
597
  }
610
598
  }
611
599
  async function decidePlanReviewFor(taskId, decision, permissionModeAfter, opts, gateBefore) {
612
- if (typeof taskId === 'string' && planReviewDecisionOps.some((op) => op.taskId === taskId && op.phase === 'posting')) {
600
+ if (typeof taskId === 'string' && planReviewOpsOf(taskId).some((op) => op.phase === 'posting')) {
613
601
  hostLog('error', `planReviewWire: decidePlanReview(${decision}) for task ${taskId} REFUSED — a decision for this task is already in flight (duplicate delivery latched)`);
614
602
  return;
615
603
  }
616
- let op = claimablePlanReviewDecisionOp(taskId);
604
+ let op = typeof taskId === 'string' ? claimablePlanReviewDecisionOp(taskId) : undefined;
617
605
  if (op === undefined) {
618
- op = { taskId: typeof taskId === 'string' ? taskId : String(taskId), handedAt: ++planReviewLedgerClock, settledAt: null, settler: null, phase: 'posting', notApplied: false, ownCallOpen: true };
619
- pushPlanReviewDecisionOp(op);
606
+ op = openDecisionOp('plan_review', planReviewLedgerKeys(typeof taskId === 'string' ? taskId : String(taskId)), 'posting', true);
620
607
  }
621
608
  else {
622
609
  if (op.settler === 'gate_left') {
@@ -635,7 +622,7 @@ async function decidePlanReviewFor(taskId, decision, permissionModeAfter, opts,
635
622
  const settle = (notApplied) => {
636
623
  if (notApplied)
637
624
  mine.notApplied = true;
638
- settlePlanReviewDecisionOp(mine, 'package');
625
+ settleDecisionOp(mine, 'package');
639
626
  };
640
627
  const dispatchNo = ++decideDispatchSeq;
641
628
  hostLog('debug', `planReviewWire: decidePlanReview dispatch #${dispatchNo} task=${taskId} decision=${decision} mode=${permissionModeAfter ?? '-'}`);
@@ -644,7 +631,7 @@ async function decidePlanReviewFor(taskId, decision, permissionModeAfter, opts,
644
631
  }
645
632
  finally {
646
633
  releaseLatch();
647
- settlePlanReviewDecisionOp(mine, 'package');
634
+ settleDecisionOp(mine, 'package');
648
635
  mine.ownCallOpen = false;
649
636
  }
650
637
  }
@@ -665,7 +652,6 @@ async function decidePlanReviewInner(taskId, decision, permissionModeAfter, disp
665
652
  let outcome;
666
653
  let effect = 'unconfirmed';
667
654
  let stillParkedCause;
668
- let stillParkedProven = false;
669
655
  let statusSeen;
670
656
  const wire = opts?.wire;
671
657
  const resolved = engineWireFor(clientOnlyView(wire), DEFAULT_SESSION_KEY, usablePlanReviewWireClient);
@@ -708,7 +694,8 @@ async function decidePlanReviewInner(taskId, decision, permissionModeAfter, disp
708
694
  }
709
695
  catch (e1) {
710
696
  const conflict = e1;
711
- if (mode === 'default' && conflict?.status === 400 && conflict?.errorCode === REQUEST_FIELD_CONFLICT) {
697
+ const defaultConflict = mode === 'default' && conflict?.status === 400 && conflict?.errorCode === REQUEST_FIELD_CONFLICT;
698
+ if (defaultConflict && !directFailureVerdictOf(e1, directSafetyStopOf(e1)).yields) {
712
699
  hostLog('debug', 'planReviewWire: permissionModeAfter "default" refused as not applicable — re-sending the approval without the key (same meaning)');
713
700
  body = await sendOnce(undefined, () => client.assistant.planReview(taskId, reason !== undefined ? { decision, reason } : { decision }));
714
701
  }
@@ -749,9 +736,7 @@ async function decidePlanReviewInner(taskId, decision, permissionModeAfter, disp
749
736
  const bodyStatus = bodyWordOf(body, 'status');
750
737
  const effective = postStatus ?? bodyStatus;
751
738
  statusSeen = effective;
752
- const verdict = planReviewSettledVerdict({ postStatus, bodyStatus, reparked: bodySaysReparked(body), gateBefore, gateAfter, gateKindAfter });
753
- effect = verdict.effect;
754
- stillParkedProven = verdict.proven;
739
+ effect = planReviewSettledVerdict({ postStatus, bodyStatus, reparked: bodySaysReparked(body), gateBefore, gateAfter, gateKindAfter });
755
740
  const code = bodyWordOf(body, 'errorCode');
756
741
  if (effect === 'still_parked' && postStatus === 'needs_review' && !bodySaysReparked(body)) {
757
742
  outcome =
@@ -797,14 +782,13 @@ async function decidePlanReviewInner(taskId, decision, permissionModeAfter, disp
797
782
  const noAnswer = typeof status === 'number' || typeof e !== 'object' ? null : noAnswerKindOf(e);
798
783
  if (status === 400 && refusedCode === REQUEST_FIELD_CONFLICT && permissionModeAfter === 'acceptEdits') {
799
784
  hostLog('debug', `planReviewWire: ${decision} + acceptEdits refused (request.field_conflict) — NOT re-sent with a different mode`);
800
- effect = 'still_parked';
801
- stillParkedProven = true;
785
+ effect = decision === 'approve' ? 'still_parked' : 'not_applied';
802
786
  outcome =
803
787
  decision === 'approve'
804
788
  ? 'The plan approval was NOT applied: the engine refused "auto-accept edits" for this task (it was not started read-only in plan mode, so that option does not apply). ' +
805
789
  'Nothing changed engine-side — the plan is still waiting for review. Tell the user plainly, and that approving with "manually approve edits" will go through.'
806
790
  : `The plan ${decision} was NOT applied: the engine refused the post-approval permission mode that was sent with it (request.field_conflict). ` +
807
- 'Nothing changed engine-side — the plan is still waiting for review. Tell the user plainly that the decision did not go through.';
791
+ 'This request changed nothing engine-side. Tell the user plainly that the decision did not go through.';
808
792
  }
809
793
  else if (status === 404 && refusedCode === 'not_found.plan_review') {
810
794
  hostLog('debug', `planReviewWire: ${decision} → 404 not_found.plan_review (no pending plan review any more — an earlier decision likely settled it)`);
@@ -817,7 +801,6 @@ async function decidePlanReviewInner(taskId, decision, permissionModeAfter, disp
817
801
  const cu = checkpointUnsupportedVersionFromError(e);
818
802
  hostLog('debug', `planReviewWire: ${decision} → 409 checkpoint.unsupported_version (the server cannot continue this parked review in its stored form; still pending)`);
819
803
  effect = 'still_parked';
820
- stillParkedProven = true;
821
804
  stillParkedCause = 'stored_form_unsupported';
822
805
  outcome = `This ${decision} was not applied. ${checkpointUnsupportedVersionContent(cu, { parkKind: 'plan_review', runId: taskId })}`;
823
806
  }
@@ -858,9 +841,9 @@ async function decidePlanReviewInner(taskId, decision, permissionModeAfter, disp
858
841
  const tail = planReviewOutcomeTail(taskId, decision, effect, stillParkedCause);
859
842
  const prompt = `<plan-review-outcome>\n${outcome}\n${tail}\n</plan-review-outcome>`;
860
843
  const onOutcome = opts?.onOutcome;
861
- settle(effect === 'not_sent' || (effect === 'still_parked' && stillParkedProven));
844
+ settle(effect === 'not_sent' || effect === 'still_parked');
862
845
  try {
863
- const delivered = enqueuePlanReviewOutcome(prompt, { taskId, dispatchNo, decision, effect });
846
+ const delivered = enqueuePlanReviewOutcome(prompt, { taskId, dispatchNo, decision, effect, ...(effect === 'still_parked' && stillParkedCause !== undefined ? { cause: stillParkedCause } : {}) });
864
847
  if (!delivered) {
865
848
  if (onOutcome !== undefined) {
866
849
  hostLog('debug', `planReviewWire: outcome queue port not installed for task ${taskId} — outcome handed to the host's onOutcome callback only`);
@@ -875,7 +858,17 @@ async function decidePlanReviewInner(taskId, decision, permissionModeAfter, disp
875
858
  }
876
859
  if (onOutcome !== undefined) {
877
860
  try {
878
- onOutcome({ taskId, dispatchNo, decision, effect, detail: outcome, tail, prompt, ...(statusSeen !== undefined ? { status: statusSeen } : {}) });
861
+ onOutcome({
862
+ taskId,
863
+ dispatchNo,
864
+ decision,
865
+ effect,
866
+ ...(effect === 'still_parked' && stillParkedCause !== undefined ? { cause: stillParkedCause } : {}),
867
+ detail: outcome,
868
+ tail,
869
+ prompt,
870
+ ...(statusSeen !== undefined ? { status: statusSeen } : {}),
871
+ });
879
872
  }
880
873
  catch (e) {
881
874
  hostLog('debug', `planReviewWire: onOutcome callback threw for task ${taskId} (ignored): ${String(e)}`);
@@ -912,10 +905,10 @@ function joinReopenFlight(flight, taskId, receiptMs) {
912
905
  abortableSleep(Math.max(0, receiptMs), ac.signal).then(() => false),
913
906
  ]).then((presented) => {
914
907
  ac.abort();
915
- return presented ? { reopened: true, firstSight: false } : { reopened: false };
908
+ return presented ? { reopened: true, firstSight: false } : refusedReopen('not_presented');
916
909
  }, () => {
917
910
  ac.abort();
918
- return { reopened: false };
911
+ return refusedReopen('not_presented');
919
912
  });
920
913
  }
921
914
  function mintPlanReviewReopen(taskId, opts, sessionKey, receiptMs) {
@@ -955,10 +948,10 @@ function mintPlanReviewReopenCard(taskId, opts, sessionKey, receiptMs) {
955
948
  const markBefore = dismissalEntryFor(sessionKey, taskId);
956
949
  const settleOnReceipt = (receipt, firstSight) => receipt.then((presented) => {
957
950
  if (!presented)
958
- return { reopened: false };
951
+ return refusedReopen('not_presented');
959
952
  revokePlanReviewUserDismissal(sessionKey, taskId, markBefore);
960
953
  return { reopened: true, firstSight };
961
- }, () => ({ reopened: false }));
954
+ }, () => refusedReopen('not_presented'));
962
955
  const canonicalId = planReviewQuestionId(taskId);
963
956
  const armedKey = planReviewArmedKeyFor(sessionKey, taskId);
964
957
  const firstSight = !wasGateArmedFor(sessionKey, armedKey);
@@ -992,7 +985,7 @@ function mintPlanReviewReopenCard(taskId, opts, sessionKey, receiptMs) {
992
985
  if (activeReopenResponders.get(activeKey)?.questionId === questionId) {
993
986
  activeReopenResponders.delete(activeKey);
994
987
  }
995
- const choice = planReviewChoiceFromAnswer(answer, LEGACY_TWO_CHOICE_LABELS);
988
+ const choice = planReviewAnswerChoiceOf(questionId, answer);
996
989
  if (choice === 'dismissed') {
997
990
  notePlanReviewUserDismissalFor(sessionKey, taskId, opts?.readGateInstanceKeys, questionId);
998
991
  return { ok: true };
@@ -1017,6 +1010,9 @@ function mintPlanReviewReopenCard(taskId, opts, sessionKey, receiptMs) {
1017
1010
  publishQuestionFrameFor(sessionKey, planReviewQuestionFrame(questionId, REOPEN_QUESTION, false, true));
1018
1011
  return settleOnReceipt(receipt, firstSight);
1019
1012
  }
1013
+ function refusedReopen(cause) {
1014
+ return { reopened: false, _sema_reopenRefusal: cause };
1015
+ }
1020
1016
  function noPresentationSurfaceVerdict(taskId, sessionKey) {
1021
1017
  const verdict = { reopened: false, _sema_noPresentationSurface: true };
1022
1018
  hostLog('debug', `planReviewWire: reopen for task ${taskId} refused — nothing is subscribed to question frames for session ` +
@@ -1039,7 +1035,7 @@ async function reopenAfterDismissalCheck(taskId, opts, sessionKey, receiptMs, ma
1039
1035
  }
1040
1036
  }
1041
1037
  }
1042
- const ledgerSaysInFlight = planReviewDecisionInFlight(taskId, recheckReadStart);
1038
+ const ledgerSaysInFlight = decisionInFlightOf({ gate: 'plan_review', taskId }, recheckReadStart);
1043
1039
  if (ledgerSaysInFlight) {
1044
1040
  hostLog('debug', `planReviewWire: reopen for task ${taskId} refused after the dismissal check — a decision for this task went out while the check was reading`);
1045
1041
  return { reopened: false, _sema_decisionInFlight: true };
@@ -1088,24 +1084,26 @@ async function staleDismissalVerdict(current, sessionKey, taskId, receiptMs) {
1088
1084
  const windowEnd = abortableSleep(Math.max(0, receiptMs), ac.signal).then(() => false);
1089
1085
  try {
1090
1086
  let entry = current;
1087
+ let lastWaitPresented;
1091
1088
  for (let round = 0; round < 8; round++) {
1092
1089
  if (entry?.kind === 'decided')
1093
1090
  return { reopened: false, _sema_decisionInFlight: true };
1094
1091
  if (entry?.kind === 'dismissed')
1095
1092
  return { reopened: false, dismissedByUser: true };
1096
1093
  if (entry?.kind !== 'reopened' || entry.onScreen === undefined)
1097
- return { reopened: false };
1094
+ return refusedReopen(entry === undefined && lastWaitPresented === false ? 'not_presented' : 'gate_record_gone');
1098
1095
  const onScreen = await Promise.race([
1099
1096
  entry.onScreen.then((v) => v === true, () => false),
1100
1097
  windowEnd,
1101
1098
  ]);
1102
1099
  const now = dismissalEntryFor(sessionKey, taskId);
1103
1100
  if (now === entry) {
1104
- return onScreen ? { reopened: true, firstSight: !wasGateArmedFor(sessionKey, planReviewArmedKeyFor(sessionKey, taskId)) } : { reopened: false };
1101
+ return onScreen ? { reopened: true, firstSight: !wasGateArmedFor(sessionKey, planReviewArmedKeyFor(sessionKey, taskId)) } : refusedReopen('not_presented');
1105
1102
  }
1103
+ lastWaitPresented = onScreen;
1106
1104
  entry = now;
1107
1105
  }
1108
- return { reopened: false };
1106
+ return refusedReopen('gate_record_gone');
1109
1107
  }
1110
1108
  finally {
1111
1109
  ac.abort();
@@ -1115,25 +1113,25 @@ export function reopenPlanReviewCard(taskId, opts) {
1115
1113
  const receiptMs = opts?.presentationReceiptMs;
1116
1114
  if (typeof receiptMs !== 'number' || Number.isNaN(receiptMs)) {
1117
1115
  hostLog('debug', `planReviewWire: reopen for task ${String(taskId)} refused — presentationReceiptMs is required (a number of milliseconds); the synchronous form was retired in 0.98.0`);
1118
- return Promise.resolve({ reopened: false });
1116
+ return Promise.resolve(refusedReopen('invalid_call'));
1119
1117
  }
1120
1118
  try {
1121
1119
  if (typeof taskId !== 'string' || taskId.length === 0) {
1122
- return Promise.resolve({ reopened: false });
1120
+ return Promise.resolve(refusedReopen('invalid_call'));
1123
1121
  }
1124
1122
  const injected = opts;
1125
1123
  if (opts?.mintFreshQuestionId === false && (injected?.deliverDecision !== undefined || injected?.wire !== undefined || injected?.onOutcome !== undefined)) {
1126
1124
  hostLog('error', `planReviewWire: plan_review reopen for task ${taskId} refused — mintFreshQuestionId:false reuses the armed card's responder and its delivery, ` +
1127
1125
  'so deliverDecision / wire / onOutcome cannot be given with it; drop mintFreshQuestionId:false to deliver through the injected path');
1128
- return Promise.resolve({ reopened: false });
1126
+ return Promise.resolve(refusedReopen('invalid_call'));
1129
1127
  }
1130
1128
  const readStart = typeof opts.pendingReadStartedAt === 'number' && Number.isFinite(opts.pendingReadStartedAt) ? opts.pendingReadStartedAt : undefined;
1131
- if (planReviewDecisionInFlight(taskId, readStart)) {
1129
+ if (decisionInFlightOf({ gate: 'plan_review', taskId }, readStart)) {
1132
1130
  hostLog('debug', `planReviewWire: reopen for task ${taskId} refused — a decision for this task is in flight (its answer is still being delivered)`);
1133
1131
  const refused = { reopened: false, _sema_decisionInFlight: true };
1134
1132
  return Promise.resolve(refused);
1135
1133
  }
1136
- const guardStartedAt = planReviewPendingReadMark();
1134
+ const guardStartedAt = decisionReadMark();
1137
1135
  const recheckReadStart = readStart === undefined ? guardStartedAt : Math.min(readStart, guardStartedAt);
1138
1136
  const sessionKey = opts.sessionKey ?? DEFAULT_SESSION_KEY;
1139
1137
  if (!hasQuestionOverlayFor(sessionKey)) {
@@ -1144,7 +1142,7 @@ export function reopenPlanReviewCard(taskId, opts) {
1144
1142
  '而缺省决断投递口(decidePlanReview)今天固定打默认槽的 baseUrl/token/principal。' +
1145
1143
  '整条链转 keyed 之前,非默认槽要重开请自带 deliverDecision(按本槽投递);' +
1146
1144
  '此处拒绝而不是照发 —— 照发会把这条会话的决断发到另一个槽上。');
1147
- return Promise.resolve({ reopened: false });
1145
+ return Promise.resolve(refusedReopen('no_delivery_path'));
1148
1146
  }
1149
1147
  const trigger = opts.trigger === undefined ? undefined : opts.trigger === 'user' ? 'user' : 'automatic';
1150
1148
  if (trigger === 'automatic') {
@@ -1155,6 +1153,6 @@ export function reopenPlanReviewCard(taskId, opts) {
1155
1153
  return mintPlanReviewReopen(taskId, opts, sessionKey, receiptMs);
1156
1154
  }
1157
1155
  catch {
1158
- return Promise.resolve({ reopened: false });
1156
+ return Promise.resolve(refusedReopen('internal_error'));
1159
1157
  }
1160
1158
  }
@@ -26,6 +26,7 @@ export declare function resumeRunningNoUiGuidance(i: {
26
26
  taskId: string;
27
27
  sessionId?: string | null;
28
28
  }): string;
29
- export declare function resumeAttachReplayDisclosure(taskId: string): string;
29
+ export declare function resumeAttachReplayDisclosure(taskId: string, lane?: CardSentenceLane): string;
30
+ export type CardSentenceLane = 'interactive' | 'print' | 'utility';
30
31
  export declare function resumeRunningCancelConfirmedRow(taskId: string): string;
31
- export declare function resumeRunningCancelUnconfirmedRow(taskId: string): string;
32
+ export declare function resumeRunningCancelUnconfirmedRow(taskId: string, lane?: CardSentenceLane): string;
@@ -62,22 +62,28 @@ export function resumeRunningNoUiGuidance(i) {
62
62
  `${T} background=do nothing — run ${i.taskId} keeps executing on the engine; this client does not list it (read it with GET /v1/runs/${i.taskId})`,
63
63
  ].join('\n');
64
64
  }
65
- export function resumeAttachReplayDisclosure(taskId) {
65
+ export function resumeAttachReplayDisclosure(taskId, lane) {
66
66
  return (`sema: attaching to run ${taskId} — sema is replaying it from the engine's ledger, so anything from that ` +
67
67
  `turn already shown above will appear again below. There is no resume marker for a run that outlived its shell. ` +
68
- `The replayed turns are not billed into this session's cost again either — the engine's own record ` +
69
- `(GET /v1/runs/${taskId}) is the authority on what that run really spent.`);
68
+ `The replayed turns are not billed into this session's cost again either — ` +
69
+ (interactiveCardLane(lane)
70
+ ? `the engine's own record of run ${taskId} is the authority on what that run really spent.`
71
+ : `the engine's own record (GET /v1/runs/${taskId}) is the authority on what that run really spent.`));
70
72
  }
71
- function cancelRow(taskId, confirmed) {
72
- return confirmed
73
- ? `The engine accepted the cancel for run ${taskId} on your request. A cancel finishes on the engine's side, so that run may need a moment to stop.`
74
- : `sema: the cancel for run ${taskId} did not come back confirmed, so that run may still be executing. ` +
75
- `This screen does not list it — read its real state on the engine (GET /v1/runs/${taskId}) before ` +
76
- `assuming this session is free.`;
73
+ function cancelRow(taskId, confirmed, lane) {
74
+ if (confirmed)
75
+ return `The engine accepted the cancel for run ${taskId} on your request. A cancel finishes on the engine's side, so that run may need a moment to stop.`;
76
+ return (`sema: the cancel for run ${taskId} did not come back confirmed, so that run may still be executing. ` +
77
+ (interactiveCardLane(lane)
78
+ ? `This screen does not list it — its real state lives on the engine, under run ${taskId}, so do not assume this session is free.`
79
+ : `This screen does not list it — read its real state on the engine (GET /v1/runs/${taskId}) before assuming this session is free.`));
80
+ }
81
+ function interactiveCardLane(lane) {
82
+ return lane !== 'print' && lane !== 'utility';
77
83
  }
78
84
  export function resumeRunningCancelConfirmedRow(taskId) {
79
85
  return cancelRow(taskId, true);
80
86
  }
81
- export function resumeRunningCancelUnconfirmedRow(taskId) {
82
- return cancelRow(taskId, false);
87
+ export function resumeRunningCancelUnconfirmedRow(taskId, lane) {
88
+ return cancelRow(taskId, false, lane);
83
89
  }
@@ -1,7 +1,9 @@
1
1
  import type { SessionPermissionRules } from '@sema-agent/sdk';
2
2
  import type { ToolRosterView } from '../toolRoster.js';
3
+ import type { SessionRulesNamespaceFormsReading } from '../sessionRulesNamespaceFormsCapability.js';
4
+ import type { UiLanguage } from '../env/uiLanguage.js';
3
5
  import type { SessionRuleInertReason } from './sessionPolicyWire.js';
4
- export type SessionPolicyWithheldWhy = 'ask_no_bucket' | 'qualified_deny' | 'peer_wide' | 'wildcard' | 'not_a_tool_name' | 'legacy_tool_name' | 'not_in_roster';
6
+ export type SessionPolicyWithheldWhy = 'ask_no_bucket' | 'qualified_deny' | 'peer_wide' | 'wildcard' | 'not_a_tool_name' | 'legacy_tool_name' | 'not_in_roster' | 'namespace_covering_unconfirmed';
5
7
  export declare const SESSION_POLICY_WITHHELD_WHY: readonly SessionPolicyWithheldWhy[];
6
8
  export interface SessionPolicyWithheldRule {
7
9
  readonly rule: string;
@@ -16,7 +18,8 @@ export interface SessionPolicyDeliverability {
16
18
  }
17
19
  export interface SessionPolicyDeliverableOptions {
18
20
  readonly roster?: ToolRosterView;
21
+ readonly namespaceForms?: SessionRulesNamespaceFormsReading;
19
22
  }
20
23
  export declare function sessionPolicyDeliverable(behavior: 'deny' | 'ask', rules: readonly string[], opts?: SessionPolicyDeliverableOptions): SessionPolicyDeliverability;
21
- export declare function sessionPolicyWithheldNotice(why: SessionPolicyWithheldWhy): string;
24
+ export declare function sessionPolicyWithheldNotice(why: SessionPolicyWithheldWhy, lang?: UiLanguage): string;
22
25
  export declare function legacyToolNameFailureNoteOf(code: string | undefined): string | undefined;