@sema-agent/client-core 0.84.1 → 0.85.1

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 (91) hide show
  1. package/CHANGELOG.md +206 -0
  2. package/README.md +20 -13
  3. package/dist/adapt/arms.js +1 -1
  4. package/dist/adapt.d.ts +1 -1
  5. package/dist/adapt.js +1 -1
  6. package/dist/adapter/activeRunSelfHeal.d.ts +3 -0
  7. package/dist/adapter/activeRunSelfHeal.js +149 -17
  8. package/dist/adapter/downstream/terminalToSdkResult.js +9 -5
  9. package/dist/adapter/runStream.js +6 -2
  10. package/dist/agentSession/engineSessionBackgroundStop.d.ts +50 -0
  11. package/dist/agentSession/engineSessionBackgroundStop.js +291 -0
  12. package/dist/agentsWireCaps.d.ts +2 -1
  13. package/dist/cloudConfigWireCaps.js +2 -1
  14. package/dist/corruptSession.d.ts +3 -0
  15. package/dist/corruptSession.js +29 -0
  16. package/dist/corruptSessionCopy.d.ts +1 -0
  17. package/dist/corruptSessionCopy.js +4 -0
  18. package/dist/decideFailureNote.js +4 -1
  19. package/dist/decideReceipt.d.ts +6 -0
  20. package/dist/decideReceipt.js +30 -1
  21. package/dist/effortWire.d.ts +2 -1
  22. package/dist/effortWire.js +2 -4
  23. package/dist/engineErrorCodes.d.ts +9 -0
  24. package/dist/engineErrorCodes.js +29 -0
  25. package/dist/engineNoticeCodes.d.ts +9 -0
  26. package/dist/engineNoticeCodes.js +44 -156
  27. package/dist/engineWireFor.d.ts +43 -0
  28. package/dist/engineWireFor.js +399 -0
  29. package/dist/engineWireSdk.d.ts +4 -0
  30. package/dist/fileHistoryCaptureCapability.d.ts +4 -1
  31. package/dist/fileHistoryCaptureCapability.js +43 -9
  32. package/dist/gateVocabulary.d.ts +1 -2
  33. package/dist/gateVocabulary.js +1 -22
  34. package/dist/generated/engineNoticeTables.d.ts +3 -0
  35. package/dist/generated/engineNoticeTables.js +156 -0
  36. package/dist/generated/toolNameTables.d.ts +2 -0
  37. package/dist/generated/toolNameTables.js +43 -0
  38. package/dist/headlessPermissionModeWire.js +2 -4
  39. package/dist/hitl/armedGateRegistry.d.ts +1 -0
  40. package/dist/hitl/armedGateRegistry.js +1 -1
  41. package/dist/hitl/frameRouter.js +4 -2
  42. package/dist/hitl/parkResolver.js +3 -1
  43. package/dist/hitl/planReviewWire.d.ts +11 -0
  44. package/dist/hitl/planReviewWire.js +191 -72
  45. package/dist/hitl/rosterMountedNames.d.ts +2 -0
  46. package/dist/hitl/rosterMountedNames.js +38 -0
  47. package/dist/hitl/sessionPolicyDeliverable.d.ts +6 -2
  48. package/dist/hitl/sessionPolicyDeliverable.js +25 -45
  49. package/dist/hitl/sessionPolicyWire.js +1 -38
  50. package/dist/hitl/toolApprovalWire.d.ts +4 -2
  51. package/dist/hitl/toolApprovalWire.js +4 -2
  52. package/dist/host.d.ts +1 -1
  53. package/dist/host.js +11 -2
  54. package/dist/index.d.ts +10 -4
  55. package/dist/index.js +7 -3
  56. package/dist/permissionWireCaps.d.ts +2 -1
  57. package/dist/permissionWireCaps.js +2 -7
  58. package/dist/request/taskRequest.d.ts +4 -0
  59. package/dist/request/taskRequest.js +30 -1
  60. package/dist/resumeRefusalCopy.js +4 -2
  61. package/dist/runTerminal.js +4 -0
  62. package/dist/sandboxWire.js +1 -1
  63. package/dist/sealedKeyCapability.d.ts +17 -0
  64. package/dist/sealedKeyCapability.js +42 -0
  65. package/dist/seatContract.d.ts +2 -1
  66. package/dist/seatContract.js +5 -21
  67. package/dist/subagent/engineCompactWire.d.ts +13 -2
  68. package/dist/subagent/engineCompactWire.js +48 -37
  69. package/dist/subagent/engineDelegatedPrompt.d.ts +9 -1
  70. package/dist/subagent/engineDelegatedPrompt.js +16 -16
  71. package/dist/subagent/engineRowStopGate.d.ts +2 -2
  72. package/dist/subagent/engineRowStopGate.js +4 -4
  73. package/dist/subagent/engineSubagentOutput.d.ts +8 -0
  74. package/dist/subagent/engineSubagentOutput.js +37 -18
  75. package/dist/subagent/engineSubagentResume.d.ts +11 -2
  76. package/dist/subagent/engineSubagentResume.js +28 -14
  77. package/dist/subagent/engineSubagentSteer.d.ts +10 -1
  78. package/dist/subagent/engineSubagentSteer.js +16 -11
  79. package/dist/subagent/engineSubagentTail.d.ts +10 -1
  80. package/dist/subagent/engineSubagentTail.js +35 -17
  81. package/dist/subagent/engineTaskHandleWire.d.ts +13 -0
  82. package/dist/subagent/engineTaskHandleWire.js +41 -20
  83. package/dist/subagent/subagentOwnerAbsence.js +2 -5
  84. package/dist/taskRequestWords.d.ts +5 -0
  85. package/dist/taskRequestWords.js +4 -0
  86. package/dist/wireErrorTriage.d.ts +1 -0
  87. package/dist/wireErrorTriage.js +3 -1
  88. package/dist/wireRefusalCopy.d.ts +10 -0
  89. package/dist/wireRefusalCopy.js +62 -2
  90. package/docs/INTEGRATION-CLIENTS.md +867 -22
  91. package/package.json +1 -1
@@ -141,7 +141,7 @@ const userArm = function* (m, { ctx, idOf }) {
141
141
  };
142
142
  const systemArm = function* (m, { ctx, idOf }) {
143
143
  yield transcript(m, ctx.now());
144
- const attachedFiles = m._sema_attached_files ?? m.attachedFiles;
144
+ const attachedFiles = m._sema_attached_files;
145
145
  if (Array.isArray(attachedFiles)) {
146
146
  let i = 0;
147
147
  for (const f of attachedFiles) {
package/dist/adapt.d.ts CHANGED
@@ -1,5 +1,5 @@
1
1
  import type { AdapterContext, AdapterOutput, WireToCcAdapter } from './seam.js';
2
- export { CANCEL_MESSAGE, estimateCjkTokens, flattenWireOutput, FLUSH_INTERVAL_MS, IDLE_FLUSH_MS, REJECT_MESSAGE, sanitizeToolUseBlock, shortTaskLabel, SUBAGENT_TOOL_NAMES, WORKFLOW_TOOL_NAMES, } from './adapt/wireShapes.js';
2
+ export { CANCEL_MESSAGE, estimateCjkTokens, flattenWireOutput, FLUSH_INTERVAL_MS, IDLE_FLUSH_MS, REJECT_MESSAGE, sanitizeToolUseBlock, SUBAGENT_TOOL_NAMES, WORKFLOW_TOOL_NAMES, } from './adapt/wireShapes.js';
3
3
  export interface AdapterLedgerState {
4
4
  version: 1;
5
5
  renderedNotifications: string[];
package/dist/adapt.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { isEngineWorkflowNotified, isWorkflowCompletionCardEnqueued, listNotifiedRuns, listWorkflowCompletionCardsEnqueued, markEngineWorkflowNotified, noteWorkflowCompletionCardEnqueued, parseTranscriptNotificationSeeds, } from './notifications.js';
2
- export { CANCEL_MESSAGE, estimateCjkTokens, flattenWireOutput, FLUSH_INTERVAL_MS, IDLE_FLUSH_MS, REJECT_MESSAGE, sanitizeToolUseBlock, shortTaskLabel, SUBAGENT_TOOL_NAMES, WORKFLOW_TOOL_NAMES, } from './adapt/wireShapes.js';
2
+ export { CANCEL_MESSAGE, estimateCjkTokens, flattenWireOutput, FLUSH_INTERVAL_MS, IDLE_FLUSH_MS, REJECT_MESSAGE, sanitizeToolUseBlock, SUBAGENT_TOOL_NAMES, WORKFLOW_TOOL_NAMES, } from './adapt/wireShapes.js';
3
3
  import { IDLE_FLUSH_MS } from './adapt/wireShapes.js';
4
4
  import { chrome, mainLane, makeIdOf } from './adapt/ids.js';
5
5
  import { createTextStream } from './adapt/textStream.js';
@@ -35,6 +35,7 @@ export type ReopenCardVerdict = {
35
35
  pendingRowGone?: true;
36
36
  _sema_decisionInFlight?: true;
37
37
  dismissedByUser?: true;
38
+ _sema_noPresentationSurface?: true;
38
39
  } | {
39
40
  reopened: true;
40
41
  firstSight: boolean;
@@ -86,6 +87,7 @@ export type SelfHealOutcome = {
86
87
  decisionInFlight?: true;
87
88
  pendingRowGone?: true;
88
89
  dismissedByUser?: true;
90
+ noPresentationSurface?: true;
89
91
  } | {
90
92
  kind: 'not-parked';
91
93
  taskId: string;
@@ -108,6 +110,7 @@ export type SelfHealOutcome = {
108
110
  decidePath: string | null;
109
111
  decisionInFlight?: true;
110
112
  pendingRowGone?: true;
113
+ noPresentationSurface?: true;
111
114
  } | {
112
115
  kind: 'ask-decided-without-card';
113
116
  taskId: string;
@@ -79,11 +79,105 @@ export function readCancelRequested(body) {
79
79
  const v = body.cancelRequested;
80
80
  return typeof v === 'boolean' ? v : undefined;
81
81
  }
82
+ const REOPEN_VERDICT_KEYS = [
83
+ 'reopened',
84
+ 'firstSight',
85
+ 'presented',
86
+ 'decidedWithoutCard',
87
+ 'pendingRowGone',
88
+ '_sema_decisionInFlight',
89
+ 'dismissedByUser',
90
+ '_sema_noPresentationSurface',
91
+ ];
92
+ function snapshotReopenVerdict(raw) {
93
+ if (raw === null || raw === undefined)
94
+ return { reopened: false };
95
+ if (typeof raw !== 'object' && typeof raw !== 'function')
96
+ return raw;
97
+ const src = raw;
98
+ let nullProto = false;
99
+ try {
100
+ nullProto = Object.getPrototypeOf(raw) === null;
101
+ }
102
+ catch {
103
+ nullProto = false;
104
+ }
105
+ const snap = nullProto ? Object.create(null) : {};
106
+ const put = (k, v) => {
107
+ Object.defineProperty(snap, k, { value: v, enumerable: true, writable: true, configurable: true });
108
+ };
109
+ let own = [];
110
+ try {
111
+ own = Reflect.ownKeys(raw);
112
+ }
113
+ catch {
114
+ own = [];
115
+ }
116
+ const copied = new Set();
117
+ for (const k of own) {
118
+ let enumerable = false;
119
+ try {
120
+ enumerable = Object.prototype.propertyIsEnumerable.call(raw, k);
121
+ }
122
+ catch {
123
+ enumerable = false;
124
+ }
125
+ if (!enumerable)
126
+ continue;
127
+ let v;
128
+ let readable = true;
129
+ try {
130
+ v = src[k];
131
+ }
132
+ catch {
133
+ readable = false;
134
+ }
135
+ if (!readable)
136
+ continue;
137
+ put(k, v);
138
+ copied.add(k);
139
+ }
140
+ for (const k of REOPEN_VERDICT_KEYS) {
141
+ if (copied.has(k))
142
+ continue;
143
+ let v;
144
+ let readable = true;
145
+ try {
146
+ v = src[k];
147
+ }
148
+ catch {
149
+ readable = false;
150
+ }
151
+ if (readable && v !== undefined)
152
+ put(k, v);
153
+ }
154
+ return snap;
155
+ }
82
156
  function reopenRefusedForDecisionInFlight(verdict) {
83
- return verdict !== null && verdict.reopened === false && verdict._sema_decisionInFlight === true;
157
+ try {
158
+ return verdict !== null && verdict.reopened === false && verdict._sema_decisionInFlight === true;
159
+ }
160
+ catch {
161
+ return false;
162
+ }
84
163
  }
85
164
  function reopenRefusedForUserDismissal(verdict) {
86
- return verdict !== null && verdict.reopened === false && verdict.dismissedByUser === true;
165
+ try {
166
+ return verdict !== null && verdict.reopened === false && verdict.dismissedByUser === true;
167
+ }
168
+ catch {
169
+ return false;
170
+ }
171
+ }
172
+ function reopenRefusedForNoPresentationSurface(verdict) {
173
+ try {
174
+ return (verdict !== null &&
175
+ verdict.reopened === false &&
176
+ verdict._sema_noPresentationSurface === true);
177
+ }
178
+ catch {
179
+ return false;
180
+ }
87
181
  }
88
182
  function planReviewReopenTriggerFor(origin) {
89
183
  if (origin === 'user')
@@ -93,7 +187,31 @@ function planReviewReopenTriggerFor(origin) {
93
187
  return undefined;
94
188
  }
95
189
  function reopenDelivered(verdict) {
96
- return verdict.reopened === true && verdict.presented !== false;
190
+ let reopened;
191
+ let presented;
192
+ try {
193
+ reopened = verdict.reopened;
194
+ }
195
+ catch {
196
+ return false;
197
+ }
198
+ if (reopened !== true)
199
+ return false;
200
+ try {
201
+ presented = verdict.presented;
202
+ }
203
+ catch {
204
+ presented = undefined;
205
+ }
206
+ return presented !== false;
207
+ }
208
+ function reopenedOfOutcome(outcome) {
209
+ try {
210
+ return outcome.reopened ?? null;
211
+ }
212
+ catch {
213
+ return null;
214
+ }
97
215
  }
98
216
  export function atMostOnceFailureClass(e) {
99
217
  const status = e?.status;
@@ -299,7 +417,7 @@ async function planVerdict(taskId, deps) {
299
417
  try {
300
418
  const trigger = planReviewReopenTriggerFor(deps?.submissionOrigin);
301
419
  const verdict = trigger === undefined ? deps?.reopenPlanReview?.(taskId) : deps?.reopenPlanReview?.(taskId, { trigger });
302
- return (await verdict) ?? { reopened: false };
420
+ return snapshotReopenVerdict(await verdict);
303
421
  }
304
422
  catch {
305
423
  return { reopened: false };
@@ -307,7 +425,7 @@ async function planVerdict(taskId, deps) {
307
425
  }
308
426
  async function askVerdict(taskId, deps) {
309
427
  try {
310
- return (await deps?.reopenAskPark?.(taskId)) ?? { reopened: false };
428
+ return snapshotReopenVerdict(await deps?.reopenAskPark?.(taskId));
311
429
  }
312
430
  catch {
313
431
  return { reopened: false };
@@ -324,6 +442,7 @@ async function planReviewArm(taskId, signal, deps) {
324
442
  ...(reopenRefusedForDecisionInFlight(verdict) ? { decisionInFlight: true } : {}),
325
443
  ...(verdict.pendingRowGone === true ? { pendingRowGone: true } : {}),
326
444
  ...(reopenRefusedForUserDismissal(verdict) ? { dismissedByUser: true } : {}),
445
+ ...(reopenRefusedForNoPresentationSurface(verdict) ? { noPresentationSurface: true } : {}),
327
446
  };
328
447
  }
329
448
  async function askParkArm(taskId, signal, runs, deps) {
@@ -364,6 +483,7 @@ async function askParkArm(taskId, signal, runs, deps) {
364
483
  decidePath: signal.pendingGate?.decidePath ?? null,
365
484
  ...(inFlight ? { decisionInFlight: true } : {}),
366
485
  ...(verdict.pendingRowGone === true ? { pendingRowGone: true } : {}),
486
+ ...(reopenRefusedForNoPresentationSurface(verdict) ? { noPresentationSurface: true } : {}),
367
487
  };
368
488
  }
369
489
  async function probeRunStatusOnce(taskId, durable, durableGet, deps) {
@@ -655,6 +775,7 @@ export function activeRunSelfHealRow(outcome, signal, copy, origin, follow) {
655
775
  }
656
776
  const INJECTED_LEAD = 'A follow-up message sema sent on its own (not one you typed)';
657
777
  const USER_CLOSED_CARD_NOT_PUT_BACK = 'sema does not put a card you closed back on screen by itself';
778
+ const NO_CARD_VIEW_ATTACHED = 'this session has no view attached that can show decision cards';
658
779
  function injectedSubmissionRow(outcome, following = false) {
659
780
  const lead = INJECTED_LEAD;
660
781
  const id = 'taskId' in outcome && outcome.taskId ? ` (id ${outcome.taskId})` : '';
@@ -677,17 +798,19 @@ function injectedSubmissionRow(outcome, following = false) {
677
798
  }
678
799
  if (outcome.kind === 'running-steered' && outcome.delivery === 'queued') {
679
800
  const queuedOn = `${lead} is queued on an earlier reply${id} that is paused waiting for a decision`;
680
- if (outcome.reopened !== null && reopenDelivered(outcome.reopened)) {
801
+ const reopened = reopenedOfOutcome(outcome);
802
+ if (reopened !== null && reopenDelivered(reopened)) {
681
803
  return `${queuedOn}; sema has shown that decision card, and the message is picked up once you answer it.`;
682
804
  }
683
- if (reopenRefusedForDecisionInFlight(outcome.reopened)) {
805
+ if (reopenRefusedForDecisionInFlight(reopened)) {
684
806
  return `${queuedOn}; your answer to it is still on its way, and the message is picked up once that answer is applied.`;
685
807
  }
686
- if (reopenRefusedForUserDismissal(outcome.reopened)) {
808
+ if (reopenRefusedForUserDismissal(reopened)) {
687
809
  return (`${queuedOn}; you closed that card yourself, so sema did not put it back on screen — send a message to bring it ` +
688
810
  `back, and the message is picked up once that decision is made.`);
689
811
  }
690
- return `${queuedOn} sema could not show here; the message is picked up only once that decision is made.`;
812
+ const noView = reopenRefusedForNoPresentationSurface(reopened) ? ` (${NO_CARD_VIEW_ATTACHED})` : '';
813
+ return `${queuedOn} sema could not show here${noView}; the message is picked up only once that decision is made.`;
691
814
  }
692
815
  if (outcome.kind === 'running-steered' && outcome.delivery === 'parked_for_wake') {
693
816
  return (`${lead} has not reached the model: the earlier reply${id} had already finished, so the message was set aside on it ` +
@@ -710,9 +833,13 @@ function injectedSubmissionRow(outcome, following = false) {
710
833
  `sema is following that reply and will show whatever it asks for next; nothing for you to do now.`
711
834
  : `${lead} was passed to the reply already in progress${id} instead of starting a new one — ` +
712
835
  `watch that reply for what it does with it.`;
713
- case 'not-delivered':
836
+ case 'not-delivered': {
837
+ const noView = (outcome.kind === 'ask-reopen-failed' || outcome.kind === 'plan-review-reopen-failed') && outcome.noPresentationSurface === true
838
+ ? ` (${NO_CARD_VIEW_ATTACHED})`
839
+ : '';
714
840
  return (`${lead} was not delivered: this session was still busy with an earlier reply${id}, and there was no open card ` +
715
- `you could answer to free it. sema did not retry, so the model has not seen it.`);
841
+ `you could answer to free it${noView}. sema did not retry, so the model has not seen it.`);
842
+ }
716
843
  }
717
844
  }
718
845
  function decisionInFlightRow(parkedOn) {
@@ -780,8 +907,9 @@ function activeRunSelfHealBaseRow(outcome, signal, wayOut, following = false, ke
780
907
  const viaEngine = engineDecide && outcome.decidePath
781
908
  ? ` You can also decide it on the engine directly: POST ${outcome.decidePath}.`
782
909
  : '';
910
+ const noView = outcome.noPresentationSurface === true ? `: ${NO_CARD_VIEW_ATTACHED}` : '';
783
911
  return (`The previous turn is parked waiting for your decision (run ${outcome.taskId}) and sema could ` +
784
- `not reopen that card here. It did NOT cancel the run — that would have decided it for you. ` +
912
+ `not reopen that card here${noView}. It did NOT cancel the run — that would have decided it for you. ` +
785
913
  (keepSessionWayOut !== null
786
914
  ? `Your message was NOT sent. To keep this conversation, ${keepSessionWayOut}: the card comes back when the session resumes, if it is still waiting. Or ${wayOut} if you no longer want it.${viaEngine}`
787
915
  : `Your message was NOT sent; ${wayOut} if you no longer want it.${viaEngine}`));
@@ -797,8 +925,9 @@ function activeRunSelfHealBaseRow(outcome, signal, wayOut, following = false, ke
797
925
  const viaEngine = engineDecide && outcome.decidePath
798
926
  ? ` You can also decide it on the engine directly: POST ${outcome.decidePath}.`
799
927
  : '';
928
+ const noView = outcome.noPresentationSurface === true ? `: ${NO_CARD_VIEW_ATTACHED}` : '';
800
929
  return (`The previous turn is parked waiting for a plan review (run ${outcome.taskId}) and sema could not ` +
801
- `reopen that approval card. It did NOT cancel the run — that would have discarded the plan for ` +
930
+ `reopen that approval card${noView}. It did NOT cancel the run — that would have discarded the plan for ` +
802
931
  (keepSessionWayOut !== null
803
932
  ? `you. Your message was NOT sent. To keep this conversation, ${keepSessionWayOut}: the card comes back when the session resumes, if it is still waiting. Or ${wayOut} if you no longer want that plan.${viaEngine}`
804
933
  : `you. Your message was NOT sent; ${wayOut} if you no longer want that plan.${viaEngine}`));
@@ -816,15 +945,18 @@ function activeRunSelfHealBaseRow(outcome, signal, wayOut, following = false, ke
816
945
  }
817
946
  if (outcome.delivery === 'queued') {
818
947
  const parked = outcome.status ? `parked (status ${outcome.status})` : 'parked';
819
- const next = outcome.reopened !== null && reopenDelivered(outcome.reopened)
948
+ const reopened = reopenedOfOutcome(outcome);
949
+ const next = reopened !== null && reopenDelivered(reopened)
820
950
  ? `sema has surfaced that decision card — answering it is what lets that run resume and pick your message up.`
821
- : reopenRefusedForDecisionInFlight(outcome.reopened)
951
+ : reopenRefusedForDecisionInFlight(reopened)
822
952
  ? `Your answer to that decision is still on its way to the engine, so sema did not show the card again; ` +
823
953
  `that run moves on once the engine applies it.`
824
- : reopenRefusedForUserDismissal(outcome.reopened)
954
+ : reopenRefusedForUserDismissal(reopened)
825
955
  ? `You closed that decision card yourself, so sema did not put it back on screen; nothing will resume that ` +
826
956
  `run until that decision is made — send a message to bring the card back.`
827
- : `sema could not surface that decision card here, so nothing will resume that run until that decision is made; ` +
957
+ : `sema could not surface that decision card here` +
958
+ (reopenRefusedForNoPresentationSurface(reopened) ? ` (${NO_CARD_VIEW_ATTACHED})` : '') +
959
+ `, so nothing will resume that run until that decision is made; ` +
828
960
  `${wayOut} if you no longer want it.`;
829
961
  return (`${handle} is not actually working right now: the engine reports it ${parked} on a decision it needs ` +
830
962
  `from you, so it queued your message on that park instead of running it. ${next} ${textOnly} ` +
@@ -5,7 +5,11 @@ import { REDACTION_MARKER_PREFIX, washCredentials } from '../../displayUntrusted
5
5
  import { readEffectiveReasoning, readEffectiveMemoryScopes } from '../../effectiveFacts.js';
6
6
  import { isReviewPark, readRunTerminal, runTerminalCode, runTerminalGateToolName, } from '../../runTerminal.js';
7
7
  import { toCcModelUsage } from './turnUsageToModelUsage.js';
8
- import { LIMITS_MAX_COST_EXCEEDED, LIMITS_MAX_TOKENS_EXCEEDED, LIMITS_MAX_TURNS_EXCEEDED, LIMITS_MAX_WALLTIME_EXCEEDED, OUTPUT_INVALID, isRewindFamilyCode, } from '../../engineErrorCodes.js';
8
+ import { LIMITS_MAX_COST_EXCEEDED, LIMITS_MAX_TOKENS_EXCEEDED, LIMITS_MAX_TURNS_EXCEEDED, LIMITS_MAX_WALLTIME_EXCEEDED, OUTPUT_INVALID, isCorruptSessionCode, isRewindFamilyCode, } from '../../engineErrorCodes.js';
9
+ import { corruptSessionContent } from '../../corruptSessionCopy.js';
10
+ function withSessionUnreadableNote(text, code) {
11
+ return isCorruptSessionCode(code) ? `${text}\n${corruptSessionContent()}` : text;
12
+ }
9
13
  function finiteOr0(v) {
10
14
  return typeof v === 'number' && Number.isFinite(v) ? v : 0;
11
15
  }
@@ -527,9 +531,9 @@ export function doneToSdkResult(ev, ctx, observed) {
527
531
  ...errorBase,
528
532
  subtype: failedSubtype,
529
533
  errors: [
530
- isRewindFamilyCode(failedCode) && failedMessage
534
+ withSessionUnreadableNote(isRewindFamilyCode(failedCode) && failedMessage
531
535
  ? `${failedMessage} (${failedCode})`
532
- : (failedMessage ?? 'run failed'),
536
+ : (failedMessage ?? 'run failed'), failedCode),
533
537
  ],
534
538
  });
535
539
  }
@@ -619,9 +623,9 @@ export function failedToSdkResult(ev, ctx, observed) {
619
623
  durationMs: elapsedMs(ctx),
620
624
  errorCode: ev.errorCode,
621
625
  errors: [
622
- isRewindFamilyCode(ev.errorCode) && ev.errorMessage
626
+ withSessionUnreadableNote(isRewindFamilyCode(ev.errorCode) && ev.errorMessage
623
627
  ? `${ev.errorMessage} (${ev.errorCode})`
624
- : (ev.errorMessage ?? ev.errorCode ?? 'run failed'),
628
+ : (ev.errorMessage ?? ev.errorCode ?? 'run failed'), ev.errorCode),
625
629
  ],
626
630
  });
627
631
  }
@@ -3,7 +3,8 @@ import { eventToSdkMessage, turnEndUsage } from './downstream/eventToSdkMessage.
3
3
  import { turnUsageToModelUsage } from './downstream/turnUsageToModelUsage.js';
4
4
  import { readRunCostFacts, terminalToSdkResult, TOOL_INPUT_JOIN_MAX_CALLS } from './downstream/terminalToSdkResult.js';
5
5
  import { coerceOutput, publishSubagentContentEvent } from '../subagentContentStore.js';
6
- import { ACTIVE_RUN_BUSY_ERROR_CODE, OUTPUT_INVALID, isLimitsExceededCode } from '../engineErrorCodes.js';
6
+ import { ACTIVE_RUN_BUSY_ERROR_CODE, OUTPUT_INVALID, isCorruptSessionCode, isLimitsExceededCode } from '../engineErrorCodes.js';
7
+ import { corruptSessionContent } from '../corruptSessionCopy.js';
7
8
  import { isReviewPark, readRunTerminal, runTerminalCode } from '../runTerminal.js';
8
9
  import { washCredentials } from '../displayUntrusted.js';
9
10
  import { ccToolDenialKindForToolEnd, gateDeniedBy, gateOutcomeOf } from '../gateOutcome.js';
@@ -474,7 +475,10 @@ async function* runStreamInner(events, ctx, handle = {}) {
474
475
  ?
475
476
  `${MODEL_OUTPUT_ERROR_PREFIX}: ${errText}${maxTokHint}`
476
477
  : `API Error: ${errText}${maxTokHint}`;
477
- yield syntheticTerminalRow(ctx, rowText);
478
+ const sessionUnreadable = ev.type === 'failed'
479
+ ? isCorruptSessionCode(ev.errorCode)
480
+ : doneTerminal?.kind === 'failed' && isCorruptSessionCode(doneTerminal.code);
481
+ yield syntheticTerminalRow(ctx, sessionUnreadable ? `${rowText}\n${corruptSessionContent()}` : rowText);
478
482
  }
479
483
  if (ev.type === 'done' && isReviewPark(doneTerminal) && ctx.emitChrome) {
480
484
  try {
@@ -0,0 +1,50 @@
1
+ import type { AgentClient, SessionBackgroundStopOutcome } from '@sema-agent/sdk';
2
+ import type { EngineWireInjection } from '../engineWireSdk.js';
3
+ export type EngineSessionBackgroundStopClient = {
4
+ sessions: Pick<AgentClient['sessions'], 'backgroundStop'>;
5
+ };
6
+ export type EngineSessionBackgroundStopWire = EngineWireInjection<EngineSessionBackgroundStopClient>;
7
+ export interface EngineSessionBackgroundStopOptions {
8
+ wire?: EngineSessionBackgroundStopWire;
9
+ signal?: AbortSignal;
10
+ sessionKey?: string;
11
+ }
12
+ export interface EngineSessionBackgroundReceipt {
13
+ readonly id: string;
14
+ readonly outcome: SessionBackgroundStopOutcome | (string & {});
15
+ }
16
+ export type EngineSessionBackgroundStopUnavailableWhy = 'bad_input' | 'no_wire' | 'capability_unknown' | 'no_exit_face';
17
+ export type EngineSessionBackgroundStopRefusedWhy = 'credentials_required' | 'not_permitted' | 'ownership_required' | 'session_not_found' | 'route_absent' | 'bad_request' | 'rate_limited' | 'other';
18
+ export type EngineSessionBackgroundStopResult = {
19
+ kind: 'stopped';
20
+ receipts?: readonly EngineSessionBackgroundReceipt[];
21
+ unreadableReceipts?: number;
22
+ } | {
23
+ kind: 'unavailable';
24
+ why: EngineSessionBackgroundStopUnavailableWhy;
25
+ detail: string;
26
+ } | {
27
+ kind: 'refused';
28
+ why: EngineSessionBackgroundStopRefusedWhy;
29
+ detail: string;
30
+ status?: number;
31
+ errorCode?: string;
32
+ retryAfterMs?: number;
33
+ } | {
34
+ kind: 'error';
35
+ detail: string;
36
+ status?: number;
37
+ errorCode?: string;
38
+ unconfirmed?: true;
39
+ };
40
+ export declare function stopEngineSessionBackground(sessionId: string, body: {
41
+ readonly includeRetained: boolean;
42
+ }, opts?: EngineSessionBackgroundStopOptions): Promise<EngineSessionBackgroundStopResult>;
43
+ export type EngineSessionBackgroundReceiptState = 'stopped' | 'still_running' | 'may_be_running';
44
+ export declare const ENGINE_SESSION_BACKGROUND_RECEIPT_STATES: readonly EngineSessionBackgroundReceiptState[];
45
+ export interface EngineSessionBackgroundReceiptReading {
46
+ readonly state: EngineSessionBackgroundReceiptState;
47
+ readonly text: string;
48
+ readonly unrecognizedOutcome?: string;
49
+ }
50
+ export declare function engineSessionBackgroundReceiptReadingOf(outcome: string): EngineSessionBackgroundReceiptReading;