@sema-agent/client-core 0.93.1 → 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 +554 -0
- package/README.md +89 -55
- package/dist/adapt/arms.js +13 -11
- 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 +13 -6
- 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 +5 -3
- package/dist/agentsWireCaps.d.ts +17 -0
- package/dist/agentsWireCaps.js +111 -1
- package/dist/approvalDecidedByCapability.d.ts +0 -1
- package/dist/approvalDecidedByCapability.js +2 -7
- package/dist/approvalReachWire.d.ts +18 -0
- package/dist/approvalReachWire.js +58 -0
- package/dist/approvalsStreamLiveCapability.d.ts +0 -1
- package/dist/approvalsStreamLiveCapability.js +15 -14
- 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 +15 -0
- package/dist/callerCwdCapability.js +42 -0
- 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/controlRouter.js +3 -10
- package/dist/coreValuePorts.d.ts +64 -1
- package/dist/coreValuePorts.js +30 -0
- 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/detachWire.d.ts +1 -4
- package/dist/detachWire.js +1 -1
- package/dist/deviceExecutorManagementCapability.d.ts +0 -1
- package/dist/deviceExecutorManagementCapability.js +36 -40
- package/dist/deviceFlowPolling.d.ts +5 -0
- package/dist/deviceFlowPolling.js +28 -0
- package/dist/deviceRebind.d.ts +88 -0
- package/dist/deviceRebind.js +242 -0
- package/dist/displayUntrusted.d.ts +1 -0
- package/dist/displayUntrusted.js +963 -30
- 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 +19 -4
- package/dist/engineErrorCodes.js +39 -21
- package/dist/engineIdentity.js +2 -0
- package/dist/engineNoticeCodes.d.ts +22 -2
- package/dist/engineNoticeCodes.js +73 -6
- package/dist/engineRefusedToolName.d.ts +1 -0
- package/dist/engineRefusedToolName.js +8 -0
- package/dist/engineWireSdk.js +2 -2
- package/dist/executionLaneCapability.d.ts +2 -3
- package/dist/executionLaneCapability.js +28 -28
- package/dist/fileHistoryCaptureCapability.d.ts +0 -1
- package/dist/fileHistoryCaptureCapability.js +13 -12
- package/dist/fileHistoryLegNotice.d.ts +14 -2
- package/dist/fileHistoryLegNotice.js +101 -15
- package/dist/fleet/fleetLedger.d.ts +2 -0
- package/dist/fleet/fleetLedger.js +74 -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.d.ts +2 -1
- package/dist/gateOutcome.js +33 -18
- package/dist/gateVocabulary.js +1 -1
- package/dist/generated/engineAskFaceTables.d.ts +3 -0
- package/dist/generated/engineAskFaceTables.js +12 -0
- package/dist/generated/engineFactTables.d.ts +4 -2
- package/dist/generated/engineFactTables.js +13 -0
- package/dist/generated/engineNoticeTables.d.ts +5 -0
- package/dist/generated/engineNoticeTables.js +7 -0
- package/dist/generated/sdkFactTables.d.ts +5 -0
- package/dist/generated/sdkFactTables.js +34 -0
- package/dist/generated/settingsSchemaFns.d.ts +10 -0
- package/dist/generated/settingsSchemaFns.js +22 -0
- package/dist/generated/settingsSchemaTables.d.ts +3 -0
- package/dist/generated/settingsSchemaTables.js +3 -0
- package/dist/headlessPermissionModeWire.d.ts +2 -2
- package/dist/headlessPermissionModeWire.js +11 -21
- 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 +46 -0
- package/dist/hitl/approvalHolds.js +140 -0
- package/dist/hitl/approvalOutcomeNote.js +2 -1
- package/dist/hitl/approvalResolution.js +9 -1
- package/dist/hitl/approvalsFeed.js +23 -6
- package/dist/hitl/askGateWire.d.ts +2 -1
- package/dist/hitl/askGateWire.js +29 -1
- package/dist/hitl/automaticAnswerVerdict.d.ts +8 -2
- package/dist/hitl/automaticAnswerVerdict.js +71 -23
- 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 +23 -0
- package/dist/hitl/decisionRefusal.js +88 -0
- package/dist/hitl/frameRouter.d.ts +10 -0
- package/dist/hitl/frameRouter.js +71 -32
- package/dist/hitl/gateLedger.d.ts +8 -0
- package/dist/hitl/gateLedger.js +38 -0
- package/dist/hitl/hitlBridge.d.ts +14 -3
- package/dist/hitl/hitlBridge.js +75 -62
- package/dist/hitl/hitlHostSurface.d.ts +3 -0
- package/dist/hitl/hitlHostSurface.js +17 -15
- package/dist/hitl/livePendingAsk.d.ts +16 -6
- package/dist/hitl/livePendingAsk.js +36 -4
- package/dist/hitl/localAllowRule.js +2 -1
- package/dist/hitl/noAllowCause.d.ts +9 -0
- package/dist/hitl/noAllowCause.js +26 -0
- 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 +55 -28
- package/dist/hitl/parkRowBirthWait.js +2 -1
- package/dist/hitl/persistedRulesWire.d.ts +6 -1
- package/dist/hitl/persistedRulesWire.js +16 -4
- package/dist/hitl/planReviewWire.d.ts +2 -3
- package/dist/hitl/planReviewWire.js +86 -39
- 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/sessionPolicyDeliverable.d.ts +1 -1
- package/dist/hitl/sessionPolicyDeliverable.js +3 -8
- package/dist/hitl/sessionPolicyWire.js +1 -1
- package/dist/hitl/toolApprovalWire.d.ts +50 -5
- package/dist/hitl/toolApprovalWire.js +368 -56
- 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/humanTurnRead.d.ts +15 -1
- package/dist/humanTurnRead.js +28 -2
- package/dist/index.d.ts +45 -14
- package/dist/index.js +33 -12
- package/dist/interactiveInterrupt.d.ts +8 -0
- package/dist/interactiveInterrupt.js +54 -0
- package/dist/limitsWire.d.ts +5 -1
- package/dist/limitsWire.js +51 -13
- package/dist/liveModelCatalog.d.ts +109 -0
- package/dist/liveModelCatalog.js +344 -18
- 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 +13 -12
- package/dist/mcpReconnect.d.ts +1 -3
- package/dist/mcpReconnect.js +20 -10
- package/dist/memoryComplianceCapability.d.ts +0 -1
- package/dist/memoryComplianceCapability.js +14 -13
- package/dist/memoryOriginCapability.d.ts +0 -1
- package/dist/memoryOriginCapability.js +14 -13
- 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 +4 -2
- package/dist/modelIdentityResolvability.js +25 -5
- package/dist/modelSwitchFallback.d.ts +69 -0
- package/dist/modelSwitchFallback.js +206 -0
- package/dist/notifications.js +12 -11
- package/dist/outputStyleSeatCapability.d.ts +15 -0
- package/dist/outputStyleSeatCapability.js +42 -0
- package/dist/ownKey.d.ts +7 -0
- package/dist/ownKey.js +58 -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 +15 -14
- package/dist/permissionModesCapability.d.ts +0 -1
- package/dist/permissionModesCapability.js +5 -10
- package/dist/permissionRuleIssue.js +1 -1
- package/dist/permissionRulesWriteCapability.d.ts +0 -1
- package/dist/permissionRulesWriteCapability.js +15 -14
- package/dist/permissionsAllowGrantCapability.d.ts +2 -1
- package/dist/permissionsAllowGrantCapability.js +35 -19
- package/dist/permissionsDeclaration.d.ts +16 -1
- package/dist/permissionsDeclaration.js +142 -15
- package/dist/printToolResultFrame.js +2 -10
- package/dist/promptDelivery.js +0 -8
- package/dist/protocolSegment.d.ts +1 -0
- package/dist/protocolSegment.js +13 -1
- package/dist/request/taskRequest.d.ts +11 -3
- package/dist/request/taskRequest.js +13 -1
- package/dist/resultFrameKeys.d.ts +4 -0
- package/dist/resultFrameKeys.js +13 -0
- package/dist/resumeRefusalCopy.d.ts +18 -1
- package/dist/resumeRefusalCopy.js +132 -31
- package/dist/retryStatus.js +6 -4
- package/dist/rewindArchiveCapability.d.ts +2 -1
- package/dist/rewindArchiveCapability.js +28 -15
- 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/{hitl/rosterMountedNames.d.ts → rosterMountedNames.d.ts} +1 -1
- package/dist/runCancelContext.js +2 -1
- 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 +19 -20
- package/dist/seatContract.d.ts +85 -28
- package/dist/seatContract.js +512 -148
- 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 +14 -13
- package/dist/sessionReadRedactionCapability.d.ts +15 -0
- package/dist/sessionReadRedactionCapability.js +42 -0
- package/dist/sessionSyncFileHistoryCapability.d.ts +0 -1
- package/dist/sessionSyncFileHistoryCapability.js +13 -12
- package/dist/skillToolListsCapability.d.ts +0 -1
- package/dist/skillToolListsCapability.js +13 -12
- package/dist/skillsWireCaps.d.ts +4 -0
- package/dist/skillsWireCaps.js +66 -1
- package/dist/sqlEngineCapability.d.ts +0 -1
- package/dist/sqlEngineCapability.js +21 -21
- package/dist/steerPriorityCapability.d.ts +0 -1
- package/dist/steerPriorityCapability.js +18 -19
- 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/agentStateDetail.d.ts +1 -0
- package/dist/subagent/agentStateDetail.js +41 -0
- package/dist/subagent/engineCompactWire.d.ts +15 -0
- package/dist/subagent/engineCompactWire.js +82 -45
- 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/taskRequestWords.d.ts +2 -4
- package/dist/taskRequestWords.js +3 -2
- 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/userAttachmentEnvelope.d.ts +22 -1
- package/dist/userAttachmentEnvelope.js +90 -2
- package/dist/userInvokedSkillsCapability.d.ts +0 -1
- package/dist/userInvokedSkillsCapability.js +13 -12
- package/dist/webSearchBackendCapability.d.ts +0 -1
- package/dist/webSearchBackendCapability.js +20 -19
- package/dist/webSearchWireCaps.js +3 -11
- package/dist/wireErrorTriage.d.ts +11 -0
- package/dist/wireErrorTriage.js +35 -0
- package/dist/wireFailureShape.d.ts +10 -0
- package/dist/wireFailureShape.js +72 -5
- package/dist/wireRefusalCopy.d.ts +6 -1
- package/dist/wireRefusalCopy.js +23 -25
- package/dist/wiringInstructionsAttribution.d.ts +10 -0
- package/dist/wiringInstructionsAttribution.js +67 -0
- package/dist/workflowClient.js +19 -2
- package/dist/workflowsJournalCapability.d.ts +0 -1
- package/dist/workflowsJournalCapability.js +13 -12
- package/dist/writeProtectionCapability.d.ts +0 -1
- package/dist/writeProtectionCapability.js +26 -26
- package/docs/INTEGRATION-CLIENTS.md +1733 -52
- package/package.json +5 -5
- package/dist/askSurvivesStandingAnswer.d.ts +0 -13
- package/dist/askSurvivesStandingAnswer.js +0 -53
- package/dist/engineCapsGenerationGuard.d.ts +0 -4
- package/dist/engineCapsGenerationGuard.js +0 -19
- package/dist/hitl/askSurvivesPosture.d.ts +0 -20
- package/dist/hitl/askSurvivesPosture.js +0 -48
- 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
- /package/dist/{hitl/rosterMountedNames.js → rosterMountedNames.js} +0 -0
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
function ownData(o, key) {
|
|
2
|
+
const d = Object.getOwnPropertyDescriptor(o, key);
|
|
3
|
+
return d !== undefined && 'value' in d ? d.value : undefined;
|
|
4
|
+
}
|
|
5
|
+
export function approvalCompleteParked(frame) {
|
|
6
|
+
try {
|
|
7
|
+
if (frame === null || typeof frame !== 'object')
|
|
8
|
+
return false;
|
|
9
|
+
return ownData(frame, 'outcome') === 'expired' && ownData(frame, 'parked') === true;
|
|
10
|
+
}
|
|
11
|
+
catch {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ApprovalSettleCause, AskRowEndingCause } from '@sema-agent/sdk';
|
|
2
|
+
export declare const ASK_ROW_ENDING_CAUSE_WORDS: readonly ["routing_failure_fail_closed", "run_cancelled", "run_exited", "batch_aborted", "batch_sibling_withdrawn", "batch_bound_elsewhere", "adhoc_leg_no_durable_domain", "orphan_ttl_exceeded", "crashed_before_park", "shutdown_before_park"];
|
|
3
|
+
export declare function askRowEndingCauseFor(state: 'VOID' | 'DENIED' | undefined, word: unknown): AskRowEndingCause | undefined;
|
|
4
|
+
export declare function approvalCompleteCauseOf(frame: unknown): ApprovalSettleCause | undefined;
|
|
5
|
+
export declare function notPendingCauseSaysEnded(err: object): boolean;
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
import { ASK_GONE_DENIED_WORD } from '../engineErrorCodes.js';
|
|
2
|
+
import { SDK_ASK_ROW_ENDING_CAUSES } from '../generated/sdkFactTables.js';
|
|
3
|
+
export const ASK_ROW_ENDING_CAUSE_WORDS = SDK_ASK_ROW_ENDING_CAUSES;
|
|
4
|
+
const _askRowCausePin = true;
|
|
5
|
+
void _askRowCausePin;
|
|
6
|
+
const DENIED_GROUP_WORD = ASK_GONE_DENIED_WORD;
|
|
7
|
+
const WAIT_CLASS_SETTLE_CAUSE_WORDS = Object.freeze({
|
|
8
|
+
ttl_expired: true,
|
|
9
|
+
broadcast_lost: true,
|
|
10
|
+
stream_disconnected: true,
|
|
11
|
+
undeliverable: true,
|
|
12
|
+
});
|
|
13
|
+
function isAskRowEndingCause(v) {
|
|
14
|
+
return typeof v === 'string' && ASK_ROW_ENDING_CAUSE_WORDS.includes(v);
|
|
15
|
+
}
|
|
16
|
+
function isApprovalSettleCause(v) {
|
|
17
|
+
return isAskRowEndingCause(v) || (typeof v === 'string' && Object.hasOwn(WAIT_CLASS_SETTLE_CAUSE_WORDS, v));
|
|
18
|
+
}
|
|
19
|
+
export function askRowEndingCauseFor(state, word) {
|
|
20
|
+
if (!isAskRowEndingCause(word))
|
|
21
|
+
return undefined;
|
|
22
|
+
if (state === 'DENIED')
|
|
23
|
+
return word === DENIED_GROUP_WORD ? word : undefined;
|
|
24
|
+
if (state === 'VOID')
|
|
25
|
+
return word !== DENIED_GROUP_WORD ? word : undefined;
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
export function approvalCompleteCauseOf(frame) {
|
|
29
|
+
try {
|
|
30
|
+
if (typeof frame !== 'object' || frame === null)
|
|
31
|
+
return undefined;
|
|
32
|
+
const typeSlot = Object.getOwnPropertyDescriptor(frame, 'type');
|
|
33
|
+
if (typeSlot === undefined || !Object.hasOwn(typeSlot, 'value') || typeSlot.value !== 'tool_approval_complete')
|
|
34
|
+
return undefined;
|
|
35
|
+
const causeSlot = Object.getOwnPropertyDescriptor(frame, 'cause');
|
|
36
|
+
if (causeSlot === undefined || !Object.hasOwn(causeSlot, 'value'))
|
|
37
|
+
return undefined;
|
|
38
|
+
const word = causeSlot.value;
|
|
39
|
+
return isApprovalSettleCause(word) ? word : undefined;
|
|
40
|
+
}
|
|
41
|
+
catch {
|
|
42
|
+
return undefined;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
const LEGACY_NOT_PENDING_ENDED_WORDS = new Set(['voided', 'denied']);
|
|
46
|
+
export function notPendingCauseSaysEnded(err) {
|
|
47
|
+
try {
|
|
48
|
+
const extraSlot = Object.getOwnPropertyDescriptor(err, 'extra');
|
|
49
|
+
const extra = extraSlot !== undefined && Object.hasOwn(extraSlot, 'value') ? extraSlot.value : undefined;
|
|
50
|
+
if (typeof extra !== 'object' || extra === null || Array.isArray(extra))
|
|
51
|
+
return false;
|
|
52
|
+
const causeSlot = Object.getOwnPropertyDescriptor(extra, 'cause');
|
|
53
|
+
if (causeSlot === undefined || !Object.hasOwn(causeSlot, 'value'))
|
|
54
|
+
return false;
|
|
55
|
+
const word = causeSlot.value;
|
|
56
|
+
return isAskRowEndingCause(word) || (typeof word === 'string' && LEGACY_NOT_PENDING_ENDED_WORDS.has(word));
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
return false;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
import type { ApprovalHolderIdentity, FsApprovalOutcome, ToolApprovalFrameOutcome } from './toolApprovalWire.js';
|
|
2
|
+
export interface DurableDecisionHold {
|
|
3
|
+
readonly lane: 'durable';
|
|
4
|
+
readonly outcome: Promise<FsApprovalOutcome>;
|
|
5
|
+
presented: boolean;
|
|
6
|
+
readonly interrupt: () => void;
|
|
7
|
+
readonly cardSignal: AbortSignal;
|
|
8
|
+
trailing?: Promise<unknown>;
|
|
9
|
+
}
|
|
10
|
+
export interface LiveCardHold {
|
|
11
|
+
readonly lane: 'live';
|
|
12
|
+
readonly identity: LiveCardIdentity;
|
|
13
|
+
readonly outcome: Promise<ToolApprovalFrameOutcome>;
|
|
14
|
+
phase: 'card' | 'respond';
|
|
15
|
+
superseded?: {
|
|
16
|
+
readonly parked: boolean;
|
|
17
|
+
};
|
|
18
|
+
readonly cardSignal: AbortSignal;
|
|
19
|
+
readonly interrupt: () => void;
|
|
20
|
+
trailing?: Promise<void>;
|
|
21
|
+
}
|
|
22
|
+
export type ApprovalHold = DurableDecisionHold | LiveCardHold;
|
|
23
|
+
export interface LiveCardIdentity {
|
|
24
|
+
readonly approvalId: string;
|
|
25
|
+
readonly toolCallId?: string;
|
|
26
|
+
readonly taskId?: string;
|
|
27
|
+
readonly sessionId?: string;
|
|
28
|
+
}
|
|
29
|
+
export declare function liveCardHoldFor(who: ApprovalHolderIdentity): LiveCardHold | undefined;
|
|
30
|
+
export declare function liveCardAnsweredHow(o: ToolApprovalFrameOutcome): 'answered' | 'interrupted' | undefined;
|
|
31
|
+
export declare function awaitLiveCardHolder(hold: LiveCardHold, signal: AbortSignal | undefined): Promise<ToolApprovalFrameOutcome | undefined>;
|
|
32
|
+
export interface ApprovalDecisionHoldTable {
|
|
33
|
+
readonly inFlight: Map<string, ApprovalHold>;
|
|
34
|
+
readonly settled: Map<string, DurableSettledHold>;
|
|
35
|
+
readonly openReads: Set<number>;
|
|
36
|
+
clock: number;
|
|
37
|
+
}
|
|
38
|
+
export interface DurableSettledHold {
|
|
39
|
+
readonly at: number;
|
|
40
|
+
readonly hold: DurableDecisionHold;
|
|
41
|
+
}
|
|
42
|
+
export declare const approvalDecisionHolds: ApprovalDecisionHoldTable;
|
|
43
|
+
export declare function liveCardHoldOf(key: string): LiveCardHold | undefined;
|
|
44
|
+
export declare function holdLiveCard(identity: LiveCardIdentity, callerSignal: AbortSignal | undefined, present: (hold: LiveCardHold) => Promise<ToolApprovalFrameOutcome>): Promise<ToolApprovalFrameOutcome>;
|
|
45
|
+
export declare function joinLiveCard(hold: LiveCardHold, signal: AbortSignal | undefined): Promise<ToolApprovalFrameOutcome>;
|
|
46
|
+
export declare function supersedeLiveCard(key: string, parked: boolean): boolean;
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import { hostLog } from '../host.js';
|
|
2
|
+
import { liveFrameCallKey } from './gateIdentity.js';
|
|
3
|
+
import { approvalResolutionOf } from './approvalResolution.js';
|
|
4
|
+
const nonEmpty = (v) => typeof v === 'string' && v !== '';
|
|
5
|
+
export function liveCardHoldFor(who) {
|
|
6
|
+
if (nonEmpty(who.approvalId))
|
|
7
|
+
return liveCardHoldOf(liveFrameCallKey(who.approvalId));
|
|
8
|
+
if (!nonEmpty(who.taskId) || !nonEmpty(who.toolCallId))
|
|
9
|
+
return undefined;
|
|
10
|
+
for (const h of approvalDecisionHolds.inFlight.values()) {
|
|
11
|
+
if (h.lane !== 'live' || h.phase !== 'card')
|
|
12
|
+
continue;
|
|
13
|
+
const id = h.identity;
|
|
14
|
+
if (id.taskId !== who.taskId || id.toolCallId !== who.toolCallId)
|
|
15
|
+
continue;
|
|
16
|
+
if (nonEmpty(who.sessionId) && nonEmpty(id.sessionId) && id.sessionId !== who.sessionId)
|
|
17
|
+
continue;
|
|
18
|
+
return h;
|
|
19
|
+
}
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
function liveCardSettledQuestion(hold, o) {
|
|
23
|
+
const r = approvalResolutionOf(o);
|
|
24
|
+
if (answeredHowOf(r) !== undefined)
|
|
25
|
+
return true;
|
|
26
|
+
if (r.kind === 'unsettled')
|
|
27
|
+
return false;
|
|
28
|
+
return hold.superseded !== undefined && !hold.superseded.parked;
|
|
29
|
+
}
|
|
30
|
+
export function liveCardAnsweredHow(o) {
|
|
31
|
+
return answeredHowOf(approvalResolutionOf(o));
|
|
32
|
+
}
|
|
33
|
+
function answeredHowOf(r) {
|
|
34
|
+
if (r.kind === 'decided')
|
|
35
|
+
return 'answered';
|
|
36
|
+
return r.kind === 'unsettled' && r.cause === 'interrupted' ? 'interrupted' : undefined;
|
|
37
|
+
}
|
|
38
|
+
export async function awaitLiveCardHolder(hold, signal) {
|
|
39
|
+
const unsubscribe = followCallerSignal(signal, hold.interrupt);
|
|
40
|
+
let o;
|
|
41
|
+
try {
|
|
42
|
+
o = await hold.outcome;
|
|
43
|
+
}
|
|
44
|
+
catch {
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
finally {
|
|
48
|
+
unsubscribe();
|
|
49
|
+
}
|
|
50
|
+
return liveCardSettledQuestion(hold, o) ? { ...o, joinedInFlight: true } : undefined;
|
|
51
|
+
}
|
|
52
|
+
export const approvalDecisionHolds = { inFlight: new Map(), settled: new Map(), openReads: new Set(), clock: 0 };
|
|
53
|
+
export function liveCardHoldOf(key) {
|
|
54
|
+
const h = approvalDecisionHolds.inFlight.get(key);
|
|
55
|
+
return h !== undefined && h.lane === 'live' ? h : undefined;
|
|
56
|
+
}
|
|
57
|
+
export function holdLiveCard(identity, callerSignal, present) {
|
|
58
|
+
const key = liveFrameCallKey(identity.approvalId);
|
|
59
|
+
const h = approvalDecisionHolds;
|
|
60
|
+
const cut = new AbortController();
|
|
61
|
+
let settled = false;
|
|
62
|
+
const interrupt = () => {
|
|
63
|
+
if (!settled && !cut.signal.aborted)
|
|
64
|
+
cut.abort();
|
|
65
|
+
};
|
|
66
|
+
const unsubscribe = followCallerSignal(callerSignal, interrupt);
|
|
67
|
+
let resolveOutcome = () => { };
|
|
68
|
+
let rejectOutcome = () => { };
|
|
69
|
+
const outcome = new Promise((resolve, reject) => {
|
|
70
|
+
resolveOutcome = resolve;
|
|
71
|
+
rejectOutcome = reject;
|
|
72
|
+
});
|
|
73
|
+
const hold = { lane: 'live', identity: Object.freeze({ ...identity }), outcome, phase: 'card', cardSignal: cut.signal, interrupt };
|
|
74
|
+
h.inFlight.set(key, hold);
|
|
75
|
+
const release = () => {
|
|
76
|
+
if (h.inFlight.get(key) === hold)
|
|
77
|
+
h.inFlight.delete(key);
|
|
78
|
+
};
|
|
79
|
+
const settle = (give) => {
|
|
80
|
+
settled = true;
|
|
81
|
+
unsubscribe();
|
|
82
|
+
const trailing = hold.trailing;
|
|
83
|
+
if (trailing === undefined) {
|
|
84
|
+
release();
|
|
85
|
+
give();
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
give();
|
|
89
|
+
trailing.then(release, release);
|
|
90
|
+
};
|
|
91
|
+
let run;
|
|
92
|
+
try {
|
|
93
|
+
run = present(hold);
|
|
94
|
+
}
|
|
95
|
+
catch (e) {
|
|
96
|
+
run = Promise.reject(e);
|
|
97
|
+
}
|
|
98
|
+
run.then((o) => settle(() => resolveOutcome(o)), (e) => settle(() => rejectOutcome(e)));
|
|
99
|
+
return outcome;
|
|
100
|
+
}
|
|
101
|
+
export async function joinLiveCard(hold, signal) {
|
|
102
|
+
const unsubscribe = followCallerSignal(signal, hold.interrupt);
|
|
103
|
+
try {
|
|
104
|
+
const o = await hold.outcome;
|
|
105
|
+
return { ...o, joinedInFlight: true };
|
|
106
|
+
}
|
|
107
|
+
finally {
|
|
108
|
+
unsubscribe();
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
function followCallerSignal(signal, onAbort) {
|
|
112
|
+
if (signal === undefined || signal === null)
|
|
113
|
+
return () => { };
|
|
114
|
+
try {
|
|
115
|
+
if (signal.aborted === true) {
|
|
116
|
+
onAbort();
|
|
117
|
+
return () => { };
|
|
118
|
+
}
|
|
119
|
+
signal.addEventListener('abort', onAbort, { once: true });
|
|
120
|
+
}
|
|
121
|
+
catch {
|
|
122
|
+
return () => { };
|
|
123
|
+
}
|
|
124
|
+
return () => {
|
|
125
|
+
try {
|
|
126
|
+
signal.removeEventListener('abort', onAbort);
|
|
127
|
+
}
|
|
128
|
+
catch (e) {
|
|
129
|
+
hostLog('debug', `approvalHolds: could not detach from the caller's abort signal (${String(e).slice(0, 120)}) — the listener is one-shot and inert after settle`);
|
|
130
|
+
}
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
export function supersedeLiveCard(key, parked) {
|
|
134
|
+
const hold = liveCardHoldOf(key);
|
|
135
|
+
if (hold === undefined || hold.phase !== 'card' || hold.superseded !== undefined)
|
|
136
|
+
return false;
|
|
137
|
+
hold.superseded = Object.freeze({ parked });
|
|
138
|
+
hold.interrupt();
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
@@ -17,7 +17,8 @@ function detailOf(r) {
|
|
|
17
17
|
}
|
|
18
18
|
export function approvalOutcomeNoteOf(frame, outcome) {
|
|
19
19
|
const r = approvalResolutionOf(outcome);
|
|
20
|
-
const
|
|
20
|
+
const cause = approvalNotSentCause(r);
|
|
21
|
+
const retracted = cause === 'retracted';
|
|
21
22
|
const detail = detailOf(r);
|
|
22
23
|
return {
|
|
23
24
|
approvalId: frame.approvalId,
|
|
@@ -106,13 +106,21 @@ function parkingViewOf(v) {
|
|
|
106
106
|
const hint = pick(v, 'retryAfterMs');
|
|
107
107
|
const retryAfterMs = typeof hint === 'number' && Number.isFinite(hint) && hint >= 0 ? hint : undefined;
|
|
108
108
|
const decidePath = str(pick(v, 'decidePath'));
|
|
109
|
-
|
|
109
|
+
const message = str(pick(v, 'message'));
|
|
110
|
+
return {
|
|
111
|
+
approvalId,
|
|
112
|
+
...(retryAfterMs !== undefined ? { retryAfterMs } : {}),
|
|
113
|
+
...(decidePath !== undefined ? { decidePath } : {}),
|
|
114
|
+
...(message !== undefined ? { message } : {}),
|
|
115
|
+
};
|
|
110
116
|
}
|
|
111
117
|
function frameLegResolution(outcome) {
|
|
112
118
|
if (pick(outcome, 'retracted') === true)
|
|
113
119
|
return { kind: 'not_sent', cause: 'retracted' };
|
|
114
120
|
if (pick(outcome, 'editRefused') === true)
|
|
115
121
|
return { kind: 'not_sent', cause: 'edit_refused' };
|
|
122
|
+
if (pick(outcome, 'aborted') === true)
|
|
123
|
+
return { kind: 'unsettled', cause: 'interrupted' };
|
|
116
124
|
const parking = parkingViewOf(pick(outcome, 'parking'));
|
|
117
125
|
if (parking !== undefined)
|
|
118
126
|
return { kind: 'unsettled', cause: 'parking_in_progress', parking };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { hostLog } from '../host.js';
|
|
2
2
|
import { unrefTimer } from '../unrefTimer.js';
|
|
3
3
|
import { readLivePendingRows } from './livePendingAsk.js';
|
|
4
|
+
import { createStreamDrainingLegs } from '../streamDrainingLegs.js';
|
|
4
5
|
const MAX_CONSECUTIVE_POLL_ESCAPES = 5;
|
|
5
6
|
function readDurablePendingRows(raw) {
|
|
6
7
|
if (!Array.isArray(raw))
|
|
@@ -364,7 +365,7 @@ export function startApprovalsFeed(client, onSnapshot, opts) {
|
|
|
364
365
|
.then(() => scheduleReconcile());
|
|
365
366
|
}, reconcileDelayMs));
|
|
366
367
|
}
|
|
367
|
-
function scheduleStreamRetry() {
|
|
368
|
+
function scheduleStreamRetry(afterMs = streamRetryMs) {
|
|
368
369
|
if (stopped || ac.signal.aborted || streamRetryMs <= 0)
|
|
369
370
|
return;
|
|
370
371
|
if (!client.approvals.stream)
|
|
@@ -377,9 +378,9 @@ export function startApprovalsFeed(client, onSnapshot, opts) {
|
|
|
377
378
|
return;
|
|
378
379
|
hostLog('debug', 'approvalsFeed: retrying push leg (降级是暂时的,服务端升级后不该还要重启客户端)');
|
|
379
380
|
void runStream();
|
|
380
|
-
},
|
|
381
|
+
}, afterMs));
|
|
381
382
|
}
|
|
382
|
-
function degradeToPoll(why, real = true) {
|
|
383
|
+
function degradeToPoll(why, real = true, retryAfterMs) {
|
|
383
384
|
if (stopped)
|
|
384
385
|
return;
|
|
385
386
|
if (real)
|
|
@@ -389,8 +390,9 @@ export function startApprovalsFeed(client, onSnapshot, opts) {
|
|
|
389
390
|
}
|
|
390
391
|
mode = 'poll';
|
|
391
392
|
schedulePoll();
|
|
392
|
-
scheduleStreamRetry();
|
|
393
|
+
scheduleStreamRetry(retryAfterMs);
|
|
393
394
|
}
|
|
395
|
+
const drains = createStreamDrainingLegs();
|
|
394
396
|
async function runStream() {
|
|
395
397
|
const stream = client.approvals.stream;
|
|
396
398
|
if (!stream) {
|
|
@@ -401,6 +403,10 @@ export function startApprovalsFeed(client, onSnapshot, opts) {
|
|
|
401
403
|
for await (const ev of stream.call(client.approvals, { signal: ac.signal })) {
|
|
402
404
|
if (stopped || ac.signal.aborted)
|
|
403
405
|
return;
|
|
406
|
+
if (drains.see(ev)) {
|
|
407
|
+
hostLog('debug', 'approvalsFeed: push leg received the drain end frame — the engine is going down; this leg ends with it and reopens on the draining ladder');
|
|
408
|
+
continue;
|
|
409
|
+
}
|
|
404
410
|
if (mode !== 'push') {
|
|
405
411
|
mode = 'push';
|
|
406
412
|
if (pollTimer !== undefined) {
|
|
@@ -418,10 +424,21 @@ export function startApprovalsFeed(client, onSnapshot, opts) {
|
|
|
418
424
|
stats.pushEvents++;
|
|
419
425
|
await take('push');
|
|
420
426
|
}
|
|
421
|
-
if (
|
|
422
|
-
|
|
427
|
+
if (stopped || ac.signal.aborted)
|
|
428
|
+
return;
|
|
429
|
+
const drained = drains.legEnded('returned');
|
|
430
|
+
if (drained !== undefined) {
|
|
431
|
+
const decision = drained;
|
|
432
|
+
if ('reconnectAfterMs' in decision)
|
|
433
|
+
degradeToPoll(`engine draining — push leg closed; reopening in ${decision.reconnectAfterMs}ms`, false, decision.reconnectAfterMs);
|
|
434
|
+
else
|
|
435
|
+
degradeToPoll(`engine draining — reconnect attempts exhausted (${decision.giveUp})`);
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
degradeToPoll('stream ended without progress');
|
|
423
439
|
}
|
|
424
440
|
catch (e) {
|
|
441
|
+
drains.legEnded('threw');
|
|
425
442
|
if (stopped || ac.signal.aborted)
|
|
426
443
|
return;
|
|
427
444
|
degradeToPoll(String(e));
|
|
@@ -8,9 +8,10 @@ export type { AskAnsweredOutput } from './gateLedger.js';
|
|
|
8
8
|
export { SEMA_COLLATERAL_ABORT_KEY } from './gateLedger.js';
|
|
9
9
|
export { SEMA_DENIAL_KIND_KEY } from './gateLedger.js';
|
|
10
10
|
export type { GateDenyAttribution } from './gateLedger.js';
|
|
11
|
-
export { toAnsweredOutput, isAlreadyResolvedFailure, isAlreadyResolvedGateReason, isGateStandingErrorCode, isCodeClassifiedGateFailure,
|
|
11
|
+
export { toAnsweredOutput, isAlreadyResolvedFailure, isAlreadyResolvedGateReason, isGateStandingErrorCode, isCodeClassifiedGateFailure, nextHopBudget, MAX_GATE_HOPS, MAX_TOTAL_PARKS } from './parkResolver.js';
|
|
12
12
|
export type { HopBudget, HopRound } from './parkResolver.js';
|
|
13
13
|
export type { GateOutcome, GateFailureCode } from './parkResolver.js';
|
|
14
|
+
export { GATE_FAILURE_CODES } from './hitlBridge.js';
|
|
14
15
|
export declare function bridgeAskUserQuestionGates(source: AsyncGenerator<AgentEvent>, deps: AskGateWireDeps, opts?: {
|
|
15
16
|
signal?: AbortSignal;
|
|
16
17
|
taskId?: string;
|
package/dist/hitl/askGateWire.js
CHANGED
|
@@ -1,12 +1,16 @@
|
|
|
1
1
|
import { createGateLedger } from './gateLedger.js';
|
|
2
2
|
import { flushHeldWithInterruptRewrite, isHostProgressFrame, routeFrame, } from './frameRouter.js';
|
|
3
3
|
import { resolvePark, nextHopBudget, stalledTerminal, MAX_GATE_HOPS } from './parkResolver.js';
|
|
4
|
+
import { createStreamDrainingLegs } from '../streamDrainingLegs.js';
|
|
5
|
+
import { abortableSleep } from '../abortableSleep.js';
|
|
6
|
+
import { hostLog } from '../host.js';
|
|
4
7
|
export { HITL_REJECT_MESSAGE, ENGINE_ABORT_TOOL_RESULT } from './frameRouter.js';
|
|
5
8
|
export { HITL_INTERRUPT_MESSAGE_FOR_TOOL_USE } from './frameRouter.js';
|
|
6
9
|
export { HITL_POLICY_DENY_MESSAGE } from './frameRouter.js';
|
|
7
10
|
export { SEMA_COLLATERAL_ABORT_KEY } from './gateLedger.js';
|
|
8
11
|
export { SEMA_DENIAL_KIND_KEY } from './gateLedger.js';
|
|
9
|
-
export { toAnsweredOutput, isAlreadyResolvedFailure, isAlreadyResolvedGateReason, isGateStandingErrorCode, isCodeClassifiedGateFailure,
|
|
12
|
+
export { toAnsweredOutput, isAlreadyResolvedFailure, isAlreadyResolvedGateReason, isGateStandingErrorCode, isCodeClassifiedGateFailure, nextHopBudget, MAX_GATE_HOPS, MAX_TOTAL_PARKS } from './parkResolver.js';
|
|
13
|
+
export { GATE_FAILURE_CODES } from './hitlBridge.js';
|
|
10
14
|
export async function* bridgeAskUserQuestionGates(source, deps, opts) {
|
|
11
15
|
const led = createGateLedger();
|
|
12
16
|
const taskId = { current: opts?.taskId };
|
|
@@ -24,9 +28,15 @@ export async function* bridgeAskUserQuestionGates(source, deps, opts) {
|
|
|
24
28
|
let lastResolvedGatedCallId;
|
|
25
29
|
let lastRoundDecided = false;
|
|
26
30
|
let unverifiableParks = 0;
|
|
31
|
+
const drains = createStreamDrainingLegs();
|
|
27
32
|
while (true) {
|
|
28
33
|
let park = null;
|
|
29
34
|
for await (const ev of stream) {
|
|
35
|
+
if (drains.see(ev))
|
|
36
|
+
continue;
|
|
37
|
+
const answering = led.answeringLiveCards();
|
|
38
|
+
if (answering.length > 0)
|
|
39
|
+
await Promise.all(answering);
|
|
30
40
|
led.noteSeq(ev);
|
|
31
41
|
if (isHostProgressFrame(ev))
|
|
32
42
|
progressedSinceReattach = true;
|
|
@@ -54,6 +64,24 @@ export async function* bridgeAskUserQuestionGates(source, deps, opts) {
|
|
|
54
64
|
break;
|
|
55
65
|
}
|
|
56
66
|
if (!park) {
|
|
67
|
+
const drained = drains.legEnded('returned');
|
|
68
|
+
if (drained !== undefined) {
|
|
69
|
+
const reopenAfterMs = 'reconnectAfterMs' in drained ? drained.reconnectAfterMs : undefined;
|
|
70
|
+
if (reopenAfterMs !== undefined && taskId.current !== undefined && !opts?.signal?.aborted) {
|
|
71
|
+
hostLog('debug', `liveHitlAskWire: runs.events(${taskId.current}) ended on the drain end frame — the engine is going down; reopening in ${reopenAfterMs}ms`);
|
|
72
|
+
await abortableSleep(reopenAfterMs, opts?.signal ?? new AbortController().signal);
|
|
73
|
+
if (!opts?.signal?.aborted) {
|
|
74
|
+
const seq = led.lastSeq();
|
|
75
|
+
led.beginStreamSegment();
|
|
76
|
+
stream = deps.runsEvents(taskId.current, {
|
|
77
|
+
...(seq !== undefined ? { lastEventId: seq } : {}),
|
|
78
|
+
...(opts?.signal ? { signal: opts.signal } : {}),
|
|
79
|
+
});
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
hostLog('debug', `liveHitlAskWire: runs.events ended on the drain end frame and is not reopened (${'giveUp' in drained ? drained.giveUp : taskId.current === undefined ? 'no run handle' : 'aborted'}) — ending this leg like a dropped stream`);
|
|
84
|
+
}
|
|
57
85
|
yield* flushHeldWithInterruptRewrite(led, { signal: opts?.signal });
|
|
58
86
|
return;
|
|
59
87
|
}
|
|
@@ -1,5 +1,7 @@
|
|
|
1
1
|
import { type CoreModeArbitrationRow } from '../generated/engineFactTables.js';
|
|
2
|
-
|
|
2
|
+
import { CORE_ASK_FACES } from '../generated/engineAskFaceTables.js';
|
|
3
|
+
export type AutomaticAnswerLane = 'mode_posture' | 'standing_rule' | 'permission_request_hook';
|
|
4
|
+
export type AutomaticAnswerAskFace = (typeof CORE_ASK_FACES)[number];
|
|
3
5
|
export interface AutomaticAnswerFacts {
|
|
4
6
|
readonly settingsAskRuleMatched?: boolean;
|
|
5
7
|
}
|
|
@@ -17,5 +19,9 @@ export type AutomaticAnswerVerdict = {
|
|
|
17
19
|
readonly kind: 'unknown';
|
|
18
20
|
readonly why: AutomaticAnswerUnknownWhy;
|
|
19
21
|
};
|
|
20
|
-
export declare
|
|
22
|
+
export declare const MODE_ARBITRATION: Readonly<Record<"hook" | "write_protection" | "mode" | "rule_unreadable" | "write_protection_unresolved" | "content_question" | "ancestor" | "dangerous_delete" | "unverifiable_delete" | "transcript_write" | "org_rule" | "governance_unavailable" | "ask_rule" | "denial_limit_fallback" | "classifier_no_ruling" | "requires_user_interaction" | "operator_forced" | "shell_floor" | "probe" | "tool_marks_mcp" | "tool_marks_a2a" | "policy_rra" | "artifact_shared_read" | "unstated" | "ordinary", CoreModeArbitrationRow>>;
|
|
23
|
+
export declare function foldModeArbitrationRow(classes: Iterable<string>, askFace?: AutomaticAnswerAskFace): CoreModeArbitrationRow;
|
|
21
24
|
export declare function automaticAnswerVerdict(card: object | null | undefined, lane: AutomaticAnswerLane, facts?: AutomaticAnswerFacts | null): AutomaticAnswerVerdict;
|
|
25
|
+
export declare function mandatedApprovalDetailOf(card: object | null | undefined): string;
|
|
26
|
+
export type PermissionRequestHookScope = 'allow_or_deny' | 'deny_only' | 'skip';
|
|
27
|
+
export declare function permissionRequestHookScope(verdict: AutomaticAnswerVerdict | null | undefined): PermissionRequestHookScope;
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { CORE_MODE_ARBITRATION, CORE_MODE_RELEASE_REASONS } from '../generated/engineFactTables.js';
|
|
2
|
-
import {
|
|
2
|
+
import { CORE_RELEASABLE_ASK_CLASSES_BY_FACE, CORE_SHELL_FACE_TOOL_NAMES } from '../generated/engineAskFaceTables.js';
|
|
3
|
+
import { mandatedApprovalDetail } from '../gateVocabulary.js';
|
|
4
|
+
import { readAskOrigin, readOwnNonEmptyString } from '../ownKey.js';
|
|
3
5
|
import { readAskClassPairState } from './askClassPair.js';
|
|
4
6
|
import { approvalAllowRuleShadowed } from './allowRuleShadow.js';
|
|
5
7
|
import { approvalIsMandated, readApprovalMandate } from './toolApprovalWire.js';
|
|
8
|
+
export const MODE_ARBITRATION = CORE_MODE_ARBITRATION;
|
|
6
9
|
const TABLE = CORE_MODE_ARBITRATION;
|
|
7
10
|
const ORIGIN_IMPLIES_CLASS = Object.freeze({
|
|
8
11
|
content_question: 'content_question',
|
|
@@ -12,12 +15,26 @@ const ORIGIN_IMPLIES_CLASS = Object.freeze({
|
|
|
12
15
|
ask_rule: 'ask_rule',
|
|
13
16
|
denial_limit_fallback: 'denial_limit_fallback',
|
|
14
17
|
});
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
18
|
+
function mandateWordClass(word) {
|
|
19
|
+
if (word === 'operator_always')
|
|
20
|
+
return 'shell_floor';
|
|
21
|
+
return Object.hasOwn(TABLE, word) ? word : undefined;
|
|
22
|
+
}
|
|
19
23
|
const ORDINARY_ROW = CORE_MODE_ARBITRATION.ordinary;
|
|
20
|
-
|
|
24
|
+
function bypassImmuneOn(c, face) {
|
|
25
|
+
const on = face !== undefined && Object.hasOwn(CORE_RELEASABLE_ASK_CLASSES_BY_FACE, face) ? face : 'other';
|
|
26
|
+
return !CORE_RELEASABLE_ASK_CLASSES_BY_FACE[on].includes(c);
|
|
27
|
+
}
|
|
28
|
+
function askFaceOfCard(card) {
|
|
29
|
+
try {
|
|
30
|
+
const d = Object.getOwnPropertyDescriptor(card, 'toolName');
|
|
31
|
+
return d !== undefined && 'value' in d && typeof d.value === 'string' && CORE_SHELL_FACE_TOOL_NAMES.includes(d.value) ? 'shell' : 'other';
|
|
32
|
+
}
|
|
33
|
+
catch {
|
|
34
|
+
return 'other';
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export function foldModeArbitrationRow(classes, askFace) {
|
|
21
38
|
let any = false;
|
|
22
39
|
let bypassImmune = false;
|
|
23
40
|
let classifierEligible = true;
|
|
@@ -29,7 +46,7 @@ export function foldModeArbitrationRow(classes) {
|
|
|
29
46
|
continue;
|
|
30
47
|
const row = TABLE[c];
|
|
31
48
|
any = true;
|
|
32
|
-
bypassImmune ||=
|
|
49
|
+
bypassImmune ||= bypassImmuneOn(c, askFace);
|
|
33
50
|
classifierEligible &&= row.classifierEligible;
|
|
34
51
|
sandboxAdmission &&= row.sandboxAdmission;
|
|
35
52
|
ruleMayClear &&= row.ruleMayClear;
|
|
@@ -39,8 +56,12 @@ export function foldModeArbitrationRow(classes) {
|
|
|
39
56
|
return ORDINARY_ROW;
|
|
40
57
|
return Object.freeze({ bypassImmune, classifierEligible, sandboxAdmission, ruleMayClear, hookAskFloor });
|
|
41
58
|
}
|
|
42
|
-
function
|
|
43
|
-
return lane === 'mode_posture' ? row.bypassImmune : !row.ruleMayClear;
|
|
59
|
+
function rowBlocks(lane, row) {
|
|
60
|
+
return lane === 'mode_posture' ? row.bypassImmune : lane === 'standing_rule' ? !row.ruleMayClear : row.hookAskFloor;
|
|
61
|
+
}
|
|
62
|
+
function classBlocks(lane, c, face) {
|
|
63
|
+
const row = TABLE[c];
|
|
64
|
+
return lane === 'mode_posture' ? bypassImmuneOn(c, face) : lane === 'standing_rule' ? !row.ruleMayClear : row.hookAskFloor;
|
|
44
65
|
}
|
|
45
66
|
function mustAsk(road, extra) {
|
|
46
67
|
return Object.freeze({ kind: 'must_ask', road, ...(extra?.askClass !== undefined ? { askClass: extra.askClass } : {}), ...(extra?.origin !== undefined ? { origin: extra.origin } : {}) });
|
|
@@ -75,34 +96,33 @@ function readHostAskRuleMatched(facts) {
|
|
|
75
96
|
}
|
|
76
97
|
}
|
|
77
98
|
export function automaticAnswerVerdict(card, lane, facts) {
|
|
78
|
-
if (lane !== 'mode_posture' && lane !== 'standing_rule')
|
|
99
|
+
if (lane !== 'mode_posture' && lane !== 'standing_rule' && lane !== 'permission_request_hook')
|
|
79
100
|
return UNKNOWN.lane_not_recognised;
|
|
80
101
|
try {
|
|
81
102
|
if (typeof card !== 'object' || card === null)
|
|
82
103
|
return UNKNOWN.card_unreadable;
|
|
83
|
-
const
|
|
104
|
+
const face = lane === 'mode_posture' ? askFaceOfCard(card) : undefined;
|
|
105
|
+
const origin = readAskOrigin(evidenceView(card, 'origin'));
|
|
84
106
|
if (origin !== undefined && Object.hasOwn(ORIGIN_IMPLIES_CLASS, origin)) {
|
|
85
107
|
const cls = ORIGIN_IMPLIES_CLASS[origin];
|
|
86
|
-
if (
|
|
108
|
+
if (classBlocks(lane, cls, face))
|
|
87
109
|
return mustAsk('origin', { origin, askClass: cls });
|
|
88
110
|
}
|
|
89
|
-
if (lane
|
|
111
|
+
if (lane !== 'mode_posture' && evidenceView(card, 'requiresRealApproval').requiresRealApproval === true)
|
|
90
112
|
return mustAsk('requires_real_approval');
|
|
91
113
|
if (evidenceView(card, 'governanceForced').governanceForced === true)
|
|
92
114
|
return mustAsk('governance');
|
|
93
115
|
if (lane === 'mode_posture') {
|
|
94
116
|
const word = readApprovalMandate(evidenceView(card, 'mandate'));
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
return mustAsk('mandate_word', { askClass: cls });
|
|
99
|
-
}
|
|
117
|
+
const cls = word !== undefined ? mandateWordClass(word) : undefined;
|
|
118
|
+
if (cls !== undefined && classBlocks(lane, cls, face))
|
|
119
|
+
return mustAsk('mandate_word', { askClass: cls });
|
|
100
120
|
}
|
|
101
121
|
else {
|
|
102
122
|
const mandateView = evidenceView(card, 'mandated', 'ruleOffersAbsence', 'mandate');
|
|
103
123
|
if (approvalIsMandated(mandateView))
|
|
104
124
|
return mustAsk('mandated');
|
|
105
|
-
if (approvalAllowRuleShadowed(card) || readOwnNonEmptyString(mandateView, 'ruleOffersAbsence') === 'shadowed')
|
|
125
|
+
if (lane === 'standing_rule' && (approvalAllowRuleShadowed(card) || readOwnNonEmptyString(mandateView, 'ruleOffersAbsence') === 'shadowed'))
|
|
106
126
|
return mustAsk('allow_rule_shadow');
|
|
107
127
|
}
|
|
108
128
|
const pair = readAskClassPairState(card);
|
|
@@ -110,7 +130,7 @@ export function automaticAnswerVerdict(card, lane, facts) {
|
|
|
110
130
|
return UNKNOWN.classes_malformed;
|
|
111
131
|
if (pair.state === 'absent')
|
|
112
132
|
return UNKNOWN.classes_absent;
|
|
113
|
-
const folded = foldModeArbitrationRow(pair.classes);
|
|
133
|
+
const folded = foldModeArbitrationRow(pair.classes, face);
|
|
114
134
|
let anyKnown = false;
|
|
115
135
|
let firstBlocking;
|
|
116
136
|
let anyUnknown = false;
|
|
@@ -120,14 +140,14 @@ export function automaticAnswerVerdict(card, lane, facts) {
|
|
|
120
140
|
continue;
|
|
121
141
|
}
|
|
122
142
|
anyKnown = true;
|
|
123
|
-
if (firstBlocking === undefined &&
|
|
143
|
+
if (firstBlocking === undefined && classBlocks(lane, c, face))
|
|
124
144
|
firstBlocking = c;
|
|
125
145
|
}
|
|
126
|
-
if (anyKnown &&
|
|
146
|
+
if (anyKnown && rowBlocks(lane, folded))
|
|
127
147
|
return mustAsk('ask_class', firstBlocking !== undefined ? { askClass: firstBlocking } : undefined);
|
|
128
148
|
if (anyUnknown)
|
|
129
149
|
return UNKNOWN.class_not_in_table;
|
|
130
|
-
if (lane
|
|
150
|
+
if (lane !== 'mode_posture')
|
|
131
151
|
return MAY_ANSWER;
|
|
132
152
|
const matched = readHostAskRuleMatched(facts);
|
|
133
153
|
if (matched === true)
|
|
@@ -141,3 +161,31 @@ export function automaticAnswerVerdict(card, lane, facts) {
|
|
|
141
161
|
return UNKNOWN.card_unreadable;
|
|
142
162
|
}
|
|
143
163
|
}
|
|
164
|
+
export function mandatedApprovalDetailOf(card) {
|
|
165
|
+
try {
|
|
166
|
+
if (typeof card !== 'object' || card === null)
|
|
167
|
+
return mandatedApprovalDetail();
|
|
168
|
+
const pair = readAskClassPairState(card);
|
|
169
|
+
if (pair.state !== 'pair')
|
|
170
|
+
return mandatedApprovalDetail();
|
|
171
|
+
if (pair.classes.some((c) => !Object.hasOwn(TABLE, c)))
|
|
172
|
+
return mandatedApprovalDetail();
|
|
173
|
+
const row = foldModeArbitrationRow(pair.classes);
|
|
174
|
+
if (row.classifierEligible || row.sandboxAdmission)
|
|
175
|
+
return mandatedApprovalDetail();
|
|
176
|
+
return MANDATED_NO_AUTOMATIC_CHECK_DETAIL;
|
|
177
|
+
}
|
|
178
|
+
catch {
|
|
179
|
+
return mandatedApprovalDetail();
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
const MANDATED_NO_AUTOMATIC_CHECK_DETAIL = 'no saved allow rule and no remembered answer can retire this question, and no automatic check answers it; each call is settled on its own, by you here, and an answer covers only that call';
|
|
183
|
+
export function permissionRequestHookScope(verdict) {
|
|
184
|
+
try {
|
|
185
|
+
const kind = typeof verdict === 'object' && verdict !== null ? verdict.kind : undefined;
|
|
186
|
+
return kind === 'may_answer' ? 'allow_or_deny' : kind === 'must_ask' ? 'skip' : 'deny_only';
|
|
187
|
+
}
|
|
188
|
+
catch {
|
|
189
|
+
return 'deny_only';
|
|
190
|
+
}
|
|
191
|
+
}
|
|
@@ -3,6 +3,8 @@ const CRASH_CONVERGED_CAUSE_WORDS = Object.freeze({
|
|
|
3
3
|
shutdown_before_park: true,
|
|
4
4
|
});
|
|
5
5
|
export const isCrashConvergedCause = (v) => typeof v === 'string' && Object.hasOwn(CRASH_CONVERGED_CAUSE_WORDS, v);
|
|
6
|
+
const _crashConvergedCausePin = true;
|
|
7
|
+
void _crashConvergedCausePin;
|
|
6
8
|
const isString = (v) => typeof v === 'string';
|
|
7
9
|
const isNumber = (v) => typeof v === 'number';
|
|
8
10
|
const nonEmptyString = (v) => typeof v === 'string' && v.length > 0;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export type DecisionRefusalConflict = 'binding_mismatch' | 'row_integrity' | 'format_version' | 'answer_invalid';
|
|
2
|
+
export declare function decisionConflictOf(err: unknown): DecisionRefusalConflict | undefined;
|
|
3
|
+
export declare const DECISION_ANSWER_INVALID_CONTENT = "The engine rejected the answer itself because it does not fit the question that was asked \u00B7 Nothing was decided and the question is still waiting \u00B7 Correct the answer and send it again";
|