@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
|
@@ -1,17 +1,3 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* parkResolver — HITL gate 桥**外环**的 park 决断(REF-CC-032 / SPLIT-12 第三刀,2026-08-02)。
|
|
3
|
-
*
|
|
4
|
-
* 内环(`frameRouter.ts`)带出一个 `GatePark` 之后,这里回答唯一一个问题:**接着读流,还是
|
|
5
|
-
* fail-soft 收场**。三条出路:
|
|
6
|
-
* · 决断成功 ⇒ `reattach`(驱动 attach `runs.events`,`lastEventId` 续传);
|
|
7
|
-
* · 「这个 gate 早就被解决了」(durable re-attach 必然重放已决断的 park)⇒ 同样 `reattach`;
|
|
8
|
-
* · 其余(overlay 缺席 / pending 蒸发 / decide 409/404 / turn 中断 / hop 预算耗尽)⇒ `failsoft`:
|
|
9
|
-
* flush HOLD 的毒化帧 + 原样吐 suspended 终帧(durable 腿无终帧则合成一条可见的 failed)。
|
|
10
|
-
*
|
|
11
|
-
* 🔴 本文件不碰流、不 yield:events 以数组交回驱动。`resolvePark` 的**返回值**就是它的全部对外
|
|
12
|
-
* 效果(台账写入除外,且台账写入全经 `GateLedger` 的动词)—— 于是「禁掉某条真臂」这种变异
|
|
13
|
-
* 在驱动的消费点上必然显形,而不是被本文件自己吞掉。
|
|
14
|
-
*/
|
|
15
1
|
import { putOwnKey } from '../ownKey.js';
|
|
16
2
|
import { DecideTransportRetryExhaustedError, HitlBridge, HitlSafetyError, findPendingForTask, readDecideCurrentPending, readWireErrorCode, } from './hitlBridge.js';
|
|
17
3
|
import { publishQuestionFrame, registerLocalQuestionResponder, hasQuestionOverlay, } from '../liveQuestionStore.js';
|
|
@@ -20,87 +6,21 @@ import { surfaceFsApprovalAndDecide } from './toolApprovalWire.js';
|
|
|
20
6
|
import { observeCancelByDeny } from './hitlHostSurface.js';
|
|
21
7
|
import { flushHeldWithInterruptRewrite, isAskTool } from './frameRouter.js';
|
|
22
8
|
import { approvalCallKey, askGateQuestionId } from './gateIdentity.js';
|
|
23
|
-
// B-070 / L-200(0.65.0):`/decide` 200 回执的单一读面(换挂句柄 + executionOutcome)。
|
|
24
9
|
import { readDecideReceipt } from '../decideReceipt.js';
|
|
25
|
-
/**
|
|
26
|
-
* L-80(2026-09-03,[6215];#357 复发):**连续非进展轮**上限 —— 数的是「壳再附着之后那段流里一个
|
|
27
|
-
* host 推进帧都没有」的轮次,**不是** park 次数。修前这里是 `24` 且按每次 park 递增
|
|
28
|
-
* (askGateWire `hops++` 无条件),于是一个 turn 里模型对同一失败 Edit 重试 24 次、每次真被门真被决,
|
|
29
|
-
* 也会在第 25 次撞成 `gate hop limit (24) exceeded`——一句与真因无关的预算话术。CC 没有这条预算:
|
|
30
|
-
* 模型问 N 次就答 N 次。本闸只留作最后防线:连续 N 轮零进展(坐标失配空转 / reopen 类 re-park /
|
|
31
|
-
* decide 出站恒断)才收场,收场前再呈一次收场卡、终帧带真因与出路。
|
|
32
|
-
*/
|
|
33
10
|
export const MAX_GATE_HOPS = 2;
|
|
34
|
-
/** 纯函数:上一轮预算 + 本轮判决 ⇒ 新预算(不就地改入参;`undefined` = 本 turn 第一轮)。 */
|
|
35
11
|
export function nextHopBudget(prev, round) {
|
|
36
12
|
const total = (prev?.total ?? 0) + 1;
|
|
37
13
|
return round === 'progress' ? { stalled: 0, total } : { stalled: (prev?.stalled ?? 0) + 1, total };
|
|
38
14
|
}
|
|
39
|
-
/** decide 出站瞬断耗尽臂(retryExhausted)的同因连续上限:第 3 次同因即诚实收场(修前该臂**无闸**)。 */
|
|
40
15
|
const MAX_TRANSPORT_REATTACHES = 2;
|
|
41
|
-
/**
|
|
42
|
-
* 硬兜底(对抗复审 r1 [high]①,r6 [high] 收窄):一 turn 内**解析不出身份**的 park 数上限。连续非进展计数靠
|
|
43
|
-
* 「解析到的 pending 行身份 + host 推进帧」判进展;解析不到行(tool-less park / approvals 恒空)时身份判不出 ⇒
|
|
44
|
-
* 只能靠推进帧,一个每轮先吐一帧文本再原样 park 的病态引擎在那一形下仍可能无限。**只数这一类**:每轮都解析到
|
|
45
|
-
* 新 call 且真推进的门(模型重试同一失败调用 N 次)不吃这格 —— CC 没有此闸,问 65 次就答 65 次。
|
|
46
|
-
* 命中即收场、终帧如实说「本 turn 有 N 次 park 解析不出身份」。
|
|
47
|
-
*/
|
|
48
16
|
export const MAX_TOTAL_PARKS = 64;
|
|
49
|
-
/**
|
|
50
|
-
* 「已解决 ⇒ reattach」臂的**同因连续命中上限**(#357,现网 P0;[5522] 定谳 / [5525] server 答复)。
|
|
51
|
-
* 同一判据源连续第 `N+1` 次命中即**不再** reattach。
|
|
52
|
-
*
|
|
53
|
-
* ── 病 ──────────────────────────────────────────────────────────────────────────────────────
|
|
54
|
-
* 用户批完两张卡,第三只门 16 分钟长等,最后吐 `gate hop limit (24) exceeded`,工具 abort,
|
|
55
|
-
* 而引擎侧 run 仍 parked。链:run 仍 parked 但取件当拍读不到本 run 的可决行 ⇒ 每一轮重放的 park
|
|
56
|
-
* 都命中「已解决」⇒ reattach ⇒ 引擎重放同一张 park ⇒ 循环到 hop 预算耗尽。24 轮里只有 debug 级
|
|
57
|
-
* 日志,用户零告知,拿到的还是一句与真因无关的预算话术。
|
|
58
|
-
*
|
|
59
|
-
* ── 两件修的分工(**别合并**)──────────────────────────────────────────────────────────────
|
|
60
|
-
* · **主修 = 坐标重探**({@link resolvePark} 的 rescan 臂):server [5525] 定谳这不是「状态失配」
|
|
61
|
-
* 而是**坐标失配** —— decide 受理后 resume **消费**掉 checkpoint(token 一次性),下一 turn 再
|
|
62
|
-
* 撞门就是**新 park / 新 token / 新行**;拿旧坐标去查/去决恒得 409 `approval_stale`(体
|
|
63
|
-
* terminal:"resolved")或 404 no-pending,逐字命中本文件的「已解决」判据集,而 run 真身是
|
|
64
|
-
* parked、**新行真实存在待决**。⇒ 命中「已解决」时先**重读当前队列**(丢掉这张 park 自带的
|
|
65
|
-
* 陈旧身份,让取件腿按当前拍的坐标选行):有行 ⇒ 这一轮就把**新卡**真呈给用户;确无行 ⇒ 才是
|
|
66
|
-
* #110 的重放窗,照旧 reattach。
|
|
67
|
-
* · **兜底 = 本闸**:重探自己也失配/读不动时(网络类、或队列确实空而 run 就是不动),不许再
|
|
68
|
-
* 空转 24 轮 —— 同因连续第 2 次即诚实收场,终帧带真因。
|
|
69
|
-
*
|
|
70
|
-
* 值 = 1 的理由:「已解决」判据的**正当性只覆盖一次重放窗**(#110 成文:`lastEventId` 再准也只能
|
|
71
|
-
* 精确到帧,park 就在重放窗里,而那个窗**只有一次**)。第二次同因命中意味着重探也没能把新坐标
|
|
72
|
-
* 找出来 —— 那时继续 reattach 只是把同一个空转再跑一遍。
|
|
73
|
-
* 🔴 {@link MAX_GATE_HOPS} 总闸**保留**(最后防线):本闸只管「已解决」这一条臂,别的臂
|
|
74
|
-
* (重呈臂每轮真呈卡)仍由总闸兜底。
|
|
75
|
-
*
|
|
76
|
-
* 🔴 键**按语义分不按表征分**(异源复审 finding③):「已解决」在 wire 上有 `no_pending` 码 /
|
|
77
|
-
* 409 体 `resolved` / 404 `not found` 三种长相,它们是同一个真因 —— 按长相分键的话,表征一轮换
|
|
78
|
-
* 计数就重置回 1,闸永远不触发。判据见 {@link alreadyResolvedStreakKey}。
|
|
79
|
-
*/
|
|
80
17
|
const MAX_ALREADY_RESOLVED_REATTACHES = 1;
|
|
81
|
-
/**
|
|
82
|
-
* REF-CC-033:`GateOutcome` 的 `failed` 分支闭集判别码。来源两处:①本文件自己的
|
|
83
|
-
* 「pending 行取不到」早退(`surfaceGateAndDecide` 里 `!pending` 那条);②`HitlBridge` 抛出的
|
|
84
|
-
* `HitlSafetyError.code`(hitlBridge.ts 契约:`binding_mismatch|no_pending|wrong_gate|bad_plan_edit`
|
|
85
|
-
* ——该属性今天仍是开集 `string`,TYPESHAPE-07/REF-CC-036 候后续车锁死;这里落地前用
|
|
86
|
-
* `isGateFailureCode` 按闭集白名单过滤,不认得的值一律降级成 `undefined`,退回文案兜底,不让
|
|
87
|
-
* 开集腐蚀这个新判别位)。消费点只认 `'no_pending'` 为「已解决」,其余码(binding_mismatch 等)
|
|
88
|
-
* 是真需要重新呈现给人的失败,不能走「继续读流」这条路。
|
|
89
|
-
*/
|
|
90
|
-
/**
|
|
91
|
-
* 白名单的**运行期真源**(FIX② 2026-08-07 由三处散落的 `===` 收成一份元组)。
|
|
92
|
-
* 🔴 与 `hitlBridge.HitlSafetyError.code` 的联合是**同一个闭集的两半**:下方 `_gateFailureCodePins`
|
|
93
|
-
* 双向钉住,任何一边加员而另一边不跟 ⇒ 编译红。此前两边靠人肉同步,而不同步的可观测后果是
|
|
94
|
-
* 「新码被 `isGateFailureCode` 降成 undefined 后静默走文案兜底臂」—— 门里长得跟正常一模一样。
|
|
95
|
-
*/
|
|
96
18
|
export const GATE_FAILURE_CODES = [
|
|
97
19
|
'no_pending',
|
|
98
20
|
'binding_mismatch',
|
|
99
21
|
'wrong_gate',
|
|
100
22
|
'bad_plan_edit',
|
|
101
|
-
/** 0.72.13 CC-46:plan-review 的 permissionModeAfter 坏形(非 approve 带这一位 / 词表外)被本地拦下。 */
|
|
102
23
|
'bad_plan_mode',
|
|
103
|
-
/** FIX②:空作答被本地拦下(空 answers[] / 空 selected[] / 空 header)。 */
|
|
104
24
|
'empty_answer',
|
|
105
25
|
];
|
|
106
26
|
const _gateFailureCodePins = [true, true];
|
|
@@ -108,66 +28,26 @@ void _gateFailureCodePins;
|
|
|
108
28
|
function isGateFailureCode(v) {
|
|
109
29
|
return typeof v === 'string' && GATE_FAILURE_CODES.includes(v);
|
|
110
30
|
}
|
|
111
|
-
/**
|
|
112
|
-
* decide 的 `failed` 原因是不是「这个 gate 早就被解决了」(#110 缺陷② c 的判据)。
|
|
113
|
-
*
|
|
114
|
-
* REF-CC-033:此前判据**只**锚在文案词(`no pending checkpoint` / `resolved` / `already` 三者
|
|
115
|
-
* 任一在场)——server 原文改一个字,整条命中当场失效(FIX-13 / 域词表-01)。现在消费点(见下方
|
|
116
|
-
* `isAlreadyResolvedFailure`)优先判 `GateOutcome.code`(闭集判别位,见 `GateFailureCode`);
|
|
117
|
-
* 这个函数降级为**文案兜底臂**,只在 outcome 没带 code 的时候才被调用(典型:`FsApprovalOutcome`
|
|
118
|
-
* 来自 `toolApprovalWire.ts`,那份类型今天没有 code 字段——C-bridge 卡的文件域,本卡不改)。
|
|
119
|
-
* 🔴 方向没变:这条判**错**的后果不对称 —— 误判成「已解决」最多让流多读一轮(hop 预算兜底),
|
|
120
|
-
* 误判成「真失败」会把一个已经 completed 的 run 谎报成失败并烧掉整条会话转录。所以宁可宽。
|
|
121
|
-
*/
|
|
122
|
-
/** #114/[C68] 单源化提升:desktop 照抄件(durable 双实现审计 P0-1 修)到货换包导入删抄件。
|
|
123
|
-
* [C106] 收编 `not found` 形(2026-08-05):引擎对已批门的 deny 回 `approval not found`
|
|
124
|
-
* (desktop 实测——parked 刚批完、decide 未返回的竞态窗内 Stop 走 parked-deny 路),旧词表
|
|
125
|
-
* 判不中 ⇒ 按真失败 log-only 放弃 ⇒ runs.cancel 永不发出=Stop 哑弹。按上方「宁可宽」方向收编。 */
|
|
126
31
|
export function isAlreadyResolvedGateReason(reason) {
|
|
127
32
|
return alreadyResolvedReasonToken(reason) !== undefined;
|
|
128
33
|
}
|
|
129
|
-
/**
|
|
130
|
-
* 文案兜底臂的**词表**(判据本体;`isAlreadyResolvedGateReason` 是它的布尔投影)。
|
|
131
|
-
* 🔴 #357 把它从「四个 `||` 就地写死」抽成词表,**行为一个字节不变**:一处词表,两个消费点
|
|
132
|
-
* (布尔判定 + 诊断串里「是哪个词命中的」),此前后者只能靠人再读一遍那四个 `||`。
|
|
133
|
-
* 🔴 命中的词**不进限次闸的键** —— 键按语义分,理由见 {@link alreadyResolvedStreakKey}。
|
|
134
|
-
*/
|
|
135
34
|
const ALREADY_RESOLVED_REASON_TOKENS = ['no pending checkpoint', 'resolved', 'already', 'not found'];
|
|
136
|
-
/** 命中的那个词(没命中 ⇒ `undefined`)。顺序即优先级,只进诊断串,不参与判定强弱。 */
|
|
137
35
|
function alreadyResolvedReasonToken(reason) {
|
|
138
36
|
if (typeof reason !== 'string')
|
|
139
37
|
return undefined;
|
|
140
38
|
const r = reason.toLowerCase();
|
|
141
39
|
return ALREADY_RESOLVED_REASON_TOKENS.find((t) => r.includes(t));
|
|
142
40
|
}
|
|
143
|
-
/** 已解决判据(REF-CC-033):code 在场就只信 code,不在场才落回文案兜底。
|
|
144
|
-
* ✅ **记案已销**(#357,0.47.0):原注末句写的是「fs 审批腿的 `FsApprovalOutcome` 今天没有
|
|
145
|
-
* code 字段——C-bridge 卡域,退役条件 = 那边也补上 code」。那个退役条件已兑现:取件腿的
|
|
146
|
-
* `no_pending` 码现在由 `toolApprovalWire.surfaceFsApprovalAndDecide` 原样透传(见
|
|
147
|
-
* `FsApprovalOutcome.code` 头注),两条腿从此同走 code 臂;文案兜底只剩 decide 失败那一类
|
|
148
|
-
* (引擎的 409/404 语义答复文本)与旧引擎路径。
|
|
149
|
-
* 🔴 入参**已经**是窄化到 `{kind:'failed'}` 的那半:一个「true ⇒ 是 failed」的判定不能反过来
|
|
150
|
-
* 当「false ⇒ 不是 failed」的类型谓词用(TS 的 `outcome is Extract<…>` 负向窄化会把整个
|
|
151
|
-
* `'failed'` 分支从联合类型里排除,而这个函数对未解决的真失败照样返回 false——那不是「它不是
|
|
152
|
-
* failed」,是「它是 failed 但没解决」。调用点先用 `outcome.kind === 'failed'` 做真正的判别式
|
|
153
|
-
* 窄化,再把窄化后的值交给这里,本函数只回答布尔,不再兼职类型谓词。 */
|
|
154
41
|
function isAlreadyResolvedFailure(outcome) {
|
|
155
42
|
const code = 'code' in outcome && isGateFailureCode(outcome.code) ? outcome.code : undefined;
|
|
156
43
|
return code !== undefined ? code === 'no_pending' : isAlreadyResolvedGateReason(outcome.reason);
|
|
157
44
|
}
|
|
158
|
-
/** 把 wire 答案({answers:[{header,selected,note?}]})折回 CC 卡片的 Record<question,string> 形状
|
|
159
|
-
* (multiSelect 与对话框同款 ", " lossy join;note → annotations.notes)。 */
|
|
160
45
|
export function toAnsweredOutput(questions, answer) {
|
|
161
46
|
const answers = {};
|
|
162
47
|
const annotations = {};
|
|
163
48
|
for (const entry of answer.answers ?? []) {
|
|
164
49
|
const q = questions.find(qq => qq.header === entry.header);
|
|
165
50
|
const key = typeof q?.question === 'string' ? q.question : entry.header;
|
|
166
|
-
// 🔴 0.68.0 / L-246 B2:落键走**单源** `putOwnKey`(`src/ownKey.ts`)。修前这里是一只内联的
|
|
167
|
-
// 同形实现,与 `adapter/downstream/terminalToSdkResult.ts` 的那一份各写各的 —— 陷阱与取舍
|
|
168
|
-
// 的完整说明现在只在那个模块的头注里一份。`key` 来自 wire(问题正文 / header),字面等于
|
|
169
|
-
// `"__proto__"` 时裸赋值走的是 `Object.prototype` 上那只 accessor:`answers` 那一格(串值)
|
|
170
|
-
// 整条静默丢失,`annotations` 那一格(对象值)还顺手改了表自己的原型。
|
|
171
51
|
putOwnKey(answers, key, (entry.selected ?? []).join(', '));
|
|
172
52
|
if (entry.note)
|
|
173
53
|
putOwnKey(annotations, key, { notes: entry.note });
|
|
@@ -179,37 +59,20 @@ export function toAnsweredOutput(questions, answer) {
|
|
|
179
59
|
...(Object.keys(annotations).length > 0 ? { annotations } : {}),
|
|
180
60
|
};
|
|
181
61
|
}
|
|
182
|
-
|
|
183
|
-
* 弹既有 AskUserQuestion overlay → 等作答 → 经 HitlBridge decide(答案/拒答)。
|
|
184
|
-
* decide 成功即引擎已把 run 驱到下一状态(sync);调用方随后 attach runs.events 续流。
|
|
185
|
-
*/
|
|
186
|
-
async function surfaceGateAndDecide(deps, taskId, askArgsByCall, signal,
|
|
187
|
-
/** 这张 park 的待批 call 身份(server ≥7.41.0;缺席是常态)。语义与不 fail-closed 的理由
|
|
188
|
-
* 与 fs 腿同一条,见 `toolApprovalWire.surfaceFsApprovalAndDecide` 的同名参数头注。 */
|
|
189
|
-
parkGatedCallId, onPresented) {
|
|
62
|
+
async function surfaceGateAndDecide(deps, taskId, askArgsByCall, signal, parkGatedCallId, onPresented) {
|
|
190
63
|
if (!hasQuestionOverlay()) {
|
|
191
64
|
return { kind: 'failed', stage: 'card', reason: 'no question overlay mounted (print/non-REPL mode)' };
|
|
192
65
|
}
|
|
193
|
-
|
|
194
|
-
// REF-CC-029(单源取件)+ REF-CC-033(no_pending 判别码):findPendingForTask 是唯一取件口
|
|
195
|
-
// (三份近似复刻已收敛),其失败形带 code 判别位,本处原样透传给 GateOutcome ——
|
|
196
|
-
// 「没有待决 gate」(良性,park 重放常见)与「approvals.list 真失败」自此结构可分。
|
|
197
|
-
const found = await findPendingForTask(deps.client, taskId, isAskTool, signal ? { signal } : undefined, parkGatedCallId, // 身份在场 ⇒ 逐字命中优先;缺席/不命中 ⇒ 原两腿(不 fail-closed,理由见参数头注)
|
|
198
|
-
// 本腿的族就是 ask 一族(整行可读闸的 ask 半场,与 fs 腿的 `isToolApprovalGate` 对称)。
|
|
199
|
-
(row) => isAskTool(typeof row.toolName === 'string' ? row.toolName : undefined));
|
|
66
|
+
const found = await findPendingForTask(deps.client, taskId, isAskTool, signal ? { signal } : undefined, parkGatedCallId, (row) => isAskTool(typeof row.toolName === 'string' ? row.toolName : undefined));
|
|
200
67
|
if (!found.ok)
|
|
201
68
|
return { kind: 'failed', stage: 'fetch', reason: found.reason, ...(found.code !== undefined ? { code: found.code } : {}) };
|
|
202
69
|
const { pending, gatedCallId } = found;
|
|
203
|
-
// 问题 payload:优先流上 tool_start.args(零额外语义),缺则 pending.input(service 已 redact + 限长)。
|
|
204
70
|
const fromArgs = gatedCallId
|
|
205
71
|
? askArgsByCall.get(gatedCallId)?.questions
|
|
206
72
|
: undefined;
|
|
207
73
|
const fromPending = pending.input?.questions;
|
|
208
74
|
const questions = Array.isArray(fromArgs) && fromArgs.length > 0 ? fromArgs : fromPending;
|
|
209
75
|
if (!Array.isArray(questions) || questions.length === 0) {
|
|
210
|
-
// [1543]②:input 超引擎入参帽(MAX_TOOL_INPUT_CHARS,preview 富文本题易中)时 server 降级为
|
|
211
|
-
// {truncated:true} ——无题可渲不是引擎代差,是 payload 被截。分形出诚实理由(fail-soft 链
|
|
212
|
-
// 会把 reason 记入 SEMA_DEBUG,别再误导成 pre-CHANNEL[56] 老引擎)。
|
|
213
76
|
const truncated = pending.input?.truncated === true;
|
|
214
77
|
return {
|
|
215
78
|
kind: 'failed',
|
|
@@ -220,8 +83,6 @@ parkGatedCallId, onPresented) {
|
|
|
220
83
|
: 'gate has no question payload (pre-CHANNEL[56] engine?)',
|
|
221
84
|
};
|
|
222
85
|
}
|
|
223
|
-
// overlay 往返:合成 frame(id 独占命名空间 hitl-ask:)→ local responder 一次性收答。
|
|
224
|
-
// A-028.3:id 经 gateIdentity 唯一铸口(呈现台账/壳侧重开腿的键推导同源,字面不再各铸各的)。
|
|
225
86
|
const questionId = askGateQuestionId(approvalCallKey(gatedCallId, taskId));
|
|
226
87
|
const answer = await new Promise(resolve => {
|
|
227
88
|
const unregister = registerLocalQuestionResponder(questionId, async (_id, a) => {
|
|
@@ -231,7 +92,6 @@ parkGatedCallId, onPresented) {
|
|
|
231
92
|
});
|
|
232
93
|
const onAbort = () => {
|
|
233
94
|
cleanup();
|
|
234
|
-
// 撤下还开着的对话框(question_complete = overlay 的既有 dismiss 语义)
|
|
235
95
|
publishQuestionFrame({ type: 'question_complete', questionId });
|
|
236
96
|
resolve(null);
|
|
237
97
|
};
|
|
@@ -244,42 +104,20 @@ parkGatedCallId, onPresented) {
|
|
|
244
104
|
return;
|
|
245
105
|
}
|
|
246
106
|
signal?.addEventListener('abort', onAbort, { once: true });
|
|
247
|
-
onPresented?.();
|
|
107
|
+
onPresented?.();
|
|
248
108
|
publishQuestionFrame({ type: 'question', questionId, questions });
|
|
249
109
|
});
|
|
250
110
|
const bridge = new HitlBridge(deps.client, taskId);
|
|
251
111
|
if (answer === null) {
|
|
252
|
-
// turn 被中断(Esc/Ctrl+C):把这只挂着的 ask 用一次 **TOOL 级 deny** 结算掉,好让 run 不停在
|
|
253
|
-
// suspended 上(server `ASSISTANT-WIRE-CONTRACT.md` §4a)。
|
|
254
|
-
// 🔴 **0.42.0 撤稿**:原文写的是「cancel-by-deny(contract/04 §2.4 —— suspended run 不
|
|
255
|
-
// runs.cancel)」。那条引用的两个前提都已作废 —— §4a 逐字说 DENY 是 tool 级应答**永远不是**
|
|
256
|
-
// run kill;而「suspended run 不能 runs.cancel」自 server [868] 起就不成立(就地取消已实装,
|
|
257
|
-
// 本仓 fresh-scan B型-5 按真字节证伪)。这里选 deny 不是因为 cancel 不可用,是因为**这一刻
|
|
258
|
-
// 要处理的就是一只挂着的 ask**:先把它结算掉,run 才走得下去。下方那句「引擎侧解锁腿到货前」
|
|
259
|
-
// 同批订正:那条腿早就到货了,本臂保留的理由变成「结算 ask 是这一步的正解」,不再是权宜。
|
|
260
|
-
// 件3(中断事故修复批 G,2026-07-15,症状1 壳侧配套):此前 .catch(()=>{}) 全吞 = deny 丢失时
|
|
261
|
-
// run 永卡 suspended,session 锁死,用户下一条消息撞 409「active run」还全无线索。改为有界观察
|
|
262
|
-
// (observeCancelByDeny,2s 预算):abort 仍立即返回用户控制(不 await,交互时序不变),后台
|
|
263
|
-
// settle 失败/超时上屏一行 warn + SEMA_DEBUG 记失败原因。
|
|
264
|
-
// 🔴 **0.42.0 订正**:本段原文以「引擎侧解锁腿([866] server:cancel suspended 改语义 +
|
|
265
|
-
// reapSuspended TTL)**到货前**,这是壳能做的最诚实半场」收尾 —— 那条腿早已到货
|
|
266
|
-
// (server [868] 起 suspended run 就地取消 + `reapSuspended` 实体在,fresh-scan B型-5 已按
|
|
267
|
-
// 真字节证伪)。本臂**不是**在等一条不存在的上游腿:它保留的理由是「这一刻要处理的就是一只
|
|
268
|
-
// 挂着的 ask,先结算它 run 才走得下去」。观察器的预算论证前提见 `CANCEL_DENY_BUDGET_MS` 头注
|
|
269
|
-
// 的重审段(同批 §2.4 撤稿件)。
|
|
270
112
|
observeCancelByDeny(bridge.decideTool({ decision: 'deny', reason: 'Interrupted by user' }, gatedCallId, undefined, pending), taskId);
|
|
271
113
|
return { kind: 'aborted', gatedCallId };
|
|
272
114
|
}
|
|
273
115
|
let declinedReceipt;
|
|
274
116
|
try {
|
|
275
|
-
// REF-CC-038(2026-08-02):`answer.answers` 已经是 `AskAnswer[]`(liveQuestionStore 的
|
|
276
|
-
// `QuestionAnswer` 直用 hitlBridge 的 `AskAnswer` 为唯一源)—— 不再需要靠 cast 把两个
|
|
277
|
-
// 名不同的等价形状缝合。
|
|
278
117
|
const entries = answer.answers ?? [];
|
|
279
118
|
const hasContent = entries.some(a => (a.selected?.length ?? 0) > 0 || (a.note?.length ?? 0) > 0);
|
|
280
119
|
if (hasContent) {
|
|
281
120
|
const raw = await bridge.answerQuestion(entries, gatedCallId, signal ? { signal } : undefined, pending);
|
|
282
|
-
// B-070:回执原样读一次(缺席即缺席);两条腿同形 —— fs 腿在 `toolApprovalWire` 的三处。
|
|
283
121
|
const receipt = readDecideReceipt(raw);
|
|
284
122
|
return {
|
|
285
123
|
kind: 'decided',
|
|
@@ -289,20 +127,14 @@ parkGatedCallId, onPresented) {
|
|
|
289
127
|
};
|
|
290
128
|
}
|
|
291
129
|
else {
|
|
292
|
-
// 用户拒答(overlay reject/dismiss 送空 answers)= 诚实 deny;模型收 denied 结果自续。
|
|
293
130
|
const raw = await bridge.decideTool({ decision: 'deny', reason: 'User declined to answer' }, gatedCallId, signal ? { signal } : undefined, pending);
|
|
294
131
|
declinedReceipt = readDecideReceipt(raw);
|
|
295
132
|
}
|
|
296
133
|
return { kind: 'decided', gatedCallId, ...(declinedReceipt !== undefined ? { receipt: declinedReceipt } : {}) };
|
|
297
134
|
}
|
|
298
135
|
catch (e) {
|
|
299
|
-
// REF-CC-033:HitlSafetyError.code 是 hitlBridge.ts 自己的闭集契约(见其类型头注),
|
|
300
|
-
// 这里 instanceof 窄化后再过 isGateFailureCode 白名单——不认得的码(将来 hitlBridge 那边
|
|
301
|
-
// 万一多加一种)一律降级成 undefined,退回文案兜底,不让开集腐蚀这个新判别位。
|
|
302
136
|
const code = e instanceof HitlSafetyError && isGateFailureCode(e.code) ? e.code : undefined;
|
|
303
|
-
// #363:S-02 指路键原样透传 —— 与 `toolApprovalWire` 两条 decide 失败腿同形同源。
|
|
304
137
|
const currentPending = readDecideCurrentPending(e);
|
|
305
|
-
// 0.60.0(候包件 ②):引擎机器码原样透传 —— 与 fs 腿两条 decide 失败腿同形同源。
|
|
306
138
|
const wireCode = readWireErrorCode(e);
|
|
307
139
|
return {
|
|
308
140
|
kind: 'failed',
|
|
@@ -310,100 +142,45 @@ parkGatedCallId, onPresented) {
|
|
|
310
142
|
gatedCallId,
|
|
311
143
|
reason: `decide failed: ${String(e)}`,
|
|
312
144
|
...(code !== undefined ? { code } : {}),
|
|
313
|
-
// Inkglow-1085 P0a:ask 腿与 fs 腿同形 —— 瞬断耗尽给判别位,resolvePark 走重呈臂。
|
|
314
145
|
...(e instanceof DecideTransportRetryExhaustedError ? { retryExhausted: true } : {}),
|
|
315
146
|
...(currentPending !== undefined ? { currentPending } : {}),
|
|
316
147
|
...(wireCode !== undefined ? { errorCode: wireCode } : {}),
|
|
317
148
|
};
|
|
318
149
|
}
|
|
319
150
|
}
|
|
320
|
-
/** 台账里那批 gated `tool_start` 当拍 args 快照 → 决断腿要的 `toolCallId → args` 表(UNTRUSTED 原样搬运)。 */
|
|
321
151
|
function argsByCallOf(led) {
|
|
322
152
|
return new Map(led.gatedStartArgs());
|
|
323
153
|
}
|
|
324
|
-
/**
|
|
325
|
-
* 限次闸的**判据源**(键)——「是哪一**条判据**把这一轮判成已解决的」。
|
|
326
|
-
*
|
|
327
|
-
* 🔴 键**按语义分,不按表征分**(异源复审 finding③ 的采纳):「队列里没有本 run 的可决行」这件事
|
|
328
|
-
* 在 wire 上有好几种长相 —— 取件读到空表落 `code:'no_pending'`,server 的 409 `approval_stale`
|
|
329
|
-
* (体 terminal:"resolved")/ 404 落文案臂的 `resolved` / `not found`。它们是**同一个真因的三种
|
|
330
|
-
* 说法**;按长相分键的话,一个卡死的 gate 只要在这几种表征之间轮换,连续计数就一路重置回 1,
|
|
331
|
-
* 闸永远不触发 —— 正是本闸要消灭的那个空转([anchor-on-the-deciding-quantity]:锚真正决定结果
|
|
332
|
-
* 的量,不锚它的表征)。命中的那个词只进诊断串,不进键。
|
|
333
|
-
*
|
|
334
|
-
* 只有身份腿(`decidedGates` 一次性匹配)另占一个键:它与「已解决」是两条独立判据,而且它一次性
|
|
335
|
-
* 消费、连续最多命中一次,天然不会把闸推到跳闸线。
|
|
336
|
-
*/
|
|
337
154
|
function alreadyResolvedStreakKey(byDecidedIdOnly) {
|
|
338
155
|
return byDecidedIdOnly ? 'decided-id-match' : 'already-resolved';
|
|
339
156
|
}
|
|
340
|
-
/**
|
|
341
|
-
* 这一轮的失败是不是「**取件那一步**就没找到本 run 的可决行」—— 即坐标重探唯一有资格跑的那一形。
|
|
342
|
-
*
|
|
343
|
-
* 🔴 判据锚在**结构**上,不锚文案:`code === 'no_pending'`(取件腿的结构化判别位,两条呈卡腿
|
|
344
|
-
* 今天都透传它)**且** `gatedCallId` 缺席。后半条是承重的 —— 两条呈卡腿里,`findPendingForTask`
|
|
345
|
-
* 失败那一条是**唯一**不带 `gatedCallId` 的 failed 出口(行都没选出来,哪来的 call 身份);它之后
|
|
346
|
-
* 的每一个失败出口(卡口缺席 / 无 payload / decide 4xx,包括 `HitlSafetyError.code==='no_pending'`)
|
|
347
|
-
* 都带着 `gatedCallId`。于是这条判据同时证明了一件承重的事:**这一轮没有向用户呈过卡**。
|
|
348
|
-
*
|
|
349
|
-
* 🔴 为什么必须证明「没呈过卡」(异源复审 finding② 的采纳):重探会把整条呈卡腿**再走一遍**。
|
|
350
|
-
* 若允许它在「卡已经呈过、用户答了、decide 回了一句带 resolved 字样的 409」之后跑,用户会在同一轮
|
|
351
|
-
* 里被同一张卡问第二遍(而且可能给出与第一次不同的答案)。把重探限定在取件步失败这一形,
|
|
352
|
-
* 「同一轮重复呈卡」在结构上就不成立。代价:decide 步的 stale 409 不再就地重探 —— 那一形照旧
|
|
353
|
-
* reattach 一次(durable 流本就会把 park 再送一遍),第二次同因命中由限次闸诚实收场。
|
|
354
|
-
*/
|
|
355
157
|
function isFetchStepNoPending(outcome) {
|
|
356
158
|
const code = 'code' in outcome && isGateFailureCode(outcome.code) ? outcome.code : undefined;
|
|
357
159
|
return code === 'no_pending' && outcome.gatedCallId === undefined;
|
|
358
160
|
}
|
|
359
|
-
/**
|
|
360
|
-
* 「呈这张 park 的卡 → 等人决断 → decide」的**唯一**入口(两族各一条腿;fs 腿的 denied 记账随行)。
|
|
361
|
-
*
|
|
362
|
-
* 🔴 #357 抽成一处的理由不是去重:坐标重探臂要用**当前拍的坐标**再走一次同一条腿,两处各写一份
|
|
363
|
-
* 的话,「第一次走的路」与「重探走的路」会各自漂(记账少一笔 / 族判据不同 ⇒ 决断落到另一行)。
|
|
364
|
-
*
|
|
365
|
-
* @param gatedCallId 交给取件腿的**身份**(wire 给的 park 身份;缺席是常态)。首击与坐标重探
|
|
366
|
-
* 传的是**同一个值** —— 重探要的是读数新鲜,不是判据放宽,理由见调用点的红线注。
|
|
367
|
-
*/
|
|
368
161
|
async function surfaceParkGate(park, ctx, gatedCallId, onPresented) {
|
|
369
162
|
const { deps, led, taskId } = ctx;
|
|
370
163
|
if (park.gate === 'fs') {
|
|
371
|
-
// [816] 放宽腿:fs 写权限 gate → CC 三选卡(vendored PermissionRequest)→ decide。
|
|
372
164
|
const outcome = await surfaceFsApprovalAndDecide({ client: deps.client, ...(onPresented ? { onPresented } : {}) }, taskId, argsByCallOf(led), ctx.signal, gatedCallId);
|
|
373
|
-
// #51: `outcome`'s declared type is the wider `GateOutcome |
|
|
374
|
-
// FsApprovalOutcome`; both unions share a 'decided' kind with
|
|
375
|
-
// different optional fields (`answered` vs `denied`), so a plain
|
|
376
|
-
// `.denied` access doesn't hold for every 'decided' member even
|
|
377
|
-
// though this branch only ever assigns the FsApprovalOutcome shape.
|
|
378
|
-
// 'in' narrowing sidesteps it.
|
|
379
165
|
const outcomeDenied = 'denied' in outcome ? outcome.denied : undefined;
|
|
380
166
|
if (outcome.kind === 'decided' && outcomeDenied === true && outcome.gatedCallId) {
|
|
381
|
-
led.markDenied(outcome.gatedCallId);
|
|
167
|
+
led.markDenied(outcome.gatedCallId);
|
|
382
168
|
}
|
|
383
169
|
return outcome;
|
|
384
170
|
}
|
|
385
171
|
return surfaceGateAndDecide(deps, taskId, argsByCallOf(led), ctx.signal, gatedCallId, onPresented);
|
|
386
172
|
}
|
|
387
173
|
export async function resolvePark(park, ctx) {
|
|
388
|
-
// `deps` 不在本函数直读:呈卡/决断两族腿统一经 `surfaceParkGate`(#357 单源化,见其头注)。
|
|
389
174
|
const { led, taskId } = ctx;
|
|
390
175
|
let outcome;
|
|
391
|
-
// REF-CC-034:这次 park 的候选 callId(仅 fs 分支填,已决断身份匹配用)——ask 分支不填,
|
|
392
|
-
// 因为 `surfaceGateAndDecide` 的 `!pending` 早退已经自带 `code:'no_pending'`(REF-CC-033),
|
|
393
|
-
// 不需要这条第二判据。用 `lastFsOrShellGatedCallId()` 而非「未收口 fs call 栈」:durable
|
|
394
|
-
// re-attach 重放的 `suspended` park 没有配套的新 tool_start/tool_end,那个栈在这次重放之前
|
|
395
|
-
// 早被 tool_end 的 drop 清空了(见台账声明处注),取不到候选。
|
|
396
176
|
let candidateGatedCallId;
|
|
397
177
|
const stalledRounds = ctx.stalledRounds ?? 0;
|
|
398
178
|
let closingCardTried = false;
|
|
399
|
-
// 呈现回执(对抗复审 r2 [medium]②③):每次 resolvePark 各自一枚旗,fs 腿经 deps.onPresented、ask 腿经
|
|
400
|
-
// publishQuestionFrame 前的同一枚旗置位;并发会话互不串扰,规则直决/取件失败恒 false。
|
|
401
179
|
let presentedThisRound = false;
|
|
402
180
|
const witness = () => {
|
|
403
181
|
presentedThisRound = true;
|
|
404
182
|
};
|
|
405
183
|
if ((ctx.unverifiableParks ?? 0) > MAX_TOTAL_PARKS) {
|
|
406
|
-
// 硬兜底:见 MAX_TOTAL_PARKS 头注(只数解析不出身份的 park)。不呈收场卡,终帧如实。
|
|
407
184
|
closingCardTried = true;
|
|
408
185
|
outcome = {
|
|
409
186
|
kind: 'failed',
|
|
@@ -412,13 +189,10 @@ export async function resolvePark(park, ctx) {
|
|
|
412
189
|
};
|
|
413
190
|
}
|
|
414
191
|
else if (stalledRounds > MAX_GATE_HOPS) {
|
|
415
|
-
// 最后防线:连续 N 轮零进展。收场前**再呈一次收场卡**(现读队列的可决行,用户面能看见能答),
|
|
416
|
-
// 真呈出来且决了就按决断走;呈不出/仍失败才 failsoft,终帧带真因与出路(不再是预算话术)。
|
|
417
192
|
closingCardTried = true;
|
|
418
193
|
const stalledReason = `the run stayed parked across ${stalledRounds} consecutive re-attach rounds without any host progress ` +
|
|
419
194
|
`(last: ${ctx.lastStallReason ?? 'unknown'})`;
|
|
420
195
|
if (ctx.lastRoundPresentedCard === true) {
|
|
421
|
-
// 上一轮已经把卡呈给用户、用户也答了、引擎还是原样 park 回来 —— 再呈一次只是把同一张失效卡再问一遍。
|
|
422
196
|
outcome = { kind: 'failed', stage: 'orchestration', reason: stalledReason };
|
|
423
197
|
}
|
|
424
198
|
else {
|
|
@@ -434,66 +208,21 @@ export async function resolvePark(park, ctx) {
|
|
|
434
208
|
candidateGatedCallId = led.lastFsOrShellGatedCallId();
|
|
435
209
|
outcome = await surfaceParkGate(park, ctx, park.gatedCallId, witness);
|
|
436
210
|
}
|
|
437
|
-
// #110 缺陷② b/c —— **重放的、早已决断过的 park 不是失败**。
|
|
438
|
-
// durable re-attach 必然会把 park 帧再送一遍(`lastEventId` 再准也只能精确到帧,park 就在
|
|
439
|
-
// 重放窗口里)。这时 approval 行早已 resolved,`surfaceFsApprovalAndDecide` 取不到 pending,
|
|
440
|
-
// 返回 `failed: no pending checkpoint for this run (resolved/expired?)` —— 那句话的语义恰恰是
|
|
441
|
-
// **「这个 gate 已经被解决了」**,正确处置是**继续读流**(引擎那边 run 正常往下跑,实测
|
|
442
|
-
// `run.json status="completed"`),而不是宣布 turn 失败。旧行为的代价不是一句错文案:
|
|
443
|
-
// 终帧被投影成 `error_during_execution` ⇒ 壳走失败路径 ⇒ CC 转录**一行都不写** ⇒
|
|
444
|
-
// 同 session `--resume` 报 `No conversation found` ⇒ **整个会话废掉**。
|
|
445
|
-
// 无限循环由 `hops > MAX_GATE_HOPS` 兜底(本 reattach 照常吃 hop 预算,不绕过它)。
|
|
446
|
-
//
|
|
447
|
-
// REF-CC-034:`isAlreadyResolvedFailure` 是首选判据(code/文案双臂;#357 起 fs 腿的取件码也
|
|
448
|
-
// 走 code 臂,见该函数头注的销案段)。失败原因若两臂都判不出(例如 `approvals.list` 自身网络
|
|
449
|
-
// 失败),已决断身份匹配是独立于文案的第二判据 —— 两臂任一命中都按「已解决」处置,方向偏宽
|
|
450
|
-
// (见台账 `markDecided` 处注)。
|
|
451
|
-
//
|
|
452
|
-
// [2393] hitl-F2(2026-08-02):这条身份判据**一次性消费**(`takeDecided` 而不是 `isDecided`)。
|
|
453
|
-
// 它的正当性只覆盖「durable re-attach 把**那一次**已决断的 park 重放一遍」这一个窗口,而它的两个
|
|
454
|
-
// 输入都是单调的(`lastFsOrShellGatedCallId()` 故意不随 tool_end 清空 + `decidedGates` 只增),
|
|
455
|
-
// 不消费就等于:本 turn 只要成功决断过一次,之后**每一次** park 失败都被判「已解决」——
|
|
456
|
-
// `approvals.list` 网络失败这类真失败会连吃 24 个 hop,最后吐一句与真因无关的 `gate hop limit`。
|
|
457
|
-
// 消费点写在 `outcome.kind === 'failed'` 之内:决断成功的那一轮压根不该动这个记号。
|
|
458
|
-
//
|
|
459
|
-
// 🔴 #357(现网 P0,[5522]/[5525]):上面那条一次性只关掉了**身份腿**的空转;它的孪生腿
|
|
460
|
-
// (code/文案判据)当时没有任何限次 —— 「run 仍 parked 而取件读到空表」的**坐标失配**态下,
|
|
461
|
-
// 每一轮重放都命中 code 臂,照样烧满 24 个 hop、16 分钟长等、终帧还是那句与真因无关的预算话术
|
|
462
|
-
// ([same-shape-residue-constitution]:同一病形的第二处存量)。下面两件按 `MAX_ALREADY_RESOLVED_REATTACHES`
|
|
463
|
-
// 头注的分工落地:主修 = 坐标重探(拿当前拍的坐标真把新卡呈出去),兜底 = 同因连续限次。
|
|
464
211
|
const alreadyDecidedById = outcome.kind === 'failed' &&
|
|
465
212
|
candidateGatedCallId !== undefined &&
|
|
466
213
|
led.takeDecided(candidateGatedCallId);
|
|
467
|
-
// L-80:触顶收场的合成失败**不进**「已解决」臂(它的文案判据会把 `(last: no pending …)` 认成同族再续一轮)。
|
|
468
214
|
if (!closingCardTried && outcome.kind === 'failed' && (isAlreadyResolvedFailure(outcome) || alreadyDecidedById)) {
|
|
469
215
|
const firstReason = outcome.reason;
|
|
470
|
-
// 键按语义分(见 `alreadyResolvedStreakKey` 头注);命中的那个文案词只进诊断串。
|
|
471
216
|
const streakKey = alreadyResolvedStreakKey(!isAlreadyResolvedFailure(outcome) && alreadyDecidedById);
|
|
472
217
|
const reasonToken = alreadyResolvedReasonToken(outcome.reason);
|
|
473
|
-
|
|
474
|
-
// 🔴 重探 = **按当前拍再读一次队列**(同一条呈卡腿、**同样的入参**)。有可决行 ⇒ 这一轮就把
|
|
475
|
-
// 新卡真呈给用户(死锁在这里破);无行 ⇒ 它照旧回同一个「已解决」,落下面的限次闸。
|
|
476
|
-
// 坐标轮换在这里是**自动**发生的:取件腿的身份腿在队列里找不到那张 park 的陈旧 callId 时
|
|
477
|
-
// 本就回落 taskId + 族谓词两腿,于是选中的正是当前拍的新行(server [5525] 的新 token 新行)。
|
|
478
|
-
// 🔴 **刻意不把身份入参抹成 `undefined`**(异源门 F10-j 当场证伪的写法):`parkGatedCallId` 在
|
|
479
|
-
// `findPendingForTask` 里同时是「优先命中的身份」**和**「身份与本腿族属冲突时把候选池收紧」
|
|
480
|
-
// 的那把闸。抹掉它就等于把 F10-j 钉住的那条绕道兜底重新打开 —— 身份指着一行反族行、队列里
|
|
481
|
-
// 又没有别的行时,「任意行」兜底会把那行反族行捞回来呈卡 + decide(卡面全错、决断打在另一个
|
|
482
|
-
// checkpoint 上)。重探要的是**读数新鲜**,不是**判据放宽**。
|
|
483
|
-
const rescan = isFetchStepNoPending(outcome) && stalledRounds <= MAX_GATE_HOPS // L-80:按连续非进展轮判,不按 park 总数
|
|
218
|
+
const rescan = isFetchStepNoPending(outcome) && stalledRounds <= MAX_GATE_HOPS
|
|
484
219
|
? await surfaceParkGate(park, ctx, park.gatedCallId, witness)
|
|
485
220
|
: undefined;
|
|
486
|
-
// 🔴 只有**真进展**才采信重探的结果:决断成功 / 用户 Esc / 瞬断耗尽(那一形有自己的重呈臂)。
|
|
487
|
-
// 重探自己失败(网络类、或队列确实没有可决行)⇒ **不采信**,走限次闸兜底 —— 采信的话,
|
|
488
|
-
// 一次瞬时读面故障就会把 #110 那条「重放的 park 不是失败」救回腿改判成 fail-soft(会话废掉
|
|
489
|
-
// 那条路径),代价严重不对称。
|
|
490
221
|
if (rescan !== undefined &&
|
|
491
222
|
(rescan.kind === 'decided' ||
|
|
492
223
|
rescan.kind === 'aborted' ||
|
|
493
|
-
rescan.kind === 'retracted' ||
|
|
224
|
+
rescan.kind === 'retracted' ||
|
|
494
225
|
(rescan.kind === 'failed' && rescan.retryExhausted === true))) {
|
|
495
|
-
// L-80:**不在这里**复位同因计数 —— 复位只在驱动侧观察到 host 进展帧时发生(#357 的闸曾被这一行
|
|
496
|
-
// 每轮绕空:坐标失配序下每轮都「找到新行→决成功→引擎原样重放」,计数永远回不到 2)。
|
|
497
226
|
hostLog('debug', `liveHitlAskWire: gate reported already-resolved (${firstReason}) but a fresh approvals re-read for run ` +
|
|
498
227
|
`${taskId} surfaced a decidable row under the current coordinates — re-presented it (rescan: ${rescan.kind}) ` +
|
|
499
228
|
`instead of re-attaching on the stale park identity`);
|
|
@@ -509,12 +238,6 @@ export async function resolvePark(park, ctx) {
|
|
|
509
238
|
(led.decidedCount() > 0 ? ` [decided so far: ${led.decidedCount()}]` : ''));
|
|
510
239
|
return { kind: 'reattach', progress: false, reason: reasonToken ?? streakKey, presented: presentedThisRound, gatedCallId: outcome.gatedCallId };
|
|
511
240
|
}
|
|
512
|
-
// ── 兜底:同因连续第 2 次 ⇒ 不再空转,诚实收场 ──────────────────────────────────────
|
|
513
|
-
// 件B(可见告知):真因走**终帧的 errorMessage**(下面 fail-soft 汇流合成的那一条),不是只落
|
|
514
|
-
// debug —— 修前用户在 24 轮里什么都看不到,最后拿到的是一句关于 hop 预算的话。
|
|
515
|
-
// 🔴 如实记边界:`park.pendingDone` 在场(sync leg 的 `done{suspended}`)时,fail-soft 汇流
|
|
516
|
-
// 按既有语义原样吐那一帧、不合成 failed —— 那一格的告知面仍只有本行日志。durable 腿
|
|
517
|
-
// (真实病形所在:`suspended` 事件无 pendingDone)恒走合成帧,真因必然上屏。
|
|
518
241
|
const stalled = `the gate reported already-resolved ${streak} times in a row while the run stayed parked, and a fresh ` +
|
|
519
242
|
`approvals re-read surfaced no decidable row for it — run/approvals coordinate mismatch ` +
|
|
520
243
|
`(last gate reason: ${firstReason})`;
|
|
@@ -528,16 +251,7 @@ export async function resolvePark(park, ctx) {
|
|
|
528
251
|
};
|
|
529
252
|
}
|
|
530
253
|
}
|
|
531
|
-
// Inkglow-1085 P0a —— **重呈臂**:decide 出站在瞬断类失败上重试一次仍未送达(两发都没拿到引擎的
|
|
532
|
-
// 语义答复)。此刻 run 仍 parked、pending 行仍可决 —— 合成 `hitl_unanswered` 把 turn 判死是三条
|
|
533
|
-
// 出路里唯一不可逆的那条,只配给「引擎答了且拒了」的语义失败。这里改走 reattach:durable 流对
|
|
534
|
-
// suspended run 必然把 park 帧再送一遍(#110 已解决重放同一条机械路径),于是**同一张卡重新交给
|
|
535
|
-
// 用户**(重呈的呈现就是卡本身,归端零新 UI);hop 预算照吃(每轮都要人再答一次,不会空转)。
|
|
536
|
-
// 引擎真死时失败也尽快显形:下一轮的 approvals.list / runs.events 对死引擎当场失败,walks 既有
|
|
537
|
-
// 诚实红(reason 是 approvals.list failed,不带 retryExhausted ⇒ 不再进本臂)。
|
|
538
254
|
if (outcome.kind === 'failed' && outcome.retryExhausted === true && !closingCardTried) {
|
|
539
|
-
// L-80:该臂修前**无次数闸**(头注自认「approvals.list 网络失败这类真失败会连吃 24 个 hop」)——
|
|
540
|
-
// 现进同一本同因账:连续第 3 次即收场(下方 failsoft),终帧带真因。
|
|
541
255
|
const token = transportReasonToken(outcome.reason);
|
|
542
256
|
const streak = led.noteAlreadyResolvedGate(`transport:${token}`);
|
|
543
257
|
if (streak <= MAX_TRANSPORT_REATTACHES) {
|
|
@@ -549,8 +263,6 @@ export async function resolvePark(park, ctx) {
|
|
|
549
263
|
}
|
|
550
264
|
outcome = {
|
|
551
265
|
kind: 'failed',
|
|
552
|
-
// 🔴 `orchestration` 而不是 `decide`:这一格是**重呈臂用尽之后**编排层的收口,不是某一次
|
|
553
|
-
// decide 的语义结局(那一次的结局在 `outcome.reason` 里被引述)。
|
|
554
266
|
stage: 'orchestration',
|
|
555
267
|
...(outcome.gatedCallId !== undefined ? { gatedCallId: outcome.gatedCallId } : {}),
|
|
556
268
|
reason: `the decide call failed on transport ${streak} times in a row while the run stayed parked (${outcome.reason})`,
|
|
@@ -558,8 +270,6 @@ export async function resolvePark(park, ctx) {
|
|
|
558
270
|
}
|
|
559
271
|
if (outcome.kind !== 'decided') {
|
|
560
272
|
hostLog('debug', `liveHitlAskWire: gate not decided (${outcome.kind}${'reason' in outcome ? `: ${outcome.reason}` : ''}) — fail-soft to suspended terminal`);
|
|
561
|
-
// 0.74.1(CC-67):宿主撤卡(无决断收口)⇒ 零 decide,run 照旧 parked;这一轮按 fail-soft 收口并把真因写进去
|
|
562
|
-
// (不是用户中断、不是 decide 失败 —— 是这张卡在这个宿主上已经没有决断口了)。
|
|
563
273
|
const failedReason = outcome.kind === 'failed'
|
|
564
274
|
? outcome.reason
|
|
565
275
|
: outcome.kind === 'retracted'
|
|
@@ -567,44 +277,12 @@ export async function resolvePark(park, ctx) {
|
|
|
567
277
|
: undefined;
|
|
568
278
|
return { kind: 'failsoft', events: failsoftEvents(park, ctx, outcome.kind === 'aborted', failedReason) };
|
|
569
279
|
}
|
|
570
|
-
// decide 成功:丢弃该 call 的毒化 HOLD(续流重放会带 isError:false 的解答帧收口卡片),
|
|
571
|
-
// 并记下真实答案供该解答帧 stamp `structured`(否则卡片渲成结果不可用)。
|
|
572
|
-
//
|
|
573
|
-
// 🔴 件④([4933] 立案的存量,0.41.0 根修):摘扣留帧走 `dropHeldForDecidedPark` 而不是裸
|
|
574
|
-
// `dropHeld(outcome.gatedCallId)` —— 后者的入参是 `findPendingForTask` 的**卡面渲染宽口**
|
|
575
|
-
// (同 taskId + 谓词命中的第一行),同族多行排队时它可能是旁观者,于是摘掉的是**另一条**
|
|
576
|
-
// call 的扣留帧、那一帧再也不吐(「一帧不丢」在这一格上不成立)。新动词的两条腿见其头注:
|
|
577
|
-
// `park.gatedCallId`(server ≥7.41.0 的 wire 身份)在场就点名摘,缺席则只在同族唯一时摘。
|
|
578
|
-
// 这一行**刻意排在 `if (outcome.gatedCallId)` 之外**:身份在 wire 上时,摘不摘与 pending
|
|
579
|
-
// 行给没给出 callId 无关(park 有主角,decide 也成功了)。
|
|
580
|
-
// #357:决断成功 = 判据链上的**真进展**,「已解决」的同因连续计数归零(否则一个 turn 里两只门
|
|
581
|
-
// 各带一次正当重放,第二只的重放会被第一只的计数顶成「第 2 次」而被闸掉)。
|
|
582
|
-
// L-80:决断成功**不在这里**复位同因计数 —— 「决了」不等于「引擎动了」(reopen 类 re-park / 坐标
|
|
583
|
-
// 失配都是决了又原样 park 回来);复位归驱动侧的进展观察点。
|
|
584
280
|
led.dropHeldForDecidedPark(outcome.gatedCallId, park.gatedCallId);
|
|
585
281
|
if (outcome.gatedCallId) {
|
|
586
|
-
|
|
587
|
-
// 不带 callId,`findPendingForTask` 取的是「同 taskId + 谓词命中的**第一行**」(谓词不命中
|
|
588
|
-
// 时还退「任意行」)—— 那是给**卡面渲染**用的宽口,证明不了这一行就是这张 park 的主角:
|
|
589
|
-
// 同族两行排队时它可能给出旁观者,于是真主角被挤成「非主角」而 stamp(异源复审实测)。
|
|
590
|
-
// 连坐判别改由台账按「本批唯一的该族 call」自证(`gateLedger.flushHeld` 头注),
|
|
591
|
-
// 分不出来就整批不标。下面两行是 gate 生命周期(#110 / REF-CC-034),与判别无关,照旧。
|
|
592
|
-
// ✅ **记案已销**(0.41.0 件④):此处原先那句「`dropHeld` 用的也是这个不可信 callId」的
|
|
593
|
-
// 存量记案,已由上方 `dropHeldForDecidedPark` 收口(wire 身份点名 / 判不出就不摘)。
|
|
594
|
-
// 🔴 `markDecided` **刻意仍用** `outcome.gatedCallId`:它喂的是 #110 那条「重放的 park 不是
|
|
595
|
-
// 失败」的承重判据,而那条判据的候选取自 `lastFsOrShellGatedCallId()`(同一条 pending 宽口
|
|
596
|
-
// 时代的口径),两边必须同源才对得上;换成 wire 身份是**另一件**改动(要连着上方
|
|
597
|
-
// `candidateGatedCallId` 一起换,且会改动烧会话那条路径的行为),不搭本批的车。
|
|
598
|
-
led.markDecided(outcome.gatedCallId); // #110 缺陷② b / REF-CC-034:身份留痕,上方候选匹配消费
|
|
282
|
+
led.markDecided(outcome.gatedCallId);
|
|
599
283
|
if ('answered' in outcome && outcome.answered)
|
|
600
284
|
led.rememberAnswer(outcome.gatedCallId, outcome.answered);
|
|
601
285
|
}
|
|
602
|
-
// ── B-070:200 = 投递受理,续跑可能挂在**另一条 run** 上 ────────────────────────────────────
|
|
603
|
-
// workflow 车道的受理形回执带的是**宿主新铸**的 run id(sdk README §9.0.0:「poll 它,不要盯那张
|
|
604
|
-
// 卡」)。修前这里恒用原 `taskId` 重挂 `runs.events` ⇒ 旧流上再无推进帧,一路烧到 hop 上限。
|
|
605
|
-
// 🔴 判据是回执上的**两件合取**(`status:"resuming"` ∧ 非空 taskId,判在 `readDecideReceipt` 里),
|
|
606
|
-
// 而且**必须与当前 taskId 不同**才算换挂 —— 任务级车道的受理形回执带的就是同一条 run,
|
|
607
|
-
// 把它当「换挂」会白白丢掉 `lastEventId`(等于从头重放一遍这条流)。
|
|
608
286
|
const handoffTaskId = 'receipt' in outcome && outcome.receipt?.handoffTaskId !== undefined && outcome.receipt.handoffTaskId !== taskId
|
|
609
287
|
? outcome.receipt.handoffTaskId
|
|
610
288
|
: undefined;
|
|
@@ -620,11 +298,6 @@ export async function resolvePark(park, ctx) {
|
|
|
620
298
|
...(handoffTaskId !== undefined ? { handoffTaskId } : {}),
|
|
621
299
|
};
|
|
622
300
|
}
|
|
623
|
-
/**
|
|
624
|
-
* fail-soft 收场的事件序列:扣留帧一律走中断感知出口(件 B:五个排水出口同一形,零-park 硬门必挡,语义等价 no-op;
|
|
625
|
-
* 常驻门 hitl F13-h 钉 src 下 `flushHeld()` 调用点恰一处)+ sync 终帧原样回吐 / durable 腿合成 `hitl_unanswered` 真因终帧
|
|
626
|
-
* (#87 评审② minor 记案:durable 第二问走 `aborted` 时不吐终帧 —— 下游正在拆流,合成了也没人渲)。
|
|
627
|
-
*/
|
|
628
301
|
function failsoftEvents(park, ctx, gateAbortedByUser, failedReason, terminal) {
|
|
629
302
|
const events = [
|
|
630
303
|
...flushHeldWithInterruptRewrite(ctx.led, {
|
|
@@ -643,27 +316,15 @@ function failsoftEvents(park, ctx, gateAbortedByUser, failedReason, terminal) {
|
|
|
643
316
|
events.push({
|
|
644
317
|
type: 'failed',
|
|
645
318
|
errorCode: 'hitl_unanswered',
|
|
646
|
-
// 真因 + 出路(L-80:修前的终帧只有一句预算话术,用户拿不到「run 还 parked、卡还能决」这件事)。
|
|
647
319
|
errorMessage: `${park.gate === 'fs' ? 'Tool approval' : 'AskUserQuestion'} gate could not be answered: ${failedReason}` +
|
|
648
320
|
' — the run is still parked on this approval: decide it on the card when it is shown again, or cancel the run.',
|
|
649
321
|
});
|
|
650
322
|
}
|
|
651
323
|
return events;
|
|
652
324
|
}
|
|
653
|
-
|
|
654
|
-
* 驱动侧在**预算提交之后**判定触顶时的收场(对抗复审 r4 [high]①:有推进帧的轮次触顶必须等权威身份解析完 ——
|
|
655
|
-
* 先呈 B、决 B,提交后仍是同一只 call 才收场;这一轮已经呈过卡,不再呈收场卡)。
|
|
656
|
-
*/
|
|
657
|
-
export function stalledTerminal(park, ctx, stalledRounds, lastStallReason,
|
|
658
|
-
/** 这一轮的决断有没有落地(r5 [medium]③):落地了就**不许**说「could not be answered」「still parked」—— 那是谎报。 */
|
|
659
|
-
decidedThisRound,
|
|
660
|
-
/** 这一轮决断落在哪只 call(解析到的行身份):收场排水前先把**它**的扣留帧摘掉(r6 [medium]:两只同族 call 都在
|
|
661
|
-
* 扣留、park 帧无可信身份时,决断臂刻意保守不摘,排水会把刚批准的那只当 abort 吐出)。 */
|
|
662
|
-
decidedGatedCallId) {
|
|
325
|
+
export function stalledTerminal(park, ctx, stalledRounds, lastStallReason, decidedThisRound, decidedGatedCallId) {
|
|
663
326
|
const gate = park.gate === 'fs' ? 'Tool approval' : 'AskUserQuestion';
|
|
664
327
|
if (decidedThisRound) {
|
|
665
|
-
// r7 [high]:第二参必须是 **park 帧上的**可信身份(GateLedger 契约),不能拿候选身份自证 —— 无可信身份且同族
|
|
666
|
-
// 不唯一时保守不摘、由排水按中断语义吐出(一帧不丢),与决断臂同一条纪律。
|
|
667
328
|
if (decidedGatedCallId !== undefined)
|
|
668
329
|
ctx.led.dropHeldForDecidedPark(decidedGatedCallId, park.gatedCallId);
|
|
669
330
|
const errorMessage = `${gate} was decided, but the engine parked the same call again after each of the last ${stalledRounds} decisions, so sema ` +
|
|
@@ -677,7 +338,6 @@ decidedGatedCallId) {
|
|
|
677
338
|
hostLog('debug', `liveHitlAskWire: ${reason} — fail-soft after the round committed`);
|
|
678
339
|
return { kind: 'failsoft', events: failsoftEvents(park, ctx, false, reason) };
|
|
679
340
|
}
|
|
680
|
-
/** 非进展 reattach 的用户面告知(deps 口缺席 = 只留 debug;口抛错不许炸续流)。 */
|
|
681
341
|
function notifyParkReattach(ctx, attempt, max, reason) {
|
|
682
342
|
const cb = ctx.deps.onParkReattach;
|
|
683
343
|
if (typeof cb !== 'function')
|
|
@@ -689,7 +349,6 @@ function notifyParkReattach(ctx, attempt, max, reason) {
|
|
|
689
349
|
hostLog('debug', `liveHitlAskWire: onParkReattach threw (${String(e)}) — ignored`);
|
|
690
350
|
}
|
|
691
351
|
}
|
|
692
|
-
/** 传输失败的同因键:只留错误类词(同一类连断才算同因;数字/id 每次都变,不能进键)。 */
|
|
693
352
|
function transportReasonToken(reason) {
|
|
694
353
|
const m = /(ECONNREFUSED|ECONNRESET|ETIMEDOUT|EPIPE|EAI_AGAIN|TimeoutError|AbortError|fetch failed|network)/i.exec(reason);
|
|
695
354
|
return (m?.[1] ?? reason.split(/\s+/).slice(0, 4).join(' ')).toLowerCase();
|