@sema-agent/client-core 0.77.0 → 0.77.2

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 (382) hide show
  1. package/CHANGELOG.md +23 -1
  2. package/README.md +5 -4
  3. package/dist/abortableSleep.d.ts +0 -28
  4. package/dist/abortableSleep.js +0 -28
  5. package/dist/adapt/arms.d.ts +0 -46
  6. package/dist/adapt/arms.js +9 -544
  7. package/dist/adapt/ids.d.ts +0 -58
  8. package/dist/adapt/ids.js +0 -63
  9. package/dist/adapt/instanceLedger.d.ts +0 -25
  10. package/dist/adapt/instanceLedger.js +0 -20
  11. package/dist/adapt/panelTasks.d.ts +0 -69
  12. package/dist/adapt/panelTasks.js +0 -95
  13. package/dist/adapt/textSegmentAuthority.d.ts +1 -137
  14. package/dist/adapt/textSegmentAuthority.js +0 -54
  15. package/dist/adapt/textStream.d.ts +0 -252
  16. package/dist/adapt/textStream.js +2 -281
  17. package/dist/adapt/toolCards.d.ts +0 -46
  18. package/dist/adapt/toolCards.js +0 -23
  19. package/dist/adapt/turnFlags.d.ts +0 -54
  20. package/dist/adapt/turnFlags.js +1 -17
  21. package/dist/adapt/wireShapes.d.ts +0 -92
  22. package/dist/adapt/wireShapes.js +0 -83
  23. package/dist/adapt.d.ts +0 -55
  24. package/dist/adapt.js +1 -120
  25. package/dist/adapter/activeRunSelfHeal.d.ts +22 -515
  26. package/dist/adapter/activeRunSelfHeal.js +10 -625
  27. package/dist/adapter/downstream/eventToSdkMessage.d.ts +2 -305
  28. package/dist/adapter/downstream/eventToSdkMessage.js +2 -867
  29. package/dist/adapter/downstream/terminalToSdkResult.d.ts +2 -314
  30. package/dist/adapter/downstream/terminalToSdkResult.js +13 -560
  31. package/dist/adapter/downstream/turnUsageToModelUsage.d.ts +0 -95
  32. package/dist/adapter/downstream/turnUsageToModelUsage.js +2 -31
  33. package/dist/adapter/runStream.d.ts +0 -206
  34. package/dist/adapter/runStream.js +6 -596
  35. package/dist/adapter/types.d.ts +0 -111
  36. package/dist/adapter/types.js +0 -29
  37. package/dist/agentSession/backgroundView.d.ts +0 -106
  38. package/dist/agentSession/backgroundView.js +3 -49
  39. package/dist/agentSession/contract.d.ts +0 -98
  40. package/dist/agentSession/contract.js +0 -12
  41. package/dist/agentsWireCaps.d.ts +0 -72
  42. package/dist/agentsWireCaps.js +4 -72
  43. package/dist/approvalsStreamLiveCapability.d.ts +0 -25
  44. package/dist/approvalsStreamLiveCapability.js +0 -31
  45. package/dist/argvFlagValue.d.ts +0 -33
  46. package/dist/argvFlagValue.js +3 -35
  47. package/dist/attachmentsWireCaps.d.ts +0 -127
  48. package/dist/attachmentsWireCaps.js +0 -144
  49. package/dist/autoModeUnavailable.d.ts +0 -120
  50. package/dist/autoModeUnavailable.js +0 -144
  51. package/dist/classifierStatus.d.ts +0 -72
  52. package/dist/classifierStatus.js +0 -167
  53. package/dist/classifierVerdictWire.d.ts +0 -54
  54. package/dist/classifierVerdictWire.js +0 -133
  55. package/dist/clientContextWireCaps.d.ts +0 -37
  56. package/dist/clientContextWireCaps.js +0 -36
  57. package/dist/clientSlice.d.ts +0 -63
  58. package/dist/clientSlice.js +0 -45
  59. package/dist/cloudConfigWireCaps.d.ts +0 -86
  60. package/dist/cloudConfigWireCaps.js +2 -65
  61. package/dist/compensations.d.ts +0 -52
  62. package/dist/compensations.js +2 -63
  63. package/dist/controlRouter.d.ts +2 -208
  64. package/dist/controlRouter.js +1 -129
  65. package/dist/coreValuePorts.d.ts +0 -84
  66. package/dist/coreValuePorts.js +0 -29
  67. package/dist/decideReceipt.d.ts +0 -110
  68. package/dist/decideReceipt.js +0 -84
  69. package/dist/detachWire.d.ts +0 -130
  70. package/dist/detachWire.js +1 -130
  71. package/dist/deviceExecutorManagementCapability.d.ts +2 -35
  72. package/dist/deviceExecutorManagementCapability.js +1 -37
  73. package/dist/diagnostics.d.ts +0 -8
  74. package/dist/diagnostics.js +0 -8
  75. package/dist/diff/patch.d.ts +0 -17
  76. package/dist/diff/patch.js +0 -19
  77. package/dist/effectiveFacts.d.ts +0 -40
  78. package/dist/effectiveFacts.js +0 -22
  79. package/dist/effortWire.d.ts +0 -11
  80. package/dist/effortWire.js +0 -12
  81. package/dist/engineAgentPanelStore.d.ts +0 -169
  82. package/dist/engineAgentPanelStore.js +13 -293
  83. package/dist/engineCapReader.d.ts +0 -62
  84. package/dist/engineCapReader.js +1 -43
  85. package/dist/engineCapsCache.d.ts +0 -177
  86. package/dist/engineCapsCache.js +0 -199
  87. package/dist/engineCapsGenerationGuard.d.ts +0 -2
  88. package/dist/engineCapsGenerationGuard.js +0 -11
  89. package/dist/engineErrorCodes.d.ts +1 -316
  90. package/dist/engineErrorCodes.js +0 -427
  91. package/dist/engineHttpTools.d.ts +0 -29
  92. package/dist/engineHttpTools.js +0 -29
  93. package/dist/engineIdentity.d.ts +0 -83
  94. package/dist/engineIdentity.js +0 -88
  95. package/dist/engineInlineTaskStats.d.ts +0 -57
  96. package/dist/engineInlineTaskStats.js +1 -42
  97. package/dist/engineNoticeCodes.d.ts +0 -190
  98. package/dist/engineNoticeCodes.js +0 -182
  99. package/dist/engineSessionParam.d.ts +0 -30
  100. package/dist/engineSessionParam.js +0 -52
  101. package/dist/engineToolLabelStore.d.ts +0 -29
  102. package/dist/engineToolLabelStore.js +0 -31
  103. package/dist/engineWireSdk.d.ts +0 -90
  104. package/dist/engineWireSdk.js +0 -74
  105. package/dist/engineWireTarget.d.ts +0 -14
  106. package/dist/engineWireTarget.js +0 -39
  107. package/dist/env/localeGeo.d.ts +0 -12
  108. package/dist/env/localeGeo.js +2 -77
  109. package/dist/env/localeTag.d.ts +0 -34
  110. package/dist/env/localeTag.js +0 -32
  111. package/dist/env/uiLanguage.d.ts +0 -13
  112. package/dist/env/uiLanguage.js +0 -25
  113. package/dist/envFlag.d.ts +0 -37
  114. package/dist/envFlag.js +0 -40
  115. package/dist/executionLaneCapability.d.ts +0 -48
  116. package/dist/executionLaneCapability.js +0 -54
  117. package/dist/finalVerifyWire.d.ts +0 -67
  118. package/dist/finalVerifyWire.js +3 -43
  119. package/dist/fleet/fleetLedger.d.ts +0 -308
  120. package/dist/fleet/fleetLedger.js +10 -429
  121. package/dist/fleet/fleetProjection.d.ts +0 -240
  122. package/dist/fleet/fleetProjection.js +0 -189
  123. package/dist/fleet/fleetRowAgentType.d.ts +0 -6
  124. package/dist/fleet/fleetRowAgentType.js +1 -32
  125. package/dist/fleet/workflowSizeWarning.d.ts +0 -47
  126. package/dist/fleet/workflowSizeWarning.js +1 -46
  127. package/dist/fleetAgentPanelProjection.d.ts +0 -48
  128. package/dist/fleetAgentPanelProjection.js +8 -173
  129. package/dist/fleetTaskDesc.d.ts +0 -39
  130. package/dist/fleetTaskDesc.js +0 -69
  131. package/dist/forkWireCaps.d.ts +0 -23
  132. package/dist/forkWireCaps.js +1 -24
  133. package/dist/gateOutcome.d.ts +0 -140
  134. package/dist/gateOutcome.js +0 -85
  135. package/dist/gateVocabulary.d.ts +0 -114
  136. package/dist/gateVocabulary.js +1 -161
  137. package/dist/goalStopHook.d.ts +0 -127
  138. package/dist/goalStopHook.js +0 -178
  139. package/dist/headlessPermissionModeWire.d.ts +0 -76
  140. package/dist/headlessPermissionModeWire.js +1 -155
  141. package/dist/headlessReconnectWire.d.ts +0 -84
  142. package/dist/headlessReconnectWire.js +13 -67
  143. package/dist/hitl/approvalDecisionNoteAudit.d.ts +0 -49
  144. package/dist/hitl/approvalDecisionNoteAudit.js +0 -56
  145. package/dist/hitl/approvalOutcomeNote.d.ts +0 -2
  146. package/dist/hitl/approvalOutcomeNote.js +0 -20
  147. package/dist/hitl/approvalResolution.d.ts +0 -113
  148. package/dist/hitl/approvalResolution.js +0 -66
  149. package/dist/hitl/approvalsFeed.d.ts +0 -183
  150. package/dist/hitl/approvalsFeed.js +12 -243
  151. package/dist/hitl/armedGateRegistry.d.ts +0 -55
  152. package/dist/hitl/armedGateRegistry.js +0 -146
  153. package/dist/hitl/askGateWire.d.ts +0 -86
  154. package/dist/hitl/askGateWire.js +1 -95
  155. package/dist/hitl/askParkRowRouting.d.ts +0 -123
  156. package/dist/hitl/askParkRowRouting.js +1 -89
  157. package/dist/hitl/crashConverged.d.ts +0 -148
  158. package/dist/hitl/crashConverged.js +0 -214
  159. package/dist/hitl/editedRuleTextPrecheck.d.ts +0 -109
  160. package/dist/hitl/editedRuleTextPrecheck.js +0 -71
  161. package/dist/hitl/frameRouter.d.ts +0 -134
  162. package/dist/hitl/frameRouter.js +6 -378
  163. package/dist/hitl/gateIdentity.d.ts +0 -39
  164. package/dist/hitl/gateIdentity.js +0 -41
  165. package/dist/hitl/gateLedger.d.ts +0 -267
  166. package/dist/hitl/gateLedger.js +0 -121
  167. package/dist/hitl/hitlBridge.d.ts +7 -431
  168. package/dist/hitl/hitlBridge.js +7 -476
  169. package/dist/hitl/hitlHostSurface.d.ts +0 -150
  170. package/dist/hitl/hitlHostSurface.js +0 -169
  171. package/dist/hitl/livePendingAsk.d.ts +0 -91
  172. package/dist/hitl/livePendingAsk.js +0 -74
  173. package/dist/hitl/localAllowRule.d.ts +0 -62
  174. package/dist/hitl/localAllowRule.js +1 -33
  175. package/dist/hitl/parkOwnership.d.ts +0 -56
  176. package/dist/hitl/parkOwnership.js +0 -22
  177. package/dist/hitl/parkResolver.d.ts +3 -88
  178. package/dist/hitl/parkResolver.js +8 -349
  179. package/dist/hitl/parkRowBirthWait.d.ts +2 -26
  180. package/dist/hitl/parkRowBirthWait.js +3 -93
  181. package/dist/hitl/persistedRulesWire.d.ts +13 -358
  182. package/dist/hitl/persistedRulesWire.js +0 -310
  183. package/dist/hitl/planReviewWire.d.ts +4 -176
  184. package/dist/hitl/planReviewWire.js +9 -312
  185. package/dist/hitl/resumeRunningCard.d.ts +0 -105
  186. package/dist/hitl/resumeRunningCard.js +0 -105
  187. package/dist/hitl/sessionPolicyWire.d.ts +11 -191
  188. package/dist/hitl/sessionPolicyWire.js +0 -149
  189. package/dist/hitl/suspendedReopen.d.ts +3 -24
  190. package/dist/hitl/suspendedReopen.js +0 -14
  191. package/dist/hitl/toolApprovalWire.d.ts +5 -1308
  192. package/dist/hitl/toolApprovalWire.js +5 -945
  193. package/dist/hooksWireCaps.d.ts +0 -38
  194. package/dist/hooksWireCaps.js +0 -190
  195. package/dist/host.d.ts +0 -105
  196. package/dist/host.js +0 -33
  197. package/dist/hostEnv.d.ts +0 -14
  198. package/dist/hostEnv.js +0 -13
  199. package/dist/imagesWireCaps.d.ts +0 -21
  200. package/dist/imagesWireCaps.js +0 -22
  201. package/dist/index.d.ts +0 -134
  202. package/dist/index.js +0 -476
  203. package/dist/interactiveHalt.d.ts +5 -153
  204. package/dist/interactiveHalt.js +0 -111
  205. package/dist/interactiveToolsWire.d.ts +0 -62
  206. package/dist/interactiveToolsWire.js +1 -67
  207. package/dist/leaderConflict.d.ts +0 -59
  208. package/dist/leaderConflict.js +0 -48
  209. package/dist/limitsWire.d.ts +0 -125
  210. package/dist/limitsWire.js +2 -120
  211. package/dist/liveInitToolFace.d.ts +0 -77
  212. package/dist/liveInitToolFace.js +1 -109
  213. package/dist/liveModelCatalog.d.ts +0 -52
  214. package/dist/liveModelCatalog.js +0 -48
  215. package/dist/liveQuestionStore.d.ts +0 -87
  216. package/dist/liveQuestionStore.js +1 -56
  217. package/dist/mcpLiveness.d.ts +0 -151
  218. package/dist/mcpLiveness.js +0 -122
  219. package/dist/mcpPanel.d.ts +0 -104
  220. package/dist/mcpPanel.js +0 -49
  221. package/dist/mcpReconnect.d.ts +0 -58
  222. package/dist/mcpReconnect.js +1 -69
  223. package/dist/mcpWireCaps.d.ts +0 -55
  224. package/dist/mcpWireCaps.js +1 -13
  225. package/dist/memoryComplianceCapability.d.ts +3 -57
  226. package/dist/memoryComplianceCapability.js +0 -57
  227. package/dist/memoryEntriesWire.d.ts +6 -198
  228. package/dist/memoryEntriesWire.js +0 -144
  229. package/dist/memoryOriginCapability.d.ts +3 -53
  230. package/dist/memoryOriginCapability.js +0 -50
  231. package/dist/memorySpecWire.d.ts +0 -116
  232. package/dist/memorySpecWire.js +0 -150
  233. package/dist/model/catalog.d.ts +0 -111
  234. package/dist/model/catalog.js +0 -87
  235. package/dist/model/catalogLoader.d.ts +0 -114
  236. package/dist/model/catalogLoader.js +2 -139
  237. package/dist/model/modelSupplyRules.d.ts +1 -55
  238. package/dist/model/modelSupplyRules.js +0 -62
  239. package/dist/model/providerAuth.d.ts +0 -103
  240. package/dist/model/providerAuth.js +2 -38
  241. package/dist/model/providerCatalog.d.ts +0 -45
  242. package/dist/model/providerCatalog.js +0 -37
  243. package/dist/model/providerPresets.d.ts +0 -33
  244. package/dist/model/providerPresets.js +2 -91
  245. package/dist/model/tierVocabulary.d.ts +0 -31
  246. package/dist/model/tierVocabulary.js +0 -27
  247. package/dist/modelBudgetRule.d.ts +0 -39
  248. package/dist/modelBudgetRule.js +0 -39
  249. package/dist/modelCapabilityProbe.d.ts +0 -175
  250. package/dist/modelCapabilityProbe.js +0 -147
  251. package/dist/modelWireCaps.d.ts +0 -13
  252. package/dist/modelWireCaps.js +0 -13
  253. package/dist/notifications.d.ts +0 -233
  254. package/dist/notifications.js +14 -492
  255. package/dist/oneShotWireCaps.d.ts +0 -34
  256. package/dist/oneShotWireCaps.js +0 -35
  257. package/dist/ownKey.d.ts +0 -33
  258. package/dist/ownKey.js +0 -33
  259. package/dist/panelRunningHistory.d.ts +0 -28
  260. package/dist/panelRunningHistory.js +0 -43
  261. package/dist/peerFrames.d.ts +0 -71
  262. package/dist/peerFrames.js +0 -168
  263. package/dist/peerLaneCapability.d.ts +0 -44
  264. package/dist/peerLaneCapability.js +0 -52
  265. package/dist/permissionRuleIssue.d.ts +0 -30
  266. package/dist/permissionRuleIssue.js +0 -78
  267. package/dist/permissionRulesWriteCapability.d.ts +0 -46
  268. package/dist/permissionRulesWriteCapability.js +0 -54
  269. package/dist/permissionWireCaps.d.ts +0 -37
  270. package/dist/permissionWireCaps.js +0 -37
  271. package/dist/postureKnob.d.ts +0 -71
  272. package/dist/postureKnob.js +0 -86
  273. package/dist/principalWire.d.ts +0 -17
  274. package/dist/principalWire.js +0 -17
  275. package/dist/printToolResultFrame.d.ts +0 -100
  276. package/dist/printToolResultFrame.js +0 -33
  277. package/dist/promptProfileWireCaps.d.ts +0 -13
  278. package/dist/promptProfileWireCaps.js +0 -13
  279. package/dist/readFacePosture.d.ts +0 -43
  280. package/dist/readFacePosture.js +0 -46
  281. package/dist/request/printNotification.d.ts +0 -20
  282. package/dist/request/printNotification.js +0 -55
  283. package/dist/request/taskRequest.d.ts +0 -249
  284. package/dist/request/taskRequest.js +10 -496
  285. package/dist/resumeRefusalCopy.d.ts +0 -136
  286. package/dist/resumeRefusalCopy.js +1 -117
  287. package/dist/retainBackgroundWireCaps.d.ts +0 -48
  288. package/dist/retainBackgroundWireCaps.js +0 -48
  289. package/dist/retryStatus.d.ts +2 -221
  290. package/dist/retryStatus.js +0 -107
  291. package/dist/rewindWireCaps.d.ts +0 -27
  292. package/dist/rewindWireCaps.js +0 -24
  293. package/dist/runCancelContext.d.ts +1 -20
  294. package/dist/runCancelContext.js +0 -34
  295. package/dist/runTerminal.d.ts +0 -273
  296. package/dist/runTerminal.js +0 -177
  297. package/dist/sandboxWire.d.ts +0 -38
  298. package/dist/sandboxWire.js +0 -82
  299. package/dist/scenarioWire.d.ts +0 -60
  300. package/dist/scenarioWire.js +0 -68
  301. package/dist/scratchpadWireCaps.d.ts +0 -11
  302. package/dist/scratchpadWireCaps.js +0 -32
  303. package/dist/sdkWireTransit.d.ts +0 -38
  304. package/dist/sdkWireTransit.js +0 -30
  305. package/dist/seam.d.ts +18 -853
  306. package/dist/seam.js +0 -52
  307. package/dist/seatContract.d.ts +0 -555
  308. package/dist/seatContract.js +5 -304
  309. package/dist/selfOrchestrationDenial.d.ts +0 -189
  310. package/dist/selfOrchestrationDenial.js +0 -162
  311. package/dist/selfOrchestrationWireCaps.d.ts +0 -38
  312. package/dist/selfOrchestrationWireCaps.js +0 -38
  313. package/dist/sessionMap.d.ts +0 -60
  314. package/dist/sessionMap.js +0 -37
  315. package/dist/sessionMemoryStatus.d.ts +11 -114
  316. package/dist/sessionMemoryStatus.js +0 -112
  317. package/dist/sessionModelLatch.d.ts +0 -29
  318. package/dist/sessionModelLatch.js +0 -40
  319. package/dist/sessionPolicyCapability.d.ts +3 -53
  320. package/dist/sessionPolicyCapability.js +0 -52
  321. package/dist/sessionSlot.d.ts +0 -26
  322. package/dist/sessionSlot.js +0 -17
  323. package/dist/skillsWireCaps.d.ts +0 -87
  324. package/dist/skillsWireCaps.js +0 -38
  325. package/dist/sqlEngineCapability.d.ts +0 -118
  326. package/dist/sqlEngineCapability.js +0 -134
  327. package/dist/sseIdleTriage.d.ts +0 -79
  328. package/dist/sseIdleTriage.js +1 -80
  329. package/dist/steering.d.ts +0 -54
  330. package/dist/steering.js +0 -63
  331. package/dist/subagent/engineCompactWire.d.ts +0 -34
  332. package/dist/subagent/engineCompactWire.js +4 -134
  333. package/dist/subagent/engineDelegatedPrompt.d.ts +0 -31
  334. package/dist/subagent/engineDelegatedPrompt.js +1 -103
  335. package/dist/subagent/engineRowStopGate.d.ts +0 -20
  336. package/dist/subagent/engineRowStopGate.js +0 -49
  337. package/dist/subagent/engineSubagentOutput.d.ts +0 -7
  338. package/dist/subagent/engineSubagentOutput.js +1 -51
  339. package/dist/subagent/engineSubagentResume.d.ts +2 -279
  340. package/dist/subagent/engineSubagentResume.js +2 -129
  341. package/dist/subagent/engineSubagentSteer.d.ts +0 -26
  342. package/dist/subagent/engineSubagentSteer.js +0 -63
  343. package/dist/subagent/engineSubagentTail.d.ts +0 -38
  344. package/dist/subagent/engineSubagentTail.js +2 -110
  345. package/dist/subagent/engineTaskHandleWire.d.ts +11 -65
  346. package/dist/subagent/engineTaskHandleWire.js +20 -131
  347. package/dist/subagent/subagentOwnerAbsence.d.ts +0 -2
  348. package/dist/subagent/subagentOwnerAbsence.js +0 -25
  349. package/dist/subagentContentStore.d.ts +3 -260
  350. package/dist/subagentContentStore.js +7 -540
  351. package/dist/systemReminderTag.d.ts +0 -49
  352. package/dist/systemReminderTag.js +0 -61
  353. package/dist/toolResult.d.ts +1 -211
  354. package/dist/toolResult.js +1 -358
  355. package/dist/toolRoster.d.ts +0 -140
  356. package/dist/toolRoster.js +0 -66
  357. package/dist/typePins.d.ts +0 -46
  358. package/dist/types/engineState.d.ts +0 -71
  359. package/dist/types/engineState.js +0 -16
  360. package/dist/ultracodeWireCaps.d.ts +0 -75
  361. package/dist/ultracodeWireCaps.js +0 -92
  362. package/dist/unrefTimer.d.ts +0 -27
  363. package/dist/webSearchBackendCapability.d.ts +0 -72
  364. package/dist/webSearchBackendCapability.js +0 -79
  365. package/dist/webSearchWireCaps.d.ts +0 -37
  366. package/dist/webSearchWireCaps.js +0 -34
  367. package/dist/websearch/searchProviderPresets.d.ts +0 -81
  368. package/dist/websearch/searchProviderPresets.js +0 -27
  369. package/dist/wireErrorTriage.d.ts +4 -160
  370. package/dist/wireErrorTriage.js +0 -171
  371. package/dist/wireRefusalCopy.d.ts +0 -28
  372. package/dist/wireRefusalCopy.js +0 -28
  373. package/dist/workflow.d.ts +0 -40
  374. package/dist/workflow.js +0 -52
  375. package/dist/workflowClient.d.ts +0 -122
  376. package/dist/workflowClient.js +8 -360
  377. package/dist/workflowMonitor.d.ts +2 -72
  378. package/dist/workflowMonitor.js +0 -26
  379. package/dist/writeProtectionCapability.d.ts +0 -112
  380. package/dist/writeProtectionCapability.js +0 -109
  381. package/docs/INTEGRATION-CLIENTS.md +62 -1
  382. package/package.json +1 -1
@@ -1,70 +1,15 @@
1
- /**
2
- * ⇄ B2 批搬迁(2026-07-27,多端改造设计稿 §3 B2):cli src/seam/adapter/upstream/controlRouter.ts 逐字搬入(闭包 1 文件,只 import SDK)。
3
- */
4
- /**
5
- * src/seam/adapter/upstream/controlRouter.ts — the UPSTREAM control-VERB router (NEW file, no CC-logic edit).
6
- *
7
- * Where `hitlBridge.ts` owns the suspended → decide → resume HITL loop (the gate-resolution verbs:
8
- * `approvals.decide` / `assistant.planReview` / `assistant.resume`), THIS module owns the OTHER half of the
9
- * upstream control channel (contract/04 §5/§6, contract/08 IH-7/IH-8): the SUPERVISION verbs that act on a
10
- * run *while it works* — submit a turn, steer it mid-flight, kill it, and the client-side QUEUED-COMMAND
11
- * ordering that has no wire of its own. It is the single choke point that maps a shell control INTENT onto
12
- * the right `client.runs.*` verb, branching the §9.1 error taxonomy fail-closed.
13
- *
14
- * The five routes (contract/04 §5/§6; 08 IH-7/IH-8; the catalog rows it binds):
15
- *
16
- * 1. **submit** (IH-1/IH-2, catalog L73/L74). A turn → its OWN durable run: `runs.create(TaskRequest)` →
17
- * 202 `RunReceipt`. The SAME `sessionId` continues the conversation (the service serializes turns per
18
- * session); the SAME `jobId` groups the sub-runs into ONE Task in the work view (contract/04 §5.2,
19
- * types.ts:59-63). `runs.create` is a SUBMIT → it carries an idempotency key and the SDK may retry it.
20
- *
21
- * 2. **steer** (IH-7, §5.1, catalog L81). Inject mid-flight direction into a RUNNING durable run:
22
- * `runs.steer(taskId, { text, mode? })`. The text is untrusted DATA — the shell sends it RAW and the
23
- * SERVER fences it (the shell does NOT pre-sanitize control markers). AT-MOST-ONCE: steer is NOT
24
- * idempotent, so it is NEVER retried (runs.ts:43). `mode` drains queued steers at the TURN boundary
25
- * ("all" = inject all next turn; "one-at-a-time" = one per turn, FIFO). Errors are fail-closed and
26
- * dispatched by the WHOLE `steering.*` family (FIX③ 2026-08-07 — 此前只认 2 个码;server 7.4.0
27
- * dist 实扫 7 个,主 run steer 路由可达 4 个)。逐码语义 + 处置见 `ControlSafetyCode` 与
28
- * 文件底部的 `STEERING_CODE_TO_SAFETY` / `STEERING_ADVICE` 两张表。
29
- *
30
- * 3. **cancel** (IH-8, §5.3, catalog L84). HARD-STOP an async run: `runs.cancel(taskId)` → 202 `CancelAck`
31
- * (`status:"cancelling"` or a terminal no-op). The run then SETTLES to `failed` + `errorCode:"cancelled"`
32
- * (NOT a new status — the UI shows "cancelled", not an error). 🔴 A 409 no longer means "suspended"
33
- * (server [868] cancels a suspended/needs_review run in place — that IS the unlock handle); it now only
34
- * means the pending gate was decided/expired concurrently, surfaced as
35
- * `ControlSafetyError('cancel_lost_race')` = re-read state and retry. 404 =
36
- * non-owner/unknown (no existence leak). Server-idempotent; not a submit → no SDK retry.
37
- *
38
- * 4. **queued commands** (§5.2, catalog L82 `contract-extension`). CC enqueues next turns with a per-message
39
- * `priority: 'now'|'next'|'later'` and drops a queued message by uuid (`cancel_async_message`). The SDK
40
- * has NEITHER: no `priority` on `TaskRequest`, no drop-queued verb. The faithful behavior is CLIENT-SIDE:
41
- * hold a local priority-ordered queue, allow a DEQUEUE *before* submit (the only stop a queued message
42
- * has — once submitted the nearest lever is `cancel`, which kills the whole run, not one message), and
43
- * drain by submitting each queued turn as its own run under the same sessionId+jobId.
44
- *
45
- * Provider- and presentation-agnostic (contract/04 laws 2-3; 08 invariants): every verb stays at
46
- * `TaskRequest` / `RunReceipt` / `CancelAck` altitude. No Anthropic `effort`/`fast_mode`, no claude.ai
47
- * control-message shape, no widget/glyph crosses this seam. The router emits the SDK verb; the shell owns the
48
- * keybinding, the queue chrome, and the "cancelled" badge.
49
- */
50
1
  import type { TaskRequest, RunReceipt, CancelAck, Scenario } from '@sema-agent/sdk';
51
2
  export interface RunsResourceLike {
52
- /** POST /v1/runs → 202 RunReceipt. SUBMIT-class: carries an idempotency key, SDK may retry (runs.ts:13). */
53
3
  create(req: TaskRequest, opts?: {
54
4
  idempotencyKey?: string | null;
55
5
  signal?: AbortSignal;
56
6
  }): Promise<RunReceipt>;
57
- /** POST /v1/runs/:id/steer — inject mid-flight direction into a RUNNING run. AT-MOST-ONCE: NOT a submit,
58
- * NEVER retried (runs.ts:51). The text is untrusted DATA the server fences. */
59
7
  steer(taskId: string, steer: {
60
8
  text: string;
61
9
  mode?: 'all' | 'one-at-a-time';
62
10
  }, opts?: {
63
11
  signal?: AbortSignal;
64
12
  }): Promise<unknown>;
65
- /** POST /v1/runs/:id/cancel → 202 CancelAck. Hard-stop; server-idempotent; not a submit → no retry
66
- * (runs.ts:34). 🔴 suspended/needs_review 也走这里就地终态化([868]);409 只剩「挂起的 gate 被
67
- * 并发决定/过期」这一种(重读状态后重试);404 non-owner。 */
68
13
  cancel(taskId: string, opts?: {
69
14
  signal?: AbortSignal;
70
15
  }): Promise<CancelAck>;
@@ -72,208 +17,57 @@ export interface RunsResourceLike {
72
17
  export interface ControlClientLike {
73
18
  runs: RunsResourceLike;
74
19
  }
75
- /**
76
- * A supervision-verb stop the shell must HANDLE, not retry (contract/04 §9.1). The `code` is stable so the
77
- * shell can branch.
78
- *
79
- * 🔴 FIX③(2026-08-07,server 7.4.0 `dist/` 亲扫)—— steering 族此前只认 2 个码。实测 `steering.*`
80
- * 在 server 7.4.0 里共 **7 个**;主 run 的 `POST /v1/runs/:id/steer` 路由(本 router 唯一调用的那条)
81
- * 可达其中 4 个:`not_running`(409)/ `invalid_content`(422)/ `queue_full`(409,core 5.14.0 队列
82
- * 化后新出)/ `duplicate_input_id`(409,调用方带 `Idempotency-Key` 时可达);另外 3 个来自子代
83
- * steer/resume 面与 workflow agent steer 面(`ambiguous_target` / `ambiguous_label` / `still_running`)。
84
- * 🔴 **[7226] 包侧缺口 ①(0.68.1)**:码表补**第 8 码** `steering.blocked_by_hook`(422,部署
85
- * `userPromptSubmit` 门拦下;live 腿可达)。它此前落开集兜底位 `steering_other` —— 兜底位的判词
86
- * 逐字是「别按成员猜它的意思」,而这一码的处置恰恰是**明确的**(输入未受理、改内容自由重试)⇒
87
- * 兜底在这一位上不是「安全降级」,是把一条能自救的拒绝渲成一条不知道怎么办的拒绝。
88
- * SDK 6.3.0 侧已把整族改成**前缀分派**(`SteeringError` 基类),所以「没认全」的后果不是崩溃,
89
- * 而是那些码原样裸抛给壳 —— 壳只 `catch (e instanceof ControlSafetyError)` 就漏在外面。
90
- *
91
- * ⚠️ `still_running` 与 `not_running` **语义正相反**(前者=子代还在飞,该 steer 不该 resume;后者=
92
- * 它不在飞)。两码塌进同一个判别位会让 UI 说反话,所以它们各占一个码,永不合并。
93
- */
94
- export type ControlSafetyCode =
95
- /** steer 了一个不在飞的 run(suspended/terminal/跨副本);处置=先解它的 gate,别 steer。 */
96
- 'not_running'
97
- /** steer 正文带控制面越狱串,core 拒;处置=SURFACE,绝不 strip-and-retry。 */
98
- | 'invalid_content'
99
- /** 挂起 checkpoint 上的 steer 队列满了(core fail-loud,绝不驱逐已接受的指令);处置=等它 drain。 */
100
- | 'queue_full'
101
- /** 同一个 `Idempotency-Key` 配了**不同**正文;处置=换一个 key,别复用(重发原文没有意义)。 */
102
- | 'duplicate_input_id'
103
- /** `ambiguous_target`(子代面)/ `ambiguous_label`(workflow 面)—— 不止一个活体匹配;
104
- * 两码同一处置(换唯一定位方式),故共用一个判别位,`cause.errorCode` 保留是哪条轴。 */
105
- | 'ambiguous_target'
106
- /** 对一个**还在飞**的子代调了 resume;处置=改调 steer,或等它 settle。`not_running` 的反面。 */
107
- | 'still_running'
108
- /**
109
- * 部署的 `userPromptSubmit` 门拦下了这条输入([7226] 包侧缺口 ①,0.68.1;server 契约 (2) 表
110
- * 第 8 行;core 5.62 design/373 §4.3)。block / 超时 / 崩溃**同码 fail-closed**,成因由 message
111
- * 判别(携 hook 自己的 bounded reason)。
112
- * 🔴 **输入未被受理**:没有 `human_input` 帧、`inputId` 不入账 ⇒ 处置 = **改内容自由重试**。
113
- * 🔴 它与 `invalid_content` / `steering_other` 都**不许合并**:前者是「正文违规,SURFACE 别
114
- * strip-and-retry」,后者的判词逐字是「别按成员猜它的意思」—— 把一条**能自救**的拒绝塌进这两位
115
- * 任何一位,UI 都会把「改一句话再发」说成「你没救了」。
116
- * ⚠️ `/steer` 的 **park 腿结构性不可达本码**(hook 对 parked 转向的拦截发生在 resume 再投递时刻,
117
- * 走 `steering.parked_input_blocked` 通告);本路由器调的是 live 腿,所以这一位在这里可达。
118
- */
119
- | 'blocked_by_hook'
120
- /** 开集兜底:`steering.` 前缀但本表不认得的**未来**码(SDK 前缀分派同款姿势)。
121
- * 处置=按「这条 steer 没落地」呈现,并把 `cause.errorCode` 原样打进日志,别按成员猜语义。 */
122
- | 'steering_other'
123
- /** cancel 的 409:挂起的 gate 被并发决定/过期(重读状态后重试 cancel)。码缺席 / 认不出的 409 也落这一位(行为同旧)。 */
124
- | 'cancel_lost_race'
125
- /** 0.73.1:cancel 的 409 `conflict.run_not_running` —— 取消旗反复挂不上(行在 running 与 park 之间来回跳);引擎一个字节没改,处置 = **直接重试**。
126
- * 与 `cancel_lost_race` 处置相反(那一位是「别人已经替这条 run 做了决定,先去看结果」),所以各占一个码。 */
127
- | 'cancel_run_not_running'
128
- /** 404 — non-owner / unknown run(无存在性谕示器)。 */
129
- | 'not_found';
20
+ export type ControlSafetyCode = 'not_running' | 'invalid_content' | 'queue_full' | 'duplicate_input_id' | 'ambiguous_target' | 'still_running' | 'blocked_by_hook' | 'steering_other' | 'cancel_lost_race' | 'cancel_run_not_running' | 'not_found';
130
21
  export declare class ControlSafetyError extends Error {
131
22
  readonly code: ControlSafetyCode;
132
- /** The original SDK error, for logging (never re-thrown blind). */
133
23
  readonly cause?: unknown | undefined;
134
- constructor(message: string, code: ControlSafetyCode,
135
- /** The original SDK error, for logging (never re-thrown blind). */
136
- cause?: unknown | undefined);
24
+ constructor(message: string, code: ControlSafetyCode, cause?: unknown | undefined);
137
25
  }
138
26
  export type QueuePriority = 'now' | 'next' | 'later';
139
- /** A turn the user queued but has not yet submitted. `id` is a local uuid the shell uses to DEQUEUE it. */
140
27
  export interface QueuedCommand {
141
28
  id: string;
142
29
  text: string;
143
30
  priority: QueuePriority;
144
31
  }
145
32
  export interface ControlRouterOptions {
146
- /** Continue a conversation: the SAME sessionId across turns (contract/04 §5.2; types.ts:59). Omit to start
147
- * fresh — the service mints one and the shell adopts it from the first `RunReceipt.sessionId`. */
148
33
  sessionId?: string;
149
- /** Group the sub-runs of one logical job into one Task (contract/04 §5.2; types.ts:62). */
150
34
  jobId?: string;
151
- /** Scenario passthrough (default/oa/code-review/team) applied to every submitted turn. */
152
35
  scenario?: Scenario;
153
- /** Per-submit system prompt the integrator owns (types.ts:64 — stable cacheable prefix). */
154
36
  systemPrompt?: string;
155
37
  }
156
38
  export declare class ControlRouter {
157
39
  private readonly client;
158
- /** The run currently in flight — the target of steer/cancel. Null before the first submit. */
159
40
  private taskId;
160
- /** Adopted from the first RunReceipt when the caller did not pin one (service-minted continuity). */
161
41
  private sessionId;
162
42
  private readonly jobId;
163
43
  private readonly scenario;
164
44
  private readonly systemPrompt;
165
- /** The client-side queued turns (contract/04 §5.2 — no wire equivalent). */
166
45
  private readonly queue;
167
46
  private seq;
168
47
  constructor(client: ControlClientLike, opts?: ControlRouterOptions);
169
- /** The run currently in flight, if any. The shell reads this to know what steer/cancel will target. */
170
48
  activeTaskId(): string | null;
171
- /** The session token threading the conversation (service-minted after the first submit). */
172
49
  activeSessionId(): string | undefined;
173
- /**
174
- * Submit a turn as a durable async run (`runs.create` → 202 `RunReceipt`). The SAME `sessionId` continues
175
- * the conversation (the service serializes turns per session — a session-CAS conflict while a prior run
176
- * holds the claim → 409 `Conflict`, contract/04 §5.2 / openapi:173); the SAME `jobId` groups the sub-runs
177
- * into one Task in the work view. `runs.create` is a SUBMIT, so the idempotency key rides along (the SDK
178
- * auto-generates one and may safely retry on transport failure).
179
- *
180
- * Adopts the service-minted `sessionId` from the receipt when the caller did not pin one (continuity), and
181
- * latches the new run as the active steer/cancel target.
182
- */
183
50
  submit(text: string, opts?: {
184
51
  signal?: AbortSignal;
185
52
  }): Promise<RunReceipt>;
186
- /** Project the session context + the typed turn into the `@sema-ai` `TaskRequest` wire shape. Secret
187
- * discipline (types.ts:54-58): NEVER put tokens in `objective`/`systemPrompt`. */
188
53
  private buildTaskRequest;
189
- /**
190
- * Steer the RUNNING run: `runs.steer(taskId, { text, mode? })`. Hard rules this method enforces:
191
- *
192
- * - **The text is untrusted DATA — sent RAW.** The shell does NOT pre-sanitize control markers; the SERVER
193
- * fences the text (contract/04 §5.1). A text carrying a control-plane escape → 422
194
- * `SteeringInvalidContentError` → surfaced as `ControlSafetyError('invalid_content')` (SURFACE the error;
195
- * never strip-and-retry).
196
- * - **`trusted` is NOT a client field** — the server derives trust from the authenticated operator role;
197
- * this method has no way to assert it, by construction.
198
- * - **AT-MOST-ONCE — never retried.** `runs.steer` is not idempotent and not a submit, so a transport
199
- * failure propagates; the router does NOT auto-resend (a double-steer must be impossible).
200
- * - **Steer needs a RUNNING run.** A suspended/terminal run → 409 `SteeringNotRunningError` → surfaced as
201
- * `ControlSafetyError('not_running')` (resolve its gate via the hitlBridge `decide`, don't steer).
202
- * 🔴 FIX③:整个 `steering.*` 族(7 员)都归到 `ControlSafetyError` 上,含 core 5.14.0 队列化
203
- * 新出的 `queue_full` / `duplicate_input_id`,以及与 `not_running` **语义相反**的 `still_running`
204
- * (两者永不合并);表外的未来码落开集位 `steering_other`,不再裸抛。
205
- * - **`mode` drains at the TURN boundary** (FORWARD-DRAFT per-call mapping, runs.ts:49-50): `"all"` injects
206
- * all queued steers at the next turn; `"one-at-a-time"` (default) one per turn, FIFO. Steer applies at
207
- * the next turn boundary, not instantly.
208
- */
209
54
  steer(text: string, mode?: 'all' | 'one-at-a-time', opts?: {
210
55
  signal?: AbortSignal;
211
56
  }): Promise<unknown>;
212
- /**
213
- * Cancel (kill) the in-flight run: `runs.cancel(taskId)` → 202 `CancelAck` (`status:"cancelling"` or a
214
- * terminal no-op). The run then SETTLES to `failed` + `errorCode:"cancelled"` — the UI shows "cancelled",
215
- * NOT an error (the router does not synthesize that terminal; the downstream stream / `terminalToSdkResult`
216
- * does). Branching (contract/04 §9.1):
217
- *
218
- * - **409 = a LOST CAS RACE, not "suspended".** 🔴 2026-07-31 更正:这段原本写的是「409 = run 是
219
- * suspended,要改走 deny」—— 那是 **[868] 之前**的世界。服务端自 [868] 起对
220
- * suspended/needs_review 的 run **就地取消**(先 CAS 结掉挂起的 checkpoint,再 setTerminal
221
- * 释放 session claim),`cancel` 就是那种 run 的恢复把手,不再 409。今天的 409 只剩一种成因:
222
- * 挂起的那个 gate 被并发决定/过期了(server `conflict.approval_settled`)。正确处置是**重读
223
- * run 状态后重试 cancel**,而不是去 deny 一个已经不存在的审批 —— 照旧文指路只会指进空处。
224
- * Surfaced as `ControlSafetyError('cancel_lost_race')`(干净切:旧码名 `cancel_suspended` 已
225
- * 退役,本仓/壳/web/桌面均无行为消费方,只有一条注释引用,同批改)。
226
- * - **404 = non-owner / unknown.** No existence oracle (404, not 403) → `ControlSafetyError('not_found')`.
227
- *
228
- * Server-idempotent and NOT a submit, so a successful cancel is safe to repeat (a terminal run no-ops);
229
- * the router still does not auto-retry on transport failure (the shell re-invokes on the user's repeat).
230
- */
231
57
  cancel(opts?: {
232
58
  signal?: AbortSignal;
233
59
  }): Promise<CancelAck>;
234
- /** Enqueue a turn for later submission. `now` jumps the line, `next` (default) is FIFO, `later` trails.
235
- * Returns the queued row (its `id` is the dequeue handle). Nothing leaves the machine until `drainNext`. */
236
60
  enqueue(text: string, priority?: QueuePriority): QueuedCommand;
237
- /** Drop a STILL-QUEUED turn by id BEFORE it is submitted (the only stop a queued message has —
238
- * contract/04 §5.2). Returns true if it was in the queue, false if absent / already drained (mirrors CC's
239
- * `cancel_async_message` → `{cancelled:false}` "not in the queue / already dequeued"). */
240
61
  dequeue(id: string): boolean;
241
- /** A stable, priority-banded view of the queue (the shell renders this; drain order matches it). */
242
62
  pending(): readonly QueuedCommand[];
243
- /**
244
- * Drain the highest-priority queued turn: dequeue it and `submit` it as its own durable run (same session
245
- * → continues the conversation; same jobId → one Task). Returns the `RunReceipt`, or null when the queue is
246
- * empty. The session serializes turns, so the caller drains one at a time (submit, await the run, drain the
247
- * next); submitting while a prior run holds the session claim surfaces the SDK's 409 `ConflictError` from
248
- * `submit` — the shell waits and re-drains (contract/04 §5.2; openapi:173).
249
- */
250
63
  drainNext(opts?: {
251
64
  signal?: AbortSignal;
252
65
  }): Promise<RunReceipt | null>;
253
66
  private nextId;
254
67
  }
255
- /** design/161 批 A 起导出:错误判型单源 —— 包内新读面(backgroundView 等)一律吃这一口,不再各自
256
- * 手摸 `(e as any).status`。 */
257
68
  export interface ErrCodes {
258
69
  code?: string | undefined;
259
70
  name?: string | undefined;
260
71
  status?: number | undefined;
261
72
  }
262
- /**
263
- * Read a normalized error code/status off any SDK error shape variant (errorCode / code / name / status).
264
- * REF-CC-135(TYPESHAPE-15,P3 wave1 卡C-argv):判型单源此前返回 3 个裸 unknown(B2/B4 违规——调用方
265
- * `code === 404`(status 才是数字位)这类拼写型 bug 能编译期全绿恒 false)。窄化成具名 `ErrCodes`,
266
- * 非匹配类型一律降到 undefined(而不是把垃圾值原样放行)。
267
- *
268
- * 🔴 [2393] sweep-F6(2026-08-03 全窗复审)**这不只是类型收窄,是运行期丢值**(裁定:保留行为,
269
- * 但把它记成可核的承诺):旧实现 `return { code: o.errorCode, name: o.name, status: o.status ?? o.statusCode }`
270
- * 是原样透传。今天,包外消费者若拿到的错误对象上 `status` 是数字**串**(某些传输层/代理把 status
271
- * 序列化成字符串)、或 `errorCode` 是数值码,读到的一律是 `undefined`。
272
- * 方向对(「拿到一个不好用的值」→「诚实地什么都没有」;下游 `code === 404` 那类拼写型 bug 也因此
273
- * 编译期就红),但它是**公面行为变更**:本函数是 npm 导出的判型单源,三端各自的错误对象形需要复核。
274
- * ⇒ 已进 `docs/refactor/README.md` 的提货单/BREAKING 清单(此前只列四条 wire BREAKING,签名级与
275
- * 行为级的这几条靠人工列表兜底,而列表没列)。
276
- * 判据:pure 门 B5 段那组钉现在也钉「脏形一律降 undefined、绝不悄悄回落成 0/空串」——
277
- * 谁要把某一种脏形改回透传,必须先在那里显形。
278
- */
279
73
  export declare function errCodes(e: unknown): ErrCodes;
@@ -3,27 +3,21 @@ import { uuid } from './adapter/types.js';
3
3
  export class ControlSafetyError extends Error {
4
4
  code;
5
5
  cause;
6
- constructor(message, code,
7
- /** The original SDK error, for logging (never re-thrown blind). */
8
- cause) {
6
+ constructor(message, code, cause) {
9
7
  super(message);
10
8
  this.code = code;
11
9
  this.cause = cause;
12
10
  this.name = 'ControlSafetyError';
13
11
  }
14
12
  }
15
- /** Band rank for stable priority ordering: lower drains first. */
16
13
  const BAND_RANK = { now: 0, next: 1, later: 2 };
17
14
  export class ControlRouter {
18
15
  client;
19
- /** The run currently in flight — the target of steer/cancel. Null before the first submit. */
20
16
  taskId = null;
21
- /** Adopted from the first RunReceipt when the caller did not pin one (service-minted continuity). */
22
17
  sessionId;
23
18
  jobId;
24
19
  scenario;
25
20
  systemPrompt;
26
- /** The client-side queued turns (contract/04 §5.2 — no wire equivalent). */
27
21
  queue = [];
28
22
  seq = 0;
29
23
  constructor(client, opts = {}) {
@@ -33,40 +27,21 @@ export class ControlRouter {
33
27
  this.scenario = opts.scenario;
34
28
  this.systemPrompt = opts.systemPrompt;
35
29
  }
36
- /** The run currently in flight, if any. The shell reads this to know what steer/cancel will target. */
37
30
  activeTaskId() {
38
31
  return this.taskId;
39
32
  }
40
- /** The session token threading the conversation (service-minted after the first submit). */
41
33
  activeSessionId() {
42
34
  return this.sessionId;
43
35
  }
44
- // ── §1. submit — a turn → its own durable run (contract/04 §5.2; 08 IH-2, catalog L74) ───────────────────
45
- /**
46
- * Submit a turn as a durable async run (`runs.create` → 202 `RunReceipt`). The SAME `sessionId` continues
47
- * the conversation (the service serializes turns per session — a session-CAS conflict while a prior run
48
- * holds the claim → 409 `Conflict`, contract/04 §5.2 / openapi:173); the SAME `jobId` groups the sub-runs
49
- * into one Task in the work view. `runs.create` is a SUBMIT, so the idempotency key rides along (the SDK
50
- * auto-generates one and may safely retry on transport failure).
51
- *
52
- * Adopts the service-minted `sessionId` from the receipt when the caller did not pin one (continuity), and
53
- * latches the new run as the active steer/cancel target.
54
- */
55
36
  async submit(text, opts) {
56
37
  const req = this.buildTaskRequest(text);
57
38
  const receipt = await this.client.runs.create(req, opts?.signal !== undefined ? { signal: opts.signal } : undefined);
58
- // Adopt service-minted continuity + latch the in-flight run.
59
39
  if (this.sessionId === undefined)
60
40
  this.sessionId = receipt.sessionId;
61
41
  this.taskId = receipt.taskId;
62
42
  return receipt;
63
43
  }
64
- /** Project the session context + the typed turn into the `@sema-ai` `TaskRequest` wire shape. Secret
65
- * discipline (types.ts:54-58): NEVER put tokens in `objective`/`systemPrompt`. */
66
44
  buildTaskRequest(text) {
67
- // 空内容守卫(2026-07-16 唤醒 400 批,同病同修):SDK/控制面递来的空/全空白 user_message 绝不作为
68
- // 空 objective 上 wire——引擎会把空 user 消息写进会话持久历史(provider 400 + session 毒化)。
69
- // 与 CC createUserMessage 的 NO_CONTENT_MESSAGE 同语义占位。
70
45
  const req = { objective: text.trim().length > 0 ? text : '(no content)' };
71
46
  if (this.sessionId !== undefined)
72
47
  req.sessionId = this.sessionId;
@@ -78,68 +53,23 @@ export class ControlRouter {
78
53
  req.systemPrompt = this.systemPrompt;
79
54
  return req;
80
55
  }
81
- // ── §2. steer — inject mid-flight direction (contract/04 §5.1; 08 IH-7, catalog L81) ─────────────────────
82
- /**
83
- * Steer the RUNNING run: `runs.steer(taskId, { text, mode? })`. Hard rules this method enforces:
84
- *
85
- * - **The text is untrusted DATA — sent RAW.** The shell does NOT pre-sanitize control markers; the SERVER
86
- * fences the text (contract/04 §5.1). A text carrying a control-plane escape → 422
87
- * `SteeringInvalidContentError` → surfaced as `ControlSafetyError('invalid_content')` (SURFACE the error;
88
- * never strip-and-retry).
89
- * - **`trusted` is NOT a client field** — the server derives trust from the authenticated operator role;
90
- * this method has no way to assert it, by construction.
91
- * - **AT-MOST-ONCE — never retried.** `runs.steer` is not idempotent and not a submit, so a transport
92
- * failure propagates; the router does NOT auto-resend (a double-steer must be impossible).
93
- * - **Steer needs a RUNNING run.** A suspended/terminal run → 409 `SteeringNotRunningError` → surfaced as
94
- * `ControlSafetyError('not_running')` (resolve its gate via the hitlBridge `decide`, don't steer).
95
- * 🔴 FIX③:整个 `steering.*` 族(7 员)都归到 `ControlSafetyError` 上,含 core 5.14.0 队列化
96
- * 新出的 `queue_full` / `duplicate_input_id`,以及与 `not_running` **语义相反**的 `still_running`
97
- * (两者永不合并);表外的未来码落开集位 `steering_other`,不再裸抛。
98
- * - **`mode` drains at the TURN boundary** (FORWARD-DRAFT per-call mapping, runs.ts:49-50): `"all"` injects
99
- * all queued steers at the next turn; `"one-at-a-time"` (default) one per turn, FIFO. Steer applies at
100
- * the next turn boundary, not instantly.
101
- */
102
56
  async steer(text, mode, opts) {
103
57
  if (this.taskId === null) {
104
58
  throw new ControlSafetyError('no run in flight to steer — submit a turn first', 'not_running');
105
59
  }
106
- // Raw text, no pre-sanitize (the server fences). `mode` omitted → server default one-at-a-time.
107
60
  const body = mode !== undefined ? { text, mode } : { text };
108
61
  try {
109
62
  return await this.client.runs.steer(this.taskId, body, opts?.signal !== undefined ? { signal: opts.signal } : undefined);
110
63
  }
111
64
  catch (e) {
112
- // FIX③:整族逐码分派(表见文件底部)。前缀在场即归族 —— 未来新码落 `steering_other`,
113
- // 绝不再裸抛给壳(裸抛 = 壳的 `instanceof ControlSafetyError` 分支整条漏在外面)。
114
65
  const verdict = steeringVerdict(e);
115
66
  if (verdict !== undefined) {
116
67
  const wireCode = errCodes(e).code ?? errCodes(e).name ?? 'steering.<unknown>';
117
68
  throw new ControlSafetyError(`${wireCode} — ${STEERING_ADVICE.get(verdict) ?? 'steering refused'}`, verdict, e);
118
69
  }
119
- // Any other error (auth/transport): NOT retried (steer is at-most-once) — propagate to the shell.
120
70
  throw e;
121
71
  }
122
72
  }
123
- // ── §3. cancel — hard-stop / kill the run (contract/04 §5.3; 08 IH-8, catalog L84) ───────────────────────
124
- /**
125
- * Cancel (kill) the in-flight run: `runs.cancel(taskId)` → 202 `CancelAck` (`status:"cancelling"` or a
126
- * terminal no-op). The run then SETTLES to `failed` + `errorCode:"cancelled"` — the UI shows "cancelled",
127
- * NOT an error (the router does not synthesize that terminal; the downstream stream / `terminalToSdkResult`
128
- * does). Branching (contract/04 §9.1):
129
- *
130
- * - **409 = a LOST CAS RACE, not "suspended".** 🔴 2026-07-31 更正:这段原本写的是「409 = run 是
131
- * suspended,要改走 deny」—— 那是 **[868] 之前**的世界。服务端自 [868] 起对
132
- * suspended/needs_review 的 run **就地取消**(先 CAS 结掉挂起的 checkpoint,再 setTerminal
133
- * 释放 session claim),`cancel` 就是那种 run 的恢复把手,不再 409。今天的 409 只剩一种成因:
134
- * 挂起的那个 gate 被并发决定/过期了(server `conflict.approval_settled`)。正确处置是**重读
135
- * run 状态后重试 cancel**,而不是去 deny 一个已经不存在的审批 —— 照旧文指路只会指进空处。
136
- * Surfaced as `ControlSafetyError('cancel_lost_race')`(干净切:旧码名 `cancel_suspended` 已
137
- * 退役,本仓/壳/web/桌面均无行为消费方,只有一条注释引用,同批改)。
138
- * - **404 = non-owner / unknown.** No existence oracle (404, not 403) → `ControlSafetyError('not_found')`.
139
- *
140
- * Server-idempotent and NOT a submit, so a successful cancel is safe to repeat (a terminal run no-ops);
141
- * the router still does not auto-retry on transport failure (the shell re-invokes on the user's repeat).
142
- */
143
73
  async cancel(opts) {
144
74
  if (this.taskId === null) {
145
75
  throw new ControlSafetyError('no run in flight to cancel', 'not_found');
@@ -148,7 +78,6 @@ export class ControlRouter {
148
78
  return await this.client.runs.cancel(this.taskId, opts?.signal !== undefined ? { signal: opts.signal } : undefined);
149
79
  }
150
80
  catch (e) {
151
- // 0.73.1:409 先按机器码分家(见 wireRefusalCopy.ts 头注);码缺席 / 认不出 ⇒ 落到下面那条旧臂,行为逐字同旧。
152
81
  if (cancelConflictFromError(e)?.kind === 'run_not_running') {
153
82
  throw new ControlSafetyError(`runs.cancel 409 conflict.run_not_running — ${cancelConflictContent({ kind: 'run_not_running' })}`, 'cancel_run_not_running', e);
154
83
  }
@@ -162,21 +91,11 @@ export class ControlRouter {
162
91
  throw e;
163
92
  }
164
93
  }
165
- // ── §4. queued commands — client-side priority + drop (contract/04 §5.2, catalog L82) ────────────────────
166
- //
167
- // The SDK has no per-message priority and no drop-queued verb. The router holds the queue locally: enqueue
168
- // by priority band, dequeue a still-queued turn by its local id, and drain by submitting each as its own
169
- // run under the same session. A submitted turn LEAVES the queue — its only after-submit stop is `cancel`.
170
- /** Enqueue a turn for later submission. `now` jumps the line, `next` (default) is FIFO, `later` trails.
171
- * Returns the queued row (its `id` is the dequeue handle). Nothing leaves the machine until `drainNext`. */
172
94
  enqueue(text, priority = 'next') {
173
95
  const cmd = { id: this.nextId(), text, priority };
174
96
  this.queue.push(cmd);
175
97
  return cmd;
176
98
  }
177
- /** Drop a STILL-QUEUED turn by id BEFORE it is submitted (the only stop a queued message has —
178
- * contract/04 §5.2). Returns true if it was in the queue, false if absent / already drained (mirrors CC's
179
- * `cancel_async_message` → `{cancelled:false}` "not in the queue / already dequeued"). */
180
99
  dequeue(id) {
181
100
  const i = this.queue.findIndex((c) => c.id === id);
182
101
  if (i < 0)
@@ -184,17 +103,9 @@ export class ControlRouter {
184
103
  this.queue.splice(i, 1);
185
104
  return true;
186
105
  }
187
- /** A stable, priority-banded view of the queue (the shell renders this; drain order matches it). */
188
106
  pending() {
189
107
  return [...this.queue].sort((a, b) => BAND_RANK[a.priority] - BAND_RANK[b.priority]);
190
108
  }
191
- /**
192
- * Drain the highest-priority queued turn: dequeue it and `submit` it as its own durable run (same session
193
- * → continues the conversation; same jobId → one Task). Returns the `RunReceipt`, or null when the queue is
194
- * empty. The session serializes turns, so the caller drains one at a time (submit, await the run, drain the
195
- * next); submitting while a prior run holds the session claim surfaces the SDK's 409 `ConflictError` from
196
- * `submit` — the shell waits and re-drains (contract/04 §5.2; openapi:173).
197
- */
198
109
  async drainNext(opts) {
199
110
  const ordered = this.pending();
200
111
  const head = ordered[0];
@@ -208,38 +119,16 @@ export class ControlRouter {
208
119
  return `q-${this.seq}-${uuid()}`;
209
120
  }
210
121
  }
211
- /**
212
- * Read a normalized error code/status off any SDK error shape variant (errorCode / code / name / status).
213
- * REF-CC-135(TYPESHAPE-15,P3 wave1 卡C-argv):判型单源此前返回 3 个裸 unknown(B2/B4 违规——调用方
214
- * `code === 404`(status 才是数字位)这类拼写型 bug 能编译期全绿恒 false)。窄化成具名 `ErrCodes`,
215
- * 非匹配类型一律降到 undefined(而不是把垃圾值原样放行)。
216
- *
217
- * 🔴 [2393] sweep-F6(2026-08-03 全窗复审)**这不只是类型收窄,是运行期丢值**(裁定:保留行为,
218
- * 但把它记成可核的承诺):旧实现 `return { code: o.errorCode, name: o.name, status: o.status ?? o.statusCode }`
219
- * 是原样透传。今天,包外消费者若拿到的错误对象上 `status` 是数字**串**(某些传输层/代理把 status
220
- * 序列化成字符串)、或 `errorCode` 是数值码,读到的一律是 `undefined`。
221
- * 方向对(「拿到一个不好用的值」→「诚实地什么都没有」;下游 `code === 404` 那类拼写型 bug 也因此
222
- * 编译期就红),但它是**公面行为变更**:本函数是 npm 导出的判型单源,三端各自的错误对象形需要复核。
223
- * ⇒ 已进 `docs/refactor/README.md` 的提货单/BREAKING 清单(此前只列四条 wire BREAKING,签名级与
224
- * 行为级的这几条靠人工列表兜底,而列表没列)。
225
- * 判据:pure 门 B5 段那组钉现在也钉「脏形一律降 undefined、绝不悄悄回落成 0/空串」——
226
- * 谁要把某一种脏形改回透传,必须先在那里显形。
227
- */
228
122
  export function errCodes(e) {
229
123
  if (!e || typeof e !== 'object')
230
124
  return {};
231
125
  const o = e;
232
- // [1912] errorCode 恒在(server ≥1.302 canonical)——`?? o.code` 老兜底已清;status 双键保留(HTTP 层形非 wire 键)。
233
126
  const code = typeof o.errorCode === 'string' ? o.errorCode : undefined;
234
127
  const name = typeof o.name === 'string' ? o.name : undefined;
235
128
  const rawStatus = o.status ?? o.statusCode;
236
129
  const status = typeof rawStatus === 'number' ? rawStatus : undefined;
237
130
  return { code, name, status };
238
131
  }
239
- // ── steering 错误族的**逐码表**(FIX③,server 7.4.0 dist 亲扫 + SDK 6.3.0 errors.d.ts 对表)────
240
- //
241
- // 🔴 用 `Map` 不是对象字面量:键来自 wire 的 `errorCode` 字符串,对象字面量上 `map['__proto__']`
242
- // 会摸到 Object.prototype(adapt/arms.ts 头注登记的同一条纪律)。
243
132
  const STEERING_CODE_TO_SAFETY = new Map([
244
133
  ['steering.not_running', 'not_running'],
245
134
  ['steering.invalid_content', 'invalid_content'],
@@ -248,14 +137,8 @@ const STEERING_CODE_TO_SAFETY = new Map([
248
137
  ['steering.ambiguous_target', 'ambiguous_target'],
249
138
  ['steering.ambiguous_label', 'ambiguous_target'],
250
139
  ['steering.still_running', 'still_running'],
251
- // [7226] 包侧缺口 ①(0.68.1):server 契约 (2) 表第 8 码(422)。SDK 8.8.0 **没有**专属子类
252
- // (`errors.d.ts` 的 `Steering*Error` 只有六只)⇒ 只能按 `errorCode` 认;认不出时它会落开集位
253
- // `steering_other`,而那一位的判词是「别猜它的意思」—— 恰好把一条「改内容重试即可」的拒绝
254
- // 说成没救。所以码表必须点名它,不能靠前缀兜底。
255
140
  ['steering.blocked_by_hook', 'blocked_by_hook'],
256
141
  ]);
257
- /** SDK 的 typed 子类名兜底(错误对象被传输层剥掉 `errorCode` 时仍认得族;`SteeringError` 基类本身
258
- * = 「是 steering 族但没有专属子类」⇒ 落开集臂)。 */
259
142
  const STEERING_NAME_TO_SAFETY = new Map([
260
143
  ['SteeringNotRunningError', 'not_running'],
261
144
  ['SteeringInvalidContentError', 'invalid_content'],
@@ -263,7 +146,6 @@ const STEERING_NAME_TO_SAFETY = new Map([
263
146
  ['SteeringStillRunningError', 'still_running'],
264
147
  ['SteeringError', 'steering_other'],
265
148
  ]);
266
- /** 每个判别位的处置指路(壳把它原样打给用户/日志 —— 判词必须说得出「现在该做什么」)。 */
267
149
  const STEERING_ADVICE = new Map([
268
150
  ['not_running', 'the run is suspended/terminal/on another replica — resolve its gate via decide, do not steer'],
269
151
  ['invalid_content', 'the steer text carried a control-plane escape; surface it, do not strip-and-retry'],
@@ -274,29 +156,19 @@ const STEERING_ADVICE = new Map([
274
156
  ['blocked_by_hook', "this deployment's userPromptSubmit gate refused the input (block, timeout and crash all report this one code, fail-closed) — the input was NOT accepted: no human_input frame, the inputId is not on the ledger, so editing the text and sending again is a normal retry, not a duplicate"],
275
157
  ['steering_other', 'an unrecognized steering.* refusal (open set) — the steer did NOT land; log the errorCode verbatim, do not guess its meaning'],
276
158
  ]);
277
- /**
278
- * 把一个 steer 抛出的错误判成 steering 族的哪一位。不是 steering 族 ⇒ `undefined`(调用方原样抛,
279
- * 路由器绝不越界吞 auth/transport 的错)。
280
- */
281
159
  function steeringVerdict(e) {
282
160
  const { code, name } = errCodes(e);
283
161
  if (typeof code === 'string' && code.startsWith('steering.')) {
284
- // 前缀在场即归族:表里没有的**未来**码落开集臂,而不是漏出去(SDK 6.3.0 的同款前缀分派)。
285
162
  return STEERING_CODE_TO_SAFETY.get(code) ?? 'steering_other';
286
163
  }
287
164
  if (typeof name === 'string')
288
165
  return STEERING_NAME_TO_SAFETY.get(name);
289
166
  return undefined;
290
167
  }
291
- /** A 409 on `cancel` = the pending gate was decided/expired concurrently (lost CAS race; server
292
- * `conflict.approval_settled`). 🔴 它**不再**表示「run 是 suspended」——[868] 起 suspended/needs_review
293
- * 的 run 由 cancel 就地终态化。
294
- * The SDK raises a generic `ConflictError` (status 409) for this case — there is no dedicated subclass. */
295
168
  function isCancelSuspendedConflict(e) {
296
169
  const { name, status } = errCodes(e);
297
170
  return name === 'ConflictError' || status === 409;
298
171
  }
299
- /** 404 — non-owner / unknown run; the SDK raises `NotFoundError` (no existence oracle, contract/04 §9.1). */
300
172
  function isNotFound(e) {
301
173
  const { name, status } = errCodes(e);
302
174
  return name === 'NotFoundError' || status === 404;