@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
@@ -1,9 +1,11 @@
1
1
  import { PROTOCOL_ERROR_NAME, THROWN_SLOT_UNREADABLE, protocolErrorNameOf, readErrorNumber, readErrorRecord, readErrorStrictStringList, readErrorString, readErrorStringList, readRefusalField, readThrownSlot, readThrownStatusSlot } from './wireFailureShape.js';
2
2
  import { readOwnDataValue, readOwnNonEmptyString } from './ownKey.js';
3
- import { ACTIVE_RUN_BUSY_ERROR_CODE, FLEET_LEASE_UNAVAILABLE, REQUEST_AUTONOMY_LANE_REFUSED, REQUEST_FIELD_CONFLICT, RESUME_OUTCOME_INVALID, RESUME_POLICY_FOLD_CODE, SCENARIO_ASSIGNMENT_UNKNOWN_ERROR_CODE, USAGE_WINDOW_EXHAUSTED } from './engineErrorCodes.js';
3
+ import { ACTIVE_RUN_BUSY_ERROR_CODE, FLEET_LEASE_UNAVAILABLE, REQUEST_AUTONOMY_LANE_REFUSED, REQUEST_FIELD_CONFLICT, RESUME_OUTCOME_INVALID, RESUME_POLICY_FOLD_CODE, USAGE_WINDOW_EXHAUSTED, USER_ATTACHMENT_INVALID_ERROR_CODE, USER_INVOKED_SKILL_UNKNOWN_ERROR_CODE } from './engineErrorCodes.js';
4
4
  import { capForDisplay } from './fleetTaskDesc.js';
5
5
  import { effectiveWireErrorCode } from './wireErrorTriage.js';
6
6
  import { CORE_TOOL_DECLARATION_CODES } from './generated/engineFactTables.js';
7
+ import { prepareRefusalNoteOf } from './prepareRefusal.js';
8
+ import { msg, renderMessage } from './i18n/translate.js';
7
9
  export const CONFLICT_APPROVAL_SETTLED = 'conflict.approval_settled';
8
10
  export const CONFLICT_RUN_NOT_RUNNING = 'conflict.run_not_running';
9
11
  function ownNonEmptyStringSlot(o, key) {
@@ -25,17 +27,14 @@ export function cancelConflictFromError(err) {
25
27
  return { kind: 'run_not_running', code };
26
28
  return { kind: 'unrecognized', ...(code !== undefined ? { code } : {}) };
27
29
  }
28
- export function cancelConflictContent(detail) {
30
+ export function cancelConflictContent(detail, lang) {
29
31
  switch (detail.kind) {
30
32
  case 'approval_settled':
31
- return ('The cancel did not apply: the approval this task was waiting on has already been decided or has expired elsewhere · ' +
32
- 'Check what that decision did to the task before doing anything else');
33
+ return renderMessage(msg('notice.wireRefusal.cancel.approvalSettled'), lang);
33
34
  case 'run_not_running':
34
- return ('The cancel could not be set: the task kept switching between running and waiting while the engine tried · ' +
35
- 'Nothing was changed — send the cancel again');
35
+ return renderMessage(msg('notice.wireRefusal.cancel.runNotRunning'), lang);
36
36
  case 'unrecognized':
37
- return ('The engine refused this cancel with a conflict it did not explain · ' +
38
- 'The task may have just been decided elsewhere, or may have changed state mid-cancel — check its current state, then cancel again if it is still active');
37
+ return renderMessage(msg('notice.wireRefusal.cancel.unrecognized'), lang);
39
38
  }
40
39
  }
41
40
  function nonNegativeFinite(v) {
@@ -79,11 +78,11 @@ function humanWait(sec) {
79
78
  const mm = m % 60;
80
79
  return mm === 0 ? `${h} h` : `${h} h ${mm} min`;
81
80
  }
82
- export function usageWindowExhaustedContent(detail) {
83
- const head = "The deployment's usage window is exhausted, so the engine did not accept this request · Nothing is wrong with the request itself";
81
+ export function usageWindowExhaustedContent(detail, lang) {
82
+ const head = renderMessage(msg('notice.wireRefusal.usageWindow.head'), lang);
84
83
  return detail.retryAfterSec !== undefined
85
- ? `${head} · Send it again in about ${humanWait(detail.retryAfterSec)}`
86
- : `${head} · The engine did not say how long the window needs — send it again a little later`;
84
+ ? `${head} · ${renderMessage(msg('notice.wireRefusal.sendAgainAbout', { wait: humanWait(detail.retryAfterSec) }), lang)}`
85
+ : `${head} · ${renderMessage(msg('notice.wireRefusal.usageWindow.unknownWait'), lang)}`;
87
86
  }
88
87
  const positiveFinite = (v) => typeof v === 'number' && Number.isFinite(v) && v > 0;
89
88
  export function fleetLeaseUnavailableFromError(err) {
@@ -111,7 +110,7 @@ export function fleetLeaseUnavailableFromError(err) {
111
110
  ...(sec !== undefined ? { retryAfterSec: sec } : {}),
112
111
  };
113
112
  }
114
- export function fleetLeaseUnavailableContent(detail) {
113
+ export function fleetLeaseUnavailableContent(detail, lang) {
115
114
  let reason;
116
115
  let sec;
117
116
  try {
@@ -126,46 +125,17 @@ export function fleetLeaseUnavailableContent(detail) {
126
125
  catch {
127
126
  sec = undefined;
128
127
  }
129
- const head = "This deployment could not confirm your usage budget with its quota service, and it refuses billed work while it cannot check, so the engine did not accept this request · Nothing is wrong with the request itself";
128
+ const head = renderMessage(msg('notice.wireRefusal.fleetLease.head'), lang);
130
129
  const cause = reason === 'auth-rejected'
131
- ? " · The quota service rejected this engine's credentials — if this keeps happening, whoever operates the engine needs to fix them"
130
+ ? ` · ${renderMessage(msg('notice.wireRefusal.fleetLease.authRejected'), lang)}`
132
131
  : reason === 'unreachable'
133
- ? ' · The engine could not reach the quota service'
132
+ ? ` · ${renderMessage(msg('notice.wireRefusal.fleetLease.unreachable'), lang)}`
134
133
  : '';
135
134
  const wait = positiveFinite(sec)
136
- ? ` · Send it again in about ${humanWait(Math.ceil(sec))}`
137
- : ' · The engine did not say how long to wait — send it again a little later';
135
+ ? ` · ${renderMessage(msg('notice.wireRefusal.sendAgainAbout', { wait: humanWait(Math.ceil(sec)) }), lang)}`
136
+ : ` · ${renderMessage(msg('notice.wireRefusal.fleetLease.unknownWait'), lang)}`;
138
137
  return `${head}${cause}${wait}`;
139
138
  }
140
- export function scenarioAssignmentUnknownFromError(err) {
141
- try {
142
- if (err === null || typeof err !== 'object')
143
- return null;
144
- if (effectiveWireErrorCode(err) !== SCENARIO_ASSIGNMENT_UNKNOWN_ERROR_CODE)
145
- return null;
146
- const detail = readErrorRecord(err, 'detail');
147
- const bit = (key) => {
148
- if (detail === undefined)
149
- return undefined;
150
- try {
151
- return Object.hasOwn(detail, key) ? detail[key] : undefined;
152
- }
153
- catch {
154
- return undefined;
155
- }
156
- };
157
- const scenario = bit('scenario');
158
- const source = bit('source');
159
- return {
160
- code: SCENARIO_ASSIGNMENT_UNKNOWN_ERROR_CODE,
161
- ...(typeof scenario === 'string' && scenario.length > 0 ? { scenario } : {}),
162
- ...(source === 'ruling' || source === 'deployment' ? { source } : {}),
163
- };
164
- }
165
- catch {
166
- return null;
167
- }
168
- }
169
139
  const SETTLED_BY_NOT_IN_PROOF = 'settled_by_not_in_proof';
170
140
  const DECIDED_BY_NOT_IN_PROOF = 'decided_by_not_in_proof';
171
141
  const RETIRED_DECISION_KEY = 'settledBy';
@@ -202,26 +172,19 @@ export function denyAttributionRefusalFromError(err, sentAttributionKey) {
202
172
  return null;
203
173
  }
204
174
  }
205
- export function denyAttributionRefusalContent(detail) {
175
+ export function denyAttributionRefusalContent(detail, lang) {
206
176
  switch (detail.kind) {
207
177
  case 'not_in_proof':
208
- return ('The engine refused this refusal before judging it: this deployment signs the decisions it accepts, and the note saying ' +
209
- 'who settled this one is not part of what gets signed · Nothing was decided and the approval is still waiting — ' +
210
- 'send the same decision again without that note');
178
+ return renderMessage(msg('notice.wireRefusal.denyAttribution.notInProof'), lang);
211
179
  case 'decision_conflict':
212
- return ('The engine refused this decision before judging it: the body says a policy settled it and also asks to allow the call, ' +
213
- 'and only a person can allow one · Nothing was decided and the approval is still waiting — ' +
214
- 'send it again with the decision and the note in agreement');
180
+ return renderMessage(msg('notice.wireRefusal.denyAttribution.decisionConflict'), lang);
215
181
  case 'retired_key':
216
- return ('The engine refused this decision before judging it: the note saying who settled it was sent under a name this engine no longer accepts · ' +
217
- 'Nothing was decided and the approval is still waiting — send the decision again with who made it given under the name the engine now takes in its place');
182
+ return renderMessage(msg('notice.wireRefusal.denyAttribution.retiredKey'), lang);
218
183
  case 'attribution_rejected': {
219
184
  const named = typeof detail.field === 'string' && APPROVAL_NON_BINDING_FIELDS.has(detail.field)
220
- ? ` It named ${detail.field} as the part it would not take.`
185
+ ? renderMessage(msg('notice.wireRefusal.denyAttribution.named', { field: detail.field }), lang)
221
186
  : '';
222
- return ('The engine would not accept the settlement details this decision carried, so it refused the decision before judging it.' +
223
- `${named} · Nothing was decided and the approval is still waiting at the same coordinates — ` +
224
- 'check what that part carried (the only piece this client sets is the note saying who settled the refusal) and decide once more');
187
+ return renderMessage(msg('notice.wireRefusal.denyAttribution.attributionRejected', { named }), lang);
225
188
  }
226
189
  }
227
190
  }
@@ -252,36 +215,36 @@ export function sessionDeleteConflictFromError(err) {
252
215
  }
253
216
  const DELETE_CONFLICT_IDS_SHOWN = 3;
254
217
  const DELETE_CONFLICT_ID_MAX = 64;
255
- function sessionDeleteConflictUnrecognizedContent() {
256
- return ('The engine refused to delete this session with a conflict it did not explain · ' +
257
- 'Check whether the session is still listed and whether anything of it is still running, then try the delete again');
218
+ function sessionDeleteConflictUnrecognizedContent(lang) {
219
+ return renderMessage(msg('notice.wireRefusal.sessionDelete.unrecognized'), lang);
258
220
  }
259
- export function sessionDeleteConflictContent(detail) {
221
+ export function sessionDeleteConflictContent(detail, lang) {
260
222
  try {
261
223
  if (detail === null || typeof detail !== 'object')
262
- return sessionDeleteConflictUnrecognizedContent();
224
+ return sessionDeleteConflictUnrecognizedContent(lang);
263
225
  switch (detail.kind) {
264
226
  case 'children_alive': {
265
227
  const raw = detail.remaining;
266
228
  const ids = Array.isArray(raw) ? raw.filter((id) => typeof id === 'string' && id.length > 0) : [];
267
229
  const shown = ids.slice(0, DELETE_CONFLICT_IDS_SHOWN).map((id) => capForDisplay(id, DELETE_CONFLICT_ID_MAX));
268
- const more = ids.length > shown.length ? ` and ${ids.length - shown.length} more` : '';
269
- const which = shown.length > 0 ? ` (${shown.join(', ')}${more})` : '';
270
- return (`This session was not deleted: background agents it started are still running where this engine cannot stop them${which} · ` +
271
- 'Nothing was deleted — delete it again once they finish, or stop them where they run first');
230
+ const which = shown.length === 0
231
+ ? ''
232
+ : ids.length > shown.length
233
+ ? renderMessage(msg('notice.wireRefusal.sessionDelete.whichMore', { ids: shown.join(', '), count: ids.length - shown.length }), lang)
234
+ : renderMessage(msg('notice.wireRefusal.sessionDelete.which', { ids: shown.join(', ') }), lang);
235
+ return renderMessage(msg('notice.wireRefusal.sessionDelete.childrenAlive', { which }), lang);
272
236
  }
273
237
  case 'active_run': {
274
238
  const active = detail.activeTaskId;
275
- const run = typeof active === 'string' && active.length > 0 ? ` (run ${capForDisplay(active, DELETE_CONFLICT_ID_MAX)})` : '';
276
- return (`This session was not deleted: it still has a run in progress${run} · ` +
277
- 'Nothing was deleted — cancel that run or let it finish, then delete the session again');
239
+ const run = typeof active === 'string' && active.length > 0 ? renderMessage(msg('notice.wireRefusal.sessionDelete.runId', { id: capForDisplay(active, DELETE_CONFLICT_ID_MAX) }), lang) : '';
240
+ return renderMessage(msg('notice.wireRefusal.sessionDelete.activeRun', { run }), lang);
278
241
  }
279
242
  default:
280
- return sessionDeleteConflictUnrecognizedContent();
243
+ return sessionDeleteConflictUnrecognizedContent(lang);
281
244
  }
282
245
  }
283
246
  catch {
284
- return sessionDeleteConflictUnrecognizedContent();
247
+ return sessionDeleteConflictUnrecognizedContent(lang);
285
248
  }
286
249
  }
287
250
  const FIELD_INVALID = 'request.field_invalid';
@@ -293,6 +256,24 @@ const BUCKET_OF_FIELD = Object.freeze({
293
256
  const nonNegInt = (v) => (typeof v === 'number' && Number.isSafeInteger(v) && v >= 0 ? v : undefined);
294
257
  const posInt = (v) => (typeof v === 'number' && Number.isSafeInteger(v) && v >= 1 ? v : undefined);
295
258
  export function settingsPermissionBucketRefusalFromError(err) {
259
+ const r = fieldLimitRefusalFromError(err);
260
+ if (r === null)
261
+ return null;
262
+ const bucket = Object.hasOwn(BUCKET_OF_FIELD, r.field) ? BUCKET_OF_FIELD[r.field] : undefined;
263
+ if (bucket === undefined || (r.reason !== 'over_cap' && r.reason !== 'bad_entry'))
264
+ return null;
265
+ if (r.reason === 'over_cap') {
266
+ return Object.freeze({
267
+ bucket,
268
+ reason: r.reason,
269
+ ...(r.count !== undefined ? { count: r.count } : {}),
270
+ ...(r.cap !== undefined ? { cap: r.cap } : {}),
271
+ ...(r.folded === true ? { folded: true } : {}),
272
+ });
273
+ }
274
+ return Object.freeze({ bucket, reason: r.reason, ...(r.index !== undefined ? { index: r.index } : {}), ...(r.folded === true ? { folded: true } : {}) });
275
+ }
276
+ export function fieldLimitRefusalFromError(err) {
296
277
  try {
297
278
  if (typeof err !== 'object' || err === null)
298
279
  return null;
@@ -306,71 +287,165 @@ export function settingsPermissionBucketRefusalFromError(err) {
306
287
  return null;
307
288
  }
308
289
  const field = readErrorString(err, 'field');
309
- const bucket = field !== undefined && Object.hasOwn(BUCKET_OF_FIELD, field) ? BUCKET_OF_FIELD[field] : undefined;
310
- if (bucket === undefined)
290
+ if (field === undefined || field.length === 0)
311
291
  return null;
312
292
  const reason = readErrorString(err, 'reason');
313
- if (reason !== 'over_cap' && reason !== 'bad_entry')
293
+ if (reason !== 'over_cap' && reason !== 'too_long' && reason !== 'bad_entry')
314
294
  return null;
315
295
  const folded = outer === RESUME_POLICY_FOLD_CODE;
316
- if (reason === 'over_cap') {
317
- const count = nonNegInt(readErrorNumber(err, 'count'));
318
- const cap = posInt(readErrorNumber(err, 'cap'));
319
- return Object.freeze({
296
+ if (reason === 'bad_entry') {
297
+ const index = nonNegInt(readErrorNumber(err, 'index'));
298
+ return Object.freeze({ field, reason, ...(index !== undefined ? { index } : {}), ...(folded ? { folded: true } : {}) });
299
+ }
300
+ const count = nonNegInt(readErrorNumber(err, 'count'));
301
+ const cap = posInt(readErrorNumber(err, 'cap'));
302
+ return Object.freeze({
303
+ field,
304
+ reason,
305
+ ...(count !== undefined ? { count } : {}),
306
+ ...(cap !== undefined ? { cap } : {}),
307
+ ...(folded ? { folded: true } : {}),
308
+ });
309
+ }
310
+ catch {
311
+ return null;
312
+ }
313
+ }
314
+ const FIELD_LIMIT_REFUSAL_UNKNOWN = 'The engine refused this request: a list in it has too many entries, or a text in it is too long · Nothing was trimmed or dropped — shorten it, then send the request again';
315
+ const FIELD_LIMIT_FIELD_MAX = 120;
316
+ export function fieldLimitRefusalContent(detail, lang) {
317
+ try {
318
+ if (typeof detail !== 'object' || detail === null)
319
+ return FIELD_LIMIT_REFUSAL_UNKNOWN;
320
+ const field = detail.field;
321
+ const reason = detail.reason;
322
+ if (typeof field !== 'string' || field.length === 0)
323
+ return FIELD_LIMIT_REFUSAL_UNKNOWN;
324
+ const folded = detail.folded === true;
325
+ const bucket = Object.hasOwn(BUCKET_OF_FIELD, field) ? BUCKET_OF_FIELD[field] : undefined;
326
+ if (bucket !== undefined && (reason === 'over_cap' || reason === 'bad_entry')) {
327
+ return settingsPermissionBucketRefusalContent({
320
328
  bucket,
321
329
  reason,
322
- ...(count !== undefined ? { count } : {}),
323
- ...(cap !== undefined ? { cap } : {}),
330
+ ...(reason === 'over_cap' && nonNegInt(detail.count) !== undefined ? { count: detail.count } : {}),
331
+ ...(reason === 'over_cap' && posInt(detail.cap) !== undefined ? { cap: detail.cap } : {}),
332
+ ...(reason === 'bad_entry' && nonNegInt(detail.index) !== undefined ? { index: detail.index } : {}),
324
333
  ...(folded ? { folded: true } : {}),
325
- });
334
+ }, lang);
326
335
  }
327
- const index = nonNegInt(readErrorNumber(err, 'index'));
328
- return Object.freeze({ bucket, reason, ...(index !== undefined ? { index } : {}), ...(folded ? { folded: true } : {}) });
336
+ if (reason !== 'over_cap' && reason !== 'too_long' && reason !== 'bad_entry')
337
+ return FIELD_LIMIT_REFUSAL_UNKNOWN;
338
+ const where = `the request field ${capForDisplay(field, FIELD_LIMIT_FIELD_MAX)}`;
339
+ const subject = folded ? 'The engine refused to continue this parked work: in the request stored for it,' : 'The engine refused this request:';
340
+ let what;
341
+ if (reason === 'bad_entry') {
342
+ const index = nonNegInt(detail.index);
343
+ what = index !== undefined ? `entry ${index + 1} of ${where} is not valid` : `${where} is not valid`;
344
+ }
345
+ else {
346
+ const count = nonNegInt(detail.count);
347
+ const cap = posInt(detail.cap);
348
+ const unit = reason === 'over_cap' ? 'entries' : 'characters';
349
+ what =
350
+ count !== undefined && cap !== undefined
351
+ ? count > cap
352
+ ? `${where} has ${count} ${unit}, ${count - cap} more than the ${cap} the engine accepts`
353
+ : `${where} has ${count} ${unit}, and the engine accepts at most ${cap}`
354
+ : reason === 'over_cap'
355
+ ? `${where} has more entries than the engine accepts`
356
+ : `${where} is longer than the engine accepts`;
357
+ }
358
+ const fix = reason === 'bad_entry' ? 'fix or remove that entry' : reason === 'over_cap' ? 'remove some entries or merge them' : 'shorten it';
359
+ const next = folded
360
+ ? `It cannot continue as stored, and the engine refuses rather than silently trimming — ${fix}, then submit the work again as a new request`
361
+ : `Nothing was trimmed or dropped, because the engine refuses rather than silently trimming — ${fix}, then send the request again`;
362
+ return `${subject} ${what} · ${next}`;
329
363
  }
330
364
  catch {
331
- return null;
365
+ return FIELD_LIMIT_REFUSAL_UNKNOWN;
332
366
  }
333
367
  }
334
- const BUCKET_REFUSAL_UNKNOWN = "The engine refused the permission rules in this request's settings as too many or malformed · Nothing was trimmed or dropped — fix the rule lists, then send the request again";
335
- export function settingsPermissionBucketRefusalContent(detail) {
368
+ const BUCKET_REFUSAL_UNKNOWN = 'notice.wireRefusal.bucket.unknown';
369
+ export function settingsPermissionBucketRefusalContent(detail, lang) {
336
370
  try {
337
371
  if (typeof detail !== 'object' || detail === null)
338
- return BUCKET_REFUSAL_UNKNOWN;
372
+ return renderMessage(msg(BUCKET_REFUSAL_UNKNOWN), lang);
339
373
  const bucket = detail.bucket;
340
374
  const reason = detail.reason;
341
375
  if (bucket !== 'allow' && bucket !== 'deny' && bucket !== 'ask')
342
- return BUCKET_REFUSAL_UNKNOWN;
376
+ return renderMessage(msg(BUCKET_REFUSAL_UNKNOWN), lang);
343
377
  if (reason !== 'over_cap' && reason !== 'bad_entry')
344
- return BUCKET_REFUSAL_UNKNOWN;
378
+ return renderMessage(msg(BUCKET_REFUSAL_UNKNOWN), lang);
345
379
  const folded = detail.folded === true;
346
- const subject = folded ? 'The engine refused to continue this parked work: in the request stored for it,' : 'The engine refused this request:';
347
- const list = `the ${bucket} rule list in the permission settings (permissions.${bucket})`;
380
+ const subject = renderMessage(folded ? msg('notice.wireRefusal.bucket.subject.stored') : msg('notice.wireRefusal.bucket.subject.fresh'), lang);
381
+ const list = msg('notice.wireRefusal.bucket.list', { bucket });
348
382
  let what;
349
383
  let fix;
350
384
  if (reason === 'over_cap') {
351
385
  const count = nonNegInt(detail.count);
352
386
  const cap = posInt(detail.cap);
353
- what =
354
- count !== undefined && cap !== undefined
355
- ? count > cap
356
- ? `${list} has ${count} entries, ${count - cap} more than the ${cap} the engine accepts`
357
- : `${list} has ${count} entries, and the engine accepts at most ${cap}`
358
- : `${list} has more entries than the engine accepts`;
359
- fix = 'merge rules into broader patterns or remove some';
387
+ what = renderMessage(count !== undefined && cap !== undefined
388
+ ? count > cap
389
+ ? msg('notice.wireRefusal.bucket.what.overCap.more', { list, count, excess: count - cap, cap })
390
+ : msg('notice.wireRefusal.bucket.what.overCap.atMost', { list, count, cap })
391
+ : msg('notice.wireRefusal.bucket.what.overCap.unknown', { list }), lang);
392
+ fix = renderMessage(msg('notice.wireRefusal.bucket.fix.merge'), lang);
360
393
  }
361
394
  else {
362
395
  const index = nonNegInt(detail.index);
363
- what = index !== undefined ? `entry ${index + 1} of ${list} is empty or not text` : `${list} is not a list of rules`;
364
- fix = index !== undefined ? 'fix or remove that entry, so every entry is a non-empty rule' : 'make it a list of non-empty rules';
396
+ what = renderMessage(index !== undefined ? msg('notice.wireRefusal.bucket.what.badEntry.at', { position: index + 1, list }) : msg('notice.wireRefusal.bucket.what.badEntry.notList', { list }), lang);
397
+ fix = renderMessage(msg(index !== undefined ? 'notice.wireRefusal.bucket.fix.entry' : 'notice.wireRefusal.bucket.fix.list'), lang);
365
398
  }
366
- const next = folded
367
- ? `It cannot continue as stored, and the engine refuses the list rather than silently losing rules — ${fix}, then submit the work again as a new request`
368
- : `Nothing was trimmed or dropped, because the engine refuses the list rather than silently losing rules — ${fix}, then send the request again`;
399
+ const next = renderMessage(msg(folded ? 'notice.wireRefusal.bucket.next.stored' : 'notice.wireRefusal.bucket.next.fresh', { fix }), lang);
369
400
  return `${subject} ${what} · ${next}`;
370
401
  }
371
402
  catch {
372
- return BUCKET_REFUSAL_UNKNOWN;
403
+ return renderMessage(msg(BUCKET_REFUSAL_UNKNOWN), lang);
404
+ }
405
+ }
406
+ const PAYLOAD_TOO_LARGE = 'request.payload_too_large';
407
+ const BLOB_TOO_LARGE_FOR_SQL = 'blob_too_large_for_sql';
408
+ export function admissionWallRefusalFromError(err) {
409
+ try {
410
+ if (typeof err !== 'object' || err === null)
411
+ return null;
412
+ const code = readThrownSlot(err, 'errorCode', 'data');
413
+ if (code !== PAYLOAD_TOO_LARGE && code !== BLOB_TOO_LARGE_FOR_SQL)
414
+ return null;
415
+ const wallSource = readErrorString(err, 'wallSource');
416
+ if (wallSource === 'reported' || wallSource === 'assumed')
417
+ return Object.freeze({ code, wallSource });
418
+ if (wallSource === 'operator' && code === BLOB_TOO_LARGE_FOR_SQL)
419
+ return Object.freeze({ code, wallSource });
420
+ return null;
421
+ }
422
+ catch {
423
+ return null;
424
+ }
425
+ }
426
+ export function admissionWallRefusalContent(detail) {
427
+ let code;
428
+ let source;
429
+ try {
430
+ code = detail.code;
431
+ source = detail.wallSource;
432
+ }
433
+ catch {
434
+ code = source = undefined;
435
+ }
436
+ const subject = code === BLOB_TOO_LARGE_FOR_SQL ? 'This snapshot file' : 'This request';
437
+ if (source === 'assumed') {
438
+ return (`${subject} was refused at the most conservative size limit, because this deployment has not read its database’s actual limit yet · ` +
439
+ 'Nothing was stored · Try again shortly; if it keeps happening, ask whoever operates the engine to let the service read the database’s size limit');
440
+ }
441
+ if (source === 'operator' && code === BLOB_TOO_LARGE_FOR_SQL) {
442
+ return ('This snapshot file is larger than the cap whoever operates the engine set for snapshots stored in the database · Nothing was stored · ' +
443
+ 'Ask them to configure object storage for large snapshots, or to raise that cap');
373
444
  }
445
+ return code === BLOB_TOO_LARGE_FOR_SQL
446
+ ? 'This snapshot file is larger than this deployment’s database can store in one piece · Nothing was stored · Ask whoever operates the engine to configure object storage for large snapshots, or to raise the database’s limit'
447
+ : 'This request is larger than this deployment’s database accepts for one submitted task · Nothing was stored · ' +
448
+ 'Shrink the inline images or attachments, or ask whoever operates the engine to raise the database’s limit (the engine’s own message names which one), then send it again';
374
449
  }
375
450
  export function toolDeclarationRefusalFromError(err) {
376
451
  try {
@@ -385,10 +460,9 @@ export function toolDeclarationRefusalFromError(err) {
385
460
  return null;
386
461
  }
387
462
  }
388
- const TOOL_DECLARATION_REFUSAL = "The engine refused to start this run because of a tool this request declares; the engine's own message says which tool and what is wrong with it · " +
389
- 'This is a problem with the request itself, not a temporary outage — sending the same request again is refused the same way; fix or remove that tool declaration, then send it';
390
- export function toolDeclarationRefusalContent(_detail) {
391
- return TOOL_DECLARATION_REFUSAL;
463
+ const TOOL_DECLARATION_REFUSAL = 'notice.wireRefusal.toolDeclaration';
464
+ export function toolDeclarationRefusalContent(_detail, lang) {
465
+ return renderMessage(msg(TOOL_DECLARATION_REFUSAL), lang);
392
466
  }
393
467
  const BODY_SHAPE = 'request.body_shape';
394
468
  const SETTINGS_KEY_PREFIX = 'settings.';
@@ -526,7 +600,7 @@ function readProp(o, key) {
526
600
  }
527
601
  export function hostPostureRefusalFromError(err, sentRequest) {
528
602
  try {
529
- if (readProp(err, 'errorCode') !== HOST_POSTURE_REFUSED)
603
+ if (readThrownSlot(err, 'errorCode', 'data') !== HOST_POSTURE_REFUSED)
530
604
  return null;
531
605
  const askedWholeEnvironment = readProp(sentRequest, 'inheritEnv') === 'all';
532
606
  const askedOpenWriteFace = readProp(sentRequest, 'permissionMode') === BYPASS_PERMISSIONS ||
@@ -541,33 +615,54 @@ export function hostPostureRefusalFromError(err, sentRequest) {
541
615
  return null;
542
616
  }
543
617
  }
544
- const HOST_POSTURE_NOT_LOCAL = 'This is not a problem with your local settings and not something this client can grant — whoever runs this engine decides it';
545
- const HOST_POSTURE_WHOLE_ENV = "The engine refused this request before anything ran: this deployment serves more than one user, so a request may not hand the shell this machine's whole environment · " +
546
- `${HOST_POSTURE_NOT_LOCAL}; send it again without the whole-environment setting (or with the default), and the shell gets the default environment, with credential-like variables removed`;
547
- const HOST_POSTURE_WRITE_FACE = 'The engine refused this request before anything ran: this deployment does not let a request lift the write boundary with bypassPermissions · ' +
548
- `${HOST_POSTURE_NOT_LOCAL}; send it again with another permission mode`;
549
- const HOST_POSTURE_BOTH = "The engine refused this request before anything ran: the request asked both for the shell to inherit this machine's whole environment and for bypassPermissions, and this deployment refused at least one of them; the refusal does not say which · " +
550
- `${HOST_POSTURE_NOT_LOCAL}; send it again without one or both (the whole-environment setting is honored only on a single-user deployment)`;
551
- const HOST_POSTURE_UNATTRIBUTED = "The engine refused this request before anything ran: this deployment does not accept a setting in it that only a single-user deployment may use; the engine's own message names it · " +
552
- `${HOST_POSTURE_NOT_LOCAL}; send it again without that setting`;
553
- export function hostPostureRefusalContent(detail) {
618
+ const HOST_POSTURE_NOT_LOCAL = 'notice.wireRefusal.hostPosture.notLocal';
619
+ const HOST_POSTURE_WHOLE_ENV = 'notice.wireRefusal.hostPosture.wholeEnv';
620
+ const HOST_POSTURE_WRITE_FACE = 'notice.wireRefusal.hostPosture.writeFace';
621
+ const HOST_POSTURE_BOTH = 'notice.wireRefusal.hostPosture.both';
622
+ const HOST_POSTURE_UNATTRIBUTED = 'notice.wireRefusal.hostPosture.unattributed';
623
+ export function hostPostureRefusalContent(detail, lang) {
624
+ const say = (key) => renderMessage(msg(key, { notLocal: msg(HOST_POSTURE_NOT_LOCAL) }), lang);
554
625
  try {
555
626
  const env = readProp(detail, 'askedWholeEnvironment') === true;
556
627
  const write = readProp(detail, 'askedOpenWriteFace') === true;
557
628
  if (env && write)
558
- return HOST_POSTURE_BOTH;
629
+ return say(HOST_POSTURE_BOTH);
559
630
  if (env)
560
- return HOST_POSTURE_WHOLE_ENV;
631
+ return say(HOST_POSTURE_WHOLE_ENV);
561
632
  if (write)
562
- return HOST_POSTURE_WRITE_FACE;
563
- return HOST_POSTURE_UNATTRIBUTED;
633
+ return say(HOST_POSTURE_WRITE_FACE);
634
+ return say(HOST_POSTURE_UNATTRIBUTED);
564
635
  }
565
636
  catch {
566
- return HOST_POSTURE_UNATTRIBUTED;
637
+ return say(HOST_POSTURE_UNATTRIBUTED);
567
638
  }
568
639
  }
569
640
  const HOOK_MATCHER_REFUSAL_FIELD = 'settings.hooks';
570
641
  export function hookMatcherRefusalFromError(err) {
642
+ return settingsHooksRefusalFromError(err)?.matcher;
643
+ }
644
+ function hooksRefusalPathOf(detail) {
645
+ try {
646
+ const raw = readOwnDataValue(detail, 'path');
647
+ if (!Array.isArray(raw))
648
+ return undefined;
649
+ const out = [];
650
+ for (let i = 0; i < raw.length; i++) {
651
+ if (!Object.hasOwn(raw, i))
652
+ return undefined;
653
+ const v = raw[i];
654
+ if (typeof v === 'string' || (typeof v === 'number' && Number.isSafeInteger(v) && v >= 0))
655
+ out.push(v);
656
+ else
657
+ return undefined;
658
+ }
659
+ return Object.freeze(out);
660
+ }
661
+ catch {
662
+ return undefined;
663
+ }
664
+ }
665
+ export function settingsHooksRefusalFromError(err) {
571
666
  try {
572
667
  if (typeof err !== 'object' || err === null)
573
668
  return undefined;
@@ -578,31 +673,43 @@ export function hookMatcherRefusalFromError(err) {
578
673
  const detail = readErrorRecord(err, 'detail');
579
674
  if (detail === undefined)
580
675
  return undefined;
581
- const event = readOwnNonEmptyString(detail, 'event');
582
- if (event === undefined)
583
- return undefined;
584
676
  const reasonRaw = readOwnDataValue(detail, 'reason');
677
+ const path = hooksRefusalPathOf(detail);
678
+ const withPath = (o) => Object.freeze({ ...o, ...(path !== undefined ? { path } : {}) });
679
+ const family = (reason, rest = {}) => Object.freeze({ reason, ...(path !== undefined ? { path } : {}), ...rest });
680
+ const event = readOwnNonEmptyString(detail, 'event');
585
681
  if (reasonRaw === undefined || reasonRaw === 'dead_alias') {
586
682
  const alias = readOwnNonEmptyString(detail, 'alias');
587
683
  const canonical = readOwnNonEmptyString(detail, 'canonical');
588
- if (alias === undefined || canonical === undefined)
684
+ const matcher = event !== undefined && alias !== undefined && canonical !== undefined ? withPath({ reason: 'alias_without_canonical', event, alias, canonical }) : undefined;
685
+ if (reasonRaw === undefined && matcher === undefined)
589
686
  return undefined;
590
- return Object.freeze({ reason: 'alias_without_canonical', event, alias, canonical });
687
+ return family('dead_alias', matcher !== undefined ? { matcher } : {});
591
688
  }
592
- if (reasonRaw !== 'invalid_regex' && reasonRaw !== 'over_budget')
593
- return undefined;
594
- const groupIndex = readOwnDataValue(detail, 'groupIndex');
595
- if (typeof groupIndex !== 'number' || !Number.isInteger(groupIndex) || groupIndex < 0)
689
+ if (typeof reasonRaw !== 'string' || reasonRaw.length === 0)
596
690
  return undefined;
597
- if (reasonRaw === 'invalid_regex')
598
- return Object.freeze({ reason: 'invalid_regex', event, groupIndex });
599
- const budget = readOwnDataValue(detail, 'budgetMs');
600
- return Object.freeze({
601
- reason: 'over_budget',
602
- event,
603
- groupIndex,
604
- ...(typeof budget === 'number' && Number.isFinite(budget) && budget > 0 ? { budgetMs: budget } : {}),
605
- });
691
+ if (reasonRaw === 'invalid_regex' || reasonRaw === 'over_budget' || reasonRaw === 'budget_exceeded') {
692
+ const groupIndex = readOwnDataValue(detail, 'groupIndex');
693
+ const okIndex = typeof groupIndex === 'number' && Number.isInteger(groupIndex) && groupIndex >= 0;
694
+ let matcher;
695
+ if (event !== undefined && okIndex) {
696
+ if (reasonRaw === 'invalid_regex')
697
+ matcher = withPath({ reason: 'invalid_regex', event, groupIndex });
698
+ else {
699
+ const key = reasonRaw === 'over_budget' ? 'budgetMs' : 'totalMs';
700
+ const ms = readOwnDataValue(detail, key);
701
+ const msBit = typeof ms === 'number' && Number.isFinite(ms) && ms > 0 ? { [key]: ms } : {};
702
+ matcher = reasonRaw === 'over_budget' ? withPath({ reason: 'over_budget', event, groupIndex, ...msBit }) : withPath({ reason: 'budget_exceeded', event, groupIndex, ...msBit });
703
+ }
704
+ }
705
+ return family(reasonRaw, matcher !== undefined ? { matcher } : {});
706
+ }
707
+ if (reasonRaw === 'over_cap' || reasonRaw === 'too_long') {
708
+ const count = nonNegInt(readOwnDataValue(detail, 'count'));
709
+ const cap = posInt(readOwnDataValue(detail, 'cap'));
710
+ return family(reasonRaw, { ...(count !== undefined ? { count } : {}), ...(cap !== undefined ? { cap } : {}) });
711
+ }
712
+ return family(reasonRaw);
606
713
  }
607
714
  catch {
608
715
  return undefined;
@@ -611,7 +718,59 @@ export function hookMatcherRefusalFromError(err) {
611
718
  export function autonomyLaneRefusalFromError(err) {
612
719
  return effectiveWireErrorCode(err) === REQUEST_AUTONOMY_LANE_REFUSED ? { code: REQUEST_AUTONOMY_LANE_REFUSED } : null;
613
720
  }
614
- export function autonomyLaneRefusalContent() {
615
- return ('The engine did not start this leader run: this deployment runs in plan-only autonomy, and a leader run has no way to have its plan reviewed, ' +
616
- 'so nothing was started · Submit the work as a regular run instead, or ask whoever operates the engine to change its autonomy setting');
721
+ export function autonomyLaneRefusalContent(lang) {
722
+ return renderMessage(msg('notice.wireRefusal.autonomyLane'), lang);
723
+ }
724
+ export function userAttachmentRefusalFromError(err) {
725
+ try {
726
+ if (typeof err !== 'object' || err === null)
727
+ return null;
728
+ let facts;
729
+ const kind = readOwnDataValue(err, 'kind');
730
+ const plane = readOwnDataValue(err, 'plane');
731
+ if (kind === 'failed' && (plane === 'cause' || plane === 'flat')) {
732
+ if (readOwnDataValue(err, 'code') !== USER_ATTACHMENT_INVALID_ERROR_CODE)
733
+ return null;
734
+ const cause = readOwnDataValue(err, 'detail');
735
+ const inner = typeof cause === 'object' && cause !== null && readOwnDataValue(cause, 'kind') === 'coded' ? readOwnDataValue(cause, 'detail') : undefined;
736
+ facts = typeof inner === 'object' && inner !== null && !Array.isArray(inner) ? inner : undefined;
737
+ }
738
+ else {
739
+ if (effectiveWireErrorCode(err) !== USER_ATTACHMENT_INVALID_ERROR_CODE)
740
+ return null;
741
+ facts = readErrorRecord(err, 'detail');
742
+ }
743
+ let index;
744
+ let path;
745
+ try {
746
+ index = facts === undefined ? undefined : readOwnDataValue(facts, 'index');
747
+ }
748
+ catch {
749
+ index = undefined;
750
+ }
751
+ try {
752
+ path = facts === undefined ? undefined : readOwnDataValue(facts, 'path');
753
+ }
754
+ catch {
755
+ path = undefined;
756
+ }
757
+ return {
758
+ code: USER_ATTACHMENT_INVALID_ERROR_CODE,
759
+ retryable: false,
760
+ ...(typeof index === 'number' && Number.isSafeInteger(index) && index >= 0 ? { index } : {}),
761
+ ...(typeof path === 'string' && path.length > 0 ? { path } : {}),
762
+ };
763
+ }
764
+ catch {
765
+ return null;
766
+ }
767
+ }
768
+ export function userAttachmentRefusalContent(detail) {
769
+ return prepareRefusalNoteOf(USER_ATTACHMENT_INVALID_ERROR_CODE, detail);
770
+ }
771
+ export function userInvokedSkillRefusalFromError(err) {
772
+ return effectiveWireErrorCode(err) === USER_INVOKED_SKILL_UNKNOWN_ERROR_CODE ? { code: USER_INVOKED_SKILL_UNKNOWN_ERROR_CODE, retryable: false } : null;
773
+ }
774
+ export function userInvokedSkillRefusalContent() {
775
+ return prepareRefusalNoteOf(USER_INVOKED_SKILL_UNKNOWN_ERROR_CODE);
617
776
  }