@sema-agent/client-core 0.95.0 → 0.97.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.
Files changed (233) hide show
  1. package/CHANGELOG.md +269 -0
  2. package/README.md +61 -31
  3. package/dist/adapt/arms.js +7 -1
  4. package/dist/adapt/toolCards.d.ts +1 -0
  5. package/dist/adapt/toolCards.js +16 -3
  6. package/dist/adapt/wireShapes.js +2 -16
  7. package/dist/adapter/activeRunSelfHeal.d.ts +4 -2
  8. package/dist/adapter/activeRunSelfHeal.js +32 -6
  9. package/dist/adapter/downstream/eventToSdkMessage.js +11 -3
  10. package/dist/adapter/downstream/terminalToSdkResult.js +14 -11
  11. package/dist/adapter/runStream.js +30 -47
  12. package/dist/agentSession/backgroundView.js +2 -15
  13. package/dist/agentSession/engineAgentRegistryRead.js +5 -4
  14. package/dist/agentSession/engineSessionBackgroundStop.js +22 -15
  15. package/dist/agentsWireCaps.d.ts +1 -1
  16. package/dist/agentsWireCaps.js +29 -12
  17. package/dist/approvalDecidedByCapability.d.ts +2 -0
  18. package/dist/approvalDecidedByCapability.js +0 -1
  19. package/dist/approvalsStreamLiveCapability.d.ts +2 -0
  20. package/dist/approvalsStreamLiveCapability.js +3 -2
  21. package/dist/attachmentSeatCapability.d.ts +2 -0
  22. package/dist/attachmentSeatCapability.js +0 -1
  23. package/dist/callerCwdCapability.d.ts +2 -4
  24. package/dist/callerCwdCapability.js +0 -7
  25. package/dist/centerWiringCapability.d.ts +2 -4
  26. package/dist/centerWiringCapability.js +4 -9
  27. package/dist/classifierVerdictWire.js +4 -16
  28. package/dist/clientSlice.js +1 -1
  29. package/dist/cloudConfigWireCaps.d.ts +4 -4
  30. package/dist/cloudConfigWireCaps.js +241 -85
  31. package/dist/coreValuePorts.d.ts +11 -7
  32. package/dist/coreValuePorts.js +5 -8
  33. package/dist/credentialProvenance.d.ts +28 -0
  34. package/dist/credentialProvenance.js +76 -0
  35. package/dist/decideFailureNote.js +3 -1
  36. package/dist/decideReceipt.js +7 -10
  37. package/dist/declared/supportFloorDeclared.js +3 -3
  38. package/dist/deviceExecutorManagementCapability.d.ts +2 -0
  39. package/dist/deviceExecutorManagementCapability.js +3 -2
  40. package/dist/displayUntrusted.d.ts +10 -3
  41. package/dist/displayUntrusted.js +371 -60
  42. package/dist/engineCapReader.d.ts +8 -2
  43. package/dist/engineCapReader.js +15 -7
  44. package/dist/engineCapsCache.d.ts +17 -3
  45. package/dist/engineCapsCache.js +268 -43
  46. package/dist/engineDirectory.d.ts +79 -0
  47. package/dist/engineDirectory.js +186 -0
  48. package/dist/engineErrorCodes.d.ts +17 -1
  49. package/dist/engineErrorCodes.js +46 -16
  50. package/dist/engineNoticeCodes.d.ts +17 -0
  51. package/dist/engineNoticeCodes.js +54 -1
  52. package/dist/executionLaneCapability.d.ts +2 -0
  53. package/dist/executionLaneCapability.js +3 -2
  54. package/dist/fileHistoryCaptureCapability.d.ts +16 -0
  55. package/dist/fileHistoryCaptureCapability.js +98 -2
  56. package/dist/fileHistoryLegNotice.js +4 -0
  57. package/dist/fleet/bgSubagentRow.d.ts +15 -0
  58. package/dist/fleet/bgSubagentRow.js +67 -0
  59. package/dist/fleet/fleetLedger.d.ts +1 -0
  60. package/dist/fleet/fleetLedger.js +164 -126
  61. package/dist/fleet/fleetProjection.d.ts +1 -0
  62. package/dist/fleet/fleetProjection.js +10 -3
  63. package/dist/fleetTaskDesc.js +4 -17
  64. package/dist/gateOutcome.d.ts +12 -1
  65. package/dist/gateOutcome.js +56 -1
  66. package/dist/gateVocabulary.d.ts +2 -2
  67. package/dist/gateVocabulary.js +4 -3
  68. package/dist/generated/engineAskFaceTables.js +1 -1
  69. package/dist/generated/engineFactTables.d.ts +5 -3
  70. package/dist/generated/engineFactTables.js +17 -4
  71. package/dist/generated/engineNoticeTables.js +12 -3
  72. package/dist/generated/sdkFactTables.d.ts +2 -0
  73. package/dist/generated/sdkFactTables.js +7 -0
  74. package/dist/generated/settingsSchemaFns.d.ts +3 -0
  75. package/dist/generated/settingsSchemaFns.js +53 -0
  76. package/dist/generated/toolNameTables.d.ts +1 -1
  77. package/dist/generated/toolNameTables.js +1 -42
  78. package/dist/hitl/approvalDecisionNoteAudit.js +2 -2
  79. package/dist/hitl/approvalEndingCause.d.ts +2 -0
  80. package/dist/hitl/approvalEndingCause.js +26 -21
  81. package/dist/hitl/approvalHolds.d.ts +16 -1
  82. package/dist/hitl/approvalHolds.js +52 -12
  83. package/dist/hitl/askGateWire.js +1 -0
  84. package/dist/hitl/askParkRowRouting.js +1 -1
  85. package/dist/hitl/automaticAnswerVerdict.d.ts +1 -1
  86. package/dist/hitl/automaticAnswerVerdict.js +13 -10
  87. package/dist/hitl/decisionConflict.js +4 -5
  88. package/dist/hitl/decisionRefusal.d.ts +8 -0
  89. package/dist/hitl/decisionRefusal.js +55 -14
  90. package/dist/hitl/frameRouter.d.ts +3 -1
  91. package/dist/hitl/frameRouter.js +58 -39
  92. package/dist/hitl/gateLedger.d.ts +0 -5
  93. package/dist/hitl/gateLedger.js +0 -21
  94. package/dist/hitl/hitlBridge.d.ts +6 -2
  95. package/dist/hitl/hitlBridge.js +46 -11
  96. package/dist/hitl/localAllowRule.d.ts +1 -0
  97. package/dist/hitl/localAllowRule.js +2 -2
  98. package/dist/hitl/noAllowCause.d.ts +2 -1
  99. package/dist/hitl/noAllowCause.js +3 -2
  100. package/dist/hitl/parkResolver.d.ts +1 -0
  101. package/dist/hitl/parkResolver.js +14 -56
  102. package/dist/hitl/parkRowBirthWait.d.ts +1 -0
  103. package/dist/hitl/parkRowBirthWait.js +2 -2
  104. package/dist/hitl/planReviewWire.d.ts +1 -0
  105. package/dist/hitl/planReviewWire.js +98 -20
  106. package/dist/hitl/replayedApproval.d.ts +3 -3
  107. package/dist/hitl/replayedApproval.js +21 -16
  108. package/dist/hitl/sessionPolicyDeliverable.d.ts +0 -1
  109. package/dist/hitl/sessionPolicyDeliverable.js +17 -17
  110. package/dist/hitl/sessionPolicyWire.d.ts +2 -0
  111. package/dist/hitl/sessionPolicyWire.js +15 -3
  112. package/dist/hitl/standingRows.d.ts +19 -0
  113. package/dist/hitl/standingRows.js +148 -0
  114. package/dist/hitl/suspendedReopen.js +2 -1
  115. package/dist/hitl/toolApprovalWire.d.ts +22 -10
  116. package/dist/hitl/toolApprovalWire.js +286 -47
  117. package/dist/hookMatcherVerdict.d.ts +1 -9
  118. package/dist/hookMatcherVerdict.js +21 -61
  119. package/dist/hooksWireCaps.js +2 -2
  120. package/dist/hostCallbackGuard.d.ts +1 -0
  121. package/dist/hostCallbackGuard.js +6 -0
  122. package/dist/index.d.ts +26 -12
  123. package/dist/index.js +20 -10
  124. package/dist/liveModelCatalog.d.ts +13 -0
  125. package/dist/liveModelCatalog.js +56 -0
  126. package/dist/mcpProbeCapability.d.ts +2 -4
  127. package/dist/mcpProbeCapability.js +3 -8
  128. package/dist/mcpWireCaps.d.ts +1 -0
  129. package/dist/mcpWireCaps.js +4 -1
  130. package/dist/memoryComplianceCapability.d.ts +2 -4
  131. package/dist/memoryComplianceCapability.js +3 -8
  132. package/dist/memoryOriginCapability.d.ts +2 -4
  133. package/dist/memoryOriginCapability.js +3 -8
  134. package/dist/memorySpecWire.js +2 -2
  135. package/dist/modelIdentityResolvability.d.ts +2 -2
  136. package/dist/modelIdentityResolvability.js +14 -5
  137. package/dist/noticePresentation.d.ts +68 -0
  138. package/dist/noticePresentation.js +247 -0
  139. package/dist/outputStyleSeatCapability.d.ts +2 -1
  140. package/dist/outputStyleSeatCapability.js +0 -4
  141. package/dist/ownKey.d.ts +2 -0
  142. package/dist/ownKey.js +18 -0
  143. package/dist/peerFrames.js +13 -9
  144. package/dist/peerLaneCapability.d.ts +2 -0
  145. package/dist/peerLaneCapability.js +3 -2
  146. package/dist/permissionModesCapability.d.ts +2 -4
  147. package/dist/permissionModesCapability.js +0 -7
  148. package/dist/permissionRuleIssue.js +0 -3
  149. package/dist/permissionRulesWriteCapability.d.ts +2 -0
  150. package/dist/permissionRulesWriteCapability.js +3 -2
  151. package/dist/permissionsAllowGrantCapability.d.ts +2 -0
  152. package/dist/permissionsAllowGrantCapability.js +4 -2
  153. package/dist/permissionsDeclaration.d.ts +2 -0
  154. package/dist/permissionsDeclaration.js +72 -59
  155. package/dist/printPermissionOutcome.d.ts +12 -0
  156. package/dist/printPermissionOutcome.js +50 -0
  157. package/dist/printToolResultFrame.d.ts +1 -0
  158. package/dist/printToolResultFrame.js +5 -9
  159. package/dist/promptBlockedCopy.d.ts +5 -0
  160. package/dist/promptBlockedCopy.js +35 -0
  161. package/dist/protocolSegment.d.ts +9 -6
  162. package/dist/protocolSegment.js +31 -21
  163. package/dist/providerRejection.d.ts +4 -0
  164. package/dist/providerRejection.js +75 -14
  165. package/dist/replayBody.d.ts +12 -0
  166. package/dist/replayBody.js +25 -0
  167. package/dist/request/taskRequest.d.ts +1 -4
  168. package/dist/request/taskRequest.js +74 -19
  169. package/dist/resumeRefusalCopy.js +9 -25
  170. package/dist/retryStatus.d.ts +9 -1
  171. package/dist/retryStatus.js +9 -2
  172. package/dist/rewindArchiveCapability.d.ts +3 -13
  173. package/dist/rewindArchiveCapability.js +12 -58
  174. package/dist/rewindArchiveReading.d.ts +17 -0
  175. package/dist/rewindArchiveReading.js +55 -0
  176. package/dist/ruleCompileVerdict.d.ts +9 -1
  177. package/dist/ruleCompileVerdict.js +29 -4
  178. package/dist/runTerminal.d.ts +48 -5
  179. package/dist/runTerminal.js +215 -12
  180. package/dist/sandboxWire.js +13 -0
  181. package/dist/sdkWireTransit.d.ts +2 -1
  182. package/dist/sdkWireTransit.js +1 -0
  183. package/dist/sealedKeyCapability.d.ts +2 -4
  184. package/dist/sealedKeyCapability.js +0 -7
  185. package/dist/seam.js +4 -2
  186. package/dist/seatContract.d.ts +76 -11
  187. package/dist/seatContract.js +222 -27
  188. package/dist/sessionPolicyCapability.d.ts +2 -0
  189. package/dist/sessionPolicyCapability.js +3 -2
  190. package/dist/sessionReadRedactionCapability.d.ts +2 -4
  191. package/dist/sessionReadRedactionCapability.js +0 -7
  192. package/dist/sessionSyncFileHistory.d.ts +4 -0
  193. package/dist/sessionSyncFileHistory.js +66 -0
  194. package/dist/sessionSyncFileHistoryCapability.d.ts +2 -1
  195. package/dist/sessionSyncFileHistoryCapability.js +3 -5
  196. package/dist/skillToolListsCapability.d.ts +2 -1
  197. package/dist/skillToolListsCapability.js +3 -5
  198. package/dist/sqlEngineCapability.d.ts +2 -0
  199. package/dist/sqlEngineCapability.js +4 -3
  200. package/dist/steerPriorityCapability.d.ts +2 -1
  201. package/dist/steerPriorityCapability.js +3 -5
  202. package/dist/storePostureCapability.d.ts +2 -4
  203. package/dist/storePostureCapability.js +4 -9
  204. package/dist/subagent/engineSubagentSteer.js +7 -5
  205. package/dist/subagentContentStore.js +4 -15
  206. package/dist/supportFloor.d.ts +1 -0
  207. package/dist/supportFloor.js +13 -9
  208. package/dist/systemReminderTag.d.ts +1 -0
  209. package/dist/systemReminderTag.js +8 -0
  210. package/dist/toolHistoryBadTurn.js +3 -2
  211. package/dist/toolHistoryMismatch.d.ts +0 -3
  212. package/dist/toolHistoryMismatch.js +3 -7
  213. package/dist/toolResult.d.ts +12 -1
  214. package/dist/toolResult.js +55 -1
  215. package/dist/toolResultContent.d.ts +2 -0
  216. package/dist/toolResultContent.js +63 -0
  217. package/dist/usageAnalytics.js +40 -16
  218. package/dist/userInvokedSkillsCapability.d.ts +2 -1
  219. package/dist/userInvokedSkillsCapability.js +3 -5
  220. package/dist/webSearchBackendCapability.d.ts +2 -0
  221. package/dist/webSearchBackendCapability.js +3 -2
  222. package/dist/wireErrorTriage.d.ts +2 -0
  223. package/dist/wireErrorTriage.js +91 -38
  224. package/dist/wireFailureShape.d.ts +20 -3
  225. package/dist/wireFailureShape.js +128 -72
  226. package/dist/workflowsJournalCapability.d.ts +2 -0
  227. package/dist/workflowsJournalCapability.js +3 -2
  228. package/dist/writeProtectionCapability.d.ts +2 -0
  229. package/dist/writeProtectionCapability.js +3 -2
  230. package/docs/INTEGRATION-CLIENTS.md +1784 -20
  231. package/package.json +5 -5
  232. package/dist/engineRefusedToolName.d.ts +0 -1
  233. package/dist/engineRefusedToolName.js +0 -8
@@ -1,6 +1,8 @@
1
1
  import { hostLog } from '../host.js';
2
2
  import { liveFrameCallKey } from './gateIdentity.js';
3
3
  import { approvalResolutionOf } from './approvalResolution.js';
4
+ export const APPROVAL_SETTLED_HOWS = Object.freeze(['answered', 'interrupted', 'closed_by_engine']);
5
+ export const SETTLED_APPROVALS_MAX_ENTRIES = 4096;
4
6
  const nonEmpty = (v) => typeof v === 'string' && v !== '';
5
7
  export function liveCardHoldFor(who) {
6
8
  if (nonEmpty(who.approvalId))
@@ -19,13 +21,8 @@ export function liveCardHoldFor(who) {
19
21
  }
20
22
  return undefined;
21
23
  }
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;
24
+ export function settledForDurableLane(entry) {
25
+ return entry !== undefined && !entry.parked;
29
26
  }
30
27
  export function liveCardAnsweredHow(o) {
31
28
  return answeredHowOf(approvalResolutionOf(o));
@@ -47,9 +44,43 @@ export async function awaitLiveCardHolder(hold, signal) {
47
44
  finally {
48
45
  unsubscribe();
49
46
  }
50
- return liveCardSettledQuestion(hold, o) ? { ...o, joinedInFlight: true } : undefined;
47
+ const stillHeld = approvalDecisionHolds.inFlight.get(liveFrameCallKey(hold.identity.approvalId)) === hold;
48
+ return stillHeld || settledForDurableLane(settledApprovalOf(hold.identity.approvalId)) ? { ...o, joinedInFlight: true } : undefined;
49
+ }
50
+ export const approvalDecisionHolds = { inFlight: new Map(), settled: new Map(), openReads: new Set(), outcomes: new Map(), clock: 0 };
51
+ export function settledApprovalOf(approvalId) {
52
+ return typeof approvalId === 'string' && approvalId !== '' ? approvalDecisionHolds.outcomes.get(approvalId) : undefined;
53
+ }
54
+ export function clearSettledApprovals() {
55
+ approvalDecisionHolds.outcomes.clear();
56
+ }
57
+ export function anyApprovalSettled() {
58
+ return approvalDecisionHolds.outcomes.size > 0;
59
+ }
60
+ function noteSettled(approvalId, how, parked, outcome) {
61
+ if (typeof approvalId !== 'string' || approvalId === '')
62
+ return;
63
+ if (!APPROVAL_SETTLED_HOWS.includes(how))
64
+ return;
65
+ const t = approvalDecisionHolds.outcomes;
66
+ if (t.has(approvalId))
67
+ return;
68
+ t.set(approvalId, Object.freeze({ how, parked, outcome: Object.freeze({ ...outcome }) }));
69
+ while (t.size > SETTLED_APPROVALS_MAX_ENTRIES) {
70
+ const oldest = t.keys().next();
71
+ if (oldest.done === true)
72
+ break;
73
+ t.delete(oldest.value);
74
+ }
75
+ }
76
+ const ENGINE_CLOSED_OUTCOME = Object.freeze({ decision: 'unresolved', retracted: true });
77
+ export function noteEngineClosedApproval(approvalId, parked) {
78
+ noteSettled(approvalId, 'closed_by_engine', parked, ENGINE_CLOSED_OUTCOME);
79
+ }
80
+ export function settledLiveCardOutcome(approvalId) {
81
+ const e = settledApprovalOf(approvalId);
82
+ return e === undefined ? undefined : { ...e.outcome, joinedInFlight: true };
51
83
  }
52
- export const approvalDecisionHolds = { inFlight: new Map(), settled: new Map(), openReads: new Set(), clock: 0 };
53
84
  export function liveCardHoldOf(key) {
54
85
  const h = approvalDecisionHolds.inFlight.get(key);
55
86
  return h !== undefined && h.lane === 'live' ? h : undefined;
@@ -76,7 +107,7 @@ export function holdLiveCard(identity, callerSignal, present) {
76
107
  if (h.inFlight.get(key) === hold)
77
108
  h.inFlight.delete(key);
78
109
  };
79
- const settle = (give) => {
110
+ const settle = (give, onLanded) => {
80
111
  settled = true;
81
112
  unsubscribe();
82
113
  const trailing = hold.trailing;
@@ -86,7 +117,11 @@ export function holdLiveCard(identity, callerSignal, present) {
86
117
  return;
87
118
  }
88
119
  give();
89
- trailing.then(release, release);
120
+ trailing.then((landed) => {
121
+ if (landed === true)
122
+ onLanded?.();
123
+ release();
124
+ }, release);
90
125
  };
91
126
  let run;
92
127
  try {
@@ -95,7 +130,12 @@ export function holdLiveCard(identity, callerSignal, present) {
95
130
  catch (e) {
96
131
  run = Promise.reject(e);
97
132
  }
98
- run.then((o) => settle(() => resolveOutcome(o)), (e) => settle(() => rejectOutcome(e)));
133
+ run.then((o) => {
134
+ const how = liveCardAnsweredHow(o);
135
+ if (how === 'answered')
136
+ noteSettled(identity.approvalId, how, false, o);
137
+ settle(() => resolveOutcome(o), how === 'interrupted' ? () => noteSettled(identity.approvalId, how, false, o) : undefined);
138
+ }, (e) => settle(() => rejectOutcome(e)));
99
139
  return outcome;
100
140
  }
101
141
  export async function joinLiveCard(hold, signal) {
@@ -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
  }
@@ -50,7 +50,7 @@ export function askParkRowArm(row) {
50
50
  const rowHasToolName = typeof row.toolName === 'string' && row.toolName.trim().length > 0;
51
51
  return askQuestionsFromPending(row) !== null || !rowHasToolName ? 'question' : 'tool-gate';
52
52
  }
53
- const GENERIC_DECISION_GATE_KINDS = ['human', 'policy_ask'];
53
+ const GENERIC_DECISION_GATE_KINDS = ['human'];
54
54
  export function askParkRowStillPending(rows, identity) {
55
55
  return rows.some(r => identity.gatedCallId !== undefined
56
56
  ? (r.toolCallId ?? r.boundCallId ?? undefined) === identity.gatedCallId
@@ -19,7 +19,7 @@ export type AutomaticAnswerVerdict = {
19
19
  readonly kind: 'unknown';
20
20
  readonly why: AutomaticAnswerUnknownWhy;
21
21
  };
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>>;
22
+ export declare const MODE_ARBITRATION: Readonly<Record<"hook" | "write_protection" | "mode" | "rule_unreadable" | "target_unresolved" | "content_question" | "ancestor" | "dangerous_delete" | "unverifiable_delete" | "unverifiable_shell_text" | "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
23
  export declare function foldModeArbitrationRow(classes: Iterable<string>, askFace?: AutomaticAnswerAskFace): CoreModeArbitrationRow;
24
24
  export declare function automaticAnswerVerdict(card: object | null | undefined, lane: AutomaticAnswerLane, facts?: AutomaticAnswerFacts | null): AutomaticAnswerVerdict;
25
25
  export declare function mandatedApprovalDetailOf(card: object | null | undefined): string;
@@ -15,10 +15,10 @@ const ORIGIN_IMPLIES_CLASS = Object.freeze({
15
15
  ask_rule: 'ask_rule',
16
16
  denial_limit_fallback: 'denial_limit_fallback',
17
17
  });
18
- function mandateWordClass(word) {
19
- if (word === 'operator_always')
18
+ function mandateWordClass(raw) {
19
+ if (raw === 'operator_always')
20
20
  return 'shell_floor';
21
- return Object.hasOwn(TABLE, word) ? word : undefined;
21
+ return Object.hasOwn(TABLE, raw) ? raw : undefined;
22
22
  }
23
23
  const ORDINARY_ROW = CORE_MODE_ARBITRATION.ordinary;
24
24
  function bypassImmuneOn(c, face) {
@@ -41,8 +41,9 @@ export function foldModeArbitrationRow(classes, askFace) {
41
41
  let sandboxAdmission = true;
42
42
  let ruleMayClear = true;
43
43
  let hookAskFloor = false;
44
- for (const c of classes) {
45
- if (!Object.hasOwn(TABLE, c))
44
+ for (const raw of classes) {
45
+ const c = raw;
46
+ if (typeof c !== 'string' || !Object.hasOwn(TABLE, c))
46
47
  continue;
47
48
  const row = TABLE[c];
48
49
  any = true;
@@ -130,11 +131,12 @@ export function automaticAnswerVerdict(card, lane, facts) {
130
131
  return UNKNOWN.classes_malformed;
131
132
  if (pair.state === 'absent')
132
133
  return UNKNOWN.classes_absent;
133
- const folded = foldModeArbitrationRow(pair.classes, face);
134
+ const classes = pair.classes;
135
+ const folded = foldModeArbitrationRow(classes, face);
134
136
  let anyKnown = false;
135
137
  let firstBlocking;
136
138
  let anyUnknown = false;
137
- for (const c of pair.classes) {
139
+ for (const c of classes) {
138
140
  if (!Object.hasOwn(TABLE, c)) {
139
141
  anyUnknown = true;
140
142
  continue;
@@ -154,7 +156,7 @@ export function automaticAnswerVerdict(card, lane, facts) {
154
156
  return mustAsk('settings_ask_rule');
155
157
  if (matched !== false)
156
158
  return UNKNOWN.host_not_reported;
157
- const releaseReason = CORE_MODE_RELEASE_REASONS.find((r) => pair.classes.includes(r));
159
+ const releaseReason = CORE_MODE_RELEASE_REASONS.find((r) => classes.includes(r));
158
160
  return releaseReason !== undefined ? Object.freeze({ kind: 'may_answer', releaseReason }) : MAY_ANSWER;
159
161
  }
160
162
  catch {
@@ -168,9 +170,10 @@ export function mandatedApprovalDetailOf(card) {
168
170
  const pair = readAskClassPairState(card);
169
171
  if (pair.state !== 'pair')
170
172
  return mandatedApprovalDetail();
171
- if (pair.classes.some((c) => !Object.hasOwn(TABLE, c)))
173
+ const classes = pair.classes;
174
+ if (classes.some((c) => !Object.hasOwn(TABLE, c)))
172
175
  return mandatedApprovalDetail();
173
- const row = foldModeArbitrationRow(pair.classes);
176
+ const row = foldModeArbitrationRow(classes);
174
177
  if (row.classifierEligible || row.sandboxAdmission)
175
178
  return mandatedApprovalDetail();
176
179
  return MANDATED_NO_AUTOMATIC_CHECK_DETAIL;
@@ -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;
@@ -34,8 +35,6 @@ export function decisionConflictOf(err) {
34
35
  }
35
36
  if (code === RESUME_OUTCOME_INVALID)
36
37
  return field === ANSWER_FIELD ? 'answer_invalid' : undefined;
37
- if (field === ANSWER_FIELD)
38
- return 'answer_invalid';
39
38
  if (field === undefined)
40
39
  return 'row_integrity';
41
40
  return BINDING_SEAT_FIELDS.has(field) ? 'binding_mismatch' : undefined;
@@ -2,6 +2,14 @@ import { type DecisionRefusalConflict } from './decisionConflict.js';
2
2
  export type DecisionRefusalStanding = 'settled-elsewhere' | 'ambiguous' | 'refused-pending';
3
3
  export type { DecisionRefusalConflict } from './decisionConflict.js';
4
4
  export declare function decisionRefusalSaysAskGone(err: unknown): boolean;
5
+ export type DecisionRefusalAskReading = 'settled' | 'not_settled' | 'unreadable';
6
+ interface DecisionRefusalAskFacts {
7
+ readonly reading: DecisionRefusalAskReading;
8
+ readonly gateMoved: boolean;
9
+ readonly wordingHint: boolean;
10
+ }
11
+ export declare function readDecisionRefusalAsk(failure: unknown): DecisionRefusalAskFacts;
12
+ export declare function decisionRefusalAskReading(failure: unknown): DecisionRefusalAskReading;
5
13
  export interface DecisionRefusalClassified {
6
14
  readonly standing: DecisionRefusalStanding;
7
15
  readonly status: number;
@@ -1,26 +1,66 @@
1
- import { refusalSaysStillPending } from '../engineErrorCodes.js';
2
- import { notPendingCauseSaysEnded } from './approvalEndingCause.js';
1
+ import { ASK_GONE, ASK_GONE_PARKED, isDecideAlreadyResolvedCode, isDecideParkMovedCode, refusalRetriableReading, refusalSaysStillPending } from '../engineErrorCodes.js';
2
+ import { notPendingCauseReading } from './approvalEndingCause.js';
3
+ import { GATE_FAILURE_CODES } from './hitlBridge.js';
4
+ import { isAlreadyResolvedGateReason, isCodeClassifiedGateFailure } from './parkResolver.js';
3
5
  import { decisionConflictOf } from './decisionConflict.js';
4
6
  import { readLivePendingRows } from './livePendingAsk.js';
7
+ import { ownDataField } from '../ownKey.js';
5
8
  import { readToolApprovalRespondRefusal } from './toolApprovalWire.js';
6
9
  const ASK_DECIDED_CODE = 'conflict.ask_decided';
7
10
  const TRANSIENT_STATUSES = new Set([408, 425, 429, 502, 503, 504]);
8
11
  const DISPLAYABLE_CODE = /^[A-Za-z0-9._:-]{1,64}$/;
9
12
  export function decisionRefusalSaysAskGone(err) {
13
+ return readDecisionRefusalAsk(err).reading === 'settled';
14
+ }
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
+ });
21
+ export function readDecisionRefusalAsk(failure) {
22
+ if (typeof failure !== 'object' || failure === null)
23
+ return facts('not_settled');
24
+ let flattened, localCode, name, errorCode, status, retriable, text;
10
25
  try {
11
- if (typeof err === 'object' && err !== null && 'code' in err) {
12
- const code = err.code;
13
- if (code === 'no_pending')
14
- return true;
15
- }
16
- const c = classifyDecisionRefusal(err);
17
- if (c?.standing !== 'settled-elsewhere')
18
- return false;
19
- return c.status !== 404 || (typeof err === 'object' && err !== null && notPendingCauseSaysEnded(err));
26
+ const slot = (key) => ownDataField(failure, key);
27
+ if (slot('unreadable') === true)
28
+ return facts('unreadable');
29
+ flattened = slot('kind') === 'failed';
30
+ const closed = (v) => (typeof v === 'string' && GATE_FAILURE_CODES.includes(v) ? v : undefined);
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');
35
+ retriable = refusalRetriableReading(failure);
36
+ text = flattened ? slot('reason') : String(failure);
20
37
  }
21
38
  catch {
22
- return false;
39
+ return facts('unreadable');
23
40
  }
41
+ if (retriable === undefined)
42
+ return facts('unreadable');
43
+ if (localCode !== undefined)
44
+ return facts(localCode === 'no_pending' ? 'settled' : 'not_settled');
45
+ if (name === 'HitlSafetyError')
46
+ return facts('not_settled');
47
+ const code = typeof errorCode === 'string' && errorCode.length > 0 ? errorCode : undefined;
48
+ if (isCodeClassifiedGateFailure(code, retriable))
49
+ return facts('not_settled');
50
+ const st = typeof status === 'number' && Number.isInteger(status) && status >= 400 && status <= 599 ? status : undefined;
51
+ if (code === ASK_DECIDED_CODE || code === ASK_GONE || (st === 410 && code !== ASK_GONE_PARKED))
52
+ return facts('settled');
53
+ if (st === 404 && notPendingCauseReading(failure) === 'ended')
54
+ return facts('settled');
55
+ if (code === undefined && name === PROTOCOL_ERROR_NAMES.askDecided)
56
+ return facts('settled');
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)
59
+ return facts('not_settled', gateMoved);
60
+ return facts('not_settled', false, isAlreadyResolvedGateReason(text));
61
+ }
62
+ export function decisionRefusalAskReading(failure) {
63
+ return readDecisionRefusalAsk(failure).reading;
24
64
  }
25
65
  export function classifyDecisionRefusal(err) {
26
66
  const r = readToolApprovalRespondRefusal(err);
@@ -29,12 +69,13 @@ export function classifyDecisionRefusal(err) {
29
69
  return undefined;
30
70
  const code = r?.errorCode;
31
71
  const errorCode = code !== undefined && DISPLAYABLE_CODE.test(code) ? code : undefined;
32
- const standing = status === 404 || status === 410 || (status === 409 && code === ASK_DECIDED_CODE)
72
+ const standing = readDecisionRefusalAsk(err).reading === 'settled'
33
73
  ? 'settled-elsewhere'
34
74
  : status >= 500 && status !== 501
35
75
  ? 'ambiguous'
36
76
  : 'refused-pending';
37
- const transient = TRANSIENT_STATUSES.has(status) || (typeof err === 'object' && err !== null && refusalSaysStillPending(err));
77
+ const transient = TRANSIENT_STATUSES.has(status) ||
78
+ (typeof err === 'object' && err !== null && (refusalSaysStillPending(err) || (status === 404 && notPendingCauseReading(err) === 'other_replica')));
38
79
  const conflict = status === 409 ? decisionConflictOf(err) : undefined;
39
80
  return Object.freeze({
40
81
  standing,
@@ -17,7 +17,6 @@ export interface PolicyDenyReasonFacts {
17
17
  export declare function policyDenyReason(facts: PolicyDenyReasonFacts): string;
18
18
  export declare const HITL_INTERRUPT_MESSAGE_FOR_TOOL_USE = "[Request interrupted by user for tool use]";
19
19
  export declare const ENGINE_ABORT_TOOL_RESULT = "Operation aborted";
20
- export declare function toolEndOutputText(output: unknown): string | undefined;
21
20
  export interface ParkReattachNotice {
22
21
  attempt: number;
23
22
  max: number;
@@ -41,6 +40,7 @@ export interface GatePark {
41
40
  gate: GateKind;
42
41
  pendingDone?: AgentEvent | undefined;
43
42
  gatedCallId?: string | undefined;
43
+ toolName?: string | undefined;
44
44
  }
45
45
  export type FrameAction = {
46
46
  kind: 'yield';
@@ -52,6 +52,7 @@ export type FrameAction = {
52
52
  gate: GateKind;
53
53
  pendingDone?: AgentEvent | undefined;
54
54
  gatedCallId?: string | undefined;
55
+ toolName?: string | undefined;
55
56
  } | {
56
57
  kind: 'end';
57
58
  events: readonly AgentEvent[];
@@ -66,6 +67,7 @@ export interface FrameRouterCtx {
66
67
  signal?: AbortSignal | undefined;
67
68
  }
68
69
  export declare function isAskTool(toolName: string | undefined): boolean;
70
+ export declare function parkGateArmOf(gate: unknown): GateKind | null;
69
71
  export declare function isHostProgressFrame(ev: AgentEvent): boolean;
70
72
  interface HeldFlushInterruptEvidence {
71
73
  terminal?: AgentEvent | undefined;
@@ -1,11 +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
+ import { toolEndOutputText } from '../toolResultContent.js';
5
6
  import { GATE_PARKED_ERROR_CODE } from '../engineErrorCodes.js';
6
7
  import { readRunTerminal, runTerminalCode, runTerminalGateKind, runTerminalGateToolName } from '../runTerminal.js';
7
8
  import { surfaceForCurrentSession, surfaceReplayedApprovalListUnreadable } from './hitlHostSurface.js';
8
- import { liveCardAnsweredHow, liveCardHoldOf, supersedeLiveCard } from './approvalHolds.js';
9
+ import { liveCardHoldOf, noteEngineClosedApproval, supersedeLiveCard } from './approvalHolds.js';
9
10
  import { approvalCompleteParked } from './approvalCompleteParked.js';
10
11
  import { liveFrameCallKey } from './gateIdentity.js';
11
12
  import { SEMA_DENIAL_KIND_KEY, hasLedgerPositionKey } from './gateLedger.js';
@@ -14,6 +15,7 @@ import { settleWithinDeadline } from '../abortableSleep.js';
14
15
  import { ccToolDenialKindForSettledBy } from '../gateVocabulary.js';
15
16
  import { REJECT_MESSAGE } from '../adapt/wireShapes.js';
16
17
  import { RUN_CANCELLED_CODE } from '../runCancelContext.js';
18
+ import { durableDecideLegOf } from '../adapter/activeRunSelfHeal.js';
17
19
  export const HITL_REJECT_MESSAGE = REJECT_MESSAGE;
18
20
  export const HITL_POLICY_DENY_MESSAGE = 'Permission for this tool use was denied: it requires interactive approval, and permission prompts are ' +
19
21
  'not available in this session. The action was NOT performed. Do not claim it succeeded, and do not retry ' +
@@ -23,7 +25,7 @@ export function policyDenyReason(facts) {
23
25
  const one = typeof facts.toolName === 'string' && SENTENCE_TOOL_NAME.test(facts.toolName) ? `this one "${facts.toolName}" call` : 'this one call';
24
26
  const flag = typeof facts.allowRuleFlag === 'string' && SENTENCE_TOOL_NAME.test(facts.allowRuleFlag.replace(/^--?/, '')) ? ` (or ${facts.allowRuleFlag})` : '';
25
27
  const budgetKnob = typeof facts.budgetSetting === 'string' && SENTENCE_TOOL_NAME.test(facts.budgetSetting) ? facts.budgetSetting : undefined;
26
- const cause = facts.cause === 'no_allow_rule' || facts.cause === 'ask_rule' || facts.cause === 'budget' ? facts.cause : 'other';
28
+ const cause = facts.cause === 'no_allow_rule' || facts.cause === 'ask_rule' || facts.cause === 'engine_ask_rule' || facts.cause === 'budget' ? facts.cause : 'other';
27
29
  if (facts.lane === 'dont_ask') {
28
30
  const mode = 'denied by the dontAsk permission mode';
29
31
  switch (cause) {
@@ -31,6 +33,8 @@ export function policyDenyReason(facts) {
31
33
  return `${mode}: ${one} needed approval, no permission rule allowed it, and this mode refuses anything that would ask — calls that need no approval still run; an allow rule in settings${flag} can approve calls like this ahead of time`;
32
34
  case 'ask_rule':
33
35
  return `${mode}: an ask rule matched ${one}, and this mode refuses anything that would ask (an ask rule outranks allow rules) — narrow or remove that ask rule, or use another permission mode to answer it`;
36
+ case 'engine_ask_rule':
37
+ return `${mode}: a rule on the engine side, not one of the user's permission rules, asks about ${one}, and this mode refuses anything that would ask — the user's settings cannot approve it; use another permission mode to answer it`;
34
38
  case 'budget':
35
39
  return `${mode}: ${one} needed approval, and this session's automatic-approval budget is used up, so saved rules no longer approve calls${budgetKnob !== undefined ? ` — raise ${budgetKnob} before launch to change the cap` : ''}`;
36
40
  default:
@@ -44,6 +48,8 @@ export function policyDenyReason(facts) {
44
48
  return `${lane}: ${one} needed a person's approval, no permission rule answered it, and ${tail}; a matching allow rule in settings${flag} can approve calls like this ahead of time`;
45
49
  case 'ask_rule':
46
50
  return `${lane}: an ask rule matched ${one}, so it needed a person's answer, and ${tail}; an ask rule outranks allow rules, so narrow or remove that ask rule, or run the task interactively to answer it`;
51
+ case 'engine_ask_rule':
52
+ return `${lane}: a rule on the engine side, not one of the user's permission rules, asks about ${one}, so it needed a person's answer, and ${tail}; the user's settings cannot approve it - run the task interactively to answer it`;
47
53
  case 'budget':
48
54
  return `${lane}: ${one} needed a person's approval, and this session's automatic-approval budget is used up, so saved rules no longer approve calls; ${tail}${budgetKnob !== undefined ? `; raise ${budgetKnob} before launch to change the cap` : ''}`;
49
55
  default:
@@ -73,19 +79,6 @@ function denyStampedEnd(ev, attribution) {
73
79
  export const HITL_INTERRUPT_MESSAGE_FOR_TOOL_USE = '[Request interrupted by user for tool use]';
74
80
  const RUN_CANCELLED_ERROR_CODE = RUN_CANCELLED_CODE;
75
81
  export const ENGINE_ABORT_TOOL_RESULT = 'Operation aborted';
76
- export function toolEndOutputText(output) {
77
- if (typeof output === 'string')
78
- return output;
79
- if (!Array.isArray(output))
80
- return undefined;
81
- const parts = [];
82
- for (const b of output) {
83
- const bb = b;
84
- if (bb?.type === 'text' && typeof bb.text === 'string')
85
- parts.push(bb.text);
86
- }
87
- return parts.length > 0 ? parts.join('') : undefined;
88
- }
89
82
  function isAskToolLoose(name) {
90
83
  return typeof name === 'string' && name.replace(/[\s_-]+/g, '').toLowerCase() === 'askuserquestion';
91
84
  }
@@ -107,6 +100,27 @@ function parkFamilyEvidence(led, gateToolName, gatedCallId) {
107
100
  return false;
108
101
  return gatedCallId === undefined || led.isFsOrShellGatedCall(gatedCallId);
109
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
+ }
110
124
  const ENGINE_GATE_PARKED_ERROR_CODE = GATE_PARKED_ERROR_CODE;
111
125
  function isEngineAbortToolEnd(ev) {
112
126
  if (ev.errorCode === ENGINE_GATE_PARKED_ERROR_CODE)
@@ -131,11 +145,8 @@ function parkGateOf(result) {
131
145
  if (typeof taskId !== 'string' || taskId.length === 0)
132
146
  return null;
133
147
  const toolName = runTerminalGateToolName(read);
134
- if (isAskToolLoose(toolName))
135
- return { taskId, gate: 'ask', toolName };
136
- if (isToolApprovalGate({ kind: runTerminalGateKind(read), toolName }))
137
- return { taskId, gate: 'fs', toolName };
138
- return null;
148
+ const arm = parkGateArmOf({ kind: runTerminalGateKind(read), toolName });
149
+ return arm === null ? null : { taskId, gate: arm, toolName };
139
150
  }
140
151
  function parkGatedCallId(src) {
141
152
  const v = src?.toolCallId;
@@ -272,18 +283,19 @@ async function routeToolApprovalFrame(ev, ctx) {
272
283
  const { led, deps } = ctx;
273
284
  if (ev.type === 'tool_approval_complete') {
274
285
  const id = ev.approvalId;
275
- 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)) {
276
290
  hostLog('debug', `liveHitlAskWire: tool_approval_complete for ${id} arrived while its card was waiting — card withdrawn (nothing will be sent from it)`);
277
291
  }
278
- if (typeof id === 'string' && id !== '')
279
- led.noteApprovalSettled(id, 'closed_by_engine');
280
292
  return { kind: 'skip' };
281
293
  }
282
294
  if (!deps.respondToolApproval) {
283
295
  hostLog('debug', `liveHitlAskWire: tool_approval frame ${ev.approvalId} but no respond wire — engine self-settles (TTL deny)`);
284
296
  return { kind: 'skip' };
285
297
  }
286
- const settledHere = settledApprovalDisposition(ev, led.settledApprovals());
298
+ const settledHere = settledApprovalDisposition(ev);
287
299
  if (settledHere !== undefined || (hasLedgerPositionKey(ev) && !led.preambleApprovals().has(ev.approvalId))) {
288
300
  const disposition = settledHere ?? (await judgeLedgerApprovalFrame(ev, ctx));
289
301
  if (disposition.kind !== 'live') {
@@ -306,21 +318,17 @@ async function routeToolApprovalFrame(ev, ctx) {
306
318
  const gatedCallId = fromSubagent ? undefined : frameCallId ?? led.lastPendingFsCall();
307
319
  const argsCallId = frameCallId === undefined ? gatedCallId : typeof ev.toolName === 'string' && toolNameIsFsWrite(ev.toolName) ? frameCallId : undefined;
308
320
  const runTaskId = ctx.taskId.current;
309
- const approvalIdAtLaunch = ev.approvalId;
310
321
  const launched = surfaceToolApprovalFrameAndRespond(ev, deps.respondToolApproval, argsOfGatedStart(led, argsCallId), ctx.signal, deps.approvalLane, typeof runTaskId === 'string' && runTaskId !== '' ? { taskId: runTaskId } : undefined);
311
322
  const hold = liveCardHoldOf(liveFrameCallKey(ev.approvalId));
312
- 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) => {
313
324
  hostLog('debug', `liveHitlAskWire: tool_approval card for ${ev.approvalId} failed: ${String(e).slice(0, 160)}`);
314
325
  });
315
326
  led.trackLiveCard(() => hold?.phase ?? 'card', handled);
316
327
  return { kind: 'skip' };
317
328
  }
318
- function settleLiveCardOutcome(ev, approvalId, outcome, ctx, fromSubagent, gatedCallId) {
329
+ function settleLiveCardOutcome(ev, outcome, ctx, fromSubagent, gatedCallId) {
319
330
  const { led, deps } = ctx;
320
331
  const { decision } = outcome;
321
- const settledHow = liveCardAnsweredHow(outcome);
322
- if (settledHow !== undefined)
323
- led.noteApprovalSettled(approvalId, settledHow);
324
332
  if (deps.onToolApprovalOutcome !== undefined) {
325
333
  invokeHostCallbackIsolated('liveHitlAskWire: onToolApprovalOutcome', () => deps.onToolApprovalOutcome?.(ev, outcome));
326
334
  }
@@ -357,7 +365,7 @@ async function judgeLedgerApprovalFrame(ev, ctx) {
357
365
  .finally(release);
358
366
  });
359
367
  const approvals = got.kind === 'value' ? { read: 'ok', body: got.value } : { read: 'failed' };
360
- return replayedApprovalDisposition(ev, { preamble: ctx.led.preambleApprovals(), approvals, settled: ctx.led.settledApprovals() });
368
+ return replayedApprovalDisposition(ev, { preamble: ctx.led.preambleApprovals(), approvals });
361
369
  }
362
370
  function routeToolStart(ev, callId, led) {
363
371
  led.noteStart(callId, ev);
@@ -390,15 +398,20 @@ function routeToolEnd(ev, callId, led) {
390
398
  }
391
399
  function routeSuspended(ev, ctx) {
392
400
  const gatedCallId = parkGatedCallId(ev);
393
- if (ev.gate && isAskToolLoose(ev.gate.toolName) && ctx.taskId.current) {
401
+ const arm = parkGateArmOf(ev.gate);
402
+ if (arm === 'ask' && ctx.taskId.current) {
394
403
  ctx.led.noteParkGate({ fsOrShellFamily: false });
395
404
  return { kind: 'park', gate: 'ask', ...(gatedCallId !== undefined ? { gatedCallId } : {}) };
396
405
  }
397
- if (ev.gate &&
398
- isToolApprovalGate(ev.gate) &&
399
- ctx.taskId.current) {
400
- ctx.led.noteParkGate({ fsOrShellFamily: parkFamilyEvidence(ctx.led, ev.gate.toolName, gatedCallId) });
401
- 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
+ };
402
415
  }
403
416
  return { kind: 'yield', events: [ev] };
404
417
  }
@@ -409,7 +422,13 @@ function routeDone(ev, ctx) {
409
422
  if (park !== null) {
410
423
  ctx.taskId.current = ctx.taskId.current ?? park.taskId;
411
424
  led.noteParkGate({ fsOrShellFamily: park.gate === 'fs' && parkFamilyEvidence(led, park.toolName, gatedCallId) });
412
- 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
+ };
413
432
  }
414
433
  const events = [...flushHeldWithInterruptRewrite(led, { terminal: ev, signal: ctx.signal })];
415
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);