@sema-agent/client-core 0.99.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 (128) hide show
  1. package/CHANGELOG.md +177 -0
  2. package/README.md +32 -19
  3. package/dist/adapt/arms.js +60 -36
  4. package/dist/adapt/panelTasks.d.ts +2 -1
  5. package/dist/adapt/panelTasks.js +32 -9
  6. package/dist/adapt/textStream.d.ts +1 -1
  7. package/dist/adapt/textStream.js +51 -28
  8. package/dist/adapter/activeRunSelfHeal.d.ts +7 -0
  9. package/dist/adapter/activeRunSelfHeal.js +58 -11
  10. package/dist/adapter/downstream/eventToSdkMessage.d.ts +25 -6
  11. package/dist/adapter/downstream/eventToSdkMessage.js +125 -9
  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 +32 -5
  16. package/dist/adapter/types.d.ts +2 -0
  17. package/dist/agentsWireCaps.d.ts +7 -0
  18. package/dist/agentsWireCaps.js +100 -15
  19. package/dist/cloudConfigWireCaps.d.ts +10 -1
  20. package/dist/cloudConfigWireCaps.js +156 -62
  21. package/dist/compactionStatus.d.ts +34 -0
  22. package/dist/compactionStatus.js +196 -0
  23. package/dist/decideFailureNote.js +3 -3
  24. package/dist/displayUntrusted.js +150 -5
  25. package/dist/engineAgentPanelStore.d.ts +7 -4
  26. package/dist/engineErrorCodes.d.ts +9 -1
  27. package/dist/engineErrorCodes.js +9 -5
  28. package/dist/engineRowRef.js +1 -0
  29. package/dist/engineToolDirectory.d.ts +3 -0
  30. package/dist/engineToolDirectory.js +4 -2
  31. package/dist/eventLeg.d.ts +1 -7
  32. package/dist/eventLeg.js +7 -8
  33. package/dist/fileHistoryCaptureCapability.d.ts +0 -3
  34. package/dist/fileHistoryCaptureCapability.js +0 -4
  35. package/dist/generated/engineFactTables.d.ts +1 -0
  36. package/dist/generated/engineFactTables.js +27 -0
  37. package/dist/generated/engineNoticeTables.js +3 -0
  38. package/dist/generated/settingsSchemaFns.d.ts +12 -0
  39. package/dist/generated/settingsSchemaFns.js +13 -0
  40. package/dist/generated/settingsSchemaMcpRequestEntry.d.ts +1 -0
  41. package/dist/generated/settingsSchemaMcpRequestEntry.js +162 -0
  42. package/dist/generated/settingsSchemaTables.d.ts +1 -0
  43. package/dist/generated/settingsSchemaTables.js +5 -0
  44. package/dist/generated/settingsSchemaTypes.d.ts +28 -0
  45. package/dist/hitl/allowRuleShadow.js +2 -2
  46. package/dist/hitl/approvalCardReasons.js +2 -2
  47. package/dist/hitl/approvalHolds.d.ts +14 -0
  48. package/dist/hitl/approvalHolds.js +41 -0
  49. package/dist/hitl/askClassPair.d.ts +2 -2
  50. package/dist/hitl/askClassPair.js +2 -2
  51. package/dist/hitl/attributionLadder.d.ts +23 -0
  52. package/dist/hitl/attributionLadder.js +67 -0
  53. package/dist/hitl/decisionLedger.d.ts +55 -0
  54. package/dist/hitl/decisionLedger.js +156 -0
  55. package/dist/hitl/decisionRefusal.d.ts +1 -0
  56. package/dist/hitl/decisionRefusal.js +1 -1
  57. package/dist/hitl/decisionSend.d.ts +113 -0
  58. package/dist/hitl/decisionSend.js +579 -0
  59. package/dist/hitl/hitlBridge.js +18 -6
  60. package/dist/hitl/planReviewWire.js +45 -76
  61. package/dist/hitl/sessionPolicyDeliverable.js +3 -6
  62. package/dist/hitl/toolApprovalWire.js +43 -109
  63. package/dist/hostTurnSettings.d.ts +46 -7
  64. package/dist/hostTurnSettings.js +408 -7
  65. package/dist/humanTurn.d.ts +2 -1
  66. package/dist/humanTurn.js +3 -3
  67. package/dist/i18n/messages.en.d.ts +131 -0
  68. package/dist/i18n/messages.en.js +143 -12
  69. package/dist/i18n/messages.zh.js +148 -12
  70. package/dist/index.d.ts +18 -2
  71. package/dist/index.js +10 -1
  72. package/dist/inheritEnvCapability.d.ts +1 -0
  73. package/dist/inheritEnvCapability.js +9 -2
  74. package/dist/inheritEnvWire.js +2 -2
  75. package/dist/injectionLaneNotice.d.ts +5 -0
  76. package/dist/injectionLaneNotice.js +46 -0
  77. package/dist/mcpPanel.js +2 -0
  78. package/dist/mcpReconnect.js +2 -2
  79. package/dist/mcpToolToggles.d.ts +6 -0
  80. package/dist/mcpToolToggles.js +46 -0
  81. package/dist/mcpWireCaps.d.ts +10 -4
  82. package/dist/mcpWireCaps.js +106 -71
  83. package/dist/mcpWireTransport.d.ts +4 -0
  84. package/dist/mcpWireTransport.js +18 -0
  85. package/dist/modelCapabilityProbe.d.ts +2 -1
  86. package/dist/modelCapabilityProbe.js +10 -9
  87. package/dist/modelIdentityResolvability.d.ts +2 -0
  88. package/dist/modelIdentityResolvability.js +23 -5
  89. package/dist/ownKey.d.ts +26 -0
  90. package/dist/ownKey.js +75 -0
  91. package/dist/panelReduce.d.ts +5 -0
  92. package/dist/panelReduce.js +45 -13
  93. package/dist/panelStateHolder.d.ts +1 -0
  94. package/dist/panelStateHolder.js +10 -1
  95. package/dist/permissionRuleIssue.d.ts +2 -1
  96. package/dist/permissionRuleIssue.js +22 -21
  97. package/dist/pluginHooksWire.js +12 -10
  98. package/dist/prepareRefusal.d.ts +8 -0
  99. package/dist/prepareRefusal.js +72 -0
  100. package/dist/request/taskRequest.d.ts +10 -10
  101. package/dist/request/taskRequest.js +106 -65
  102. package/dist/resumeRefusalCopy.d.ts +3 -1
  103. package/dist/resumeRefusalCopy.js +22 -4
  104. package/dist/retryStatus.d.ts +18 -0
  105. package/dist/retryStatus.js +76 -19
  106. package/dist/ruleRefusalSentence.d.ts +4 -0
  107. package/dist/ruleRefusalSentence.js +58 -0
  108. package/dist/sandboxWire.d.ts +2 -1
  109. package/dist/sandboxWire.js +55 -21
  110. package/dist/scenarioRefusal.d.ts +2 -1
  111. package/dist/scenarioRefusal.js +5 -5
  112. package/dist/seam.d.ts +24 -9
  113. package/dist/seam.js +44 -4
  114. package/dist/seatContract.d.ts +16 -8
  115. package/dist/seatContract.js +21 -6
  116. package/dist/settingsCredentialKeyPaths.d.ts +8 -0
  117. package/dist/settingsCredentialKeyPaths.js +219 -0
  118. package/dist/skillsWireCaps.d.ts +0 -3
  119. package/dist/skillsWireCaps.js +1 -2
  120. package/dist/subagentContentStore.d.ts +1 -0
  121. package/dist/subagentContentStore.js +135 -27
  122. package/dist/toolsFlagNames.d.ts +8 -0
  123. package/dist/toolsFlagNames.js +110 -0
  124. package/dist/turnFailurePresentation.js +15 -7
  125. package/dist/wireRefusalCopy.d.ts +51 -17
  126. package/dist/wireRefusalCopy.js +298 -135
  127. package/docs/INTEGRATION-CLIENTS.md +423 -26
  128. package/package.json +4 -4
@@ -1,10 +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, USER_ATTACHMENT_INVALID_ERROR_CODE, USER_INVOKED_SKILL_UNKNOWN_ERROR_CODE } 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 { scenarioRefusalFromError } from './scenarioRefusal.js';
7
+ import { prepareRefusalNoteOf } from './prepareRefusal.js';
8
+ import { msg, renderMessage } from './i18n/translate.js';
8
9
  export const CONFLICT_APPROVAL_SETTLED = 'conflict.approval_settled';
9
10
  export const CONFLICT_RUN_NOT_RUNNING = 'conflict.run_not_running';
10
11
  function ownNonEmptyStringSlot(o, key) {
@@ -26,17 +27,14 @@ export function cancelConflictFromError(err) {
26
27
  return { kind: 'run_not_running', code };
27
28
  return { kind: 'unrecognized', ...(code !== undefined ? { code } : {}) };
28
29
  }
29
- export function cancelConflictContent(detail) {
30
+ export function cancelConflictContent(detail, lang) {
30
31
  switch (detail.kind) {
31
32
  case 'approval_settled':
32
- return ('The cancel did not apply: the approval this task was waiting on has already been decided or has expired elsewhere · ' +
33
- 'Check what that decision did to the task before doing anything else');
33
+ return renderMessage(msg('notice.wireRefusal.cancel.approvalSettled'), lang);
34
34
  case 'run_not_running':
35
- return ('The cancel could not be set: the task kept switching between running and waiting while the engine tried · ' +
36
- 'Nothing was changed — send the cancel again');
35
+ return renderMessage(msg('notice.wireRefusal.cancel.runNotRunning'), lang);
37
36
  case 'unrecognized':
38
- return ('The engine refused this cancel with a conflict it did not explain · ' +
39
- '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);
40
38
  }
41
39
  }
42
40
  function nonNegativeFinite(v) {
@@ -80,11 +78,11 @@ function humanWait(sec) {
80
78
  const mm = m % 60;
81
79
  return mm === 0 ? `${h} h` : `${h} h ${mm} min`;
82
80
  }
83
- export function usageWindowExhaustedContent(detail) {
84
- 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);
85
83
  return detail.retryAfterSec !== undefined
86
- ? `${head} · Send it again in about ${humanWait(detail.retryAfterSec)}`
87
- : `${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)}`;
88
86
  }
89
87
  const positiveFinite = (v) => typeof v === 'number' && Number.isFinite(v) && v > 0;
90
88
  export function fleetLeaseUnavailableFromError(err) {
@@ -112,7 +110,7 @@ export function fleetLeaseUnavailableFromError(err) {
112
110
  ...(sec !== undefined ? { retryAfterSec: sec } : {}),
113
111
  };
114
112
  }
115
- export function fleetLeaseUnavailableContent(detail) {
113
+ export function fleetLeaseUnavailableContent(detail, lang) {
116
114
  let reason;
117
115
  let sec;
118
116
  try {
@@ -127,27 +125,17 @@ export function fleetLeaseUnavailableContent(detail) {
127
125
  catch {
128
126
  sec = undefined;
129
127
  }
130
- 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);
131
129
  const cause = reason === 'auth-rejected'
132
- ? " · 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)}`
133
131
  : reason === 'unreachable'
134
- ? ' · The engine could not reach the quota service'
132
+ ? ` · ${renderMessage(msg('notice.wireRefusal.fleetLease.unreachable'), lang)}`
135
133
  : '';
136
134
  const wait = positiveFinite(sec)
137
- ? ` · Send it again in about ${humanWait(Math.ceil(sec))}`
138
- : ' · 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)}`;
139
137
  return `${head}${cause}${wait}`;
140
138
  }
141
- export function scenarioAssignmentUnknownFromError(err) {
142
- const r = scenarioRefusalFromError(err);
143
- if (r === null)
144
- return null;
145
- return {
146
- code: SCENARIO_ASSIGNMENT_UNKNOWN_ERROR_CODE,
147
- ...(r.scenario !== undefined ? { scenario: r.scenario } : {}),
148
- ...(r.source !== undefined ? { source: r.source } : {}),
149
- };
150
- }
151
139
  const SETTLED_BY_NOT_IN_PROOF = 'settled_by_not_in_proof';
152
140
  const DECIDED_BY_NOT_IN_PROOF = 'decided_by_not_in_proof';
153
141
  const RETIRED_DECISION_KEY = 'settledBy';
@@ -184,26 +172,19 @@ export function denyAttributionRefusalFromError(err, sentAttributionKey) {
184
172
  return null;
185
173
  }
186
174
  }
187
- export function denyAttributionRefusalContent(detail) {
175
+ export function denyAttributionRefusalContent(detail, lang) {
188
176
  switch (detail.kind) {
189
177
  case 'not_in_proof':
190
- return ('The engine refused this refusal before judging it: this deployment signs the decisions it accepts, and the note saying ' +
191
- 'who settled this one is not part of what gets signed · Nothing was decided and the approval is still waiting — ' +
192
- 'send the same decision again without that note');
178
+ return renderMessage(msg('notice.wireRefusal.denyAttribution.notInProof'), lang);
193
179
  case 'decision_conflict':
194
- return ('The engine refused this decision before judging it: the body says a policy settled it and also asks to allow the call, ' +
195
- 'and only a person can allow one · Nothing was decided and the approval is still waiting — ' +
196
- 'send it again with the decision and the note in agreement');
180
+ return renderMessage(msg('notice.wireRefusal.denyAttribution.decisionConflict'), lang);
197
181
  case 'retired_key':
198
- 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 · ' +
199
- '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);
200
183
  case 'attribution_rejected': {
201
184
  const named = typeof detail.field === 'string' && APPROVAL_NON_BINDING_FIELDS.has(detail.field)
202
- ? ` It named ${detail.field} as the part it would not take.`
185
+ ? renderMessage(msg('notice.wireRefusal.denyAttribution.named', { field: detail.field }), lang)
203
186
  : '';
204
- return ('The engine would not accept the settlement details this decision carried, so it refused the decision before judging it.' +
205
- `${named} · Nothing was decided and the approval is still waiting at the same coordinates — ` +
206
- '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);
207
188
  }
208
189
  }
209
190
  }
@@ -234,36 +215,36 @@ export function sessionDeleteConflictFromError(err) {
234
215
  }
235
216
  const DELETE_CONFLICT_IDS_SHOWN = 3;
236
217
  const DELETE_CONFLICT_ID_MAX = 64;
237
- function sessionDeleteConflictUnrecognizedContent() {
238
- return ('The engine refused to delete this session with a conflict it did not explain · ' +
239
- '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);
240
220
  }
241
- export function sessionDeleteConflictContent(detail) {
221
+ export function sessionDeleteConflictContent(detail, lang) {
242
222
  try {
243
223
  if (detail === null || typeof detail !== 'object')
244
- return sessionDeleteConflictUnrecognizedContent();
224
+ return sessionDeleteConflictUnrecognizedContent(lang);
245
225
  switch (detail.kind) {
246
226
  case 'children_alive': {
247
227
  const raw = detail.remaining;
248
228
  const ids = Array.isArray(raw) ? raw.filter((id) => typeof id === 'string' && id.length > 0) : [];
249
229
  const shown = ids.slice(0, DELETE_CONFLICT_IDS_SHOWN).map((id) => capForDisplay(id, DELETE_CONFLICT_ID_MAX));
250
- const more = ids.length > shown.length ? ` and ${ids.length - shown.length} more` : '';
251
- const which = shown.length > 0 ? ` (${shown.join(', ')}${more})` : '';
252
- return (`This session was not deleted: background agents it started are still running where this engine cannot stop them${which} · ` +
253
- '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);
254
236
  }
255
237
  case 'active_run': {
256
238
  const active = detail.activeTaskId;
257
- const run = typeof active === 'string' && active.length > 0 ? ` (run ${capForDisplay(active, DELETE_CONFLICT_ID_MAX)})` : '';
258
- return (`This session was not deleted: it still has a run in progress${run} · ` +
259
- '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);
260
241
  }
261
242
  default:
262
- return sessionDeleteConflictUnrecognizedContent();
243
+ return sessionDeleteConflictUnrecognizedContent(lang);
263
244
  }
264
245
  }
265
246
  catch {
266
- return sessionDeleteConflictUnrecognizedContent();
247
+ return sessionDeleteConflictUnrecognizedContent(lang);
267
248
  }
268
249
  }
269
250
  const FIELD_INVALID = 'request.field_invalid';
@@ -275,6 +256,24 @@ const BUCKET_OF_FIELD = Object.freeze({
275
256
  const nonNegInt = (v) => (typeof v === 'number' && Number.isSafeInteger(v) && v >= 0 ? v : undefined);
276
257
  const posInt = (v) => (typeof v === 'number' && Number.isSafeInteger(v) && v >= 1 ? v : undefined);
277
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) {
278
277
  try {
279
278
  if (typeof err !== 'object' || err === null)
280
279
  return null;
@@ -288,72 +287,166 @@ export function settingsPermissionBucketRefusalFromError(err) {
288
287
  return null;
289
288
  }
290
289
  const field = readErrorString(err, 'field');
291
- const bucket = field !== undefined && Object.hasOwn(BUCKET_OF_FIELD, field) ? BUCKET_OF_FIELD[field] : undefined;
292
- if (bucket === undefined)
290
+ if (field === undefined || field.length === 0)
293
291
  return null;
294
292
  const reason = readErrorString(err, 'reason');
295
- if (reason !== 'over_cap' && reason !== 'bad_entry')
293
+ if (reason !== 'over_cap' && reason !== 'too_long' && reason !== 'bad_entry')
296
294
  return null;
297
295
  const folded = outer === RESUME_POLICY_FOLD_CODE;
298
- if (reason === 'over_cap') {
299
- const count = nonNegInt(readErrorNumber(err, 'count'));
300
- const cap = posInt(readErrorNumber(err, 'cap'));
301
- 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({
302
328
  bucket,
303
329
  reason,
304
- ...(count !== undefined ? { count } : {}),
305
- ...(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 } : {}),
306
333
  ...(folded ? { folded: true } : {}),
307
- });
334
+ }, lang);
308
335
  }
309
- const index = nonNegInt(readErrorNumber(err, 'index'));
310
- 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}`;
311
363
  }
312
364
  catch {
313
- return null;
365
+ return FIELD_LIMIT_REFUSAL_UNKNOWN;
314
366
  }
315
367
  }
316
- 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";
317
- export function settingsPermissionBucketRefusalContent(detail) {
368
+ const BUCKET_REFUSAL_UNKNOWN = 'notice.wireRefusal.bucket.unknown';
369
+ export function settingsPermissionBucketRefusalContent(detail, lang) {
318
370
  try {
319
371
  if (typeof detail !== 'object' || detail === null)
320
- return BUCKET_REFUSAL_UNKNOWN;
372
+ return renderMessage(msg(BUCKET_REFUSAL_UNKNOWN), lang);
321
373
  const bucket = detail.bucket;
322
374
  const reason = detail.reason;
323
375
  if (bucket !== 'allow' && bucket !== 'deny' && bucket !== 'ask')
324
- return BUCKET_REFUSAL_UNKNOWN;
376
+ return renderMessage(msg(BUCKET_REFUSAL_UNKNOWN), lang);
325
377
  if (reason !== 'over_cap' && reason !== 'bad_entry')
326
- return BUCKET_REFUSAL_UNKNOWN;
378
+ return renderMessage(msg(BUCKET_REFUSAL_UNKNOWN), lang);
327
379
  const folded = detail.folded === true;
328
- const subject = folded ? 'The engine refused to continue this parked work: in the request stored for it,' : 'The engine refused this request:';
329
- 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 });
330
382
  let what;
331
383
  let fix;
332
384
  if (reason === 'over_cap') {
333
385
  const count = nonNegInt(detail.count);
334
386
  const cap = posInt(detail.cap);
335
- what =
336
- count !== undefined && cap !== undefined
337
- ? count > cap
338
- ? `${list} has ${count} entries, ${count - cap} more than the ${cap} the engine accepts`
339
- : `${list} has ${count} entries, and the engine accepts at most ${cap}`
340
- : `${list} has more entries than the engine accepts`;
341
- 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);
342
393
  }
343
394
  else {
344
395
  const index = nonNegInt(detail.index);
345
- what = index !== undefined ? `entry ${index + 1} of ${list} is empty or not text` : `${list} is not a list of rules`;
346
- 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);
347
398
  }
348
- const next = folded
349
- ? `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`
350
- : `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);
351
400
  return `${subject} ${what} · ${next}`;
352
401
  }
353
402
  catch {
354
- return BUCKET_REFUSAL_UNKNOWN;
403
+ return renderMessage(msg(BUCKET_REFUSAL_UNKNOWN), lang);
355
404
  }
356
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');
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';
449
+ }
357
450
  export function toolDeclarationRefusalFromError(err) {
358
451
  try {
359
452
  if (typeof err !== 'object' || err === null)
@@ -367,10 +460,9 @@ export function toolDeclarationRefusalFromError(err) {
367
460
  return null;
368
461
  }
369
462
  }
370
- 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 · " +
371
- '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';
372
- export function toolDeclarationRefusalContent(_detail) {
373
- 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);
374
466
  }
375
467
  const BODY_SHAPE = 'request.body_shape';
376
468
  const SETTINGS_KEY_PREFIX = 'settings.';
@@ -523,33 +615,54 @@ export function hostPostureRefusalFromError(err, sentRequest) {
523
615
  return null;
524
616
  }
525
617
  }
526
- 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';
527
- 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 · " +
528
- `${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`;
529
- 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 · ' +
530
- `${HOST_POSTURE_NOT_LOCAL}; send it again with another permission mode`;
531
- 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 · " +
532
- `${HOST_POSTURE_NOT_LOCAL}; send it again without one or both (the whole-environment setting is honored only on a single-user deployment)`;
533
- 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 · " +
534
- `${HOST_POSTURE_NOT_LOCAL}; send it again without that setting`;
535
- 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);
536
625
  try {
537
626
  const env = readProp(detail, 'askedWholeEnvironment') === true;
538
627
  const write = readProp(detail, 'askedOpenWriteFace') === true;
539
628
  if (env && write)
540
- return HOST_POSTURE_BOTH;
629
+ return say(HOST_POSTURE_BOTH);
541
630
  if (env)
542
- return HOST_POSTURE_WHOLE_ENV;
631
+ return say(HOST_POSTURE_WHOLE_ENV);
543
632
  if (write)
544
- return HOST_POSTURE_WRITE_FACE;
545
- return HOST_POSTURE_UNATTRIBUTED;
633
+ return say(HOST_POSTURE_WRITE_FACE);
634
+ return say(HOST_POSTURE_UNATTRIBUTED);
546
635
  }
547
636
  catch {
548
- return HOST_POSTURE_UNATTRIBUTED;
637
+ return say(HOST_POSTURE_UNATTRIBUTED);
549
638
  }
550
639
  }
551
640
  const HOOK_MATCHER_REFUSAL_FIELD = 'settings.hooks';
552
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) {
553
666
  try {
554
667
  if (typeof err !== 'object' || err === null)
555
668
  return undefined;
@@ -560,31 +673,43 @@ export function hookMatcherRefusalFromError(err) {
560
673
  const detail = readErrorRecord(err, 'detail');
561
674
  if (detail === undefined)
562
675
  return undefined;
563
- const event = readOwnNonEmptyString(detail, 'event');
564
- if (event === undefined)
565
- return undefined;
566
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');
567
681
  if (reasonRaw === undefined || reasonRaw === 'dead_alias') {
568
682
  const alias = readOwnNonEmptyString(detail, 'alias');
569
683
  const canonical = readOwnNonEmptyString(detail, 'canonical');
570
- 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)
571
686
  return undefined;
572
- return Object.freeze({ reason: 'alias_without_canonical', event, alias, canonical });
687
+ return family('dead_alias', matcher !== undefined ? { matcher } : {});
573
688
  }
574
- if (reasonRaw !== 'invalid_regex' && reasonRaw !== 'over_budget')
575
- return undefined;
576
- const groupIndex = readOwnDataValue(detail, 'groupIndex');
577
- if (typeof groupIndex !== 'number' || !Number.isInteger(groupIndex) || groupIndex < 0)
689
+ if (typeof reasonRaw !== 'string' || reasonRaw.length === 0)
578
690
  return undefined;
579
- if (reasonRaw === 'invalid_regex')
580
- return Object.freeze({ reason: 'invalid_regex', event, groupIndex });
581
- const budget = readOwnDataValue(detail, 'budgetMs');
582
- return Object.freeze({
583
- reason: 'over_budget',
584
- event,
585
- groupIndex,
586
- ...(typeof budget === 'number' && Number.isFinite(budget) && budget > 0 ? { budgetMs: budget } : {}),
587
- });
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);
588
713
  }
589
714
  catch {
590
715
  return undefined;
@@ -593,21 +718,59 @@ export function hookMatcherRefusalFromError(err) {
593
718
  export function autonomyLaneRefusalFromError(err) {
594
719
  return effectiveWireErrorCode(err) === REQUEST_AUTONOMY_LANE_REFUSED ? { code: REQUEST_AUTONOMY_LANE_REFUSED } : null;
595
720
  }
596
- export function autonomyLaneRefusalContent() {
597
- 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, ' +
598
- '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);
599
723
  }
600
724
  export function userAttachmentRefusalFromError(err) {
601
- return effectiveWireErrorCode(err) === USER_ATTACHMENT_INVALID_ERROR_CODE ? { code: USER_ATTACHMENT_INVALID_ERROR_CODE, retryable: false } : null;
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
+ }
602
767
  }
603
- export function userAttachmentRefusalContent() {
604
- return ('This message was not sent: the engine refused the files attached to it — together with the message they are more than it can take in one request on this model, ' +
605
- 'or one of them is in a form it does not accept · Nothing was started and your draft is kept · Remove some attachments or attach smaller parts, then send it again');
768
+ export function userAttachmentRefusalContent(detail) {
769
+ return prepareRefusalNoteOf(USER_ATTACHMENT_INVALID_ERROR_CODE, detail);
606
770
  }
607
771
  export function userInvokedSkillRefusalFromError(err) {
608
772
  return effectiveWireErrorCode(err) === USER_INVOKED_SKILL_UNKNOWN_ERROR_CODE ? { code: USER_INVOKED_SKILL_UNKNOWN_ERROR_CODE, retryable: false } : null;
609
773
  }
610
774
  export function userInvokedSkillRefusalContent() {
611
- return ('The engine did not start this run: a skill named for it is not one this run has loaded, or skills are turned off for this run · ' +
612
- 'Nothing was started and your draft is kept · Check the skill name, or load that skill, then send it again');
775
+ return prepareRefusalNoteOf(USER_INVOKED_SKILL_UNKNOWN_ERROR_CODE);
613
776
  }