@sema-agent/client-core 0.98.0 → 0.100.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 (236) hide show
  1. package/CHANGELOG.md +376 -0
  2. package/README.md +61 -35
  3. package/dist/adapt/arms.js +120 -55
  4. package/dist/adapt/panelTasks.d.ts +3 -2
  5. package/dist/adapt/panelTasks.js +34 -11
  6. package/dist/adapt/textStream.d.ts +1 -1
  7. package/dist/adapt/textStream.js +51 -28
  8. package/dist/adapter/activeRunSelfHeal.d.ts +11 -3
  9. package/dist/adapter/activeRunSelfHeal.js +210 -294
  10. package/dist/adapter/downstream/eventToSdkMessage.d.ts +25 -6
  11. package/dist/adapter/downstream/eventToSdkMessage.js +176 -12
  12. package/dist/adapter/downstream/terminalToSdkResult.js +10 -0
  13. package/dist/adapter/downstream/wiringManifestView.d.ts +3 -1
  14. package/dist/adapter/downstream/wiringManifestView.js +1 -0
  15. package/dist/adapter/runStream.js +82 -40
  16. package/dist/adapter/types.d.ts +2 -0
  17. package/dist/adapter/types.js +2 -1
  18. package/dist/agentSession/engineSessionBackgroundStop.js +16 -8
  19. package/dist/agentsWireCaps.d.ts +7 -3
  20. package/dist/agentsWireCaps.js +133 -39
  21. package/dist/cloudConfigWireCaps.d.ts +10 -1
  22. package/dist/cloudConfigWireCaps.js +181 -65
  23. package/dist/compactionStatus.d.ts +34 -0
  24. package/dist/compactionStatus.js +196 -0
  25. package/dist/controlRouter.d.ts +4 -2
  26. package/dist/controlRouter.js +39 -51
  27. package/dist/coreValuePorts.d.ts +26 -1
  28. package/dist/coreValuePorts.js +10 -0
  29. package/dist/corruptSessionCopy.d.ts +2 -1
  30. package/dist/corruptSessionCopy.js +3 -3
  31. package/dist/decideFailureNote.js +3 -3
  32. package/dist/declared/supportFloorDeclared.js +1 -1
  33. package/dist/detachWire.js +3 -2
  34. package/dist/devicesFace.d.ts +34 -0
  35. package/dist/devicesFace.js +90 -0
  36. package/dist/displayUntrusted.d.ts +1 -0
  37. package/dist/displayUntrusted.js +153 -5
  38. package/dist/engineAgentPanelStore.d.ts +14 -4
  39. package/dist/engineAgentPanelStore.js +14 -0
  40. package/dist/engineCapReader.d.ts +2 -1
  41. package/dist/engineCapReader.js +7 -5
  42. package/dist/engineCapsCache.d.ts +8 -0
  43. package/dist/engineCapsCache.js +59 -6
  44. package/dist/engineCapsChange.d.ts +2 -0
  45. package/dist/engineCapsChange.js +9 -0
  46. package/dist/engineErrorCodes.d.ts +11 -2
  47. package/dist/engineErrorCodes.js +11 -12
  48. package/dist/engineRowRef.js +4 -0
  49. package/dist/engineSessionMessages.d.ts +1 -0
  50. package/dist/engineSessionMessages.js +7 -1
  51. package/dist/engineTargetSeat.d.ts +27 -0
  52. package/dist/engineTargetSeat.js +199 -0
  53. package/dist/engineToolDirectory.d.ts +3 -0
  54. package/dist/engineToolDirectory.js +4 -2
  55. package/dist/engineWireFor.js +3 -8
  56. package/dist/env/uiLanguage.d.ts +2 -1
  57. package/dist/env/uiLanguage.js +3 -2
  58. package/dist/eventLeg.d.ts +7 -5
  59. package/dist/eventLeg.js +68 -49
  60. package/dist/fileHistoryCaptureCapability.d.ts +2 -4
  61. package/dist/fileHistoryCaptureCapability.js +12 -22
  62. package/dist/fileHistoryLegNotice.d.ts +2 -1
  63. package/dist/fileHistoryLegNotice.js +3 -3
  64. package/dist/frameBinding.d.ts +3 -0
  65. package/dist/frameBinding.js +12 -0
  66. package/dist/gateOutcome.js +16 -2
  67. package/dist/gateVocabulary.d.ts +8 -7
  68. package/dist/gateVocabulary.js +71 -73
  69. package/dist/generated/engineFactTables.d.ts +18 -1
  70. package/dist/generated/engineFactTables.js +56 -0
  71. package/dist/generated/engineNoticeTables.js +12 -3
  72. package/dist/generated/settingsSchemaFns.d.ts +18 -0
  73. package/dist/generated/settingsSchemaFns.js +70 -0
  74. package/dist/generated/settingsSchemaHooksClassifier.d.ts +2 -0
  75. package/dist/generated/settingsSchemaHooksClassifier.js +254 -0
  76. package/dist/generated/settingsSchemaMcpRequestEntry.d.ts +1 -0
  77. package/dist/generated/settingsSchemaMcpRequestEntry.js +162 -0
  78. package/dist/generated/settingsSchemaTables.d.ts +2 -0
  79. package/dist/generated/settingsSchemaTables.js +9 -0
  80. package/dist/generated/settingsSchemaTypes.d.ts +133 -0
  81. package/dist/generated/settingsSchemaTypes.js +1 -0
  82. package/dist/hitl/allowRuleShadow.d.ts +2 -1
  83. package/dist/hitl/allowRuleShadow.js +18 -15
  84. package/dist/hitl/approvalCardReasons.d.ts +3 -2
  85. package/dist/hitl/approvalCardReasons.js +29 -30
  86. package/dist/hitl/approvalHolds.d.ts +17 -0
  87. package/dist/hitl/approvalHolds.js +114 -29
  88. package/dist/hitl/askClassPair.d.ts +2 -2
  89. package/dist/hitl/askClassPair.js +16 -0
  90. package/dist/hitl/askGateWire.js +2 -1
  91. package/dist/hitl/askSettlementLine.d.ts +14 -4
  92. package/dist/hitl/askSettlementLine.js +67 -47
  93. package/dist/hitl/attributionLadder.d.ts +23 -0
  94. package/dist/hitl/attributionLadder.js +67 -0
  95. package/dist/hitl/automaticAnswerVerdict.d.ts +2 -1
  96. package/dist/hitl/automaticAnswerVerdict.js +8 -8
  97. package/dist/hitl/crashConvergedNotice.d.ts +5 -4
  98. package/dist/hitl/crashConvergedNotice.js +28 -41
  99. package/dist/hitl/decisionLedger.d.ts +55 -0
  100. package/dist/hitl/decisionLedger.js +156 -0
  101. package/dist/hitl/decisionRefusal.d.ts +1 -0
  102. package/dist/hitl/decisionRefusal.js +1 -1
  103. package/dist/hitl/decisionSend.d.ts +113 -0
  104. package/dist/hitl/decisionSend.js +579 -0
  105. package/dist/hitl/frameRouter.js +7 -8
  106. package/dist/hitl/hitlBridge.d.ts +1 -0
  107. package/dist/hitl/hitlBridge.js +21 -9
  108. package/dist/hitl/persistedRulesWire.d.ts +6 -5
  109. package/dist/hitl/persistedRulesWire.js +55 -73
  110. package/dist/hitl/planReviewWire.d.ts +5 -0
  111. package/dist/hitl/planReviewWire.js +53 -76
  112. package/dist/hitl/sessionPolicyDeliverable.d.ts +2 -0
  113. package/dist/hitl/sessionPolicyDeliverable.js +49 -9
  114. package/dist/hitl/sessionPolicyWire.d.ts +2 -1
  115. package/dist/hitl/sessionPolicyWire.js +23 -24
  116. package/dist/hitl/suspendedReopen.d.ts +2 -1
  117. package/dist/hitl/suspendedReopen.js +7 -10
  118. package/dist/hitl/toolApprovalWire.d.ts +17 -5
  119. package/dist/hitl/toolApprovalWire.js +120 -147
  120. package/dist/hooksWireCaps.js +145 -56
  121. package/dist/host.d.ts +21 -0
  122. package/dist/hostTurnSettings.d.ts +110 -0
  123. package/dist/hostTurnSettings.js +692 -0
  124. package/dist/humanTurn.d.ts +15 -1
  125. package/dist/humanTurn.js +100 -12
  126. package/dist/humanTurnRead.d.ts +2 -0
  127. package/dist/humanTurnRead.js +22 -1
  128. package/dist/i18n/messages.en.d.ts +713 -0
  129. package/dist/i18n/messages.en.js +713 -0
  130. package/dist/i18n/messages.zh.js +854 -1
  131. package/dist/index.d.ts +45 -13
  132. package/dist/index.js +27 -9
  133. package/dist/inheritEnvCapability.d.ts +4 -2
  134. package/dist/inheritEnvCapability.js +12 -5
  135. package/dist/inheritEnvWire.d.ts +3 -2
  136. package/dist/inheritEnvWire.js +14 -16
  137. package/dist/injectionLaneNotice.d.ts +5 -0
  138. package/dist/injectionLaneNotice.js +46 -0
  139. package/dist/interactiveHalt.js +17 -6
  140. package/dist/liveModelCatalog.d.ts +2 -1
  141. package/dist/liveModelCatalog.js +14 -8
  142. package/dist/mcpPanel.d.ts +10 -1
  143. package/dist/mcpPanel.js +42 -13
  144. package/dist/mcpProbeCapability.d.ts +2 -1
  145. package/dist/mcpProbeCapability.js +7 -11
  146. package/dist/mcpProbeWire.d.ts +3 -1
  147. package/dist/mcpProbeWire.js +5 -0
  148. package/dist/mcpReconnect.js +2 -2
  149. package/dist/mcpToolToggles.d.ts +6 -0
  150. package/dist/mcpToolToggles.js +46 -0
  151. package/dist/mcpWireCaps.d.ts +43 -3
  152. package/dist/mcpWireCaps.js +194 -59
  153. package/dist/mcpWireTransport.d.ts +4 -0
  154. package/dist/mcpWireTransport.js +18 -0
  155. package/dist/memoryEntriesWire.js +5 -10
  156. package/dist/model/onboardJudgement.d.ts +93 -0
  157. package/dist/model/onboardJudgement.js +415 -0
  158. package/dist/model/tierVocabulary.d.ts +2 -0
  159. package/dist/model/tierVocabulary.js +17 -5
  160. package/dist/modelCapabilityProbe.d.ts +65 -0
  161. package/dist/modelCapabilityProbe.js +601 -0
  162. package/dist/modelIdentityResolvability.d.ts +5 -0
  163. package/dist/modelIdentityResolvability.js +49 -22
  164. package/dist/ownKey.d.ts +33 -0
  165. package/dist/ownKey.js +109 -0
  166. package/dist/panelReduce.d.ts +11 -1
  167. package/dist/panelReduce.js +95 -16
  168. package/dist/panelStateHolder.d.ts +1 -0
  169. package/dist/panelStateHolder.js +10 -1
  170. package/dist/permissionRuleIssue.d.ts +2 -1
  171. package/dist/permissionRuleIssue.js +23 -20
  172. package/dist/permissionRulesWriteCapability.d.ts +2 -1
  173. package/dist/permissionRulesWriteCapability.js +8 -6
  174. package/dist/pluginHooksWire.d.ts +46 -3
  175. package/dist/pluginHooksWire.js +220 -12
  176. package/dist/prepareRefusal.d.ts +8 -0
  177. package/dist/prepareRefusal.js +72 -0
  178. package/dist/printModelStatus.d.ts +63 -0
  179. package/dist/printModelStatus.js +155 -0
  180. package/dist/request/taskRequest.d.ts +16 -10
  181. package/dist/request/taskRequest.js +195 -58
  182. package/dist/resumeRefusalCopy.d.ts +14 -9
  183. package/dist/resumeRefusalCopy.js +89 -144
  184. package/dist/retryStatus.d.ts +55 -0
  185. package/dist/retryStatus.js +155 -19
  186. package/dist/ruleRefusalSentence.d.ts +4 -0
  187. package/dist/ruleRefusalSentence.js +58 -0
  188. package/dist/sandboxWire.d.ts +2 -1
  189. package/dist/sandboxWire.js +55 -21
  190. package/dist/scenarioRefusal.d.ts +10 -0
  191. package/dist/scenarioRefusal.js +111 -0
  192. package/dist/seam.d.ts +48 -9
  193. package/dist/seam.js +54 -5
  194. package/dist/seatContract.d.ts +272 -14
  195. package/dist/seatContract.js +711 -23
  196. package/dist/selfOrchestrationDenial.js +7 -19
  197. package/dist/sessionIdSegment.d.ts +6 -0
  198. package/dist/sessionIdSegment.js +24 -0
  199. package/dist/sessionMemoryStatus.js +6 -11
  200. package/dist/sessionPolicyCapability.d.ts +2 -1
  201. package/dist/sessionPolicyCapability.js +8 -6
  202. package/dist/settingsCredentialKeyPaths.d.ts +8 -0
  203. package/dist/settingsCredentialKeyPaths.js +219 -0
  204. package/dist/settingsHooksSalvage.d.ts +44 -0
  205. package/dist/settingsHooksSalvage.js +211 -0
  206. package/dist/skillToolListsCapability.d.ts +2 -1
  207. package/dist/skillToolListsCapability.js +8 -6
  208. package/dist/skillsWireCaps.d.ts +0 -3
  209. package/dist/skillsWireCaps.js +1 -2
  210. package/dist/sseIdleTriage.js +3 -2
  211. package/dist/subagent/engineSubagentResume.js +15 -9
  212. package/dist/subagentContentStore.d.ts +4 -0
  213. package/dist/subagentContentStore.js +157 -27
  214. package/dist/toolHistoryMismatch.js +3 -2
  215. package/dist/toolRoster.d.ts +3 -2
  216. package/dist/toolRoster.js +21 -20
  217. package/dist/toolsFlagNames.d.ts +8 -0
  218. package/dist/toolsFlagNames.js +110 -0
  219. package/dist/turnFailurePresentation.d.ts +12 -1
  220. package/dist/turnFailurePresentation.js +220 -15
  221. package/dist/usageAnalytics.js +6 -11
  222. package/dist/userAttachmentEnvelope.d.ts +1 -0
  223. package/dist/userAttachmentEnvelope.js +37 -7
  224. package/dist/userAttachmentSeat.d.ts +21 -0
  225. package/dist/userAttachmentSeat.js +75 -0
  226. package/dist/userInvokedSkillsCapability.d.ts +11 -1
  227. package/dist/userInvokedSkillsCapability.js +31 -7
  228. package/dist/wireErrorTriage.d.ts +7 -0
  229. package/dist/wireErrorTriage.js +23 -1
  230. package/dist/wireFailureShape.js +2 -1
  231. package/dist/wireRefusalCopy.d.ts +62 -16
  232. package/dist/wireRefusalCopy.js +307 -148
  233. package/dist/workflowsJournalCapability.d.ts +2 -1
  234. package/dist/workflowsJournalCapability.js +8 -6
  235. package/docs/INTEGRATION-CLIENTS.md +951 -42
  236. package/package.json +5 -5
@@ -11,15 +11,17 @@ import { readAllowRuleShadowFromWire, retiredAllowRuleShadowKeyPresent, RETIRED_
11
11
  import { createSessionSlot, DEFAULT_SESSION_KEY } from '../sessionSlot.js';
12
12
  import { readEngineActiveBgTasks } from '../fleet/fleetLedger.js';
13
13
  import { CORE_SKILL_TOOL_NAME } from '../generated/toolNameTables.js';
14
+ import { CORE_ALLOW_ENTRY_INERT_REASONS } from '../generated/engineFactTables.js';
15
+ import { msg, renderMessage } from '../i18n/translate.js';
14
16
  import { INTERRUPT_DENY_REASON, observeCancelByDeny, surfaceApprovalParking, surfaceRememberNotApplied, surfaceEditNotForwarded, surfaceEditRefusedOnBlindAsk, surfaceRuleArmNotSent, surfaceRuleArmRejected } from './hitlHostSurface.js';
15
17
  import { approvalCallKey, liveFrameCallKey } from './gateIdentity.js';
16
18
  import { displayUntrusted } from '../displayUntrusted.js';
17
19
  import { frameBindingOf } from '../frameBinding.js';
18
- import { approvalDecisionHolds, approvalHoldFor, awaitApprovalHolder, claimApprovalCardFor, holdLiveCard, joinLiveCard, liveCardHoldOf, clearSettledApprovals, noteHolderSettledApproval, settledApprovalOf, settledForDurableLane, settledLiveCardOutcome } from './approvalHolds.js';
20
+ import { carriesAttributionKey, deliverWithAttributionLadder } from './attributionLadder.js';
21
+ import { approvalDecisionHolds, approvalHoldFor, awaitApprovalHolder, claimApprovalCardFor, enterLiveRespondPhase, holdLiveCard, joinLiveCard, liveCardHoldOf, clearSettledApprovals, noteHolderSettledApproval, settledApprovalOf, settledForDurableLane, settledLiveCardOutcome } from './approvalHolds.js';
19
22
  import { joinedResolution, resolutionOfDecisionFailure } from './approvalResolution.js';
20
23
  import { parkRowDeadlineState } from './parkExpiryJudgements.js';
21
24
  import { isApprovalMandateWord } from '../gateVocabulary.js';
22
- import { denyAttributionRefusalFromError } from '../wireRefusalCopy.js';
23
25
  import { approvalDecidedByAdmitted } from '../approvalDecidedByCapability.js';
24
26
  import { decideFailureNote } from '../decideFailureNote.js';
25
27
  import { wireFailureTextsOf } from '../wireFailureShape.js';
@@ -460,49 +462,30 @@ async function presentFsApprovalAndDecide(deps, taskId, argsByCall, signal, foun
460
462
  try {
461
463
  const denyPayload = { decision: 'deny', reason: answerPayloadFor({ kind: 'deny', ...(denyReasonSnapshot !== undefined ? { reason: denyReasonSnapshot } : {}) }, 'decide').reason };
462
464
  const denyBody = { ...denyPayload, ...attributionKeys };
463
- let attributionDropped = false;
464
- let attributionRenamed = false;
465
+ const ladder = { lastCarried: carriesAttributionKey(attributionKeys), dropped: false, renamed: false };
465
466
  let raw;
466
- lastSendCarriedAttribution = carriesAttributionKey(attributionKeys);
467
+ lastSendCarriedAttribution = ladder.lastCarried;
467
468
  emitAnswerCommitted(callKey, 'decide', card, denyPayload);
468
469
  try {
469
- raw = await bridge.decideTool(denyBody, gatedCallId, decideOpts, pending);
470
+ raw = await deliverWithAttributionLadder(denyBody, (b) => bridge.decideTool(b, gatedCallId, decideOpts, pending), signal, ladder, (step) => {
471
+ hostLog('debug', step === 'renamed'
472
+ ? `liveToolApprovalWire: decide(deny) for task ${taskId} was refused because the settlement note was sent under a name ` +
473
+ 'this engine has retired — re-sending the SAME decision exactly once with that one key renamed to the name the refusal points to ' +
474
+ '(the refusal happened before the approval was judged, so nothing was consumed and this is a re-delivery, not a second act)'
475
+ : step === 'dropped'
476
+ ? `liveToolApprovalWire: decide(deny) for task ${taskId} was refused because the settlement note is not part of ` +
477
+ 'what this deployment signs — re-sending the SAME decision exactly once with that one key removed ' +
478
+ '(the refusal happened before the approval was judged, so nothing was consumed and this is a re-delivery, not a second act)'
479
+ : `liveToolApprovalWire: decide(deny) for task ${taskId} was refused again because the settlement note is not part of ` +
480
+ 'what this deployment signs — re-sending the SAME decision exactly once more with that key removed ' +
481
+ '(still before the approval was judged)');
482
+ });
470
483
  }
471
- catch (first) {
472
- if (shouldResendWithoutAttribution(first, lastSendCarriedAttribution, signal)) {
473
- const withoutAttribution = withoutAttributionKey(denyBody);
474
- lastSendCarriedAttribution = false;
475
- hostLog('debug', `liveToolApprovalWire: decide(deny) for task ${taskId} was refused because the settlement note is not part of ` +
476
- 'what this deployment signs — re-sending the SAME decision exactly once with that one key removed ' +
477
- '(the refusal happened before the approval was judged, so nothing was consumed and this is a re-delivery, not a second act)');
478
- raw = await bridge.decideTool(withoutAttribution, gatedCallId, decideOpts, pending);
479
- attributionDropped = true;
480
- }
481
- else if (shouldResendUnderSuccessorKey(first, Object.hasOwn(denyBody, 'settledBy'), signal)) {
482
- const renamed = withAttributionKeyRenamed(denyBody);
483
- hostLog('debug', `liveToolApprovalWire: decide(deny) for task ${taskId} was refused because the settlement note was sent under a name ` +
484
- 'this engine has retired — re-sending the SAME decision exactly once with that one key renamed to the name the refusal points to ' +
485
- '(the refusal happened before the approval was judged, so nothing was consumed and this is a re-delivery, not a second act)');
486
- try {
487
- raw = await bridge.decideTool(renamed, gatedCallId, decideOpts, pending);
488
- attributionRenamed = true;
489
- }
490
- catch (second) {
491
- if (!shouldResendWithoutAttribution(second, true, signal))
492
- throw second;
493
- const renamedWithoutAttribution = withoutAttributionKey(renamed);
494
- lastSendCarriedAttribution = false;
495
- hostLog('debug', `liveToolApprovalWire: decide(deny) for task ${taskId} was refused again because the settlement note is not part of ` +
496
- 'what this deployment signs — re-sending the SAME decision exactly once more with that key removed ' +
497
- '(still before the approval was judged)');
498
- raw = await bridge.decideTool(renamedWithoutAttribution, gatedCallId, decideOpts, pending);
499
- attributionDropped = true;
500
- }
501
- }
502
- else {
503
- throw first;
504
- }
484
+ finally {
485
+ lastSendCarriedAttribution = ladder.lastCarried;
505
486
  }
487
+ const attributionDropped = ladder.dropped;
488
+ const attributionRenamed = ladder.renamed;
506
489
  const receipt = readDecideReceipt(raw);
507
490
  const deny = denyFactsOf(denySettledByForWire, denyReasonSnapshot, attributionDropped, attributionRenamed);
508
491
  return {
@@ -870,39 +853,11 @@ function readPersistedRuleAnchors(v) {
870
853
  function isNonNegativeSafeInt(v) {
871
854
  return typeof v === 'number' && Number.isSafeInteger(v) && v >= 0;
872
855
  }
873
- function shouldResendWithoutAttribution(e, sentAttributionKey, signal) {
874
- if (!sentAttributionKey)
875
- return false;
876
- if (signal?.aborted === true)
877
- return false;
878
- return denyAttributionRefusalFromError(e, true)?.kind === 'not_in_proof';
879
- }
880
- function shouldResendUnderSuccessorKey(e, lastSendCarriedRetiredKey, signal) {
881
- if (!lastSendCarriedRetiredKey)
882
- return false;
883
- if (signal?.aborted === true)
884
- return false;
885
- return denyAttributionRefusalFromError(e, true)?.kind === 'retired_key';
886
- }
887
856
  export function decisionAttributionKeyOf(reading, denySettledBy) {
888
857
  if (denySettledBy !== 'policy')
889
858
  return {};
890
859
  return approvalDecidedByAdmitted(reading) ? { decidedBy: 'policy' } : { settledBy: 'policy' };
891
860
  }
892
- function carriesAttributionKey(body) {
893
- return Object.hasOwn(body, 'settledBy') || Object.hasOwn(body, 'decidedBy');
894
- }
895
- function withoutAttributionKey(body) {
896
- const { settledBy: _droppedSettledBy, decidedBy: _droppedDecidedBy, ...rest } = body;
897
- void _droppedSettledBy;
898
- void _droppedDecidedBy;
899
- return rest;
900
- }
901
- function withAttributionKeyRenamed(body) {
902
- const { settledBy, decidedBy: _replaced, ...rest } = body;
903
- void _replaced;
904
- return settledBy === undefined ? rest : { ...rest, decidedBy: settledBy };
905
- }
906
861
  function readDecidedByReadingOf(holder) {
907
862
  try {
908
863
  return readOwnDataValue(holder, 'approvalDecidedBy');
@@ -967,23 +922,24 @@ function usableProbeReason(raw) {
967
922
  return typeof raw === 'string' && raw.trim() !== '' ? raw : undefined;
968
923
  }
969
924
  const PROBE_CAUSE_CODE_WORD = /^[a-z][a-z0-9_]{0,31}(?:\.[a-z][a-z0-9_]{0,31}){1,3}$/;
970
- export function askProbeReasonDetail(card) {
925
+ export function askProbeReasonDetail(card, lang) {
971
926
  const prose = usableProbeReason(ownDataValue(card, 'probeReason'));
972
927
  const shown = prose === undefined ? '' : displayUntrusted(prose);
973
- const sentence = probeCauseSentence(ownDataValue(card, 'probeCause'), shown !== '');
928
+ const sentence = probeCauseSentence(ownDataValue(card, 'probeCause'), shown !== '', lang);
974
929
  if (sentence === undefined)
975
930
  return shown === '' ? undefined : shown;
976
- return shown === '' ? sentence : `${sentence} ${shown}`;
931
+ return shown === '' ? sentence : renderMessage(msg('approval.probe.proseJoin', { sentence, prose: shown }), lang);
977
932
  }
978
- function probeCauseSentence(cause, withProse) {
933
+ function probeCauseSentence(cause, withProse, lang) {
979
934
  try {
980
935
  if (!isWireRecordCarrier(cause))
981
936
  return undefined;
982
937
  const code = ownDataValue(cause, 'code');
983
- const head = withProse
984
- ? 'An automatic check could not clear this call, so it is asking you'
985
- : 'An automatic check could not clear this call, so it is asking you; the engine did not say the specific reason';
986
- return typeof code === 'string' && PROBE_CAUSE_CODE_WORD.test(code) ? `${head} (check code: ${code}).` : `${head}.`;
938
+ const withCode = typeof code === 'string' && PROBE_CAUSE_CODE_WORD.test(code);
939
+ const key = withProse
940
+ ? withCode ? 'approval.probe.withProseCode' : 'approval.probe.withProse'
941
+ : withCode ? 'approval.probe.noProseCode' : 'approval.probe.noProse';
942
+ return renderMessage(withCode ? msg(key, { code: displayUntrusted(code) }) : msg(key), lang);
987
943
  }
988
944
  catch {
989
945
  return undefined;
@@ -1041,6 +997,21 @@ export function readApprovalBoundGrants(v) {
1041
997
  return undefined;
1042
998
  return Object.freeze({ skill, allowedTools, disallowedTools });
1043
999
  }
1000
+ const READS_AS_NOTHING_HEAD = '<reads as nothing (';
1001
+ export function readBoundGrantEntry(entry) {
1002
+ if (typeof entry !== 'string' || entry === '')
1003
+ return undefined;
1004
+ if (!entry.startsWith('<'))
1005
+ return Object.freeze({ kind: 'rule' });
1006
+ if (entry.startsWith(READS_AS_NOTHING_HEAD)) {
1007
+ const close = entry.indexOf('): ', READS_AS_NOTHING_HEAD.length);
1008
+ const word = close > 0 ? entry.slice(READS_AS_NOTHING_HEAD.length, close) : undefined;
1009
+ if (word !== undefined && CORE_ALLOW_ENTRY_INERT_REASONS.includes(word)) {
1010
+ return Object.freeze({ kind: 'reads_as_nothing', reason: word });
1011
+ }
1012
+ }
1013
+ return Object.freeze({ kind: 'reads_as_nothing' });
1014
+ }
1044
1015
  const BOUND_GRANT_NOT_BINDABLE = 'not_bindable';
1045
1016
  const SERVER_CLASS_READ_CAP = 64;
1046
1017
  function readApprovalGrantBinding(carrier) {
@@ -1161,34 +1132,45 @@ export function readApprovalClassifierNoRuling(v) {
1161
1132
  return typeof w === 'string' && CAUSE_WORD.test(w) ? w : undefined;
1162
1133
  }
1163
1134
  const CLASSIFIER_NO_RULING_REASONS = Object.freeze({
1164
- error: 'could not run for this call (it failed)',
1165
- timeout: 'could not run for this call (it timed out)',
1166
- parse_error: 'answered for this call but gave no verdict it could use',
1135
+ error: 'approval.classifier.noRulingError',
1136
+ timeout: 'approval.classifier.noRulingTimeout',
1137
+ parse_error: 'approval.classifier.noRulingParseError',
1167
1138
  });
1168
1139
  const _noRulingPin = [true, true];
1169
1140
  void _noRulingPin;
1170
- export function classifierNoRulingDetail(word) {
1141
+ export function classifierNoRulingDetail(word, lang) {
1171
1142
  if (typeof word === 'string' && Object.hasOwn(CLASSIFIER_NO_RULING_REASONS, word)) {
1172
- return `The auto-mode classifier ${CLASSIFIER_NO_RULING_REASONS[word]}, so it is asking you instead.`;
1143
+ return renderMessage(msg(CLASSIFIER_NO_RULING_REASONS[word]), lang);
1173
1144
  }
1174
1145
  if (typeof word === 'string' && CAUSE_WORD.test(word))
1175
- return `The auto-mode classifier did not rule on this call (reason: ${word}), so it is asking you instead.`;
1176
- return 'The auto-mode classifier did not rule on this call, so it is asking you instead.';
1146
+ return renderMessage(msg('approval.classifier.noRulingOther', { reason: displayUntrusted(word) }), lang);
1147
+ return renderMessage(msg('approval.classifier.noRulingBare'), lang);
1177
1148
  }
1178
- const entries = (n) => (n === 1 ? '1 tool entry' : `${String(n)} tool entries`);
1179
- export function approvalBoundGrantsDetail(grants) {
1149
+ export function approvalBoundGrantsDetail(grants, lang) {
1180
1150
  const g = readApprovalBoundGrants({ boundGrants: grants });
1181
1151
  if (g === undefined)
1182
1152
  return undefined;
1183
1153
  if (g.skill === null)
1184
- return 'This call names no loaded skill, so approving it grants nothing beyond this call.';
1185
- const a = g.allowedTools.length;
1186
- const d = g.disallowedTools.length;
1187
- if (a === 0 && d === 0)
1188
- return 'Approving this activates the skill shown on the card; it lists no tools to run without asking and none to refuse.';
1189
- const allow = `${entries(a)} it lists ${a === 1 ? 'runs' : 'run'} without asking once it is active`;
1190
- const deny = `${entries(d)} ${d === 1 ? 'is' : 'are'} refused for the rest of this run`;
1191
- return `Approving this activates the skill shown on the card: ${allow}, and ${deny}.`;
1154
+ return renderMessage(msg('approval.boundGrants.noSkill'), lang);
1155
+ const isRule = (e) => readBoundGrantEntry(e)?.kind === 'rule';
1156
+ const a = g.allowedTools.filter(isRule).length;
1157
+ const d = g.disallowedTools.filter(isRule).length;
1158
+ const allowNothing = g.allowedTools.length - a;
1159
+ const denyNothing = g.disallowedTools.length - d;
1160
+ if (denyNothing > 0) {
1161
+ return renderMessage(denyNothing === 1 ? msg('approval.boundGrants.notActivated.one') : msg('approval.boundGrants.notActivated.other', { count: String(denyNothing) }), lang);
1162
+ }
1163
+ if (a === 0 && d === 0) {
1164
+ if (allowNothing > 0)
1165
+ return renderMessage(allowNothing === 1 ? msg('approval.boundGrants.listsNoToolsWithNothing.one') : msg('approval.boundGrants.listsNoToolsWithNothing.other', { count: String(allowNothing) }), lang);
1166
+ return renderMessage(msg('approval.boundGrants.listsNoTools'), lang);
1167
+ }
1168
+ const allow = a === 1 ? msg('approval.boundGrants.allowPart.one') : msg('approval.boundGrants.allowPart.other', { count: a });
1169
+ const deny = d === 1 ? msg('approval.boundGrants.denyPart.one') : msg('approval.boundGrants.denyPart.other', { count: d });
1170
+ if (allowNothing > 0) {
1171
+ return renderMessage(allowNothing === 1 ? msg('approval.boundGrants.activatesWithNothing.one', { allow, deny }) : msg('approval.boundGrants.activatesWithNothing.other', { allow, deny, count: String(allowNothing) }), lang);
1172
+ }
1173
+ return renderMessage(msg('approval.boundGrants.activates', { allow, deny }), lang);
1192
1174
  }
1193
1175
  const CALL_LEDGER_MAX_CALLS = 256;
1194
1176
  const CALL_LEDGER_MAX_ASKS_PER_CALL = 8;
@@ -1289,7 +1271,7 @@ function noteCallOutcome(slot, r) {
1289
1271
  const fateRank = { not_sent: 0, not_accepted: 1, unconfirmed: 2 };
1290
1272
  entry.answerFate = entry.answerFate !== undefined && fateRank[entry.answerFate] > fateRank[next] ? entry.answerFate : next;
1291
1273
  }
1292
- export function approvalPriorCardsDetail(card) {
1274
+ export function approvalPriorCardsDetail(card, lang) {
1293
1275
  const prior = ownDataValue(card, 'priorCardsForCall');
1294
1276
  let isList = false;
1295
1277
  try {
@@ -1307,13 +1289,12 @@ export function approvalPriorCardsDetail(card) {
1307
1289
  for (let i = 0; i < length; i++)
1308
1290
  items.push(ownDataValue(prior, String(i)));
1309
1291
  const outcome = ownDataValue(items[length - 1], 'outcome');
1310
- const earlier = outcome === 'allowed' ? 'you already approved an earlier one' : outcome === 'denied' ? 'an earlier one was denied' : 'an earlier one was shown first';
1292
+ const earlier = msg(outcome === 'allowed' ? 'approval.priorCard.earlier.allowed' : outcome === 'denied' ? 'approval.priorCard.earlier.denied' : 'approval.priorCard.earlier.shown');
1311
1293
  const fromRule = items.some((p) => ownDataValue(p, 'origin') === 'ask_rule');
1312
1294
  const thisFromRule = ownDataValue(card, 'origin') === 'ask_rule';
1313
- if (fromRule && !thisFromRule) {
1314
- return `This is a second approval for the same call: ${earlier}, which your ask rule asked for. This one is a separate check, not from your ask rule, and needs its own answer.`;
1315
- }
1316
- return `This is a second approval for the same call: ${earlier}. This one is a separate check and needs its own answer.`;
1295
+ if (fromRule && !thisFromRule)
1296
+ return renderMessage(msg('approval.priorCard.fromRule', { earlier }), lang);
1297
+ return renderMessage(msg('approval.priorCard.plain', { earlier }), lang);
1317
1298
  }
1318
1299
  const PRIOR_ANSWER_PHRASE = Object.freeze({
1319
1300
  allow: 'Yes',
@@ -1710,10 +1691,9 @@ export async function surfaceToolApprovalFrameAndRespond(frame, respond, streamA
1710
1691
  const receivedAtMs = Date.now();
1711
1692
  const approvalId = frame.approvalId;
1712
1693
  const entry = { frame, approvalId, identity: liveCardIdentityOf(approvalId, frame, run), respond, streamArgs, signal, lane, receivedAtMs };
1713
- return enterLiveCard(entry, 0);
1694
+ return enterLiveCard(entry);
1714
1695
  }
1715
- const LIVE_ENTRY_MAX_ROUNDS = 8;
1716
- function enterLiveCard(e, round) {
1696
+ function enterLiveCard(e) {
1717
1697
  const { approvalId, signal } = e;
1718
1698
  const held = liveCardHoldOf(liveFrameCallKey(approvalId));
1719
1699
  if (held !== undefined)
@@ -1721,9 +1701,9 @@ function enterLiveCard(e, round) {
1721
1701
  const settled = settledLiveCardOutcome(approvalId);
1722
1702
  if (settled !== undefined)
1723
1703
  return Promise.resolve(settled);
1724
- const other = round < LIVE_ENTRY_MAX_ROUNDS ? approvalHoldFor(e.identity, (h) => h.lane === 'live') : undefined;
1704
+ const other = approvalHoldFor(e.identity, (h) => h.lane === 'live');
1725
1705
  if (other !== undefined)
1726
- return joinOtherLaneHolder(e, other, round);
1706
+ return joinOtherLaneHolder(e, other);
1727
1707
  return holdLiveCard(e.identity, signal, async (hold) => {
1728
1708
  const slot = {};
1729
1709
  const out = await presentToolApprovalFrameAndRespond(e.frame, approvalId, e.respond, e.streamArgs, signal, e.lane, hold, slot, e.receivedAtMs);
@@ -1731,7 +1711,7 @@ function enterLiveCard(e, round) {
1731
1711
  return out;
1732
1712
  });
1733
1713
  }
1734
- async function joinOtherLaneHolder(e, other, round) {
1714
+ async function joinOtherLaneHolder(e, other) {
1735
1715
  const wait = await awaitApprovalHolder(other, e.signal, 'respond');
1736
1716
  if (wait.kind === 'settled') {
1737
1717
  noteHolderSettledApproval(e.approvalId, wait.how, wait.outcome);
@@ -1739,7 +1719,7 @@ async function joinOtherLaneHolder(e, other, round) {
1739
1719
  }
1740
1720
  if (wait.kind === 'left')
1741
1721
  return { kind: 'not_sent', lane: 'respond', cause: 'retracted', joinedInFlight: true };
1742
- return enterLiveCard(e, round + 1);
1722
+ return enterLiveCard(e);
1743
1723
  }
1744
1724
  function liveCardIdentityOf(approvalId, frame, run) {
1745
1725
  const toolCallId = typeof frame.toolCallId === 'string' && frame.toolCallId !== '' ? frame.toolCallId : undefined;
@@ -1789,8 +1769,20 @@ export async function joinApprovalHolder(identity, signal) {
1789
1769
  return { kind: 'joined', outcome: { kind: 'not_sent', lane: 'decide', cause: 'retracted', joinedInFlight: true } };
1790
1770
  return { kind: 'free' };
1791
1771
  }
1792
- export function claimApprovalCard(identity, signal) {
1793
- return claimApprovalCardFor(readApprovalHolderIdentity(identity), signal);
1772
+ function readApprovalCardClaimSignal(v) {
1773
+ if (typeof v !== 'object' || v === null)
1774
+ return undefined;
1775
+ try {
1776
+ const d = Object.getOwnPropertyDescriptor(v, 'signal');
1777
+ const x = d !== undefined && Object.hasOwn(d, 'value') ? d.value : undefined;
1778
+ return typeof x === 'object' && x !== null ? x : undefined;
1779
+ }
1780
+ catch {
1781
+ return undefined;
1782
+ }
1783
+ }
1784
+ export function claimApprovalCard(identity, options) {
1785
+ return claimApprovalCardFor(readApprovalHolderIdentity(identity), readApprovalCardClaimSignal(options));
1794
1786
  }
1795
1787
  async function presentToolApprovalFrameAndRespond(frame, approvalId, respond, streamArgs, signal, lane, hold, ledgerSlot, receivedAtMs) {
1796
1788
  const frameToolCallId = typeof frame.toolCallId === 'string' && frame.toolCallId !== '' ? frame.toolCallId : undefined;
@@ -1824,7 +1816,7 @@ async function presentToolApprovalFrameAndRespond(frame, approvalId, respond, st
1824
1816
  return { kind: 'not_sent', lane: 'respond', cause: 'retracted' };
1825
1817
  }
1826
1818
  if (card.kind === 'aborted') {
1827
- hold.phase = 'respond';
1819
+ enterLiveRespondPhase(hold);
1828
1820
  const interruptOpts = lane?.approvalDecisionNoteCapable === true ? { note: INTERRUPT_DENY_REASON } : {};
1829
1821
  let interruptDeny;
1830
1822
  try {
@@ -1838,7 +1830,7 @@ async function presentToolApprovalFrameAndRespond(frame, approvalId, respond, st
1838
1830
  hostLog('debug', `liveToolApprovalWire: ${approvalId} card aborted — one tool-level deny issued to settle the pending ask`);
1839
1831
  return { kind: 'unsettled', lane: 'respond', cause: 'interrupted' };
1840
1832
  }
1841
- hold.phase = 'respond';
1833
+ enterLiveRespondPhase(hold);
1842
1834
  const noteCapable = lane?.approvalDecisionNoteCapable === true;
1843
1835
  const denyReasonRead = card.kind === 'deny' ? ((r) => (typeof r === 'string' ? r : undefined))(card.reason) : undefined;
1844
1836
  const answerSnapshot = card.kind === 'deny'
@@ -1943,49 +1935,30 @@ async function presentToolApprovalFrameAndRespond(frame, approvalId, respond, st
1943
1935
  ...(note !== undefined ? { note } : {}),
1944
1936
  ...attributionKeys,
1945
1937
  };
1946
- let attributionDropped = false;
1947
- let attributionRenamed = false;
1938
+ const ladder = { lastCarried: lastSendCarriedAttribution, dropped: false, renamed: false };
1948
1939
  let raw;
1949
1940
  if (basePayload !== undefined)
1950
1941
  emitAnswerCommitted(liveFrameCallKey(approvalId), 'respond', answerSnapshot, basePayload);
1951
1942
  try {
1952
- raw = await respond(approvalId, decision, respondOpts);
1943
+ raw = await deliverWithAttributionLadder(respondOpts, (o) => respond(approvalId, decision, o), signal, ladder, (step) => {
1944
+ hostLog('debug', step === 'renamed'
1945
+ ? `liveToolApprovalWire: respond(deny) for ${approvalId} was refused because the settlement note was sent under a name ` +
1946
+ 'this engine has retired — re-sending the SAME decision exactly once with that one key renamed to the name the refusal points to ' +
1947
+ '(the refusal happened before the approval was judged, so nothing was consumed and this is a re-delivery, not a second act)'
1948
+ : step === 'dropped'
1949
+ ? `liveToolApprovalWire: respond(deny) for ${approvalId} was refused because the settlement note is not part of ` +
1950
+ 'what this deployment signs — re-sending the SAME decision exactly once with that one key removed ' +
1951
+ '(the refusal happened before the approval was judged, so nothing was consumed and this is a re-delivery, not a second act)'
1952
+ : `liveToolApprovalWire: respond(deny) for ${approvalId} was refused again because the settlement note is not part of ` +
1953
+ 'what this deployment signs — re-sending the SAME decision exactly once more with that key removed ' +
1954
+ '(still before the approval was judged)');
1955
+ });
1953
1956
  }
1954
- catch (first) {
1955
- if (shouldResendWithoutAttribution(first, lastSendCarriedAttribution, signal)) {
1956
- const withoutAttribution = withoutAttributionKey(respondOpts);
1957
- lastSendCarriedAttribution = false;
1958
- hostLog('debug', `liveToolApprovalWire: respond(deny) for ${approvalId} was refused because the settlement note is not part of ` +
1959
- 'what this deployment signs — re-sending the SAME decision exactly once with that one key removed ' +
1960
- '(the refusal happened before the approval was judged, so nothing was consumed and this is a re-delivery, not a second act)');
1961
- raw = await respond(approvalId, decision, withoutAttribution);
1962
- attributionDropped = true;
1963
- }
1964
- else if (shouldResendUnderSuccessorKey(first, Object.hasOwn(respondOpts, 'settledBy'), signal)) {
1965
- const renamed = withAttributionKeyRenamed(respondOpts);
1966
- hostLog('debug', `liveToolApprovalWire: respond(deny) for ${approvalId} was refused because the settlement note was sent under a name ` +
1967
- 'this engine has retired — re-sending the SAME decision exactly once with that one key renamed to the name the refusal points to ' +
1968
- '(the refusal happened before the approval was judged, so nothing was consumed and this is a re-delivery, not a second act)');
1969
- try {
1970
- raw = await respond(approvalId, decision, renamed);
1971
- attributionRenamed = true;
1972
- }
1973
- catch (second) {
1974
- if (!shouldResendWithoutAttribution(second, true, signal))
1975
- throw second;
1976
- const renamedWithoutAttribution = withoutAttributionKey(renamed);
1977
- lastSendCarriedAttribution = false;
1978
- hostLog('debug', `liveToolApprovalWire: respond(deny) for ${approvalId} was refused again because the settlement note is not part of ` +
1979
- 'what this deployment signs — re-sending the SAME decision exactly once more with that key removed ' +
1980
- '(still before the approval was judged)');
1981
- raw = await respond(approvalId, decision, renamedWithoutAttribution);
1982
- attributionDropped = true;
1983
- }
1984
- }
1985
- else {
1986
- throw first;
1987
- }
1957
+ finally {
1958
+ lastSendCarriedAttribution = ladder.lastCarried;
1988
1959
  }
1960
+ const attributionDropped = ladder.dropped;
1961
+ const attributionRenamed = ladder.renamed;
1989
1962
  const parkingBody = readToolApprovalRespondParking(raw);
1990
1963
  if (parkingBody !== undefined) {
1991
1964
  const parking = parkingBody.kind === 'parking' && parkingBody.view.approvalId === approvalId ? parkingBody.view : undefined;