@sema-agent/client-core 0.77.0 → 0.77.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +23 -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 +1 -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 +10 -496
- 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 +11 -65
- package/dist/subagent/engineTaskHandleWire.js +20 -131
- 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 +62 -1
- package/package.json +1 -1
|
@@ -1,87 +1,40 @@
|
|
|
1
1
|
import { stamp } from '../types.js';
|
|
2
2
|
import { putOwnKey } from '../../ownKey.js';
|
|
3
3
|
import { readEffectiveReasoning, readEffectiveMemoryScopes } from '../../effectiveFacts.js';
|
|
4
|
-
// 0.60.0(engine ≥7.64.0 / sdk 8.4.0):终局读数的**单一读器**(两代字节 → 一个带标因由)。
|
|
5
4
|
import { isReviewPark, readRunTerminal, runTerminalCode, runTerminalGateToolName, } from '../../runTerminal.js';
|
|
6
5
|
import { toCcModelUsage } from './turnUsageToModelUsage.js';
|
|
7
|
-
// G1 去字面化(2026-08-04):到限/结构化输出/rewind 三族的码字面收编进单一真源,本文件只 import。
|
|
8
|
-
// 开集纪律不变——下面三个集合仍是**识别表**,`subtypeForErrorCode` 的 default 臂才是开集的兑现处。
|
|
9
6
|
import { LIMITS_MAX_COST_EXCEEDED, LIMITS_MAX_TOKENS_EXCEEDED, LIMITS_MAX_TURNS_EXCEEDED, LIMITS_MAX_WALLTIME_EXCEEDED, OUTPUT_INVALID, isRewindFamilyCode, } from '../../engineErrorCodes.js';
|
|
10
|
-
/**
|
|
11
|
-
* wire 数值 → CC 扁平 usage 里的数值:非数 / 非有限一律 0。
|
|
12
|
-
* 与 `turnUsageToModelUsage.finiteOrZero` 同一条规约(那边是 `ModelUsage` 八键的 mint 点,
|
|
13
|
-
* 这边是 `NonNullableUsage` 五键的);两处**刻意不共用一个导出**,因为它们分属两个可移植闭包
|
|
14
|
-
* 的叶,而这一行判据本身没有会漂的内容(有会漂的内容时才值得上收)。
|
|
15
|
-
*/
|
|
16
7
|
function finiteOr0(v) {
|
|
17
8
|
return typeof v === 'number' && Number.isFinite(v) ? v : 0;
|
|
18
9
|
}
|
|
19
|
-
/**
|
|
20
|
-
* Flatten TaskStats → the CC NonNullableUsage placeholder.
|
|
21
|
-
* 🔴 REF-CC-055(xlate-01):`failedToSdkResult` 此前手抄了一份「五键全零」的字面量,那不是
|
|
22
|
-
* 另一种形状,就是本函数 `stats === undefined` 的退化输出 —— 现在它也走这里(单一构造点)。
|
|
23
|
-
*/
|
|
24
10
|
function flattenUsage(stats) {
|
|
25
|
-
// D-2 / L-192②:`webSearchRequests` 修前是**字面量 0**。`TaskStats` 是开集索引 ⇒ 按 CC 的名字
|
|
26
|
-
// 宽读一次:读得出就是真账(显式 0 = 做了零次,一句正面事实),读不出才是「没有这本账」。
|
|
27
11
|
const webSearch = stats?.webSearchRequests;
|
|
28
12
|
const webSearchKnown = typeof webSearch === 'number' && Number.isFinite(webSearch);
|
|
29
13
|
const totalInput = stats?.totalInputTokens;
|
|
30
14
|
const totalInputKnown = typeof totalInput === 'number' && Number.isFinite(totalInput);
|
|
31
|
-
// D-2 族扫(异源对抗复审 [medium]):1 小时 TTL 的缓存写入(core `cacheWriteTokensLong`)此前
|
|
32
|
-
// 在终局的**两处**投影上都读不到 —— 见 {@link SemaFlatUsage._sema_cache_write_tokens_long}。
|
|
33
15
|
const longWrite = stats?.cacheWriteTokensLong;
|
|
34
16
|
const longWriteKnown = typeof longWrite === 'number' && Number.isFinite(longWrite);
|
|
35
17
|
return {
|
|
36
|
-
// 🔴 B-073 ③ 族扫(0.65.0):四格一律走 {@link finiteOr0},不再用 `?? 0`。
|
|
37
|
-
// `??` 只挡 `null`/`undefined` —— 而 `TaskStats` 带 `[key: string]: unknown` 开集索引,
|
|
38
|
-
// wire 是 JSON,一个 `"12"` / `NaN` / `Infinity` 会**原样落进** CC 侧型面写着 `number`
|
|
39
|
-
// 的槽位(编译期全绿,消费端在求和时才炸或静默出错)。`Infinity` 尤其糟:它会被当成真
|
|
40
|
-
// 数字摊进总计(与本文件 `microUsdToUsd` 头注同一条规约)。
|
|
41
18
|
inputTokens: finiteOr0(stats?.promptTokens),
|
|
42
19
|
outputTokens: finiteOr0(stats?.outputTokens),
|
|
43
20
|
cacheReadInputTokens: finiteOr0(stats?.cachedTokens),
|
|
44
|
-
// B-073 ③(L-192② 姊妹):此前是**字面量 0**,而 wire 上一直有这一格
|
|
45
|
-
// (`TaskStats.cacheWriteTokens`,sdk `types.d.ts` 真字节)—— 硬编 0 把一笔真实发生的缓存
|
|
46
|
-
// 写入抹成「没发生」,而 CC 的 footer/账单面正是拿这一格算缓存成本的。
|
|
47
|
-
// 缺席仍折 0:CC `NonNullableUsage` 的这一格型面上是必填 number,而它与**成本**那一格不同
|
|
48
|
-
// (token 计数没报就是没写过),缺席与真 0 在 wire 上本来就同义 —— 成本那一格的缺席是 core
|
|
49
|
-
// 刻意造出来的第三档,故单有判别位(见 `toCcModelUsage`)。
|
|
50
21
|
cacheCreationInputTokens: finiteOr0(stats?.cacheWriteTokens),
|
|
51
|
-
// D-2:值仍是 number(CC 形不破、只读这一格的旧消费者行为逐字不变);「wire 上没有这本账」
|
|
52
|
-
// 这句话交给同行的判别位,见 {@link SemaFlatUsage._sema_web_search_requests_absent}。
|
|
53
22
|
webSearchRequests: webSearchKnown ? webSearch : 0,
|
|
54
23
|
...(webSearchKnown ? {} : { _sema_web_search_requests_absent: true }),
|
|
55
|
-
// D-2:cache-INCLUSIVE 总量的超集座位(缺席 ⇒ 键不铸,绝不拿 MISS 分量冒充总量)。
|
|
56
24
|
...(totalInputKnown ? { _sema_total_input_tokens: totalInput } : {}),
|
|
57
|
-
// D-2 族扫:长 TTL 缓存写入分量原样过境(**不求和**,理由见该位注释)。
|
|
58
25
|
...(longWriteKnown ? { _sema_cache_write_tokens_long: longWrite } : {}),
|
|
59
26
|
};
|
|
60
27
|
}
|
|
61
|
-
/** 非空串窄化(空串按缺席归一 —— 空串骑上一个键就是「这一格有值」的冒充)。 */
|
|
62
28
|
function nonEmptyStr(v) {
|
|
63
29
|
return typeof v === 'string' && v.length > 0 ? v : undefined;
|
|
64
30
|
}
|
|
65
|
-
/** 本流 `toolCallId → args` 快照的条数上限;溢出的调用不记 ⇒ 那一行 join 不上,留在 sema 载体(诚实缺席)。 */
|
|
66
31
|
export const TOOL_INPUT_JOIN_MAX_CALLS = 4096;
|
|
67
|
-
/** 传输层的替换记号前缀(闭形 `«redacted»` / `«redacted:<词>»` / `«redacted:<词>:partial»`;按前缀认 = 多认不少认)。 */
|
|
68
32
|
const REDACTION_TOKEN_PREFIX = '\u00abredacted';
|
|
69
|
-
/** 传输层把环 / 超深子树换成的两个占位串(只认「叶值恰等于」)。 */
|
|
70
33
|
function isTransportPlaceholderLeaf(v) {
|
|
71
34
|
return v === '[circular]' || v === '[depth-limit]';
|
|
72
35
|
}
|
|
73
|
-
/** 扫描预算:节点数与深度任一超限 ⇒ 按「判不出干净」处置(不铸)。 */
|
|
74
36
|
const TOOL_INPUT_SCAN_MAX_NODES = 20000;
|
|
75
37
|
const TOOL_INPUT_SCAN_MAX_DEPTH = 80;
|
|
76
|
-
/**
|
|
77
|
-
* 流内 `tool_start.args` 能不能当 CC `tool_input` 用。三道闸,任一不过 ⇒ `undefined`(该行留在 sema 载体):
|
|
78
|
-
* ① 是普通对象(CC 形是 `Record<string, unknown>`;字符串 / 数组 / null 都不是);
|
|
79
|
-
* ② **没被传输层动过**:帧上的入参在到达客户端之前过一道保形脱敏(结构与键名不动,字符串叶里的凭据形
|
|
80
|
-
* 子串换成记号;环与超深子树换成占位串)。被换过的对象**不是**那次调用的入参 —— 铸进 CC 键等于
|
|
81
|
-
* 声称「模型就是拿这只对象调的工具」。方向是少铸不错铸:入参里本来就含这些字面的极端情形会被
|
|
82
|
-
* 一并挡掉,代价是那一行留在 sema 载体;
|
|
83
|
-
* ③ 扫描在预算内走完(超大 / 超深 / 自环的对象判不出干净 ⇒ 不铸)。
|
|
84
|
-
*/
|
|
85
38
|
function joinableToolInput(args) {
|
|
86
39
|
if (args === null || typeof args !== 'object' || Array.isArray(args))
|
|
87
40
|
return undefined;
|
|
@@ -104,60 +57,14 @@ function joinableToolInput(args) {
|
|
|
104
57
|
}
|
|
105
58
|
return args;
|
|
106
59
|
}
|
|
107
|
-
/**
|
|
108
|
-
* 「这条 gate 是**被拒**的」判词表。
|
|
109
|
-
* 🔴 **识别表,不是合法值表**(同 `engineErrorCodes` 的开集纪律):core 今天在两处铸这一格 ——
|
|
110
|
-
* 同步 ask 腿写 `resolved.action === 'allow' ? 'allow' : 'deny'`,耐久 resume 腿原样透传
|
|
111
|
-
* `ResumeOutcome.decision`。后者的 `plan_review` 臂词表是 `approve` / `edit` / `reject` ——
|
|
112
|
-
* 「人否了一份**计划**」不是「一次**工具调用**被拒」,CC 的 `permission_denials` 逐字是
|
|
113
|
-
* "One auto-denied **tool call**"。⇒ 认不出的判词一律**不铸** denial:少报一条(消费方还能从
|
|
114
|
-
* `humanReview` 看见有人工门)远好过把一次计划否决冒充成一次工具拒绝。
|
|
115
|
-
*/
|
|
116
60
|
const GATE_DENIED_DECISIONS = new Set(['deny']);
|
|
117
|
-
/**
|
|
118
|
-
* **认得出、但不是工具拒绝**的判词。与上面那张表合起来才是「这一行我判得出」的全集 ——
|
|
119
|
-
* 落在两张表**之外**的词(上游新词 / 大小写变体 / 空串 / 整个缺席)一律**不猜**:既不铸 denial,
|
|
120
|
-
* 也**不许**让这份清单继续声称完整(异源对抗复审 [medium]:修前这些行被静默跳过,`[]` 于是被
|
|
121
|
-
* 当成「零拒绝」这句正面事实)。今天的成员:同步 ask 腿的 `allow`,计划复核腿的
|
|
122
|
-
* `approve`/`edit`/`reject`(那是「人否了一份**计划**」,不是 CC 说的 one auto-denied tool call)。
|
|
123
|
-
*/
|
|
124
61
|
const GATE_NON_DENIAL_DECISIONS = new Set(['allow', 'approve', 'edit', 'reject']);
|
|
125
|
-
/**
|
|
126
|
-
* D-1 / L-192① —— 终帧拒绝清单的**唯一 mint 点**(成功臂与错误信封共用)。
|
|
127
|
-
*
|
|
128
|
-
* 修前两处各写一个字面量 `[]`,于是**两句话被折成一句**:「这条 run 一次都没被拒」与「这条帧
|
|
129
|
-
* 根本没有这本账」(老引擎 / 409 拒绝信封 / `failed` 事件帧都不带 stats)在 CC 形上都是 `[]`。
|
|
130
|
-
*
|
|
131
|
-
* 🔴 **为什么是两条清单而不是把 wire 的记录塞进 CC 数组**(异源复审 [medium] 逼出的口径订正):
|
|
132
|
-
* CC 的 `SDKPermissionDenial` 三键 `tool_name` / `tool_use_id` / `tool_input` **全是必填**
|
|
133
|
-
* (agent-types `permissions.d.ts` 与壳侧 zod `SDKPermissionDenialSchema` 皆然),而 wire 的 gate
|
|
134
|
-
* 账本(7.23.0 起六格)给不出 `tool_input`。两条路都不能走:**补零补空 = 编造**;**塞半条记录 = 破坏元素契约**
|
|
135
|
-
* ——严格消费方 `safeParse` 会把**整条 result 帧**判非法(丢一格 vs 丢整帧,后者严重得多)。
|
|
136
|
-
* ⇒ CC 数组只收**三键齐全**的记录,wire 上真有的每一条走 sema 载体 `_sema_permission_denials`,
|
|
137
|
-
* 键按能兑现的铸。`tool_use_id` ⇐ 账本行的 `toolCallId`(引擎 ≥7.23.0);`tool_input` ⇐ 账本行的
|
|
138
|
-
* `toolInput`(今天没有)**或**同一条流 `tool_start` 帧上的入参(0.73.4;调用方把本流快照作为按次入参
|
|
139
|
-
* 交进来,没交 = 没有流内面 = 与 0.73.3 之前逐字同)。🔴 0.73.2 的发布说明曾把「`tool_use_id` 到货」写成
|
|
140
|
-
* 「CC 数组自动填满」—— 那是错的:缺第三键的行进不了 CC 数组,直到本版的流内 join 才真有三键齐的行。
|
|
141
|
-
*
|
|
142
|
-
* 🔴 判别位 `_sema_permission_denials_absent` = **「CC 那条清单不可声称完整」**,四条路径:
|
|
143
|
-
* ① 账本整个读不出(`humanReview` 缺席 / 坏形 / `gates` 不是数组 / 无 stats);
|
|
144
|
-
* ② 有读不出的行(非对象);
|
|
145
|
-
* ③ 有**认不出的判词**(两张判词表之外的词 / 判词缺席)—— 不猜它是不是拒绝;
|
|
146
|
-
* ④ 有被拒记录**没能铸成 CC 形**(行无 `toolCallId` / 本流没见过那只 `tool_start`(重连后的流、
|
|
147
|
-
* 宿主自建管线没交快照)/ 入参不是普通对象 / 入参被传输层动过)。
|
|
148
|
-
* 读法因此是两键合读:`[]` + 判别位缺席 = **零拒绝**(正面事实);`[]` + 判别位 `true` = 别渲肯定句。
|
|
149
|
-
* 判别位**只在该说话时铸,绝不铸 `false`**(本包 additive 一贯纪律)。
|
|
150
|
-
*
|
|
151
|
-
* 逐行独立:坏行只丢自己,绝不丢整本账(但会让清单失去「完整」资格,见 ②③)。
|
|
152
|
-
*/
|
|
153
62
|
function permissionDenialParts(stats, toolInputByCallId) {
|
|
154
63
|
const hr = stats?.humanReview;
|
|
155
64
|
const gates = hr !== null && typeof hr === 'object' ? hr.gates : undefined;
|
|
156
|
-
// 账本整个读不出(缺席 / 坏形 / 无 stats)—— 诚实缺席,不猜。
|
|
157
65
|
if (!Array.isArray(gates))
|
|
158
66
|
return { permission_denials: [], _sema_permission_denials_absent: true };
|
|
159
67
|
const denials = [];
|
|
160
|
-
/** 这份清单还能不能声称「完整」(见头注 ②③④)。 */
|
|
161
68
|
let complete = true;
|
|
162
69
|
for (const g of gates) {
|
|
163
70
|
if (g === null || typeof g !== 'object') {
|
|
@@ -167,34 +74,25 @@ function permissionDenialParts(stats, toolInputByCallId) {
|
|
|
167
74
|
const row = g;
|
|
168
75
|
const decision = row.decision;
|
|
169
76
|
if (typeof decision !== 'string' || decision.length === 0) {
|
|
170
|
-
// 判词缺席(耐久 wake 腿真会这样)⇒ 这一行是不是拒绝**判不出**,不猜、也不再声称完整。
|
|
171
77
|
complete = false;
|
|
172
78
|
continue;
|
|
173
79
|
}
|
|
174
80
|
if (!GATE_DENIED_DECISIONS.has(decision)) {
|
|
175
|
-
// 认得出的非拒绝判词照旧跳过(不影响完整性);认不出的词一律降级为「清单不完整」。
|
|
176
81
|
if (!GATE_NON_DENIAL_DECISIONS.has(decision))
|
|
177
82
|
complete = false;
|
|
178
83
|
continue;
|
|
179
84
|
}
|
|
180
85
|
const toolName = nonEmptyStr(row.toolName);
|
|
181
86
|
const toolArg = nonEmptyStr(row.toolArg);
|
|
182
|
-
// 🔴 开集宽读两键:`toolCallId` 自引擎 7.23.0 起真在账本上(门里锚着真字节;老引擎 / 不可 join 的行
|
|
183
|
-
// 缺席);`toolInput` 今天仍没有,按 core 自己的命名习惯(`toolName` / `toolArg` 同族)预读,
|
|
184
|
-
// 上游若用别的名字补上,门里的缺席证据当天红 ⇒ 那一批改读真名。绝不自铸值。
|
|
185
87
|
const toolUseId = nonEmptyStr(row.toolCallId);
|
|
186
88
|
const rawInput = row.toolInput;
|
|
187
89
|
const ledgerInput = rawInput !== null && typeof rawInput === 'object' && !Array.isArray(rawInput)
|
|
188
90
|
? rawInput
|
|
189
91
|
: undefined;
|
|
190
|
-
// 0.73.4:账本没带 ⇒ 按行身份去本流快照里 join(账本那份在场时恒优先;`has` 先判,绝不把
|
|
191
|
-
// 「没见过这只 id」与「见过、入参是 undefined」混成一格)。
|
|
192
92
|
const joinedInput = ledgerInput === undefined && toolUseId !== undefined && toolInputByCallId?.has(toolUseId) === true
|
|
193
93
|
? joinableToolInput(toolInputByCallId.get(toolUseId))
|
|
194
94
|
: undefined;
|
|
195
95
|
const toolInput = ledgerInput ?? joinedInput;
|
|
196
|
-
// 键都读不出时仍然 push 一条空记录:**条数**(「这条 run 被拒了几次」)是这本账最要紧的
|
|
197
|
-
// 事实,丢掉它等于把一次真实发生的拒绝抹成没发生;键按能兑现的铸,不编。
|
|
198
96
|
denials.push({
|
|
199
97
|
...(toolName !== undefined ? { tool_name: toolName } : {}),
|
|
200
98
|
...(toolUseId !== undefined ? { tool_use_id: toolUseId } : {}),
|
|
@@ -203,7 +101,6 @@ function permissionDenialParts(stats, toolInputByCallId) {
|
|
|
203
101
|
...(toolArg !== undefined ? { _sema_tool_arg: toolArg } : {}),
|
|
204
102
|
});
|
|
205
103
|
}
|
|
206
|
-
/** CC 元素契约:三键齐全才进 CC 数组(类型窄化由这只谓词负责)。 */
|
|
207
104
|
const ccList = denials.filter((d) => d.tool_name !== undefined && d.tool_use_id !== undefined && d.tool_input !== undefined);
|
|
208
105
|
const claimable = complete && ccList.length === denials.length;
|
|
209
106
|
return {
|
|
@@ -212,67 +109,23 @@ function permissionDenialParts(stats, toolInputByCallId) {
|
|
|
212
109
|
...(claimable ? {} : { _sema_permission_denials_absent: true }),
|
|
213
110
|
};
|
|
214
111
|
}
|
|
215
|
-
/**
|
|
216
|
-
* 0.67.1 —— **以 wire 给的 id / 键名当对象键**时的唯一落键姿势(`__proto__` 陷阱)。
|
|
217
|
-
* 🔴 0.68.0 / L-246 B2:实现**下沉到 `src/ownKey.ts`**(单源)—— 修前本文件与
|
|
218
|
-
* `hitl/parkResolver.ts` 各持一份同形实现,理由、陷阱与「不改成 null 原型交付」的取舍都在
|
|
219
|
-
* 那个模块的头注里。本别名保留是为了本文件三十余处调用点零改动。
|
|
220
|
-
*/
|
|
221
112
|
const putOwn = putOwnKey;
|
|
222
|
-
/** 有限数窄化(非数 / 非有限 ⇒ 缺席;`0` 是事实不是缺席)。 */
|
|
223
113
|
function finiteOrAbsent(v) {
|
|
224
114
|
return typeof v === 'number' && Number.isFinite(v) ? v : undefined;
|
|
225
115
|
}
|
|
226
|
-
/**
|
|
227
|
-
* 0.67.1 / B-091 —— usage **下界位**的**唯一判据**(纯函数,两面读的是**同一次计算**)。
|
|
228
|
-
*
|
|
229
|
-
* 🔴 它为什么必须是一只函数、而不是两处各写一遍的表达式:下界位有**两个来源**——
|
|
230
|
-
* · `stats.usageMissing`:只在带得出 `TaskResult` 的终帧上有;
|
|
231
|
-
* · **本条流**的流内观测(`failed` 事件帧 / 409 拒绝信封 / park 体**没有 stats**,
|
|
232
|
-
* 只读 stats 的话一条已经观测到缺口的 run 会在终帧上被读成「每一轮都报了 usage」)。
|
|
233
|
-
* 修前取并只包在**终帧**那一面({@link costFactParts}),而 chrome 对账臂的铸点直接展开
|
|
234
|
-
* `readRunCostFacts(stats).reconcile` ⇒ 「流内观测到缺口、终局 stats 对此缄默」那一形上两面各说
|
|
235
|
-
* 各的(终帧铸了 `_sema_usage_lower_bound`、同一拍的臂上没有 `usageLowerBound`)——
|
|
236
|
-
* [paired-mechanisms-must-share-premise] 的教科书形。⇒ 取并**下沉到这里**,两面共用。
|
|
237
|
-
*
|
|
238
|
-
* 🔴 **第二参是「这一条流」的观测快照,不是一个跨流留存的状态**(0.67.2 / 车 I 件 I-1):它此前住在
|
|
239
|
-
* `EmitContext` 上、只写 `true` 永不清,而 ctx 是调用方的对象、可以复用给多条流 ⇒ 上一条流的缺口
|
|
240
|
-
* 会把下一条账数得全的流标成下界(顺序复用),或两条并发流互相串。现在由 `runStream` 按流持有、
|
|
241
|
-
* 终局**按值**交给两个投影口;端自建管线同样是**按次调用**传入。
|
|
242
|
-
*
|
|
243
|
-
* 🔴 **严格 true 才认**(core 契约:`true` 或缺席,恒不写 `false`/`null`);`stats` 不是可读对象时
|
|
244
|
-
* 它那一半读作「没说」,而流内观测那一半**照旧成立**。
|
|
245
|
-
*/
|
|
246
116
|
function usageLowerBoundOf(stats, observed) {
|
|
247
117
|
const statsSaid = stats !== null && typeof stats === 'object' && !Array.isArray(stats)
|
|
248
118
|
? stats.usageMissing === true
|
|
249
119
|
: false;
|
|
250
120
|
return statsSaid || observed?.usageMissingObserved === true;
|
|
251
121
|
}
|
|
252
|
-
/**
|
|
253
|
-
* D-3 / B-068 · L-198 —— 终局成本事实的**唯一读器**(终帧超集键与 chrome 对账臂共用)。
|
|
254
|
-
*
|
|
255
|
-
* 🔴 `stats` 不是可读对象(409 拒绝信封 / park 体 / `failed` 事件帧)⇒ 返 `undefined` =
|
|
256
|
-
* **这条帧没有账**,调用方据此「不说话」(不发臂、不铸键),而不是发一条全缺席的空账。
|
|
257
|
-
*
|
|
258
|
-
* 🔴 **第二参 `observed`(0.67.1 / B-091,additive)**:**这一条流**的流内观测快照。给了它,对账段上的
|
|
259
|
-
* {@link RunCostReconcile.usageLowerBound} 就是**取并后**的读数(见 {@link usageLowerBoundOf});
|
|
260
|
-
* 不给(旧签名)⇒ 只读 `stats` 那一半,既有端逐位不变。
|
|
261
|
-
* ⚠️ 包内的两个调用点(`costFactParts` 与 `runStream` 的 `run_cost_reconciled` 铸点)**都必须**
|
|
262
|
-
* 传它 —— 少传一处就是把本件修的那条不对称原样种回去。
|
|
263
|
-
* 🔴 0.67.2 / 车 I 件 I-1:它是**按次调用的入参**,不再是 `EmitContext` 上的一格 —— 共享 ctx 被复用
|
|
264
|
-
* 给多条流时,那一格会把别的流的缺口串进这一条(见 {@link usageLowerBoundOf} 的第三段 🔴)。
|
|
265
|
-
*/
|
|
266
122
|
export function readRunCostFacts(stats, observed) {
|
|
267
|
-
// 数组也不是「一份账」:`typeof [] === 'object'` 会把一条畸形载体放进来,然后它的每一格都读不出
|
|
268
|
-
// ⇒ 发出一条「own 没定价」的臂,而真相是**这条帧根本没有账**(两句话又折成一句)。
|
|
269
123
|
if (stats === null || typeof stats !== 'object' || Array.isArray(stats))
|
|
270
124
|
return undefined;
|
|
271
125
|
const rawBreakdown = stats.costBreakdown;
|
|
272
126
|
let breakdown;
|
|
273
127
|
if (rawBreakdown !== null && typeof rawBreakdown === 'object' && !Array.isArray(rawBreakdown)) {
|
|
274
128
|
const out = {};
|
|
275
|
-
// 逐键独立:坏值只丢自己(整段不连坐)。开集 —— 键名不套闭表,词表属主是 core。
|
|
276
129
|
for (const [k, v] of Object.entries(rawBreakdown)) {
|
|
277
130
|
const n = finiteOrAbsent(v);
|
|
278
131
|
if (n !== undefined)
|
|
@@ -282,10 +135,6 @@ export function readRunCostFacts(stats, observed) {
|
|
|
282
135
|
breakdown = out;
|
|
283
136
|
}
|
|
284
137
|
const rawNested = stats.nested;
|
|
285
|
-
// 🔴 「**委派过**」这件事本身是 load-bearing 的(它决定总额算不算得出来),所以它的判据是
|
|
286
|
-
// **原始载体**在不在,而**不是**过滤产物空不空(异源对抗复审 [medium] 的实抓:
|
|
287
|
-
// `{costMicroUsd:100, nested:{}}` / `nested:{tokens:'bad'}` 修前被当成「没委派」⇒ 铸出一个
|
|
288
|
-
// 确定的总额 100,而真相是「委派过、那本账读不出来」)。
|
|
289
138
|
const nestedRan = rawNested !== null && typeof rawNested === 'object' && !Array.isArray(rawNested);
|
|
290
139
|
let nested;
|
|
291
140
|
if (nestedRan) {
|
|
@@ -296,20 +145,12 @@ export function readRunCostFacts(stats, observed) {
|
|
|
296
145
|
if (v !== undefined)
|
|
297
146
|
picked[k] = v;
|
|
298
147
|
}
|
|
299
|
-
// 一个数都读不出时仍然铸**空对象**:键在场 = 委派过(与 `costMicroUsd` 缺席 = 那本账不知道
|
|
300
|
-
// 是两键合读的两半);整键不铸会把「委派过」这句事实一起抹掉。
|
|
301
148
|
nested = picked;
|
|
302
149
|
}
|
|
303
150
|
const ownMicroUsd = finiteOrAbsent(stats.costMicroUsd);
|
|
304
151
|
const nestedMicroUsd = nested?.costMicroUsd;
|
|
305
|
-
// 「委派过但那本账没定价/读不出」与「压根没委派」是两句话:前者判别位立起来,后者什么都不说。
|
|
306
152
|
const nestedUnknown = nestedRan && nestedMicroUsd === undefined;
|
|
307
|
-
// 求和自身也必须是有限数:两个合法但极端的值相加可以溢出成 Infinity,而 Infinity 会被下游
|
|
308
|
-
// 当成真数字摊进总计(与 `microUsdToUsd` 同一条规约)⇒ 宁可不铸。
|
|
309
153
|
const sum = ownMicroUsd !== undefined && !nestedUnknown ? ownMicroUsd + (nestedMicroUsd ?? 0) : undefined;
|
|
310
|
-
// 0.67.0(core 7.14.0):usage 下界位。**严格 true 才铸**(core 契约:`true` 或缺席,恒不写
|
|
311
|
-
// `false`/`null`;认宽了就会把一个 falsy 值渲成「数得不全」)。它与成本三段正交,所以读在这里、
|
|
312
|
-
// 与三段同一只读器出 —— 两面(终帧超集键 / chrome 对账臂)因此永远不会各算各的。
|
|
313
154
|
const usageLowerBound = usageLowerBoundOf(stats, observed);
|
|
314
155
|
const reconcile = {
|
|
315
156
|
...(ownMicroUsd !== undefined ? { ownMicroUsd } : { costAbsent: true }),
|
|
@@ -318,7 +159,6 @@ export function readRunCostFacts(stats, observed) {
|
|
|
318
159
|
...(nestedUnknown ? { nestedCostAbsent: true } : {}),
|
|
319
160
|
...(breakdown?.compactionMicroUsd !== undefined ? { compactionMicroUsd: breakdown.compactionMicroUsd } : {}),
|
|
320
161
|
...(breakdown?.llmRootMicroUsd !== undefined ? { llmRootMicroUsd: breakdown.llmRootMicroUsd } : {}),
|
|
321
|
-
// 对账值:own 读得出、子代那一边不是「跑了却不知道多少钱」、且和本身有限时才算得出来。
|
|
322
162
|
...(sum !== undefined && Number.isFinite(sum) ? { reconciledMicroUsd: sum } : {}),
|
|
323
163
|
};
|
|
324
164
|
return {
|
|
@@ -327,11 +167,6 @@ export function readRunCostFacts(stats, observed) {
|
|
|
327
167
|
reconcile,
|
|
328
168
|
};
|
|
329
169
|
}
|
|
330
|
-
/**
|
|
331
|
-
* CC-06 / B-081:`TaskResult.effectiveReasoning` / `effectiveMemoryScopes` 由 server 终帧键集 verbatim 转发,
|
|
332
|
-
* sdk d.ts 未建模 ⇒ 从裸终帧记录窄读后按 `_sema_` 超集键铸到 CC 形 `result` 上;坏形 / 缺席 ⇒ 键不铸。
|
|
333
|
-
* 🔴 CC 同名键零改:这两位是 additive,`result` 上既有的任何键字节不动。
|
|
334
|
-
*/
|
|
335
170
|
function effectiveFactParts(rec) {
|
|
336
171
|
const reasoning = readEffectiveReasoning(rec.effectiveReasoning);
|
|
337
172
|
const scopes = readEffectiveMemoryScopes(rec.effectiveMemoryScopes);
|
|
@@ -340,22 +175,8 @@ function effectiveFactParts(rec) {
|
|
|
340
175
|
...(scopes !== undefined ? { _sema_effective_memory_scopes: scopes } : {}),
|
|
341
176
|
};
|
|
342
177
|
}
|
|
343
|
-
/**
|
|
344
|
-
* D-3 —— 终帧上的两个成本超集键(成功臂与错误信封共用的**唯一** mint 点)。
|
|
345
|
-
* 🔴 CC 同名键 `total_cost_usd` **语义零改**:它仍然只是 own 花费,`nested` **不折进去**
|
|
346
|
-
* (超集键纪律:CC 形上已有的位不许塞我们自己的含义)。「fully-reconciled spend」由消费方按
|
|
347
|
-
* 这两个超集键自己加 —— 包给的是**可对账的事实**,不是一个改了口径的数。
|
|
348
|
-
*/
|
|
349
178
|
function costFactParts(stats, observed) {
|
|
350
179
|
const facts = readRunCostFacts(stats, observed);
|
|
351
|
-
// 🔴 **下界位与成本三段分开算**(异源对抗复审 [medium] 实抓):`stats` 读不出(`failed` 事件帧 /
|
|
352
|
-
// 409 拒绝信封 / park 体)时**成本**那三段确实没有账、一条都不该说;但「这条流观测到过一轮
|
|
353
|
-
// 没有 usage」这件事**照旧成立**,而那种终帧的 `usage` 恰恰是 `flattenUsage(undefined)` 的
|
|
354
|
-
// 全零 —— 早退回空对象等于把「不知道」渲成精确零(正是本位要修的病的另一条路径)。
|
|
355
|
-
// ⇒ 两者**取并**:stats 说了算一半,流内观测算另一半。
|
|
356
|
-
// 🔴 0.67.1 / B-091:取并本身已经**下沉**到 {@link usageLowerBoundOf} —— 这里与读器内部、与
|
|
357
|
-
// chrome 对账臂读的是**同一只函数**,三面不会各算各的(`facts === undefined` 时读器整只不
|
|
358
|
-
// 返回,所以这一行必须自己再调一次那只判据,而不是回头读 `facts`)。
|
|
359
180
|
const lowerBound = usageLowerBoundOf(stats, observed);
|
|
360
181
|
const lowerBoundPart = lowerBound ? { _sema_usage_lower_bound: true } : {};
|
|
361
182
|
if (facts === undefined)
|
|
@@ -364,51 +185,9 @@ function costFactParts(stats, observed) {
|
|
|
364
185
|
...lowerBoundPart,
|
|
365
186
|
...(facts.breakdown !== undefined ? { _sema_cost_breakdown: facts.breakdown } : {}),
|
|
366
187
|
...(facts.nested !== undefined ? { _sema_nested_usage: facts.nested } : {}),
|
|
367
|
-
// ── 0.67.0(core 7.14.0 `TaskResult.stats.usageMissing`)────────────────────────────────
|
|
368
|
-
// 🔴 CC 同名键**语义零改**:`usage` / `modelUsage` / `total_cost_usd` 的字节一个不动,本位是
|
|
369
|
-
// 一个 `_sema_` 超集**判别位**,说的是「上面那些数字是**下界**」。把它折进数字里(比如
|
|
370
|
-
// 把 tokens 抹成 null)会让每一个既有消费者当场坏掉,而它们今天读到的是一笔**看起来
|
|
371
|
-
// 已知**的账 —— 那正是本位要修的病。
|
|
372
|
-
// 🔴 **缺席不铸**(never false):缺席 ⇔ 每一轮都报了 usage。
|
|
373
|
-
// 🔴 与 §31d 的 `usage._sema_total_input_tokens` **同帧不同问**:那一位答「这一行报了多少总
|
|
374
|
-
// 输入」,本位答「这一整条 run 的账数全了没有」。
|
|
375
|
-
// (本位在上面与流内观测取并后已铸;这里不再重复。)
|
|
376
188
|
};
|
|
377
189
|
}
|
|
378
|
-
// ══ 0.68.0(L-244 包侧半场)—— 子代用量「这笔账是下界」的**自有位**,与终帧那一位**分名** ══
|
|
379
|
-
//
|
|
380
|
-
// ── 病形(三重复审 A4/B10 在壳上实抓)──────────────────────────────────────────────────────
|
|
381
|
-
// 壳的子代用量 store 把「这一行还没收口(`partial`)」∪「这一轮引擎没报账(`usageMissing`)」两件事
|
|
382
|
-
// 铸成了一个**与终帧同名**的键 `_sema_usage_lower_bound`。两者是**同名异义**:
|
|
383
|
-
// · 终帧那一位答的是「**这条 run 的合计**是下界」(来源 = `stats.usageMissing` ∪ 流内观测);
|
|
384
|
-
// · 子代面那一位答的是「**这一只子代的这一行**现在还不是最终数」(来源 = 行还没收口 / 那一轮没报账)。
|
|
385
|
-
// 同名的代价是消费面分不出自己读到的是哪一个:一个按键名做聚合的面(把所有 `_sema_usage_lower_bound`
|
|
386
|
-
// 收起来渲一句「本次会话的账是下界」)会把一条**只是还没收口的子代行**算成整条 run 的账不可信。
|
|
387
|
-
//
|
|
388
|
-
// ⇒ 包侧给出**自有名**与**唯一判据**,壳/web/desktop 三端照它渲,谁都不再自己拼一个键名:
|
|
389
|
-
/**
|
|
390
|
-
* 子代用量面的**下界判别位键名**(`_sema_subagent_usage_partial`)。
|
|
391
|
-
*
|
|
392
|
-
* 🔴 它与终帧的 `_sema_usage_lower_bound` **刻意不同名**(见上段):两者答的是两个问题,
|
|
393
|
-
* 一个消费面同时拿到两者时必须分得出来。
|
|
394
|
-
* 🔴 本包**不在任何 wire 帧上铸它** —— 它是**渲染面**的位(端把一行子代用量交给自己的视图时用)。
|
|
395
|
-
* 包给名与判据,是为了三端零自拼(同 `gateIdentity` 的三条身份键字面同一条纪律)。
|
|
396
|
-
*/
|
|
397
190
|
export const SEMA_SUBAGENT_USAGE_PARTIAL_KEY = '_sema_subagent_usage_partial';
|
|
398
|
-
/**
|
|
399
|
-
* 一行子代用量的数字**是不是下界**({@link SEMA_SUBAGENT_USAGE_PARTIAL_KEY} 该不该立)。
|
|
400
|
-
*
|
|
401
|
-
* 三个来源**取并**,每一条都能独立让这一行的数字不是最终数:
|
|
402
|
-
* · `row.usageMissing` —— 这只子代**至少有一轮**引擎没报账(数字照累加,但它是下界);
|
|
403
|
-
* · `row.keyCollision` —— 两个命名空间的 id 撞了字面,这一行是**几只子代的账并起来的**;
|
|
404
|
-
* · `opts.tablePartial` —— 整张表对不上引擎的权威合计(`_sema_nested_usage_by_task_partial`)⇒
|
|
405
|
-
* 表里**每一行**都不可证完整。
|
|
406
|
-
*
|
|
407
|
-
* 🔴 **`false` 不是「这一行是最终数」的证据**:它只说「本端没有任何一条理由认为它是下界」。
|
|
408
|
-
* 行本身还没收口(端自己的 store 知道,包不知道)时,端要自己把那一条并进来 —— 所以这只谓词
|
|
409
|
-
* 收一个 `opts`,而不是假装它掌握全部真相。
|
|
410
|
-
* 🔴 非对象 / 缺席入参 ⇒ `false`(答不出,不是断言);坏形位(非 `true` 的值)不当真。
|
|
411
|
-
*/
|
|
412
191
|
export function subagentUsageIsPartial(row, opts) {
|
|
413
192
|
if (opts?.tablePartial === true)
|
|
414
193
|
return true;
|
|
@@ -416,55 +195,12 @@ export function subagentUsageIsPartial(row, opts) {
|
|
|
416
195
|
return false;
|
|
417
196
|
return row.usageMissing === true || row.keyCollision === true;
|
|
418
197
|
}
|
|
419
|
-
/**
|
|
420
|
-
* L-228 —— 流内子代分表 → 终帧两个超集键的**唯一 mint 点**(成功臂与错误信封共用)。
|
|
421
|
-
*
|
|
422
|
-
* **不导出**:它的入参是一个只有 `runStream` 攒得出来的累加表,推上公面等于邀请宿主自己攒一份
|
|
423
|
-
* 「看见了多少」的账(而那份账的 `partial` 判据在宿主手上不成立)。包侧门走**端到端**素材:
|
|
424
|
-
* 喂子流 `turn_end` + `done` 给 `runStream`,断言终帧上那两个键 —— 那也是三端真正拿到它的路。
|
|
425
|
-
*
|
|
426
|
-
* ── 🔴 `partial` 怎么判(设计定谳,与派车单的「恒铸于重连车道」不同,理由写在这里)────────────
|
|
427
|
-
* 派车单给的形是「本条流不是从 run 起点观测 ⇒ 恒铸 partial」。而本层**没有**「从不从起点观测」
|
|
428
|
-
* 这个读数:`runStream` 手上只有**同一条流内**的事件序号去重表(`seen`),它答的是「这一帧重放过
|
|
429
|
-
* 没有」,答不了「这条流之前还有没有别的帧」;`--resume` / 重连开出来的流与首开的流在本层
|
|
430
|
-
* **逐位不可分**。按一个读不出来的量铸判别位 = 编一件事实。
|
|
431
|
-
* ⇒ 判据改锚在**真正决定结果的量**上([anchor-on-the-deciding-quantity]):拿引擎自己的**权威
|
|
432
|
-
* 合计** `stats.nested` 对账 —— 分表的 `turns` 之和等于 `nested.turns` **且**行数等于 `nested.tasks`
|
|
433
|
-
* 时,这张表**可证**覆盖了整条 run ⇒ 不铸 partial;任何一边对不上、或 `stats.nested` 根本读不出来
|
|
434
|
-
* ⇒ **铸 partial**。
|
|
435
|
-
* 🔴 失效方向是安全的那一侧:上游哪天让某类嵌套轮不上子流 `turn_end`(比如更深一层的编排),
|
|
436
|
-
* 本判据只会**多**铸 partial(把一张其实完整的表说成不完整),**永远不会**把一张残表说成完整。
|
|
437
|
-
* 🔴 **两个键不互证、也不相加**:`_sema_nested_usage`(合计,引擎报的)与本表(流内看见的)是
|
|
438
|
-
* 两份独立的账;`partial` 在场时两者**本来就该不等**,消费方不许拿其中一份去「修正」另一份。
|
|
439
|
-
* 🔴 **0.67.2(车 I 件 I-2)身份键碰撞**:累加表的键按出身隔离(`s:` / `p:`),交付面按裸 id 归并 ——
|
|
440
|
-
* 跨命名空间的同字面合并成一行、立 {@link SemaSubagentUsageRow.keyCollision},并让 `partial` 恒立。
|
|
441
|
-
* 🔴 **0.67.2(车 I 件 I-2b)这张表是「本流快照」,不再从 `EmitContext` 上读**(与件 I-1 逐字同形的
|
|
442
|
-
* 同形存量,轮二异源复审实抓):流结束后它此前**留在调用方对象上**,而本文件这三只终帧投影器是
|
|
443
|
-
* **公面导出** —— 端「A 走 runStream、B 直调终帧投影」共用一个 ctx 时,B 的终帧会带出 **A 的**分表;
|
|
444
|
-
* B 的 `nested` 计数若恰好与那张表对得上(`tasks`/`turns` 相等),`partial` 还不铸 = 一张属于别人的
|
|
445
|
-
* 表被标成「可证完整」。⇒ 表随终帧那一拍**按值**传进来;没传 ⇒ 两个键都不铸(诚实缺席:这次投影
|
|
446
|
-
* 一条子流都没看见),**绝不**回头读残留。
|
|
447
|
-
*/
|
|
448
198
|
function nestedUsageByTaskParts(stats, rollup) {
|
|
449
|
-
// 🔴 一行都没有 ⇒ **什么都不说**:空表会被读成「这条 run 一个子代都没委派」,而真相可能是
|
|
450
|
-
// 「委派了,但这条流没看见任何一轮」(重连车道)。两句话不许折成一句。
|
|
451
199
|
if (rollup === undefined || rollup.size === 0)
|
|
452
200
|
return {};
|
|
453
201
|
let turnsSeen = 0;
|
|
454
|
-
// 🔴 0.67.1:行键的**出身**统计(见 {@link MutableSubagentUsageRow.keyFromParentFallback})。
|
|
455
|
-
// 出身按行是均匀的 —— 0.67.2 起这件事由**键空间**保证:累加表的键带 `s:` / `p:` 前缀,所以
|
|
456
|
-
// 一行的每一轮必然来自同一个命名空间(修前靠的是「`taskId = sourceTaskId ?? parent`」那条推理,
|
|
457
|
-
// 而那条推理在两个空间撞字面时不成立)。
|
|
458
202
|
let fallbackKeyedRows = 0;
|
|
459
203
|
let sourceKeyedRows = 0;
|
|
460
|
-
// ── 🔴 0.67.2(车 I 件 I-2)—— 交付面按**裸 id** 归并,跨命名空间的同字面 = **碰撞** ──────────
|
|
461
|
-
// 交付面的键必须是裸 id(端零改),而累加表的键带出身前缀 ⇒ 两个命名空间里字面相同的两行会在这里
|
|
462
|
-
// 落到同一个交付键上。本层**没有任何读数**能把它们拆回去(core 的合同不保证两个命名空间互斥),
|
|
463
|
-
// 于是:合并数字(不偷偷丢一边)+ 立 `keyCollision`(如实说这一行是混的)+ `partial` 恒立
|
|
464
|
-
// (证不出逐任务归属就不许说完整)。
|
|
465
|
-
// 🔴 为什么不「两行分列」:交付形是 `Record<taskId, row>`,同一个裸 id 不可能占两格 —— 要分列就得
|
|
466
|
-
// 改交付键的形(把出身前缀推到 wire 上),那是三端 BREAKING,而且把本层的内部编码变成端要解的
|
|
467
|
-
// 身份语义。合并 + 显式标记是**同一批事实**下唯一不撒谎的交付形。
|
|
468
204
|
const merged = new Map();
|
|
469
205
|
for (const r of rollup.values()) {
|
|
470
206
|
turnsSeen += r.turns;
|
|
@@ -486,7 +222,6 @@ function nestedUsageByTaskParts(stats, rollup) {
|
|
|
486
222
|
prev.turns += r.turns;
|
|
487
223
|
prev.inputTokens += r.inputTokens;
|
|
488
224
|
prev.outputTokens += r.outputTokens;
|
|
489
|
-
// `cacheReadTokens` 的缺席语义在合并处也守住:两边都没报过 ⇒ 键仍不铸(0 会被读成「零命中」)。
|
|
490
225
|
if (r.cacheReadTokens !== undefined)
|
|
491
226
|
prev.cacheReadTokens = (prev.cacheReadTokens ?? 0) + r.cacheReadTokens;
|
|
492
227
|
if (r.usageMissing === true)
|
|
@@ -496,7 +231,6 @@ function nestedUsageByTaskParts(stats, rollup) {
|
|
|
496
231
|
const keyCollisions = [...merged.values()].filter((v) => v.keyCollision === true).length;
|
|
497
232
|
const rows = {};
|
|
498
233
|
for (const [taskId, v] of merged) {
|
|
499
|
-
// 🔴 落键仍走 `putOwn`(`__proto__` 陷阱):合并臂不是绕过那条纪律的第二条路(见 `putOwn` 头注)。
|
|
500
234
|
putOwn(rows, taskId, {
|
|
501
235
|
turns: v.turns,
|
|
502
236
|
inputTokens: v.inputTokens,
|
|
@@ -511,15 +245,7 @@ function nestedUsageByTaskParts(stats, rollup) {
|
|
|
511
245
|
: undefined;
|
|
512
246
|
const authTurns = finiteOrAbsent(nested?.turns);
|
|
513
247
|
const authTasks = finiteOrAbsent(nested?.tasks);
|
|
514
|
-
// 🔴 0.67.1:**出身混合 ⇒ 证不出完整**。计数相等只说明「数目对得上」,说不了「逐任务归属对得上」
|
|
515
|
-
// —— 拆一行与并一行的误差方向相反、可以恰好抵消(见 `keyFromParentFallback` 头注的反例)。
|
|
516
|
-
// 出身一致时既有两条对账才是充分的:全真身份 ⇒ 一行一任务;全回落 ⇒ 多任务共父会让行数 <
|
|
517
|
-
// `nested.tasks`,那一格自己会翻。失效方向仍是安全的那一侧(只会**多**铸 partial)。
|
|
518
248
|
const mixedKeyOrigin = fallbackKeyedRows > 0 && sourceKeyedRows > 0;
|
|
519
|
-
// 🔴 0.67.2:碰撞也单独挡一格。按构造 `keyCollisions > 0 ⇒ mixedKeyOrigin`(同一个命名空间里的键
|
|
520
|
-
// 本来就唯一,撞字面只能跨空间发生),所以这一格今天是**冗余的第二道**;留着是因为两条判据问的
|
|
521
|
-
// 不是同一件事(「这条流上有两种出身」vs「这一行里混了两种出身」),而上游哪天再加一个身份来源
|
|
522
|
-
// 时,前者的判法要改、后者不用。
|
|
523
249
|
const complete = !mixedKeyOrigin && keyCollisions === 0 && authTurns !== undefined && authTasks !== undefined &&
|
|
524
250
|
authTurns === turnsSeen && authTasks === Object.keys(rows).length;
|
|
525
251
|
return {
|
|
@@ -527,125 +253,53 @@ function nestedUsageByTaskParts(stats, rollup) {
|
|
|
527
253
|
...(complete ? {} : { _sema_nested_usage_by_task_partial: true }),
|
|
528
254
|
};
|
|
529
255
|
}
|
|
530
|
-
/** P1-5 — real elapsed ms since the stream opened (runStream stamps startedAtMs); 0 only pre-stamp. */
|
|
531
256
|
function elapsedMs(ctx) {
|
|
532
257
|
return typeof ctx.startedAtMs === 'number' ? Math.max(0, Date.now() - ctx.startedAtMs) : 0;
|
|
533
258
|
}
|
|
534
|
-
/**
|
|
535
|
-
* micro-USD → USD。引擎账面的成本单位是 **micro-USD**(百万分之一美元,整数轨:1e6 micro = 1 USD;
|
|
536
|
-
* 整数是为了不吃 FP 漂移)。CC 的输出面字段 `total_cost_usd` / `costUSD` 单位是 **USD**(字段名即
|
|
537
|
-
* 单位),所以出口一律 `/1e6`。非有限值(NaN/Infinity)不上账 —— Infinity 比 undefined 更糟,它会被
|
|
538
|
-
* 当成真数字参与求和,把一条离谱账悄悄摊进总计(与 SDK `taskCostMicroUsd()` 的规约逐条同义;
|
|
539
|
-
* `mapModelUsage()` 里的 `costMicroUsd / 1e6` 是同一换算的既有用法,两处此后共用本函数)。
|
|
540
|
-
*
|
|
541
|
-
* 为什么不直接调 SDK 的 `taskCostMicroUsd()`:本文件在 `runStream` **可移植闭包**内,portability 门
|
|
542
|
-
* 对该闭包断言「值级外部包 = 空集」(EXPECTED_PACKAGES_KERNEL),值级 import SDK 会当场红。故就地
|
|
543
|
-
* 复刻规约,单一真源以 SDK 那份注释为准。
|
|
544
|
-
*/
|
|
545
259
|
function microUsdToUsd(micro) {
|
|
546
260
|
return typeof micro === 'number' && Number.isFinite(micro) ? micro / 1e6 : null;
|
|
547
261
|
}
|
|
548
|
-
/**
|
|
549
|
-
* P1-5 — `total_cost_usd` truthfulness: 报**引擎真的说出来的那个数**;引擎**没说**(键缺席 /
|
|
550
|
-
* 非有限)才报 `null`(JSON 消费者看到 "unknown",绝不是一个编出来的零)。
|
|
551
|
-
* 🔴 **0.65.0(B-073 ①)口径订正**:P1-5 当初写的是「只有真正的正成本才报,其余一律 null」,
|
|
552
|
-
* 前提是那时 `0` 分不清「免费」与「没配 MODEL_COST_*」。core 之后把这两件事在 wire 上**分开**
|
|
553
|
-
* (缺席 = 没定价;显式 0 = 声明免费),旧口径于是开始把一条真免费的 run 渲成「不知道」——
|
|
554
|
-
* 那是同一条病的反向。现在的口径见 {@link costOrNull}。CC 的 schema 字段是 numeric ——
|
|
555
|
-
* number-guarded 的读者(replEntry cost fold)本来就把非 number 当缺席。
|
|
556
|
-
*
|
|
557
|
-
* 🔴 键迁移([2006] cli 自查最重命中,2026-07-29):取数源从 legacy float `TaskStats.costUsd` 换成
|
|
558
|
-
* 整数 `TaskStats.costMicroUsd`。`costUsd` 已被 **core 2.0.0 / server 1.319.0 / SDK 1.0.0 同批删除**
|
|
559
|
-
* (发端、适配、类型三层),对 core 2.0.0+ 引擎该键恒 undefined ⇒ 本函数恒 null ⇒ `sema -p
|
|
560
|
-
* --output-format json` 的 `total_cost_usd` **恒 null**,而账其实一直在 `costMicroUsd` 上
|
|
561
|
-
* (本文件 `mapModelUsage()` 早就在读它 = 两代键并存的实锤)。devDep 此前钉 SDK `^0.1.7`(0.x 的 caret 是精确锁)
|
|
562
|
-
* ⇒ 类型层看到的还是「两轨都在」的旧声明,对 1.0.0 才报 TS2345 —— 校旧物的门抓不住这类断链,故
|
|
563
|
-
* 另有 `run-sdk-floor-test.mjs` 断言实装 SDK 地板 ≥ 1.1。
|
|
564
|
-
*
|
|
565
|
-
* 老引擎只发 float `costUsd` 时**不做兼容换算**:单轨之后读到 undefined(当场可见「不知道」)好过
|
|
566
|
-
* 把一笔来源可疑的账静默吸收成看起来正常的数字(SDK normalize.ts 的 BREAKING 留档同款裁定;
|
|
567
|
-
* 本仓 [clean-cut-no-legacy-compat])。
|
|
568
|
-
*/
|
|
569
262
|
function costOrNull(stats) {
|
|
570
|
-
// 🔴 B-073 ①(0.65.0):修前是 `usd !== null && usd > 0 ? usd : null` —— 一条**数值真值判定
|
|
571
|
-
// 当存在性判定**(§B10 病族)的教科书例。core 早已把两件事在 wire 上分开:
|
|
572
|
-
// · `costMicroUsd` **ABSENT** = 有一笔花销没定价 ⇒ 报 `null`(不知道);
|
|
573
|
-
// · `costMicroUsd === 0` = 这台模型**显式声明免费**(core 逐字
|
|
574
|
-
// `an explicit all-zero Model.cost still reports 0`)⇒ 就该报 `0`。
|
|
575
|
-
// 旧写法把「声明免费」也渲成 `null`,于是一条真免费的 run 在 `-p --output-format json` 上
|
|
576
|
-
// 说不出「免费」;而它当初写成 `> 0` 的理由(「0 可能是没配 MODEL_COST_*」)在 core 把缺席
|
|
577
|
-
// 做成可表达的那一刻就失效了 —— 那一档现在由**缺席**自己承载,不必再借 0 当哨兵。
|
|
578
|
-
// 负数照报:退款/修正在引擎账面上是合法值,包不当第二个会计(非有限值仍由 microUsdToUsd 判掉)。
|
|
579
263
|
return microUsdToUsd(stats?.costMicroUsd);
|
|
580
264
|
}
|
|
581
|
-
// 件2a(中断事故修复批 G,2026-07-15,症状2 第一环):参数放宽 TaskStats | undefined + 全链守卫。
|
|
582
|
-
// 409 active-run 拒绝时引擎的 done 帧本体是 {status:'failed', errorMessage, activeTaskId} —— NO stats
|
|
583
|
-
// (ai-agent-service server.ts:1526 同型),此前 `mapModelUsage` 裸读 `(stats).modelUsage` 直接
|
|
584
|
-
// TypeError,炸穿 runStream → seamQuery catch → 误诊 "engine is unreachable"(件2c)。缺 stats 时
|
|
585
|
-
// 产出合法空 usage 形状(flattenUsage 本就守卫;这里返回 {},`modelUsageFor` 再按 r.model 合成当前行)。
|
|
586
|
-
//
|
|
587
|
-
// MF-25 — map the wire's per-model usage split (`stats.modelUsage`, an open `{ <modelId>: usage }` map;
|
|
588
|
-
// e.g. `{ "deepseek-v4-pro": {...} }`) into the CC `SDKResult.modelUsage` record (model-id → CC ModelUsage).
|
|
589
|
-
// 🔴 REF-CC-062(xlate-08):八键形状与那套 load-bearing 改名**不在本文件构造** —— 单源 mint 点是
|
|
590
|
-
// `turnUsageToModelUsage.ts` 的 `toCcModelUsage()`(core 3.0.0 的 inputTokens 语义翻转注也钉在那里)。
|
|
591
|
-
// 本函数只负责 wire 边界的窄化:开集 map 的每个值都是 `unknown`,先取出数值位再交给 mint 点。
|
|
592
265
|
function mapModelUsage(stats) {
|
|
593
266
|
const raw = stats?.modelUsage;
|
|
594
267
|
if (raw === undefined || raw === null || typeof raw !== 'object')
|
|
595
268
|
return {};
|
|
596
269
|
const out = {};
|
|
597
|
-
/** 边界窄化:非数值一律当缺席交给 mint 点(它把缺席与非有限值一并折 0)。 */
|
|
598
270
|
const numOrAbsent = (v) => (typeof v === 'number' ? v : undefined);
|
|
599
271
|
for (const [modelId, u] of Object.entries(raw)) {
|
|
600
272
|
if (u === undefined || u === null || typeof u !== 'object')
|
|
601
273
|
continue;
|
|
602
274
|
const m = u;
|
|
603
|
-
// 0.67.1 同形族:`modelId` 也是 wire 给的键 ⇒ 落键走 {@link putOwn}。
|
|
604
275
|
putOwn(out, modelId, withTerminalUsageFacts(toCcModelUsage({
|
|
605
276
|
inputTokens: numOrAbsent(m.inputTokens),
|
|
606
277
|
outputTokens: numOrAbsent(m.outputTokens),
|
|
607
278
|
cacheReadTokens: numOrAbsent(m.cacheReadTokens),
|
|
608
279
|
cacheWriteTokens: numOrAbsent(m.cacheWriteTokens),
|
|
609
280
|
costMicroUsd: numOrAbsent(m.costMicroUsd),
|
|
610
|
-
// D-2(0.66.0):per-model 行今天也不带这一格 ⇒ 宽读一次,读不出由 mint 点立判别位。
|
|
611
281
|
webSearchRequests: numOrAbsent(m.webSearchRequests),
|
|
612
282
|
}), m));
|
|
613
283
|
}
|
|
614
284
|
return out;
|
|
615
285
|
}
|
|
616
|
-
/**
|
|
617
|
-
* P1-5 — 终帧的 `modelUsage`:优先 wire 的 per-model split;缺席(老引擎 stats 无 MF-25 分表,或
|
|
618
|
-
* split-less done)时按**当前模型**从扁平 `TaskStats` 合成一行,JSON 消费者才知道这笔 usage 是谁产的。
|
|
619
|
-
* 🔴 REF-CC-055/062:success 臂与五个 error 臂此前各自持有这段逻辑的结果(合成行只在 success 路径
|
|
620
|
-
* 算一次、error 臂靠共享局部变量捎带),现在两条路都调本函数 —— 同一输入同一输出,单一构造点。
|
|
621
|
-
*/
|
|
622
286
|
function modelUsageFor(stats, model) {
|
|
623
287
|
const split = mapModelUsage(stats);
|
|
624
288
|
if (Object.keys(split).length > 0)
|
|
625
289
|
return split;
|
|
626
290
|
if (typeof model !== 'string' || model.length === 0)
|
|
627
291
|
return split;
|
|
628
|
-
// 键迁移(见 costOrNull 头注):legacy float `costUsd` → 整数 `costMicroUsd`(/1e6 → USD)。
|
|
629
|
-
// ⚠️ 这一处**类型门抓不到**:TaskStats 带 `[key: string]: unknown` 开集索引,`typeof
|
|
630
|
-
// stats?.costUsd === 'number'` 的旧写法在 SDK 1.x 下照样编译得过,只是恒假 ⇒ 合成行的
|
|
631
|
-
// costUSD 静默恒 0(比报错更隐蔽)。tsc 只红了 6 处直传,这处靠人核 + pure 门的行为钉。
|
|
632
292
|
return {
|
|
633
293
|
[model]: withTerminalUsageFacts(toCcModelUsage({
|
|
634
294
|
inputTokens: stats?.promptTokens,
|
|
635
295
|
outputTokens: stats?.outputTokens,
|
|
636
296
|
cacheReadTokens: stats?.cachedTokens,
|
|
637
|
-
// B-073 ③ 族扫:合成行是 `flattenUsage` 的**同形第二处**,同批一并改读真值。
|
|
638
297
|
cacheWriteTokens: stats?.cacheWriteTokens,
|
|
639
298
|
costMicroUsd: stats?.costMicroUsd,
|
|
640
|
-
// D-2(0.66.0):与扁平 usage 同一格同一读法(开集宽读,读不出由 mint 点立判别位)。
|
|
641
299
|
webSearchRequests: stats?.webSearchRequests,
|
|
642
300
|
}), stats),
|
|
643
301
|
};
|
|
644
302
|
}
|
|
645
|
-
/**
|
|
646
|
-
* 给一条已铸好的 CC `ModelUsage` 行挂上终局那三个座位(读不出的一律不铸)。
|
|
647
|
-
* `raw` = 这一行的 wire 原形(分表的那一行,或扁平 `TaskStats` —— 两处键名相同)。
|
|
648
|
-
*/
|
|
649
303
|
function withTerminalUsageFacts(row, raw) {
|
|
650
304
|
const total = finiteOr0Absent(raw?.totalInputTokens);
|
|
651
305
|
const long = finiteOr0Absent(raw?.cacheWriteTokensLong);
|
|
@@ -657,51 +311,19 @@ function withTerminalUsageFacts(row, raw) {
|
|
|
657
311
|
...(long !== undefined ? { _sema_cache_write_tokens_long: long } : {}),
|
|
658
312
|
};
|
|
659
313
|
}
|
|
660
|
-
/** 有限数窄化(非数 / 非有限 ⇒ 缺席;`0` 是读数不是缺席)。 */
|
|
661
314
|
function finiteOr0Absent(v) {
|
|
662
315
|
return typeof v === 'number' && Number.isFinite(v) ? v : undefined;
|
|
663
316
|
}
|
|
664
|
-
/**
|
|
665
|
-
* TaskResult 五键最小消费批([1543] SDK-M,2026-07-23)之一 —— `degraded` = 模型降级链实录
|
|
666
|
-
* (from/to/reason/atTurn;多模型网关部署的关键可观测面)。
|
|
667
|
-
*
|
|
668
|
-
* 🔴 REF-CC-056(xlate-02):文件头共享注一直写着「success/timeout/blocked/unknown 各终态都可能带,
|
|
669
|
-
* **恒 additive 附上**」,而实际只有 timeout 与 success 两臂 spread 了它,blocked/park/未知/failed
|
|
670
|
-
* 四臂全漏 —— 一条经历过降级并最终失败的 run,降级链在终帧上无痕消失,而注释向下一棒承诺它在。
|
|
671
|
-
* 修法不是再补四处 spread(那是第五、六个构造点),而是把它放进 {@link errorResult} 信封本体:
|
|
672
|
-
* 「恒 additive 附上」这句话从此是结构,不是散文。
|
|
673
|
-
*
|
|
674
|
-
* 边界守门(M1):wire 上的值仍按对象守卫 —— 非对象/缺席一律不 stamp 这个键(诚实缺席)。
|
|
675
|
-
*/
|
|
676
317
|
function degradedOf(r) {
|
|
677
318
|
const d = r.degraded;
|
|
678
319
|
return d !== undefined && d !== null && typeof d === 'object' ? d : undefined;
|
|
679
320
|
}
|
|
680
|
-
// ── 到限码词表(core 5.8.0 [2489] 新码单代)──────────────────────────────────────────────────
|
|
681
|
-
// 退役批(server 6.0.0 捆 core 5.8.0 发车,2026-08-04):三个集合里的 5.7 旧码成员
|
|
682
|
-
// (`budget.exceeded`/`budget.precall`/`limit.max_turns`)已删,只留新码。放成集合而不是就地 `||`
|
|
683
|
-
// 链的原因不变:词表变动集中在一处可数,不必满文件找 `===` 比较。
|
|
684
|
-
// G1 去字面化(2026-08-04):**码的字面**已收编进 `engineErrorCodes.ts`(单一真源),这里留的是
|
|
685
|
-
// 「哪些码映射到哪个 CC subtype」的**映射事实** —— 那是本文件的职责,不是词表的。
|
|
686
|
-
/** 成本到限 → CC `error_max_budget_usd`(唯一一个 CC 有专词的预算轴)。 */
|
|
687
321
|
const COST_EXCEEDED_CODES = new Set([LIMITS_MAX_COST_EXCEEDED]);
|
|
688
|
-
/** 轮数到限 → CC `error_max_turns`。 */
|
|
689
322
|
const TURNS_EXCEEDED_CODES = new Set([LIMITS_MAX_TURNS_EXCEEDED]);
|
|
690
|
-
/**
|
|
691
|
-
* 「截断」族到限码:CC 4 词表里**没有**对应词(token 账不是美元账、墙钟停不是轮数耗尽),
|
|
692
|
-
* 所以 subtype 落诚实兜底词,真实语义靠 errorCode 透传;且这两种停因都可能已产出正文
|
|
693
|
-
* ([2489] 对 max_tokens 明记 result 带正文;墙钟停是既有的写出窗 salvage 语义)⇒ 共用 salvage 腿。
|
|
694
|
-
*/
|
|
695
323
|
const CUTOFF_EXCEEDED_CODES = new Set([
|
|
696
324
|
LIMITS_MAX_TOKENS_EXCEEDED,
|
|
697
325
|
LIMITS_MAX_WALLTIME_EXCEEDED,
|
|
698
326
|
]);
|
|
699
|
-
/**
|
|
700
|
-
* 🔴 **errorCode → CC subtype 的唯一映射点**。收编前这段 `||`/三元链在 done{failed} 与
|
|
701
|
-
* `failedToSdkResult` 两处各写一份,而且两份**并不同义**(事件臂只认 budget.*,连 limit.max_turns
|
|
702
|
-
* 都不认 ⇒ 同一个「轮数耗尽」经 done 帧来是 error_max_turns、经 failed 事件来是
|
|
703
|
-
* error_during_execution)。5.8.0 的词表迁移要在两处各改一遍正是这类漏配的温床,故先收成单点。
|
|
704
|
-
*/
|
|
705
327
|
function subtypeForErrorCode(code) {
|
|
706
328
|
if (code === undefined || code.length === 0)
|
|
707
329
|
return 'error_during_execution';
|
|
@@ -709,19 +331,10 @@ function subtypeForErrorCode(code) {
|
|
|
709
331
|
return 'error_max_budget_usd';
|
|
710
332
|
if (TURNS_EXCEEDED_CODES.has(code))
|
|
711
333
|
return 'error_max_turns';
|
|
712
|
-
// assemble-result.js:58 该 code 的语义字面就是 CC 这词:「did not produce a valid structured
|
|
713
|
-
// output within the retry limit」。
|
|
714
334
|
if (code === OUTPUT_INVALID)
|
|
715
335
|
return 'error_max_structured_output_retries';
|
|
716
|
-
// 🔴 开集兑现处:未知/未来码(core 5.10.0 的 `config.*` 拒绝族、`usage.window_exhausted`、
|
|
717
|
-
// `env.lifetime_expired` 都落这里)一律诚实兜底词 —— CC 四词表里没有它们的对位词,真实语义
|
|
718
|
-
// 靠上面 `errorCode` 原样透传辨认。绝不为了「有个更像的词」把它们塞进任何一个已知 subtype。
|
|
719
336
|
return 'error_during_execution';
|
|
720
337
|
}
|
|
721
|
-
/**
|
|
722
|
-
* 写出窗抢救文本:引擎已兑现的最终正文(`result` 优先,回落 `salvagedOutput`)。空白串当缺席
|
|
723
|
-
* —— 空串骑上 `result` 键就是「冒充有产出」。
|
|
724
|
-
*/
|
|
725
338
|
function salvagedTextOf(r) {
|
|
726
339
|
const salvagedOutput = r.salvagedOutput;
|
|
727
340
|
return typeof r.result === 'string' && r.result.trim().length > 0
|
|
@@ -730,137 +343,54 @@ function salvagedTextOf(r) {
|
|
|
730
343
|
? salvagedOutput
|
|
731
344
|
: undefined;
|
|
732
345
|
}
|
|
733
|
-
/**
|
|
734
|
-
* 截断臂(墙钟/ token 到限)的公共两位:errors[0] + 可选 salvage。
|
|
735
|
-
*
|
|
736
|
-
* [2084]②b:引擎的 cutoff 句承诺「cut off to preserve a write-out window」,但 pre-call throw 路径上
|
|
737
|
-
* 写出窗可能零兑现(core dist/brain/stream-engine 五处 throw,载体天生空)。抢救为空时补诚实尾注 ——
|
|
738
|
-
* 每一层都复述没兑现的承诺,消费者就无从分辨救没救回来。
|
|
739
|
-
*/
|
|
740
346
|
function cutoffParts(r, message, fallbackMessage, code) {
|
|
741
347
|
const salvaged = salvagedTextOf(r);
|
|
742
348
|
return {
|
|
743
349
|
errors: [
|
|
744
350
|
`${message ?? fallbackMessage} (${code})${salvaged === undefined ? ' — no output survived the cutoff' : ''}`,
|
|
745
351
|
],
|
|
746
|
-
// 写出窗 salvage(additive seam 字段):非空时随帧带出 —— CC error 帧无 result 键,但静默丢弃
|
|
747
|
-
// 已救回的答案对 -p 集成面是净损失(TB qe** 实证)。
|
|
748
352
|
...(salvaged !== undefined ? { salvagedResult: salvaged } : {}),
|
|
749
353
|
};
|
|
750
354
|
}
|
|
751
|
-
/**
|
|
752
|
-
* 🔴 **CC `SDKResultError` 信封的唯一 mint 点**(REF-CC-055 / xlate-01,E1 单源构造)。
|
|
753
|
-
*
|
|
754
|
-
* 收编前这 13 个位在**六处**逐字重复:done 的 failed/timeout/blocked/park/未知终态五臂,加上
|
|
755
|
-
* `failedToSdkResult` —— 后者看着像「另一种信封」,其实是同一信封 `stats === undefined` 的退化
|
|
756
|
-
* 实例被手抄了一遍(`num_turns: 0` ≡ `stats?.turns ?? 0`、`total_cost_usd: null` ≡ `costOrNull(undefined)`、
|
|
757
|
-
* 手写五键零 usage ≡ `flattenUsage(undefined)`、`modelUsage: {}` ≡ `mapModelUsage(undefined)`)。
|
|
758
|
-
* 六份手抄的代价不是行数,是 REF-CC-056 那种**漏配**:给信封加一个位要改六处,漏掉的那几处没有
|
|
759
|
-
* 任何门会说话。
|
|
760
|
-
*/
|
|
761
355
|
function errorResult(ctx, parts) {
|
|
762
356
|
return stamp(ctx, {
|
|
763
|
-
// Explicit (always-undefined) uuid/session_id: stamp() always overwrites session_id from
|
|
764
|
-
// ctx and falls back to a fresh uuid when body.uuid is nullish, so this is a pure type-level
|
|
765
|
-
// nudge (zero runtime effect) — without at least one property name in common with stamp's
|
|
766
|
-
// all-optional constraint, TS's "weak type" detection rejects the call (TS2559/TS2345/TS2353).
|
|
767
357
|
uuid: undefined,
|
|
768
358
|
session_id: undefined,
|
|
769
359
|
type: 'result',
|
|
770
360
|
subtype: parts.subtype,
|
|
771
|
-
duration_ms: parts.durationMs,
|
|
772
|
-
duration_api_ms: parts.durationMs,
|
|
361
|
+
duration_ms: parts.durationMs,
|
|
362
|
+
duration_api_ms: parts.durationMs,
|
|
773
363
|
is_error: true,
|
|
774
|
-
num_turns: parts.stats?.turns ?? 0,
|
|
775
|
-
stop_reason: null,
|
|
776
|
-
total_cost_usd: costOrNull(parts.stats),
|
|
364
|
+
num_turns: parts.stats?.turns ?? 0,
|
|
365
|
+
stop_reason: null,
|
|
366
|
+
total_cost_usd: costOrNull(parts.stats),
|
|
777
367
|
usage: flattenUsage(parts.stats),
|
|
778
368
|
modelUsage: modelUsageFor(parts.stats, parts.model),
|
|
779
|
-
// D-1 / L-192①:两句话不再折成一句 —— 清单 + 「有没有这本账」的判别位,见 permissionDenialParts。
|
|
780
369
|
...permissionDenialParts(parts.stats, parts.observed?.toolInputByCallId),
|
|
781
|
-
// D-3 / B-068:失败/到限/park 的 run 一样花过钱,账不因结局不好就不报。
|
|
782
370
|
...costFactParts(parts.stats, parts.observed),
|
|
783
|
-
// CC-06:引擎生效面两键(失败臂同带)。
|
|
784
371
|
...(parts.facts ?? {}),
|
|
785
|
-
// L-228(0.67.0):流内 per-subagent 分表的收口快照(判据本体在 `nestedUsageByTaskParts`)。
|
|
786
|
-
// 🔴 与成本三段同理 —— 失败的 run 一样委派过,账不因结局不好就不报。
|
|
787
372
|
...nestedUsageByTaskParts(parts.stats, parts.observed?.nestedUsageByTask),
|
|
788
373
|
errors: [...parts.errors],
|
|
789
374
|
...(parts.errorCode !== undefined && parts.errorCode.length > 0 ? { errorCode: parts.errorCode } : {}),
|
|
790
375
|
...(parts.degraded !== undefined ? { degraded: parts.degraded } : {}),
|
|
791
|
-
// ADAPTER-F4:具名 additive 位(见 `ErrorResultParts.salvagedResult`)。展开的是**一个已知键**,
|
|
792
|
-
// 覆写不到上面任何一个不变量;要加第二个位必须动这里,而动这里在 diff 里显形。
|
|
793
376
|
...(parts.salvagedResult !== undefined ? { result: parts.salvagedResult } : {}),
|
|
794
|
-
// CC-50:结局不知道的稀疏标记(见 `ErrorResultParts.outcomeUnknown`);真终局帧永不带。
|
|
795
377
|
...(parts.outcomeUnknown === true ? { _sema_outcome: 'unknown' } : {}),
|
|
796
378
|
});
|
|
797
379
|
}
|
|
798
|
-
|
|
799
|
-
export function doneToSdkResult(ev, ctx,
|
|
800
|
-
/**
|
|
801
|
-
* 0.67.2:**这一条流**的收口快照 —— usage 缺口观测(见 {@link usageLowerBoundOf})与 per-subagent
|
|
802
|
-
* 累加表(见 {@link nestedUsageByTaskParts})。两格都是 per-stream 的事实,缺席 ⇒ 这次投影没有流内面
|
|
803
|
-
* (只读 `stats` 那一半、两个分表键都不铸),**绝不**回头去读调用方对象上可能残留的上一条流。
|
|
804
|
-
*/
|
|
805
|
-
observed) {
|
|
806
|
-
// sdk 4.1.0([2395]E 调和):`done.result` 是判别联合 `TaskResult | ActiveRunConflictDoneResult`。
|
|
807
|
-
// 🔄 全窗复审 ADAPTER-1/-2 收口(2026-08-03):首版接线用 `'stats' in r` 铸 tr 并让 result/model/
|
|
808
|
-
// degraded 全走 tr?.——把「stats 在不在」错当成了这些键的门控(anchor-on-the-deciding-quantity
|
|
809
|
-
// 反例):R1b 抢救腿从 run row 合成的 done 帧 stats 可缺席但带答案正文,被投影成空成功;且
|
|
810
|
-
// `in` 对非对象 result 抛 TypeError(旧码宽读不抛,件2c 事故形)。正解=各键**独立宽读**
|
|
811
|
-
// (键在就读、缺席 undefined,与拆分前逐键同语义),判别联合只影响类型声明不影响读法。
|
|
380
|
+
export function doneToSdkResult(ev, ctx, observed) {
|
|
812
381
|
const rRaw = ev.result;
|
|
813
382
|
const rec = typeof rRaw === 'object' && rRaw !== null ? rRaw : {};
|
|
814
383
|
const r = rec;
|
|
815
384
|
const stats = r.stats;
|
|
816
|
-
// P1-5 — the terminal frame's session_id must be the ENGINE-AUTHORITATIVE id (done.result.sessionId):
|
|
817
|
-
// on the headless `-p` path ctx was seeded from the REQUEST (historically the mock constant
|
|
818
|
-
// "sema-mock-session-0001" leaked to stdout, so `sema -r <session_id>` on the JSON output could never
|
|
819
|
-
// resume). The engine echo is the id its session store actually keyed — adopt it for the result stamp.
|
|
820
385
|
const echoedSid = r.sessionId;
|
|
821
386
|
if (typeof echoedSid === 'string' && echoedSid.length > 0)
|
|
822
387
|
ctx.sessionId = echoedSid;
|
|
823
|
-
// P1-5 — modelUsage/usage 的构造已收敛到 `flattenUsage` / `modelUsageFor`(REF-CC-055/062),
|
|
824
|
-
// 四个 error 臂经 `errorResult` 信封拿到同一份,success 臂在下方直接调 —— 同一输入同一输出。
|
|
825
|
-
// clay P0 壳半场([450],2026-07-05):上游 4xx(如无 vision 模型收到 image)时
|
|
826
|
-
// 引擎的 done 帧本体带 result.status='failed' + errorMessage —— 传播链没吞,断点在这:
|
|
827
|
-
// 此前无条件投影 subtype:'success'/is_error:false,把失败洗成"成功空回复"= 用户看到的
|
|
828
|
-
// 静默卡死。status failed → 走 SDKResultError 形态(errors[] 渲染线现成)。
|
|
829
|
-
// TS2367 note: `TaskResult & { status?: string }` does NOT actually widen `status` — TS
|
|
830
|
-
// intersects the pre-existing required `RunStatus` with the added optional `string`, and
|
|
831
|
-
// `RunStatus & string` stays `RunStatus` (the narrower member wins). That's exactly why the
|
|
832
|
-
// status branches below (the SDK's `RunStatus` is a CLOSED union, while core's TaskStatus vocab
|
|
833
|
-
// moves on its own release train — see file header) used to type-error as "no overlap": the cast
|
|
834
|
-
// looked like a widening but wasn't one. `Omit` the narrow key first so the added wider
|
|
835
|
-
// `status?: string` actually applies — that is also what keeps the 未知终态 defensive arm below
|
|
836
|
-
// expressible at all.
|
|
837
|
-
// 🔴 0.60.0(engine ≥7.64.0 / sdk 8.4.0):终局分流的判据从**八个平面键**换成**一条带标因由**
|
|
838
|
-
// (`result.terminal`)。读法单源在 `runTerminal.readRunTerminal` —— 本文件一个 `status` 字面
|
|
839
|
-
// 都不再比较(平面形的两个来源、以及「不认识的终态词绝不落成功」那条不变量,全在读器里)。
|
|
840
|
-
// `null` = 这份载体上连终态词都没有(mock 车道 / 不带 status 的旧合成帧)⇒ 0.72.12 起 fail-closed +
|
|
841
|
-
// `_sema_outcome:'unknown'`(此前维持成功臂;取舍见 `ErrorResultParts.outcomeUnknown`)。
|
|
842
388
|
const terminal = readRunTerminal(rRaw);
|
|
843
389
|
const durationMs = elapsedMs(ctx);
|
|
844
|
-
// [909]B1 — errorCode 透传(additive seam 字段;CC schema 无此键,与 success 臂 `model` 同款超集
|
|
845
|
-
// 姿势):引擎值原样,绝不铸造。所有 error 臂共用(`errorResult` 信封负责 stamp)。
|
|
846
|
-
// 🔴 因由形下「码属于失败」是**形状**:paused / blocked 上引擎写不出码 ⇒ 这两臂的 `errorCode`
|
|
847
|
-
// 从 0.60.0 起恒缺席(此前 `review.pending` 骑在 park 帧的平面 errorCode 上)。扁平形回放的
|
|
848
|
-
// 历史行仍带得动它(读器在那三臂上保留 `code`),所以盘上真有的事实不丢。
|
|
849
390
|
const errorCode = runTerminalCode(terminal);
|
|
850
|
-
// TaskResult 五键最小消费批([1543] SDK-M,2026-07-23):additive seam 字段——
|
|
851
|
-
// · degraded = 模型降级链实录,**各终态恒 additive 附上**(见 `degradedOf` 头注 / REF-CC-056);
|
|
852
|
-
// · structuredOutput = outputSchema 任务的结构化产出(success 臂);
|
|
853
|
-
// · salvagedOutput = degenerate/到限截断抢救出的最后模型文本(`cutoffParts` 的 salvage 回落源:
|
|
854
|
-
// failed + limits.max_{tokens,walltime}_exceeded 两族共用)。
|
|
855
391
|
const degraded = degradedOf(r);
|
|
856
|
-
/** 四个 error 臂共享的固定位(信封其余 13 位见 `errorResult`)。 */
|
|
857
392
|
const errorBase = { durationMs, stats, model: r.model, errorCode, degraded, observed, facts: effectiveFactParts(rec) };
|
|
858
393
|
if (terminal?.kind === 'failed') {
|
|
859
|
-
// [909]B1 — failed 臂 subtype 语义化(见文件头对表);core 5.8.0([2489])起到限码全部改名,
|
|
860
|
-
// 映射本身已收进单点 `subtypeForErrorCode`(退役批后只认新码)。
|
|
861
|
-
// 5.8.0 的「截断」族到限(token/墙钟):subtype 只能落诚实兜底词,但这两种停因**可能已产出正文**
|
|
862
|
-
// —— [2489] 对 limits.max_tokens_exceeded 明记「result 带已产出正文」,墙钟停是既有写出窗语义,
|
|
863
|
-
// 两族共用 `cutoffParts`(salvage + 零抢救诚实尾注)。
|
|
864
394
|
const failedCode = terminal.code;
|
|
865
395
|
const failedMessage = terminal.message;
|
|
866
396
|
const failedSubtype = subtypeForErrorCode(failedCode);
|
|
@@ -876,9 +406,6 @@ observed) {
|
|
|
876
406
|
return errorResult(ctx, {
|
|
877
407
|
...errorBase,
|
|
878
408
|
subtype: failedSubtype,
|
|
879
|
-
// rewind 族错误码透传(server 1.192 [838]③ 实测:stream 腿把 resume_at.before_* /
|
|
880
|
-
// rewind_snapshot.unresolvable 骑在失败因由的码上)—— 与 failedToSdkResult 的同款 append
|
|
881
|
-
// 对齐,message 后附 code 便于对账。
|
|
882
409
|
errors: [
|
|
883
410
|
isRewindFamilyCode(failedCode) && failedMessage
|
|
884
411
|
? `${failedMessage} (${failedCode})`
|
|
@@ -886,15 +413,6 @@ observed) {
|
|
|
886
413
|
],
|
|
887
414
|
});
|
|
888
415
|
}
|
|
889
|
-
// 留档(退役批,2026-08-04):此处曾有一条 `rr.status === 'timeout'` 的窗口期臂 —— 5.7 的墙钟
|
|
890
|
-
// 停是 `status:'timeout'` + `errorCode:'limit.timeout'`([909]B1;此前落 success 臂 = TB 的
|
|
891
|
-
// 「4 个引擎已记 timeout 的 trial 全 subtype:success」)。core 5.8.0 把这个终态词整体退役,墙钟停
|
|
892
|
-
// 改走上面的 failed + `limits.max_walltime_exceeded`(同处置,共用 `cutoffParts`);server 6.0.0
|
|
893
|
-
// 捆 core 5.8.0 发车后旧形不再上 wire,本臂随之删除。未知终态(含万一漏网的 'timeout')不会掉回
|
|
894
|
-
// 空成功 —— 下方兜底臂把任何非 completed 终态都投影成 SDKResultError。
|
|
895
|
-
// [909]B1 — blocked 终态:agent 自报无法推进(assemble-result.js:99,只带 blockedReason 无
|
|
896
|
-
// errorCode)。此前落 success 臂(TB db-wal-recovery__uuH5cAg 实证:引擎终态 blocked、帧却
|
|
897
|
-
// subtype:success)。≠空成功 → SDKResultError,blockedReason 如实进 errors[]。
|
|
898
416
|
if (terminal?.kind === 'blocked') {
|
|
899
417
|
const blockedReason = terminal.reason;
|
|
900
418
|
return errorResult(ctx, {
|
|
@@ -907,25 +425,9 @@ observed) {
|
|
|
907
425
|
],
|
|
908
426
|
});
|
|
909
427
|
}
|
|
910
|
-
// [884]A1(TB 公平 P0,2026-07-16):suspended/needs_review park 终帧不许洗成空成功。
|
|
911
|
-
// `-p` 恒 DURABLE_APPROVAL=true 起引擎;模型调 AskUserQuestion(或 plan-mode ExitPlanMode)时
|
|
912
|
-
// 引擎 park 吐 done{status:'suspended'|'needs_review'}(+ taskId/checkpointGate)。交互 REPL 有
|
|
913
|
-
// liveHitlAskWire/planReviewWire 把 park 接成对话框;print/非 REPL 无 overlay → 桥 fail-soft
|
|
914
|
-
// 原样吐终帧落到这里,此前落 success 臂 = subtype:'success'/is_error:false/result:'' →
|
|
915
|
-
// **exit 0 空成功**(评测 harness 判 0 分且零错误信号,比死等更隐蔽)。分流 SDKResultError:
|
|
916
|
-
// 三 output 形态经既有消费面各自正确(json 单文档 is_error、stream-json result 帧 is_error、
|
|
917
|
-
// text errors[0]→stderr formatTextModeExecutionError),rc≠0 由 print.ts
|
|
918
|
-
// gracefulShutdownSync(is_error ? 1 : 0) 顺出。文案带 run/session id 指路(交互 REPL resume 或
|
|
919
|
-
// approvals decide),与批 G 件2 的 409 active-run 文案同源指引——那是 409 拒的
|
|
920
|
-
// done{status:'failed', activeTaskId} 帧(上方 failed 臂),这是 park 终帧,两帧互不冲突。
|
|
921
|
-
// CC 对照:CC 2.1.207 AskUserQuestion.isEnabled 在非交互且无 SDK permissionPromptTool 时
|
|
922
|
-
// return false = 模型源头看不到该工具;core [884] 自领 1.296 加同款非交互闸(roster 源头不进)。
|
|
923
|
-
// 本分流是闸到货后的防御纵深:即便引擎吐了 suspended,壳也不许洗成空成功。
|
|
924
428
|
if (terminal?.kind === 'paused') {
|
|
925
429
|
const parked = r;
|
|
926
430
|
const runId = typeof parked.taskId === 'string' && parked.taskId.length > 0 ? parked.taskId : undefined;
|
|
927
|
-
// 🔴 0.60.0:两句措辞的判据从退役的 `status` 五词换成**门种**(因由形下 park 只带 gate)——
|
|
928
|
-
// 单源 `runTerminal.isReviewPark`(词表 ⊇ 重开臂路由表,包含关系由常驻门钉)。
|
|
929
431
|
const gateTool = runTerminalGateToolName(terminal);
|
|
930
432
|
const review = isReviewPark(terminal);
|
|
931
433
|
const sid = typeof ctx.sessionId === 'string' && ctx.sessionId.length > 0 ? ctx.sessionId : undefined;
|
|
@@ -933,8 +435,6 @@ observed) {
|
|
|
933
435
|
const wayOut = review
|
|
934
436
|
? `Review the plan in the interactive REPL${sid ? ` (sema --resume ${sid})` : ''}.`
|
|
935
437
|
: `Answer it in the interactive REPL${sid ? ` (sema --resume ${sid})` : ''}, or decide the pending approval via the engine approvals API${sid ? ` (POST /v1/approvals/${sid}/decide)` : ''}.`;
|
|
936
|
-
// [909]B1 — 平面形回放的 needs_review 行仍带 review.pending;因由形下 park **写不出**码
|
|
937
|
-
// (见上方 errorCode 头注),两代都由信封原样透传。
|
|
938
438
|
return errorResult(ctx, {
|
|
939
439
|
...errorBase,
|
|
940
440
|
subtype: 'error_during_execution',
|
|
@@ -943,14 +443,6 @@ observed) {
|
|
|
943
443
|
],
|
|
944
444
|
});
|
|
945
445
|
}
|
|
946
|
-
// [909]B1 — 防御臂:四臂之外的未知终态词(core 未来加因由臂 / 未知 wire 变形)绝不洗成空成功
|
|
947
|
-
// —— error_during_execution + errors[] 如实报出那个词的字面。读器把两代字节的这一格都归到
|
|
948
|
-
// `unknown` 臂(因由形取 `terminal.kind`,扁平形取 `status`),所以本臂对两代同样有效。
|
|
949
|
-
// 🔴 **终态词整个缺席**(读器返 `null`):0.72.12 CC-50 起**不再**落 success 臂 —— 此前这里维持成功
|
|
950
|
-
// (mock 车道 / 不带终态词的旧合成帧「零行为变化」),等于把「这份载体上连终态词都没有」编成一份成功
|
|
951
|
-
// 结果。改为 fail-closed + `_sema_outcome:'unknown'`(取舍与理由见 `ErrorResultParts.outcomeUnknown`);
|
|
952
|
-
// 旧合成帧那一路从 success 翻成 error 是**真行为变化**,随 0.72.12 发车帖「取舍」段披露,mock 车道
|
|
953
|
-
// 要成功请在帧上带真终态词(`status:'completed'` / `terminal:{kind:'completed'}`)。
|
|
954
446
|
if (terminal === null || terminal === undefined) {
|
|
955
447
|
return errorResult(ctx, {
|
|
956
448
|
...errorBase,
|
|
@@ -970,8 +462,7 @@ observed) {
|
|
|
970
462
|
terminal.message ??
|
|
971
463
|
(terminal.word !== undefined
|
|
972
464
|
? `run ended with terminal cause "${terminal.word}" (not a success; this CLI predates that terminal word)`
|
|
973
|
-
:
|
|
974
|
-
// 更不是成功。诚实缺席优先于编一个词([honest-absence-not-fabricated-zero])。
|
|
465
|
+
:
|
|
975
466
|
'run ended with a terminal cause this client could not read (not a success; the engine sent a malformed terminal record)'),
|
|
976
467
|
],
|
|
977
468
|
});
|
|
@@ -981,65 +472,34 @@ observed) {
|
|
|
981
472
|
session_id: undefined,
|
|
982
473
|
type: 'result',
|
|
983
474
|
subtype: 'success',
|
|
984
|
-
duration_ms: durationMs,
|
|
985
|
-
duration_api_ms: durationMs,
|
|
475
|
+
duration_ms: durationMs,
|
|
476
|
+
duration_api_ms: durationMs,
|
|
986
477
|
is_error: false,
|
|
987
|
-
num_turns: stats?.turns ?? 0,
|
|
478
|
+
num_turns: stats?.turns ?? 0,
|
|
988
479
|
result: r.result ?? '',
|
|
989
|
-
// TaskResult 五键(additive):outputSchema 任务的结构化产出 + 降级实录(见 `degradedOf`)。
|
|
990
480
|
...(() => {
|
|
991
481
|
const so = r.structuredOutput;
|
|
992
482
|
return so !== undefined ? { structuredOutput: so } : {};
|
|
993
483
|
})(),
|
|
994
484
|
...(degraded !== undefined ? { degraded } : {}),
|
|
995
|
-
stop_reason: null,
|
|
996
|
-
total_cost_usd: costOrNull(stats),
|
|
485
|
+
stop_reason: null,
|
|
486
|
+
total_cost_usd: costOrNull(stats),
|
|
997
487
|
usage: flattenUsage(stats),
|
|
998
|
-
// MF-25/P1-5 — the per-model usage split (wire `stats.modelUsage`, or the synthesized current-model row).
|
|
999
488
|
modelUsage: modelUsageFor(stats, r.model),
|
|
1000
|
-
// D-1 / L-192①:同形第二处 —— 与错误信封共用**同一个** mint 点(修前两处各一个字面量 [])。
|
|
1001
489
|
...permissionDenialParts(stats, observed?.toolInputByCallId),
|
|
1002
|
-
// D-3 / B-068:成本明细与子代那本账(micro-USD 原值);`total_cost_usd` 语义一字不动。
|
|
1003
490
|
...costFactParts(stats, observed),
|
|
1004
|
-
// CC-06(0.71.3):`_sema_effective_reasoning` / `_sema_effective_memory_scopes`。
|
|
1005
491
|
...effectiveFactParts(rec),
|
|
1006
|
-
// L-228(0.67.0):流内 per-subagent 分表的收口快照;与 `_sema_nested_usage`(引擎报的合计)
|
|
1007
|
-
// 是**两份独立的账**,不相加、不互证(见 `nestedUsageByTaskParts` 顶注)。
|
|
1008
492
|
...nestedUsageByTaskParts(stats, observed?.nestedUsageByTask),
|
|
1009
|
-
// MF-25 — the effective served model id (`done.result.model`, e.g. "deepseek-v4-pro"). The CC
|
|
1010
|
-
// SDKResultSuccess schema has no `model` field, so this rides as an additive seam field a cost/overview
|
|
1011
|
-
// consumer reads (it is ALSO surfaced as the `modelUsage` key). Omitted when the wire didn't carry it.
|
|
1012
493
|
...(typeof r.model === 'string' ? { model: r.model } : {}),
|
|
1013
494
|
});
|
|
1014
495
|
}
|
|
1015
|
-
|
|
1016
|
-
export function failedToSdkResult(ev, ctx,
|
|
1017
|
-
/** 0.67.2:同 {@link doneToSdkResult} 的第三参。 */
|
|
1018
|
-
observed) {
|
|
1019
|
-
// Flatten the 4 CC error subtypes onto the single neutral errorCode.
|
|
1020
|
-
// error_max_budget_usd is a non-error "budget exceeded" notice, not a crash
|
|
1021
|
-
// (contract 02 §2.11) — the renderer branches on subtype.
|
|
1022
|
-
//
|
|
1023
|
-
// 🔴 单点(core 5.8.0 [2489]):此臂此前手写「只认 budget.*」的两分支,与 done{failed} 臂
|
|
1024
|
-
// 的四分支**并不同义**(同一个轮数耗尽经 done 帧来是 error_max_turns、经 failed 事件来是
|
|
1025
|
-
// error_during_execution)。现在两条路共用 `subtypeForErrorCode` —— 到限码与 CC 词表的对应关系
|
|
1026
|
-
// 只有一处定义,5.8.0 的改名、以及本批的旧码退役,都只改了一处。
|
|
496
|
+
export function failedToSdkResult(ev, ctx, observed) {
|
|
1027
497
|
const subtype = subtypeForErrorCode(ev.errorCode);
|
|
1028
|
-
// 🔴 REF-CC-055:此臂**不是另一种信封**,是 `errorResult` 在 `stats === undefined` 时的退化实例
|
|
1029
|
-
// (`num_turns: 0` ≡ `stats?.turns ?? 0`、`total_cost_usd: null` ≡ `costOrNull(undefined)`、
|
|
1030
|
-
// 五键零 usage ≡ `flattenUsage(undefined)`、`modelUsage: {}` ≡ `modelUsageFor(undefined, undefined)`)。
|
|
1031
|
-
// `failed` 事件帧本体不带 stats/model/degraded,所以这三个位如实缺席 —— 不是「这里少算了」。
|
|
1032
498
|
return errorResult(ctx, {
|
|
1033
499
|
subtype,
|
|
1034
500
|
observed,
|
|
1035
501
|
durationMs: elapsedMs(ctx),
|
|
1036
|
-
// [909]B1 — errorCode 透传(additive seam 字段;done 臂同款):`failed` 事件的 cancelled/
|
|
1037
|
-
// limits.* 等引擎值原样给集成面。
|
|
1038
502
|
errorCode: ev.errorCode,
|
|
1039
|
-
// errorCode + errorMessage flattened into the single CC errors[] string.
|
|
1040
|
-
// Rewind-family codes(core 1.292 [833]:resume_at.before_target_not_user /
|
|
1041
|
-
// resume_at.before_root_unsupported / rewind_snapshot.unresolvable)透传给用户 —— 这些是
|
|
1042
|
-
// 用户可自解的操作性错误(选错目标/回退过根/快照缺失),code 附在 message 后便于对账。
|
|
1043
503
|
errors: [
|
|
1044
504
|
isRewindFamilyCode(ev.errorCode) && ev.errorMessage
|
|
1045
505
|
? `${ev.errorMessage} (${ev.errorCode})`
|
|
@@ -1047,13 +507,6 @@ observed) {
|
|
|
1047
507
|
],
|
|
1048
508
|
});
|
|
1049
509
|
}
|
|
1050
|
-
/**
|
|
1051
|
-
* Dispatch a terminal AgentEvent to its SDKResult arm.
|
|
1052
|
-
*
|
|
1053
|
-
* 🔴 第三参(0.67.2 / 车 I 件 I-1):**这一条流**的 usage 观测快照。`runStream` 在终帧那一拍**按值**
|
|
1054
|
-
* 交给它与 `run_cost_reconciled` 铸臂 —— 两个投影口读的是**同一份本流快照**,而不是一个可能被别的流
|
|
1055
|
-
* 写过的共享位。缺席(端直调)⇒ 与 0.67.1 的旧签名逐位同行为。
|
|
1056
|
-
*/
|
|
1057
510
|
export function terminalToSdkResult(ev, ctx, observed) {
|
|
1058
511
|
return ev.type === 'done' ? doneToSdkResult(ev, ctx, observed) : failedToSdkResult(ev, ctx, observed);
|
|
1059
512
|
}
|