@sema-agent/client-core 0.94.0 → 0.96.0
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 +521 -0
- package/README.md +104 -57
- package/dist/adapt/arms.js +12 -7
- package/dist/adapt/panelTasks.js +4 -10
- package/dist/adapt/toolCards.d.ts +1 -0
- package/dist/adapt/toolCards.js +18 -5
- package/dist/adapt/wireShapes.js +5 -24
- package/dist/adapter/activeRunSelfHeal.d.ts +12 -3
- package/dist/adapter/activeRunSelfHeal.js +50 -16
- package/dist/adapter/downstream/eventToSdkMessage.js +33 -18
- package/dist/adapter/downstream/terminalToSdkResult.js +19 -12
- package/dist/adapter/runStream.js +30 -46
- package/dist/adapter/types.d.ts +7 -0
- package/dist/adapter/types.js +15 -0
- package/dist/agentSession/backgroundView.js +5 -1
- package/dist/agentSession/engineAgentRegistryRead.js +7 -5
- package/dist/agentSession/engineSessionBackgroundStop.js +25 -17
- package/dist/agentsWireCaps.d.ts +2 -0
- package/dist/agentsWireCaps.js +13 -2
- package/dist/approvalDecidedByCapability.d.ts +0 -1
- package/dist/approvalDecidedByCapability.js +2 -7
- package/dist/approvalsStreamLiveCapability.d.ts +0 -1
- package/dist/approvalsStreamLiveCapability.js +2 -6
- package/dist/atMostOnce.d.ts +8 -0
- package/dist/atMostOnce.js +36 -0
- package/dist/attachmentSeatCapability.d.ts +0 -1
- package/dist/attachmentSeatCapability.js +0 -3
- package/dist/attachmentsWireCaps.js +11 -6
- package/dist/bashExitReading.d.ts +10 -0
- package/dist/bashExitReading.js +12 -0
- package/dist/callerCwdCapability.d.ts +0 -5
- package/dist/callerCwdCapability.js +2 -13
- package/dist/centerWiringCapability.d.ts +1 -7
- package/dist/centerWiringCapability.js +18 -27
- package/dist/classifierStatus.js +4 -4
- package/dist/classifierVerdictWire.js +4 -16
- package/dist/clientSlice.js +1 -1
- package/dist/cloudConfigWireCaps.d.ts +3 -3
- package/dist/cloudConfigWireCaps.js +85 -43
- package/dist/compensations.js +1 -1
- package/dist/coreValuePorts.d.ts +11 -7
- package/dist/coreValuePorts.js +5 -8
- package/dist/credentialProvenance.d.ts +28 -0
- package/dist/credentialProvenance.js +76 -0
- package/dist/cycleOrder.d.ts +15 -0
- package/dist/cycleOrder.js +45 -0
- package/dist/decideFailureNote.js +7 -2
- package/dist/decideReceipt.d.ts +2 -1
- package/dist/decideReceipt.js +39 -14
- package/dist/declared/supportFloorDeclared.d.ts +1 -0
- package/dist/declared/supportFloorDeclared.js +5 -0
- package/dist/deviceExecutorManagementCapability.d.ts +0 -1
- package/dist/deviceExecutorManagementCapability.js +7 -16
- package/dist/deviceRebind.d.ts +88 -0
- package/dist/deviceRebind.js +242 -0
- package/dist/displayUntrusted.d.ts +8 -3
- package/dist/displayUntrusted.js +661 -63
- package/dist/engineAgentAbsence.d.ts +2 -2
- package/dist/engineAgentPanelStore.d.ts +8 -18
- package/dist/engineAgentPanelStore.js +19 -537
- package/dist/engineCapReader.d.ts +6 -6
- package/dist/engineCapReader.js +30 -43
- package/dist/engineCapsCache.d.ts +13 -2
- package/dist/engineCapsCache.js +276 -44
- package/dist/engineCredentialRequirement.d.ts +9 -0
- package/dist/engineCredentialRequirement.js +23 -0
- package/dist/engineDirectory.d.ts +79 -0
- package/dist/engineDirectory.js +186 -0
- package/dist/engineEnvSourcing.d.ts +53 -0
- package/dist/engineEnvSourcing.js +81 -0
- package/dist/engineErrorCodes.d.ts +28 -4
- package/dist/engineErrorCodes.js +68 -25
- package/dist/engineIdentity.js +2 -0
- package/dist/engineNoticeCodes.d.ts +17 -0
- package/dist/engineNoticeCodes.js +57 -3
- package/dist/engineWireSdk.js +2 -2
- package/dist/engineWordRenames.d.ts +8 -0
- package/dist/engineWordRenames.js +13 -0
- package/dist/executionLaneCapability.d.ts +2 -3
- package/dist/executionLaneCapability.js +18 -23
- package/dist/fileHistoryCaptureCapability.d.ts +14 -1
- package/dist/fileHistoryCaptureCapability.js +72 -6
- package/dist/fileHistoryLegNotice.d.ts +3 -2
- package/dist/fileHistoryLegNotice.js +51 -2
- package/dist/fleet/bgSubagentRow.d.ts +15 -0
- package/dist/fleet/bgSubagentRow.js +67 -0
- package/dist/fleet/fleetLedger.d.ts +3 -0
- package/dist/fleet/fleetLedger.js +153 -122
- package/dist/fleet/fleetProjection.d.ts +1 -3
- package/dist/fleet/fleetProjection.js +19 -19
- package/dist/fleetAgentPanelProjection.d.ts +4 -17
- package/dist/fleetAgentPanelProjection.js +7 -197
- package/dist/fleetAgentRowLike.d.ts +16 -0
- package/dist/fleetAgentRowLike.js +1 -0
- package/dist/fleetTaskDesc.js +4 -17
- package/dist/gateOutcome.d.ts +12 -1
- package/dist/gateOutcome.js +87 -18
- package/dist/gateVocabulary.d.ts +7 -2
- package/dist/gateVocabulary.js +5 -1
- package/dist/generated/engineAskFaceTables.js +1 -1
- package/dist/generated/engineFactTables.d.ts +5 -3
- package/dist/generated/engineFactTables.js +17 -4
- package/dist/generated/engineNoticeTables.js +12 -3
- package/dist/generated/sdkFactTables.d.ts +2 -0
- package/dist/generated/sdkFactTables.js +17 -0
- package/dist/generated/settingsSchemaFns.d.ts +13 -0
- package/dist/generated/settingsSchemaFns.js +75 -0
- package/dist/generated/toolNameTables.d.ts +1 -0
- package/dist/generated/toolNameTables.js +1 -0
- package/dist/headlessPermissionModeWire.d.ts +1 -1
- package/dist/headlessPermissionModeWire.js +1 -1
- package/dist/headlessReconnectWire.js +49 -20
- package/dist/hitl/allowRuleShadow.d.ts +1 -1
- package/dist/hitl/allowRuleShadow.js +49 -8
- package/dist/hitl/approvalCompleteParked.d.ts +1 -0
- package/dist/hitl/approvalCompleteParked.js +14 -0
- package/dist/hitl/approvalEndingCause.d.ts +7 -0
- package/dist/hitl/approvalEndingCause.js +71 -0
- package/dist/hitl/approvalHolds.d.ts +12 -2
- package/dist/hitl/approvalHolds.js +53 -2
- package/dist/hitl/approvalsFeed.js +23 -11
- package/dist/hitl/askGateWire.d.ts +2 -1
- package/dist/hitl/askGateWire.js +26 -1
- package/dist/hitl/askParkRowRouting.js +1 -1
- package/dist/hitl/automaticAnswerVerdict.d.ts +1 -1
- package/dist/hitl/automaticAnswerVerdict.js +15 -10
- package/dist/hitl/crashConverged.js +2 -0
- package/dist/hitl/decisionConflict.d.ts +3 -0
- package/dist/hitl/decisionConflict.js +41 -0
- package/dist/hitl/decisionRefusal.d.ts +12 -0
- package/dist/hitl/decisionRefusal.js +63 -4
- package/dist/hitl/frameRouter.d.ts +0 -1
- package/dist/hitl/frameRouter.js +32 -57
- package/dist/hitl/gateLedger.d.ts +5 -0
- package/dist/hitl/gateLedger.js +21 -0
- package/dist/hitl/hitlBridge.d.ts +17 -2
- package/dist/hitl/hitlBridge.js +91 -55
- package/dist/hitl/hitlHostSurface.js +3 -11
- package/dist/hitl/livePendingAsk.d.ts +16 -6
- package/dist/hitl/livePendingAsk.js +36 -4
- package/dist/hitl/localAllowRule.d.ts +1 -0
- package/dist/hitl/localAllowRule.js +2 -2
- package/dist/hitl/noAllowCause.d.ts +2 -1
- package/dist/hitl/noAllowCause.js +3 -2
- package/dist/hitl/parkExpiryJudgements.d.ts +19 -0
- package/dist/hitl/parkExpiryJudgements.js +46 -0
- package/dist/hitl/parkResolver.d.ts +4 -7
- package/dist/hitl/parkResolver.js +12 -34
- package/dist/hitl/parkRowBirthWait.d.ts +1 -0
- package/dist/hitl/parkRowBirthWait.js +2 -2
- package/dist/hitl/persistedRulesWire.js +5 -1
- package/dist/hitl/planReviewWire.d.ts +3 -2
- package/dist/hitl/planReviewWire.js +154 -50
- package/dist/hitl/replayedApproval.d.ts +9 -0
- package/dist/hitl/replayedApproval.js +139 -10
- package/dist/hitl/resumeRunningCard.d.ts +2 -0
- package/dist/hitl/resumeRunningCard.js +15 -4
- package/dist/hitl/sessionPolicyDeliverable.js +8 -6
- package/dist/hitl/standingRows.d.ts +18 -0
- package/dist/hitl/standingRows.js +127 -0
- package/dist/hitl/toolApprovalWire.d.ts +39 -7
- package/dist/hitl/toolApprovalWire.js +351 -61
- package/dist/hookMatcherVerdict.d.ts +1 -9
- package/dist/hookMatcherVerdict.js +21 -61
- package/dist/hooksWireCaps.js +40 -8
- package/dist/host.d.ts +5 -0
- package/dist/host.js +3 -1
- package/dist/hostCallbackGuard.d.ts +2 -0
- package/dist/hostCallbackGuard.js +31 -0
- package/dist/index.d.ts +48 -17
- package/dist/index.js +36 -15
- package/dist/interactiveInterrupt.d.ts +8 -0
- package/dist/interactiveInterrupt.js +54 -0
- package/dist/limitsWire.d.ts +5 -0
- package/dist/limitsWire.js +49 -3
- package/dist/liveModelCatalog.d.ts +95 -0
- package/dist/liveModelCatalog.js +297 -32
- package/dist/mcpEngineLeg.d.ts +25 -0
- package/dist/mcpEngineLeg.js +71 -15
- package/dist/mcpPanel.js +2 -1
- package/dist/mcpProbeCapability.d.ts +0 -5
- package/dist/mcpProbeCapability.js +2 -12
- package/dist/mcpReconnect.d.ts +1 -3
- package/dist/mcpReconnect.js +10 -5
- package/dist/memoryComplianceCapability.d.ts +0 -5
- package/dist/memoryComplianceCapability.js +2 -12
- package/dist/memoryOriginCapability.d.ts +0 -5
- package/dist/memoryOriginCapability.js +2 -12
- package/dist/memorySpecWire.js +2 -2
- package/dist/memoryVerbsWire.d.ts +1 -1
- package/dist/memoryVerbsWire.js +4 -0
- package/dist/model/liveCatalogShape.d.ts +14 -0
- package/dist/model/liveCatalogShape.js +71 -0
- package/dist/model/modelSupplyRules.d.ts +1 -0
- package/dist/model/modelSupplyRules.js +30 -9
- package/dist/model/modelsPolicy.d.ts +21 -0
- package/dist/model/modelsPolicy.js +90 -0
- package/dist/modelIdentityResolvability.d.ts +2 -2
- package/dist/modelIdentityResolvability.js +14 -12
- package/dist/modelSwitchFallback.d.ts +69 -0
- package/dist/modelSwitchFallback.js +206 -0
- package/dist/noticePresentation.d.ts +68 -0
- package/dist/noticePresentation.js +247 -0
- package/dist/notifications.js +12 -11
- package/dist/outputStyleSeatCapability.d.ts +0 -2
- package/dist/outputStyleSeatCapability.js +2 -10
- package/dist/ownKey.d.ts +8 -0
- package/dist/ownKey.js +66 -0
- package/dist/panelReduce.d.ts +114 -0
- package/dist/panelReduce.js +1135 -0
- package/dist/panelStateHolder.d.ts +17 -0
- package/dist/panelStateHolder.js +201 -0
- package/dist/peerFrames.js +13 -9
- package/dist/peerLaneCapability.d.ts +0 -1
- package/dist/peerLaneCapability.js +2 -6
- package/dist/permissionModesCapability.d.ts +0 -5
- package/dist/permissionModesCapability.js +5 -16
- package/dist/permissionRuleIssue.js +0 -3
- package/dist/permissionRulesWriteCapability.d.ts +0 -1
- package/dist/permissionRulesWriteCapability.js +2 -6
- package/dist/permissionsAllowGrantCapability.d.ts +0 -1
- package/dist/permissionsAllowGrantCapability.js +3 -9
- package/dist/permissionsDeclaration.d.ts +8 -0
- package/dist/permissionsDeclaration.js +101 -41
- package/dist/printPermissionOutcome.d.ts +12 -0
- package/dist/printPermissionOutcome.js +50 -0
- package/dist/printToolResultFrame.d.ts +1 -0
- package/dist/printToolResultFrame.js +5 -17
- package/dist/promptBlockedCopy.d.ts +5 -0
- package/dist/promptBlockedCopy.js +35 -0
- package/dist/promptDelivery.js +0 -8
- package/dist/protocolSegment.d.ts +9 -6
- package/dist/protocolSegment.js +31 -21
- package/dist/providerRejection.d.ts +4 -0
- package/dist/providerRejection.js +75 -14
- package/dist/replayBody.d.ts +12 -0
- package/dist/replayBody.js +25 -0
- package/dist/resumeRefusalCopy.d.ts +18 -1
- package/dist/resumeRefusalCopy.js +127 -32
- package/dist/retryStatus.d.ts +9 -1
- package/dist/retryStatus.js +9 -2
- package/dist/rewindArchiveCapability.d.ts +5 -14
- package/dist/rewindArchiveCapability.js +18 -61
- package/dist/rewindArchiveReading.d.ts +15 -0
- package/dist/rewindArchiveReading.js +56 -0
- package/dist/rewindEngineAction.d.ts +21 -0
- package/dist/rewindEngineAction.js +36 -0
- package/dist/rewindWireCaps.d.ts +2 -1
- package/dist/rewindWireCaps.js +1 -0
- package/dist/ruleCompileVerdict.d.ts +9 -1
- package/dist/ruleCompileVerdict.js +29 -4
- package/dist/runTerminal.d.ts +15 -12
- package/dist/runTerminal.js +60 -35
- package/dist/sandboxWire.js +13 -0
- package/dist/sdkRegistryTransit.d.ts +2 -1
- package/dist/sdkRegistryTransit.js +1 -0
- package/dist/sealedKeyCapability.d.ts +0 -5
- package/dist/sealedKeyCapability.js +3 -15
- package/dist/seam.js +4 -2
- package/dist/seatContract.d.ts +125 -34
- package/dist/seatContract.js +583 -179
- package/dist/sessionIdSegment.d.ts +1 -0
- package/dist/sessionIdSegment.js +11 -0
- package/dist/sessionMemoryErase.d.ts +1 -1
- package/dist/sessionMemoryErase.js +6 -1
- package/dist/sessionMemoryStatus.js +3 -2
- package/dist/sessionPolicyCapability.d.ts +0 -1
- package/dist/sessionPolicyCapability.js +2 -6
- package/dist/sessionReadRedactionCapability.d.ts +0 -5
- package/dist/sessionReadRedactionCapability.js +2 -13
- package/dist/sessionSyncFileHistory.d.ts +4 -0
- package/dist/sessionSyncFileHistory.js +66 -0
- package/dist/sessionSyncFileHistoryCapability.d.ts +0 -2
- package/dist/sessionSyncFileHistoryCapability.js +2 -9
- package/dist/skillToolListsCapability.d.ts +0 -2
- package/dist/skillToolListsCapability.js +2 -9
- package/dist/skillsWireCaps.d.ts +4 -0
- package/dist/skillsWireCaps.js +66 -1
- package/dist/sqlEngineCapability.d.ts +0 -1
- package/dist/sqlEngineCapability.js +9 -14
- package/dist/steerPriorityCapability.d.ts +0 -2
- package/dist/steerPriorityCapability.js +3 -12
- package/dist/storePostureCapability.d.ts +1 -5
- package/dist/storePostureCapability.js +16 -22
- package/dist/streamDrainingLegs.d.ts +6 -0
- package/dist/streamDrainingLegs.js +23 -0
- package/dist/subagent/engineCompactWire.js +13 -38
- package/dist/subagent/engineDelegatedPrompt.js +10 -6
- package/dist/subagent/engineSubagentOutput.d.ts +0 -1
- package/dist/subagent/engineSubagentOutput.js +5 -20
- package/dist/subagent/engineSubagentSteer.js +7 -5
- package/dist/subagent/engineSubagentTail.d.ts +0 -1
- package/dist/subagent/engineSubagentTail.js +7 -32
- package/dist/subagentContentStore.js +7 -18
- package/dist/supportFloor.d.ts +1 -0
- package/dist/supportFloor.js +15 -14
- package/dist/systemReminderTag.d.ts +1 -0
- package/dist/systemReminderTag.js +8 -0
- package/dist/terminalStatuses.d.ts +30 -0
- package/dist/terminalStatuses.js +67 -0
- package/dist/toolHistoryMismatch.d.ts +0 -3
- package/dist/toolHistoryMismatch.js +3 -7
- package/dist/toolResult.d.ts +6 -1
- package/dist/toolResult.js +90 -37
- package/dist/toolResultContent.d.ts +2 -0
- package/dist/toolResultContent.js +63 -0
- package/dist/types/engineState.d.ts +2 -1
- package/dist/usageAnalytics.d.ts +146 -0
- package/dist/usageAnalytics.js +335 -0
- package/dist/userInvokedSkillsCapability.d.ts +0 -2
- package/dist/userInvokedSkillsCapability.js +2 -9
- package/dist/webSearchBackendCapability.d.ts +0 -1
- package/dist/webSearchBackendCapability.js +3 -7
- package/dist/webSearchWireCaps.js +3 -11
- package/dist/wireErrorTriage.d.ts +2 -0
- package/dist/wireErrorTriage.js +34 -5
- package/dist/wireFailureShape.d.ts +23 -2
- package/dist/wireFailureShape.js +88 -43
- package/dist/wireRefusalCopy.js +2 -18
- package/dist/workflowClient.js +7 -11
- package/dist/workflowsJournalCapability.d.ts +0 -1
- package/dist/workflowsJournalCapability.js +2 -6
- package/dist/writeProtectionCapability.d.ts +0 -1
- package/dist/writeProtectionCapability.js +5 -10
- package/docs/INTEGRATION-CLIENTS.md +2279 -27
- package/package.json +5 -5
- package/dist/engineCapsGenerationGuard.d.ts +0 -4
- package/dist/engineCapsGenerationGuard.js +0 -19
- package/dist/panelRunningHistory.d.ts +0 -22
- package/dist/panelRunningHistory.js +0 -82
- package/dist/registryConflict.d.ts +0 -3
- package/dist/registryConflict.js +0 -44
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { putOwnKey, readOwnDataValue } from '../ownKey.js';
|
|
2
|
-
import { DecideTransportRetryExhaustedError,
|
|
3
|
-
import {
|
|
2
|
+
import { DecideTransportRetryExhaustedError, GATE_FAILURE_CODES, HitlBridge, NO_QUESTION_OVERLAY_REASON, findPendingForTask, hitlSafetyCodeOf, isNoDecisionSurfaceReason, readDecideCurrentPending, readWireCodes, } from './hitlBridge.js';
|
|
3
|
+
import { DECIDE_WORKFLOW_PARK_FORKED, DECIDE_WORKFLOW_PARKS_UNREADABLE, PARKED_RESUME_STARTUP_FAILED, RESUME_POLICY_FOLD_CODE, isRefusedParkCode, refusalSaysStillPending } from '../engineErrorCodes.js';
|
|
4
|
+
import { readDecisionRefusalAsk } from './decisionRefusal.js';
|
|
4
5
|
import { publishQuestionFrame, registerLocalQuestionResponder, hasQuestionOverlay, } from '../liveQuestionStore.js';
|
|
5
6
|
import { hostLog } from '../host.js';
|
|
6
7
|
import { surfaceFsApprovalAndDecide } from './toolApprovalWire.js';
|
|
@@ -9,7 +10,7 @@ import { flushHeldWithInterruptRewrite, isAskTool } from './frameRouter.js';
|
|
|
9
10
|
import { approvalCallKey, askGateQuestionId } from './gateIdentity.js';
|
|
10
11
|
import { readDecideReceipt } from '../decideReceipt.js';
|
|
11
12
|
import { decideFailureNote } from '../decideFailureNote.js';
|
|
12
|
-
import { wireFailureTextsOf } from '../wireFailureShape.js';
|
|
13
|
+
import { thrownIsInstanceOf, wireFailureTextsOf } from '../wireFailureShape.js';
|
|
13
14
|
export const MAX_GATE_HOPS = 2;
|
|
14
15
|
export function nextHopBudget(prev, round) {
|
|
15
16
|
const total = (prev?.total ?? 0) + 1;
|
|
@@ -18,16 +19,6 @@ export function nextHopBudget(prev, round) {
|
|
|
18
19
|
const MAX_TRANSPORT_REATTACHES = 2;
|
|
19
20
|
export const MAX_TOTAL_PARKS = 64;
|
|
20
21
|
const MAX_ALREADY_RESOLVED_REATTACHES = 1;
|
|
21
|
-
export const GATE_FAILURE_CODES = [
|
|
22
|
-
'no_pending',
|
|
23
|
-
'binding_mismatch',
|
|
24
|
-
'wrong_gate',
|
|
25
|
-
'bad_plan_edit',
|
|
26
|
-
'bad_plan_mode',
|
|
27
|
-
'empty_answer',
|
|
28
|
-
];
|
|
29
|
-
const _gateFailureCodePins = [true, true];
|
|
30
|
-
void _gateFailureCodePins;
|
|
31
22
|
function isGateFailureCode(v) {
|
|
32
23
|
return typeof v === 'string' && GATE_FAILURE_CODES.includes(v);
|
|
33
24
|
}
|
|
@@ -41,32 +32,19 @@ function alreadyResolvedReasonToken(reason) {
|
|
|
41
32
|
const r = reason.toLowerCase();
|
|
42
33
|
return ALREADY_RESOLVED_REASON_TOKENS.find((t) => r.includes(t));
|
|
43
34
|
}
|
|
44
|
-
export function isAlreadyResolvedFailure(
|
|
35
|
+
export function isAlreadyResolvedFailure(failure) {
|
|
45
36
|
try {
|
|
46
|
-
|
|
37
|
+
const r = readDecisionRefusalAsk(failure);
|
|
38
|
+
return r.reading === 'settled' || (r.reading === 'not_settled' && (r.gateMoved || r.wordingHint));
|
|
47
39
|
}
|
|
48
40
|
catch {
|
|
49
41
|
return false;
|
|
50
42
|
}
|
|
51
43
|
}
|
|
52
|
-
function alreadyResolvedFailureVerdict(outcome) {
|
|
53
|
-
if (typeof outcome !== 'object' || outcome === null)
|
|
54
|
-
return false;
|
|
55
|
-
const code = 'code' in outcome && isGateFailureCode(outcome.code) ? outcome.code : undefined;
|
|
56
|
-
if (code !== undefined)
|
|
57
|
-
return code === 'no_pending';
|
|
58
|
-
if ('errorCode' in outcome && isCodeClassifiedGateFailure(outcome.errorCode, Object.hasOwn(outcome, 'retriable') && outcome.retriable === true))
|
|
59
|
-
return false;
|
|
60
|
-
if ('errorCode' in outcome && isDecideParkMovedCode(outcome.errorCode))
|
|
61
|
-
return true;
|
|
62
|
-
if ('errorCode' in outcome && outcome.errorCode === ASK_GONE)
|
|
63
|
-
return true;
|
|
64
|
-
return isAlreadyResolvedGateReason(outcome.reason);
|
|
65
|
-
}
|
|
66
44
|
export function isGateStandingErrorCode(code, retriable) {
|
|
67
45
|
return (code === RESUME_POLICY_FOLD_CODE ||
|
|
68
46
|
code === 'corrupt' ||
|
|
69
|
-
(code
|
|
47
|
+
(isRefusedParkCode(code) && retriable === true) ||
|
|
70
48
|
code === DECIDE_WORKFLOW_PARKS_UNREADABLE ||
|
|
71
49
|
code === DECIDE_WORKFLOW_PARK_FORKED);
|
|
72
50
|
}
|
|
@@ -167,9 +145,9 @@ async function surfaceGateAndDecide(deps, taskId, askArgsByCall, signal, parkGat
|
|
|
167
145
|
return { kind: 'decided', gatedCallId, ...(declinedReceipt !== undefined ? { receipt: declinedReceipt } : {}) };
|
|
168
146
|
}
|
|
169
147
|
catch (e) {
|
|
170
|
-
const code =
|
|
148
|
+
const code = hitlSafetyCodeOf(e);
|
|
171
149
|
const currentPending = readDecideCurrentPending(e);
|
|
172
|
-
const
|
|
150
|
+
const wireCodes = readWireCodes(e);
|
|
173
151
|
const wireRetriable = typeof e === 'object' && e !== null && refusalSaysStillPending(e);
|
|
174
152
|
const failureTexts = wireFailureTextsOf(e);
|
|
175
153
|
hostLog('debug', `liveHitlAskWire: decide failed: ${failureTexts.log}`);
|
|
@@ -179,9 +157,9 @@ async function surfaceGateAndDecide(deps, taskId, askArgsByCall, signal, parkGat
|
|
|
179
157
|
gatedCallId,
|
|
180
158
|
reason: `decide failed: ${failureTexts.reason}${decideFailureNote(e, attemptedDecision)}`,
|
|
181
159
|
...(code !== undefined ? { code } : {}),
|
|
182
|
-
...(e
|
|
160
|
+
...(thrownIsInstanceOf(e, DecideTransportRetryExhaustedError) ? { retryExhausted: true } : {}),
|
|
183
161
|
...(currentPending !== undefined ? { currentPending } : {}),
|
|
184
|
-
...
|
|
162
|
+
...wireCodes,
|
|
185
163
|
...(wireRetriable ? { retriable: true } : {}),
|
|
186
164
|
};
|
|
187
165
|
}
|
|
@@ -35,5 +35,6 @@ export interface ParkRowBirthWaitDeps<Row> {
|
|
|
35
35
|
now?: () => number;
|
|
36
36
|
sleep?: (ms: number, signal?: AbortSignal) => Promise<void>;
|
|
37
37
|
signal?: AbortSignal;
|
|
38
|
+
onFailure?: (log: string) => void;
|
|
38
39
|
}
|
|
39
40
|
export declare function waitForParkRowBirth<Row>(deps: ParkRowBirthWaitDeps<Row>): Promise<ParkRowWaitVerdict<Row>>;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { abortableSleep } from '../abortableSleep.js';
|
|
2
|
-
import {
|
|
2
|
+
import { reasonOfThrownWithSink } from '../hostCallbackGuard.js';
|
|
3
3
|
function parkRowPollDelay(ms, signal) {
|
|
4
4
|
return abortableSleep(ms, signal ?? new AbortController().signal);
|
|
5
5
|
}
|
|
@@ -17,7 +17,7 @@ export async function waitForParkRowBirth(deps) {
|
|
|
17
17
|
return await deps.probe(attempt, signal);
|
|
18
18
|
}
|
|
19
19
|
catch (e) {
|
|
20
|
-
return { kind: 'unborn', reason: `probe threw: ${
|
|
20
|
+
return { kind: 'unborn', reason: `probe threw: ${reasonOfThrownWithSink(e, (log) => deps.onFailure?.(log))}` };
|
|
21
21
|
}
|
|
22
22
|
};
|
|
23
23
|
const probeWithinRemaining = async (attempt, remainingMs) => {
|
|
@@ -66,7 +66,11 @@ export function classifyRulesFailure(e, context) {
|
|
|
66
66
|
catch {
|
|
67
67
|
cursorSent = undefined;
|
|
68
68
|
}
|
|
69
|
-
|
|
69
|
+
if (cursorSent === true)
|
|
70
|
+
return { kind: 'cursor-stale', message };
|
|
71
|
+
if (cursorSent === false)
|
|
72
|
+
return { kind: 'query-refused', message };
|
|
73
|
+
return { kind: 'error', message };
|
|
70
74
|
}
|
|
71
75
|
if (status === 400 && errorCode === 'request.field_invalid')
|
|
72
76
|
return { kind: 'field-refused', message };
|
|
@@ -12,6 +12,7 @@ export type PlanReviewChoice = {
|
|
|
12
12
|
permissionModeAfter?: PlanReviewModeAfter;
|
|
13
13
|
} | {
|
|
14
14
|
decision: 'reject';
|
|
15
|
+
reason?: string;
|
|
15
16
|
};
|
|
16
17
|
export declare function planReviewChoiceFromAnswer(answer: QuestionAnswer | null | undefined, shownLabels?: readonly string[]): PlanReviewChoice | 'dismissed';
|
|
17
18
|
export declare function planReviewCardOptions(offerModeAfter: boolean): Array<{
|
|
@@ -61,6 +62,7 @@ export interface PlanReviewDeliveryOptions {
|
|
|
61
62
|
}
|
|
62
63
|
export interface DecidePlanReviewOptions extends PlanReviewDeliveryOptions {
|
|
63
64
|
reason?: string;
|
|
65
|
+
parkedResult?: unknown;
|
|
64
66
|
}
|
|
65
67
|
export interface PlanReviewDecisionHandle {
|
|
66
68
|
settle(): void;
|
|
@@ -76,14 +78,13 @@ export declare function __resetPlanReviewDecisionLatchForTests(): void;
|
|
|
76
78
|
export declare function decidePlanReview(taskId: string, decision: 'approve' | 'reject', permissionModeAfter?: string, opts?: DecidePlanReviewOptions): Promise<void>;
|
|
77
79
|
export interface ReopenPlanReviewOpts {
|
|
78
80
|
mintFreshQuestionId?: boolean;
|
|
79
|
-
deliverDecision?: (taskId: string, decision: 'approve' | 'reject') => void | Promise<void>;
|
|
81
|
+
deliverDecision?: (taskId: string, decision: 'approve' | 'reject', reason?: string) => void | Promise<void>;
|
|
80
82
|
sessionKey?: string;
|
|
81
83
|
wire?: PlanReviewWire;
|
|
82
84
|
onOutcome?: PlanReviewDeliveryOptions['onOutcome'];
|
|
83
85
|
presentationReceiptMs?: number;
|
|
84
86
|
trigger?: PlanReviewReopenTrigger;
|
|
85
87
|
readGateInstanceKeys?: PlanReviewGateInstanceReader;
|
|
86
|
-
decisionHandedOver?: (taskId: string) => boolean;
|
|
87
88
|
pendingReadStartedAt?: number;
|
|
88
89
|
}
|
|
89
90
|
export declare function _resetActiveReopenRespondersForTest(): void;
|
|
@@ -13,7 +13,7 @@ import { denyReasonForWire, isPlanReviewModeAfter } from './hitlBridge.js';
|
|
|
13
13
|
import { planReviewQuestionId, REOPEN_ID_TAIL, taskIdFromPlanReviewQuestionId } from './gateIdentity.js';
|
|
14
14
|
import { notePlanReviewAnswered, notePlanReviewAnsweredFor, planReviewArmedKeyFor, registerArmedGateFor, waitForGateArmedFor, wasGateArmedFor, } from './armedGateRegistry.js';
|
|
15
15
|
import { createSessionSlot, DEFAULT_SESSION_KEY } from '../sessionSlot.js';
|
|
16
|
-
import { PLAN_REVIEW_GATE_KIND } from '../adapter/activeRunSelfHeal.js';
|
|
16
|
+
import { PLAN_REVIEW_GATE_KIND, durableDecideLegOf } from '../adapter/activeRunSelfHeal.js';
|
|
17
17
|
import { readRunTerminal, runTerminalGateKind } from '../runTerminal.js';
|
|
18
18
|
const PLAN_REVIEW_RESUME_TIMEOUT_MS = 6 * 60 * 60_000;
|
|
19
19
|
export const PLAN_REVIEW_APPROVE_LABEL = 'Yes, approve and run the plan';
|
|
@@ -29,31 +29,59 @@ const ALL_KNOWN_LABELS = Object.freeze([
|
|
|
29
29
|
PLAN_REVIEW_APPROVE_LABEL,
|
|
30
30
|
PLAN_REVIEW_REJECT_LABEL,
|
|
31
31
|
]);
|
|
32
|
-
export function planReviewDecisionFromAnswer(answer, shownLabels) {
|
|
33
|
-
const choice =
|
|
32
|
+
export function planReviewDecisionFromAnswer(answer, shownLabels = LEGACY_TWO_CHOICE_LABELS) {
|
|
33
|
+
const { choice } = readPlanReviewAnswer(answer, shownLabels);
|
|
34
34
|
if (choice === 'dismissed')
|
|
35
35
|
return 'dismissed';
|
|
36
36
|
return choice.decision;
|
|
37
37
|
}
|
|
38
|
-
|
|
38
|
+
function readDismissed() {
|
|
39
|
+
return { choice: 'dismissed', noteIgnoredOnApprove: false };
|
|
40
|
+
}
|
|
41
|
+
function freeTextNoteOf(entry) {
|
|
42
|
+
try {
|
|
43
|
+
const note = entry?.note;
|
|
44
|
+
return typeof note === 'string' && note.trim() !== '' ? note : undefined;
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
return undefined;
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
function readPlanReviewAnswer(answer, shownLabels) {
|
|
39
51
|
const answers = answer?.answers;
|
|
40
52
|
if (!Array.isArray(answers) || answers.length !== 1)
|
|
41
|
-
return
|
|
42
|
-
const
|
|
43
|
-
|
|
44
|
-
|
|
53
|
+
return readDismissed();
|
|
54
|
+
const entry = answers[0];
|
|
55
|
+
const picked = entry?.selected;
|
|
56
|
+
if (!Array.isArray(picked))
|
|
57
|
+
return readDismissed();
|
|
58
|
+
const note = freeTextNoteOf(entry);
|
|
59
|
+
if (picked.length === 0) {
|
|
60
|
+
if (note === undefined || !shownLabels.includes(REJECT_LABEL))
|
|
61
|
+
return readDismissed();
|
|
62
|
+
return { choice: { decision: 'reject', reason: note }, noteIgnoredOnApprove: false };
|
|
63
|
+
}
|
|
64
|
+
if (picked.length !== 1)
|
|
65
|
+
return readDismissed();
|
|
45
66
|
const selected = picked[0];
|
|
46
67
|
if (typeof selected !== 'string' || !shownLabels.includes(selected))
|
|
47
|
-
return
|
|
68
|
+
return readDismissed();
|
|
69
|
+
const ignored = note !== undefined;
|
|
48
70
|
if (selected === PLAN_REVIEW_APPROVE_AUTO_LABEL)
|
|
49
|
-
return { decision: 'approve', permissionModeAfter: 'acceptEdits' };
|
|
71
|
+
return { choice: { decision: 'approve', permissionModeAfter: 'acceptEdits' }, noteIgnoredOnApprove: ignored };
|
|
50
72
|
if (selected === PLAN_REVIEW_APPROVE_MANUAL_LABEL)
|
|
51
|
-
return { decision: 'approve', permissionModeAfter: 'default' };
|
|
73
|
+
return { choice: { decision: 'approve', permissionModeAfter: 'default' }, noteIgnoredOnApprove: ignored };
|
|
52
74
|
if (selected === APPROVE_LABEL)
|
|
53
|
-
return { decision: 'approve' };
|
|
75
|
+
return { choice: { decision: 'approve' }, noteIgnoredOnApprove: ignored };
|
|
54
76
|
if (selected === REJECT_LABEL)
|
|
55
|
-
return { decision: 'reject' };
|
|
56
|
-
return
|
|
77
|
+
return { choice: note === undefined ? { decision: 'reject' } : { decision: 'reject', reason: note }, noteIgnoredOnApprove: false };
|
|
78
|
+
return readDismissed();
|
|
79
|
+
}
|
|
80
|
+
export function planReviewChoiceFromAnswer(answer, shownLabels = LEGACY_TWO_CHOICE_LABELS) {
|
|
81
|
+
const { choice, noteIgnoredOnApprove } = readPlanReviewAnswer(answer, shownLabels);
|
|
82
|
+
if (noteIgnoredOnApprove)
|
|
83
|
+
hostLog('debug', 'planReviewWire: note ignored on approve — an approval carries no feedback text; the note was not sent');
|
|
84
|
+
return choice;
|
|
57
85
|
}
|
|
58
86
|
export function planReviewCardOptions(offerModeAfter) {
|
|
59
87
|
const reject = { label: REJECT_LABEL, description: 'Discard this plan and stay in plan mode to refine it' };
|
|
@@ -102,6 +130,18 @@ function pausedCheckpointIdOf(carrier) {
|
|
|
102
130
|
return undefined;
|
|
103
131
|
}
|
|
104
132
|
}
|
|
133
|
+
function pausedGateKindOf(carrier) {
|
|
134
|
+
try {
|
|
135
|
+
const read = readRunTerminal(carrier);
|
|
136
|
+
if (read === null || read.kind !== 'paused')
|
|
137
|
+
return undefined;
|
|
138
|
+
const kind = runTerminalGateKind(read);
|
|
139
|
+
return typeof kind === 'string' && kind.length > 0 ? kind : undefined;
|
|
140
|
+
}
|
|
141
|
+
catch {
|
|
142
|
+
return undefined;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
105
145
|
const armedPlanReviewTaskIds = new Set();
|
|
106
146
|
const offerModeAfterByTask = new Map();
|
|
107
147
|
export function _resetArmedPlanReviewsForTest() {
|
|
@@ -270,10 +310,12 @@ export function armPlanReviewApproval(result, sessionKey, opts) {
|
|
|
270
310
|
const decided = choice.decision;
|
|
271
311
|
notePlanReviewDecisiveAnswerFor(DEFAULT_SESSION_KEY, taskId);
|
|
272
312
|
const modeAfter = choice.decision === 'approve' ? choice.permissionModeAfter : undefined;
|
|
313
|
+
const cardReason = choice.decision === 'reject' ? choice.reason : undefined;
|
|
314
|
+
const cardDelivery = cardReason !== undefined ? { ...delivery, reason: cardReason } : delivery;
|
|
273
315
|
offerModeAfterByTask.delete(taskId);
|
|
274
316
|
notePlanReviewAnswered(questionId);
|
|
275
317
|
hostLog('debug', `planReviewWire: arm responder delivering ${decided} for task ${taskId} (path=arm)`);
|
|
276
|
-
void decidePlanReviewFor(taskId, decided, modeAfter,
|
|
318
|
+
void decidePlanReviewFor(taskId, decided, modeAfter, cardDelivery, gateBefore);
|
|
277
319
|
return { ok: true };
|
|
278
320
|
});
|
|
279
321
|
publishPlanReviewCard(taskId);
|
|
@@ -440,7 +482,53 @@ export function __resetPlanReviewDecisionLatchForTests() {
|
|
|
440
482
|
planReviewDecisionOps.length = 0;
|
|
441
483
|
}
|
|
442
484
|
export async function decidePlanReview(taskId, decision, permissionModeAfter, opts) {
|
|
443
|
-
return decidePlanReviewFor(taskId, decision, permissionModeAfter, opts,
|
|
485
|
+
return decidePlanReviewFor(taskId, decision, permissionModeAfter, opts, parkedGateIdentityOf(opts));
|
|
486
|
+
}
|
|
487
|
+
function parkedGateIdentityOf(opts) {
|
|
488
|
+
try {
|
|
489
|
+
return opts !== null && typeof opts === 'object' ? pausedCheckpointIdOf(opts.parkedResult) : undefined;
|
|
490
|
+
}
|
|
491
|
+
catch {
|
|
492
|
+
return undefined;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
function planReviewSettledVerdict(r) {
|
|
496
|
+
const status = r.postStatus ?? r.bodyStatus;
|
|
497
|
+
const gateMoved = r.gateBefore !== undefined && r.gateAfter !== undefined && r.gateAfter !== r.gateBefore;
|
|
498
|
+
if (r.reparked)
|
|
499
|
+
return status !== 'completed' && !gateMoved ? { effect: 'still_parked', proven: true } : { effect: 'unconfirmed', proven: false };
|
|
500
|
+
if (status === 'completed')
|
|
501
|
+
return { effect: 'took_effect', proven: false };
|
|
502
|
+
const newGateHasCard = () => {
|
|
503
|
+
const leg = durableDecideLegOf({ gateKind: r.gateKindAfter ?? null });
|
|
504
|
+
return leg === 'approval' || leg === 'plan_review';
|
|
505
|
+
};
|
|
506
|
+
if (status === 'suspended' && r.postStatus === 'suspended' && newGateHasCard())
|
|
507
|
+
return { effect: 'advanced', proven: false };
|
|
508
|
+
if (status === 'needs_review' && r.postStatus === 'needs_review' && r.gateBefore !== undefined && r.gateAfter !== undefined) {
|
|
509
|
+
if (r.gateAfter === r.gateBefore)
|
|
510
|
+
return { effect: 'still_parked', proven: true };
|
|
511
|
+
if (newGateHasCard())
|
|
512
|
+
return { effect: 'advanced', proven: false };
|
|
513
|
+
}
|
|
514
|
+
return { effect: 'unconfirmed', proven: false };
|
|
515
|
+
}
|
|
516
|
+
function bodyWordOf(body, key) {
|
|
517
|
+
try {
|
|
518
|
+
const v = body !== null && typeof body === 'object' ? body[key] : undefined;
|
|
519
|
+
return typeof v === 'string' && v.length > 0 ? v : undefined;
|
|
520
|
+
}
|
|
521
|
+
catch {
|
|
522
|
+
return undefined;
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
function bodySaysReparked(body) {
|
|
526
|
+
try {
|
|
527
|
+
return body !== null && typeof body === 'object' && body.retriable === true;
|
|
528
|
+
}
|
|
529
|
+
catch {
|
|
530
|
+
return false;
|
|
531
|
+
}
|
|
444
532
|
}
|
|
445
533
|
async function decidePlanReviewFor(taskId, decision, permissionModeAfter, opts, gateBefore) {
|
|
446
534
|
if (typeof taskId === 'string' && planReviewDecisionOps.some((op) => op.taskId === taskId && op.phase === 'posting')) {
|
|
@@ -556,6 +644,7 @@ async function decidePlanReviewInner(taskId, decision, permissionModeAfter, disp
|
|
|
556
644
|
hostLog('debug', `planReviewWire: ${decision} → ok (dispatch #${dispatchNo}) ${JSON.stringify(body).slice(0, 200)}`);
|
|
557
645
|
let postStatus;
|
|
558
646
|
let gateAfter;
|
|
647
|
+
let gateKindAfter;
|
|
559
648
|
try {
|
|
560
649
|
const probe = clients.repull();
|
|
561
650
|
if (probe) {
|
|
@@ -571,35 +660,54 @@ async function decidePlanReviewInner(taskId, decision, permissionModeAfter, disp
|
|
|
571
660
|
else {
|
|
572
661
|
post = (await probe.runs.get(taskId));
|
|
573
662
|
}
|
|
574
|
-
postStatus =
|
|
663
|
+
postStatus = bodyWordOf(post, 'status');
|
|
575
664
|
gateAfter = pausedCheckpointIdOf(post?.result);
|
|
665
|
+
gateKindAfter = pausedGateKindOf(post?.result);
|
|
576
666
|
}
|
|
577
667
|
}
|
|
578
668
|
catch (e) {
|
|
579
669
|
hostLog('debug', `planReviewWire: post-decide status re-pull failed (fail-soft): ${String(e)}`);
|
|
580
670
|
}
|
|
581
|
-
const
|
|
671
|
+
const bodyStatus = bodyWordOf(body, 'status');
|
|
672
|
+
const effective = postStatus ?? bodyStatus;
|
|
582
673
|
statusSeen = effective;
|
|
583
|
-
const
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
else if (effective === 'needs_review') {
|
|
589
|
-
effect = 'still_parked';
|
|
590
|
-
stillParkedProven = postStatus === 'needs_review' && gateBefore !== undefined && gateAfter !== undefined && gateAfter === gateBefore;
|
|
674
|
+
const verdict = planReviewSettledVerdict({ postStatus, bodyStatus, reparked: bodySaysReparked(body), gateBefore, gateAfter, gateKindAfter });
|
|
675
|
+
effect = verdict.effect;
|
|
676
|
+
stillParkedProven = verdict.proven;
|
|
677
|
+
const code = bodyWordOf(body, 'errorCode');
|
|
678
|
+
if (effect === 'still_parked' && postStatus === 'needs_review' && !bodySaysReparked(body)) {
|
|
591
679
|
outcome =
|
|
592
680
|
`The plan_review ${decision} returned HTTP 200 but the session is STILL locked on the same review gate ` +
|
|
593
681
|
`(post-decide status: needs_review). The decision did NOT take effect (known engine issue, RB-471 family). ` +
|
|
594
682
|
`Tell the user plainly that the ${decision} did not go through; the reliable exits today are approving the plan or cancelling the task.`;
|
|
595
683
|
}
|
|
596
|
-
else if (
|
|
597
|
-
|
|
598
|
-
|
|
684
|
+
else if (effect === 'still_parked') {
|
|
685
|
+
outcome =
|
|
686
|
+
`The plan_review ${decision} was NOT applied: the engine could not continue the task and put the plan back to wait for a decision` +
|
|
687
|
+
`${code !== undefined ? ` (engine code: ${code})` : ''}. Tell the user plainly that the ${decision} did not go through.`;
|
|
688
|
+
}
|
|
689
|
+
else if (effect === 'advanced') {
|
|
690
|
+
outcome = planReviewAdvancedOutcome(decision, effective === 'needs_review' ? 'needs_review' : 'suspended');
|
|
691
|
+
}
|
|
692
|
+
else if (effect === 'took_effect') {
|
|
693
|
+
outcome =
|
|
694
|
+
`The plan was ${decision === 'approve' ? 'approved and the parked task resumed to completion' : 'rejected (plan discarded)'} — final status: ${effective} ` +
|
|
695
|
+
`(${postStatus !== undefined ? 'post-decide re-checked: task left the review gate' : "from the decision's own reply; the post-decide re-check was unavailable"}).`;
|
|
696
|
+
}
|
|
697
|
+
else if (effective === 'needs_review' && (gateBefore === undefined || gateAfter === undefined || postStatus !== 'needs_review')) {
|
|
698
|
+
outcome =
|
|
699
|
+
`The plan_review ${decision} returned HTTP 200 and the task is waiting at a plan review gate again (post-decide status: needs_review), ` +
|
|
700
|
+
`but it could not be told whether this is the same review (the ${decision} did not take effect) or a new plan written after it (it did).`;
|
|
701
|
+
}
|
|
702
|
+
else if (effective === 'suspended' || effective === 'needs_review') {
|
|
703
|
+
outcome =
|
|
704
|
+
`The plan_review ${decision} was accepted by the engine (HTTP 200) and the task is paused again (post-decide status: ${effective}), ` +
|
|
705
|
+
`${gateKindAfter !== undefined ? `at a '${gateKindAfter}' pause that is not an approval card` : 'but the pause it stopped at was not reported'} — what the ${decision} led to could not be confirmed.`;
|
|
599
706
|
}
|
|
600
707
|
else if (effective !== undefined) {
|
|
601
|
-
|
|
602
|
-
|
|
708
|
+
outcome =
|
|
709
|
+
`The plan_review ${decision} was accepted by the engine (HTTP 200), but the task then reported status ${effective}` +
|
|
710
|
+
`${code !== undefined ? ` (engine code: ${code})` : ''} — not a completion; what the ${decision} led to could not be confirmed.`;
|
|
603
711
|
}
|
|
604
712
|
else {
|
|
605
713
|
outcome = `The plan_review ${decision} was accepted by the engine (HTTP 200) but its effect is unconfirmed — final status: unknown (post-decide verification unavailable). Do not treat this as ${decision === 'approve' ? 'an approval that resumed the task' : 'a discarded plan'}.`;
|
|
@@ -648,10 +756,10 @@ async function decidePlanReviewInner(taskId, decision, permissionModeAfter, disp
|
|
|
648
756
|
outcome = `This ${decision} was not applied. ${corruptStoredRowContent(where)}`;
|
|
649
757
|
}
|
|
650
758
|
else if (typeof status === 'number') {
|
|
651
|
-
const
|
|
652
|
-
hostLog('debug', `planReviewWire: ${decision} → ${status} ${
|
|
759
|
+
const failureTexts = wireFailureTextsOf(e);
|
|
760
|
+
hostLog('debug', `planReviewWire: ${decision} → ${status} ${failureTexts.log.slice(0, 200)}`);
|
|
653
761
|
effect = (status >= 400 && status < 500) || (typeof refusedCode === 'string' && isUnavailableFaceCode(refusedCode)) ? 'not_applied' : 'unconfirmed';
|
|
654
|
-
outcome = `${`The plan_review decision failed: HTTP ${status} ${
|
|
762
|
+
outcome = `${`The plan_review decision failed: HTTP ${status} ${failureTexts.reason}`.trim()}${decideFailureNote(e)}`;
|
|
655
763
|
}
|
|
656
764
|
else if (noAnswer === 'time-limit' || noAnswer === 'deadline') {
|
|
657
765
|
hostLog('debug', `planReviewWire: ${decision} sent but no answer within the request time limit (task ${taskId})`);
|
|
@@ -821,9 +929,10 @@ function mintPlanReviewReopenCard(taskId, opts, sessionKey, receiptMs) {
|
|
|
821
929
|
? { ...(opts.wire !== undefined ? { wire: opts.wire } : {}), ...(opts.onOutcome !== undefined ? { onOutcome: opts.onOutcome } : {}) }
|
|
822
930
|
: undefined;
|
|
823
931
|
const deliver = opts?.deliverDecision ??
|
|
824
|
-
((tid, decision) => {
|
|
932
|
+
((tid, decision, reason) => {
|
|
825
933
|
hostLog('debug', `planReviewWire: reopen responder delivering ${decision} for task ${tid} (path=reopen-default)`);
|
|
826
|
-
|
|
934
|
+
const withReason = reason === undefined ? delivery : { ...delivery, reason };
|
|
935
|
+
void (withReason === undefined ? decidePlanReview(tid, decision) : decidePlanReview(tid, decision, undefined, withReason));
|
|
827
936
|
});
|
|
828
937
|
const activeKey = `${sessionKey}\u0000${canonicalId}`;
|
|
829
938
|
const unregister = registerLocalQuestionResponder(questionId, async (_id, answer) => {
|
|
@@ -831,15 +940,20 @@ function mintPlanReviewReopenCard(taskId, opts, sessionKey, receiptMs) {
|
|
|
831
940
|
if (activeReopenResponders.get(activeKey)?.questionId === questionId) {
|
|
832
941
|
activeReopenResponders.delete(activeKey);
|
|
833
942
|
}
|
|
834
|
-
const
|
|
835
|
-
if (
|
|
943
|
+
const choice = planReviewChoiceFromAnswer(answer, LEGACY_TWO_CHOICE_LABELS);
|
|
944
|
+
if (choice === 'dismissed') {
|
|
836
945
|
notePlanReviewUserDismissalFor(sessionKey, taskId, opts?.readGateInstanceKeys, questionId);
|
|
837
946
|
return { ok: true };
|
|
838
947
|
}
|
|
948
|
+
const decided = choice.decision;
|
|
949
|
+
const cardReason = choice.decision === 'reject' ? choice.reason : undefined;
|
|
839
950
|
notePlanReviewDecisiveAnswerFor(sessionKey, taskId);
|
|
840
951
|
notePlanReviewAnsweredFor(sessionKey, questionId);
|
|
841
952
|
try {
|
|
842
|
-
|
|
953
|
+
if (cardReason === undefined)
|
|
954
|
+
await deliver(taskId, decided);
|
|
955
|
+
else
|
|
956
|
+
await deliver(taskId, decided, cardReason);
|
|
843
957
|
}
|
|
844
958
|
catch (e) {
|
|
845
959
|
hostLog('error', `planReviewWire: reopen decision delivery threw for task ${taskId}: ${String(e)}`);
|
|
@@ -887,18 +1001,8 @@ async function reopenAfterDismissalCheck(taskId, opts, sessionKey, receiptMs, ma
|
|
|
887
1001
|
}
|
|
888
1002
|
}
|
|
889
1003
|
}
|
|
890
|
-
let handedOver = false;
|
|
891
1004
|
const ledgerSaysInFlight = planReviewDecisionInFlight(taskId, recheckReadStart);
|
|
892
|
-
if (
|
|
893
|
-
try {
|
|
894
|
-
handedOver = opts.decisionHandedOver?.(taskId) === true;
|
|
895
|
-
}
|
|
896
|
-
catch (err) {
|
|
897
|
-
hostLog('debug', `planReviewWire: reopen for task ${taskId} refused — the host's decision hand-over check threw: ${String(err)}`);
|
|
898
|
-
return { reopened: false };
|
|
899
|
-
}
|
|
900
|
-
}
|
|
901
|
-
if (ledgerSaysInFlight || handedOver) {
|
|
1005
|
+
if (ledgerSaysInFlight) {
|
|
902
1006
|
hostLog('debug', `planReviewWire: reopen for task ${taskId} refused after the dismissal check — a decision for this task went out while the check was reading`);
|
|
903
1007
|
return { reopened: false, _sema_decisionInFlight: true };
|
|
904
1008
|
}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type ApprovalSettledHow } from './gateLedger.js';
|
|
1
2
|
import { type ApprovalsListEnvelope, type CrashConvergedRow } from './crashConverged.js';
|
|
2
3
|
export type ReplayedApprovalDisposition = {
|
|
3
4
|
readonly kind: 'live';
|
|
@@ -5,6 +6,8 @@ export type ReplayedApprovalDisposition = {
|
|
|
5
6
|
} | {
|
|
6
7
|
readonly kind: 'decided';
|
|
7
8
|
readonly cause?: CrashConvergedRow['cause'];
|
|
9
|
+
readonly needsHumanReason?: NonNullable<CrashConvergedRow['needsHumanReason']>;
|
|
10
|
+
readonly settled?: ApprovalSettledHow;
|
|
8
11
|
} | {
|
|
9
12
|
readonly kind: 'unknown';
|
|
10
13
|
readonly why: 'unreadable_frame' | 'no_approval_id' | 'not_read' | 'list_unreadable' | 'list_not_reported' | 'list_incomplete';
|
|
@@ -17,5 +20,11 @@ export interface ReplayPendingBasis {
|
|
|
17
20
|
} | {
|
|
18
21
|
readonly read: 'failed';
|
|
19
22
|
};
|
|
23
|
+
readonly settled?: ReadonlyMap<string, ApprovalSettledHow>;
|
|
20
24
|
}
|
|
25
|
+
export declare function settledApprovalDisposition(frame: object, settled: ReplayPendingBasis['settled']): ReplayedApprovalDisposition | undefined;
|
|
21
26
|
export declare function replayedApprovalDisposition(frame: object, basis: ReplayPendingBasis): ReplayedApprovalDisposition;
|
|
27
|
+
export declare function replayedApprovalClosesCardFrame(disposition: ReplayedApprovalDisposition | null | undefined): boolean;
|
|
28
|
+
export declare function replayedApprovalSentence(disposition: ReplayedApprovalDisposition | undefined, opts?: {
|
|
29
|
+
readonly toolName?: string;
|
|
30
|
+
}): string | undefined;
|