@sema-agent/client-core 0.94.0 → 0.95.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 +341 -0
- package/README.md +70 -47
- package/dist/adapt/arms.js +5 -6
- package/dist/adapt/panelTasks.js +4 -10
- package/dist/adapt/toolCards.js +2 -2
- package/dist/adapt/wireShapes.js +3 -8
- package/dist/adapter/activeRunSelfHeal.d.ts +8 -3
- package/dist/adapter/activeRunSelfHeal.js +20 -12
- package/dist/adapter/downstream/eventToSdkMessage.js +24 -17
- package/dist/adapter/downstream/terminalToSdkResult.js +11 -3
- package/dist/adapter/runStream.js +2 -1
- 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 +2 -1
- package/dist/agentSession/engineSessionBackgroundStop.js +3 -2
- package/dist/agentsWireCaps.d.ts +2 -0
- 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 -1
- package/dist/callerCwdCapability.js +2 -7
- package/dist/centerWiringCapability.d.ts +1 -3
- package/dist/centerWiringCapability.js +18 -21
- package/dist/classifierStatus.js +4 -4
- package/dist/cloudConfigWireCaps.js +43 -21
- package/dist/compensations.js +1 -1
- package/dist/cycleOrder.d.ts +15 -0
- package/dist/cycleOrder.js +45 -0
- package/dist/decideFailureNote.js +4 -1
- package/dist/decideReceipt.d.ts +2 -1
- package/dist/decideReceipt.js +41 -13
- 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 +1 -0
- package/dist/displayUntrusted.js +313 -11
- 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 +7 -2
- package/dist/engineCapsCache.js +64 -26
- package/dist/engineCredentialRequirement.d.ts +9 -0
- package/dist/engineCredentialRequirement.js +23 -0
- package/dist/engineEnvSourcing.d.ts +53 -0
- package/dist/engineEnvSourcing.js +81 -0
- package/dist/engineErrorCodes.d.ts +14 -3
- package/dist/engineErrorCodes.js +31 -10
- package/dist/engineIdentity.js +2 -0
- package/dist/engineWireSdk.js +2 -2
- package/dist/executionLaneCapability.d.ts +2 -3
- package/dist/executionLaneCapability.js +18 -23
- package/dist/fileHistoryCaptureCapability.d.ts +0 -1
- package/dist/fileHistoryCaptureCapability.js +2 -6
- package/dist/fileHistoryLegNotice.d.ts +3 -2
- package/dist/fileHistoryLegNotice.js +51 -2
- package/dist/fleet/fleetLedger.d.ts +2 -0
- package/dist/fleet/fleetLedger.js +69 -52
- package/dist/fleet/fleetProjection.d.ts +0 -3
- package/dist/fleet/fleetProjection.js +9 -16
- 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/gateOutcome.js +30 -18
- package/dist/generated/sdkFactTables.d.ts +2 -0
- package/dist/generated/sdkFactTables.js +17 -0
- package/dist/generated/settingsSchemaFns.d.ts +10 -0
- package/dist/generated/settingsSchemaFns.js +22 -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 +5 -0
- package/dist/hitl/approvalEndingCause.js +61 -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/automaticAnswerVerdict.js +2 -2
- package/dist/hitl/crashConverged.js +2 -0
- package/dist/hitl/decisionConflict.d.ts +3 -0
- package/dist/hitl/decisionConflict.js +43 -0
- package/dist/hitl/decisionRefusal.d.ts +4 -0
- package/dist/hitl/decisionRefusal.js +26 -1
- package/dist/hitl/frameRouter.js +26 -43
- package/dist/hitl/gateLedger.d.ts +5 -0
- package/dist/hitl/gateLedger.js +21 -0
- package/dist/hitl/hitlBridge.d.ts +12 -1
- package/dist/hitl/hitlBridge.js +68 -53
- 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/parkExpiryJudgements.d.ts +19 -0
- package/dist/hitl/parkExpiryJudgements.js +46 -0
- package/dist/hitl/parkResolver.d.ts +3 -7
- package/dist/hitl/parkResolver.js +50 -26
- package/dist/hitl/persistedRulesWire.js +5 -1
- package/dist/hitl/planReviewWire.d.ts +2 -2
- package/dist/hitl/planReviewWire.js +56 -30
- package/dist/hitl/replayedApproval.d.ts +8 -0
- package/dist/hitl/replayedApproval.js +125 -10
- package/dist/hitl/resumeRunningCard.d.ts +2 -0
- package/dist/hitl/resumeRunningCard.js +15 -4
- package/dist/hitl/toolApprovalWire.d.ts +24 -4
- package/dist/hitl/toolApprovalWire.js +115 -38
- package/dist/hooksWireCaps.js +38 -6
- package/dist/host.d.ts +5 -0
- package/dist/host.js +3 -1
- package/dist/hostCallbackGuard.d.ts +1 -0
- package/dist/hostCallbackGuard.js +25 -0
- package/dist/index.d.ts +30 -11
- package/dist/index.js +20 -8
- 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 -1
- package/dist/mcpProbeCapability.js +2 -6
- package/dist/mcpReconnect.d.ts +1 -3
- package/dist/mcpReconnect.js +10 -5
- package/dist/memoryComplianceCapability.d.ts +0 -1
- package/dist/memoryComplianceCapability.js +2 -6
- package/dist/memoryOriginCapability.d.ts +0 -1
- package/dist/memoryOriginCapability.js +2 -6
- 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 +1 -1
- package/dist/modelIdentityResolvability.js +5 -12
- package/dist/modelSwitchFallback.d.ts +69 -0
- package/dist/modelSwitchFallback.js +206 -0
- package/dist/notifications.js +12 -11
- package/dist/outputStyleSeatCapability.d.ts +0 -1
- package/dist/outputStyleSeatCapability.js +2 -7
- package/dist/ownKey.d.ts +6 -0
- package/dist/ownKey.js +48 -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/peerLaneCapability.d.ts +0 -1
- package/dist/peerLaneCapability.js +2 -6
- package/dist/permissionModesCapability.d.ts +0 -1
- package/dist/permissionModesCapability.js +5 -10
- 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 +6 -0
- package/dist/permissionsDeclaration.js +45 -0
- package/dist/printToolResultFrame.js +2 -10
- package/dist/promptDelivery.js +0 -8
- package/dist/resumeRefusalCopy.d.ts +18 -1
- package/dist/resumeRefusalCopy.js +126 -15
- package/dist/rewindArchiveCapability.d.ts +2 -1
- package/dist/rewindArchiveCapability.js +15 -7
- 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/runTerminal.d.ts +0 -11
- package/dist/runTerminal.js +4 -27
- package/dist/sdkRegistryTransit.d.ts +2 -1
- package/dist/sdkRegistryTransit.js +1 -0
- package/dist/sealedKeyCapability.d.ts +0 -1
- package/dist/sealedKeyCapability.js +3 -9
- package/dist/seatContract.d.ts +54 -25
- package/dist/seatContract.js +394 -171
- 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 -1
- package/dist/sessionReadRedactionCapability.js +2 -7
- package/dist/sessionSyncFileHistoryCapability.d.ts +0 -1
- package/dist/sessionSyncFileHistoryCapability.js +2 -6
- package/dist/skillToolListsCapability.d.ts +0 -1
- package/dist/skillToolListsCapability.js +2 -6
- 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 -1
- package/dist/steerPriorityCapability.js +3 -9
- package/dist/storePostureCapability.d.ts +1 -1
- package/dist/storePostureCapability.js +16 -16
- 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/engineSubagentTail.d.ts +0 -1
- package/dist/subagent/engineSubagentTail.js +7 -32
- package/dist/subagentContentStore.js +3 -3
- package/dist/supportFloor.js +2 -5
- package/dist/terminalStatuses.d.ts +30 -0
- package/dist/terminalStatuses.js +67 -0
- package/dist/toolResult.d.ts +5 -0
- package/dist/toolResult.js +88 -36
- package/dist/types/engineState.d.ts +2 -1
- package/dist/usageAnalytics.d.ts +146 -0
- package/dist/usageAnalytics.js +311 -0
- package/dist/userInvokedSkillsCapability.d.ts +0 -1
- package/dist/userInvokedSkillsCapability.js +2 -6
- package/dist/webSearchBackendCapability.d.ts +0 -1
- package/dist/webSearchBackendCapability.js +3 -7
- package/dist/webSearchWireCaps.js +3 -11
- package/dist/wireFailureShape.d.ts +4 -0
- package/dist/wireFailureShape.js +42 -2
- 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 +1033 -26
- 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,8 @@
|
|
|
1
1
|
import { putOwnKey, readOwnDataValue } from '../ownKey.js';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
2
|
+
import { ApprovalStaleError, NotFoundError, ParkedResumeStartupError } from '@sema-agent/sdk';
|
|
3
|
+
import { DecideTransportRetryExhaustedError, GATE_FAILURE_CODES, HitlBridge, NO_QUESTION_OVERLAY_REASON, findPendingForTask, hitlSafetyCodeOf, isNoDecisionSurfaceReason, readDecideCurrentPending, readWireErrorCode, } from './hitlBridge.js';
|
|
4
|
+
import { ASK_GONE, CHECKPOINT_UNSUPPORTED_VERSION, DECIDE_WORKFLOW_PARK_FORKED, DECIDE_WORKFLOW_PARKS_UNREADABLE, PARKED_RESUME_STARTUP_FAILED, RESUME_POLICY_FOLD_CODE, isDecideAlreadyResolvedCode, isDecideParkMovedCode, refusalSaysStillPending } from '../engineErrorCodes.js';
|
|
5
|
+
import { isHitlSafetyErrorLike } from './parkOwnership.js';
|
|
4
6
|
import { publishQuestionFrame, registerLocalQuestionResponder, hasQuestionOverlay, } from '../liveQuestionStore.js';
|
|
5
7
|
import { hostLog } from '../host.js';
|
|
6
8
|
import { surfaceFsApprovalAndDecide } from './toolApprovalWire.js';
|
|
@@ -9,7 +11,7 @@ import { flushHeldWithInterruptRewrite, isAskTool } from './frameRouter.js';
|
|
|
9
11
|
import { approvalCallKey, askGateQuestionId } from './gateIdentity.js';
|
|
10
12
|
import { readDecideReceipt } from '../decideReceipt.js';
|
|
11
13
|
import { decideFailureNote } from '../decideFailureNote.js';
|
|
12
|
-
import { wireFailureTextsOf } from '../wireFailureShape.js';
|
|
14
|
+
import { thrownIsInstanceOf, wireFailureTextsOf } from '../wireFailureShape.js';
|
|
13
15
|
export const MAX_GATE_HOPS = 2;
|
|
14
16
|
export function nextHopBudget(prev, round) {
|
|
15
17
|
const total = (prev?.total ?? 0) + 1;
|
|
@@ -18,16 +20,6 @@ export function nextHopBudget(prev, round) {
|
|
|
18
20
|
const MAX_TRANSPORT_REATTACHES = 2;
|
|
19
21
|
export const MAX_TOTAL_PARKS = 64;
|
|
20
22
|
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
23
|
function isGateFailureCode(v) {
|
|
32
24
|
return typeof v === 'string' && GATE_FAILURE_CODES.includes(v);
|
|
33
25
|
}
|
|
@@ -41,27 +33,59 @@ function alreadyResolvedReasonToken(reason) {
|
|
|
41
33
|
const r = reason.toLowerCase();
|
|
42
34
|
return ALREADY_RESOLVED_REASON_TOKENS.find((t) => r.includes(t));
|
|
43
35
|
}
|
|
44
|
-
export function isAlreadyResolvedFailure(
|
|
36
|
+
export function isAlreadyResolvedFailure(failure) {
|
|
45
37
|
try {
|
|
46
|
-
return alreadyResolvedFailureVerdict(
|
|
38
|
+
return alreadyResolvedFailureVerdict(failure);
|
|
47
39
|
}
|
|
48
40
|
catch {
|
|
49
41
|
return false;
|
|
50
42
|
}
|
|
51
43
|
}
|
|
52
|
-
|
|
53
|
-
|
|
44
|
+
const ALREADY_RESOLVED_TYPED_ERROR_NAMES = Object.freeze([ApprovalStaleError.name, NotFoundError.name]);
|
|
45
|
+
const PARKED_RESUME_STARTUP_TYPED_ERROR_NAME = ParkedResumeStartupError.name;
|
|
46
|
+
function decideFailureFactsOf(failure) {
|
|
47
|
+
if (typeof failure !== 'object' || failure === null)
|
|
48
|
+
return undefined;
|
|
49
|
+
const o = failure;
|
|
50
|
+
const ec = o.errorCode;
|
|
51
|
+
const errorCode = typeof ec === 'string' && ec.length > 0 ? ec : undefined;
|
|
52
|
+
const retriable = refusalSaysStillPending(failure);
|
|
53
|
+
if (Object.hasOwn(failure, 'kind') && o.kind === 'failed') {
|
|
54
|
+
const safety = isGateFailureCode(o.safetyCode) ? o.safetyCode : undefined;
|
|
55
|
+
const code = isGateFailureCode(o.code) ? o.code : safety;
|
|
56
|
+
return { code, safetySignal: safety !== undefined, errorCode, retriable, typedErrorName: undefined, reason: o.reason };
|
|
57
|
+
}
|
|
58
|
+
const name = o.name;
|
|
59
|
+
return {
|
|
60
|
+
code: isGateFailureCode(o.code) ? o.code : undefined,
|
|
61
|
+
safetySignal: isHitlSafetyErrorLike(failure),
|
|
62
|
+
errorCode,
|
|
63
|
+
retriable,
|
|
64
|
+
typedErrorName: typeof name === 'string' ? name : undefined,
|
|
65
|
+
reason: String(failure),
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
function alreadyResolvedFailureVerdict(failure) {
|
|
69
|
+
const f = decideFailureFactsOf(failure);
|
|
70
|
+
if (f === undefined)
|
|
54
71
|
return false;
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
72
|
+
if (f.code !== undefined)
|
|
73
|
+
return f.code === 'no_pending';
|
|
74
|
+
if (f.safetySignal)
|
|
75
|
+
return false;
|
|
76
|
+
if (isDecideAlreadyResolvedCode(f.errorCode))
|
|
77
|
+
return true;
|
|
78
|
+
if (f.typedErrorName !== undefined && ALREADY_RESOLVED_TYPED_ERROR_NAMES.includes(f.typedErrorName))
|
|
79
|
+
return true;
|
|
80
|
+
if (f.typedErrorName === PARKED_RESUME_STARTUP_TYPED_ERROR_NAME && !isDecideParkMovedCode(f.errorCode))
|
|
81
|
+
return false;
|
|
82
|
+
if (isCodeClassifiedGateFailure(f.errorCode, f.retriable))
|
|
59
83
|
return false;
|
|
60
|
-
if (
|
|
84
|
+
if (isDecideParkMovedCode(f.errorCode))
|
|
61
85
|
return true;
|
|
62
|
-
if (
|
|
86
|
+
if (f.errorCode === ASK_GONE)
|
|
63
87
|
return true;
|
|
64
|
-
return isAlreadyResolvedGateReason(
|
|
88
|
+
return isAlreadyResolvedGateReason(f.reason);
|
|
65
89
|
}
|
|
66
90
|
export function isGateStandingErrorCode(code, retriable) {
|
|
67
91
|
return (code === RESUME_POLICY_FOLD_CODE ||
|
|
@@ -167,7 +191,7 @@ async function surfaceGateAndDecide(deps, taskId, askArgsByCall, signal, parkGat
|
|
|
167
191
|
return { kind: 'decided', gatedCallId, ...(declinedReceipt !== undefined ? { receipt: declinedReceipt } : {}) };
|
|
168
192
|
}
|
|
169
193
|
catch (e) {
|
|
170
|
-
const code =
|
|
194
|
+
const code = hitlSafetyCodeOf(e);
|
|
171
195
|
const currentPending = readDecideCurrentPending(e);
|
|
172
196
|
const wireCode = readWireErrorCode(e);
|
|
173
197
|
const wireRetriable = typeof e === 'object' && e !== null && refusalSaysStillPending(e);
|
|
@@ -179,7 +203,7 @@ async function surfaceGateAndDecide(deps, taskId, askArgsByCall, signal, parkGat
|
|
|
179
203
|
gatedCallId,
|
|
180
204
|
reason: `decide failed: ${failureTexts.reason}${decideFailureNote(e, attemptedDecision)}`,
|
|
181
205
|
...(code !== undefined ? { code } : {}),
|
|
182
|
-
...(e
|
|
206
|
+
...(thrownIsInstanceOf(e, DecideTransportRetryExhaustedError) ? { retryExhausted: true } : {}),
|
|
183
207
|
...(currentPending !== undefined ? { currentPending } : {}),
|
|
184
208
|
...(wireCode !== undefined ? { errorCode: wireCode } : {}),
|
|
185
209
|
...(wireRetriable ? { retriable: true } : {}),
|
|
@@ -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<{
|
|
@@ -76,14 +77,13 @@ export declare function __resetPlanReviewDecisionLatchForTests(): void;
|
|
|
76
77
|
export declare function decidePlanReview(taskId: string, decision: 'approve' | 'reject', permissionModeAfter?: string, opts?: DecidePlanReviewOptions): Promise<void>;
|
|
77
78
|
export interface ReopenPlanReviewOpts {
|
|
78
79
|
mintFreshQuestionId?: boolean;
|
|
79
|
-
deliverDecision?: (taskId: string, decision: 'approve' | 'reject') => void | Promise<void>;
|
|
80
|
+
deliverDecision?: (taskId: string, decision: 'approve' | 'reject', reason?: string) => void | Promise<void>;
|
|
80
81
|
sessionKey?: string;
|
|
81
82
|
wire?: PlanReviewWire;
|
|
82
83
|
onOutcome?: PlanReviewDeliveryOptions['onOutcome'];
|
|
83
84
|
presentationReceiptMs?: number;
|
|
84
85
|
trigger?: PlanReviewReopenTrigger;
|
|
85
86
|
readGateInstanceKeys?: PlanReviewGateInstanceReader;
|
|
86
|
-
decisionHandedOver?: (taskId: string) => boolean;
|
|
87
87
|
pendingReadStartedAt?: number;
|
|
88
88
|
}
|
|
89
89
|
export declare function _resetActiveReopenRespondersForTest(): void;
|
|
@@ -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' };
|
|
@@ -270,10 +298,12 @@ export function armPlanReviewApproval(result, sessionKey, opts) {
|
|
|
270
298
|
const decided = choice.decision;
|
|
271
299
|
notePlanReviewDecisiveAnswerFor(DEFAULT_SESSION_KEY, taskId);
|
|
272
300
|
const modeAfter = choice.decision === 'approve' ? choice.permissionModeAfter : undefined;
|
|
301
|
+
const cardReason = choice.decision === 'reject' ? choice.reason : undefined;
|
|
302
|
+
const cardDelivery = cardReason !== undefined ? { ...delivery, reason: cardReason } : delivery;
|
|
273
303
|
offerModeAfterByTask.delete(taskId);
|
|
274
304
|
notePlanReviewAnswered(questionId);
|
|
275
305
|
hostLog('debug', `planReviewWire: arm responder delivering ${decided} for task ${taskId} (path=arm)`);
|
|
276
|
-
void decidePlanReviewFor(taskId, decided, modeAfter,
|
|
306
|
+
void decidePlanReviewFor(taskId, decided, modeAfter, cardDelivery, gateBefore);
|
|
277
307
|
return { ok: true };
|
|
278
308
|
});
|
|
279
309
|
publishPlanReviewCard(taskId);
|
|
@@ -821,9 +851,10 @@ function mintPlanReviewReopenCard(taskId, opts, sessionKey, receiptMs) {
|
|
|
821
851
|
? { ...(opts.wire !== undefined ? { wire: opts.wire } : {}), ...(opts.onOutcome !== undefined ? { onOutcome: opts.onOutcome } : {}) }
|
|
822
852
|
: undefined;
|
|
823
853
|
const deliver = opts?.deliverDecision ??
|
|
824
|
-
((tid, decision) => {
|
|
854
|
+
((tid, decision, reason) => {
|
|
825
855
|
hostLog('debug', `planReviewWire: reopen responder delivering ${decision} for task ${tid} (path=reopen-default)`);
|
|
826
|
-
|
|
856
|
+
const withReason = reason === undefined ? delivery : { ...delivery, reason };
|
|
857
|
+
void (withReason === undefined ? decidePlanReview(tid, decision) : decidePlanReview(tid, decision, undefined, withReason));
|
|
827
858
|
});
|
|
828
859
|
const activeKey = `${sessionKey}\u0000${canonicalId}`;
|
|
829
860
|
const unregister = registerLocalQuestionResponder(questionId, async (_id, answer) => {
|
|
@@ -831,15 +862,20 @@ function mintPlanReviewReopenCard(taskId, opts, sessionKey, receiptMs) {
|
|
|
831
862
|
if (activeReopenResponders.get(activeKey)?.questionId === questionId) {
|
|
832
863
|
activeReopenResponders.delete(activeKey);
|
|
833
864
|
}
|
|
834
|
-
const
|
|
835
|
-
if (
|
|
865
|
+
const choice = planReviewChoiceFromAnswer(answer, LEGACY_TWO_CHOICE_LABELS);
|
|
866
|
+
if (choice === 'dismissed') {
|
|
836
867
|
notePlanReviewUserDismissalFor(sessionKey, taskId, opts?.readGateInstanceKeys, questionId);
|
|
837
868
|
return { ok: true };
|
|
838
869
|
}
|
|
870
|
+
const decided = choice.decision;
|
|
871
|
+
const cardReason = choice.decision === 'reject' ? choice.reason : undefined;
|
|
839
872
|
notePlanReviewDecisiveAnswerFor(sessionKey, taskId);
|
|
840
873
|
notePlanReviewAnsweredFor(sessionKey, questionId);
|
|
841
874
|
try {
|
|
842
|
-
|
|
875
|
+
if (cardReason === undefined)
|
|
876
|
+
await deliver(taskId, decided);
|
|
877
|
+
else
|
|
878
|
+
await deliver(taskId, decided, cardReason);
|
|
843
879
|
}
|
|
844
880
|
catch (e) {
|
|
845
881
|
hostLog('error', `planReviewWire: reopen decision delivery threw for task ${taskId}: ${String(e)}`);
|
|
@@ -887,18 +923,8 @@ async function reopenAfterDismissalCheck(taskId, opts, sessionKey, receiptMs, ma
|
|
|
887
923
|
}
|
|
888
924
|
}
|
|
889
925
|
}
|
|
890
|
-
let handedOver = false;
|
|
891
926
|
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) {
|
|
927
|
+
if (ledgerSaysInFlight) {
|
|
902
928
|
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
929
|
return { reopened: false, _sema_decisionInFlight: true };
|
|
904
930
|
}
|
|
@@ -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,10 @@ 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 replayedApprovalSentence(disposition: ReplayedApprovalDisposition | undefined, opts?: {
|
|
28
|
+
readonly toolName?: string;
|
|
29
|
+
}): string | undefined;
|
|
@@ -1,29 +1,64 @@
|
|
|
1
|
-
import { hasLedgerPositionKey } from './gateLedger.js';
|
|
1
|
+
import { APPROVAL_SETTLED_HOWS, hasLedgerPositionKey } from './gateLedger.js';
|
|
2
2
|
import { readLivePendingRows } from './livePendingAsk.js';
|
|
3
3
|
import { projectCrashConverged } from './crashConverged.js';
|
|
4
|
+
import { quoteUntrustedForSentence } from '../displayUntrusted.js';
|
|
4
5
|
const live = (basis) => Object.freeze({ kind: 'live', basis });
|
|
5
6
|
const unknown = (why) => Object.freeze({ kind: 'unknown', why });
|
|
6
|
-
const decided = (
|
|
7
|
+
const decided = (row) => Object.freeze(row === undefined
|
|
8
|
+
? { kind: 'decided' }
|
|
9
|
+
: { kind: 'decided', cause: row.cause, ...(row.needsHumanReason !== undefined ? { needsHumanReason: row.needsHumanReason } : {}) });
|
|
10
|
+
const decidedSettled = (how) => Object.freeze({ kind: 'decided', settled: how });
|
|
7
11
|
function approvalIdOf(frame) {
|
|
8
12
|
const v = frame.approvalId;
|
|
9
13
|
return typeof v === 'string' && v !== '' ? v : undefined;
|
|
10
14
|
}
|
|
11
|
-
function
|
|
15
|
+
function crashConvergedFactsOf(body, approvalId) {
|
|
12
16
|
const projection = projectCrashConverged(body);
|
|
13
17
|
if (projection === undefined)
|
|
14
18
|
return undefined;
|
|
15
19
|
for (const row of [...projection.resumeSafe, ...projection.needsHuman]) {
|
|
16
20
|
if (row.approvalId === approvalId)
|
|
17
|
-
return row.cause;
|
|
21
|
+
return { cause: row.cause, ...(row.needsHumanReason !== undefined ? { needsHumanReason: row.needsHumanReason } : {}) };
|
|
18
22
|
}
|
|
19
23
|
return undefined;
|
|
20
24
|
}
|
|
25
|
+
export function settledApprovalDisposition(frame, settled) {
|
|
26
|
+
try {
|
|
27
|
+
if (typeof settled !== 'object' || settled === null || typeof settled.get !== 'function')
|
|
28
|
+
return undefined;
|
|
29
|
+
const id = approvalIdOf(frame);
|
|
30
|
+
if (id === undefined)
|
|
31
|
+
return undefined;
|
|
32
|
+
const how = settled.get(id);
|
|
33
|
+
return typeof how === 'string' && APPROVAL_SETTLED_HOWS.includes(how) ? decidedSettled(how) : undefined;
|
|
34
|
+
}
|
|
35
|
+
catch {
|
|
36
|
+
return undefined;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
21
39
|
export function replayedApprovalDisposition(frame, basis) {
|
|
22
40
|
let approvalId;
|
|
41
|
+
let positioned;
|
|
23
42
|
try {
|
|
24
43
|
if (typeof frame !== 'object' || frame === null)
|
|
25
44
|
return unknown('unreadable_frame');
|
|
26
|
-
|
|
45
|
+
positioned = hasLedgerPositionKey(frame);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
return unknown('unreadable_frame');
|
|
49
|
+
}
|
|
50
|
+
let settledBasis;
|
|
51
|
+
try {
|
|
52
|
+
settledBasis = typeof basis === 'object' && basis !== null ? basis.settled : undefined;
|
|
53
|
+
}
|
|
54
|
+
catch {
|
|
55
|
+
settledBasis = undefined;
|
|
56
|
+
}
|
|
57
|
+
const early = settledApprovalDisposition(frame, settledBasis);
|
|
58
|
+
if (early !== undefined)
|
|
59
|
+
return early;
|
|
60
|
+
try {
|
|
61
|
+
if (!positioned)
|
|
27
62
|
return live('live_leg');
|
|
28
63
|
approvalId = approvalIdOf(frame);
|
|
29
64
|
}
|
|
@@ -70,15 +105,15 @@ export function replayedApprovalDisposition(frame, basis) {
|
|
|
70
105
|
}
|
|
71
106
|
if (reading.kind === 'present' && reading.rows.some((r) => r.approvalId === approvalId))
|
|
72
107
|
return live('pending_list');
|
|
73
|
-
let
|
|
108
|
+
let facts;
|
|
74
109
|
try {
|
|
75
|
-
|
|
110
|
+
facts = crashConvergedFactsOf(body, approvalId);
|
|
76
111
|
}
|
|
77
112
|
catch {
|
|
78
|
-
|
|
113
|
+
facts = undefined;
|
|
79
114
|
}
|
|
80
|
-
if (
|
|
81
|
-
return decided(
|
|
115
|
+
if (facts !== undefined)
|
|
116
|
+
return decided(facts);
|
|
82
117
|
if (reading.kind === 'not_reported')
|
|
83
118
|
return unknown('list_not_reported');
|
|
84
119
|
if (reading.kind === 'malformed')
|
|
@@ -87,3 +122,83 @@ export function replayedApprovalDisposition(frame, basis) {
|
|
|
87
122
|
return unknown('list_incomplete');
|
|
88
123
|
return decided();
|
|
89
124
|
}
|
|
125
|
+
const TOOL_NAME_MAX = 80;
|
|
126
|
+
const THIS_REQUEST = 'this approval request';
|
|
127
|
+
const sentenceInitial = (s) => s.charAt(0).toUpperCase() + s.slice(1);
|
|
128
|
+
const TOOL_STATE_NOT_SHOWN = 'Whether the tool had started is not shown here.';
|
|
129
|
+
const STOPPED_BY_CAUSE = Object.freeze({
|
|
130
|
+
crashed_before_park: 'the engine stopped unexpectedly',
|
|
131
|
+
shutdown_before_park: 'the engine was shut down in an orderly way',
|
|
132
|
+
});
|
|
133
|
+
const STATE_BY_REASON = Object.freeze({
|
|
134
|
+
pending_unsafe: 'waiting',
|
|
135
|
+
approved_then_interrupted: 'approved',
|
|
136
|
+
contradictory: 'unclear',
|
|
137
|
+
unstable_row: 'unclear',
|
|
138
|
+
});
|
|
139
|
+
const CRASH_CONVERGED_SENTENCE = Object.freeze({
|
|
140
|
+
waiting: (what, stopped) => `${sentenceInitial(what)} was still waiting when ${stopped}, so the engine denied it automatically; no decision was sent for it from here. ${TOOL_STATE_NOT_SHOWN}`,
|
|
141
|
+
approved: (what, stopped) => `${sentenceInitial(what)} had already been approved and may have been running when ${stopped}, so a side effect may have partly landed; the engine then marked it denied, and no decision was sent for it from here.`,
|
|
142
|
+
unclear: (what, stopped) => `${sentenceInitial(what)} was denied automatically when ${stopped}, but its record does not show reliably whether it had been approved or whether the tool had started; no decision was sent for it from here.`,
|
|
143
|
+
});
|
|
144
|
+
function crashConvergedStateOf(disposition) {
|
|
145
|
+
let reason;
|
|
146
|
+
try {
|
|
147
|
+
if (typeof disposition !== 'object' || disposition === null || !('needsHumanReason' in disposition))
|
|
148
|
+
return 'waiting';
|
|
149
|
+
reason = disposition.needsHumanReason;
|
|
150
|
+
}
|
|
151
|
+
catch {
|
|
152
|
+
return 'unclear';
|
|
153
|
+
}
|
|
154
|
+
if (reason === undefined)
|
|
155
|
+
return 'waiting';
|
|
156
|
+
return typeof reason === 'string' && Object.hasOwn(STATE_BY_REASON, reason) ? STATE_BY_REASON[reason] : 'unclear';
|
|
157
|
+
}
|
|
158
|
+
const SETTLED_PHRASE = Object.freeze({
|
|
159
|
+
answered: 'answered',
|
|
160
|
+
interrupted: 'dismissed',
|
|
161
|
+
closed_by_engine: 'closed by the engine',
|
|
162
|
+
});
|
|
163
|
+
const settledRepeat = (what, how) => `${sentenceInitial(what)} was ${SETTLED_PHRASE[how]} earlier, so this repeated copy of it was not raised as a new question and no decision was sent for it.`;
|
|
164
|
+
const decidedPlain = (what) => `${sentenceInitial(what)} is no longer listed by the engine as waiting for a decision, so no decision was sent for it.`;
|
|
165
|
+
const unconfirmed = (what) => `Whether ${what} is still waiting for a decision could not be confirmed, so no decision was sent for it.`;
|
|
166
|
+
function guardedGet(o, key) {
|
|
167
|
+
try {
|
|
168
|
+
if (typeof o !== 'object' || o === null)
|
|
169
|
+
return undefined;
|
|
170
|
+
return o[key];
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
return undefined;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
function subjectOf(opts) {
|
|
177
|
+
const raw = guardedGet(opts, 'toolName');
|
|
178
|
+
if (typeof raw !== 'string')
|
|
179
|
+
return THIS_REQUEST;
|
|
180
|
+
let quoted;
|
|
181
|
+
try {
|
|
182
|
+
quoted = quoteUntrustedForSentence(raw, TOOL_NAME_MAX);
|
|
183
|
+
}
|
|
184
|
+
catch {
|
|
185
|
+
return THIS_REQUEST;
|
|
186
|
+
}
|
|
187
|
+
return quoted === undefined ? THIS_REQUEST : `the approval request for ${quoted}`;
|
|
188
|
+
}
|
|
189
|
+
export function replayedApprovalSentence(disposition, opts) {
|
|
190
|
+
const kind = guardedGet(disposition, 'kind');
|
|
191
|
+
if (kind === 'unknown')
|
|
192
|
+
return unconfirmed(subjectOf(opts));
|
|
193
|
+
if (kind !== 'decided')
|
|
194
|
+
return undefined;
|
|
195
|
+
const what = subjectOf(opts);
|
|
196
|
+
const cause = guardedGet(disposition, 'cause');
|
|
197
|
+
if (typeof cause === 'string' && Object.hasOwn(STOPPED_BY_CAUSE, cause)) {
|
|
198
|
+
return CRASH_CONVERGED_SENTENCE[crashConvergedStateOf(disposition)](what, STOPPED_BY_CAUSE[cause]);
|
|
199
|
+
}
|
|
200
|
+
const settled = guardedGet(disposition, 'settled');
|
|
201
|
+
if (typeof settled === 'string' && Object.hasOwn(SETTLED_PHRASE, settled))
|
|
202
|
+
return settledRepeat(what, settled);
|
|
203
|
+
return decidedPlain(what);
|
|
204
|
+
}
|
|
@@ -17,6 +17,7 @@ export interface ResumeRunningCardOption {
|
|
|
17
17
|
}
|
|
18
18
|
export declare function resumeRunningLivenessRow(msSinceLastActivity: number | null | undefined): string | null;
|
|
19
19
|
export declare function resumeRunningQuestionText(i: ResumeRunningCardInput): string;
|
|
20
|
+
export declare function runningAttachOffered(canAttach: boolean | undefined): boolean;
|
|
20
21
|
export declare function resumeRunningOptions(i: ResumeRunningCardInput): ResumeRunningCardOption[];
|
|
21
22
|
export declare function resumeChoiceFromLabels(selected: readonly string[] | null | undefined): ResumeRunningChoice;
|
|
22
23
|
export declare const RESUME_RUNNING_NO_UI_EXIT_CODE = 75;
|
|
@@ -26,4 +27,5 @@ export declare function resumeRunningNoUiGuidance(i: {
|
|
|
26
27
|
sessionId?: string | null;
|
|
27
28
|
}): string;
|
|
28
29
|
export declare function resumeAttachReplayDisclosure(taskId: string): string;
|
|
30
|
+
export declare function resumeRunningCancelConfirmedRow(taskId: string): string;
|
|
29
31
|
export declare function resumeRunningCancelUnconfirmedRow(taskId: string): string;
|
|
@@ -14,6 +14,9 @@ export function resumeRunningQuestionText(i) {
|
|
|
14
14
|
const liveness = resumeRunningLivenessRow(i.msSinceLastActivity);
|
|
15
15
|
return liveness === null ? head : `${head}\n${liveness}`;
|
|
16
16
|
}
|
|
17
|
+
export function runningAttachOffered(canAttach) {
|
|
18
|
+
return canAttach === true;
|
|
19
|
+
}
|
|
17
20
|
export function resumeRunningOptions(i) {
|
|
18
21
|
const options = [
|
|
19
22
|
{
|
|
@@ -21,7 +24,7 @@ export function resumeRunningOptions(i) {
|
|
|
21
24
|
description: 'Leaves the run alone. It keeps executing on the engine, but this screen will not show it and it will not be listed here — your next message runs into it again, and sema asks you then.',
|
|
22
25
|
},
|
|
23
26
|
];
|
|
24
|
-
if (i.canAttach) {
|
|
27
|
+
if (runningAttachOffered(i.canAttach)) {
|
|
25
28
|
options.push({
|
|
26
29
|
label: RESUME_CHOICE_ATTACH_LABEL,
|
|
27
30
|
description: 'Follows that run from here: sema replays it from the engine ledger and keeps streaming it into this conversation. ' +
|
|
@@ -65,8 +68,16 @@ export function resumeAttachReplayDisclosure(taskId) {
|
|
|
65
68
|
`The replayed turns are not billed into this session's cost again either — the engine's own record ` +
|
|
66
69
|
`(GET /v1/runs/${taskId}) is the authority on what that run really spent.`);
|
|
67
70
|
}
|
|
71
|
+
function cancelRow(taskId, confirmed) {
|
|
72
|
+
return confirmed
|
|
73
|
+
? `The engine accepted the cancel for run ${taskId} on your request. A cancel finishes on the engine's side, so that run may need a moment to stop.`
|
|
74
|
+
: `sema: the cancel for run ${taskId} did not come back confirmed, so that run may still be executing. ` +
|
|
75
|
+
`This screen does not list it — read its real state on the engine (GET /v1/runs/${taskId}) before ` +
|
|
76
|
+
`assuming this session is free.`;
|
|
77
|
+
}
|
|
78
|
+
export function resumeRunningCancelConfirmedRow(taskId) {
|
|
79
|
+
return cancelRow(taskId, true);
|
|
80
|
+
}
|
|
68
81
|
export function resumeRunningCancelUnconfirmedRow(taskId) {
|
|
69
|
-
return (
|
|
70
|
-
`This screen does not list it — read its real state on the engine (GET /v1/runs/${taskId}) before ` +
|
|
71
|
-
`assuming this session is free.`);
|
|
82
|
+
return cancelRow(taskId, false);
|
|
72
83
|
}
|
|
@@ -6,7 +6,7 @@ import { type DenyAttributionRefusalDetail } from '../wireRefusalCopy.js';
|
|
|
6
6
|
import { type ApprovalDecidedByReading } from '../approvalDecidedByCapability.js';
|
|
7
7
|
import { type DecideReceiptView } from '../decideReceipt.js';
|
|
8
8
|
import { RULE_OFFER_MATCHES, RULE_OFFER_BATCH_MEMBER_KINDS, RULE_OFFER_UNCOVERED_REASONS, RULE_OFFERS_ABSENCE_REASONS } from '@sema-agent/sdk';
|
|
9
|
-
import type { ApprovalDecidedBy, ToolApprovalRespondAck, PersistedRuleAnchor as SdkPersistedRuleAnchor, RuleOfferMatch as SdkRuleOfferMatch, RuleOfferBatchMember as SdkRuleOfferBatchMember, RuleOfferUncoveredDetail as SdkRuleOfferUncoveredDetail, RuleOfferUncoveredReason as SdkRuleOfferUncoveredReason, AskOrigin as SdkAskOrigin, RuleOffersAbsence as SdkRuleOffersAbsence, DenialLimitKind as SdkDenialLimitKind, DenialLimitFallback as SdkDenialLimitFallback } from '@sema-agent/sdk';
|
|
9
|
+
import type { ApprovalDecidedBy, ApprovalSettleCause, ToolApprovalRespondAck, PersistedRuleAnchor as SdkPersistedRuleAnchor, RuleOfferMatch as SdkRuleOfferMatch, RuleOfferBatchMember as SdkRuleOfferBatchMember, RuleOfferUncoveredDetail as SdkRuleOfferUncoveredDetail, RuleOfferUncoveredReason as SdkRuleOfferUncoveredReason, AskOrigin as SdkAskOrigin, RuleOffersAbsence as SdkRuleOffersAbsence, DenialLimitKind as SdkDenialLimitKind, DenialLimitFallback as SdkDenialLimitFallback } from '@sema-agent/sdk';
|
|
10
10
|
export declare function isFsApprovalGate(gate: {
|
|
11
11
|
kind?: unknown;
|
|
12
12
|
toolName?: unknown;
|
|
@@ -137,7 +137,6 @@ export interface ApprovalCardRequest {
|
|
|
137
137
|
ruleOffersReadOnly?: RuleOffer[];
|
|
138
138
|
inputHasBidi?: true;
|
|
139
139
|
hasBidiControls?: true;
|
|
140
|
-
persistedRuleShadowed?: string;
|
|
141
140
|
allowRuleShadow?: ApprovalAllowRuleShadow;
|
|
142
141
|
probeCause?: unknown;
|
|
143
142
|
probeReason?: string;
|
|
@@ -177,6 +176,9 @@ export declare function hasApprovalCardPortFor(sessionKey: string): boolean;
|
|
|
177
176
|
export declare function approvalCardPortFor(sessionKey: string): ApprovalCardPort | null;
|
|
178
177
|
export declare function _resetApprovalCardPortForTest(): void;
|
|
179
178
|
export declare function surfaceApprovalCard(req: ApprovalCardRequest): Promise<ApprovalCardDecision>;
|
|
179
|
+
declare const REMEMBER_REFUSAL_CODES: readonly ["remember_not_in_proof", "remember_requires_binding", "capability.store_required", "decide.workflow_remember_unsupported", "decide.parked_remember_unsupported"];
|
|
180
|
+
export type RememberRefusalCode = (typeof REMEMBER_REFUSAL_CODES)[number];
|
|
181
|
+
export declare function rememberRefusalOf(error: unknown): RememberRefusalCode | undefined;
|
|
180
182
|
export declare function surfaceFsApprovalAndDecide(deps: FsApprovalWireDeps, taskId: string, argsByCall: Map<string, unknown>, signal?: AbortSignal, parkGatedCallId?: string): Promise<FsApprovalOutcome>;
|
|
181
183
|
export interface BoundSkillGrantsWire {
|
|
182
184
|
readonly skill: string | null;
|
|
@@ -192,6 +194,7 @@ export interface ToolApprovalFrame {
|
|
|
192
194
|
args?: unknown;
|
|
193
195
|
argsOmitted?: boolean;
|
|
194
196
|
outcome?: 'allowed' | 'denied' | 'expired';
|
|
197
|
+
cause?: ApprovalSettleCause;
|
|
195
198
|
sourceTaskId?: string;
|
|
196
199
|
fromSubagent?: true;
|
|
197
200
|
sourceAgentName?: string;
|
|
@@ -232,7 +235,7 @@ export interface ToolApprovalDelegation {
|
|
|
232
235
|
depth: number;
|
|
233
236
|
agentName?: string;
|
|
234
237
|
}
|
|
235
|
-
export declare const TOOL_APPROVAL_FRAME_KEYS_MIRROR: readonly ["type", "approvalId", "toolCallId", "toolName", "sourceTaskId", "fromSubagent", "sourceAgentName", "message", "args", "argsOmitted", "governanceForced", "ruleOffers", "ruleOffersAbsence", "denialLimitFallback", "readRootCandidate", "mandated", "mandate", "origin", "askClass", "classes", "inputHasBidi", "parked", "persistedRuleShadowed", "allowRuleShadowed", "probeCause", "probeReason", "rememberRefused", "boundGrantDigest", "boundGrants", "classifierNoRuling", "ruleEvidence", "requiresRealApproval", "expiresInMs", "expiresAtMs", "serverNowMs", "delegation", "outcome"];
|
|
238
|
+
export declare const TOOL_APPROVAL_FRAME_KEYS_MIRROR: readonly ["type", "approvalId", "toolCallId", "toolName", "sourceTaskId", "fromSubagent", "sourceAgentName", "message", "args", "argsOmitted", "governanceForced", "ruleOffers", "ruleOffersAbsence", "denialLimitFallback", "readRootCandidate", "mandated", "mandate", "origin", "askClass", "classes", "inputHasBidi", "parked", "persistedRuleShadowed", "allowRuleShadowed", "probeCause", "probeReason", "rememberRefused", "boundGrantDigest", "boundGrants", "classifierNoRuling", "ruleEvidence", "requiresRealApproval", "expiresInMs", "expiresAtMs", "serverNowMs", "delegation", "outcome", "cause"];
|
|
236
239
|
export interface ApprovalMandatedFacts {
|
|
237
240
|
readonly mandated?: true;
|
|
238
241
|
readonly ruleOffersAbsence?: string;
|
|
@@ -307,6 +310,7 @@ export type ToolApprovalRespondRefusal = (ToolApprovalRespondRefusalFields & {
|
|
|
307
310
|
export declare function readToolApprovalRespondRefusal(err: unknown): ToolApprovalRespondRefusal | undefined;
|
|
308
311
|
export declare function isToolApprovalFrame(ev: unknown): ev is ToolApprovalFrame;
|
|
309
312
|
export declare function askProbeReasonDetail(card: Pick<ApprovalCardRequest, 'probeReason' | 'probeCause'> | null | undefined): string | undefined;
|
|
313
|
+
export declare function readApprovalRememberRefused(v: unknown): boolean;
|
|
310
314
|
export declare function readApprovalBoundGrants(v: unknown): BoundSkillGrantsWire | undefined;
|
|
311
315
|
export declare function readApprovalClassifierNoRuling(v: unknown): string | undefined;
|
|
312
316
|
export declare function classifierNoRulingDetail(word: string | undefined): string;
|
|
@@ -323,4 +327,20 @@ export interface ToolApprovalFrameLaneOpts {
|
|
|
323
327
|
windowIsCurrent?: boolean;
|
|
324
328
|
argsUnavailable?: true;
|
|
325
329
|
}
|
|
326
|
-
export declare function surfaceToolApprovalFrameAndRespond(frame: ToolApprovalFrame, respond: RespondToolApprovalFn, streamArgs: unknown | undefined, signal?: AbortSignal, lane?: ToolApprovalFrameLaneOpts
|
|
330
|
+
export declare function surfaceToolApprovalFrameAndRespond(frame: ToolApprovalFrame, respond: RespondToolApprovalFn, streamArgs: unknown | undefined, signal?: AbortSignal, lane?: ToolApprovalFrameLaneOpts, run?: {
|
|
331
|
+
readonly taskId?: string;
|
|
332
|
+
readonly sessionId?: string;
|
|
333
|
+
}): Promise<ToolApprovalFrameOutcome>;
|
|
334
|
+
export interface ApprovalHolderIdentity {
|
|
335
|
+
readonly approvalId?: string;
|
|
336
|
+
readonly taskId?: string;
|
|
337
|
+
readonly toolCallId?: string;
|
|
338
|
+
readonly sessionId?: string;
|
|
339
|
+
}
|
|
340
|
+
export type ApprovalHolderJoin = {
|
|
341
|
+
readonly kind: 'joined';
|
|
342
|
+
readonly outcome: ToolApprovalFrameOutcome;
|
|
343
|
+
} | {
|
|
344
|
+
readonly kind: 'free';
|
|
345
|
+
};
|
|
346
|
+
export declare function joinApprovalHolder(identity: ApprovalHolderIdentity, signal?: AbortSignal): Promise<ApprovalHolderJoin>;
|