@sema-agent/client-core 0.104.1 → 0.106.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 (175) hide show
  1. package/CHANGELOG.md +310 -0
  2. package/README.md +36 -14
  3. package/dist/adapt/arms.js +23 -6
  4. package/dist/adapter/activeRunSelfHeal.d.ts +14 -2
  5. package/dist/adapter/activeRunSelfHeal.js +90 -12
  6. package/dist/adapter/downstream/eventToSdkMessage.d.ts +0 -5
  7. package/dist/adapter/downstream/eventToSdkMessage.js +24 -23
  8. package/dist/adapter/downstream/terminalToSdkResult.js +2 -3
  9. package/dist/adapter/downstream/wiringManifestView.d.ts +7 -3
  10. package/dist/adapter/downstream/wiringManifestView.js +25 -1
  11. package/dist/adapter/runStream.js +8 -5
  12. package/dist/approvalReachWire.d.ts +1 -0
  13. package/dist/approvalReachWire.js +4 -1
  14. package/dist/approvalSeat.d.ts +21 -0
  15. package/dist/approvalSeat.js +73 -0
  16. package/dist/assistantInbox.d.ts +2 -0
  17. package/dist/assistantInbox.js +3 -0
  18. package/dist/checkpointRowVerdict.d.ts +23 -0
  19. package/dist/checkpointRowVerdict.js +89 -0
  20. package/dist/cloudConfigWireCaps.js +3 -0
  21. package/dist/compensations.js +6 -6
  22. package/dist/coreValuePorts.d.ts +14 -1
  23. package/dist/coreValuePorts.js +14 -0
  24. package/dist/decideFailureNote.js +3 -1
  25. package/dist/decideReceipt.d.ts +9 -0
  26. package/dist/decideReceipt.js +29 -1
  27. package/dist/declared/supportFloorDeclared.js +2 -2
  28. package/dist/deviceRebind.d.ts +7 -0
  29. package/dist/deviceRebind.js +39 -5
  30. package/dist/displayUntrusted.d.ts +4 -2
  31. package/dist/displayUntrusted.js +45 -22
  32. package/dist/engineAddress.d.ts +3 -0
  33. package/dist/engineAddress.js +25 -0
  34. package/dist/engineDirectory.js +9 -17
  35. package/dist/engineErrorCodes.d.ts +8 -0
  36. package/dist/engineErrorCodes.js +8 -0
  37. package/dist/engineGenerationPort.d.ts +11 -2
  38. package/dist/engineGenerationPort.js +63 -9
  39. package/dist/engineHealthFacts.d.ts +5 -0
  40. package/dist/engineHealthFacts.js +11 -0
  41. package/dist/engineNoticeCodes.d.ts +26 -3
  42. package/dist/engineNoticeCodes.js +52 -7
  43. package/dist/engineRowRef.js +1 -1
  44. package/dist/errorSupplementRoles.js +2 -0
  45. package/dist/eventLeg.d.ts +3 -3
  46. package/dist/eventLeg.js +25 -4
  47. package/dist/fleet/fleetProjection.js +26 -5
  48. package/dist/generated/engineFactTables.d.ts +3 -1
  49. package/dist/generated/engineFactTables.js +4 -1
  50. package/dist/generated/engineNoticeTables.js +19 -4
  51. package/dist/generated/sdkFactTables.d.ts +5 -0
  52. package/dist/generated/sdkFactTables.js +24 -0
  53. package/dist/generated/settingsSchemaFns.d.ts +11 -0
  54. package/dist/generated/settingsSchemaFns.js +2 -1
  55. package/dist/generated/settingsSchemaSafetyMergeSpec.js +1 -1
  56. package/dist/generated/settingsSchemaSettingsSources.d.ts +1 -1
  57. package/dist/generated/settingsSchemaSettingsSources.js +22 -2
  58. package/dist/headlessReconnectWire.js +31 -4
  59. package/dist/hitl/approvalLiveFace.d.ts +17 -0
  60. package/dist/hitl/approvalLiveFace.js +35 -0
  61. package/dist/hitl/approvalQueueRow.d.ts +21 -0
  62. package/dist/hitl/approvalQueueRow.js +69 -0
  63. package/dist/hitl/approvalsFeed.d.ts +5 -4
  64. package/dist/hitl/approvalsFeed.js +38 -6
  65. package/dist/hitl/askGateWire.js +26 -2
  66. package/dist/hitl/askParkRowRouting.d.ts +4 -3
  67. package/dist/hitl/askParkRowRouting.js +15 -3
  68. package/dist/hitl/automaticAnswerVerdict.js +13 -10
  69. package/dist/hitl/crashConverged.d.ts +5 -1
  70. package/dist/hitl/decisionConflict.js +2 -1
  71. package/dist/hitl/decisionRefusal.js +1 -1
  72. package/dist/hitl/decisionSend.d.ts +1 -0
  73. package/dist/hitl/decisionSend.js +14 -2
  74. package/dist/hitl/frameRouter.d.ts +4 -0
  75. package/dist/hitl/frameRouter.js +18 -5
  76. package/dist/hitl/gateIdentity.d.ts +1 -0
  77. package/dist/hitl/gateIdentity.js +3 -0
  78. package/dist/hitl/hitlBridge.d.ts +1 -1
  79. package/dist/hitl/hitlBridge.js +26 -5
  80. package/dist/hitl/livePendingAsk.d.ts +5 -0
  81. package/dist/hitl/livePendingAsk.js +6 -1
  82. package/dist/hitl/planReviewCard.d.ts +23 -0
  83. package/dist/hitl/planReviewCard.js +250 -0
  84. package/dist/hitl/planReviewWire.d.ts +39 -14
  85. package/dist/hitl/planReviewWire.js +450 -163
  86. package/dist/hitl/sessionAllowRoute.d.ts +2 -0
  87. package/dist/hitl/sessionAllowRoute.js +7 -0
  88. package/dist/hitl/sessionPolicyWire.d.ts +1 -7
  89. package/dist/hitl/sessionPolicyWire.js +3 -43
  90. package/dist/hitl/subagentSource.d.ts +1 -0
  91. package/dist/hitl/subagentSource.js +13 -0
  92. package/dist/hitl/toolApprovalWire.d.ts +3 -2
  93. package/dist/hitl/toolApprovalWire.js +79 -37
  94. package/dist/hostSettingsSource.d.ts +5 -2
  95. package/dist/hostSettingsSource.js +19 -10
  96. package/dist/hostTurnSettings.d.ts +5 -6
  97. package/dist/hostTurnSettings.js +106 -26
  98. package/dist/i18n/messages.en.d.ts +85 -12
  99. package/dist/i18n/messages.en.js +85 -12
  100. package/dist/i18n/messages.zh.js +88 -12
  101. package/dist/index.d.ts +35 -4
  102. package/dist/index.js +19 -2
  103. package/dist/liveInitToolFace.js +0 -1
  104. package/dist/liveModelCatalog.d.ts +15 -0
  105. package/dist/liveModelCatalog.js +40 -0
  106. package/dist/mcpTransportKindsCapability.d.ts +18 -0
  107. package/dist/mcpTransportKindsCapability.js +75 -0
  108. package/dist/mcpWireCaps.d.ts +4 -1
  109. package/dist/mcpWireCaps.js +25 -14
  110. package/dist/modelCapabilityProbe.js +66 -33
  111. package/dist/notifications.d.ts +9 -0
  112. package/dist/notifications.js +11 -2
  113. package/dist/ownKey.d.ts +4 -1
  114. package/dist/ownKey.js +8 -2
  115. package/dist/permissionModeWriteCapability.d.ts +13 -0
  116. package/dist/permissionModeWriteCapability.js +35 -0
  117. package/dist/permissionsAllowGrantCapability.d.ts +3 -0
  118. package/dist/permissionsAllowGrantCapability.js +26 -3
  119. package/dist/permissionsDeclaration.d.ts +25 -3
  120. package/dist/permissionsDeclaration.js +69 -41
  121. package/dist/planReviewCardFacts.d.ts +116 -0
  122. package/dist/planReviewCardFacts.js +469 -0
  123. package/dist/projectSeed.d.ts +39 -0
  124. package/dist/projectSeed.js +80 -0
  125. package/dist/promptDelivery.js +1 -1
  126. package/dist/reattachWindow.d.ts +8 -1
  127. package/dist/reattachWindow.js +44 -12
  128. package/dist/replayBody.d.ts +7 -6
  129. package/dist/replayBody.js +62 -7
  130. package/dist/request/taskRequest.js +3 -4
  131. package/dist/ruleCompileVerdict.d.ts +0 -2
  132. package/dist/ruleCompileVerdict.js +0 -31
  133. package/dist/ruleRefusalSentence.js +0 -3
  134. package/dist/runFollow.d.ts +30 -0
  135. package/dist/runFollow.js +117 -0
  136. package/dist/runLedgerSnapshot.d.ts +20 -0
  137. package/dist/runLedgerSnapshot.js +272 -0
  138. package/dist/runPermissionModeSwitch.d.ts +57 -0
  139. package/dist/runPermissionModeSwitch.js +135 -0
  140. package/dist/runReattachPolicy.d.ts +16 -5
  141. package/dist/runReattachPolicy.js +72 -24
  142. package/dist/runTerminal.js +30 -8
  143. package/dist/sandboxWire.d.ts +0 -3
  144. package/dist/sandboxWire.js +0 -9
  145. package/dist/seam.d.ts +17 -7
  146. package/dist/seam.js +13 -1
  147. package/dist/seatContract.d.ts +57 -7
  148. package/dist/seatContract.js +133 -3
  149. package/dist/serverSupportRange.d.ts +18 -0
  150. package/dist/serverSupportRange.js +25 -0
  151. package/dist/sessionEngine.d.ts +156 -0
  152. package/dist/sessionEngine.js +464 -0
  153. package/dist/sessionMap.d.ts +11 -1
  154. package/dist/sessionMap.js +35 -9
  155. package/dist/sessionMemoryErase.d.ts +1 -1
  156. package/dist/sessionMemoryErase.js +5 -0
  157. package/dist/sessionMemoryStatus.d.ts +27 -1
  158. package/dist/sessionMemoryStatus.js +117 -0
  159. package/dist/sessionMemorySync.d.ts +31 -0
  160. package/dist/sessionMemorySync.js +95 -0
  161. package/dist/sessionRowTag.d.ts +4 -0
  162. package/dist/sessionRowTag.js +18 -0
  163. package/dist/settingsLayerAdmission.d.ts +1 -0
  164. package/dist/settingsLayerAdmission.js +4 -1
  165. package/dist/sseIdleTriage.d.ts +3 -1
  166. package/dist/sseIdleTriage.js +19 -4
  167. package/dist/subagent/engineSubagentTail.js +2 -0
  168. package/dist/subagentContentStore.d.ts +3 -0
  169. package/dist/subagentContentStore.js +10 -1
  170. package/dist/toolResult.js +1 -1
  171. package/dist/turnFailurePresentation.d.ts +5 -2
  172. package/dist/turnFailurePresentation.js +12 -4
  173. package/dist/wireRefusalCopy.js +2 -6
  174. package/docs/INTEGRATION-CLIENTS.md +1507 -18
  175. package/package.json +5 -5
@@ -0,0 +1,69 @@
1
+ import { slotReadOf } from '../wireFailureShape.js';
2
+ import { SDK_APPROVAL_QUEUE_KINDS } from '../generated/sdkFactTables.js';
3
+ const _queueKindsPin = true;
4
+ void _queueKindsPin;
5
+ const isApprovalQueueKind = (v) => SDK_APPROVAL_QUEUE_KINDS.includes(v);
6
+ export function approvalQueueRowFamilyOf(row) {
7
+ const kind = slotReadOf(row, 'kind');
8
+ if (kind.presence === 'absent')
9
+ return 'checkpoint';
10
+ if (kind.presence !== 'present' || typeof kind.value !== 'string')
11
+ return 'unreadable';
12
+ return isApprovalQueueKind(kind.value) ? kind.value : 'unknown';
13
+ }
14
+ export function checkpointQueueRowSortOf(row) {
15
+ try {
16
+ if (typeof row !== 'object' || row === null || Array.isArray(row))
17
+ return 'excluded';
18
+ const family = approvalQueueRowFamilyOf(row);
19
+ return family === 'checkpoint' ? 'checkpoint' : family === 'unreadable' ? 'unreadable' : 'excluded';
20
+ }
21
+ catch {
22
+ return 'unreadable';
23
+ }
24
+ }
25
+ export const QUEUE_ROW_FAMILY_UNREADABLE_GATE = '(unreadable)';
26
+ const ownString = (row, key, nonEmpty) => {
27
+ const r = slotReadOf(row, key);
28
+ return r.presence === 'present' && typeof r.value === 'string' && (!nonEmpty || r.value !== '') ? r.value : undefined;
29
+ };
30
+ const ownTime = (row, key) => {
31
+ const r = slotReadOf(row, key);
32
+ return r.presence === 'present' && typeof r.value === 'number' && Number.isFinite(r.value) && r.value >= 0 ? r.value : undefined;
33
+ };
34
+ export function peerInboundQueueRowOf(row) {
35
+ try {
36
+ const id = ownString(row, 'id', true);
37
+ const recipientSessionId = ownString(row, 'recipientSessionId', true);
38
+ if (id === undefined || recipientSessionId === undefined)
39
+ return undefined;
40
+ const out = { id, recipientSessionId };
41
+ const lane = ownString(row, 'lane', true);
42
+ if (lane !== undefined)
43
+ out.lane = lane;
44
+ const cause = ownString(row, 'cause', true);
45
+ if (cause !== undefined)
46
+ out.cause = cause;
47
+ const content = ownString(row, 'content', false);
48
+ if (content !== undefined)
49
+ out.content = content;
50
+ const sentAt = ownTime(row, 'sentAt');
51
+ if (sentAt !== undefined)
52
+ out.sentAt = sentAt;
53
+ const heldAt = ownTime(row, 'heldAt');
54
+ if (heldAt !== undefined)
55
+ out.heldAt = heldAt;
56
+ const deadline = ownTime(row, 'deadline');
57
+ if (deadline !== undefined)
58
+ out.deadline = deadline;
59
+ for (const k of ['fromSession', 'fromName', 'fromScope']) {
60
+ const v = ownString(row, k, true);
61
+ if (v !== undefined)
62
+ out[k] = v;
63
+ }
64
+ return Object.freeze(out);
65
+ }
66
+ catch {
67
+ return undefined;
68
+ }
69
+ }
@@ -1,13 +1,13 @@
1
1
  import type { PendingCheckpoint } from '@sema-agent/sdk';
2
2
  import { type LivePendingAskView } from './livePendingAsk.js';
3
+ import { type ApprovalQueuePeerInboundRow } from './approvalQueueRow.js';
4
+ import type { ApprovalsListEnvelope } from './crashConverged.js';
5
+ export type { ApprovalQueuePeerInboundRow } from './approvalQueueRow.js';
3
6
  export interface ApprovalsFeedClientLike {
4
7
  approvals: {
5
8
  list(opts?: {
6
9
  signal?: AbortSignal;
7
- }): Promise<{
8
- pending: PendingCheckpoint[];
9
- livePending?: unknown[];
10
- }>;
10
+ }): Promise<ApprovalsListEnvelope>;
11
11
  stream?(opts?: {
12
12
  signal?: AbortSignal;
13
13
  }): AsyncGenerator<{
@@ -20,6 +20,7 @@ export type ApprovalsFeedMode = 'push' | 'poll' | 'idle';
20
20
  export interface ApprovalsFeedSnapshot {
21
21
  kind: 'snapshot';
22
22
  pending: PendingCheckpoint[];
23
+ peerInbound?: ApprovalQueuePeerInboundRow[];
23
24
  livePending?: LivePendingAskView[];
24
25
  livePendingDropped?: number;
25
26
  pendingDropped?: number;
@@ -2,17 +2,40 @@ import { hostLog } from '../host.js';
2
2
  import { unrefTimer } from '../unrefTimer.js';
3
3
  import { readLivePendingRows } from './livePendingAsk.js';
4
4
  import { createStreamDrainingLegs } from '../streamDrainingLegs.js';
5
+ import { approvalQueueRowFamilyOf, peerInboundQueueRowOf } from './approvalQueueRow.js';
6
+ import { checkpointRowVerdictOf } from '../checkpointRowVerdict.js';
7
+ const _realClientFitsFeedSlice = true;
8
+ void _realClientFitsFeedSlice;
5
9
  const MAX_CONSECUTIVE_POLL_ESCAPES = 5;
6
10
  function readDurablePendingRows(raw) {
7
11
  if (!Array.isArray(raw))
8
12
  return { kind: 'malformed' };
9
13
  const rows = [];
14
+ const peer = [];
10
15
  let dropped = 0;
16
+ let skipped = 0;
11
17
  for (const item of raw) {
12
18
  if (item === null || typeof item !== 'object' || Array.isArray(item)) {
13
19
  dropped++;
14
20
  continue;
15
21
  }
22
+ const family = approvalQueueRowFamilyOf(item);
23
+ if (family === 'unknown') {
24
+ skipped++;
25
+ continue;
26
+ }
27
+ if (family === 'peer_inbound') {
28
+ const view = peerInboundQueueRowOf(item);
29
+ if (view === undefined)
30
+ dropped++;
31
+ else
32
+ peer.push(view);
33
+ continue;
34
+ }
35
+ if (family === 'unreadable') {
36
+ dropped++;
37
+ continue;
38
+ }
16
39
  const sid = item.sessionId;
17
40
  if (typeof sid !== 'string' || sid === '') {
18
41
  dropped++;
@@ -20,13 +43,13 @@ function readDurablePendingRows(raw) {
20
43
  }
21
44
  rows.push(item);
22
45
  }
23
- if (raw.length > 0 && rows.length === 0)
46
+ if (raw.length > 0 && rows.length + peer.length + skipped === 0)
24
47
  return { kind: 'malformed' };
25
- return { kind: 'present', rows, dropped };
48
+ return { kind: 'present', rows, peer, dropped };
26
49
  }
27
50
  function durableDigestOf(rows) {
28
51
  return rows
29
- .map(r => [r.sessionId ?? '', r.taskId ?? '', r.toolCallId ?? '', r.boundCallId ?? '', r.boundInputHash ?? '', r.toolName ?? '']
52
+ .map(r => [r.sessionId ?? '', r.taskId ?? '', r.toolCallId ?? '', r.boundCallId ?? '', r.boundInputHash ?? '', r.toolName ?? '', JSON.stringify(checkpointRowVerdictOf(r) ?? null)]
30
53
  .join(''))
31
54
  .sort()
32
55
  .join('');
@@ -34,14 +57,20 @@ function durableDigestOf(rows) {
34
57
  const LIVE_FIELD_SEP = String.fromCharCode(1);
35
58
  const LIVE_ROW_SEP = String.fromCharCode(2);
36
59
  const LIVE_SECTION_SEP = String.fromCharCode(3);
37
- function digestOf(rows, live, dropped = 0, droppedDurable = 0) {
60
+ function peerDigestOf(peer) {
61
+ return peer
62
+ .map(r => JSON.stringify(r))
63
+ .sort()
64
+ .join(LIVE_ROW_SEP);
65
+ }
66
+ function digestOf(rows, live, dropped = 0, droppedDurable = 0, peer = []) {
38
67
  const liveDigest = live === undefined
39
68
  ? 'absent'
40
69
  : live
41
70
  .map(r => [r.approvalId, r.toolName, String(r.expiresAtMs), r.sessionId ?? '', r.originTaskId ?? '', r.frame !== undefined ? 'f' : ''].join(LIVE_FIELD_SEP))
42
71
  .sort()
43
72
  .join(LIVE_ROW_SEP);
44
- return `${durableDigestOf(rows)}${LIVE_SECTION_SEP}${liveDigest}${LIVE_SECTION_SEP}${dropped}${LIVE_SECTION_SEP}${droppedDurable}`;
73
+ return `${durableDigestOf(rows)}${LIVE_SECTION_SEP}${liveDigest}${LIVE_SECTION_SEP}${dropped}${LIVE_SECTION_SEP}${droppedDurable}${LIVE_SECTION_SEP}${peerDigestOf(peer)}`;
45
74
  }
46
75
  export function startApprovalsFeed(client, onSnapshot, opts) {
47
76
  const pollIntervalMs = opts?.pollIntervalMs ?? 5000;
@@ -158,6 +187,7 @@ export function startApprovalsFeed(client, onSnapshot, opts) {
158
187
  return;
159
188
  const seq = ++takeSeq;
160
189
  let rows;
190
+ let peer;
161
191
  let live;
162
192
  let dropped = 0;
163
193
  let droppedDurable = 0;
@@ -212,6 +242,7 @@ export function startApprovalsFeed(client, onSnapshot, opts) {
212
242
  throw new TypeError('approvalsFeed: unreadable pending section');
213
243
  }
214
244
  rows = durableRead.rows;
245
+ peer = durableRead.peer;
215
246
  droppedDurable = durableRead.dropped;
216
247
  if (durableRead.dropped > 0)
217
248
  hostLog('debug', `approvalsFeed: dropped ${durableRead.dropped} malformed pending row(s) — snapshot carries pendingDropped`);
@@ -220,7 +251,7 @@ export function startApprovalsFeed(client, onSnapshot, opts) {
220
251
  return;
221
252
  let d;
222
253
  try {
223
- d = digestOf(rows, live, dropped, droppedDurable);
254
+ d = digestOf(rows, live, dropped, droppedDurable, peer);
224
255
  }
225
256
  catch (e) {
226
257
  noteTakeMissed(via, seq);
@@ -252,6 +283,7 @@ export function startApprovalsFeed(client, onSnapshot, opts) {
252
283
  const snap = {
253
284
  kind: 'snapshot',
254
285
  pending: rows,
286
+ ...(peer.length > 0 ? { peerInbound: peer } : {}),
255
287
  ...(live !== undefined ? { livePending: live } : {}),
256
288
  ...(dropped > 0 ? { livePendingDropped: dropped } : {}),
257
289
  ...(droppedDurable > 0 ? { pendingDropped: droppedDurable } : {}),
@@ -1,9 +1,10 @@
1
1
  import { createGateLedger } from './gateLedger.js';
2
- import { flushHeldWithInterruptRewrite, isHostProgressFrame, routeFrame, } from './frameRouter.js';
2
+ import { bridgeRunHandleFallbackOf, flushHeldWithInterruptRewrite, isHostProgressFrame, routeFrame, } from './frameRouter.js';
3
3
  import { resolvePark, nextHopBudget, stalledTerminal, MAX_GATE_HOPS } from './parkResolver.js';
4
4
  import { createStreamDrainingLegs } from '../streamDrainingLegs.js';
5
5
  import { abortableSleep } from '../abortableSleep.js';
6
6
  import { hostLog } from '../host.js';
7
+ import { invokeHostCallbackIsolated } from '../hostCallbackGuard.js';
7
8
  import { decideAcceptedNotResolved, readDecideReceipt } from '../decideReceipt.js';
8
9
  import { APPROVAL_EXPIRED } from '../engineErrorCodes.js';
9
10
  import { isNotFoundFailure } from '../wireErrorTriage.js';
@@ -37,11 +38,14 @@ export async function* bridgeAskUserQuestionGates(source, deps, opts) {
37
38
  let lastRoundDecided = false;
38
39
  let unverifiableParks = 0;
39
40
  const drains = createStreamDrainingLegs();
41
+ let lastDrainFrame;
40
42
  while (true) {
41
43
  let park = null;
42
44
  for await (const ev of stream) {
43
- if (drains.see(ev))
45
+ if (drains.see(ev)) {
46
+ lastDrainFrame = ev;
44
47
  continue;
48
+ }
45
49
  const answering = led.answeringLiveCards();
46
50
  if (answering.length > 0)
47
51
  await Promise.all(answering);
@@ -77,6 +81,11 @@ export async function* bridgeAskUserQuestionGates(source, deps, opts) {
77
81
  const drained = drains.legEnded('returned');
78
82
  if (drained !== undefined) {
79
83
  const reopenAfterMs = 'reconnectAfterMs' in drained ? drained.reconnectAfterMs : undefined;
84
+ if (taskId.current === undefined) {
85
+ const bound = bridgeRunHandleFallbackOf(deps);
86
+ if (bound !== undefined && reopenAfterMs !== undefined)
87
+ taskId.current = bound;
88
+ }
80
89
  if (reopenAfterMs !== undefined && taskId.current !== undefined && !opts?.signal?.aborted) {
81
90
  hostLog('debug', `liveHitlAskWire: runs.events(${taskId.current}) ended on the drain end frame — the engine is going down; reopening in ${reopenAfterMs}ms`);
82
91
  await abortableSleep(reopenAfterMs, opts?.signal ?? new AbortController().signal);
@@ -91,6 +100,13 @@ export async function* bridgeAskUserQuestionGates(source, deps, opts) {
91
100
  }
92
101
  }
93
102
  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`);
103
+ if (!opts?.signal?.aborted) {
104
+ const runId = taskId.current;
105
+ const event = 'giveUp' in drained
106
+ ? { cause: 'stream_draining', ladder: 'exhausted', ...(runId !== undefined ? { runId } : {}) }
107
+ : { cause: 'stream_draining', frame: lastDrainFrame ?? {}, ...(runId !== undefined ? { runId } : {}) };
108
+ notifyBreak(deps, Object.freeze(event), opts?.signal);
109
+ }
94
110
  }
95
111
  yield* flushHeldWithInterruptRewrite(led, { signal: opts?.signal });
96
112
  return;
@@ -161,6 +177,14 @@ export async function* bridgeAskUserQuestionGates(source, deps, opts) {
161
177
  });
162
178
  }
163
179
  }
180
+ function notifyBreak(deps, event, signal) {
181
+ invokeHostCallbackIsolated('liveHitlAskWire: onBreak', () => {
182
+ const cb = deps.onBreak;
183
+ if (typeof cb !== 'function' || signal?.aborted === true)
184
+ return;
185
+ return cb.call(deps, event);
186
+ });
187
+ }
164
188
  export const LATE_DECIDE_OUTCOMES = Object.freeze(['accepted-not-resolved', 'resumed', 'expired-reaped', 'settled-elsewhere', 'unknown']);
165
189
  const LATE_DECIDE_TASK_ID_MAX = 64;
166
190
  export function lateDecideOutcomeOf(reply, opts) {
@@ -1,4 +1,5 @@
1
1
  import type { PendingCheckpoint } from '@sema-agent/sdk';
2
+ import type { ApprovalQueueRow } from './crashConverged.js';
2
3
  import type { ParkRowProbe } from './parkRowBirthWait.js';
3
4
  import { type ParkOwnershipDeps } from './parkOwnership.js';
4
5
  export declare const ASK_PARK_ROW_WAIT_MS = 15000;
@@ -7,7 +8,7 @@ export interface AskParkRowScanDeps {
7
8
  isOwned?: (row: PendingCheckpoint) => boolean;
8
9
  ownership?: ParkOwnershipDeps;
9
10
  }
10
- export declare function classifyAskParkRows(rows: readonly PendingCheckpoint[], taskId: string, deps?: AskParkRowScanDeps): ParkRowProbe<PendingCheckpoint>;
11
+ export declare function classifyAskParkRows(queueRows: readonly ApprovalQueueRow[], taskId: string, deps?: AskParkRowScanDeps): ParkRowProbe<PendingCheckpoint>;
11
12
  export interface AskParkRowIdentity {
12
13
  rowTaskId: string;
13
14
  gatedCallId: string | undefined;
@@ -15,7 +16,7 @@ export interface AskParkRowIdentity {
15
16
  }
16
17
  export declare function askParkRowIdentity(taskId: string, row: PendingCheckpoint): AskParkRowIdentity;
17
18
  export declare function askParkRowArm(row: PendingCheckpoint): 'question' | 'tool-gate';
18
- export declare function askParkRowStillPending(rows: readonly PendingCheckpoint[], identity: AskParkRowIdentity): boolean;
19
+ export declare function askParkRowStillPending(rows: readonly ApprovalQueueRow[], identity: AskParkRowIdentity): boolean;
19
20
  export type AskParkChainFailureDisposition = 'retry' | 'row-gone-after-card' | 'row-unborn';
20
21
  export declare function classifyAskParkChainFailure(i: {
21
22
  rowStillPending: boolean;
@@ -29,6 +30,6 @@ export interface RowArmSingleFlight<T> {
29
30
  export declare function createRowArmSingleFlight<T>(): RowArmSingleFlight<T>;
30
31
  export declare function pendingRowIsOwnedAndDecidable(row: PendingCheckpoint, deps?: ParkOwnershipDeps): boolean;
31
32
  export interface OwnedPendingListView {
32
- readonly pending?: readonly PendingCheckpoint[] | null;
33
+ readonly pending?: readonly ApprovalQueueRow[] | null;
33
34
  }
34
35
  export declare function countOwnedPendingRows(listed: OwnedPendingListView | null | undefined, deps?: ParkOwnershipDeps): number;
@@ -2,10 +2,17 @@ import { askParkForeignGateKind, durableDecideLegOf } from '../adapter/activeRun
2
2
  import { isAskTool, questionCardVerdict } from './frameRouter.js';
3
3
  import { approvalCallKey } from './gateIdentity.js';
4
4
  import { askQuestionsFromPending, pendingRowIsOwnedByThisSession } from './parkOwnership.js';
5
+ import { approvalQueueRowFamilyOf, checkpointQueueRowSortOf, QUEUE_ROW_FAMILY_UNREADABLE_GATE } from './approvalQueueRow.js';
5
6
  export const ASK_PARK_ROW_WAIT_MS = 15000;
6
7
  export const ASK_PARK_ROW_POLL_MS = 500;
7
- export function classifyAskParkRows(rows, taskId, deps) {
8
+ export function classifyAskParkRows(queueRows, taskId, deps) {
8
9
  const isOwned = deps?.isOwned ?? ((row) => pendingRowIsOwnedByThisSession(row, deps?.ownership));
10
+ const sorted = queueRows.flatMap((r) => {
11
+ const sort = checkpointQueueRowSortOf(r);
12
+ return sort === 'excluded' ? [] : [{ r: r, unreadable: sort === 'unreadable' }];
13
+ });
14
+ const rows = sorted.map((x) => x.r);
15
+ const familyUnreadable = new Set(sorted.filter((x) => x.unreadable).map((x) => x.r));
9
16
  const own = rows.find(r => r.taskId === taskId);
10
17
  const sole = rows.length === 1 ? rows[0] : undefined;
11
18
  const soleUnowned = sole !== undefined && !isOwned(sole);
@@ -21,7 +28,7 @@ export function classifyAskParkRows(rows, taskId, deps) {
21
28
  : `${String(rows.length)} pending rows but none for task ${taskId} — ambiguous queue, refusing to surface an unrelated row`,
22
29
  };
23
30
  }
24
- const foreignKind = askParkForeignGateKind(pending);
31
+ const foreignKind = familyUnreadable.has(pending) ? QUEUE_ROW_FAMILY_UNREADABLE_GATE : askParkForeignGateKind(pending);
25
32
  if (foreignKind !== null) {
26
33
  return {
27
34
  kind: 'unborn',
@@ -120,7 +127,7 @@ export function pendingRowIsOwnedAndDecidable(row, deps) {
120
127
  const leg = durableDecideLegOf(row);
121
128
  if (leg === 'plan_review')
122
129
  return true;
123
- if (leg !== 'approval' && leg !== 'absent')
130
+ if (leg !== 'approval')
124
131
  return false;
125
132
  return askParkRowArm(row) === 'question' ? askQuestionsFromPending(row) !== null : true;
126
133
  }
@@ -137,6 +144,11 @@ export function countOwnedPendingRows(listed, deps) {
137
144
  if (typeof row !== 'object' || row === null) {
138
145
  throw new Error('approvals.list answered with a pending row that is not an object — the owned pending count is unknown');
139
146
  }
147
+ const family = approvalQueueRowFamilyOf(row);
148
+ if (family === 'unreadable')
149
+ throw new Error('approvals.list answered with a pending row whose family (`kind`) cannot be read — the owned pending count is unknown');
150
+ if (family !== 'checkpoint')
151
+ continue;
140
152
  if (pendingRowIsOwnedAndDecidable(row, deps))
141
153
  n++;
142
154
  }
@@ -125,6 +125,17 @@ function evidenceUnreadable(card) {
125
125
  const nested = evidenceSlotOf(risk.value, 'requiresRealApproval');
126
126
  return nested.kind !== 'data' || typeof nested.value !== 'boolean';
127
127
  }
128
+ function registryUnreadable(card) {
129
+ const slot = evidenceSlotOf(card, 'unreadableEvidence');
130
+ if (slot.kind === 'absent' || (slot.kind === 'data' && slot.value === undefined))
131
+ return false;
132
+ if (slot.kind === 'unreadable')
133
+ return true;
134
+ const list = slot.value;
135
+ if (!Array.isArray(list) || list.some((k) => typeof k !== 'string'))
136
+ return true;
137
+ return list.some((k) => k !== 'rememberRefused' && k !== 'ruleOffers');
138
+ }
128
139
  function readHostAskRuleMatched(facts) {
129
140
  if (typeof facts !== 'object' || facts === null)
130
141
  return undefined;
@@ -137,17 +148,9 @@ export function automaticAnswerVerdict(card, lane, facts) {
137
148
  try {
138
149
  if (typeof card !== 'object' || card === null)
139
150
  return UNKNOWN.card_unreadable;
151
+ const unreadableAtEntry = registryUnreadable(card) || evidenceUnreadable(card) || (retiredAllowRuleShadowKeyPresent(card, 'frame') && !approvalAllowRuleShadowed(card));
140
152
  if (card.cardPayloadUnreadable === true)
141
153
  return UNKNOWN.card_unreadable;
142
- const unreadable = card.unreadableEvidence;
143
- if (unreadable !== undefined) {
144
- if (!Array.isArray(unreadable) || unreadable.some((k) => typeof k !== 'string'))
145
- return UNKNOWN.card_unreadable;
146
- if (unreadable.some((k) => k !== 'rememberRefused' && k !== 'ruleOffers'))
147
- return UNKNOWN.card_unreadable;
148
- }
149
- if (!approvalAllowRuleShadowed(card) && retiredAllowRuleShadowKeyPresent(card, 'frame'))
150
- return UNKNOWN.card_unreadable;
151
154
  const face = lane === 'mode_posture' ? askFaceOfCard(card) : undefined;
152
155
  const origin = readAskOrigin(evidenceView(card, 'origin'));
153
156
  if (origin !== undefined && Object.hasOwn(ORIGIN_IMPLIES_CLASS, origin)) {
@@ -175,7 +178,7 @@ export function automaticAnswerVerdict(card, lane, facts) {
175
178
  return mustAsk('allow_rule_shadow');
176
179
  }
177
180
  }
178
- if (evidenceUnreadable(card))
181
+ if (unreadableAtEntry)
179
182
  return UNKNOWN.card_unreadable;
180
183
  const pair = readAskClassPairState(card);
181
184
  if (pair.state === 'malformed')
@@ -4,8 +4,12 @@ export interface CrashConvergedRowReading extends Readonly<CrashConvergedRow> {
4
4
  readonly needsHumanReason?: 'approved_then_interrupted' | 'pending_unsafe' | 'unstable_row' | 'contradictory';
5
5
  }
6
6
  export declare const isCrashConvergedCause: (v: unknown) => v is CrashConvergedRowReading["cause"];
7
+ export interface ApprovalQueueKindedRow {
8
+ readonly kind: string;
9
+ }
10
+ export type ApprovalQueueRow = PendingCheckpoint | ApprovalQueueKindedRow;
7
11
  export interface ApprovalsListEnvelope {
8
- pending: PendingCheckpoint[];
12
+ pending: ApprovalQueueRow[];
9
13
  livePending?: unknown[];
10
14
  crashConverged?: CrashConvergedRowReading[];
11
15
  }
@@ -1,8 +1,9 @@
1
1
  import { APPROVAL_BINDING_MISMATCH, CHECKPOINT_UNSUPPORTED_VERSION, RESUME_OUTCOME_INVALID } from '../engineErrorCodes.js';
2
2
  import { msg, renderMessage } from '../i18n/translate.js';
3
3
  import { ownDataField } from '../ownKey.js';
4
+ import { SDK_DECIDE_BINDING_KEYS } from '../generated/sdkFactTables.js';
4
5
  import { isSlotCarrier, PROTOCOL_ERROR_NAME, protocolErrorNameReading, readRefusalSlots, readThrownExtraSnapshot } from '../wireFailureShape.js';
5
- const BINDING_SEAT_FIELDS = new Set(['boundCallId', 'boundInputHash']);
6
+ const BINDING_SEAT_FIELDS = new Set(SDK_DECIDE_BINDING_KEYS);
6
7
  const ANSWER_FIELD = 'answer';
7
8
  const REFUSAL_WORD_KEYS = Object.freeze(['field', 'reason']);
8
9
  const GRANT_DIGEST_FIELD = 'boundGrantDigest';
@@ -146,7 +146,7 @@ export function readDecisionRefusalAsk(failure, answer, read) {
146
146
  if (name === 'HitlSafetyError')
147
147
  return facts('not_settled');
148
148
  const code = typeof errorCode === 'string' && errorCode.length > 0 ? errorCode : undefined;
149
- if (code === RESUME_PREFLIGHT_REJECTED && (preflightSettledBitsPresent(carrier) || retriable !== true))
149
+ if (code === RESUME_PREFLIGHT_REJECTED && preflightSettledBitsPresent(carrier))
150
150
  return facts('not_settled', true);
151
151
  if (isCodeClassifiedGateFailure(code, retriable))
152
152
  return facts('not_settled');
@@ -63,6 +63,7 @@ interface HitlDecisionOutcomeBase {
63
63
  readonly fallback?: 'approval';
64
64
  readonly noteDropped?: true;
65
65
  readonly rememberDropped?: true;
66
+ readonly allowSessionCarried?: true;
66
67
  readonly attributionDropped?: true;
67
68
  readonly attributionRenamed?: true;
68
69
  readonly pending?: LiveAskPendingReading;
@@ -10,6 +10,7 @@ import { readDecisionNoteAudit } from './approvalDecisionNoteAudit.js';
10
10
  import { carrierReadOf, deliverWithAttributionLadder, isLocalSafetyStop } from './attributionLadder.js';
11
11
  import { budgetSpent, deliverApprovalDecision, deliveryTiming, isAborted, newSendTally, PARKING_WAIT_CAP_MS, setDeliveryTimingForTests, sleepFor, settledTransportReadingOf, withTransportRetry, deliveryReadingOf, } from './approvalDelivery.js';
12
12
  import { ASK_DECIDED_CODE, classifyDeliveredDecisionRefusal, decisionRefusalClosesOut, notPendingAfterRetry } from './decisionRefusal.js';
13
+ import { sessionAllowCarried } from './sessionAllowRoute.js';
13
14
  import { addDecisionOpKeys, closeDecisionOp, decisionLedgerKeysOf, decisionOpsWithKey, openDecisionOp } from './decisionLedger.js';
14
15
  import { hostHoldIsActive, takeHostHoldLedgerOp, tryHoldApprovalNow } from './approvalHolds.js';
15
16
  import { answerPayloadFor, decisionAttributionKeyOf, isToolApprovalRespondReplayed, readApprovalDenySettledBy, readToolApprovalRespondAck, readToolApprovalRespondParking, } from './toolApprovalWire.js';
@@ -183,6 +184,9 @@ function bodyFacts(answer, payload, rememberUnsupported) {
183
184
  ...(rememberUnsupported && answer.kind === 'allow' && answer.allowSession === true ? { rememberDropped: true } : {}),
184
185
  };
185
186
  }
187
+ function answerGateCannotTake(out) {
188
+ return out.kind === 'not_applied' && (out.cause === 'gone' || out.cause === 'parking' || out.cause === 'lane_disabled');
189
+ }
186
190
  function ownTrue(raw, key) {
187
191
  return typeof raw === 'object' && raw !== null && guardedRead(() => readOwnDataValue(raw, key)) === true;
188
192
  }
@@ -190,6 +194,14 @@ async function sendAskFamily(respondForFallback, decideAsk, req, ctx) {
190
194
  const payload = answerPayloadFor(req.answer, 'respond', { approvalDecisionNoteCapable: ctx.noteCapable });
191
195
  if (payload === undefined)
192
196
  return { family: 'ask', attempts: ctx.tally.attempts, kind: 'not_sent', cause: 'not_an_answer' };
197
+ let fallbackRespond = respondForFallback;
198
+ if (req.answer.kind === 'allow' && req.answer.allowSession === true && respondForFallback !== undefined && req.approvalId !== undefined && sessionAllowCarried('v1', req.approvalId)) {
199
+ const viaAnswerGate = await sendApprovalFamily(respondForFallback, req.approvalId, req.answer, ctx);
200
+ if (!answerGateCannotTake(viaAnswerGate))
201
+ return { ...viaAnswerGate, family: 'ask', allowSessionCarried: true };
202
+ hostLog('debug', `decisionSend: session-allow-fallback ask=${req.askId} cause=${String(viaAnswerGate.cause)} via=ask-decide-once`);
203
+ fallbackRespond = undefined;
204
+ }
193
205
  const verdict = verdictOf(payload.decision) ?? 'deny';
194
206
  const attribution = req.answer.kind === 'deny' ? decisionAttributionKeyOf(ctx.decidedBy, readApprovalDenySettledBy(req.answer)) : {};
195
207
  const body = {
@@ -232,8 +244,8 @@ async function sendAskFamily(respondForFallback, decideAsk, req, ctx) {
232
244
  }
233
245
  const out = outcomeOfThrown(e, 'ask', verdict, ctx.signal, ctx.tally, ctx.noteCapable, settled);
234
246
  if (out.kind === 'not_applied' && out.cause === 'lane_disabled' && code === ASK_DECISION_LANE_DISABLED && req.approvalId !== undefined) {
235
- if (respondForFallback !== undefined && ctx.signal?.aborted !== true) {
236
- const fb = await sendApprovalFamily(respondForFallback, req.approvalId, req.answer, ctx);
247
+ if (fallbackRespond !== undefined && ctx.signal?.aborted !== true) {
248
+ const fb = await sendApprovalFamily(fallbackRespond, req.approvalId, req.answer, ctx);
237
249
  return { ...fb, family: 'ask', fallback: 'approval' };
238
250
  }
239
251
  }
@@ -5,6 +5,7 @@ import type { ApprovalResolution } from './approvalResolution.js';
5
5
  import type { GateLedger } from './gateLedger.js';
6
6
  import type { NoAllowCause } from './noAllowCause.js';
7
7
  import { type ReplayedApprovalDisposition } from './replayedApproval.js';
8
+ import type { ReattachDrainingEvent } from '../runReattachPolicy.js';
8
9
  export declare const HITL_REJECT_MESSAGE = "The user doesn't want to proceed with this tool use. The tool use was rejected (eg. if it was a file edit, the new_string was NOT written to the file). STOP what you are doing and wait for the user to tell you how to proceed.";
9
10
  export declare const HITL_POLICY_DENY_MESSAGE: string;
10
11
  export type PolicyDenyLane = 'no_approval_ui' | 'dont_ask';
@@ -31,11 +32,14 @@ export interface AskGateWireDeps {
31
32
  }) => AsyncGenerator<AgentEvent>;
32
33
  respondToolApproval?: RespondToolApprovalFn;
33
34
  onParkReattach?: (e: ParkReattachNotice) => void;
35
+ onBreak?: (event: ReattachDrainingEvent) => void;
34
36
  approvalLane?: ToolApprovalFrameLaneOpts;
35
37
  onToolApprovalOutcome?: (frame: ToolApprovalFrame, resolution: ApprovalResolution) => void | Promise<void>;
36
38
  onDecideOperation?: DecideOperationObserver;
37
39
  onReplayedApproval?: (frame: ToolApprovalFrame, disposition: ReplayedApprovalDisposition) => void | Promise<void>;
38
40
  }
41
+ export declare function setBridgeRunHandleFallback(deps: object, read: () => string | undefined): void;
42
+ export declare function bridgeRunHandleFallbackOf(deps: object): string | undefined;
39
43
  type GateKind = 'ask' | 'fs';
40
44
  export interface GatePark {
41
45
  gate: GateKind;
@@ -20,6 +20,7 @@ import { ccToolDenialKindForSettledBy } from '../gateVocabulary.js';
20
20
  import { REJECT_MESSAGE } from '../adapt/wireShapes.js';
21
21
  import { RUN_CANCELLED_CODE } from '../runCancelContext.js';
22
22
  import { durableDecideLegOf } from '../adapter/activeRunSelfHeal.js';
23
+ import { subagentSourceSessionOf } from './subagentSource.js';
23
24
  export const HITL_REJECT_MESSAGE = REJECT_MESSAGE;
24
25
  export const HITL_POLICY_DENY_MESSAGE = 'Permission for this tool use was denied: it requires interactive approval, and permission prompts are ' +
25
26
  'not available in this session. The action was NOT performed. Do not claim it succeeded, and do not retry ' +
@@ -83,6 +84,20 @@ function denyStampedEnd(ev, attribution) {
83
84
  export const HITL_INTERRUPT_MESSAGE_FOR_TOOL_USE = '[Request interrupted by user for tool use]';
84
85
  const RUN_CANCELLED_ERROR_CODE = RUN_CANCELLED_CODE;
85
86
  export const ENGINE_ABORT_TOOL_RESULT = 'Operation aborted';
87
+ const bridgeRunHandleFallbacks = new WeakMap();
88
+ export function setBridgeRunHandleFallback(deps, read) {
89
+ bridgeRunHandleFallbacks.set(deps, read);
90
+ }
91
+ export function bridgeRunHandleFallbackOf(deps) {
92
+ try {
93
+ const read = bridgeRunHandleFallbacks.get(deps);
94
+ const v = read?.();
95
+ return typeof v === 'string' && v !== '' ? v : undefined;
96
+ }
97
+ catch {
98
+ return undefined;
99
+ }
100
+ }
86
101
  function isAskToolLoose(name) {
87
102
  return typeof name === 'string' && name.replace(/[\s_-]+/g, '').toLowerCase() === 'askuserquestion';
88
103
  }
@@ -121,13 +136,11 @@ export function parkGateArmOf(gate) {
121
136
  return null;
122
137
  }
123
138
  const leg = durableDecideLegOf(typeof kind === 'string' ? { gateKind: kind } : null);
124
- if (leg !== 'approval' && leg !== 'absent')
139
+ if (leg !== 'approval')
125
140
  return null;
126
141
  if (questionCardVerdict(gate) ?? isAskToolLoose(toolName))
127
142
  return 'ask';
128
- if (leg === 'approval')
129
- return 'fs';
130
- return isFsOrShellToolName(toolName) ? 'fs' : null;
143
+ return 'fs';
131
144
  }
132
145
  const ENGINE_GATE_PARKED_ERROR_CODE = GATE_PARKED_ERROR_CODE;
133
146
  function isEngineAbortToolEnd(ev) {
@@ -322,7 +335,7 @@ async function routeToolApprovalFrame(ev, ctx) {
322
335
  }
323
336
  }
324
337
  const fromSubagent = isFromSubagent(ev);
325
- hostLog('debug', `liveHitlAskWire: tool_approval frame ${ev.approvalId} tool=${String(ev.toolName)}${fromSubagent ? ` from-subagent=${String(ev.sourceTaskId ?? ev.sourceAgentName ?? 'explicit')}` : ''}`);
338
+ hostLog('debug', `liveHitlAskWire: tool_approval frame ${ev.approvalId} tool=${String(ev.toolName)}${fromSubagent ? ` from-subagent=${String(subagentSourceSessionOf(ev) ?? ev.sourceAgentName ?? 'explicit')}` : ''}`);
326
339
  const frameCallId = !fromSubagent && typeof ev.toolCallId === 'string' && ev.toolCallId !== '' ? ev.toolCallId : undefined;
327
340
  const gatedCallId = fromSubagent ? undefined : frameCallId ?? led.lastPendingFsCall();
328
341
  const argsCallId = frameCallId === undefined ? gatedCallId : typeof ev.toolName === 'string' && toolNameIsFsWrite(ev.toolName) ? frameCallId : undefined;
@@ -3,6 +3,7 @@ export declare const REOPEN_ID_TAIL = "#reopen-";
3
3
  export declare function approvalCallKey(gatedCallId: string | undefined, taskId: string): string;
4
4
  export declare function askGateQuestionId(callKey: string): string;
5
5
  export declare function planReviewQuestionId(taskId: string): string;
6
+ export declare function freshPlanReviewQuestionId(taskId: string, suffix: string): string;
6
7
  export declare function liveFrameCallKey(approvalId: string): string;
7
8
  export declare function taskIdFromPlanReviewQuestionId(questionId: string): string | undefined;
8
9
  export declare function armedKeyFromQuestionId(questionId: string): string;
@@ -11,6 +11,9 @@ export function askGateQuestionId(callKey) {
11
11
  export function planReviewQuestionId(taskId) {
12
12
  return `${PLAN_REVIEW_QUESTION_ID_PREFIX}${taskId}`;
13
13
  }
14
+ export function freshPlanReviewQuestionId(taskId, suffix) {
15
+ return `${planReviewQuestionId(taskId)}${REOPEN_ID_TAIL}${suffix}`;
16
+ }
14
17
  export function liveFrameCallKey(approvalId) {
15
18
  return `${HITL_FRAME_CALL_KEY_PREFIX}${approvalId}`;
16
19
  }
@@ -26,7 +26,7 @@ export interface AssistantResourceLike {
26
26
  planReview(taskId: string, req: PlanReviewRequest, opts?: {
27
27
  signal?: AbortSignal;
28
28
  }): Promise<AssistantTaskStatus>;
29
- resume(taskId: string, opts?: {
29
+ resume(taskId: string, body?: undefined, opts?: {
30
30
  signal?: AbortSignal;
31
31
  }): Promise<AssistantTaskStatus>;
32
32
  }