@sema-agent/client-core 0.77.1 → 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 +13 -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 +0 -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 +6 -498
  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 +6 -67
  346. package/dist/subagent/engineTaskHandleWire.js +0 -126
  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 +30 -1
  382. package/package.json +1 -1
@@ -1,89 +1,9 @@
1
- /**
2
- * ⇄ B6 批搬迁(2026-07-27,设计稿 §3 B6):cli `src/sema/workflowClient.ts` 整搬(依赖面 = SDK + env,
3
- * §3 表登记 472 行)。
4
- *
5
- * 🔴 搬迁四处差分(端资产上移 / 单一构造点,行为面逐条记账):
6
- * ① `new AgentClient({…})` 直造 → `makeEngineWireClient()`(§8-2 定谳的唯一构造点;凭证过
7
- * `resolveWireAuth` 三态)。**`maxRetries: 2` 显式传** —— 工厂缺省是 0(raw fetch 单发语义),
8
- * 而这里原本吃的是 SDK 缺省 2;不显式传就等于**偷偷改了这条观测环路的重试次数**。
9
- * 唯一残余差分:`authToken` 为**空串**时,原版原样交给 SDK,收编后走三态(loopback ⇒ 零
10
- * Authorization 头 / 非 loopback ⇒ 'anon')—— 与另外 11 处构造点同一处置,记在 §8-2。
11
- * 工厂 fail-soft 返回 null(SDK 拒绝构造)⇒ 本源恒 degraded、`snapshot()` 恒 null,宿主回落
12
- * mock/空态 —— 与「501/404/空列表」同一条不抛的路。
13
- * ② `process.env.SEMA_DEBUG` → `engineWireDebugEnabled()`;`console.error` → `hostLog('debug', …)`
14
- * (本包零 `process`、零 console —— portability 门盯着)。
15
- * ③ 投影产物的类型契约(`WorkflowRunState` 族)改 import 本包 `workflowMonitor.ts`(同批搬入),
16
- * 不再从 TUI 的 `overrides/workflow-detail-dialog.js` 反向依赖渲染件。
17
- * ④ `export default createLiveWorkflowSource` **不带过来**:本包是具名导出面(index 做 `export *`,
18
- * default 不在其中)。壳侧那一行 default import 若存在,shim 里改具名。
19
- *
20
- * ── 以下为原文件的领域说明(逐字保留)────────────────────────────────────────────────────────
21
- *
22
- * workflowClient — MF-W LIVE WIRE source (the workflow-monitor TWIN of fleetClient.ts).
23
- *
24
- * WHY THIS FILE EXISTS
25
- * --------------------
26
- * mock/workflow/workflowRun.ts synthesizes ONE representative WorkflowRunState from a scripted run (offline/
27
- * demo). This file is its LIVE TWIN: it constructs the @sema-ai/sdk `AgentClient`, consumes the §workflow
28
- * observability surface shipped in @sema-ai/sdk 0.0.40 (`client.workflows.list/get/stream`, resources/
29
- * workflows.ts — GET /v1/workflows*, the S8 self-orchestration-observability endpoints), and PROJECTS the
30
- * SDK's `WorkflowRun` (phases / agents / stats) to the SAME `WorkflowRunState` the reconstructed monitor
31
- * (src/sema/overrides/workflow-detail-dialog.tsx) already consumes. ZERO renderer change — exactly the
32
- * fleetClient.ts pattern (a projector, not a port).
33
- *
34
- * SDK CONTRACT (resources/workflows.ts + types.ts):
35
- * - `list({status?,limit?})` → `{ workflows: WorkflowRunSummary[] }` (OWNER-scoped: only the caller's runs).
36
- * - `get(id)` → full `WorkflowRun` (phases: unknown[] structured {title,status,done,total};
37
- * agents: WorkflowAgentRow[] with activity[].arg; stats.tokens own+nested).
38
- * - `stream(id)` → SSE of `WorkflowStreamEvent` (first frame `meta`, then core WorkflowEvent
39
- * frames). REPLICA-LOCAL + in-process, NOT resumable — a drop is a FULL restart
40
- * (re-`get()` for the snapshot), never a resume.
41
- *
42
- * 🔴 GRACEFUL DEGRADE (the load-bearing half — see the mount seam's verification-debt note): the LIVE
43
- * endpoints are gated behind the server's S8 (self-orchestration-observability) flag. With S8 OFF the
44
- * routes answer **501** (typed APIError) BEFORE any frame; a non-owner / absent run answers **404**; an
45
- * owner with no runs yields an **empty** list. ALL THREE are EXPECTED, NOT crashes: this source records
46
- * them (status().degraded/code) and keeps `snapshot()` null so the host can fall back to the mock/empty
47
- * state. A raw connection error (server down) is treated the same way — the stream/loop just backs off and
48
- * retries; the source NEVER throws into the host.
49
- *
50
- * 🔴 THE SDK PRODUCES FRAMES, IT DOES NOT MAINTAIN STATE. We take the AUTHORITATIVE snapshot from `get()` and
51
- * treat `stream()` as a "something changed" TICKER: on each frame we re-`get()` the owner-scoped detail
52
- * (throttled) and re-project, rather than reduce the permissive/core-internal WorkflowEvent shapes on the
53
- * client. On stream drop we re-`get()` for a fresh snapshot (not resumable) with a small backoff.
54
- *
55
- * DROP-IN SHAPE: `snapshot()` returns the latest projected `WorkflowRunState | null` (null until the first
56
- * successful `get()`, or while degraded) — the host polls it on an interval and swaps the mock for the live
57
- * state once one resolves. `dispose()` aborts the stream + stops the background loop on host unmount.
58
- */
59
1
  import { APIError } from '@sema-agent/sdk';
60
2
  import { abortableSleep } from './abortableSleep.js';
61
3
  import { engineSessionParamSpread } from './engineSessionParam.js';
62
4
  import { makeEngineWireClient } from './engineWireSdk.js';
63
5
  import { engineWireDebugEnabled } from './engineWireTarget.js';
64
6
  import { hostLog } from './host.js';
65
- // ── SDK WorkflowRun → monitor WorkflowRunState projectors ────────────────────────────────────────────────
66
- // The SDK shapes (types.ts) are PERMISSIVE (open index sigs). The monitor's WorkflowRunState/Phase/Agent
67
- // (workflowMonitor.ts) is the 187-faithful consumed set. We read the known fields, coerce
68
- // the vocabularies, and fill the shell-local render defaults the wire does not carry — same discipline as
69
- // projectTasks/projectWorkflows in fleet/fleetProjection.ts.
70
- /**
71
- * ── `parked` 在这一族投影里的纪律(0.63.1;G-20)────────────────────────────────────────────
72
- * 「停在审批门上」是一个**说得出口的状态词**,不是一个未知的未来值:那条腿在有人做决定之前
73
- * **永远不会**自己往前走一步,而 `running` 承诺的恰恰是「等着就好」。⇒ 下面四处窄读一律给它
74
- * 一条**自己的臂**,开集兜底(未知未来值 → 活跃)一个字节都不动。
75
- *
76
- * 三级词表今天各自的真实供给(engine core 7.10.0,亲核):
77
- * · **agent 行** —— `WorkflowItemStatus` 含 `parked`(#642),`deriveAgentDisplayStatus` 直接产
78
- * `"parked"`(`AgentDisplayStatus` 六词)⇒ 这是**今天就会到**的读数。
79
- * · **run 级** —— 仍闭在 running|completed|failed;一条腿 park ⇒ 整只 run 按
80
- * `WorkflowAgentParkedError` 收在 `failed` ⇒ `parked` 今天到不了这一位,那条臂是**前向预挂**。
81
- * · **phase 级** —— 上游明说「a phase or group never parks」,同为前向预挂;本包另从桶里的腿
82
- * **推**出这一格(见 `projectPhases`)。
83
- */
84
- /** run status → the monitor's run-level vocabulary. SDK: queued|running|completed|failed|(open). The monitor
85
- * run status is running|done|failed|stopped|paused|parked — there is no run-level 'queued', so a queued run
86
- * reads as 'running' (the header shows the raw status text anyway; the box treats non-done/failed as active). */
87
7
  function coerceRunStatus(s) {
88
8
  switch (s) {
89
9
  case 'completed':
@@ -93,14 +13,13 @@ function coerceRunStatus(s) {
93
13
  case 'running':
94
14
  return 'running';
95
15
  case 'parked':
96
- return 'parked'; // 前向预挂(见上方族头注):词真到了就原样透出,绝不折成「在跑」
16
+ return 'parked';
97
17
  case 'queued':
98
- return 'running'; // 无 run 级 queued 词,排队按活跃渲(正向证据:引擎说它在队里)
18
+ return 'running';
99
19
  default:
100
- return 'unknown'; // 0.72.12 CC-51(#64 A-28):认不出的词 ⇒ unknown,不渲成「在跑」;壳渲原串 + 未知标
20
+ return 'unknown';
101
21
  }
102
22
  }
103
- /** run 级状态的证据式收口:认得的词照旧;`unknown` 时腿上有活跃证据(start / progress / queued)⇒ `running`。 */
104
23
  function runStatusWithLegEvidence(coerced, agents) {
105
24
  if (coerced !== 'unknown')
106
25
  return coerced;
@@ -109,7 +28,6 @@ function runStatusWithLegEvidence(coerced, agents) {
109
28
  return 'running';
110
29
  return 'unknown';
111
30
  }
112
- /** detail phase status (service projects {title,status,done,total}) → the monitor's phase vocabulary. */
113
31
  function coercePhaseStatus(s) {
114
32
  switch (s) {
115
33
  case 'done':
@@ -122,16 +40,13 @@ function coercePhaseStatus(s) {
122
40
  case 'pending':
123
41
  return 'not-started';
124
42
  case 'parked':
125
- return 'parked'; // 前向预挂,同 coerceRunStatus
43
+ return 'parked';
126
44
  case 'running':
127
45
  return 'running';
128
46
  default:
129
- return 'unknown'; // CC-51:同 coerceRunStatus
47
+ return 'unknown';
130
48
  }
131
49
  }
132
- /** SDK WorkflowAgentRow.status ("the input vocab the display derivation reads", types.ts:352) → the monitor's
133
- * AgentState input set (start|progress|queued|done|error|inactive — the WPe INPUT vocabulary the monitor
134
- * derives DisplayStatus from). We pass the atlas vocab through and tolerate service display-synonyms. */
135
50
  function coerceAgentState(s) {
136
51
  switch (s) {
137
52
  case 'start':
@@ -141,7 +56,6 @@ function coerceAgentState(s) {
141
56
  case 'error':
142
57
  case 'inactive':
143
58
  return s;
144
- // service display-vocab synonyms (should the wire emit them) → the monitor's input state.
145
59
  case 'running':
146
60
  case 'active':
147
61
  return 'progress';
@@ -149,28 +63,14 @@ function coerceAgentState(s) {
149
63
  return 'done';
150
64
  case 'failed':
151
65
  return 'error';
152
- // service detail `displayStatus` (core deriveAgentDisplayStatus): `interrupted` = a non-terminal agent
153
- // under a terminated run → the monitor's `inactive` input (WPe lands it on 'interrupted' display via
154
- // !workflowActive — the run IS terminal whenever core emits this).
155
66
  case 'interrupted':
156
67
  return 'inactive';
157
- // 🔴 core 7.10.0 #642:这条腿耐久挂在一张审批卡上(行上记着 checkpoint token)。**今天就会到**
158
- // 的读数(raw `status` 与 `displayStatus` 两条腿都会带),原词透出——折进 `progress` 就是把
159
- // 「要人去批」渲成「等它跑完」。
160
68
  case 'parked':
161
69
  return 'parked';
162
70
  default:
163
- return 'progress'; // unknown-future live status → render as an active agent (open-set fallback)
71
+ return 'progress';
164
72
  }
165
73
  }
166
- /** Project the bounded activity beats (WorkflowActivityBeat, start/end PAIRS) → the monitor's per-call
167
- * WorkflowToolCall[]. The 'start' beat carries the SHORT secret-scrubbed primary-arg summary (types.ts:339);
168
- * we fold each tool CALL (keyed by toolCallId) to one row {name, summary?}, keeping the first non-empty arg
169
- * as the summary. Beats without a toolName are dropped (heartbeat/partial). Order preserved. */
170
- /** clay ⑤ 案(2026-07-22 截图定谳):beat.arg 契约上是 SHORT 摘要,但 StructuredOutput 等工具的
171
- * 主参数=整段多行内容(server 侧 scrub 不折行)——Activity 行渲染用 truncateToWidth 只截宽度
172
- * 不清换行,首个换行之后的行顶格渲出面板(样式逃框)。数据层单点单行化:取首行,有后续行缀 …;
173
- * 两个消费点(Activity 行 + lastToolSummary)一并被护。 */
174
74
  function oneLineSummary(s) {
175
75
  const nl = s.search(/\r?\n/);
176
76
  if (nl < 0)
@@ -200,27 +100,16 @@ function projectActivity(beats) {
200
100
  }
201
101
  return order.map(k => byCall.get(k)).filter((c) => !!c);
202
102
  }
203
- /** one WorkflowAgentRow → the monitor's WorkflowAgent (+ a private `_phase` carrier for phase bucketing). */
204
103
  function projectAgent(row, index) {
205
- // WorkflowAgentRow carries no TYPED id — read a stable id from the permissive fields, else index-derive.
206
104
  const rec = row;
207
105
  const id = String(rec.id ?? rec.agentId ?? `agent-${index}`);
208
106
  const agentId = typeof rec.agentId === 'string' && rec.agentId ? rec.agentId : id;
209
- // Prefer the service detail's `displayStatus` (core's shared deriveAgentDisplayStatus:
210
- // queued|running|done|failed|interrupted) over the RAW record `status` (running|completed|failed): the raw
211
- // vocabulary carries no queued/interrupted arm — a queued agent's record status is literally 'running', so
212
- // coercing `row.status` alone rendered every queued agent as "Running" (the [840] parity gap).
213
- // 🔴 空串 = 缺席(0.63.1,G-20 同形存量⑤):`??` 只挡 null/undefined,一个空串的 `displayStatus`
214
- // 会把 raw `status` 整个静默吃掉(`'' ?? row.status` === `''`)—— 那条腿真正的状态词连回落
215
- // 这条路都走不到。与 `workflow.ts` 两条链路同尺:空串不是读数。
216
107
  const displayStatus = typeof rec.displayStatus === 'string' && rec.displayStatus.length > 0 ? rec.displayStatus : undefined;
217
108
  const state = coerceAgentState(displayStatus ?? row.status);
218
109
  const activity = projectActivity(row.activity);
219
110
  const last = activity.length ? activity[activity.length - 1] : undefined;
220
111
  const label = typeof row.label === 'string' && row.label.trim() ? row.label.trim() : id || 'agent';
221
112
  const agent = { id, agentId, label, state };
222
- // #242 批 1:callKey 是 SSE 侧 activity 台账的**主键**(agent_activity 帧必带),此前投影把它丢了
223
- // ⇒ 合并层只剩 label 一把钥匙,重名 agent 只能整组跳过。带出来之后重名也能精确归属。
224
113
  if (typeof row.callKey === 'string' && row.callKey)
225
114
  agent.callKey = row.callKey;
226
115
  if (typeof row.model === 'string')
@@ -240,12 +129,6 @@ function projectAgent(row, index) {
240
129
  agent.promptPreview = row.prompt;
241
130
  if (typeof row.output === 'string')
242
131
  agent.resultPreview = row.output;
243
- // WPe (agentDisplayStatus) derives queued-vs-running from queuedAt/startedAt on the active path. The service
244
- // detail ALWAYS sends `queuedAt` (MF-W 1.150: enqueue time) and sends `startedAt` only once the agent acquired
245
- // a concurrency slot — so PASS BOTH THROUGH unconditionally and WPe derives faithfully (queuedAt set +
246
- // startedAt absent → 'queued'; both set → 'running'). The old projection dropped queuedAt unless the coerced
247
- // state was literally 'queued' (which the raw record vocabulary never produces) — every queued agent lost its
248
- // timestamps and rendered 'running'. Synthesize queuedAt only for a wire that says 'queued' without one.
249
132
  const startedAt = typeof rec.startedAt === 'number' ? rec.startedAt : undefined;
250
133
  const queuedAt = typeof rec.queuedAt === 'number' ? rec.queuedAt : undefined;
251
134
  const durationMs = typeof rec.durationMs === 'number' ? rec.durationMs : undefined;
@@ -263,7 +146,6 @@ function projectAgent(row, index) {
263
146
  const phase = typeof row.phase === 'string' && row.phase.trim() ? row.phase.trim() : undefined;
264
147
  return Object.assign(agent, phase ? { _phase: phase } : {});
265
148
  }
266
- /** read the (permissive) structured phase rows the service detail projects (`{title,status,done,total,…}`). */
267
149
  function readPhases(run) {
268
150
  const out = [];
269
151
  for (const p of run.phases ?? []) {
@@ -284,10 +166,6 @@ function stripPhase(a) {
284
166
  void _ignored;
285
167
  return rest;
286
168
  }
287
- /** Build the monitor's WorkflowPhase[] from the run's structured phases + the agents' `_phase` tags. Three
288
- * paths, all degrade-safe: (1) structured phases on the wire → bucket agents by their phase title (an agent
289
- * whose phase matches none lands in the first phase); (2) no structured phases but agents carry phase tags →
290
- * one phase per distinct tag; (3) neither → a single synthetic 'Workflow' phase holding every agent. */
291
169
  function projectPhases(run, agents) {
292
170
  const raw = readPhases(run);
293
171
  const firstRaw = raw[0];
@@ -327,8 +205,6 @@ function projectPhases(run, agents) {
327
205
  return [
328
206
  {
329
207
  title: 'Workflow',
330
- // 同形第二处(G-20):这条三元式与 `coerceRunStatus` 读的是同一位 run 状态,兜底也同形 ——
331
- // 只修一处等于把病搬个家。`parked` 走 `coerceRunStatus` 的同一条臂,不在这里另写一遍判据。
332
208
  status: synthPhaseStatus(run.status, agents),
333
209
  doneCount: agents.filter(a => a.state === 'done').length,
334
210
  totalCount: agents.length,
@@ -336,13 +212,6 @@ function projectPhases(run, agents) {
336
212
  },
337
213
  ];
338
214
  }
339
- /**
340
- * 一桶腿 → 这一格的状态词。
341
- *
342
- * 🔴 `parked` 的判据是「**这一格里没有一条腿能自己往前走**」:全员不是完成就是停在门上,且至少有
343
- * 一条真停着。混着还在跑的腿时**仍报 running** —— 那一格确实还在跑,渲成 parked 是另一个方向的谎。
344
- * 🔴 `failed` 仍先判:一格里既有失败又有停着的腿时,先要人看的是那条失败的。
345
- */
346
215
  function bucketStatus(bucket) {
347
216
  if (bucket.some(a => a.state === 'error'))
348
217
  return 'failed';
@@ -351,16 +220,10 @@ function bucketStatus(bucket) {
351
220
  if (bucket.some(a => a.state === 'parked') && bucket.every(a => a.state === 'parked' || a.state === 'done')) {
352
221
  return 'parked';
353
222
  }
354
- // 0.72.12 CC-51(异源对抗复审 R1 [high];DS-06 病形本体 = 兜底位置落正向词):`running` 只在有腿真在跑 / 排队时说;
355
- // 空桶(零腿)与全是 inactive 之类没有活跃证据的桶 ⇒ unknown。上一行的 `length > 0` 守卫做对了「空集 every 恒真」那一格,
356
- // 却栽在这个尾 return 上 —— 病不在粗心,在「兜底位置写什么」缺纪律。
357
223
  if (bucket.some(a => a.state === 'start' || a.state === 'progress' || a.state === 'queued'))
358
224
  return 'running';
359
225
  return 'unknown';
360
226
  }
361
- /** 合成 `Workflow` 单格(路径三:wire 既无结构化 phases 也无 agent 上的 phase 标)的状态词。
362
- * 跟 run 走(同 {@link coerceRunStatus} 的臂),run 说不出 `parked` 时再从腿上推一次 —— 今天真正
363
- * 会带 `parked` 的正是腿那一级,而路径三的这一格代表的就是整只 run 的全部腿。 */
364
227
  function synthPhaseStatus(runStatus, agents) {
365
228
  if (runStatus === 'completed')
366
229
  return 'done';
@@ -368,28 +231,17 @@ function synthPhaseStatus(runStatus, agents) {
368
231
  return 'parked';
369
232
  const derived = bucketStatus(agents);
370
233
  if (derived === 'parked')
371
- return 'parked'; // 腿上的 park 压过 run 级 failed(core 7.10.0 把一条腿 park 收在 failed)
372
- // 腿上的 error 是明确失败证据(bucketStatus 失败优先)—— 合成格与带 phase 标签的同组腿必须同判(异源对抗复审 R3)。
234
+ return 'parked';
373
235
  if (runStatus === 'failed' || derived === 'failed')
374
236
  return 'failed';
375
- // 0.72.12 CC-51(异源对抗复审 R1 [high]):此前尾三元 `failed ? 'failed' : 'running'` 把「run 缺 status / 认不出的词」折成在跑。
376
- // 正向证据两处:run 自己说 running / queued,或腿上有人在跑;都没有 ⇒ unknown。
377
237
  if (runStatus === 'running' || runStatus === 'queued')
378
238
  return 'running';
379
239
  return derived === 'running' ? 'running' : 'unknown';
380
240
  }
381
- /** THE projector: SDK `WorkflowRun` (client.workflows.get) → the monitor's `WorkflowRunState`. Pure/total —
382
- * tolerates absent/permissive fields and never throws (the graceful-degrade contract lives above, in the
383
- * source loop; this just maps a well-formed run). Exported for the mock-parity unit cross-check. */
384
241
  export function projectWorkflowRun(run) {
385
242
  const parks = readWorkflowParks(run);
386
243
  const agents = (run.agents ?? []).map((r, i) => projectAgent(r, i));
387
244
  const phases = projectPhases(run, agents);
388
- // 0.73.0:总用量三态 —— 有键 ⇒ 一个**完整**的总数(含真 0);缺键 ⇒ 没有完整总数。判据(每个分量都先验非负整数):
389
- // ① 引擎聚合 `stats.tokens` 在场且合法:无 nested 载体 ⇒ 就是它;nested 载体在场 ⇒ 其 tokens 也得合法才相加,否则缺席
390
- // (残缺的聚合不按 0 补齐 —— 那会发布一个偏小的「总数」);
391
- // ② `stats.tokens` 缺席但 nested 载体在场 ⇒ 聚合残缺 ⇒ 缺席(不退到腿上求和:腿只覆盖本 run,会把嵌套的那部分漏掉);
392
- // ③ 两者都没有 ⇒ 退到腿上求和,但只在**每条腿都报过合法用量**且至少一条腿时成立;有腿未报 / 非法 / 零条腿 ⇒ 缺席。
393
245
  const validTokens = (v) => typeof v === 'number' && Number.isInteger(v) && v >= 0 ? v : undefined;
394
246
  const ownTokens = validTokens(run.stats?.tokens);
395
247
  const nestedCarrier = run.stats?.nested;
@@ -409,16 +261,9 @@ export function projectWorkflowRun(run) {
409
261
  : undefined;
410
262
  const state = {
411
263
  workflowRunId: run.id,
412
- // 0.72.12 CC-51(异源对抗复审 R2 [medium]):run 状态词认不出 / 缺席时先看腿上的**活跃证据** —— 有腿在跑 / 排队 ⇒ running
413
- // (老壳用 `status === 'running'` 算 workflowActive,run 落 unknown 会把明明在跑的腿渲成 Stopped);零证据才 unknown。
414
- // 不拿「腿全做完了」反推 run 完成:那是 run 自己的话。
415
264
  status: runStatusWithLegEvidence(coerceRunStatus(run.status), agents),
416
- // CC-12(0.69.1):park 两新键**进视图**(修前只出读器,端拿不到裸体 ⇒ 渲染面结构性造不出);铸法与缺席律逐字同两读器。
417
265
  ...(parks !== undefined ? { parks } : {}),
418
266
  ...(readWorkflowResumeAdmissionIncomplete(run) ? { resumeAdmissionIncomplete: true } : {}),
419
- // The authored script TEXT is not projected to the wire (types.ts:375 — service does not emit it), so leave
420
- // it empty: the monitor's "save script" affordance stays off (canSave = script.length > 0). Never fabricate
421
- // a script we do not have. scriptPath is likewise absent until the service projects it.
422
267
  script: '',
423
268
  agentCount: agents.length,
424
269
  ...(totalTokens !== undefined ? { totalTokens } : {}),
@@ -430,18 +275,6 @@ export function projectWorkflowRun(run) {
430
275
  state.description = run.description;
431
276
  return state;
432
277
  }
433
- /**
434
- * `GET /v1/workflows/:id` 的 `parks[]` → 三键行;**整键缺席 ⇒ `undefined`**(与空数组逐字可分)。
435
- *
436
- * 🔴 **`undefined` 与 `[]` 不是一回事**,这是本读器最承重的一格:
437
- * · `undefined` —— 这条记录上没有 `parks` 这一键(旧引擎写的)⇒ **证不出**有没有 park;
438
- * · `[]` —— 这条记录有这一键且是空的 ⇒ 一句正面事实:这条 run 上没有 park。
439
- * 🔴 **坏行只丢自己**(与本包 `wiring_manifest.mcp[]` 的处置同尺):三键缺一 / 非串 / 空串 的行
440
- * 整条丢弃,其余行保序留下;**非空输入而全部坏行 ⇒ 返回 `[]`**?—— **不**:那会把「读不出」
441
- * 伪装成「零 park」。全坏 ⇒ `undefined`(诚实缺席)。
442
- * 🔴 `parks` 不是数组(对象 / 串 / null)⇒ 当整键缺席(非投影口喂进来的形)。
443
- * 🔴 纯函数、零副作用、**绝不抛**。
444
- */
445
278
  export function readWorkflowParks(run) {
446
279
  if (typeof run !== 'object' || run === null || Array.isArray(run))
447
280
  return undefined;
@@ -458,82 +291,25 @@ export function readWorkflowParks(run) {
458
291
  const originRunId = typeof o.originRunId === 'string' && o.originRunId.length > 0 ? o.originRunId : undefined;
459
292
  if (callKey === undefined || sessionId === undefined || originRunId === undefined)
460
293
  continue;
461
- // 🔴 **逐键铸**,不 spread:上游在这张行上多放一个键(尤其是凭据形)时,它在结构上到不了
462
- // 本包的产物。这不是风格选择 —— 它是本段 ① 那条红线的实现。
463
- // 7.18.0:第四键 never-false,严格 `true` 才铸(`false`/`"true"`/`1` 都是坏值 = 缺席 = 已确认)。
464
294
  rows.push({ callKey, sessionId, originRunId, ...(o.originUnconfirmed === true ? { originUnconfirmed: true } : {}) });
465
295
  }
466
- // 非空输入而一行都没活下来 ⇒ 读不出,不是「零 park」(绝不铸 `[]` 冒充一句正面事实)。
467
296
  if (raw.length > 0 && rows.length === 0)
468
297
  return undefined;
469
298
  return rows;
470
299
  }
471
- /**
472
- * `GET /v1/workflows/:id` 的 `resumeAdmissionIncomplete`(core 7.18.0 #755,0.68.3 CC-05)——
473
- * 「这条 resume run 的准入**没有完成**」:记录从创建起带 `true`,准入完成那一刻**删键**。
474
- *
475
- * 🔴 **在场 = 不是 resume 基**(引擎自己会拒 `workflow.park_truth_unreadable` / `admission_incomplete`,
476
- * 且不从它派生候选);缺席 = 每条非 resume run 与每次完成了的准入的常态。⇒ 读者只认在场,
477
- * 缺席不是断言。never-false:严格 `true` 才算在场,其余一律缺席。
478
- * 🔴 与 {@link readWorkflowParks} **同一条投影义务**(core 顶注逐字:dropping it turns a refused record
479
- * back into an admissible one)—— 端渲 resume 候选 / 面板行时**必须**带上这一位;本包不把它折进
480
- * `parks` 的缺席(那一形有自己的两义,见 `readWorkflowParks` 顶注)。
481
- * 🔴 纯函数、零副作用、绝不抛;坏载体 ⇒ `false`(不是「读不出」:这一位没有第三态)。
482
- */
483
300
  export function readWorkflowResumeAdmissionIncomplete(run) {
484
301
  if (typeof run !== 'object' || run === null || Array.isArray(run))
485
302
  return false;
486
303
  return run.resumeAdmissionIncomplete === true;
487
304
  }
488
- // ── 轮询/退避节拍(REF-CC-131,域词表-15):三个 3000ms 常量语义各不相同,拆开命名——合并成一个
489
- // 会把三条独立的退避策略绑死在一起(其中任一策略调优都会误伤另外两条)。──────────────────────
490
- /** owner 名下暂无任何 run(`resolveRunId` 回 null)时的重试间隔:不是错误,只是「还没有可监的
491
- * run」——退避到下一次 list() 重试,给一个正在被启动的 run 留出出现的时间。 */
492
305
  const NO_RUN_BACKOFF_MS = 3000;
493
- /** `refresh()` 判定 degraded(501 S8-off / 404 gone)后的重试间隔:不再尝试 stream(),直接退避
494
- * 重跑外层循环——与 NO_RUN_BACKOFF_MS 数值巧合相同但触发条件不同(有 run id 但拿不到快照)。 */
495
306
  const DEGRADED_BACKOFF_MS = 3000;
496
- /** consume() 外层 catch 兜到的未归类异常(list/refresh 之外的意外)后的退避间隔——保守值,
497
- * 与前两个 3000 又是同一个数字、不同的触发路径,故各自具名而非合一常量。 */
498
307
  const UNEXPECTED_ERROR_BACKOFF_MS = 3000;
499
- /** stream() 以「无终帧」收场(丢连,非可续传)之后、重新 re-`get()` 快照前的退避间隔——比另外
500
- * 三个短,因为这是「已知在连接一个存在的 run」而不是「不确定还有没有事可做」。 */
501
308
  const STREAM_DROP_BACKOFF_MS = 1000;
502
- /** stream() ticker 帧触达时,距上一次 `refresh()` 的最小间隔——节流 re-GET 频率,不是退避:
503
- * 帧到来表示「有变化」,但没必要每一帧都打一次权威快照。 */
504
309
  const REFRESH_THROTTLE_MS = 400;
505
- // ══ #242 批 1(台账 A-028.8)—— 运行期 activity 台账:模块级常驻 + 每 workflowId 恰一条 SSE ═══
506
- //
507
- // ── 修前的两半(组合 = 同一 workflowId 上两条 SSE、两份台账)────────────────────────────────
508
- // ① core:workflow run 记录的 `agents[].toolCalls` / `agents[].activity` **只在 agent_end 折入**
509
- // ⇒ 运行中 agent 的 GET 详情永远拿不到工具信息;运行期的工具事实**只在** detail SSE 上
510
- // (`agent_activity` 带 callKey/label/toolName/arg/phase/ts;`agent_end` 带权威 toolCalls;
511
- // `agent_end.modelResolved` 更是 core 记录从不折入的量 —— SSE 是唯一到达路径)。
512
- // ② 本文件:把这条 SSE 只当**变化 ticker**(`for await (const _frame …) { void _frame }`),帧体整丢。
513
- // ⇒ 壳(sema-cli `workflowLiveActivity.ts`)只好**另起一条同 id 的 SSE**自建模块级台账再自己合并。
514
- //
515
- // ── 本段(单流化)──────────────────────────────────────────────────────────────────────────
516
- // 台账收进包内,并且成为该 workflowId 的**唯一 SSE 属主**:
517
- // · `ensureWorkflowActivityLedger(cfg)` —— **预热口**(幂等):fleet 流上 workflow 行一出现就调,
518
- // 从 workflow 起跑积累工具事实。🔴 台账是**模块级常驻**而非 per-controller —— 这是刻意的:
519
- // 壳侧一版做成「开 monitor 才开流」,实测两个洞(打开前的 beat 全丢:monitor 刚开的头几秒
520
- // stats 恒空;重开 monitor = 新流 = 账本清零失忆)。`createLiveWorkflowSource().dispose()`
521
- // 只收它自己的 GET 循环,**不掐台账**,两个洞因此不会随上收复发。
522
- // · `createLiveWorkflowSource` 不再自开流,改搭台账的 change-tick 做节流 re-GET(逐拍等价)。
523
- // · `readWorkflowActivityLedger(id)` —— 台账读口(端侧合并层消费:壳 `mergeSnapshot` 只补
524
- // base 缺席的键)。归属钥匙 **callKey 优先**(agent_activity 帧必带、GET 行也带),
525
- // label 次之;同 label 多个非 replay 的 agent_start ⇒ 归属不可判 ⇒ label 读口**整组跳过**
526
- // (诚实缺席,绝不猜挂)。
527
- // 限界(如实):台账自预热口首次调用起积累 —— 壳自己没看过的时段(重启后 attach 老 run)仍是
528
- // 下界;`agent_end.toolCalls` 到手后计数转权威。
529
- /** detail 页 Activity 尾窗是 3(HIO),折叠上限给足余量即可;超限丢最老(与 server 存储折入同向)。 */
530
310
  const MAX_WORKFLOW_ACTIVITY_CALLS = 40;
531
- /** 常驻台账上限(并发运行的 workflow 数远小于此;超限先逐已收口的,再逐最老)。 */
532
311
  const MAX_WORKFLOW_ACTIVITY_LEDGERS = 16;
533
- /** 运行中的意外断流回退(终态收口是**干净空流**自然退出,不再重连)。 */
534
312
  const WORKFLOW_ACTIVITY_RECONNECT_MS = 1500;
535
- /** 「一帧都没收到就抛」的连续次数上限 —— 满了才收口。1 次即收口会把瞬时不可达固化成永久失活;
536
- * 不设上限则 S8 关闭(恒 501)的部署上会无限重连。3 次 ≈ 3s 观察窗,两头都不失守。 */
537
313
  const MAX_ACTIVITY_STREAM_ERROR_STREAK = 3;
538
314
  const activityLedgers = new Map();
539
315
  function newActivityLedger(workflowId, scope) {
@@ -561,7 +337,6 @@ function newActivityLedger(workflowId, scope) {
561
337
  viewLastError: null,
562
338
  };
563
339
  }
564
- /** 连线身份相等:凭证只比较、不落键不落日志。relay 形按 mode 比。 */
565
340
  function sameActivityScope(a, b) {
566
341
  if (a.baseUrl !== b.baseUrl)
567
342
  return false;
@@ -585,8 +360,6 @@ function registerLabelAcc(l, label, acc) {
585
360
  if (!accs.includes(acc))
586
361
  accs.push(acc);
587
362
  }
588
- /** label 位是否**唯一可判**:恰一个 acc、且没被重名探测标记。两条缺一不可 —— 前者盖住
589
- * 「中途 attach 只见 beat」「replayed 重跑」这两条不经 agent_start 的产生路径,后者是显式诊断位。 */
590
363
  function soleAccOfLabel(l, label) {
591
364
  if (l.ambiguous.has(label))
592
365
  return undefined;
@@ -595,15 +368,10 @@ function soleAccOfLabel(l, label) {
595
368
  return undefined;
596
369
  return accs[0];
597
370
  }
598
- /** callKey 在场:它是主键。同 label 已有一条**尚未绑 callKey** 的 acc(agent_start 无 callKey 在先)
599
- * ⇒ 认领它,不新建第二份;否则新建并登记。 */
600
371
  function accByCallKey(l, callKey, label) {
601
372
  const hit = l.byCallKey.get(callKey);
602
373
  if (hit)
603
374
  return hit;
604
- // 🔴 只认领「还没被 label-only 的 agent_end 写过权威事实」的 orphan —— 带事实的那种一旦认领,
605
- // 另一个 agent 的 toolCalls/modelResolved 就永久钉在这个 callKey 上了(callKey 读口不过
606
- // 重名过滤)。不认领时新建第二份 ⇒ 该 label 变成非唯一 ⇒ label 读口自动改口诚实缺席。
607
375
  const orphan = (l.labelAccs.get(label) ?? []).find(a => a.callKey === undefined && a.hasLabelOnlyEndFacts !== true);
608
376
  const acc = orphan ?? newActivityAcc(label);
609
377
  acc.callKey = callKey;
@@ -611,9 +379,6 @@ function accByCallKey(l, callKey, label) {
611
379
  registerLabelAcc(l, label, acc);
612
380
  return acc;
613
381
  }
614
- /** 只有 label 的写入(`agent_end` 帧不带 callKey)。🔴 该 label 下不止一个 acc ⇒ **不记**
615
- * ——错值比缺席更坏:写进去会被 callKey 读口原样读出来,把另一个 agent 的权威 toolCalls/
616
- * modelResolved 冒充成这一个的(对抗复审 [high] 采纳)。 */
617
382
  function accByLabelForWrite(l, label) {
618
383
  const accs = l.labelAccs.get(label);
619
384
  if (accs && accs.length > 1)
@@ -626,7 +391,6 @@ function accByLabelForWrite(l, label) {
626
391
  registerLabelAcc(l, label, acc);
627
392
  return acc;
628
393
  }
629
- /** 一帧 → 台账。开集帧形:只读认得的键,其余原样忽略(不认得的 event 直接落空)。 */
630
394
  function foldWorkflowActivityFrame(l, frame) {
631
395
  l.frames += 1;
632
396
  if (frame.event === 'agent_start') {
@@ -635,7 +399,6 @@ function foldWorkflowActivityFrame(l, frame) {
635
399
  return;
636
400
  const n = (l.startedLabels.get(label) ?? 0) + 1;
637
401
  l.startedLabels.set(label, n);
638
- // 重跑(replayed)不算重名;同 label 第二个非 replay start ⇒ 归属不可判。
639
402
  if (n > 1 && frame.data.replayed !== true)
640
403
  l.ambiguous.add(label);
641
404
  const callKey = frame.data.callKey;
@@ -653,7 +416,6 @@ function foldWorkflowActivityFrame(l, frame) {
653
416
  const label = frame.data.label;
654
417
  if (typeof label !== 'string' || !label)
655
418
  return;
656
- // agent_end 帧**不带 callKey**(wire 直证)⇒ 只有 label 一把钥匙;重名时不记。
657
419
  const acc = accByLabelForWrite(l, label);
658
420
  if (!acc)
659
421
  return;
@@ -694,7 +456,6 @@ function foldWorkflowActivityFrame(l, frame) {
694
456
  folded.summary = arg;
695
457
  if (!acc.calls.has(key)) {
696
458
  acc.order.push(key);
697
- // 上限:丢最老(order 与 map 同步),detail 尾窗只看最近几条。
698
459
  while (acc.order.length > MAX_WORKFLOW_ACTIVITY_CALLS) {
699
460
  const drop = acc.order.shift();
700
461
  if (drop !== undefined)
@@ -710,7 +471,6 @@ function projectActivityAcc(acc) {
710
471
  .map(c => ({ name: c.name, ...(c.summary ? { summary: c.summary } : {}) }));
711
472
  const view = {
712
473
  label: acc.label,
713
- // agent_end 的权威值优先,否则 start 计数下界。
714
474
  toolCalls: acc.endedToolCalls ?? acc.startCount,
715
475
  activity,
716
476
  };
@@ -730,8 +490,6 @@ function projectActivityAcc(acc) {
730
490
  view.lastProgressAt = acc.lastTs;
731
491
  return view;
732
492
  }
733
- /** 台账读口:没有该 id 的台账 ⇒ **null**(不是空视图 —— 「没开过账」与「开了账但一帧没收到」
734
- * 是两件事,端侧据此分辨)。产物只读,按 frames/closed 缓存。 */
735
493
  export function readWorkflowActivityLedger(workflowId) {
736
494
  const l = activityLedgers.get(workflowId);
737
495
  if (!l)
@@ -756,8 +514,6 @@ export function readWorkflowActivityLedger(workflowId) {
756
514
  byCallKey.set(k, viewOf(acc));
757
515
  const byLabel = new Map();
758
516
  for (const label of l.labelAccs.keys()) {
759
- // 🔴 归属不可判(同 label 多个 acc / 重名探测命中)⇒ 整组跳过(诚实缺席,绝不猜挂)。
760
- // callKey 读口不受影响 —— 它才是真钥匙。
761
517
  const sole = soleAccOfLabel(l, label);
762
518
  if (!sole)
763
519
  continue;
@@ -777,7 +533,6 @@ export function readWorkflowActivityLedger(workflowId) {
777
533
  l.viewLastError = l.lastError;
778
534
  return l.view;
779
535
  }
780
- /** 一拍。一个抛异常的订阅者不许弄死后台消费循环(与本源全篇 fail-soft 一致)。 */
781
536
  function emitActivityTick(l) {
782
537
  for (const t of [...l.ticks]) {
783
538
  try {
@@ -790,7 +545,6 @@ function emitActivityTick(l) {
790
545
  }
791
546
  }
792
547
  }
793
- /** 等下一拍:'tick' = 有帧到达 / 'closed' = 台账收口 / 'abort' = 宿主 dispose。 */
794
548
  function waitActivityTick(l, signal) {
795
549
  if (signal.aborted)
796
550
  return Promise.resolve('abort');
@@ -812,9 +566,7 @@ function waitActivityTick(l, signal) {
812
566
  signal.addEventListener('abort', onAbort, { once: true });
813
567
  });
814
568
  }
815
- /** 台账的 SSE 消费循环 —— **该 workflowId 唯一的一条流**。 */
816
569
  async function consumeWorkflowActivity(l, cfg) {
817
- // 唯一构造点 + 显式 maxRetries: 2(与 createLiveWorkflowSource 同口径)。
818
570
  const client = makeEngineWireClient({
819
571
  baseUrl: cfg.baseUrl,
820
572
  ...(cfg.authToken ? { token: cfg.authToken } : {}),
@@ -822,7 +574,6 @@ async function consumeWorkflowActivity(l, cfg) {
822
574
  maxRetries: 2,
823
575
  ...(cfg.fetchImpl ? { fetchImpl: cfg.fetchImpl } : {}),
824
576
  });
825
- // fail-soft:工厂造不出 client ⇒ 台账收口、读口如实报 closed(绝不抛进宿主)。
826
577
  if (client === null) {
827
578
  l.closed = true;
828
579
  l.closedReason = 'error';
@@ -847,7 +598,6 @@ async function consumeWorkflowActivity(l, cfg) {
847
598
  foldWorkflowActivityFrame(l, frame);
848
599
  }
849
600
  catch {
850
- // 单帧折叠失败不拆流(开集帧形;台账缺一拍好过整层失效)。
851
601
  }
852
602
  emitActivityTick(l);
853
603
  }
@@ -862,13 +612,6 @@ async function consumeWorkflowActivity(l, cfg) {
862
612
  }
863
613
  }
864
614
  l.connected = false;
865
- // 🔴 两种「本轮零帧」必须分开裁(对抗复审 [high] 采纳 —— 合并成一条会把**一次瞬时不可达**
866
- // 固化成台账永久失活,而 ensure 对已存在台账恒早退 ⇒ 引擎恢复后 SSE 再也开不回来,
867
- // 详情页此后只剩 GET 轮询,而运行期 tool/activity 恰恰是 GET 结构上给不出的量):
868
- // · **干净空流**(迭代器正常结束、一帧没有)= run 终态/不在本副本(core subscribeWorkflow
869
- // 非活跃即空迭代器)⇒ 收口,GET 此后是权威;
870
- // · **抛在首帧前**(501/404/连接失败)= 可能只是这一拍不可达 ⇒ 退避重连,连击满
871
- // MAX_ACTIVITY_STREAM_ERROR_STREAK 次(全程零帧)才收口,lastError 留痕。
872
615
  if (!sawFrame && !threw) {
873
616
  l.closed = true;
874
617
  l.closedReason = 'terminal';
@@ -880,7 +623,6 @@ async function consumeWorkflowActivity(l, cfg) {
880
623
  else if (threw) {
881
624
  l.errorStreak += 1;
882
625
  if (l.errorStreak >= MAX_ACTIVITY_STREAM_ERROR_STREAK) {
883
- // 🔴 只是「连不上」⇒ 标 error(可被下一次 ensure 重开),不是终态。
884
626
  l.closed = true;
885
627
  l.closedReason = 'error';
886
628
  emitActivityTick(l);
@@ -894,10 +636,6 @@ async function consumeWorkflowActivity(l, cfg) {
894
636
  }
895
637
  emitActivityTick(l);
896
638
  }
897
- /**
898
- * **预热口**(幂等):fleet 流上见到 running workflow 行就调 —— 从 workflow 起跑积累工具事实,
899
- * monitor 无论何时打开都有自那时起的完整台账。已有台账(哪怕已收口)即早退,**绝不开第二条流**。
900
- */
901
639
  export function ensureWorkflowActivityLedger(cfg) {
902
640
  if (!cfg.workflowId)
903
641
  return;
@@ -908,13 +646,9 @@ export function ensureWorkflowActivityLedger(cfg) {
908
646
  };
909
647
  const existing = activityLedgers.get(cfg.workflowId);
910
648
  if (existing) {
911
- // 测试钩建的离线台账:恒早退(不换、不起流)。
912
649
  if (existing.testOnly)
913
650
  return;
914
651
  if (sameActivityScope(existing.scope, scope)) {
915
- // 🔴 同连线身份:只有**因错误**收口的才重开(对抗复审 R2 [high] 采纳)——干净空流(run
916
- // 终态)与显式 stop 是永久收口,重开等于跟一个已经结束的 run 死磕。重开**复用同一条
917
- // 台账对象**,已积累的事实原样保留(重连不失忆)。
918
652
  if (existing.closed && existing.closedReason === 'error') {
919
653
  existing.closed = false;
920
654
  existing.closedReason = null;
@@ -924,9 +658,6 @@ export function ensureWorkflowActivityLedger(cfg) {
924
658
  }
925
659
  return;
926
660
  }
927
- // 🔴 同 id 但**连线身份变了**(换引擎 baseUrl / 换 principal / 换凭证)⇒ 旧台账连的是另一台
928
- // 服务,复用它等于把上一处的活动事实当成这一处的。整条换新,并给旧的打 displaced ——
929
- // 旧台账的消费者据此**不再重新 ensure**(否则两个不同 scope 的消费者会互相把槽位换来换去)。
930
661
  existing.closed = true;
931
662
  existing.closedReason = 'stopped';
932
663
  existing.displaced = true;
@@ -935,12 +666,6 @@ export function ensureWorkflowActivityLedger(cfg) {
935
666
  activityLedgers.delete(cfg.workflowId);
936
667
  }
937
668
  if (activityLedgers.size >= MAX_WORKFLOW_ACTIVITY_LEDGERS) {
938
- // 逐出顺序:① 已收口的(数据只读,重开 monitor 走 GET 权威)→ ② 无在飞消费者的最老一条。
939
- // 🔴 判活用**消费者租约** `consumers` 而不是瞬时的 `ticks.size`(对抗复审 R2 [medium]):
940
- // 消费者被一帧唤醒、正在跑一发慢 GET 的那一窗里 ticks 是空的,按它判会把在飞台账逐掉。
941
- // 🔴 **绝不逐出正在被消费的台账**:那会当场丢掉它积累的 SSE-only 历史,而被叫醒的消费方
942
- // 退避后又会重建、再逐掉另一条在飞的 —— 逐出/重连自激。
943
- // 全 16 条都有在飞消费者时**不建新账**(如实降级:该 id 的详情页退回 GET 轮询)。
944
669
  let victim;
945
670
  for (const [id, other] of activityLedgers) {
946
671
  if (other.closed && other.consumers === 0) {
@@ -975,7 +700,6 @@ export function ensureWorkflowActivityLedger(cfg) {
975
700
  activityLedgers.set(cfg.workflowId, ledger);
976
701
  void consumeWorkflowActivity(ledger, cfg);
977
702
  }
978
- /** fleet 行终态/remove 的收口口(空流收口是主径;这里防重连定时器竞态)。数据保留只读。 */
979
703
  export function stopWorkflowActivityLedger(workflowId) {
980
704
  const l = activityLedgers.get(workflowId);
981
705
  if (!l)
@@ -985,7 +709,6 @@ export function stopWorkflowActivityLedger(workflowId) {
985
709
  l.abort.abort();
986
710
  emitActivityTick(l);
987
711
  }
988
- /** 测试钩:清空全部台账(abort 在飞流)。 */
989
712
  export function resetWorkflowActivityLedgers() {
990
713
  for (const l of activityLedgers.values()) {
991
714
  l.closed = true;
@@ -995,11 +718,6 @@ export function resetWorkflowActivityLedgers() {
995
718
  }
996
719
  activityLedgers.clear();
997
720
  }
998
- /**
999
- * 测试钩:**不起 SSE 流**,直接把一帧喂进(缺则新建)指定 run 的台账 —— 折叠规则走产品那一份
1000
- * `foldWorkflowActivityFrame`,不是测试自己抄一份。建出来的台账是 closed 的,后续
1001
- * `ensureWorkflowActivityLedger` 命中它即早退,离线单测因此永不触网。
1002
- */
1003
721
  export function __feedWorkflowActivityFrameForTests(workflowId, frame) {
1004
722
  let l = activityLedgers.get(workflowId);
1005
723
  if (!l) {
@@ -1009,23 +727,11 @@ export function __feedWorkflowActivityFrameForTests(workflowId, frame) {
1009
727
  l.closedReason = 'stopped';
1010
728
  activityLedgers.set(workflowId, l);
1011
729
  }
1012
- // 🔴 只往**离线台账**里喂(对抗复审 R2 [medium] 采纳):这个钩虽在 `_` 前缀的测试钩面上
1013
- // (不进公开导出基线),但它此前能把伪造帧折进一条**真在跑**的台账。现在真台账一律拒绝
1014
- // —— 测试要用它必须先 `resetWorkflowActivityLedgers()`,离线契约从「靠调用方自觉」变成结构。
1015
730
  if (!l.testOnly)
1016
731
  return;
1017
732
  foldWorkflowActivityFrame(l, frame);
1018
733
  emitActivityTick(l);
1019
734
  }
1020
- /**
1021
- * createLiveWorkflowSource({ baseUrl, authToken, principal, workflowId? }) — the LIVE workflow-monitor source.
1022
- *
1023
- * Constructs the AgentClient and kicks off a background loop that (1) resolves a run id (explicit config, else
1024
- * the first running run from `list()`), (2) snapshots it via `get()` → project → store, and (3) follows
1025
- * `stream()` as a change-ticker (re-`get()` throttled on each frame). Every step is degrade-safe: a 501 (S8
1026
- * off) / 404 (non-owner/absent) / empty list / connection error is RECORDED (status().degraded/code) and
1027
- * leaves `snapshot()` null so the host falls back to the mock/empty state — the source never throws into it.
1028
- */
1029
735
  export function createLiveWorkflowSource(config) {
1030
736
  let current = null;
1031
737
  let connected = false;
@@ -1035,14 +741,10 @@ export function createLiveWorkflowSource(config) {
1035
741
  let lastError = null;
1036
742
  let disposed = false;
1037
743
  let lastGetAt = 0;
1038
- /** 入场打点用:只有第一发 get 是「入场」,后续都是 ticker 触发的 re-GET。 */
1039
744
  let first = true;
1040
- /** CC-38:list 空(owner 零 run)与 client 造不出来 在 status() 上同形(degraded=true, code=null),用相位分开。 */
1041
745
  let phase = 'loop';
1042
- /** 台账槽位被别的连线身份顶掉过 ⇒ 本源放弃 activity 腿(防两个 scope 互相换账)。 */
1043
746
  let activityDisabled = false;
1044
747
  const listeners = new Set();
1045
- /** 通知订阅者「快照变了」。一个抛异常的订阅者不许弄死后台消费循环(fail-soft 与本源全篇一致)。 */
1046
748
  function notify() {
1047
749
  if (disposed)
1048
750
  return;
@@ -1057,7 +759,6 @@ export function createLiveWorkflowSource(config) {
1057
759
  }
1058
760
  }
1059
761
  }
1060
- // 差分① 见头注:唯一构造点 + 显式 maxRetries: 2(= 收编前吃的 SDK 缺省;工厂缺省 0 是单发探针语义)。
1061
762
  const client = makeEngineWireClient({
1062
763
  baseUrl: config.baseUrl,
1063
764
  ...(config.authToken ? { token: config.authToken } : {}),
@@ -1066,17 +767,7 @@ export function createLiveWorkflowSource(config) {
1066
767
  ...(config.fetchImpl ? { fetchImpl: config.fetchImpl } : {}),
1067
768
  });
1068
769
  const abort = new AbortController();
1069
- /** record a degrade/error WITHOUT throwing: 501 (S8 off) / 404 (non-owner|absent) are EXPECTED degrades;
1070
- * anything else (connection refused, parse) is a soft error — either way the host keeps the mock/empty.
1071
- *
1072
- * REF-CC-153(midband-01,fix-outright):the non-APIError branch must explicitly clear `code`/`degraded`
1073
- * rather than leave a prior call's values sitting there — `status().code` is documented as "the HTTP
1074
- * status behind a degrade (501/404), else null", so a stale 404 surviving into a later connection-refused
1075
- * error would misreport an unrelated failure as "still a 404 (run gone)".
1076
- */
1077
770
  function noteDegrade(err) {
1078
- // CC-38(复审实抓):empty 相位只对「刚刚那次 list 为空」成立,之后任何失败都要退回 loop —— 否则一次空表之后的连接故障
1079
- // 会被 resolution() 一直报成「零 run」,而 status() 早已换成新的 lastError。
1080
771
  if (phase === 'empty')
1081
772
  phase = 'loop';
1082
773
  connected = false;
@@ -1094,14 +785,6 @@ export function createLiveWorkflowSource(config) {
1094
785
  hostLog('debug', `[sema][workflow] degrade/err (host falls back to mock/empty): ${lastError}`);
1095
786
  }
1096
787
  }
1097
- /**
1098
- * resolve the run id to monitor: explicit config → the first RUNNING run → the first run → null (empty).
1099
- *
1100
- * ⚠️ 入场热路径记账(#79 串行普查):`config.workflowId` 在场时**直接返回,不打 list()** —— 三个
1101
- * 面板宿主(FleetView 内联 / `/workflows` / footer 内联)都是从 fleet 行拿到 id 才开的,所以入场
1102
- * 只有 **get 一跳**;list→get 的两跳串行只发生在 `SEMA_SCENARIO=workflow` 独立宿主且未给
1103
- * SEMA_WORKFLOW_ID 的路径上(那条路没有行可依,list 是唯一的 id 来源 —— 必须串行)。
1104
- */
1105
788
  async function resolveRunId(signal) {
1106
789
  if (config.workflowId)
1107
790
  return config.workflowId;
@@ -1114,13 +797,10 @@ export function createLiveWorkflowSource(config) {
1114
797
  return null;
1115
798
  const running = workflows.find(w => w.status === 'running');
1116
799
  const firstWorkflow = workflows[0];
1117
- // `workflows.length > 0` above guarantees index 0 exists; noUncheckedIndexedAccess can't see that,
1118
- // so re-check explicitly rather than reach for a non-null assertion.
1119
800
  if (firstWorkflow === undefined)
1120
801
  return null;
1121
802
  return (running ?? firstWorkflow).id;
1122
803
  }
1123
- /** take the authoritative snapshot + project it; records degrade on failure (never throws). */
1124
804
  async function refresh(id, signal) {
1125
805
  const t0 = Date.now();
1126
806
  try {
@@ -1134,11 +814,9 @@ export function createLiveWorkflowSource(config) {
1134
814
  code = null;
1135
815
  lastError = null;
1136
816
  if (engineWireDebugEnabled()) {
1137
- // 入场打点(#79):first=true 的那一行就是「壳拿到第一份权威快照」的耗时。
1138
817
  hostLog('debug', `[sema][workflow][perf] get ${Date.now() - t0}ms first=${first} agents=${current.agentCount} phases=${current.phases.length}`);
1139
818
  }
1140
819
  first = false;
1141
- // 解析即通知(首帧不等宿主的 1s tick;后续每次 re-project 同样通知,SSE ticker 的 re-GET 也走这里)。
1142
820
  notify();
1143
821
  }
1144
822
  catch (err) {
@@ -1147,15 +825,13 @@ export function createLiveWorkflowSource(config) {
1147
825
  noteDegrade(err);
1148
826
  }
1149
827
  }
1150
- /** background loop: resolve → snapshot → follow the stream (re-get on frames), degrade-safe throughout. */
1151
828
  async function consume() {
1152
829
  while (!disposed && !abort.signal.aborted) {
1153
830
  try {
1154
831
  const id = runId ?? (await resolveRunId(abort.signal));
1155
832
  if (id !== null && phase === 'empty')
1156
- phase = 'loop'; // 名单从空变非空:还没 get 成功之前先回 pending,不再报 empty
833
+ phase = 'loop';
1157
834
  if (!id) {
1158
- // owner has no runs → empty/degraded (not an error). Back off and re-poll (a run may appear).
1159
835
  degraded = true;
1160
836
  code = null;
1161
837
  phase = 'empty';
@@ -1164,21 +840,11 @@ export function createLiveWorkflowSource(config) {
1164
840
  continue;
1165
841
  }
1166
842
  await refresh(id, abort.signal);
1167
- // snapshot degraded (501 S8-off / 404 gone) → don't attempt the stream; back off and retry.
1168
843
  if (degraded) {
1169
844
  await abortableSleep(DEGRADED_BACKOFF_MS, abort.signal);
1170
845
  continue;
1171
846
  }
1172
- // 🔴 #242 批 1 单流化:本源**不再自开 SSE**。该 workflowId 的唯一 SSE 属主是模块级 activity
1173
- // 台账(同时也是 fleet 行预热腿的属主);本源只搭它的 change-tick 做节流 re-GET —— 与旧
1174
- // `for await (const _frame of stream)` 的逐拍语义等价,而连接数从「壳一条 + 本源一条」降到 1。
1175
- // 帧体不再被丢弃:台账消费它(callKey 折叠 / agent_end.toolCalls 权威 / requested-resolved model)。
1176
847
  if (!activityDisabled) {
1177
- // 🔴 停手检查必须先于 ensure(主会话收货修,#242-E13 抓出的时序洞):循环尾的
1178
- // `ledger.displaced` 检查读的是「本轮拿的对象」,而被顶掉发生在上一轮的 backoff 期
1179
- // ——下一轮若先 ensure,本源会在检测到自己被顶之前就把别的连线身份的台账换掉
1180
- // (伤害先于检测,ping-pong 防护形同虚设)。所以进入 ensure 前先看当前槽位:
1181
- // 已被**另一连线身份**持有 ⇒ 本源就地停手降级(GET 轮询),绝不抢回。
1182
848
  const cur = activityLedgers.get(id);
1183
849
  if (cur &&
1184
850
  !cur.testOnly &&
@@ -1204,8 +870,6 @@ export function createLiveWorkflowSource(config) {
1204
870
  }
1205
871
  const ledger = activityDisabled ? undefined : activityLedgers.get(id);
1206
872
  if (ledger) {
1207
- // 🔴 消费者租约:整段消费期持有(不是瞬时的 tick 订阅)—— 逐出判活读的就是它,
1208
- // 「被一帧唤醒、正在跑慢 GET」的那一窗里台账不会被误判成无人消费。
1209
873
  ledger.consumers += 1;
1210
874
  try {
1211
875
  for (;;) {
@@ -1218,8 +882,6 @@ export function createLiveWorkflowSource(config) {
1218
882
  await refresh(id, abort.signal);
1219
883
  if (degraded)
1220
884
  break;
1221
- // 台账收口(run 终态 / 显式 stop / 错误连击 / 被别的连线身份顶掉)⇒ 退回外层的
1222
- // 「退避 + 重取权威快照」;下一轮的 ensure 决定要不要重开(只有 error 收口会重开)。
1223
885
  if (beat === 'closed')
1224
886
  break;
1225
887
  }
@@ -1227,8 +889,6 @@ export function createLiveWorkflowSource(config) {
1227
889
  finally {
1228
890
  ledger.consumers -= 1;
1229
891
  }
1230
- // 🔴 本源的台账被**另一个连线身份**顶掉过 ⇒ 本源就此不再 ensure(否则两个 scope 的
1231
- // 消费者会把同一个槽位来回换)。如实降级:详情页此后只走 GET 轮询。
1232
892
  if (ledger.displaced) {
1233
893
  activityDisabled = true;
1234
894
  if (engineWireDebugEnabled()) {
@@ -1236,7 +896,6 @@ export function createLiveWorkflowSource(config) {
1236
896
  }
1237
897
  }
1238
898
  }
1239
- // ledger 收口/降级 → 小回退后在下一轮重取权威快照(GET 此后是权威)。
1240
899
  if (!disposed && !abort.signal.aborted)
1241
900
  await abortableSleep(STREAM_DROP_BACKOFF_MS, abort.signal);
1242
901
  }
@@ -1248,20 +907,12 @@ export function createLiveWorkflowSource(config) {
1248
907
  }
1249
908
  }
1250
909
  }
1251
- // REF-CC-147(域词表-17):此前这里有一个私有 `sleep()`,裸 Promise+定时器形
1252
- // ——不感知 abort:dispose() 唤不醒正在等待的那一轮,循环最多多跑一轮,且未清的 setTimeout 在
1253
- // Node 上继续维持事件循环存活(拖慢 headless `-p` 车道的进程退出)。已改用共享叶 abortableSleep
1254
- // (与 agentSession/backgroundView.ts 同一实现,详见 ./abortableSleep.ts 头注),消费点全改传
1255
- // `abort.signal` ——dispose() 一旦 `abort.abort()`,四处退避里在飞的那一个立即唤醒。
1256
- // 差分① 的 fail-soft 半场:工厂造不出 client(SDK 拒绝构造)⇒ 不起循环、恒 degraded,
1257
- // `snapshot()` 恒 null ⇒ 宿主走它既有的 mock/空态回落。**绝不抛进宿主**(与 501/404/空列表同路)。
1258
910
  if (client === null) {
1259
911
  degraded = true;
1260
912
  phase = 'unavailable';
1261
913
  lastError = 'client construction failed (invalid baseUrl/credentials)';
1262
914
  }
1263
915
  else {
1264
- // kick off the background consumer (fire-and-forget; all failures captured into status()).
1265
916
  void consume();
1266
917
  }
1267
918
  return {
@@ -1273,14 +924,11 @@ export function createLiveWorkflowSource(config) {
1273
924
  },
1274
925
  subscribe(onChange) {
1275
926
  listeners.add(onChange);
1276
- // 订阅即对账:订阅前就已经解析完的话,notify() 那一发已经打空了(当时还没有订阅者)——
1277
- // 不在这里补一发,宿主就要白等一整个轮询 tick(配对机制必须共享前提)。
1278
927
  if (current !== null && !disposed) {
1279
928
  try {
1280
929
  onChange();
1281
930
  }
1282
931
  catch {
1283
- /* 订阅者自己的问题,不许弄坏本源 */
1284
932
  }
1285
933
  }
1286
934
  return () => {