@sema-agent/client-core 0.90.0 → 0.92.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 (172) hide show
  1. package/CHANGELOG.md +365 -0
  2. package/README.md +48 -32
  3. package/dist/adapt/arms.js +13 -12
  4. package/dist/adapt/panelTasks.d.ts +0 -2
  5. package/dist/adapt/panelTasks.js +6 -26
  6. package/dist/adapt.js +2 -2
  7. package/dist/adapter/activeRunSelfHeal.d.ts +0 -2
  8. package/dist/adapter/activeRunSelfHeal.js +5 -27
  9. package/dist/adapter/downstream/eventToSdkMessage.js +4 -2
  10. package/dist/adapter/downstream/terminalToSdkResult.js +16 -7
  11. package/dist/adapter/downstream/wiringManifestView.d.ts +6 -0
  12. package/dist/adapter/downstream/wiringManifestView.js +16 -0
  13. package/dist/adapter/runStream.js +39 -20
  14. package/dist/askSurvivesStandingAnswer.d.ts +13 -0
  15. package/dist/askSurvivesStandingAnswer.js +53 -0
  16. package/dist/attachmentSeatCapability.d.ts +11 -0
  17. package/dist/attachmentSeatCapability.js +27 -0
  18. package/dist/attachmentsWireCaps.d.ts +9 -0
  19. package/dist/attachmentsWireCaps.js +74 -21
  20. package/dist/autoModeUnavailable.js +3 -2
  21. package/dist/cloudConfigWireCaps.js +5 -4
  22. package/dist/compensations.js +13 -17
  23. package/dist/controlRouter.d.ts +32 -25
  24. package/dist/controlRouter.js +166 -63
  25. package/dist/coreValuePorts.d.ts +4 -2
  26. package/dist/coreValuePorts.js +5 -0
  27. package/dist/decideFailureNote.js +7 -3
  28. package/dist/decideReceipt.d.ts +9 -0
  29. package/dist/decideReceipt.js +62 -1
  30. package/dist/disableSkillsWire.d.ts +1 -0
  31. package/dist/disableSkillsWire.js +8 -1
  32. package/dist/displayUntrusted.js +155 -5
  33. package/dist/effectiveFacts.d.ts +14 -4
  34. package/dist/effectiveFacts.js +45 -5
  35. package/dist/engineAgentAbsence.js +2 -1
  36. package/dist/engineCapReader.js +16 -10
  37. package/dist/engineCapsCache.d.ts +5 -1
  38. package/dist/engineCapsCache.js +69 -8
  39. package/dist/engineClosedSets.d.ts +2 -0
  40. package/dist/engineClosedSets.js +3 -0
  41. package/dist/engineErrorCodes.d.ts +17 -0
  42. package/dist/engineErrorCodes.js +47 -0
  43. package/dist/engineNoticeCodes.d.ts +14 -0
  44. package/dist/engineNoticeCodes.js +71 -0
  45. package/dist/executionLaneCapability.js +2 -0
  46. package/dist/gateOutcome.js +2 -17
  47. package/dist/gateVocabulary.d.ts +2 -4
  48. package/dist/gateVocabulary.js +3 -11
  49. package/dist/generated/engineFactTables.d.ts +27 -0
  50. package/dist/generated/engineFactTables.js +128 -0
  51. package/dist/generated/engineNoticeTables.js +3 -0
  52. package/dist/generated/settingsSchemaTables.d.ts +8 -0
  53. package/dist/generated/settingsSchemaTables.js +40 -0
  54. package/dist/hitl/allowRuleShadow.d.ts +21 -0
  55. package/dist/hitl/allowRuleShadow.js +167 -0
  56. package/dist/hitl/askClassPair.d.ts +14 -0
  57. package/dist/hitl/askClassPair.js +42 -0
  58. package/dist/hitl/askGateWire.d.ts +1 -1
  59. package/dist/hitl/askGateWire.js +2 -1
  60. package/dist/hitl/askSurvivesPosture.d.ts +5 -0
  61. package/dist/hitl/askSurvivesPosture.js +17 -0
  62. package/dist/hitl/automaticAnswerVerdict.d.ts +21 -0
  63. package/dist/hitl/automaticAnswerVerdict.js +143 -0
  64. package/dist/hitl/crashConverged.d.ts +8 -0
  65. package/dist/hitl/crashConverged.js +58 -1
  66. package/dist/hitl/crashConvergedNotice.d.ts +4 -0
  67. package/dist/hitl/crashConvergedNotice.js +57 -0
  68. package/dist/hitl/frameRouter.d.ts +2 -0
  69. package/dist/hitl/frameRouter.js +66 -14
  70. package/dist/hitl/gateLedger.d.ts +6 -0
  71. package/dist/hitl/gateLedger.js +34 -5
  72. package/dist/hitl/hitlBridge.d.ts +7 -4
  73. package/dist/hitl/hitlHostSurface.d.ts +2 -0
  74. package/dist/hitl/hitlHostSurface.js +7 -0
  75. package/dist/hitl/livePendingAsk.js +24 -5
  76. package/dist/hitl/parkResolver.d.ts +7 -2
  77. package/dist/hitl/parkResolver.js +21 -7
  78. package/dist/hitl/persistedRulesWire.d.ts +4 -1
  79. package/dist/hitl/persistedRulesWire.js +9 -2
  80. package/dist/hitl/planReviewWire.d.ts +1 -1
  81. package/dist/hitl/planReviewWire.js +19 -5
  82. package/dist/hitl/replayedApproval.d.ts +21 -0
  83. package/dist/hitl/replayedApproval.js +89 -0
  84. package/dist/hitl/sessionPolicyDeliverable.js +20 -2
  85. package/dist/hitl/sessionPolicyWire.d.ts +13 -0
  86. package/dist/hitl/sessionPolicyWire.js +75 -2
  87. package/dist/hitl/suspendedReopen.js +2 -2
  88. package/dist/hitl/toolApprovalWire.d.ts +9 -1
  89. package/dist/hitl/toolApprovalWire.js +40 -40
  90. package/dist/hookMatcherVerdict.d.ts +29 -0
  91. package/dist/hookMatcherVerdict.js +266 -0
  92. package/dist/humanTurn.d.ts +91 -0
  93. package/dist/humanTurn.js +252 -0
  94. package/dist/humanTurnRead.d.ts +105 -0
  95. package/dist/humanTurnRead.js +331 -0
  96. package/dist/index.d.ts +38 -11
  97. package/dist/index.js +27 -8
  98. package/dist/inheritEnvWire.js +4 -5
  99. package/dist/liveModelCatalog.d.ts +2 -0
  100. package/dist/liveModelCatalog.js +51 -3
  101. package/dist/mcpLiveness.js +2 -1
  102. package/dist/memoryVerbsWire.d.ts +1 -1
  103. package/dist/memoryVerbsWire.js +3 -0
  104. package/dist/model/catalog.js +2 -1
  105. package/dist/model/providerPresets.d.ts +3 -1
  106. package/dist/model/tierVocabulary.d.ts +2 -1
  107. package/dist/model/tierVocabulary.js +3 -8
  108. package/dist/peerFrames.js +2 -2
  109. package/dist/permissionRuleIssue.d.ts +1 -1
  110. package/dist/permissionRuleIssue.js +31 -9
  111. package/dist/permissionsAllowGrantCapability.d.ts +2 -1
  112. package/dist/permissionsAllowGrantCapability.js +11 -2
  113. package/dist/permissionsDeclaration.d.ts +29 -0
  114. package/dist/permissionsDeclaration.js +155 -66
  115. package/dist/pluginHooksWire.js +2 -11
  116. package/dist/promptDelivery.d.ts +11 -3
  117. package/dist/promptDelivery.js +164 -29
  118. package/dist/promptProfileWireCaps.d.ts +2 -1
  119. package/dist/protocolSegment.d.ts +9 -0
  120. package/dist/protocolSegment.js +28 -0
  121. package/dist/providerRejection.d.ts +1 -0
  122. package/dist/providerRejection.js +20 -0
  123. package/dist/readDenyTiers.d.ts +10 -0
  124. package/dist/readDenyTiers.js +29 -0
  125. package/dist/request/taskRequest.js +3 -17
  126. package/dist/resumeRefusalCopy.d.ts +11 -0
  127. package/dist/resumeRefusalCopy.js +61 -4
  128. package/dist/rewindArchiveCapability.js +4 -4
  129. package/dist/rewindWireCaps.d.ts +2 -1
  130. package/dist/rewindWireCaps.js +19 -2
  131. package/dist/ruleCompileVerdict.d.ts +2 -0
  132. package/dist/ruleCompileVerdict.js +13 -0
  133. package/dist/ruleRemovalConsequence.d.ts +2 -1
  134. package/dist/runCancelContext.d.ts +12 -0
  135. package/dist/runCancelContext.js +83 -1
  136. package/dist/seam.d.ts +2 -0
  137. package/dist/seam.js +1 -1
  138. package/dist/seatContract.d.ts +2 -1
  139. package/dist/sessionMemoryStatus.d.ts +2 -4
  140. package/dist/sessionSyncFileHistoryCapability.d.ts +18 -0
  141. package/dist/sessionSyncFileHistoryCapability.js +50 -0
  142. package/dist/skillToolListsCapability.d.ts +18 -0
  143. package/dist/skillToolListsCapability.js +50 -0
  144. package/dist/sqlEngineCapability.js +1 -8
  145. package/dist/steerPriorityCapability.d.ts +18 -0
  146. package/dist/steerPriorityCapability.js +80 -0
  147. package/dist/steerReceipt.d.ts +9 -0
  148. package/dist/steerReceipt.js +25 -0
  149. package/dist/subagent/engineSubagentSteer.js +2 -9
  150. package/dist/supportFloor.js +2 -2
  151. package/dist/taskRequestWords.d.ts +7 -1
  152. package/dist/taskRequestWords.js +18 -8
  153. package/dist/toolHistoryBadTurn.d.ts +1 -0
  154. package/dist/toolHistoryBadTurn.js +89 -0
  155. package/dist/toolHistoryMismatch.d.ts +2 -1
  156. package/dist/toolHistoryMismatch.js +19 -6
  157. package/dist/toolResult.d.ts +8 -0
  158. package/dist/toolResult.js +47 -3
  159. package/dist/types/engineState.d.ts +2 -12
  160. package/dist/userAttachmentEnvelope.d.ts +61 -0
  161. package/dist/userAttachmentEnvelope.js +204 -0
  162. package/dist/userInvokedSkillsCapability.d.ts +18 -0
  163. package/dist/userInvokedSkillsCapability.js +50 -0
  164. package/dist/wireFailureShape.d.ts +3 -0
  165. package/dist/wireFailureShape.js +8 -0
  166. package/dist/wireRefusalCopy.d.ts +6 -0
  167. package/dist/wireRefusalCopy.js +26 -3
  168. package/dist/workflowsJournalCapability.d.ts +18 -0
  169. package/dist/workflowsJournalCapability.js +50 -0
  170. package/dist/writeProtectionCapability.d.ts +2 -4
  171. package/docs/INTEGRATION-CLIENTS.md +1489 -16
  172. package/package.json +3 -3
@@ -1,16 +1,21 @@
1
1
  import { cancelConflictContent, cancelConflictFromError } from './wireRefusalCopy.js';
2
- import { uuid } from './adapter/types.js';
2
+ import { steerPriorityMode } from './steerPriorityCapability.js';
3
3
  export class ControlSafetyError extends Error {
4
4
  code;
5
5
  cause;
6
- constructor(message, code, cause) {
6
+ constructor(message, code, cause, detail) {
7
7
  super(message);
8
8
  this.code = code;
9
9
  this.cause = cause;
10
10
  this.name = 'ControlSafetyError';
11
+ const advice = detail?.advice;
12
+ const status = detail?.status;
13
+ if (typeof advice === 'string' && advice.length > 0)
14
+ this.advice = advice;
15
+ if (typeof status === 'number')
16
+ this.status = status;
11
17
  }
12
18
  }
13
- const BAND_RANK = { now: 0, next: 1, later: 2 };
14
19
  export class ControlRouter {
15
20
  client;
16
21
  taskId = null;
@@ -18,8 +23,6 @@ export class ControlRouter {
18
23
  jobId;
19
24
  scenario;
20
25
  systemPrompt;
21
- queue = [];
22
- seq = 0;
23
26
  constructor(client, opts = {}) {
24
27
  this.client = client;
25
28
  this.sessionId = opts.sessionId;
@@ -55,70 +58,51 @@ export class ControlRouter {
55
58
  }
56
59
  async steer(text, mode, opts) {
57
60
  if (this.taskId === null) {
58
- throw new ControlSafetyError('no run in flight to steer — submit a turn first', 'not_running');
61
+ throw controlSafetyRefusal('not_running', 'no run in flight to steer', 'submit a turn first');
59
62
  }
60
- const body = mode !== undefined ? { text, mode } : { text };
63
+ let priority;
64
+ let reading;
65
+ try {
66
+ priority = opts?.priority;
67
+ reading = opts?.steerPriority;
68
+ }
69
+ catch (e) {
70
+ throw steerLocalRefusal('steer_input_invalid', 'unknown', e);
71
+ }
72
+ const body = steerBodyOf({ text, ...(mode !== undefined ? { mode } : {}), ...(priority !== undefined ? { priority: priority } : {}) }, (reading ?? UNOBSERVED_STEER_PRIORITY));
61
73
  try {
62
74
  return await this.client.runs.steer(this.taskId, body, opts?.signal !== undefined ? { signal: opts.signal } : undefined);
63
75
  }
64
76
  catch (e) {
65
- const verdict = steeringVerdict(e);
66
- if (verdict !== undefined) {
67
- const safety = steeringSafetyOf(e, verdict);
68
- const wireCode = errCodes(e).code ?? errCodes(e).name ?? 'steering.<unknown>';
69
- throw new ControlSafetyError(`${wireCode} — ${steeringAdviceOf(e, safety) ?? 'steering refused'}`, safety, e);
77
+ if (typeof e === 'object' && e !== null) {
78
+ const refusal = steerRefusalAdviceOf(e);
79
+ if (refusal !== undefined)
80
+ throw controlSafetyRefusal(refusal.safety, steerRefusalWireLabel(e), refusal.advice, e);
70
81
  }
71
82
  throw e;
72
83
  }
73
84
  }
74
85
  async cancel(opts) {
75
86
  if (this.taskId === null) {
76
- throw new ControlSafetyError('no run in flight to cancel', 'not_found');
87
+ throw controlSafetyRefusal('not_found', 'no run in flight to cancel');
77
88
  }
78
89
  try {
79
90
  return await this.client.runs.cancel(this.taskId, opts?.signal !== undefined ? { signal: opts.signal } : undefined);
80
91
  }
81
92
  catch (e) {
82
93
  if (cancelConflictFromError(e)?.kind === 'run_not_running') {
83
- throw new ControlSafetyError(`runs.cancel 409 conflict.run_not_running — ${cancelConflictContent({ kind: 'run_not_running' })}`, 'cancel_run_not_running', e);
94
+ throw controlSafetyRefusal('cancel_run_not_running', 'runs.cancel 409 conflict.run_not_running', cancelConflictContent({ kind: 'run_not_running' }), e);
84
95
  }
85
96
  if (isCancelSuspendedConflict(e)) {
86
- throw new ControlSafetyError('runs.cancel 409 — the pending gate was decided or expired concurrently (lost CAS race); ' +
87
- 'check what that decision did to the run before retrying the cancel', 'cancel_lost_race', e);
97
+ throw controlSafetyRefusal('cancel_lost_race', 'runs.cancel 409', 'the pending gate was decided or expired concurrently (lost CAS race); ' +
98
+ 'check what that decision did to the run before retrying the cancel', e);
88
99
  }
89
100
  if (isNotFound(e)) {
90
- throw new ControlSafetyError('runs.cancel 404 — non-owner / unknown run (no existence leak)', 'not_found', e);
101
+ throw controlSafetyRefusal('not_found', 'runs.cancel 404', `${CANCEL_NOT_FOUND_COPY.happened} — ${CANCEL_NOT_FOUND_COPY.nextStep}`, e);
91
102
  }
92
103
  throw e;
93
104
  }
94
105
  }
95
- enqueue(text, priority = 'next') {
96
- const cmd = { id: this.nextId(), text, priority };
97
- this.queue.push(cmd);
98
- return cmd;
99
- }
100
- dequeue(id) {
101
- const i = this.queue.findIndex((c) => c.id === id);
102
- if (i < 0)
103
- return false;
104
- this.queue.splice(i, 1);
105
- return true;
106
- }
107
- pending() {
108
- return [...this.queue].sort((a, b) => BAND_RANK[a.priority] - BAND_RANK[b.priority]);
109
- }
110
- async drainNext(opts) {
111
- const ordered = this.pending();
112
- const head = ordered[0];
113
- if (!head)
114
- return null;
115
- this.dequeue(head.id);
116
- return this.submit(head.text, opts);
117
- }
118
- nextId() {
119
- this.seq += 1;
120
- return `q-${this.seq}-${uuid()}`;
121
- }
122
106
  }
123
107
  export function errCodes(e) {
124
108
  if (!e || typeof e !== 'object')
@@ -147,20 +131,72 @@ const STEERING_NAME_TO_SAFETY = new Map([
147
131
  ['SteeringAmbiguousTargetError', 'ambiguous_target'],
148
132
  ['SteeringStillRunningError', 'still_running'],
149
133
  ['SteeringLedgerUnavailableError', 'ledger_unavailable'],
134
+ ['SteeringQueueFullError', 'queue_full'],
135
+ ['SteeringDuplicateInputIdError', 'duplicate_input_id'],
150
136
  ['SteeringError', 'steering_other'],
151
137
  ]);
152
- const STEERING_ADVICE = new Map([
153
- ['not_running', 'the run is suspended/terminal/on another replica — resolve its gate via decide, do not steer'],
154
- ['invalid_content', 'the steer text carried a control-plane escape; surface it, do not strip-and-retry'],
155
- ['queue_full', 'the parked steering queue on this checkpoint is full (core fails loud rather than evicting an accepted instruction) — wait for it to drain, do not resend'],
156
- ['duplicate_input_id', 'this Idempotency-Key is already parked with DIFFERENT steering content — reissue with a fresh key, resending verbatim will never succeed'],
157
- ['ambiguous_target', 'more than one live target matches — address it uniquely (sub-agent: parentToolCallId; workflow: a more specific label); retrying verbatim yields the same result'],
158
- ['still_running', 'the target is STILL RUNNING — steer it instead of resuming, or wait for it to settle (this is the exact opposite of not_running: never collapse the two)'],
159
- ['blocked_by_hook', "this deployment's userPromptSubmit gate refused the input (block, timeout and crash all report this one code, fail-closed) — the input was NOT accepted: no human_input frame, the inputId is not on the ledger, so editing the text and sending again is a normal retry, not a duplicate"],
160
- ['ledger_unavailable', 'the server could not record this steer in its user-input ledger and refused it before anything reached the engine — the input was NOT delivered; resend the same text later (the same Idempotency-Key is fine)'],
161
- ['steering_other', 'an unrecognized steering.* refusal (open set) — the steer did NOT land; log the errorCode verbatim, do not guess its meaning'],
162
- ]);
163
- const STEERING_OTHER_UNKNOWN_ADVICE = 'an unrecognized steering.* refusal (open set) — treat delivery as unknown (do not resend as if it had certainly been dropped); log the errorCode verbatim, do not guess its meaning';
138
+ const STEERING_COPY = {
139
+ not_running: {
140
+ happened: 'that run is not accepting messages right now — it has just finished, is running on another server, or is not the active run of its session',
141
+ nextStep: 'check its current state and send the message to the run that is active',
142
+ },
143
+ invalid_content: {
144
+ happened: 'the message was refused because its text contains control markers the engine does not accept, so nothing was delivered',
145
+ nextStep: 'rewrite the message and send it again',
146
+ },
147
+ queue_full: {
148
+ happened: 'that run is paused and already holds as many waiting messages as it can, so this one was not accepted',
149
+ nextStep: 'send it again once the waiting messages have been delivered (when the run resumes or the session is woken)',
150
+ },
151
+ duplicate_input_id: {
152
+ happened: 'a different instruction was already accepted under this idempotency key, and that earlier instruction stands',
153
+ nextStep: 'if you changed the text, send the new text under a new key; otherwise do not resend it — a new key would deliver the same instruction twice',
154
+ },
155
+ ambiguous_target: {
156
+ happened: 'more than one running agent matches that target, so the message was not delivered',
157
+ nextStep: 'address a sub-agent by its tool-call id; a workflow agent cannot be singled out while another running agent shares its label, so send it again once only one does',
158
+ },
159
+ still_running: {
160
+ happened: 'that agent is still running, so it cannot be resumed',
161
+ nextStep: 'send it a message instead, or wait for it to finish',
162
+ },
163
+ blocked_by_hook: {
164
+ happened: "the message was not accepted: a prompt check on this deployment blocked it, so nothing was delivered",
165
+ nextStep: 'edit the message and send it again — that is not a duplicate submission',
166
+ },
167
+ ledger_unavailable: {
168
+ happened: 'the server could not record the message and refused it before anything reached the engine, so nothing was delivered',
169
+ nextStep: 'send the same text again later',
170
+ },
171
+ steering_other: {
172
+ happened: 'the message was refused for a reason this version does not recognise, so it did not land',
173
+ nextStep: 'report its error code if this keeps happening; do not guess what it means',
174
+ },
175
+ };
176
+ const adviceOfCopy = (c) => `${c.happened} — ${c.nextStep}`;
177
+ const STEERING_ADVICE = Object.freeze(Object.fromEntries(Object.entries(STEERING_COPY).map(([k, c]) => [k, adviceOfCopy(c)])));
178
+ const STEERING_OTHER_UNKNOWN_COPY = {
179
+ happened: 'the message was refused for a reason this version does not recognise, and whether it was delivered is not known',
180
+ nextStep: 'do not resend it as if it had certainly been dropped — check the run first, and report its error code if this keeps happening',
181
+ };
182
+ const CANCEL_NOT_FOUND_COPY = {
183
+ happened: 'this server has no run with that id for you — it does not exist, or it belongs to someone else',
184
+ nextStep: 'nothing was cancelled; refresh the run list',
185
+ };
186
+ const PRIORITY_NOT_APPLIED_COPY = {
187
+ advisory: {
188
+ happened: "this server accepts a steer priority but does not apply it — a 'now' message would not interrupt the running turn and a 'later' message would not wait",
189
+ nextStep: 'nothing was sent; to interrupt the turn now, send the text as an interrupt, or send it without a priority to have it delivered at the next turn boundary',
190
+ },
191
+ unknown: {
192
+ happened: 'whether this server applies a steer priority is not known — there is no usable capability reading for it',
193
+ nextStep: 'nothing was sent; wait for the capability reading and try again, or send it without a priority to have it delivered at the next turn boundary',
194
+ },
195
+ };
196
+ const STEER_INPUT_INVALID_COPY = {
197
+ happened: "the steer request could not be built — its priority must be 'now', 'next' or 'later', and its fields must be readable",
198
+ nextStep: 'nothing was sent; fix the request and send it again',
199
+ };
164
200
  export function steeringStatusIs4xx(e) {
165
201
  let status;
166
202
  try {
@@ -171,10 +207,10 @@ export function steeringStatusIs4xx(e) {
171
207
  }
172
208
  return status !== undefined && status >= 400 && status < 500;
173
209
  }
174
- function steeringAdviceOf(e, safety) {
175
- if (safety === 'steering_other' && !(typeof e === 'object' && e !== null && steeringStatusIs4xx(e)))
176
- return STEERING_OTHER_UNKNOWN_ADVICE;
177
- return STEERING_ADVICE.get(safety);
210
+ function steeringCopyOf(e, safety) {
211
+ if (safety === 'steering_other' && !steeringStatusIs4xx(e))
212
+ return STEERING_OTHER_UNKNOWN_COPY;
213
+ return STEERING_COPY[safety];
178
214
  }
179
215
  const STEERING_REFUSED_BEFORE_ENGINE = new Map([['ledger_unavailable', 503]]);
180
216
  export function steeringRefusedBeforeEngine(e) {
@@ -185,8 +221,8 @@ export function steeringRefusedBeforeEngine(e) {
185
221
  const safety = steeringVerdict(e);
186
222
  if (safety === undefined || STEERING_REFUSED_BEFORE_ENGINE.get(safety) !== status)
187
223
  return undefined;
188
- const advice = STEERING_ADVICE.get(safety);
189
- return advice === undefined ? undefined : { safety, advice };
224
+ const copy = STEERING_COPY[safety];
225
+ return { safety, advice: STEERING_ADVICE[safety], happened: copy.happened, nextStep: copy.nextStep };
190
226
  }
191
227
  catch {
192
228
  return undefined;
@@ -195,7 +231,7 @@ export function steeringRefusedBeforeEngine(e) {
195
231
  function steeringSafetyOf(e, verdict) {
196
232
  if (!STEERING_REFUSED_BEFORE_ENGINE.has(verdict))
197
233
  return verdict;
198
- const refused = typeof e === 'object' && e !== null ? steeringRefusedBeforeEngine(e) : undefined;
234
+ const refused = steeringRefusedBeforeEngine(e);
199
235
  return refused !== undefined && refused.safety === verdict ? verdict : 'steering_other';
200
236
  }
201
237
  function steeringVerdict(e) {
@@ -207,6 +243,73 @@ function steeringVerdict(e) {
207
243
  return STEERING_NAME_TO_SAFETY.get(name);
208
244
  return undefined;
209
245
  }
246
+ export function steerRefusalAdviceOf(e) {
247
+ try {
248
+ const verdict = steeringVerdict(e);
249
+ if (verdict === undefined)
250
+ return undefined;
251
+ const safety = steeringSafetyOf(e, verdict);
252
+ const copy = steeringCopyOf(e, safety);
253
+ return { safety, advice: adviceOfCopy(copy), happened: copy.happened, nextStep: copy.nextStep };
254
+ }
255
+ catch {
256
+ return undefined;
257
+ }
258
+ }
259
+ function steerRefusalWireLabel(e) {
260
+ try {
261
+ const { code, name } = errCodes(e);
262
+ return code ?? name ?? 'steering.<unknown>';
263
+ }
264
+ catch {
265
+ return 'steering.<unknown>';
266
+ }
267
+ }
268
+ function statusOfThrown(e) {
269
+ try {
270
+ return errCodes(e).status;
271
+ }
272
+ catch {
273
+ return undefined;
274
+ }
275
+ }
276
+ function controlSafetyRefusal(code, head, advice, cause) {
277
+ const status = statusOfThrown(cause);
278
+ const detail = { ...(advice !== undefined ? { advice } : {}), ...(status !== undefined ? { status } : {}) };
279
+ return new ControlSafetyError(advice === undefined ? head : `${head} — ${advice}`, code, cause, detail);
280
+ }
281
+ export const UNOBSERVED_STEER_PRIORITY = Object.freeze({ kind: 'unobserved' });
282
+ function steerLocalRefusal(code, mode, cause) {
283
+ const copy = code === 'steer_input_invalid' ? STEER_INPUT_INVALID_COPY : PRIORITY_NOT_APPLIED_COPY[mode === 'advisory' ? 'advisory' : 'unknown'];
284
+ return controlSafetyRefusal(code, 'steer not sent', adviceOfCopy(copy), cause);
285
+ }
286
+ function ownInputField(input, key) {
287
+ return Object.hasOwn(input, key) ? input[key] : undefined;
288
+ }
289
+ export function steerBodyOf(input, reading) {
290
+ let text;
291
+ let mode;
292
+ let priority;
293
+ try {
294
+ if (input === null || typeof input !== 'object' || Array.isArray(input))
295
+ throw new TypeError('steer input is not an object');
296
+ text = ownInputField(input, 'text');
297
+ mode = ownInputField(input, 'mode');
298
+ priority = ownInputField(input, 'priority');
299
+ }
300
+ catch (e) {
301
+ throw steerLocalRefusal('steer_input_invalid', 'unknown', e);
302
+ }
303
+ const base = mode !== undefined ? { text, mode } : { text };
304
+ if (priority === undefined || priority === 'next')
305
+ return Object.freeze(base);
306
+ const tierMode = steerPriorityMode(reading);
307
+ if (priority !== 'now' && priority !== 'later')
308
+ throw steerLocalRefusal('steer_input_invalid', tierMode);
309
+ if (tierMode !== 'engine')
310
+ throw steerLocalRefusal('priority_not_applied', tierMode);
311
+ return Object.freeze({ ...base, priority });
312
+ }
210
313
  function isCancelSuspendedConflict(e) {
211
314
  const { name, status } = errCodes(e);
212
315
  return name === 'ConflictError' || status === 409;
@@ -32,7 +32,7 @@ export interface CoreProtocolNamespaceView {
32
32
  }
33
33
  export interface PermissionRuleView {
34
34
  rule: string;
35
- behavior: 'deny' | 'ask' | 'allow';
35
+ behavior: 'deny' | 'ask';
36
36
  source?: string;
37
37
  }
38
38
  export interface PermissionRuleIssueView {
@@ -59,8 +59,9 @@ export interface CoreValuePorts {
59
59
  ruleToolGrammarOf: (toolName: string) => 'command' | 'path' | undefined;
60
60
  validatePermissionRules: (rules: PermissionRuleView[], opts?: ValidatePermissionRulesOptionsView) => PermissionRuleIssueView[];
61
61
  DISCUSSION_WORKFLOW_NAME: string;
62
+ mintNamespacePrefix(ns: CoreProtocolNamespaceView, peer: string): string;
62
63
  }
63
- export declare const CORE_VALUE_PORT_NAMES: readonly ["resolveAutonomousLoopPrompt", "loosenReasons", "combinePolicies", "createAllowDenyPolicy", "MCP_NAMESPACE", "RETIRED_TOOL_NAMES", "protocolOf", "ruleToolGrammarOf", "validatePermissionRules", "DISCUSSION_WORKFLOW_NAME"];
64
+ export declare const CORE_VALUE_PORT_NAMES: readonly ["resolveAutonomousLoopPrompt", "loosenReasons", "combinePolicies", "createAllowDenyPolicy", "MCP_NAMESPACE", "RETIRED_TOOL_NAMES", "protocolOf", "ruleToolGrammarOf", "validatePermissionRules", "DISCUSSION_WORKFLOW_NAME", "mintNamespacePrefix"];
64
65
  export type CoreValuePortName = (typeof CORE_VALUE_PORT_NAMES)[number];
65
66
  export declare function installCoreValuePorts(ports: Partial<CoreValuePorts> | null): () => void;
66
67
  export declare function hasCoreValuePorts(): boolean;
@@ -76,3 +77,4 @@ export declare function protocolOf(name: string): CoreProtocolNamespaceView | un
76
77
  export declare function ruleToolGrammarOf(toolName: string): 'command' | 'path' | undefined;
77
78
  export declare function validatePermissionRules(rules: PermissionRuleView[], opts?: ValidatePermissionRulesOptionsView): PermissionRuleIssueView[] | undefined;
78
79
  export declare function discussionWorkflowName(): string | undefined;
80
+ export declare function mintNamespacePrefix(ns: CoreProtocolNamespaceView, peer: string): string | undefined;
@@ -9,6 +9,7 @@ export const CORE_VALUE_PORT_NAMES = Object.freeze([
9
9
  'ruleToolGrammarOf',
10
10
  'validatePermissionRules',
11
11
  'DISCUSSION_WORKFLOW_NAME',
12
+ 'mintNamespacePrefix',
12
13
  ]);
13
14
  let installed = null;
14
15
  export function installCoreValuePorts(ports) {
@@ -67,3 +68,7 @@ export function validatePermissionRules(rules, opts) {
67
68
  export function discussionWorkflowName() {
68
69
  return port('DISCUSSION_WORKFLOW_NAME');
69
70
  }
71
+ export function mintNamespacePrefix(ns, peer) {
72
+ const fn = port('mintNamespacePrefix');
73
+ return fn === undefined ? undefined : fn(ns, peer);
74
+ }
@@ -1,6 +1,6 @@
1
1
  import { corruptStoredRowContent, corruptStoredRowWhere } from './wireErrorTriage.js';
2
- import { parkedResumeStartupContent, parkedResumeStartupFromError, resumePolicyBlockContent, resumePolicyBlockFromError, } from './resumeRefusalCopy.js';
3
- import { decideParkMovedContent, decideParkMovedFromError } from './decideReceipt.js';
2
+ import { checkpointUnsupportedVersionContent, checkpointUnsupportedVersionFromError, parkedResumeStartupContent, parkedResumeStartupFromError, resumePolicyBlockContent, resumePolicyBlockFromError, } from './resumeRefusalCopy.js';
3
+ import { askGoneContent, askGoneFromError, decideParkMovedContent, decideParkMovedFromError } from './decideReceipt.js';
4
4
  import { settingsPermissionBucketRefusalContent, settingsPermissionBucketRefusalFromError } from './wireRefusalCopy.js';
5
5
  export function decideFailureNote(err, decision) {
6
6
  const where = corruptStoredRowWhere(err);
@@ -8,9 +8,13 @@ export function decideFailureNote(err, decision) {
8
8
  const startup = parkedResumeStartupFromError(err, decision);
9
9
  const moved = decideParkMovedFromError(err);
10
10
  const bucket = settingsPermissionBucketRefusalFromError(err);
11
+ const unsupported = checkpointUnsupportedVersionFromError(err);
12
+ const gone = askGoneFromError(err);
11
13
  return ((where === undefined ? '' : ` — ${corruptStoredRowContent(where)}`) +
12
14
  (fold === null ? '' : ` — ${resumePolicyBlockContent(fold)}`) +
13
15
  (bucket === null ? '' : ` — ${settingsPermissionBucketRefusalContent(bucket)}`) +
14
16
  (startup === null ? '' : ` — ${parkedResumeStartupContent(startup)}`) +
15
- (moved === null ? '' : ` — ${decideParkMovedContent(moved)}`));
17
+ (moved === null ? '' : ` — ${decideParkMovedContent(moved)}`) +
18
+ (unsupported === null ? '' : ` — ${checkpointUnsupportedVersionContent(unsupported)}`) +
19
+ (gone === null ? '' : ` — ${askGoneContent(gone)}`));
16
20
  }
@@ -1,5 +1,6 @@
1
1
  import { type GateOutcomeView } from './gateOutcome.js';
2
2
  import { type ResumeReopenDetail } from './hitl/suspendedReopen.js';
3
+ import { type CrashConvergedRow } from './hitl/crashConverged.js';
3
4
  export interface DecideReceiptView {
4
5
  status?: string;
5
6
  taskId?: string;
@@ -27,3 +28,11 @@ export interface DecideParkMovedDetail {
27
28
  }
28
29
  export declare function decideParkMovedFromError(e: unknown): DecideParkMovedDetail | null;
29
30
  export declare function decideParkMovedContent(detail: Pick<DecideParkMovedDetail, 'code'>): string;
31
+ export interface AskGoneDetail {
32
+ code: 'gone.ask';
33
+ state?: 'VOID' | 'DENIED';
34
+ deniedReason?: string;
35
+ holderGone?: CrashConvergedRow['cause'];
36
+ }
37
+ export declare function askGoneFromError(e: unknown): AskGoneDetail | null;
38
+ export declare function askGoneContent(detail: AskGoneDetail): string;
@@ -1,8 +1,9 @@
1
1
  import { gateOutcomeOf } from './gateOutcome.js';
2
2
  import { resumeReopenFromError } from './hitl/suspendedReopen.js';
3
- import { DECIDE_CLAIM_LOST, DECIDE_GATE_MOVED, DECIDE_NOT_PARKED, DECIDE_WORKFLOW_HOST_UNKNOWN, DECIDE_WORKFLOW_LANE_CODES, DECIDE_WORKFLOW_REMEMBER_UNSUPPORTED, isDecideParkMovedCode, } from './engineErrorCodes.js';
3
+ import { ASK_GONE, ASK_GONE_DENIED_WORD, DECIDE_CLAIM_LOST, DECIDE_GATE_MOVED, DECIDE_NOT_PARKED, DECIDE_WORKFLOW_HOST_UNKNOWN, DECIDE_WORKFLOW_LANE_CODES, DECIDE_WORKFLOW_REMEMBER_UNSUPPORTED, isDecideParkMovedCode, } from './engineErrorCodes.js';
4
4
  import { effectiveWireErrorCode } from './wireErrorTriage.js';
5
5
  import { readErrorString } from './wireFailureShape.js';
6
+ import { isCrashConvergedCause } from './hitl/crashConverged.js';
6
7
  const STATUS_RESUMING = 'resuming';
7
8
  function str(v) {
8
9
  return typeof v === 'string' && v.length > 0 ? v : undefined;
@@ -106,3 +107,63 @@ export function decideParkMovedContent(detail) {
106
107
  const extra = code === DECIDE_CLAIM_LOST ? '; if this approval is still listed, wait a little before deciding it again' : '';
107
108
  return `${what} · This decision was not applied — fetch the pending approvals again and decide from what is pending now${extra}`;
108
109
  }
110
+ export function askGoneFromError(e) {
111
+ if (typeof e !== 'object' || e === null)
112
+ return null;
113
+ if (effectiveWireErrorCode(e) !== ASK_GONE)
114
+ return null;
115
+ const rawState = readErrorString(e, 'state');
116
+ const state = rawState === 'VOID' || rawState === 'DENIED' ? rawState : undefined;
117
+ const rawReason = readErrorString(e, 'deniedReason');
118
+ const deniedReason = rawReason === undefined || rawReason.length === 0
119
+ ? undefined
120
+ : state === 'DENIED'
121
+ ? rawReason === ASK_GONE_DENIED_WORD ? rawReason : undefined
122
+ : state === 'VOID' ? rawReason : undefined;
123
+ const holderGone = state === 'VOID' && isCrashConvergedCause(deniedReason) ? deniedReason : undefined;
124
+ return {
125
+ code: ASK_GONE,
126
+ ...(state !== undefined ? { state } : {}),
127
+ ...(deniedReason !== undefined ? { deniedReason } : {}),
128
+ ...(holderGone !== undefined ? { holderGone } : {}),
129
+ };
130
+ }
131
+ export function askGoneContent(detail) {
132
+ let state;
133
+ let deniedReason;
134
+ let holderGone;
135
+ try {
136
+ state = detail.state;
137
+ deniedReason = detail.deniedReason;
138
+ holderGone = detail.holderGone;
139
+ }
140
+ catch {
141
+ state = undefined;
142
+ deniedReason = undefined;
143
+ holderGone = undefined;
144
+ }
145
+ const st = state === 'VOID' || state === 'DENIED' ? state : undefined;
146
+ const safety = 'Your answer was not applied and nothing was run on it';
147
+ if (st === 'VOID' && (isCrashConvergedCause(holderGone) || isCrashConvergedCause(deniedReason))) {
148
+ return [
149
+ 'The engine run that was waiting for this answer ended before the answer arrived',
150
+ safety,
151
+ 'That run will not continue: submit the work again as a new task, and it will ask again',
152
+ ].join(' · ');
153
+ }
154
+ if (st === 'DENIED') {
155
+ return ['This approval was closed without a human decision and the request was denied', safety, 'The denial stands; this approval cannot be reopened'].join(' · ');
156
+ }
157
+ if (st === 'VOID') {
158
+ return [
159
+ 'This approval was withdrawn without a human decision',
160
+ safety,
161
+ 'Nothing is waiting for this answer any more; if the work still needs this step, wait for it to be asked again or submit the work again',
162
+ ].join(' · ');
163
+ }
164
+ return [
165
+ 'This approval was closed without a human decision',
166
+ safety,
167
+ 'It can no longer be decided; fetch the pending approvals again and decide from what is pending now',
168
+ ].join(' · ');
169
+ }
@@ -14,4 +14,5 @@ export type DisableSkillsDeclaration = {
14
14
  };
15
15
  };
16
16
  export declare function disableSkillsDeclaration(want: unknown, baseUrl: string | undefined): DisableSkillsDeclaration;
17
+ export declare function disableSkillsDeclarationSettled(want: boolean | null | undefined, baseUrl: string | undefined, withinMs: number): Promise<DisableSkillsDeclaration>;
17
18
  export {};
@@ -1,4 +1,4 @@
1
- import { engineCapState } from './engineCapsCache.js';
1
+ import { engineCapState, engineCapsSettled } from './engineCapsCache.js';
2
2
  const KEY = 'disableSkills';
3
3
  const shapeOf = (v) => {
4
4
  try {
@@ -50,3 +50,10 @@ export function disableSkillsDeclaration(want, baseUrl) {
50
50
  const cause = WITHHELD_CAUSE_OF[state];
51
51
  return Object.freeze({ field: Object.freeze({}), withheld: Object.freeze({ cause, text: WITHHELD_TEXT[cause] }) });
52
52
  }
53
+ export async function disableSkillsDeclarationSettled(want, baseUrl, withinMs) {
54
+ refuseBadDisableSkills(want, 'disableSkillsDeclarationSettled');
55
+ if (want !== true)
56
+ return disableSkillsDeclaration(want, baseUrl);
57
+ await engineCapsSettled(baseUrl, { withinMs: typeof withinMs === 'number' ? withinMs : 0 });
58
+ return disableSkillsDeclaration(want, baseUrl);
59
+ }