@sema-agent/client-core 0.91.0 → 0.93.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 (195) hide show
  1. package/CHANGELOG.md +351 -0
  2. package/README.md +51 -34
  3. package/dist/adapt/arms.js +6 -12
  4. package/dist/adapt/panelTasks.d.ts +0 -2
  5. package/dist/adapt/panelTasks.js +6 -26
  6. package/dist/adapt/toolCards.js +6 -4
  7. package/dist/adapt.d.ts +1 -1
  8. package/dist/adapt.js +3 -3
  9. package/dist/adapter/activeRunSelfHeal.d.ts +0 -2
  10. package/dist/adapter/activeRunSelfHeal.js +5 -27
  11. package/dist/adapter/downstream/terminalToSdkResult.js +16 -7
  12. package/dist/adapter/runStream.js +6 -2
  13. package/dist/agentsWireCaps.js +1 -1
  14. package/dist/approvalDecidedByCapability.d.ts +16 -0
  15. package/dist/approvalDecidedByCapability.js +47 -0
  16. package/dist/approvalsStreamLiveCapability.js +3 -3
  17. package/dist/askSurvivesStandingAnswer.d.ts +4 -1
  18. package/dist/askSurvivesStandingAnswer.js +13 -0
  19. package/dist/autoModeUnavailable.js +3 -2
  20. package/dist/centerWiringCapability.js +1 -1
  21. package/dist/cloudConfigWireCaps.js +10 -9
  22. package/dist/compensations.js +7 -7
  23. package/dist/controlRouter.d.ts +23 -23
  24. package/dist/controlRouter.js +114 -49
  25. package/dist/coreValuePorts.d.ts +4 -2
  26. package/dist/coreValuePorts.js +5 -0
  27. package/dist/decideFailureNote.js +4 -2
  28. package/dist/decideReceipt.d.ts +11 -0
  29. package/dist/decideReceipt.js +95 -9
  30. package/dist/detachWire.d.ts +2 -14
  31. package/dist/detachWire.js +1 -47
  32. package/dist/deviceExecutorManagementCapability.d.ts +6 -2
  33. package/dist/deviceExecutorManagementCapability.js +61 -15
  34. package/dist/displayUntrusted.js +2 -1
  35. package/dist/effectiveFacts.d.ts +14 -4
  36. package/dist/effectiveFacts.js +45 -5
  37. package/dist/engineAgentAbsence.js +2 -1
  38. package/dist/engineCapReader.js +16 -10
  39. package/dist/engineCapsCache.d.ts +2 -0
  40. package/dist/engineCapsCache.js +13 -2
  41. package/dist/engineConfigDrift.d.ts +20 -0
  42. package/dist/engineConfigDrift.js +54 -0
  43. package/dist/engineErrorCodes.d.ts +17 -0
  44. package/dist/engineErrorCodes.js +45 -0
  45. package/dist/engineInlineTaskStats.d.ts +1 -0
  46. package/dist/engineNoticeCodes.d.ts +16 -2
  47. package/dist/engineNoticeCodes.js +71 -0
  48. package/dist/engineWireFor.d.ts +22 -0
  49. package/dist/engineWireFor.js +154 -9
  50. package/dist/engineWireSdk.d.ts +0 -1
  51. package/dist/engineWireSdk.js +0 -3
  52. package/dist/executionLaneCapability.js +4 -2
  53. package/dist/fileHistoryCaptureCapability.d.ts +1 -1
  54. package/dist/fileHistoryCaptureCapability.js +1 -6
  55. package/dist/fileHistoryLegNotice.d.ts +1 -1
  56. package/dist/fileHistoryLegNotice.js +1 -6
  57. package/dist/gateOutcome.js +2 -17
  58. package/dist/gateVocabulary.d.ts +2 -8
  59. package/dist/gateVocabulary.js +6 -32
  60. package/dist/generated/engineFactTables.d.ts +17 -1
  61. package/dist/generated/engineFactTables.js +91 -0
  62. package/dist/generated/engineNoticeTables.d.ts +1 -1
  63. package/dist/generated/engineNoticeTables.js +4 -1
  64. package/dist/generated/settingsSchemaTables.d.ts +8 -0
  65. package/dist/generated/settingsSchemaTables.js +40 -0
  66. package/dist/goalStopHook.d.ts +1 -8
  67. package/dist/goalStopHook.js +2 -58
  68. package/dist/headlessPermissionModeWire.d.ts +3 -2
  69. package/dist/headlessPermissionModeWire.js +46 -5
  70. package/dist/hitl/allowRuleShadow.d.ts +21 -0
  71. package/dist/hitl/allowRuleShadow.js +167 -0
  72. package/dist/hitl/askClassPair.d.ts +14 -0
  73. package/dist/hitl/askClassPair.js +42 -0
  74. package/dist/hitl/askGateWire.js +1 -0
  75. package/dist/hitl/askParkRowRouting.js +2 -2
  76. package/dist/hitl/askSurvivesPosture.d.ts +5 -0
  77. package/dist/hitl/askSurvivesPosture.js +17 -0
  78. package/dist/hitl/automaticAnswerVerdict.d.ts +21 -0
  79. package/dist/hitl/automaticAnswerVerdict.js +143 -0
  80. package/dist/hitl/crashConverged.d.ts +1 -0
  81. package/dist/hitl/crashConverged.js +1 -1
  82. package/dist/hitl/frameRouter.d.ts +2 -0
  83. package/dist/hitl/frameRouter.js +73 -16
  84. package/dist/hitl/gateLedger.d.ts +7 -0
  85. package/dist/hitl/gateLedger.js +37 -5
  86. package/dist/hitl/hitlBridge.d.ts +1 -0
  87. package/dist/hitl/hitlBridge.js +6 -1
  88. package/dist/hitl/hitlHostSurface.d.ts +5 -2
  89. package/dist/hitl/hitlHostSurface.js +25 -3
  90. package/dist/hitl/livePendingAsk.js +24 -5
  91. package/dist/hitl/parkResolver.js +24 -4
  92. package/dist/hitl/persistedRulesWire.d.ts +4 -1
  93. package/dist/hitl/persistedRulesWire.js +38 -19
  94. package/dist/hitl/planReviewWire.d.ts +0 -2
  95. package/dist/hitl/planReviewWire.js +3 -20
  96. package/dist/hitl/replayedApproval.d.ts +21 -0
  97. package/dist/hitl/replayedApproval.js +89 -0
  98. package/dist/hitl/sessionPolicyDeliverable.js +20 -2
  99. package/dist/hitl/sessionPolicyWire.d.ts +10 -0
  100. package/dist/hitl/sessionPolicyWire.js +19 -6
  101. package/dist/hitl/toolApprovalWire.d.ts +27 -7
  102. package/dist/hitl/toolApprovalWire.js +153 -94
  103. package/dist/hookMatcherVerdict.js +2 -1
  104. package/dist/hooksWireCaps.d.ts +1 -1
  105. package/dist/hooksWireCaps.js +1 -1
  106. package/dist/humanTurn.js +3 -4
  107. package/dist/index.d.ts +21 -6
  108. package/dist/index.js +17 -4
  109. package/dist/inheritEnvWire.d.ts +1 -4
  110. package/dist/inheritEnvWire.js +3 -22
  111. package/dist/limitsWire.d.ts +0 -6
  112. package/dist/limitsWire.js +0 -38
  113. package/dist/mcpLiveness.js +2 -1
  114. package/dist/mcpProbeCapability.js +1 -1
  115. package/dist/mcpProbeWire.js +10 -12
  116. package/dist/mcpReconnect.d.ts +5 -0
  117. package/dist/mcpReconnect.js +28 -0
  118. package/dist/memoryComplianceCapability.js +2 -2
  119. package/dist/memoryOriginCapability.js +2 -2
  120. package/dist/memoryVerbsWire.d.ts +1 -1
  121. package/dist/memoryVerbsWire.js +17 -13
  122. package/dist/model/catalog.js +2 -1
  123. package/dist/model/providerPresets.d.ts +3 -1
  124. package/dist/model/tierVocabulary.d.ts +2 -1
  125. package/dist/model/tierVocabulary.js +3 -8
  126. package/dist/ownKey.d.ts +2 -0
  127. package/dist/ownKey.js +15 -0
  128. package/dist/peerFrames.js +2 -2
  129. package/dist/peerLaneCapability.js +2 -2
  130. package/dist/permissionModesCapability.d.ts +16 -0
  131. package/dist/permissionModesCapability.js +71 -0
  132. package/dist/permissionRuleIssue.js +10 -7
  133. package/dist/permissionRulesWriteCapability.js +2 -2
  134. package/dist/permissionWireCaps.d.ts +2 -0
  135. package/dist/permissionWireCaps.js +8 -1
  136. package/dist/permissionsAllowGrantCapability.js +7 -2
  137. package/dist/permissionsDeclaration.d.ts +7 -1
  138. package/dist/permissionsDeclaration.js +29 -20
  139. package/dist/pluginHooksWire.js +2 -11
  140. package/dist/postureKnob.js +1 -1
  141. package/dist/promptProfileWireCaps.d.ts +2 -1
  142. package/dist/protocolSegment.d.ts +11 -0
  143. package/dist/protocolSegment.js +31 -0
  144. package/dist/readFacePosture.js +1 -1
  145. package/dist/request/taskRequest.js +1 -15
  146. package/dist/resumeRefusalCopy.d.ts +1 -0
  147. package/dist/resumeRefusalCopy.js +26 -3
  148. package/dist/retryStatus.js +2 -1
  149. package/dist/rewindArchiveCapability.js +2 -2
  150. package/dist/ruleCompileVerdict.d.ts +2 -0
  151. package/dist/ruleCompileVerdict.js +13 -0
  152. package/dist/ruleRemovalConsequence.d.ts +2 -1
  153. package/dist/runCancelContext.d.ts +12 -0
  154. package/dist/runCancelContext.js +83 -1
  155. package/dist/runTerminal.d.ts +16 -0
  156. package/dist/runTerminal.js +32 -3
  157. package/dist/seam.d.ts +1 -0
  158. package/dist/seam.js +1 -1
  159. package/dist/seatContract.d.ts +2 -1
  160. package/dist/sessionMemoryStatus.d.ts +2 -4
  161. package/dist/sessionPolicyCapability.js +1 -1
  162. package/dist/sessionSyncFileHistoryCapability.d.ts +18 -0
  163. package/dist/sessionSyncFileHistoryCapability.js +50 -0
  164. package/dist/skillToolListsCapability.d.ts +18 -0
  165. package/dist/skillToolListsCapability.js +50 -0
  166. package/dist/sqlEngineCapability.js +2 -9
  167. package/dist/steerPriorityCapability.d.ts +18 -0
  168. package/dist/steerPriorityCapability.js +80 -0
  169. package/dist/steerReceipt.d.ts +9 -0
  170. package/dist/steerReceipt.js +25 -0
  171. package/dist/storePostureCapability.js +2 -2
  172. package/dist/subagent/engineSubagentSteer.js +2 -9
  173. package/dist/supportFloor.d.ts +1 -0
  174. package/dist/supportFloor.js +15 -5
  175. package/dist/taskRequestWords.d.ts +4 -2
  176. package/dist/taskRequestWords.js +1 -1
  177. package/dist/toolHistoryBadTurn.js +1 -2
  178. package/dist/toolResult.d.ts +10 -1
  179. package/dist/toolResult.js +80 -6
  180. package/dist/types/engineState.d.ts +2 -12
  181. package/dist/userInvokedSkillsCapability.d.ts +18 -0
  182. package/dist/userInvokedSkillsCapability.js +50 -0
  183. package/dist/webSearchBackendCapability.js +2 -2
  184. package/dist/webSearchWireCaps.d.ts +1 -1
  185. package/dist/webSearchWireCaps.js +40 -2
  186. package/dist/wireFailureShape.d.ts +2 -0
  187. package/dist/wireFailureShape.js +6 -2
  188. package/dist/wireRefusalCopy.d.ts +9 -3
  189. package/dist/wireRefusalCopy.js +41 -4
  190. package/dist/workflowsJournalCapability.d.ts +18 -0
  191. package/dist/workflowsJournalCapability.js +50 -0
  192. package/dist/writeProtectionCapability.d.ts +2 -4
  193. package/dist/writeProtectionCapability.js +1 -1
  194. package/docs/INTEGRATION-CLIENTS.md +1516 -18
  195. package/package.json +2 -2
@@ -1,4 +1,5 @@
1
1
  import { readErrorNumber, readErrorString } from './wireFailureShape.js';
2
+ import { readOwnDataNonEmptyString } from './ownKey.js';
2
3
  import { RESUME_CONTEXT_UNAVAILABLE, RESUME_PLACEMENT_MISMATCH, RESUME_PREFLIGHT_REJECTED, RESUME_POLICY_FOLD_CODE, PARKED_RESUME_STARTUP_FAILED, isStatusDerivedCoarseCode, RESUME_SESSION_NOT_FOUND, REQUEST_FIELD_CONFLICT, CHECKPOINT_UNSUPPORTED_VERSION, refusalSaysStillPending, } from './engineErrorCodes.js';
3
4
  import { capForDisplay } from './fleetTaskDesc.js';
4
5
  import { resumeRetryLaterFromError } from './wireErrorTriage.js';
@@ -115,7 +116,7 @@ export function requireExistingSessionRefusalFromError(err) {
115
116
  }
116
117
  }
117
118
  const REQUIRE_EXISTING_SESSION_SENTENCES = Object.freeze({
118
- session_not_found: 'The engine did not continue this conversation: the conversation it was asked to continue does not exist there (it may have expired, been removed, or never been created on that engine), and this request asked to continue only an existing one, so no new conversation was started · Start a new conversation, or pick another one to continue',
119
+ session_not_found: 'The engine did not continue this conversation: the conversation it was asked to continue does not exist there (it may have expired, been removed, or never been created on that engine; this client cannot tell which), and this request asked to continue only an existing one, so no new conversation was started · Start a new conversation, or pick another one to continue',
119
120
  session_id_missing: 'The engine did not continue this conversation: this request asked to continue only an existing conversation but named none, so there was nothing to continue and no new conversation was started · Name the conversation to continue, or start a new one',
120
121
  });
121
122
  const REQUIRE_EXISTING_SESSION_GENERIC = 'The engine did not continue this conversation: this request asked to continue only an existing conversation and there was none it could continue, so no new conversation was started · Start a new conversation, or pick another one to continue';
@@ -158,6 +159,26 @@ export function resumeContextUnavailableContent(d) {
158
159
  third,
159
160
  ].join(' · ');
160
161
  }
162
+ function parkedResumeStartupCauseWord(err) {
163
+ let named;
164
+ try {
165
+ named = readOwnDataNonEmptyString(err, 'startupCause');
166
+ }
167
+ catch {
168
+ named = undefined;
169
+ }
170
+ if (named !== undefined)
171
+ return named;
172
+ try {
173
+ const extra = err.extra;
174
+ if (typeof extra !== 'object' || extra === null || Array.isArray(extra))
175
+ return undefined;
176
+ return readOwnDataNonEmptyString(extra, 'cause');
177
+ }
178
+ catch {
179
+ return undefined;
180
+ }
181
+ }
161
182
  export function parkedResumeStartupFromError(err, decision) {
162
183
  if (typeof err !== 'object' || err === null)
163
184
  return null;
@@ -172,10 +193,12 @@ export function parkedResumeStartupFromError(err, decision) {
172
193
  return null;
173
194
  const rawTaskId = readErrorString(err, 'taskId');
174
195
  const taskId = rawTaskId !== undefined && rawTaskId.length > 0 ? rawTaskId : undefined;
196
+ const startupCause = parkedResumeStartupCauseWord(err);
175
197
  return {
176
198
  code: PARKED_RESUME_STARTUP_FAILED,
177
199
  cause: decision === 'deny' ? 'resume_rejected' : 'undetermined',
178
200
  ...(taskId !== undefined ? { taskId } : {}),
201
+ ...(startupCause !== undefined ? { startupCause } : {}),
179
202
  resendable: false,
180
203
  denyStaysOpen: true,
181
204
  };
@@ -183,7 +206,7 @@ export function parkedResumeStartupFromError(err, decision) {
183
206
  const PARKED_RESUME_STARTUP_STATE = 'This refusal does not say whether the card is still waiting — re-fetch the pending approvals';
184
207
  const PARKED_RESUME_STARTUP_SENTENCES = Object.freeze({
185
208
  resume_rejected: [
186
- 'The engine could not start the parked work to apply this decision (its session may be gone, or the engine rejected the decision itself)',
209
+ 'The engine could not start the parked work to apply this decision (its session may be gone, or the engine rejected the decision itself; this client cannot tell which)',
187
210
  PARKED_RESUME_STARTUP_STATE,
188
211
  'If the card is still there, decide it again from the fresh list',
189
212
  ].join(' · '),
@@ -249,7 +272,7 @@ export function checkpointUnsupportedVersionContent(detail, ctx) {
249
272
  }
250
273
  else {
251
274
  outlet =
252
- 'If it was parked before this server was upgraded, submit the work again as a new task: when it still has a run waiting on it (a tool approval, a plan review or a paused resource), cancel that run first; when it was waiting to be woken up, or was a workflow step continuing its host conversation, there is no run to cancel, so start a new task in that conversation';
275
+ 'If it was parked before this server was upgraded, submit the work again as a new task (this client cannot tell which kind of parked work this is, so both ways out are given): when it still has a run waiting on it (a tool approval, a plan review or a paused resource), cancel that run first; when it was waiting to be woken up, or was a workflow step continuing its host conversation, there is no run to cancel, so start a new task in that conversation';
253
276
  }
254
277
  return [CHECKPOINT_UNSUPPORTED_WHAT, CHECKPOINT_UNSUPPORTED_STILL_WAITING, outlet + CHECKPOINT_UNSUPPORTED_DRAIN].join(' · ');
255
278
  }
@@ -47,7 +47,7 @@ export function mapBrainStatusToRetry(p, nowMs) {
47
47
  case 'reconnecting':
48
48
  return { kind: 'stalled', deadline, ...extra, ...stalledDetail };
49
49
  case 'rate_limited':
50
- return { kind: 'error', deadline, ...extra, error: { formatted: '', rateLimits: {} } };
50
+ return { kind: 'error', deadline, ...extra, error: { formatted: p.detail ?? '', rateLimits: null } };
51
51
  case 'circuit_open':
52
52
  return {
53
53
  kind: 'error',
@@ -60,6 +60,7 @@ export function mapBrainStatusToRetry(p, nowMs) {
60
60
  case 'waiting_first_token':
61
61
  return { kind: 'waiting', deadline, ...extra, error: { formatted: '' } };
62
62
  case 'retrying':
63
+ return { kind: 'error', deadline, ...extra, error: { formatted: p.detail ?? '' } };
63
64
  default:
64
65
  return { kind: 'error', deadline, ...extra, error: { formatted: '' } };
65
66
  }
@@ -77,7 +77,7 @@ export function rewindArchiveDoctorDetail(reading, mode) {
77
77
  ? `${lane} off on this deployment (no file history store) — the working tree cannot be restored here; whether the conversation alone can be rewound is a separate reading`
78
78
  : `${lane} off on this deployment — it needs both a file history store and conversation anchors, and the engine reports at least one missing (it does not say which)`;
79
79
  case 'not_reported':
80
- return `${lane} not reported by this engine — only newer engines advertise it, so this does not say whether the code archive can be restored`;
80
+ return `${lane} not reported by this engine, so this does not say whether the code archive can be restored`;
81
81
  case 'malformed':
82
82
  return `${lane} reported in a shape this reader cannot read — the value is neither true nor false, so the answer is unknown, not "no"`;
83
83
  }
@@ -102,7 +102,7 @@ export function rewindConversationDoctorDetail(reading) {
102
102
  case 'off':
103
103
  return `${lane} off on this deployment (no conversation anchors) — the conversation cannot be moved back to an earlier message here`;
104
104
  case 'not_reported':
105
- return `conversation anchors not reported by this engine — only newer engines advertise them, so this does not say whether the conversation can be rewound`;
105
+ return `conversation anchors not reported by this engine, so this does not say whether the conversation can be rewound`;
106
106
  case 'malformed':
107
107
  return `conversation anchors reported in a shape this reader cannot read — the value is neither true nor false, so the answer is unknown, not "no"`;
108
108
  }
@@ -0,0 +1,2 @@
1
+ export type RuleCompileVerdict = 'compiles' | 'refused' | 'unknown';
2
+ export declare function ruleCompileVerdict(rule: string, behavior: 'deny' | 'ask'): RuleCompileVerdict;
@@ -0,0 +1,13 @@
1
+ import { validatePermissionRules } from './coreValuePorts.js';
2
+ const RULE_COMPILE_ROOT = '/';
3
+ export function ruleCompileVerdict(rule, behavior) {
4
+ try {
5
+ const issues = validatePermissionRules([{ rule, behavior }], { pathBases: { root: RULE_COMPILE_ROOT } });
6
+ if (!Array.isArray(issues))
7
+ return 'unknown';
8
+ return issues.length === 0 ? 'compiles' : 'refused';
9
+ }
10
+ catch {
11
+ return 'unknown';
12
+ }
13
+ }
@@ -1,3 +1,4 @@
1
- export type RuleRemovalBehavior = 'allow' | 'deny' | 'ask' | undefined;
1
+ import type { RuleBehavior } from '@sema-agent/sdk';
2
+ export type RuleRemovalBehavior = RuleBehavior | undefined;
2
3
  export declare function removalConsequenceLineForBehavior(behavior: RuleRemovalBehavior): string;
3
4
  export declare function ruleRemovalBehaviorOf(raw: unknown): RuleRemovalBehavior;
@@ -15,6 +15,7 @@ import { type RunTerminalRead } from './runTerminal.js';
15
15
  export type RunAbortCause = {
16
16
  kind: 'cancelled';
17
17
  context?: RunCancelContextView;
18
+ cause?: AbortCauseReading;
18
19
  } | {
19
20
  kind: 'engine_error';
20
21
  code?: string;
@@ -28,3 +29,14 @@ export type RunAbortCause = {
28
29
  };
29
30
  export declare const RUN_CANCELLED_CODE: "cancelled";
30
31
  export declare function classifyRunAbortCause(record: unknown): RunAbortCause;
32
+ export declare const ABORT_CAUSES: readonly ["client_disconnected", "ask_park_grace_exhausted", "cancel_verb"];
33
+ export type AbortCause = (typeof ABORT_CAUSES)[number];
34
+ export type AbortCauseReading = {
35
+ readonly kind: 'known';
36
+ readonly cause: AbortCause;
37
+ } | {
38
+ readonly kind: 'unrecognized';
39
+ readonly word: string;
40
+ };
41
+ export declare function readAbortCause(frame: unknown): AbortCauseReading | undefined;
42
+ export declare function abortCauseNoteOf(frame: unknown): string | undefined;
@@ -45,7 +45,8 @@ export function classifyRunAbortCause(record) {
45
45
  if (read !== null && read.kind === 'failed') {
46
46
  if (read.code === RUN_CANCELLED_CODE) {
47
47
  const cc = readRunCancelContext(record);
48
- return { kind: 'cancelled', ...(cc?.kind === 'present' ? { context: cc.context } : {}) };
48
+ const cause = readAbortCause(record);
49
+ return { kind: 'cancelled', ...(cc?.kind === 'present' ? { context: cc.context } : {}), ...(cause !== undefined ? { cause } : {}) };
49
50
  }
50
51
  return { kind: 'engine_error', ...(read.code !== undefined ? { code: read.code } : {}), ...(read.message !== undefined ? { message: read.message } : {}) };
51
52
  }
@@ -55,3 +56,84 @@ export function classifyRunAbortCause(record) {
55
56
  return { kind: 'run_still_live', status };
56
57
  return { kind: 'unknown', ...(read !== null ? { terminal: read.kind } : {}) };
57
58
  }
59
+ export const ABORT_CAUSES = Object.freeze(['client_disconnected', 'ask_park_grace_exhausted', 'cancel_verb']);
60
+ function ownDataOf(o, key) {
61
+ const d = Object.getOwnPropertyDescriptor(o, key);
62
+ return d !== undefined && Object.hasOwn(d, 'value') ? d.value : undefined;
63
+ }
64
+ function plainRecordOf(v) {
65
+ return v !== null && typeof v === 'object' && !Array.isArray(v) ? v : undefined;
66
+ }
67
+ function cancelledHolderOf(frame) {
68
+ const f = plainRecordOf(frame);
69
+ if (f === undefined)
70
+ return undefined;
71
+ const type = ownDataOf(f, 'type');
72
+ if (type === 'failed')
73
+ return ownDataOf(f, 'errorCode') === RUN_CANCELLED_CODE ? f : undefined;
74
+ const base = plainRecordOf(type === 'done' ? ownDataOf(f, 'result') : f);
75
+ if (base === undefined)
76
+ return undefined;
77
+ const holder = runResultHolder(base);
78
+ const t = readRunTerminal(holder);
79
+ return t !== null && t.kind === 'failed' && t.code === RUN_CANCELLED_CODE ? holder : undefined;
80
+ }
81
+ function abortCauseIn(holder) {
82
+ const raw = ownDataOf(holder, 'abortCause');
83
+ if (typeof raw !== 'string' || raw.length === 0)
84
+ return undefined;
85
+ return ABORT_CAUSES.includes(raw) ? { kind: 'known', cause: raw } : { kind: 'unrecognized', word: raw };
86
+ }
87
+ export function readAbortCause(frame) {
88
+ try {
89
+ const holder = cancelledHolderOf(frame);
90
+ return holder === undefined ? undefined : abortCauseIn(holder);
91
+ }
92
+ catch {
93
+ return undefined;
94
+ }
95
+ }
96
+ const ABORT_CAUSE_SENTENCES = Object.freeze({
97
+ client_disconnected: 'Aborted: the stream connection to the engine dropped, and the engine stopped the run (cause client_disconnected) — not an engine error.',
98
+ ask_park_grace_exhausted: 'Aborted: the connection dropped while a question or approval was pending, and the run could not be parked for later resumption in time ' +
99
+ '(cause ask_park_grace_exhausted) — not an engine error.',
100
+ cancel_verb: 'Cancelled: a cancel request to the engine stopped this run (cause cancel_verb) — not an engine error.',
101
+ });
102
+ const ABORT_CAUSE_UNRECOGNIZED_SENTENCE = 'Aborted by the engine for a reason this client does not recognize — not an engine error.';
103
+ function secondsText(ms) {
104
+ return `${(ms / 1000).toFixed(1)}s`;
105
+ }
106
+ function cancelContextOf(holder) {
107
+ try {
108
+ const r = readRunCancelContext(holder);
109
+ return r?.kind === 'present' ? r.context : undefined;
110
+ }
111
+ catch {
112
+ return undefined;
113
+ }
114
+ }
115
+ function cancelContextTail(ctx) {
116
+ if (ctx === undefined)
117
+ return '';
118
+ const parts = [];
119
+ if (ctx.elapsedMs !== undefined)
120
+ parts.push(`ran ${secondsText(ctx.elapsedMs)}`);
121
+ if (ctx.lastEventAgeMs !== undefined)
122
+ parts.push(`last engine activity ${secondsText(ctx.lastEventAgeMs)} before the stop`);
123
+ return parts.length > 0 ? ` (${parts.join('; ')})` : '';
124
+ }
125
+ export function abortCauseNoteOf(frame) {
126
+ try {
127
+ const holder = cancelledHolderOf(frame);
128
+ if (holder === undefined)
129
+ return undefined;
130
+ const cause = abortCauseIn(holder);
131
+ if (cause === undefined)
132
+ return undefined;
133
+ const sentence = cause.kind === 'known' ? ABORT_CAUSE_SENTENCES[cause.cause] : ABORT_CAUSE_UNRECOGNIZED_SENTENCE;
134
+ return `${sentence}${cancelContextTail(cancelContextOf(holder))}`;
135
+ }
136
+ catch {
137
+ return undefined;
138
+ }
139
+ }
@@ -16,6 +16,21 @@ export interface RunTerminalFailureDetail {
16
16
  status?: number;
17
17
  code?: string;
18
18
  }
19
+ export declare const PROMPT_BLOCK_CAUSES: readonly ["block", "crashed", "timeout", "cancelled"];
20
+ export type PromptBlockCause = (typeof PROMPT_BLOCK_CAUSES)[number];
21
+ export type RunTerminalBlockedDetail = {
22
+ kind: 'prompt_blocked_by_hook';
23
+ cause: PromptBlockCause;
24
+ hookReason?: string;
25
+ } | {
26
+ kind: 'prompt_blocked_by_hook';
27
+ cause: 'unrecognized';
28
+ word: string;
29
+ hookReason?: string;
30
+ } | {
31
+ kind: 'unrecognized';
32
+ word: string;
33
+ };
19
34
  export type RunTerminalRead = {
20
35
  kind: 'completed';
21
36
  plane: RunTerminalPlane;
@@ -31,6 +46,7 @@ export type RunTerminalRead = {
31
46
  plane: RunTerminalPlane;
32
47
  reason?: string;
33
48
  code?: string;
49
+ detail?: RunTerminalBlockedDetail;
34
50
  } | RunTerminalPausedRead | {
35
51
  kind: 'unknown';
36
52
  plane: RunTerminalPlane;
@@ -1,4 +1,6 @@
1
- import { CORE_TERMINAL_CAUSE_KINDS } from './generated/engineFactTables.js';
1
+ import { CORE_PROMPT_BLOCK_CAUSES, CORE_TERMINAL_CAUSE_KINDS } from './generated/engineFactTables.js';
2
+ export const PROMPT_BLOCK_CAUSES = CORE_PROMPT_BLOCK_CAUSES;
3
+ const PROMPT_BLOCKED_BY_HOOK_DETAIL_KIND = 'prompt_blocked_by_hook';
2
4
  function str(v) {
3
5
  return typeof v === 'string' && v.length > 0 ? v : undefined;
4
6
  }
@@ -20,10 +22,13 @@ function pauseOf(v) {
20
22
  ...(restoreMode !== undefined ? { restoreMode } : {}),
21
23
  };
22
24
  }
25
+ function ownValueOf(o, k) {
26
+ return Object.prototype.hasOwnProperty.call(o, k) ? o[k] : undefined;
27
+ }
23
28
  const PROVIDER_REJECTED_DETAIL_KIND = 'provider_rejected';
24
29
  function failureDetailOf(cause) {
25
30
  try {
26
- const own = (o, k) => (Object.prototype.hasOwnProperty.call(o, k) ? o[k] : undefined);
31
+ const own = ownValueOf;
27
32
  const v = own(cause, 'detail');
28
33
  if (typeof v !== 'object' || v === null || Array.isArray(v))
29
34
  return undefined;
@@ -41,6 +46,29 @@ function failureDetailOf(cause) {
41
46
  return undefined;
42
47
  }
43
48
  }
49
+ function blockedDetailOf(cause) {
50
+ try {
51
+ const v = ownValueOf(cause, 'detail');
52
+ if (typeof v !== 'object' || v === null || Array.isArray(v))
53
+ return undefined;
54
+ const kind = str(ownValueOf(v, 'kind'));
55
+ if (kind === undefined)
56
+ return undefined;
57
+ if (kind !== PROMPT_BLOCKED_BY_HOOK_DETAIL_KIND)
58
+ return { kind: 'unrecognized', word: kind };
59
+ const causeWord = str(ownValueOf(v, 'cause'));
60
+ if (causeWord === undefined)
61
+ return undefined;
62
+ const hookReason = str(ownValueOf(v, 'hookReason'));
63
+ const hook = hookReason !== undefined ? { hookReason } : {};
64
+ return PROMPT_BLOCK_CAUSES.includes(causeWord)
65
+ ? { kind: PROMPT_BLOCKED_BY_HOOK_DETAIL_KIND, cause: causeWord, ...hook }
66
+ : { kind: PROMPT_BLOCKED_BY_HOOK_DETAIL_KIND, cause: 'unrecognized', word: causeWord, ...hook };
67
+ }
68
+ catch {
69
+ return undefined;
70
+ }
71
+ }
44
72
  const FLAT_PAUSED_STATUSES = ['suspended', 'needs_review'];
45
73
  export function readRunTerminal(result) {
46
74
  if (typeof result !== 'object' || result === null || Array.isArray(result))
@@ -77,7 +105,8 @@ export function readRunTerminal(result) {
77
105
  }
78
106
  case 'blocked': {
79
107
  const reason = str(c.reason);
80
- return { kind: 'blocked', plane: 'cause', ...(reason !== undefined ? { reason } : {}) };
108
+ const detail = blockedDetailOf(c);
109
+ return { kind: 'blocked', plane: 'cause', ...(reason !== undefined ? { reason } : {}), ...(detail !== undefined ? { detail } : {}) };
81
110
  }
82
111
  case 'paused':
83
112
  return { kind: 'paused', plane: 'cause', ...(pauseOf(c) ?? {}) };
package/dist/seam.d.ts CHANGED
@@ -15,6 +15,7 @@ export interface InlineTaskTick {
15
15
  totalTokens: number;
16
16
  durationMs: number;
17
17
  currentAction?: string;
18
+ model?: string;
18
19
  }
19
20
  export interface AdapterContext {
20
21
  sessionId: string;
package/dist/seam.js CHANGED
@@ -94,7 +94,7 @@ const CHROME_ARM_TABLE = {
94
94
  },
95
95
  tool_progress: {
96
96
  required: false,
97
- duty: 'CC-08(0.71.0,C-R50 一帧两拍):按 `toolCallId` 挂到那张工具卡上;`elapsedSeconds` 缺席不是 0、不等于 tool_end 的 duration;' +
97
+ duty: 'CC-08(0.71.0,一帧两拍):按 `toolCallId` 挂到那张工具卡上;`elapsedSeconds` 缺席不是 0、不等于 tool_end 的 duration;' +
98
98
  '`output` 在场 = 命令尾巴窗口(活面板,不是日志;`totalLines`/`totalBytes` 与它同进同退),🔴 它是 UNTRUSTED RAW,可再封顶展示、**绝不回喂**模型;' +
99
99
  '子代工具的进度不在这条臂上(三键断闸),fleet 面板另有口。不接 = 看不见进度,不属行为丢失。',
100
100
  },
@@ -4,6 +4,7 @@ import type { LaneProof } from "./seam.js";
4
4
  import type { QuestionAnswer } from "./liveQuestionStore.js";
5
5
  import type { ToolApprovalDelegation } from "./hitl/toolApprovalWire.js";
6
6
  import type { ApprovalMandateWord } from "./gateVocabulary.js";
7
+ import type { ModelApiWord } from "./model/providerPresets.js";
7
8
  export interface SeatValidationFailure {
8
9
  reason: string;
9
10
  field?: string;
@@ -240,7 +241,7 @@ export interface SeatCatalogEntry {
240
241
  providerId: string;
241
242
  providerName: string;
242
243
  baseUrl: string;
243
- api: "anthropic-messages" | "openai-completions";
244
+ api: ModelApiWord;
244
245
  apiKey?: string;
245
246
  modelId: string;
246
247
  contextWindow: number;
@@ -1,4 +1,4 @@
1
- import type { SessionMemoryStatus } from '@sema-agent/sdk';
1
+ import type { SessionMemoryStatus, SessionMemoryStatusResponse } from '@sema-agent/sdk';
2
2
  export interface MemoryStatusClientLike {
3
3
  sessions: {
4
4
  memoryStatus(sessionId: string, opts?: {
@@ -8,9 +8,7 @@ export interface MemoryStatusClientLike {
8
8
  } & SessionMemoryStatus>;
9
9
  };
10
10
  }
11
- export type MemoryStatusFacts = SessionMemoryStatus & {
12
- readonly autoConsolidationArmed?: boolean;
13
- };
11
+ export type MemoryStatusFacts = Omit<SessionMemoryStatusResponse, 'sessionId'>;
14
12
  export type MemoryStatusVerdict = {
15
13
  readonly kind: 'ok';
16
14
  readonly sessionId: string;
@@ -34,7 +34,7 @@ export function sessionPolicyFaceAvailable(reading) {
34
34
  export function sessionPolicyDoctorDetail(reading) {
35
35
  switch (reading.kind) {
36
36
  case 'unobserved':
37
- return 'per-session rule face not observed — the engine reports it on /v1/capabilities (sessionPolicy); this process has no usable capabilities reading cached for it (none received, or the last one was unreadable)';
37
+ return 'per-session rule face not observed — the engine reports it on /v1/capabilities (sessionPolicy); this process has no usable capabilities reading cached for it (none received, the last one was unreadable, or the last one was discarded when the engine connection was reset; this process cannot tell which)';
38
38
  case 'not_reported':
39
39
  return 'per-session rule face not reported by this engine — this binary predates the position itself; it says nothing about whether the face exists, so read the rules rather than writing them blind';
40
40
  case 'absent':
@@ -0,0 +1,18 @@
1
+ export type SessionSyncFileHistoryReading = {
2
+ kind: 'unobserved';
3
+ } | {
4
+ kind: 'not_reported';
5
+ } | {
6
+ kind: 'absent';
7
+ } | {
8
+ kind: 'present';
9
+ };
10
+ export declare function projectSessionSyncFileHistoryCapability(caps: unknown): SessionSyncFileHistoryReading | undefined;
11
+ export declare function noteEngineCapsForSessionSyncFileHistory(baseUrl: string, caps: unknown, opts?: {
12
+ generation?: number;
13
+ }): void;
14
+ export declare function observedSessionSyncFileHistory(baseUrl?: string | undefined): SessionSyncFileHistoryReading;
15
+ export declare function sessionSyncFileHistoryAvailable(reading: SessionSyncFileHistoryReading): 'yes' | 'no' | 'unknown';
16
+ export declare function sessionSyncFileHistoryDoctorDetail(reading: SessionSyncFileHistoryReading): string;
17
+ export declare function forgetSessionSyncFileHistoryReading(baseUrl: string | undefined): void;
18
+ export declare function __resetSessionSyncFileHistoryReadingsForTests(): void;
@@ -0,0 +1,50 @@
1
+ import { engineWireTarget } from './engineWireTarget.js';
2
+ import { createEngineCapReader } from './engineCapReader.js';
3
+ export function projectSessionSyncFileHistoryCapability(caps) {
4
+ if (caps === null || typeof caps !== 'object' || Array.isArray(caps))
5
+ return undefined;
6
+ if (!Object.hasOwn(caps, 'sessionSyncFileHistory'))
7
+ return { kind: 'not_reported' };
8
+ const v = caps.sessionSyncFileHistory;
9
+ if (v === undefined)
10
+ return { kind: 'not_reported' };
11
+ if (typeof v !== 'boolean')
12
+ return undefined;
13
+ return v ? { kind: 'present' } : { kind: 'absent' };
14
+ }
15
+ const reader = createEngineCapReader({
16
+ name: 'sessionSyncFileHistory',
17
+ project: projectSessionSyncFileHistoryCapability,
18
+ makeUnobserved: () => ({ kind: 'unobserved' }),
19
+ });
20
+ export function noteEngineCapsForSessionSyncFileHistory(baseUrl, caps, opts) {
21
+ reader.note(baseUrl, caps, opts);
22
+ }
23
+ export function observedSessionSyncFileHistory(baseUrl = engineWireTarget()?.baseUrl) {
24
+ return reader.observed(baseUrl);
25
+ }
26
+ export function sessionSyncFileHistoryAvailable(reading) {
27
+ if (reading.kind === 'present')
28
+ return 'yes';
29
+ if (reading.kind === 'absent')
30
+ return 'no';
31
+ return 'unknown';
32
+ }
33
+ export function sessionSyncFileHistoryDoctorDetail(reading) {
34
+ switch (reading.kind) {
35
+ case 'unobserved':
36
+ return 'session-sync file history not observed — the engine reports it on /v1/capabilities (sessionSyncFileHistory); this process has no usable capabilities reading cached for it (none received, the last one was unreadable, or the last one was discarded when the engine connection was reset; this process cannot tell which)';
37
+ case 'not_reported':
38
+ return 'session-sync file history not reported separately by this engine; this does not say whether file history can be synced';
39
+ case 'absent':
40
+ return 'no session-sync file history on this deployment — syncing a session moves the conversation only; edited-file history stays behind';
41
+ case 'present':
42
+ return 'session-sync file history on — syncing a session can also move its edited-file history';
43
+ }
44
+ }
45
+ export function forgetSessionSyncFileHistoryReading(baseUrl) {
46
+ reader.forget(baseUrl);
47
+ }
48
+ export function __resetSessionSyncFileHistoryReadingsForTests() {
49
+ reader.__resetForTests();
50
+ }
@@ -0,0 +1,18 @@
1
+ export type SkillToolListsReading = {
2
+ kind: 'unobserved';
3
+ } | {
4
+ kind: 'not_reported';
5
+ } | {
6
+ kind: 'absent';
7
+ } | {
8
+ kind: 'present';
9
+ };
10
+ export declare function projectSkillToolListsCapability(caps: unknown): SkillToolListsReading | undefined;
11
+ export declare function noteEngineCapsForSkillToolLists(baseUrl: string, caps: unknown, opts?: {
12
+ generation?: number;
13
+ }): void;
14
+ export declare function observedSkillToolLists(baseUrl?: string | undefined): SkillToolListsReading;
15
+ export declare function skillToolListsAvailable(reading: SkillToolListsReading): 'yes' | 'no' | 'unknown';
16
+ export declare function skillToolListsDoctorDetail(reading: SkillToolListsReading): string;
17
+ export declare function forgetSkillToolListsReading(baseUrl: string | undefined): void;
18
+ export declare function __resetSkillToolListsReadingsForTests(): void;
@@ -0,0 +1,50 @@
1
+ import { engineWireTarget } from './engineWireTarget.js';
2
+ import { createEngineCapReader } from './engineCapReader.js';
3
+ export function projectSkillToolListsCapability(caps) {
4
+ if (caps === null || typeof caps !== 'object' || Array.isArray(caps))
5
+ return undefined;
6
+ if (!Object.hasOwn(caps, 'skillToolLists'))
7
+ return { kind: 'not_reported' };
8
+ const v = caps.skillToolLists;
9
+ if (v === undefined)
10
+ return { kind: 'not_reported' };
11
+ if (typeof v !== 'boolean')
12
+ return undefined;
13
+ return v ? { kind: 'present' } : { kind: 'absent' };
14
+ }
15
+ const reader = createEngineCapReader({
16
+ name: 'skillToolLists',
17
+ project: projectSkillToolListsCapability,
18
+ makeUnobserved: () => ({ kind: 'unobserved' }),
19
+ });
20
+ export function noteEngineCapsForSkillToolLists(baseUrl, caps, opts) {
21
+ reader.note(baseUrl, caps, opts);
22
+ }
23
+ export function observedSkillToolLists(baseUrl = engineWireTarget()?.baseUrl) {
24
+ return reader.observed(baseUrl);
25
+ }
26
+ export function skillToolListsAvailable(reading) {
27
+ if (reading.kind === 'present')
28
+ return 'yes';
29
+ if (reading.kind === 'absent' || reading.kind === 'not_reported')
30
+ return 'no';
31
+ return 'unknown';
32
+ }
33
+ export function skillToolListsDoctorDetail(reading) {
34
+ switch (reading.kind) {
35
+ case 'unobserved':
36
+ return 'skill tool lists not observed — the engine reports it on /v1/capabilities (skillToolLists); this process has no usable capabilities reading cached for it (none received, the last one was unreadable, or the last one was discarded when the engine connection was reset; this process cannot tell which)';
37
+ case 'not_reported':
38
+ return 'skill tool lists not reported by this engine — the engine predates them: tool lists on request skills are not read, so they do not limit any tool';
39
+ case 'absent':
40
+ return 'skill tool lists off on this deployment — tool lists on request skills are not read';
41
+ case 'present':
42
+ return 'skill tool lists on — a request skill’s allowed and disallowed tool lists are read as this run’s rules';
43
+ }
44
+ }
45
+ export function forgetSkillToolListsReading(baseUrl) {
46
+ reader.forget(baseUrl);
47
+ }
48
+ export function __resetSkillToolListsReadingsForTests() {
49
+ reader.__resetForTests();
50
+ }
@@ -16,14 +16,7 @@ export function projectSqlEngineCapability(caps) {
16
16
  return { kind: 'none' };
17
17
  return projectSqlEngineView(nested);
18
18
  }
19
- if (!Object.hasOwn(caps, 'sql'))
20
- return { kind: 'not_reported' };
21
- const sql = caps.sql;
22
- if (sql === null)
23
- return { kind: 'none' };
24
- if (sql === undefined)
25
- return { kind: 'not_reported' };
26
- return projectSqlEngineView(sql);
19
+ return { kind: 'not_reported' };
27
20
  }
28
21
  function projectSqlEngineView(sql) {
29
22
  if (sql === null || typeof sql !== 'object')
@@ -59,7 +52,7 @@ export function sqlEngineDoctorDetail(reading) {
59
52
  switch (reading.kind) {
60
53
  case 'unobserved':
61
54
  return ('not observed — the engine reports it on /v1/capabilities; this process has no usable ' +
62
- 'capabilities reading cached for it (none received, or the last one was unreadable)');
55
+ 'capabilities reading cached for it (none received, the last one was unreadable, or the last one was discarded when the engine connection was reset; this process cannot tell which)');
63
56
  case 'not_reported':
64
57
  return 'not reported by this engine — the capability position needs a newer engine';
65
58
  case 'none':
@@ -0,0 +1,18 @@
1
+ export type SteerPriorityReading = {
2
+ kind: 'unobserved';
3
+ } | {
4
+ kind: 'not_reported';
5
+ } | {
6
+ kind: 'present';
7
+ word: string;
8
+ };
9
+ export type SteerPriorityMode = 'engine' | 'advisory' | 'unknown';
10
+ export declare function projectSteerPriorityCapability(caps: unknown): SteerPriorityReading | undefined;
11
+ export declare function noteEngineCapsForSteerPriority(baseUrl: string, caps: unknown, opts?: {
12
+ generation?: number;
13
+ }): void;
14
+ export declare function observedSteerPriority(baseUrl?: string | undefined): SteerPriorityReading;
15
+ export declare function steerPriorityMode(reading: SteerPriorityReading): SteerPriorityMode;
16
+ export declare function steerPriorityDoctorDetail(reading: SteerPriorityReading): string;
17
+ export declare function forgetSteerPriorityReading(baseUrl: string | undefined): void;
18
+ export declare function __resetSteerPriorityReadingsForTests(): void;