@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.
- package/CHANGELOG.md +13 -1
- package/README.md +5 -4
- package/dist/abortableSleep.d.ts +0 -28
- package/dist/abortableSleep.js +0 -28
- package/dist/adapt/arms.d.ts +0 -46
- package/dist/adapt/arms.js +9 -544
- package/dist/adapt/ids.d.ts +0 -58
- package/dist/adapt/ids.js +0 -63
- package/dist/adapt/instanceLedger.d.ts +0 -25
- package/dist/adapt/instanceLedger.js +0 -20
- package/dist/adapt/panelTasks.d.ts +0 -69
- package/dist/adapt/panelTasks.js +0 -95
- package/dist/adapt/textSegmentAuthority.d.ts +1 -137
- package/dist/adapt/textSegmentAuthority.js +0 -54
- package/dist/adapt/textStream.d.ts +0 -252
- package/dist/adapt/textStream.js +2 -281
- package/dist/adapt/toolCards.d.ts +0 -46
- package/dist/adapt/toolCards.js +0 -23
- package/dist/adapt/turnFlags.d.ts +0 -54
- package/dist/adapt/turnFlags.js +1 -17
- package/dist/adapt/wireShapes.d.ts +0 -92
- package/dist/adapt/wireShapes.js +0 -83
- package/dist/adapt.d.ts +0 -55
- package/dist/adapt.js +1 -120
- package/dist/adapter/activeRunSelfHeal.d.ts +22 -515
- package/dist/adapter/activeRunSelfHeal.js +10 -625
- package/dist/adapter/downstream/eventToSdkMessage.d.ts +2 -305
- package/dist/adapter/downstream/eventToSdkMessage.js +2 -867
- package/dist/adapter/downstream/terminalToSdkResult.d.ts +2 -314
- package/dist/adapter/downstream/terminalToSdkResult.js +13 -560
- package/dist/adapter/downstream/turnUsageToModelUsage.d.ts +0 -95
- package/dist/adapter/downstream/turnUsageToModelUsage.js +2 -31
- package/dist/adapter/runStream.d.ts +0 -206
- package/dist/adapter/runStream.js +6 -596
- package/dist/adapter/types.d.ts +0 -111
- package/dist/adapter/types.js +0 -29
- package/dist/agentSession/backgroundView.d.ts +0 -106
- package/dist/agentSession/backgroundView.js +3 -49
- package/dist/agentSession/contract.d.ts +0 -98
- package/dist/agentSession/contract.js +0 -12
- package/dist/agentsWireCaps.d.ts +0 -72
- package/dist/agentsWireCaps.js +4 -72
- package/dist/approvalsStreamLiveCapability.d.ts +0 -25
- package/dist/approvalsStreamLiveCapability.js +0 -31
- package/dist/argvFlagValue.d.ts +0 -33
- package/dist/argvFlagValue.js +3 -35
- package/dist/attachmentsWireCaps.d.ts +0 -127
- package/dist/attachmentsWireCaps.js +0 -144
- package/dist/autoModeUnavailable.d.ts +0 -120
- package/dist/autoModeUnavailable.js +0 -144
- package/dist/classifierStatus.d.ts +0 -72
- package/dist/classifierStatus.js +0 -167
- package/dist/classifierVerdictWire.d.ts +0 -54
- package/dist/classifierVerdictWire.js +0 -133
- package/dist/clientContextWireCaps.d.ts +0 -37
- package/dist/clientContextWireCaps.js +0 -36
- package/dist/clientSlice.d.ts +0 -63
- package/dist/clientSlice.js +0 -45
- package/dist/cloudConfigWireCaps.d.ts +0 -86
- package/dist/cloudConfigWireCaps.js +2 -65
- package/dist/compensations.d.ts +0 -52
- package/dist/compensations.js +2 -63
- package/dist/controlRouter.d.ts +2 -208
- package/dist/controlRouter.js +1 -129
- package/dist/coreValuePorts.d.ts +0 -84
- package/dist/coreValuePorts.js +0 -29
- package/dist/decideReceipt.d.ts +0 -110
- package/dist/decideReceipt.js +0 -84
- package/dist/detachWire.d.ts +0 -130
- package/dist/detachWire.js +1 -130
- package/dist/deviceExecutorManagementCapability.d.ts +2 -35
- package/dist/deviceExecutorManagementCapability.js +1 -37
- package/dist/diagnostics.d.ts +0 -8
- package/dist/diagnostics.js +0 -8
- package/dist/diff/patch.d.ts +0 -17
- package/dist/diff/patch.js +0 -19
- package/dist/effectiveFacts.d.ts +0 -40
- package/dist/effectiveFacts.js +0 -22
- package/dist/effortWire.d.ts +0 -11
- package/dist/effortWire.js +0 -12
- package/dist/engineAgentPanelStore.d.ts +0 -169
- package/dist/engineAgentPanelStore.js +13 -293
- package/dist/engineCapReader.d.ts +0 -62
- package/dist/engineCapReader.js +1 -43
- package/dist/engineCapsCache.d.ts +0 -177
- package/dist/engineCapsCache.js +0 -199
- package/dist/engineCapsGenerationGuard.d.ts +0 -2
- package/dist/engineCapsGenerationGuard.js +0 -11
- package/dist/engineErrorCodes.d.ts +1 -316
- package/dist/engineErrorCodes.js +0 -427
- package/dist/engineHttpTools.d.ts +0 -29
- package/dist/engineHttpTools.js +0 -29
- package/dist/engineIdentity.d.ts +0 -83
- package/dist/engineIdentity.js +0 -88
- package/dist/engineInlineTaskStats.d.ts +0 -57
- package/dist/engineInlineTaskStats.js +1 -42
- package/dist/engineNoticeCodes.d.ts +0 -190
- package/dist/engineNoticeCodes.js +0 -182
- package/dist/engineSessionParam.d.ts +0 -30
- package/dist/engineSessionParam.js +0 -52
- package/dist/engineToolLabelStore.d.ts +0 -29
- package/dist/engineToolLabelStore.js +0 -31
- package/dist/engineWireSdk.d.ts +0 -90
- package/dist/engineWireSdk.js +0 -74
- package/dist/engineWireTarget.d.ts +0 -14
- package/dist/engineWireTarget.js +0 -39
- package/dist/env/localeGeo.d.ts +0 -12
- package/dist/env/localeGeo.js +2 -77
- package/dist/env/localeTag.d.ts +0 -34
- package/dist/env/localeTag.js +0 -32
- package/dist/env/uiLanguage.d.ts +0 -13
- package/dist/env/uiLanguage.js +0 -25
- package/dist/envFlag.d.ts +0 -37
- package/dist/envFlag.js +0 -40
- package/dist/executionLaneCapability.d.ts +0 -48
- package/dist/executionLaneCapability.js +0 -54
- package/dist/finalVerifyWire.d.ts +0 -67
- package/dist/finalVerifyWire.js +3 -43
- package/dist/fleet/fleetLedger.d.ts +0 -308
- package/dist/fleet/fleetLedger.js +10 -429
- package/dist/fleet/fleetProjection.d.ts +0 -240
- package/dist/fleet/fleetProjection.js +0 -189
- package/dist/fleet/fleetRowAgentType.d.ts +0 -6
- package/dist/fleet/fleetRowAgentType.js +1 -32
- package/dist/fleet/workflowSizeWarning.d.ts +0 -47
- package/dist/fleet/workflowSizeWarning.js +1 -46
- package/dist/fleetAgentPanelProjection.d.ts +0 -48
- package/dist/fleetAgentPanelProjection.js +8 -173
- package/dist/fleetTaskDesc.d.ts +0 -39
- package/dist/fleetTaskDesc.js +0 -69
- package/dist/forkWireCaps.d.ts +0 -23
- package/dist/forkWireCaps.js +1 -24
- package/dist/gateOutcome.d.ts +0 -140
- package/dist/gateOutcome.js +0 -85
- package/dist/gateVocabulary.d.ts +0 -114
- package/dist/gateVocabulary.js +1 -161
- package/dist/goalStopHook.d.ts +0 -127
- package/dist/goalStopHook.js +0 -178
- package/dist/headlessPermissionModeWire.d.ts +0 -76
- package/dist/headlessPermissionModeWire.js +1 -155
- package/dist/headlessReconnectWire.d.ts +0 -84
- package/dist/headlessReconnectWire.js +13 -67
- package/dist/hitl/approvalDecisionNoteAudit.d.ts +0 -49
- package/dist/hitl/approvalDecisionNoteAudit.js +0 -56
- package/dist/hitl/approvalOutcomeNote.d.ts +0 -2
- package/dist/hitl/approvalOutcomeNote.js +0 -20
- package/dist/hitl/approvalResolution.d.ts +0 -113
- package/dist/hitl/approvalResolution.js +0 -66
- package/dist/hitl/approvalsFeed.d.ts +0 -183
- package/dist/hitl/approvalsFeed.js +12 -243
- package/dist/hitl/armedGateRegistry.d.ts +0 -55
- package/dist/hitl/armedGateRegistry.js +0 -146
- package/dist/hitl/askGateWire.d.ts +0 -86
- package/dist/hitl/askGateWire.js +1 -95
- package/dist/hitl/askParkRowRouting.d.ts +0 -123
- package/dist/hitl/askParkRowRouting.js +1 -89
- package/dist/hitl/crashConverged.d.ts +0 -148
- package/dist/hitl/crashConverged.js +0 -214
- package/dist/hitl/editedRuleTextPrecheck.d.ts +0 -109
- package/dist/hitl/editedRuleTextPrecheck.js +0 -71
- package/dist/hitl/frameRouter.d.ts +0 -134
- package/dist/hitl/frameRouter.js +6 -378
- package/dist/hitl/gateIdentity.d.ts +0 -39
- package/dist/hitl/gateIdentity.js +0 -41
- package/dist/hitl/gateLedger.d.ts +0 -267
- package/dist/hitl/gateLedger.js +0 -121
- package/dist/hitl/hitlBridge.d.ts +7 -431
- package/dist/hitl/hitlBridge.js +7 -476
- package/dist/hitl/hitlHostSurface.d.ts +0 -150
- package/dist/hitl/hitlHostSurface.js +0 -169
- package/dist/hitl/livePendingAsk.d.ts +0 -91
- package/dist/hitl/livePendingAsk.js +0 -74
- package/dist/hitl/localAllowRule.d.ts +0 -62
- package/dist/hitl/localAllowRule.js +1 -33
- package/dist/hitl/parkOwnership.d.ts +0 -56
- package/dist/hitl/parkOwnership.js +0 -22
- package/dist/hitl/parkResolver.d.ts +3 -88
- package/dist/hitl/parkResolver.js +8 -349
- package/dist/hitl/parkRowBirthWait.d.ts +2 -26
- package/dist/hitl/parkRowBirthWait.js +3 -93
- package/dist/hitl/persistedRulesWire.d.ts +13 -358
- package/dist/hitl/persistedRulesWire.js +0 -310
- package/dist/hitl/planReviewWire.d.ts +4 -176
- package/dist/hitl/planReviewWire.js +9 -312
- package/dist/hitl/resumeRunningCard.d.ts +0 -105
- package/dist/hitl/resumeRunningCard.js +0 -105
- package/dist/hitl/sessionPolicyWire.d.ts +11 -191
- package/dist/hitl/sessionPolicyWire.js +0 -149
- package/dist/hitl/suspendedReopen.d.ts +3 -24
- package/dist/hitl/suspendedReopen.js +0 -14
- package/dist/hitl/toolApprovalWire.d.ts +5 -1308
- package/dist/hitl/toolApprovalWire.js +5 -945
- package/dist/hooksWireCaps.d.ts +0 -38
- package/dist/hooksWireCaps.js +0 -190
- package/dist/host.d.ts +0 -105
- package/dist/host.js +0 -33
- package/dist/hostEnv.d.ts +0 -14
- package/dist/hostEnv.js +0 -13
- package/dist/imagesWireCaps.d.ts +0 -21
- package/dist/imagesWireCaps.js +0 -22
- package/dist/index.d.ts +0 -134
- package/dist/index.js +0 -476
- package/dist/interactiveHalt.d.ts +5 -153
- package/dist/interactiveHalt.js +0 -111
- package/dist/interactiveToolsWire.d.ts +0 -62
- package/dist/interactiveToolsWire.js +1 -67
- package/dist/leaderConflict.d.ts +0 -59
- package/dist/leaderConflict.js +0 -48
- package/dist/limitsWire.d.ts +0 -125
- package/dist/limitsWire.js +2 -120
- package/dist/liveInitToolFace.d.ts +0 -77
- package/dist/liveInitToolFace.js +1 -109
- package/dist/liveModelCatalog.d.ts +0 -52
- package/dist/liveModelCatalog.js +0 -48
- package/dist/liveQuestionStore.d.ts +0 -87
- package/dist/liveQuestionStore.js +1 -56
- package/dist/mcpLiveness.d.ts +0 -151
- package/dist/mcpLiveness.js +0 -122
- package/dist/mcpPanel.d.ts +0 -104
- package/dist/mcpPanel.js +0 -49
- package/dist/mcpReconnect.d.ts +0 -58
- package/dist/mcpReconnect.js +0 -69
- package/dist/mcpWireCaps.d.ts +0 -55
- package/dist/mcpWireCaps.js +1 -13
- package/dist/memoryComplianceCapability.d.ts +3 -57
- package/dist/memoryComplianceCapability.js +0 -57
- package/dist/memoryEntriesWire.d.ts +6 -198
- package/dist/memoryEntriesWire.js +0 -144
- package/dist/memoryOriginCapability.d.ts +3 -53
- package/dist/memoryOriginCapability.js +0 -50
- package/dist/memorySpecWire.d.ts +0 -116
- package/dist/memorySpecWire.js +0 -150
- package/dist/model/catalog.d.ts +0 -111
- package/dist/model/catalog.js +0 -87
- package/dist/model/catalogLoader.d.ts +0 -114
- package/dist/model/catalogLoader.js +2 -139
- package/dist/model/modelSupplyRules.d.ts +1 -55
- package/dist/model/modelSupplyRules.js +0 -62
- package/dist/model/providerAuth.d.ts +0 -103
- package/dist/model/providerAuth.js +2 -38
- package/dist/model/providerCatalog.d.ts +0 -45
- package/dist/model/providerCatalog.js +0 -37
- package/dist/model/providerPresets.d.ts +0 -33
- package/dist/model/providerPresets.js +2 -91
- package/dist/model/tierVocabulary.d.ts +0 -31
- package/dist/model/tierVocabulary.js +0 -27
- package/dist/modelBudgetRule.d.ts +0 -39
- package/dist/modelBudgetRule.js +0 -39
- package/dist/modelCapabilityProbe.d.ts +0 -175
- package/dist/modelCapabilityProbe.js +0 -147
- package/dist/modelWireCaps.d.ts +0 -13
- package/dist/modelWireCaps.js +0 -13
- package/dist/notifications.d.ts +0 -233
- package/dist/notifications.js +14 -492
- package/dist/oneShotWireCaps.d.ts +0 -34
- package/dist/oneShotWireCaps.js +0 -35
- package/dist/ownKey.d.ts +0 -33
- package/dist/ownKey.js +0 -33
- package/dist/panelRunningHistory.d.ts +0 -28
- package/dist/panelRunningHistory.js +0 -43
- package/dist/peerFrames.d.ts +0 -71
- package/dist/peerFrames.js +0 -168
- package/dist/peerLaneCapability.d.ts +0 -44
- package/dist/peerLaneCapability.js +0 -52
- package/dist/permissionRuleIssue.d.ts +0 -30
- package/dist/permissionRuleIssue.js +0 -78
- package/dist/permissionRulesWriteCapability.d.ts +0 -46
- package/dist/permissionRulesWriteCapability.js +0 -54
- package/dist/permissionWireCaps.d.ts +0 -37
- package/dist/permissionWireCaps.js +0 -37
- package/dist/postureKnob.d.ts +0 -71
- package/dist/postureKnob.js +0 -86
- package/dist/principalWire.d.ts +0 -17
- package/dist/principalWire.js +0 -17
- package/dist/printToolResultFrame.d.ts +0 -100
- package/dist/printToolResultFrame.js +0 -33
- package/dist/promptProfileWireCaps.d.ts +0 -13
- package/dist/promptProfileWireCaps.js +0 -13
- package/dist/readFacePosture.d.ts +0 -43
- package/dist/readFacePosture.js +0 -46
- package/dist/request/printNotification.d.ts +0 -20
- package/dist/request/printNotification.js +0 -55
- package/dist/request/taskRequest.d.ts +0 -249
- package/dist/request/taskRequest.js +6 -498
- package/dist/resumeRefusalCopy.d.ts +0 -136
- package/dist/resumeRefusalCopy.js +1 -117
- package/dist/retainBackgroundWireCaps.d.ts +0 -48
- package/dist/retainBackgroundWireCaps.js +0 -48
- package/dist/retryStatus.d.ts +2 -221
- package/dist/retryStatus.js +0 -107
- package/dist/rewindWireCaps.d.ts +0 -27
- package/dist/rewindWireCaps.js +0 -24
- package/dist/runCancelContext.d.ts +1 -20
- package/dist/runCancelContext.js +0 -34
- package/dist/runTerminal.d.ts +0 -273
- package/dist/runTerminal.js +0 -177
- package/dist/sandboxWire.d.ts +0 -38
- package/dist/sandboxWire.js +0 -82
- package/dist/scenarioWire.d.ts +0 -60
- package/dist/scenarioWire.js +0 -68
- package/dist/scratchpadWireCaps.d.ts +0 -11
- package/dist/scratchpadWireCaps.js +0 -32
- package/dist/sdkWireTransit.d.ts +0 -38
- package/dist/sdkWireTransit.js +0 -30
- package/dist/seam.d.ts +18 -853
- package/dist/seam.js +0 -52
- package/dist/seatContract.d.ts +0 -555
- package/dist/seatContract.js +5 -304
- package/dist/selfOrchestrationDenial.d.ts +0 -189
- package/dist/selfOrchestrationDenial.js +0 -162
- package/dist/selfOrchestrationWireCaps.d.ts +0 -38
- package/dist/selfOrchestrationWireCaps.js +0 -38
- package/dist/sessionMap.d.ts +0 -60
- package/dist/sessionMap.js +0 -37
- package/dist/sessionMemoryStatus.d.ts +11 -114
- package/dist/sessionMemoryStatus.js +0 -112
- package/dist/sessionModelLatch.d.ts +0 -29
- package/dist/sessionModelLatch.js +0 -40
- package/dist/sessionPolicyCapability.d.ts +3 -53
- package/dist/sessionPolicyCapability.js +0 -52
- package/dist/sessionSlot.d.ts +0 -26
- package/dist/sessionSlot.js +0 -17
- package/dist/skillsWireCaps.d.ts +0 -87
- package/dist/skillsWireCaps.js +0 -38
- package/dist/sqlEngineCapability.d.ts +0 -118
- package/dist/sqlEngineCapability.js +0 -134
- package/dist/sseIdleTriage.d.ts +0 -79
- package/dist/sseIdleTriage.js +1 -80
- package/dist/steering.d.ts +0 -54
- package/dist/steering.js +0 -63
- package/dist/subagent/engineCompactWire.d.ts +0 -34
- package/dist/subagent/engineCompactWire.js +4 -134
- package/dist/subagent/engineDelegatedPrompt.d.ts +0 -31
- package/dist/subagent/engineDelegatedPrompt.js +1 -103
- package/dist/subagent/engineRowStopGate.d.ts +0 -20
- package/dist/subagent/engineRowStopGate.js +0 -49
- package/dist/subagent/engineSubagentOutput.d.ts +0 -7
- package/dist/subagent/engineSubagentOutput.js +1 -51
- package/dist/subagent/engineSubagentResume.d.ts +2 -279
- package/dist/subagent/engineSubagentResume.js +2 -129
- package/dist/subagent/engineSubagentSteer.d.ts +0 -26
- package/dist/subagent/engineSubagentSteer.js +0 -63
- package/dist/subagent/engineSubagentTail.d.ts +0 -38
- package/dist/subagent/engineSubagentTail.js +2 -110
- package/dist/subagent/engineTaskHandleWire.d.ts +6 -67
- package/dist/subagent/engineTaskHandleWire.js +0 -126
- package/dist/subagent/subagentOwnerAbsence.d.ts +0 -2
- package/dist/subagent/subagentOwnerAbsence.js +0 -25
- package/dist/subagentContentStore.d.ts +3 -260
- package/dist/subagentContentStore.js +7 -540
- package/dist/systemReminderTag.d.ts +0 -49
- package/dist/systemReminderTag.js +0 -61
- package/dist/toolResult.d.ts +1 -211
- package/dist/toolResult.js +1 -358
- package/dist/toolRoster.d.ts +0 -140
- package/dist/toolRoster.js +0 -66
- package/dist/typePins.d.ts +0 -46
- package/dist/types/engineState.d.ts +0 -71
- package/dist/types/engineState.js +0 -16
- package/dist/ultracodeWireCaps.d.ts +0 -75
- package/dist/ultracodeWireCaps.js +0 -92
- package/dist/unrefTimer.d.ts +0 -27
- package/dist/webSearchBackendCapability.d.ts +0 -72
- package/dist/webSearchBackendCapability.js +0 -79
- package/dist/webSearchWireCaps.d.ts +0 -37
- package/dist/webSearchWireCaps.js +0 -34
- package/dist/websearch/searchProviderPresets.d.ts +0 -81
- package/dist/websearch/searchProviderPresets.js +0 -27
- package/dist/wireErrorTriage.d.ts +4 -160
- package/dist/wireErrorTriage.js +0 -171
- package/dist/wireRefusalCopy.d.ts +0 -28
- package/dist/wireRefusalCopy.js +0 -28
- package/dist/workflow.d.ts +0 -40
- package/dist/workflow.js +0 -52
- package/dist/workflowClient.d.ts +0 -122
- package/dist/workflowClient.js +8 -360
- package/dist/workflowMonitor.d.ts +2 -72
- package/dist/workflowMonitor.js +0 -26
- package/dist/writeProtectionCapability.d.ts +0 -112
- package/dist/writeProtectionCapability.js +0 -109
- package/docs/INTEGRATION-CLIENTS.md +30 -1
- package/package.json +1 -1
package/dist/workflowClient.js
CHANGED
|
@@ -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';
|
|
18
|
+
return 'running';
|
|
99
19
|
default:
|
|
100
|
-
return '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';
|
|
43
|
+
return 'parked';
|
|
126
44
|
case 'running':
|
|
127
45
|
return 'running';
|
|
128
46
|
default:
|
|
129
|
-
return 'unknown';
|
|
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';
|
|
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';
|
|
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';
|
|
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 () => {
|