@sema-agent/client-core 0.96.0 → 0.97.1

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.
Files changed (145) hide show
  1. package/CHANGELOG.md +110 -0
  2. package/README.md +29 -22
  3. package/dist/adapter/activeRunSelfHeal.d.ts +0 -2
  4. package/dist/adapter/activeRunSelfHeal.js +7 -7
  5. package/dist/adapter/downstream/terminalToSdkResult.js +6 -2
  6. package/dist/agentSession/backgroundView.js +2 -15
  7. package/dist/agentsWireCaps.d.ts +3 -1
  8. package/dist/agentsWireCaps.js +67 -39
  9. package/dist/approvalDecidedByCapability.d.ts +2 -0
  10. package/dist/approvalDecidedByCapability.js +0 -1
  11. package/dist/approvalsStreamLiveCapability.d.ts +2 -0
  12. package/dist/approvalsStreamLiveCapability.js +3 -2
  13. package/dist/attachmentSeatCapability.d.ts +2 -0
  14. package/dist/attachmentSeatCapability.js +0 -1
  15. package/dist/callerCwdCapability.d.ts +2 -0
  16. package/dist/callerCwdCapability.js +0 -1
  17. package/dist/centerWiringCapability.d.ts +2 -0
  18. package/dist/centerWiringCapability.js +4 -3
  19. package/dist/cloudConfigWireCaps.d.ts +2 -2
  20. package/dist/cloudConfigWireCaps.js +192 -56
  21. package/dist/declared/supportFloorDeclared.js +3 -3
  22. package/dist/deviceExecutorManagementCapability.d.ts +2 -0
  23. package/dist/deviceExecutorManagementCapability.js +3 -2
  24. package/dist/displayUntrusted.d.ts +3 -0
  25. package/dist/displayUntrusted.js +15 -0
  26. package/dist/engineCapReader.d.ts +8 -2
  27. package/dist/engineCapReader.js +15 -7
  28. package/dist/engineCapsCache.d.ts +11 -3
  29. package/dist/engineCapsCache.js +54 -23
  30. package/dist/engineErrorCodes.d.ts +3 -0
  31. package/dist/engineErrorCodes.js +9 -1
  32. package/dist/engineNoticeCodes.js +2 -3
  33. package/dist/engineToolDirectory.d.ts +27 -0
  34. package/dist/engineToolDirectory.js +178 -0
  35. package/dist/executionLaneCapability.d.ts +2 -0
  36. package/dist/executionLaneCapability.js +3 -2
  37. package/dist/fileHistoryCaptureCapability.d.ts +2 -0
  38. package/dist/fileHistoryCaptureCapability.js +34 -8
  39. package/dist/fileHistoryLegNotice.js +4 -0
  40. package/dist/fleet/fleetLedger.js +129 -105
  41. package/dist/gateOutcome.js +2 -4
  42. package/dist/gateVocabulary.d.ts +1 -6
  43. package/dist/gateVocabulary.js +2 -5
  44. package/dist/generated/sdkFactTables.d.ts +2 -0
  45. package/dist/generated/sdkFactTables.js +7 -0
  46. package/dist/generated/toolNameTables.d.ts +0 -1
  47. package/dist/generated/toolNameTables.js +0 -42
  48. package/dist/hitl/approvalDecisionNoteAudit.js +2 -2
  49. package/dist/hitl/approvalEndingCause.js +2 -7
  50. package/dist/hitl/approvalHolds.d.ts +16 -1
  51. package/dist/hitl/approvalHolds.js +52 -12
  52. package/dist/hitl/askGateWire.js +1 -0
  53. package/dist/hitl/automaticAnswerVerdict.js +5 -7
  54. package/dist/hitl/decisionConflict.js +4 -3
  55. package/dist/hitl/decisionRefusal.js +19 -12
  56. package/dist/hitl/frameRouter.d.ts +3 -0
  57. package/dist/hitl/frameRouter.js +52 -25
  58. package/dist/hitl/gateLedger.d.ts +0 -5
  59. package/dist/hitl/gateLedger.js +0 -21
  60. package/dist/hitl/hitlBridge.js +18 -4
  61. package/dist/hitl/parkResolver.js +7 -3
  62. package/dist/hitl/replayedApproval.d.ts +2 -3
  63. package/dist/hitl/replayedApproval.js +7 -16
  64. package/dist/hitl/sessionPolicyDeliverable.d.ts +0 -1
  65. package/dist/hitl/sessionPolicyDeliverable.js +15 -17
  66. package/dist/hitl/sessionPolicyWire.d.ts +2 -0
  67. package/dist/hitl/sessionPolicyWire.js +15 -3
  68. package/dist/hitl/standingRows.d.ts +1 -0
  69. package/dist/hitl/standingRows.js +38 -17
  70. package/dist/hitl/suspendedReopen.js +2 -1
  71. package/dist/hitl/toolApprovalWire.d.ts +8 -8
  72. package/dist/hitl/toolApprovalWire.js +50 -24
  73. package/dist/index.d.ts +8 -4
  74. package/dist/index.js +5 -3
  75. package/dist/liveModelCatalog.d.ts +13 -0
  76. package/dist/liveModelCatalog.js +56 -0
  77. package/dist/mcpProbeCapability.d.ts +2 -0
  78. package/dist/mcpProbeCapability.js +3 -2
  79. package/dist/mcpWireCaps.d.ts +1 -0
  80. package/dist/mcpWireCaps.js +4 -1
  81. package/dist/memoryComplianceCapability.d.ts +2 -0
  82. package/dist/memoryComplianceCapability.js +3 -2
  83. package/dist/memoryOriginCapability.d.ts +2 -0
  84. package/dist/memoryOriginCapability.js +3 -2
  85. package/dist/modelIdentityResolvability.js +2 -2
  86. package/dist/noticePresentation.js +2 -2
  87. package/dist/outputStyleSeatCapability.d.ts +2 -0
  88. package/dist/outputStyleSeatCapability.js +0 -1
  89. package/dist/peerLaneCapability.d.ts +2 -0
  90. package/dist/peerLaneCapability.js +3 -2
  91. package/dist/permissionModesCapability.d.ts +2 -0
  92. package/dist/permissionModesCapability.js +0 -1
  93. package/dist/permissionRulesWriteCapability.d.ts +2 -0
  94. package/dist/permissionRulesWriteCapability.js +3 -2
  95. package/dist/permissionsAllowGrantCapability.d.ts +2 -0
  96. package/dist/permissionsAllowGrantCapability.js +4 -2
  97. package/dist/permissionsDeclaration.js +19 -21
  98. package/dist/request/taskRequest.d.ts +1 -4
  99. package/dist/request/taskRequest.js +74 -19
  100. package/dist/resumeRefusalCopy.js +4 -4
  101. package/dist/rewindArchiveCapability.js +5 -0
  102. package/dist/rewindArchiveReading.d.ts +2 -0
  103. package/dist/rewindArchiveReading.js +0 -1
  104. package/dist/runTerminal.d.ts +33 -4
  105. package/dist/runTerminal.js +170 -15
  106. package/dist/sdkWireTransit.d.ts +2 -1
  107. package/dist/sdkWireTransit.js +1 -0
  108. package/dist/sealedKeyCapability.d.ts +2 -0
  109. package/dist/sealedKeyCapability.js +0 -1
  110. package/dist/seatContract.d.ts +7 -4
  111. package/dist/seatContract.js +34 -20
  112. package/dist/sessionPolicyCapability.d.ts +2 -0
  113. package/dist/sessionPolicyCapability.js +3 -2
  114. package/dist/sessionReadRedactionCapability.d.ts +2 -0
  115. package/dist/sessionReadRedactionCapability.js +0 -1
  116. package/dist/sessionSyncFileHistoryCapability.d.ts +2 -0
  117. package/dist/sessionSyncFileHistoryCapability.js +3 -2
  118. package/dist/skillToolListsCapability.d.ts +2 -0
  119. package/dist/skillToolListsCapability.js +3 -2
  120. package/dist/sqlEngineCapability.d.ts +2 -0
  121. package/dist/sqlEngineCapability.js +4 -3
  122. package/dist/steerPriorityCapability.d.ts +2 -0
  123. package/dist/steerPriorityCapability.js +3 -2
  124. package/dist/storePostureCapability.d.ts +2 -0
  125. package/dist/storePostureCapability.js +4 -3
  126. package/dist/toolHistoryBadTurn.js +3 -2
  127. package/dist/toolResult.d.ts +11 -0
  128. package/dist/toolResult.js +53 -0
  129. package/dist/userInvokedSkillsCapability.d.ts +2 -0
  130. package/dist/userInvokedSkillsCapability.js +3 -2
  131. package/dist/webSearchBackendCapability.d.ts +2 -0
  132. package/dist/webSearchBackendCapability.js +3 -2
  133. package/dist/wireErrorTriage.js +58 -34
  134. package/dist/wireFailureShape.d.ts +1 -1
  135. package/dist/wireFailureShape.js +76 -25
  136. package/dist/workflowsJournalCapability.d.ts +2 -0
  137. package/dist/workflowsJournalCapability.js +3 -2
  138. package/dist/writeProtectionCapability.d.ts +2 -0
  139. package/dist/writeProtectionCapability.js +3 -2
  140. package/docs/INTEGRATION-CLIENTS.md +585 -14
  141. package/package.json +4 -4
  142. package/dist/engineRefusedToolName.d.ts +0 -1
  143. package/dist/engineRefusedToolName.js +0 -8
  144. package/dist/engineWordRenames.d.ts +0 -8
  145. package/dist/engineWordRenames.js +0 -13
@@ -60,6 +60,7 @@ export async function* bridgeAskUserQuestionGates(source, deps, opts) {
60
60
  gate: action.gate,
61
61
  ...(action.pendingDone !== undefined ? { pendingDone: action.pendingDone } : {}),
62
62
  ...(action.gatedCallId !== undefined ? { gatedCallId: action.gatedCallId } : {}),
63
+ ...(action.toolName !== undefined ? { toolName: action.toolName } : {}),
63
64
  };
64
65
  break;
65
66
  }
@@ -3,7 +3,6 @@ import { CORE_RELEASABLE_ASK_CLASSES_BY_FACE, CORE_SHELL_FACE_TOOL_NAMES } from
3
3
  import { mandatedApprovalDetail } from '../gateVocabulary.js';
4
4
  import { readAskOrigin, readOwnNonEmptyString } from '../ownKey.js';
5
5
  import { readAskClassPairState } from './askClassPair.js';
6
- import { currentEngineWord } from '../engineWordRenames.js';
7
6
  import { approvalAllowRuleShadowed } from './allowRuleShadow.js';
8
7
  import { approvalIsMandated, readApprovalMandate } from './toolApprovalWire.js';
9
8
  export const MODE_ARBITRATION = CORE_MODE_ARBITRATION;
@@ -19,8 +18,7 @@ const ORIGIN_IMPLIES_CLASS = Object.freeze({
19
18
  function mandateWordClass(raw) {
20
19
  if (raw === 'operator_always')
21
20
  return 'shell_floor';
22
- const word = currentEngineWord(raw);
23
- return Object.hasOwn(TABLE, word) ? word : undefined;
21
+ return Object.hasOwn(TABLE, raw) ? raw : undefined;
24
22
  }
25
23
  const ORDINARY_ROW = CORE_MODE_ARBITRATION.ordinary;
26
24
  function bypassImmuneOn(c, face) {
@@ -44,8 +42,8 @@ export function foldModeArbitrationRow(classes, askFace) {
44
42
  let ruleMayClear = true;
45
43
  let hookAskFloor = false;
46
44
  for (const raw of classes) {
47
- const c = typeof raw === 'string' ? currentEngineWord(raw) : raw;
48
- if (!Object.hasOwn(TABLE, c))
45
+ const c = raw;
46
+ if (typeof c !== 'string' || !Object.hasOwn(TABLE, c))
49
47
  continue;
50
48
  const row = TABLE[c];
51
49
  any = true;
@@ -133,7 +131,7 @@ export function automaticAnswerVerdict(card, lane, facts) {
133
131
  return UNKNOWN.classes_malformed;
134
132
  if (pair.state === 'absent')
135
133
  return UNKNOWN.classes_absent;
136
- const classes = pair.classes.map(currentEngineWord);
134
+ const classes = pair.classes;
137
135
  const folded = foldModeArbitrationRow(classes, face);
138
136
  let anyKnown = false;
139
137
  let firstBlocking;
@@ -172,7 +170,7 @@ export function mandatedApprovalDetailOf(card) {
172
170
  const pair = readAskClassPairState(card);
173
171
  if (pair.state !== 'pair')
174
172
  return mandatedApprovalDetail();
175
- const classes = pair.classes.map(currentEngineWord);
173
+ const classes = pair.classes;
176
174
  if (classes.some((c) => !Object.hasOwn(TABLE, c)))
177
175
  return mandatedApprovalDetail();
178
176
  const row = foldModeArbitrationRow(classes);
@@ -1,4 +1,5 @@
1
1
  import { APPROVAL_BINDING_MISMATCH, CHECKPOINT_UNSUPPORTED_VERSION, RESUME_OUTCOME_INVALID } from '../engineErrorCodes.js';
2
+ import { ownDataField } from '../ownKey.js';
2
3
  import { readRefusalField } from '../wireFailureShape.js';
3
4
  const BINDING_SEAT_FIELDS = new Set(['boundCallId', 'boundInputHash']);
4
5
  const ANSWER_FIELD = 'answer';
@@ -9,13 +10,13 @@ export function decisionConflictOf(err) {
9
10
  let code;
10
11
  let name;
11
12
  try {
12
- code = err.errorCode;
13
+ code = ownDataField(err, 'errorCode');
13
14
  }
14
15
  catch {
15
- code = undefined;
16
+ return undefined;
16
17
  }
17
18
  try {
18
- name = err.name;
19
+ name = ownDataField(err, 'name');
19
20
  }
20
21
  catch {
21
22
  name = undefined;
@@ -1,10 +1,10 @@
1
- import { ApprovalStaleError, AskDecidedError, ParkedResumeStartupError } from '@sema-agent/sdk';
2
1
  import { ASK_GONE, ASK_GONE_PARKED, isDecideAlreadyResolvedCode, isDecideParkMovedCode, refusalRetriableReading, refusalSaysStillPending } from '../engineErrorCodes.js';
3
2
  import { notPendingCauseReading } from './approvalEndingCause.js';
4
3
  import { GATE_FAILURE_CODES } from './hitlBridge.js';
5
4
  import { isAlreadyResolvedGateReason, isCodeClassifiedGateFailure } from './parkResolver.js';
6
5
  import { decisionConflictOf } from './decisionConflict.js';
7
6
  import { readLivePendingRows } from './livePendingAsk.js';
7
+ import { ownDataField } from '../ownKey.js';
8
8
  import { readToolApprovalRespondRefusal } from './toolApprovalWire.js';
9
9
  const ASK_DECIDED_CODE = 'conflict.ask_decided';
10
10
  const TRANSIENT_STATUSES = new Set([408, 425, 429, 502, 503, 504]);
@@ -13,22 +13,27 @@ export function decisionRefusalSaysAskGone(err) {
13
13
  return readDecisionRefusalAsk(err).reading === 'settled';
14
14
  }
15
15
  const facts = (reading, gateMoved = false, wordingHint = false) => ({ reading, gateMoved, wordingHint });
16
+ const PROTOCOL_ERROR_NAMES = Object.freeze({
17
+ askDecided: 'AskDecidedError',
18
+ approvalStale: 'ApprovalStaleError',
19
+ parkedResumeStartup: 'ParkedResumeStartupError',
20
+ });
16
21
  export function readDecisionRefusalAsk(failure) {
17
22
  if (typeof failure !== 'object' || failure === null)
18
23
  return facts('not_settled');
19
24
  let flattened, localCode, name, errorCode, status, retriable, text;
20
25
  try {
21
- const o = failure;
22
- if (Object.hasOwn(failure, 'unreadable') && failure.unreadable === true)
26
+ const slot = (key) => ownDataField(failure, key);
27
+ if (slot('unreadable') === true)
23
28
  return facts('unreadable');
24
- flattened = Object.hasOwn(failure, 'kind') && o.kind === 'failed';
29
+ flattened = slot('kind') === 'failed';
25
30
  const closed = (v) => (typeof v === 'string' && GATE_FAILURE_CODES.includes(v) ? v : undefined);
26
- localCode = flattened ? (closed(o.code) ?? closed(o.safetyCode)) : closed(o.code);
27
- name = flattened ? undefined : o.name;
28
- errorCode = o.errorCode;
29
- status = o.status;
31
+ localCode = flattened ? (closed(slot('code')) ?? closed(slot('safetyCode'))) : closed(slot('code'));
32
+ name = flattened ? undefined : slot('name');
33
+ errorCode = slot('errorCode');
34
+ status = slot('status');
30
35
  retriable = refusalRetriableReading(failure);
31
- text = flattened ? o.reason : String(failure);
36
+ text = flattened ? slot('reason') : String(failure);
32
37
  }
33
38
  catch {
34
39
  return facts('unreadable');
@@ -40,15 +45,17 @@ export function readDecisionRefusalAsk(failure) {
40
45
  if (name === 'HitlSafetyError')
41
46
  return facts('not_settled');
42
47
  const code = typeof errorCode === 'string' && errorCode.length > 0 ? errorCode : undefined;
48
+ if (isCodeClassifiedGateFailure(code, retriable))
49
+ return facts('not_settled');
43
50
  const st = typeof status === 'number' && Number.isInteger(status) && status >= 400 && status <= 599 ? status : undefined;
44
51
  if (code === ASK_DECIDED_CODE || code === ASK_GONE || (st === 410 && code !== ASK_GONE_PARKED))
45
52
  return facts('settled');
46
53
  if (st === 404 && notPendingCauseReading(failure) === 'ended')
47
54
  return facts('settled');
48
- if (code === undefined && name === AskDecidedError.name)
55
+ if (code === undefined && name === PROTOCOL_ERROR_NAMES.askDecided)
49
56
  return facts('settled');
50
- const gateMoved = isDecideAlreadyResolvedCode(code) || isDecideParkMovedCode(code) || code === ASK_GONE_PARKED || (code === undefined && name === ApprovalStaleError.name);
51
- if (gateMoved || st !== undefined || name === ParkedResumeStartupError.name || isCodeClassifiedGateFailure(code, retriable))
57
+ const gateMoved = isDecideAlreadyResolvedCode(code) || isDecideParkMovedCode(code) || code === ASK_GONE_PARKED || (code === undefined && name === PROTOCOL_ERROR_NAMES.approvalStale);
58
+ if (gateMoved || st !== undefined || name === PROTOCOL_ERROR_NAMES.parkedResumeStartup)
52
59
  return facts('not_settled', gateMoved);
53
60
  return facts('not_settled', false, isAlreadyResolvedGateReason(text));
54
61
  }
@@ -40,6 +40,7 @@ export interface GatePark {
40
40
  gate: GateKind;
41
41
  pendingDone?: AgentEvent | undefined;
42
42
  gatedCallId?: string | undefined;
43
+ toolName?: string | undefined;
43
44
  }
44
45
  export type FrameAction = {
45
46
  kind: 'yield';
@@ -51,6 +52,7 @@ export type FrameAction = {
51
52
  gate: GateKind;
52
53
  pendingDone?: AgentEvent | undefined;
53
54
  gatedCallId?: string | undefined;
55
+ toolName?: string | undefined;
54
56
  } | {
55
57
  kind: 'end';
56
58
  events: readonly AgentEvent[];
@@ -65,6 +67,7 @@ export interface FrameRouterCtx {
65
67
  signal?: AbortSignal | undefined;
66
68
  }
67
69
  export declare function isAskTool(toolName: string | undefined): boolean;
70
+ export declare function parkGateArmOf(gate: unknown): GateKind | null;
68
71
  export declare function isHostProgressFrame(ev: AgentEvent): boolean;
69
72
  interface HeldFlushInterruptEvidence {
70
73
  terminal?: AgentEvent | undefined;
@@ -1,12 +1,12 @@
1
1
  import { hostLog } from '../host.js';
2
2
  import { invokeHostCallbackIsolated } from '../hostCallbackGuard.js';
3
- import { isToolApprovalGate, toolNameIsFsWrite, toolNameIsShellExec, isToolApprovalFrame, isFromSubagent, surfaceToolApprovalFrameAndRespond, } from './toolApprovalWire.js';
3
+ import { toolNameIsFsWrite, toolNameIsShellExec, isToolApprovalFrame, isFromSubagent, surfaceToolApprovalFrameAndRespond, } from './toolApprovalWire.js';
4
4
  import { classifierDenyFromToolEnd } from '../classifierVerdictWire.js';
5
5
  import { toolEndOutputText } from '../toolResultContent.js';
6
6
  import { GATE_PARKED_ERROR_CODE } from '../engineErrorCodes.js';
7
7
  import { readRunTerminal, runTerminalCode, runTerminalGateKind, runTerminalGateToolName } from '../runTerminal.js';
8
8
  import { surfaceForCurrentSession, surfaceReplayedApprovalListUnreadable } from './hitlHostSurface.js';
9
- import { liveCardAnsweredHow, liveCardHoldOf, supersedeLiveCard } from './approvalHolds.js';
9
+ import { liveCardHoldOf, noteEngineClosedApproval, supersedeLiveCard } from './approvalHolds.js';
10
10
  import { approvalCompleteParked } from './approvalCompleteParked.js';
11
11
  import { liveFrameCallKey } from './gateIdentity.js';
12
12
  import { SEMA_DENIAL_KIND_KEY, hasLedgerPositionKey } from './gateLedger.js';
@@ -15,6 +15,7 @@ import { settleWithinDeadline } from '../abortableSleep.js';
15
15
  import { ccToolDenialKindForSettledBy } from '../gateVocabulary.js';
16
16
  import { REJECT_MESSAGE } from '../adapt/wireShapes.js';
17
17
  import { RUN_CANCELLED_CODE } from '../runCancelContext.js';
18
+ import { durableDecideLegOf } from '../adapter/activeRunSelfHeal.js';
18
19
  export const HITL_REJECT_MESSAGE = REJECT_MESSAGE;
19
20
  export const HITL_POLICY_DENY_MESSAGE = 'Permission for this tool use was denied: it requires interactive approval, and permission prompts are ' +
20
21
  'not available in this session. The action was NOT performed. Do not claim it succeeded, and do not retry ' +
@@ -99,6 +100,27 @@ function parkFamilyEvidence(led, gateToolName, gatedCallId) {
99
100
  return false;
100
101
  return gatedCallId === undefined || led.isFsOrShellGatedCall(gatedCallId);
101
102
  }
103
+ export function parkGateArmOf(gate) {
104
+ if (gate === null || typeof gate !== 'object')
105
+ return null;
106
+ let kind;
107
+ let toolName;
108
+ try {
109
+ kind = gate.kind;
110
+ toolName = gate.toolName;
111
+ }
112
+ catch {
113
+ return null;
114
+ }
115
+ const leg = durableDecideLegOf(typeof kind === 'string' ? { gateKind: kind } : null);
116
+ if (leg !== 'approval' && leg !== 'absent')
117
+ return null;
118
+ if (isAskToolLoose(toolName))
119
+ return 'ask';
120
+ if (leg === 'approval')
121
+ return 'fs';
122
+ return isFsOrShellToolName(toolName) ? 'fs' : null;
123
+ }
102
124
  const ENGINE_GATE_PARKED_ERROR_CODE = GATE_PARKED_ERROR_CODE;
103
125
  function isEngineAbortToolEnd(ev) {
104
126
  if (ev.errorCode === ENGINE_GATE_PARKED_ERROR_CODE)
@@ -123,11 +145,8 @@ function parkGateOf(result) {
123
145
  if (typeof taskId !== 'string' || taskId.length === 0)
124
146
  return null;
125
147
  const toolName = runTerminalGateToolName(read);
126
- if (isAskToolLoose(toolName))
127
- return { taskId, gate: 'ask', toolName };
128
- if (isToolApprovalGate({ kind: runTerminalGateKind(read), toolName }))
129
- return { taskId, gate: 'fs', toolName };
130
- return null;
148
+ const arm = parkGateArmOf({ kind: runTerminalGateKind(read), toolName });
149
+ return arm === null ? null : { taskId, gate: arm, toolName };
131
150
  }
132
151
  function parkGatedCallId(src) {
133
152
  const v = src?.toolCallId;
@@ -264,18 +283,19 @@ async function routeToolApprovalFrame(ev, ctx) {
264
283
  const { led, deps } = ctx;
265
284
  if (ev.type === 'tool_approval_complete') {
266
285
  const id = ev.approvalId;
267
- if (typeof id === 'string' && id !== '' && supersedeLiveCard(liveFrameCallKey(id), approvalCompleteParked(ev))) {
286
+ const parked = approvalCompleteParked(ev);
287
+ if (typeof id === 'string' && id !== '')
288
+ noteEngineClosedApproval(id, parked);
289
+ if (typeof id === 'string' && id !== '' && supersedeLiveCard(liveFrameCallKey(id), parked)) {
268
290
  hostLog('debug', `liveHitlAskWire: tool_approval_complete for ${id} arrived while its card was waiting — card withdrawn (nothing will be sent from it)`);
269
291
  }
270
- if (typeof id === 'string' && id !== '')
271
- led.noteApprovalSettled(id, 'closed_by_engine');
272
292
  return { kind: 'skip' };
273
293
  }
274
294
  if (!deps.respondToolApproval) {
275
295
  hostLog('debug', `liveHitlAskWire: tool_approval frame ${ev.approvalId} but no respond wire — engine self-settles (TTL deny)`);
276
296
  return { kind: 'skip' };
277
297
  }
278
- const settledHere = settledApprovalDisposition(ev, led.settledApprovals());
298
+ const settledHere = settledApprovalDisposition(ev);
279
299
  if (settledHere !== undefined || (hasLedgerPositionKey(ev) && !led.preambleApprovals().has(ev.approvalId))) {
280
300
  const disposition = settledHere ?? (await judgeLedgerApprovalFrame(ev, ctx));
281
301
  if (disposition.kind !== 'live') {
@@ -298,21 +318,17 @@ async function routeToolApprovalFrame(ev, ctx) {
298
318
  const gatedCallId = fromSubagent ? undefined : frameCallId ?? led.lastPendingFsCall();
299
319
  const argsCallId = frameCallId === undefined ? gatedCallId : typeof ev.toolName === 'string' && toolNameIsFsWrite(ev.toolName) ? frameCallId : undefined;
300
320
  const runTaskId = ctx.taskId.current;
301
- const approvalIdAtLaunch = ev.approvalId;
302
321
  const launched = surfaceToolApprovalFrameAndRespond(ev, deps.respondToolApproval, argsOfGatedStart(led, argsCallId), ctx.signal, deps.approvalLane, typeof runTaskId === 'string' && runTaskId !== '' ? { taskId: runTaskId } : undefined);
303
322
  const hold = liveCardHoldOf(liveFrameCallKey(ev.approvalId));
304
- const handled = launched.then((outcome) => settleLiveCardOutcome(ev, approvalIdAtLaunch, outcome, ctx, fromSubagent, gatedCallId), (e) => {
323
+ const handled = launched.then((outcome) => settleLiveCardOutcome(ev, outcome, ctx, fromSubagent, gatedCallId), (e) => {
305
324
  hostLog('debug', `liveHitlAskWire: tool_approval card for ${ev.approvalId} failed: ${String(e).slice(0, 160)}`);
306
325
  });
307
326
  led.trackLiveCard(() => hold?.phase ?? 'card', handled);
308
327
  return { kind: 'skip' };
309
328
  }
310
- function settleLiveCardOutcome(ev, approvalId, outcome, ctx, fromSubagent, gatedCallId) {
329
+ function settleLiveCardOutcome(ev, outcome, ctx, fromSubagent, gatedCallId) {
311
330
  const { led, deps } = ctx;
312
331
  const { decision } = outcome;
313
- const settledHow = liveCardAnsweredHow(outcome);
314
- if (settledHow !== undefined)
315
- led.noteApprovalSettled(approvalId, settledHow);
316
332
  if (deps.onToolApprovalOutcome !== undefined) {
317
333
  invokeHostCallbackIsolated('liveHitlAskWire: onToolApprovalOutcome', () => deps.onToolApprovalOutcome?.(ev, outcome));
318
334
  }
@@ -349,7 +365,7 @@ async function judgeLedgerApprovalFrame(ev, ctx) {
349
365
  .finally(release);
350
366
  });
351
367
  const approvals = got.kind === 'value' ? { read: 'ok', body: got.value } : { read: 'failed' };
352
- return replayedApprovalDisposition(ev, { preamble: ctx.led.preambleApprovals(), approvals, settled: ctx.led.settledApprovals() });
368
+ return replayedApprovalDisposition(ev, { preamble: ctx.led.preambleApprovals(), approvals });
353
369
  }
354
370
  function routeToolStart(ev, callId, led) {
355
371
  led.noteStart(callId, ev);
@@ -382,15 +398,20 @@ function routeToolEnd(ev, callId, led) {
382
398
  }
383
399
  function routeSuspended(ev, ctx) {
384
400
  const gatedCallId = parkGatedCallId(ev);
385
- if (ev.gate && isAskToolLoose(ev.gate.toolName) && ctx.taskId.current) {
401
+ const arm = parkGateArmOf(ev.gate);
402
+ if (arm === 'ask' && ctx.taskId.current) {
386
403
  ctx.led.noteParkGate({ fsOrShellFamily: false });
387
404
  return { kind: 'park', gate: 'ask', ...(gatedCallId !== undefined ? { gatedCallId } : {}) };
388
405
  }
389
- if (ev.gate &&
390
- isToolApprovalGate(ev.gate) &&
391
- ctx.taskId.current) {
392
- ctx.led.noteParkGate({ fsOrShellFamily: parkFamilyEvidence(ctx.led, ev.gate.toolName, gatedCallId) });
393
- return { kind: 'park', gate: 'fs', ...(gatedCallId !== undefined ? { gatedCallId } : {}) };
406
+ if (arm === 'fs' && ctx.taskId.current) {
407
+ const gateToolName = ev.gate?.toolName;
408
+ ctx.led.noteParkGate({ fsOrShellFamily: parkFamilyEvidence(ctx.led, gateToolName, gatedCallId) });
409
+ return {
410
+ kind: 'park',
411
+ gate: 'fs',
412
+ ...(gatedCallId !== undefined ? { gatedCallId } : {}),
413
+ ...(typeof gateToolName === 'string' && gateToolName !== '' ? { toolName: gateToolName } : {}),
414
+ };
394
415
  }
395
416
  return { kind: 'yield', events: [ev] };
396
417
  }
@@ -401,7 +422,13 @@ function routeDone(ev, ctx) {
401
422
  if (park !== null) {
402
423
  ctx.taskId.current = ctx.taskId.current ?? park.taskId;
403
424
  led.noteParkGate({ fsOrShellFamily: park.gate === 'fs' && parkFamilyEvidence(led, park.toolName, gatedCallId) });
404
- return { kind: 'park', gate: park.gate, pendingDone: ev, ...(gatedCallId !== undefined ? { gatedCallId } : {}) };
425
+ return {
426
+ kind: 'park',
427
+ gate: park.gate,
428
+ pendingDone: ev,
429
+ ...(gatedCallId !== undefined ? { gatedCallId } : {}),
430
+ ...(park.toolName !== undefined && park.toolName !== '' ? { toolName: park.toolName } : {}),
431
+ };
405
432
  }
406
433
  const events = [...flushHeldWithInterruptRewrite(led, { terminal: ev, signal: ctx.signal })];
407
434
  const r = ev.result;
@@ -16,9 +16,6 @@ export interface AskAnsweredOutput {
16
16
  export declare function durableSeqOf(ev: object): string | undefined;
17
17
  export declare function hasLedgerPositionKey(ev: object): boolean;
18
18
  export declare const PREAMBLE_APPROVALS_MAX_ENTRIES = 4096;
19
- export declare const APPROVAL_SETTLED_HOWS: readonly ["answered", "interrupted", "closed_by_engine"];
20
- export type ApprovalSettledHow = (typeof APPROVAL_SETTLED_HOWS)[number];
21
- export declare const SETTLED_APPROVALS_MAX_ENTRIES = 4096;
22
19
  export interface GateLedger {
23
20
  noteSeq(ev: AgentEvent): void;
24
21
  lastSeq(): string | undefined;
@@ -26,8 +23,6 @@ export interface GateLedger {
26
23
  notePreambleApproval(approvalId: string): void;
27
24
  preambleApprovals(): ReadonlySet<string>;
28
25
  beginStreamSegment(): void;
29
- noteApprovalSettled(approvalId: string, how: ApprovalSettledHow): void;
30
- settledApprovals(): ReadonlyMap<string, ApprovalSettledHow>;
31
26
  trackLiveCard(phaseOf: () => 'card' | 'respond', handled: Promise<void>): void;
32
27
  answeringLiveCards(): Promise<void>[];
33
28
  liveCardsSettled(): Promise<void>;
@@ -13,8 +13,6 @@ export function hasLedgerPositionKey(ev) {
13
13
  return (id !== undefined && id !== null) || (seq !== undefined && seq !== null);
14
14
  }
15
15
  export const PREAMBLE_APPROVALS_MAX_ENTRIES = 4096;
16
- export const APPROVAL_SETTLED_HOWS = Object.freeze(['answered', 'interrupted', 'closed_by_engine']);
17
- export const SETTLED_APPROVALS_MAX_ENTRIES = 4096;
18
16
  export const START_ARGS_MAX_ENTRIES = 256;
19
17
  function normalizeDenyAttribution(a) {
20
18
  if (a === undefined)
@@ -90,7 +88,6 @@ export function createGateLedger() {
90
88
  let denyStampAttribution;
91
89
  let seq;
92
90
  const preambleApprovalIds = new Set();
93
- const settledApprovalHows = new Map();
94
91
  const liveCards = new Set();
95
92
  return {
96
93
  noteSeq(ev) {
@@ -124,24 +121,6 @@ export function createGateLedger() {
124
121
  beginStreamSegment() {
125
122
  preambleApprovalIds.clear();
126
123
  },
127
- noteApprovalSettled(approvalId, how) {
128
- if (typeof approvalId !== 'string' || approvalId === '')
129
- return;
130
- if (!APPROVAL_SETTLED_HOWS.includes(how))
131
- return;
132
- if (settledApprovalHows.has(approvalId))
133
- return;
134
- settledApprovalHows.set(approvalId, how);
135
- while (settledApprovalHows.size > SETTLED_APPROVALS_MAX_ENTRIES) {
136
- const oldest = settledApprovalHows.keys().next();
137
- if (oldest.done === true)
138
- break;
139
- settledApprovalHows.delete(oldest.value);
140
- }
141
- },
142
- settledApprovals() {
143
- return settledApprovalHows;
144
- },
145
124
  trackLiveCard(phaseOf, handled) {
146
125
  const entry = { phaseOf, handled };
147
126
  liveCards.add(entry);
@@ -3,7 +3,7 @@ import { eventSeq } from '../adapter/types.js';
3
3
  import { hostLog } from '../host.js';
4
4
  import { invokeHostCallbackIsolated } from '../hostCallbackGuard.js';
5
5
  import { abortableSleep } from '../abortableSleep.js';
6
- import { readOwnDataValue } from '../ownKey.js';
6
+ import { ownDataField, readOwnDataValue } from '../ownKey.js';
7
7
  import { THROWN_SLOT_UNREADABLE, readBlockedBy, readThrownSlot, thrownIsInstanceOf, wireFailureTextsOf } from '../wireFailureShape.js';
8
8
  import { RESUME_POLICY_FOLD_CODE } from '../engineErrorCodes.js';
9
9
  import { suspendedReopenOf } from './suspendedReopen.js';
@@ -55,7 +55,13 @@ export class HitlSafetyError extends Error {
55
55
  export function hitlSafetyCodeOf(e) {
56
56
  if (!thrownIsInstanceOf(e, HitlSafetyError))
57
57
  return undefined;
58
- const raw = readThrownSlot(e, 'code');
58
+ let raw;
59
+ try {
60
+ raw = ownDataField(e, 'code');
61
+ }
62
+ catch {
63
+ return undefined;
64
+ }
59
65
  return typeof raw === 'string' && GATE_FAILURE_CODES.includes(raw) ? raw : undefined;
60
66
  }
61
67
  const _gateCurrentPendingReadonlyPin = true;
@@ -88,9 +94,17 @@ export function readWireErrorCode(e) {
88
94
  export function readWireErrorCodeReading(e) {
89
95
  if (e === null || e === undefined)
90
96
  return { state: 'absent' };
91
- const raw = readThrownSlot(e, 'errorCode');
92
- if (raw === THROWN_SLOT_UNREADABLE)
97
+ let raw;
98
+ try {
99
+ if (typeof e === 'object' || typeof e === 'function') {
100
+ raw = ownDataField(e, 'errorCode');
101
+ if (raw === undefined && !Object.hasOwn(e, 'errorCode'))
102
+ void e.errorCode;
103
+ }
104
+ }
105
+ catch {
93
106
  return { state: 'unreadable' };
107
+ }
94
108
  return typeof raw === 'string' && raw.length > 0 ? { state: 'code', code: raw } : { state: 'absent' };
95
109
  }
96
110
  export function readWireCodes(e) {
@@ -1,6 +1,7 @@
1
1
  import { putOwnKey, readOwnDataValue } from '../ownKey.js';
2
2
  import { DecideTransportRetryExhaustedError, GATE_FAILURE_CODES, HitlBridge, NO_QUESTION_OVERLAY_REASON, findPendingForTask, hitlSafetyCodeOf, isNoDecisionSurfaceReason, readDecideCurrentPending, readWireCodes, } from './hitlBridge.js';
3
- import { DECIDE_WORKFLOW_PARK_FORKED, DECIDE_WORKFLOW_PARKS_UNREADABLE, PARKED_RESUME_STARTUP_FAILED, RESUME_POLICY_FOLD_CODE, isRefusedParkCode, refusalSaysStillPending } from '../engineErrorCodes.js';
3
+ import { DECIDE_WORKFLOW_PARK_FORKED, DECIDE_WORKFLOW_PARKS_UNREADABLE, PARKED_RESUME_STARTUP_FAILED, RESUME_POLICY_FOLD_CODE, RESUME_REOPEN_CODES, RESUME_RETRY_LATER_CODES, isRefusedParkCode, refusalSaysStillPending } from '../engineErrorCodes.js';
4
+ import { RESUME_REFUSAL_CODES } from '../resumeRefusalCopy.js';
4
5
  import { readDecisionRefusalAsk } from './decisionRefusal.js';
5
6
  import { publishQuestionFrame, registerLocalQuestionResponder, hasQuestionOverlay, } from '../liveQuestionStore.js';
6
7
  import { hostLog } from '../host.js';
@@ -45,11 +46,14 @@ export function isGateStandingErrorCode(code, retriable) {
45
46
  return (code === RESUME_POLICY_FOLD_CODE ||
46
47
  code === 'corrupt' ||
47
48
  (isRefusedParkCode(code) && retriable === true) ||
49
+ (typeof code === 'string' && RESUME_REOPEN_CODES.includes(code) && retriable === true) ||
48
50
  code === DECIDE_WORKFLOW_PARKS_UNREADABLE ||
49
51
  code === DECIDE_WORKFLOW_PARK_FORKED);
50
52
  }
51
53
  export function isCodeClassifiedGateFailure(code, retriable) {
52
- return isGateStandingErrorCode(code, retriable) || code === PARKED_RESUME_STARTUP_FAILED;
54
+ return (isGateStandingErrorCode(code, retriable) ||
55
+ code === PARKED_RESUME_STARTUP_FAILED ||
56
+ (typeof code === 'string' && (RESUME_RETRY_LATER_CODES.includes(code) || RESUME_REFUSAL_CODES.includes(code))));
53
57
  }
54
58
  export function toAnsweredOutput(questions, answer) {
55
59
  const answers = {};
@@ -189,7 +193,7 @@ async function surfaceParkGate(park, ctx, gatedCallId, onPresented) {
189
193
  ...(onPresented ? { onPresented } : {}),
190
194
  ...(deps.onDecideOperation ? { onDecideOperation: deps.onDecideOperation } : {}),
191
195
  ...(decidedByReading !== undefined ? { approvalDecidedBy: decidedByReading } : {}),
192
- }, taskId, argsByCallOf(led), ctx.signal, gatedCallId);
196
+ }, taskId, argsByCallOf(led), ctx.signal, gatedCallId, park.toolName);
193
197
  const outcomeDenied = 'denied' in outcome ? outcome.denied : undefined;
194
198
  if (outcome.kind === 'decided' && outcomeDenied === true && outcome.gatedCallId) {
195
199
  const denySettledBy = 'denySettledBy' in outcome ? outcome.denySettledBy : undefined;
@@ -1,4 +1,4 @@
1
- import { type ApprovalSettledHow } from './gateLedger.js';
1
+ import { type ApprovalSettledHow } from './approvalHolds.js';
2
2
  import { type ApprovalsListEnvelope, type CrashConvergedRow } from './crashConverged.js';
3
3
  export type ReplayedApprovalDisposition = {
4
4
  readonly kind: 'live';
@@ -20,9 +20,8 @@ export interface ReplayPendingBasis {
20
20
  } | {
21
21
  readonly read: 'failed';
22
22
  };
23
- readonly settled?: ReadonlyMap<string, ApprovalSettledHow>;
24
23
  }
25
- export declare function settledApprovalDisposition(frame: object, settled: ReplayPendingBasis['settled']): ReplayedApprovalDisposition | undefined;
24
+ export declare function settledApprovalDisposition(frame: object): ReplayedApprovalDisposition | undefined;
26
25
  export declare function replayedApprovalDisposition(frame: object, basis: ReplayPendingBasis): ReplayedApprovalDisposition;
27
26
  export declare function replayedApprovalClosesCardFrame(disposition: ReplayedApprovalDisposition | null | undefined): boolean;
28
27
  export declare function replayedApprovalSentence(disposition: ReplayedApprovalDisposition | undefined, opts?: {
@@ -1,4 +1,5 @@
1
- import { APPROVAL_SETTLED_HOWS, hasLedgerPositionKey } from './gateLedger.js';
1
+ import { hasLedgerPositionKey } from './gateLedger.js';
2
+ import { anyApprovalSettled, settledApprovalOf } from './approvalHolds.js';
2
3
  import { readLivePendingRows } from './livePendingAsk.js';
3
4
  import { projectCrashConverged } from './crashConverged.js';
4
5
  import { quoteUntrustedForSentence } from '../displayUntrusted.js';
@@ -23,15 +24,12 @@ function crashConvergedFactsOf(body, approvalId) {
23
24
  }
24
25
  return undefined;
25
26
  }
26
- export function settledApprovalDisposition(frame, settled) {
27
+ export function settledApprovalDisposition(frame) {
27
28
  try {
28
- if (typeof settled !== 'object' || settled === null || typeof settled.get !== 'function')
29
+ if (!anyApprovalSettled())
29
30
  return undefined;
30
- const id = approvalIdOf(frame);
31
- if (id === undefined)
32
- return undefined;
33
- const how = settled.get(id);
34
- return typeof how === 'string' && APPROVAL_SETTLED_HOWS.includes(how) ? decidedSettled(how) : undefined;
31
+ const entry = settledApprovalOf(approvalIdOf(frame));
32
+ return entry === undefined ? undefined : decidedSettled(entry.how);
35
33
  }
36
34
  catch {
37
35
  return undefined;
@@ -48,14 +46,7 @@ export function replayedApprovalDisposition(frame, basis) {
48
46
  catch {
49
47
  return unknown('unreadable_frame');
50
48
  }
51
- let settledBasis;
52
- try {
53
- settledBasis = typeof basis === 'object' && basis !== null ? basis.settled : undefined;
54
- }
55
- catch {
56
- settledBasis = undefined;
57
- }
58
- const early = settledApprovalDisposition(frame, settledBasis);
49
+ const early = settledApprovalDisposition(frame);
59
50
  if (early !== undefined)
60
51
  return early;
61
52
  try {
@@ -15,7 +15,6 @@ export interface SessionPolicyDeliverability {
15
15
  export interface SessionPolicyDeliverableOptions {
16
16
  readonly roster?: ToolRosterView;
17
17
  }
18
- export { isEngineRefusedToolName } from '../engineRefusedToolName.js';
19
18
  export declare function sessionPolicyDeliverable(behavior: 'deny' | 'ask', rules: readonly string[], opts?: SessionPolicyDeliverableOptions): SessionPolicyDeliverability;
20
19
  export declare function sessionPolicyWithheldNotice(why: SessionPolicyWithheldWhy): string;
21
20
  export declare function legacyToolNameFailureNoteOf(code: string | undefined): string | undefined;
@@ -3,10 +3,8 @@ import { rosterMountedNames } from '../rosterMountedNames.js';
3
3
  import { ruleCompileVerdict } from '../ruleCompileVerdict.js';
4
4
  import { ruleToolNameVerdictOf } from '../protocolSegment.js';
5
5
  import { PREFIXES_IN_PROSE, REFUSED_NAME_CLASSES, REFUSED_NAME_FIX, RULES_LEGACY_TOOL_NAME_WRITE_NOTE } from './refusedToolNameProse.js';
6
- import { CORE_PROTOCOL_PREFIXES, CORE_RETIRED_TOOL_CURRENT_NAMES } from '../generated/toolNameTables.js';
7
- import { isEngineRefusedToolName } from '../engineRefusedToolName.js';
6
+ import { CORE_PROTOCOL_PREFIXES } from '../generated/toolNameTables.js';
8
7
  const COVERING_NAMESPACE_PREFIXES = CORE_PROTOCOL_PREFIXES;
9
- const ENGINE_RETIRED_TOOL_NAMES = CORE_RETIRED_TOOL_CURRENT_NAMES;
10
8
  const WITHHELD_NOTICE = {
11
9
  ask_no_bucket: 'Not written to this session’s rule record: that record only holds rules that block outright, and this rule asks before running instead — recording it as a block would change what it means.',
12
10
  qualified_deny: 'Not written to this session’s rule record: that record holds whole tool names and command names only, and this rule has a part in parentheses it cannot carry — recording just the name could block more than this rule does.',
@@ -37,11 +35,8 @@ function withheldWhyOf(rule) {
37
35
  }
38
36
  if (rule.trim() !== rule)
39
37
  return 'not_a_tool_name';
40
- if (isEngineRefusedToolName(rule))
41
- return 'legacy_tool_name';
42
38
  return undefined;
43
39
  }
44
- export { isEngineRefusedToolName } from '../engineRefusedToolName.js';
45
40
  function suppliedRosterNames(opts) {
46
41
  if (opts === undefined || opts === null)
47
42
  return 'absent';
@@ -95,29 +90,32 @@ export function sessionPolicyDeliverable(behavior, rules, opts) {
95
90
  continue;
96
91
  }
97
92
  let why = withheldWhyOf(r);
93
+ let currentName;
98
94
  if (why === undefined) {
99
- const grammar = ruleCompileVerdict(r, 'deny').kind;
100
- if (grammar === 'unknown')
95
+ const verdict = ruleToolNameVerdictOf(r);
96
+ if (verdict.kind === 'unknown')
101
97
  return unreadable();
102
- if (grammar === 'refused')
98
+ if (verdict.kind === 'retired' || verdict.kind === 'unprefixed_namespace') {
99
+ why = 'legacy_tool_name';
100
+ if (verdict.kind === 'retired')
101
+ currentName = verdict.currentName;
102
+ }
103
+ else if (verdict.kind === 'unmintable_segment')
103
104
  why = 'not_a_tool_name';
104
105
  }
105
- if (why === undefined && COVERING_NAMESPACE_PREFIXES.some((p) => r.startsWith(p))) {
106
- const verdict = ruleToolNameVerdictOf(r);
107
- if (verdict.kind === 'unknown')
106
+ if (why === undefined) {
107
+ const grammar = ruleCompileVerdict(r, 'deny').kind;
108
+ if (grammar === 'unknown')
108
109
  return unreadable();
109
- if (verdict.kind === 'unmintable_segment')
110
+ if (grammar === 'refused')
110
111
  why = 'not_a_tool_name';
111
- else if (verdict.kind === 'retired' || verdict.kind === 'unprefixed_namespace')
112
- why = 'legacy_tool_name';
113
112
  }
114
113
  if (why === undefined && mounted !== undefined && !mounted.has(r))
115
114
  why = 'not_in_roster';
116
115
  if (why === undefined)
117
116
  exact.push(r);
118
117
  else {
119
- const currentName = why === 'legacy_tool_name' ? ENGINE_RETIRED_TOOL_NAMES.get(r) : undefined;
120
- withheld.push(typeof currentName === 'string' ? { rule: r, why, currentName } : { rule: r, why });
118
+ withheld.push(why === 'legacy_tool_name' && currentName !== undefined ? { rule: r, why, currentName } : { rule: r, why });
121
119
  }
122
120
  }
123
121
  if (withheld.length > 0 || exact.length === 0)
@@ -132,6 +132,8 @@ export type SessionPolicyRemovalOutcome = {
132
132
  } | {
133
133
  kind: 'nothing_to_remove';
134
134
  rev: number;
135
+ } | {
136
+ kind: 'judge_failed';
135
137
  } | {
136
138
  kind: 'loosen_forbidden';
137
139
  message: string;