@sema-agent/client-core 0.96.0 → 0.97.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 (145) hide show
  1. package/CHANGELOG.md +110 -0
  2. package/README.md +29 -22
  3. package/dist/adapter/activeRunSelfHeal.d.ts +0 -2
  4. package/dist/adapter/activeRunSelfHeal.js +7 -7
  5. package/dist/adapter/downstream/terminalToSdkResult.js +6 -2
  6. package/dist/agentSession/backgroundView.js +2 -15
  7. package/dist/agentsWireCaps.d.ts +3 -1
  8. package/dist/agentsWireCaps.js +67 -39
  9. package/dist/approvalDecidedByCapability.d.ts +2 -0
  10. package/dist/approvalDecidedByCapability.js +0 -1
  11. package/dist/approvalsStreamLiveCapability.d.ts +2 -0
  12. package/dist/approvalsStreamLiveCapability.js +3 -2
  13. package/dist/attachmentSeatCapability.d.ts +2 -0
  14. package/dist/attachmentSeatCapability.js +0 -1
  15. package/dist/callerCwdCapability.d.ts +2 -0
  16. package/dist/callerCwdCapability.js +0 -1
  17. package/dist/centerWiringCapability.d.ts +2 -0
  18. package/dist/centerWiringCapability.js +4 -3
  19. package/dist/cloudConfigWireCaps.d.ts +2 -2
  20. package/dist/cloudConfigWireCaps.js +192 -56
  21. package/dist/declared/supportFloorDeclared.js +3 -3
  22. package/dist/deviceExecutorManagementCapability.d.ts +2 -0
  23. package/dist/deviceExecutorManagementCapability.js +3 -2
  24. package/dist/displayUntrusted.d.ts +3 -0
  25. package/dist/displayUntrusted.js +15 -0
  26. package/dist/engineCapReader.d.ts +8 -2
  27. package/dist/engineCapReader.js +15 -7
  28. package/dist/engineCapsCache.d.ts +11 -3
  29. package/dist/engineCapsCache.js +54 -23
  30. package/dist/engineErrorCodes.d.ts +3 -0
  31. package/dist/engineErrorCodes.js +9 -1
  32. package/dist/engineNoticeCodes.js +2 -3
  33. package/dist/engineToolDirectory.d.ts +27 -0
  34. package/dist/engineToolDirectory.js +178 -0
  35. package/dist/executionLaneCapability.d.ts +2 -0
  36. package/dist/executionLaneCapability.js +3 -2
  37. package/dist/fileHistoryCaptureCapability.d.ts +2 -0
  38. package/dist/fileHistoryCaptureCapability.js +34 -8
  39. package/dist/fileHistoryLegNotice.js +4 -0
  40. package/dist/fleet/fleetLedger.js +129 -105
  41. package/dist/gateOutcome.js +2 -4
  42. package/dist/gateVocabulary.d.ts +1 -6
  43. package/dist/gateVocabulary.js +2 -5
  44. package/dist/generated/sdkFactTables.d.ts +2 -0
  45. package/dist/generated/sdkFactTables.js +7 -0
  46. package/dist/generated/toolNameTables.d.ts +0 -1
  47. package/dist/generated/toolNameTables.js +0 -42
  48. package/dist/hitl/approvalDecisionNoteAudit.js +2 -2
  49. package/dist/hitl/approvalEndingCause.js +2 -7
  50. package/dist/hitl/approvalHolds.d.ts +16 -1
  51. package/dist/hitl/approvalHolds.js +52 -12
  52. package/dist/hitl/askGateWire.js +1 -0
  53. package/dist/hitl/automaticAnswerVerdict.js +5 -7
  54. package/dist/hitl/decisionConflict.js +4 -3
  55. package/dist/hitl/decisionRefusal.js +19 -12
  56. package/dist/hitl/frameRouter.d.ts +3 -0
  57. package/dist/hitl/frameRouter.js +52 -25
  58. package/dist/hitl/gateLedger.d.ts +0 -5
  59. package/dist/hitl/gateLedger.js +0 -21
  60. package/dist/hitl/hitlBridge.js +18 -4
  61. package/dist/hitl/parkResolver.js +7 -3
  62. package/dist/hitl/replayedApproval.d.ts +2 -3
  63. package/dist/hitl/replayedApproval.js +7 -16
  64. package/dist/hitl/sessionPolicyDeliverable.d.ts +0 -1
  65. package/dist/hitl/sessionPolicyDeliverable.js +15 -17
  66. package/dist/hitl/sessionPolicyWire.d.ts +2 -0
  67. package/dist/hitl/sessionPolicyWire.js +15 -3
  68. package/dist/hitl/standingRows.d.ts +1 -0
  69. package/dist/hitl/standingRows.js +38 -17
  70. package/dist/hitl/suspendedReopen.js +2 -1
  71. package/dist/hitl/toolApprovalWire.d.ts +8 -8
  72. package/dist/hitl/toolApprovalWire.js +50 -24
  73. package/dist/index.d.ts +8 -4
  74. package/dist/index.js +5 -3
  75. package/dist/liveModelCatalog.d.ts +13 -0
  76. package/dist/liveModelCatalog.js +56 -0
  77. package/dist/mcpProbeCapability.d.ts +2 -0
  78. package/dist/mcpProbeCapability.js +3 -2
  79. package/dist/mcpWireCaps.d.ts +1 -0
  80. package/dist/mcpWireCaps.js +4 -1
  81. package/dist/memoryComplianceCapability.d.ts +2 -0
  82. package/dist/memoryComplianceCapability.js +3 -2
  83. package/dist/memoryOriginCapability.d.ts +2 -0
  84. package/dist/memoryOriginCapability.js +3 -2
  85. package/dist/modelIdentityResolvability.js +2 -2
  86. package/dist/noticePresentation.js +2 -2
  87. package/dist/outputStyleSeatCapability.d.ts +2 -0
  88. package/dist/outputStyleSeatCapability.js +0 -1
  89. package/dist/peerLaneCapability.d.ts +2 -0
  90. package/dist/peerLaneCapability.js +3 -2
  91. package/dist/permissionModesCapability.d.ts +2 -0
  92. package/dist/permissionModesCapability.js +0 -1
  93. package/dist/permissionRulesWriteCapability.d.ts +2 -0
  94. package/dist/permissionRulesWriteCapability.js +3 -2
  95. package/dist/permissionsAllowGrantCapability.d.ts +2 -0
  96. package/dist/permissionsAllowGrantCapability.js +4 -2
  97. package/dist/permissionsDeclaration.js +19 -21
  98. package/dist/request/taskRequest.d.ts +1 -4
  99. package/dist/request/taskRequest.js +74 -19
  100. package/dist/resumeRefusalCopy.js +4 -4
  101. package/dist/rewindArchiveCapability.js +5 -0
  102. package/dist/rewindArchiveReading.d.ts +2 -0
  103. package/dist/rewindArchiveReading.js +0 -1
  104. package/dist/runTerminal.d.ts +33 -4
  105. package/dist/runTerminal.js +170 -15
  106. package/dist/sdkWireTransit.d.ts +2 -1
  107. package/dist/sdkWireTransit.js +1 -0
  108. package/dist/sealedKeyCapability.d.ts +2 -0
  109. package/dist/sealedKeyCapability.js +0 -1
  110. package/dist/seatContract.d.ts +7 -4
  111. package/dist/seatContract.js +34 -20
  112. package/dist/sessionPolicyCapability.d.ts +2 -0
  113. package/dist/sessionPolicyCapability.js +3 -2
  114. package/dist/sessionReadRedactionCapability.d.ts +2 -0
  115. package/dist/sessionReadRedactionCapability.js +0 -1
  116. package/dist/sessionSyncFileHistoryCapability.d.ts +2 -0
  117. package/dist/sessionSyncFileHistoryCapability.js +3 -2
  118. package/dist/skillToolListsCapability.d.ts +2 -0
  119. package/dist/skillToolListsCapability.js +3 -2
  120. package/dist/sqlEngineCapability.d.ts +2 -0
  121. package/dist/sqlEngineCapability.js +4 -3
  122. package/dist/steerPriorityCapability.d.ts +2 -0
  123. package/dist/steerPriorityCapability.js +3 -2
  124. package/dist/storePostureCapability.d.ts +2 -0
  125. package/dist/storePostureCapability.js +4 -3
  126. package/dist/toolHistoryBadTurn.js +3 -2
  127. package/dist/toolResult.d.ts +11 -0
  128. package/dist/toolResult.js +53 -0
  129. package/dist/userInvokedSkillsCapability.d.ts +2 -0
  130. package/dist/userInvokedSkillsCapability.js +3 -2
  131. package/dist/webSearchBackendCapability.d.ts +2 -0
  132. package/dist/webSearchBackendCapability.js +3 -2
  133. package/dist/wireErrorTriage.js +58 -34
  134. package/dist/wireFailureShape.d.ts +1 -1
  135. package/dist/wireFailureShape.js +76 -25
  136. package/dist/workflowsJournalCapability.d.ts +2 -0
  137. package/dist/workflowsJournalCapability.js +3 -2
  138. package/dist/writeProtectionCapability.d.ts +2 -0
  139. package/dist/writeProtectionCapability.js +3 -2
  140. package/docs/INTEGRATION-CLIENTS.md +585 -14
  141. package/package.json +4 -4
  142. package/dist/engineRefusedToolName.d.ts +0 -1
  143. package/dist/engineRefusedToolName.js +0 -8
  144. package/dist/engineWordRenames.d.ts +0 -8
  145. package/dist/engineWordRenames.js +0 -13
@@ -1,6 +1,6 @@
1
1
  import { capForDisplay } from './fleetTaskDesc.js';
2
2
  import { engineWireTarget } from './engineWireTarget.js';
3
- import { storeSeatOf, createEngineCapReader } from './engineCapReader.js';
3
+ import { storeSeatOf, createEngineCapReader, unreadableReadingDetail } from './engineCapReader.js';
4
4
  import { projectSqlEngineCapability } from './sqlEngineCapability.js';
5
5
  import { ownDataField } from './ownKey.js';
6
6
  const nonEmpty = (v) => typeof v === 'string' && v !== '';
@@ -44,7 +44,6 @@ function projectStorePostureOf(caps) {
44
44
  const reader = createEngineCapReader({
45
45
  name: 'store',
46
46
  project: projectStorePostureCapability,
47
- makeUnobserved: () => ({ kind: 'unobserved' }),
48
47
  });
49
48
  export function observedStorePosture(baseUrl = engineWireTarget()?.baseUrl) {
50
49
  return reader.observed(baseUrl);
@@ -54,7 +53,7 @@ function presentView(reading) {
54
53
  return undefined;
55
54
  try {
56
55
  const kind = reading.kind;
57
- if (kind === 'not_reported' || kind === 'unobserved')
56
+ if (kind === 'not_reported' || kind === 'unobserved' || kind === 'unreadable')
58
57
  return { kind };
59
58
  if (kind !== 'present')
60
59
  return undefined;
@@ -89,6 +88,8 @@ const word = (v) => capForDisplay(v, WORD_DETAIL_MAX);
89
88
  export function storePostureDoctorDetail(reading) {
90
89
  const unobserved = 'store posture not observed — the engine reports it on /v1/capabilities; this process has no usable capabilities reading cached for it, so whether this deployment persists its state is unknown';
91
90
  const r = presentView(reading);
91
+ if (r?.kind === 'unreadable')
92
+ return unreadableReadingDetail('store posture');
92
93
  if (r?.kind === 'not_reported') {
93
94
  return 'store posture not reported by this engine; this does not say whether this deployment persists its state';
94
95
  }
@@ -1,10 +1,11 @@
1
- import { displayUntrusted } from './displayUntrusted.js';
1
+ import { displayUntrusted, markerSafeCut } from './displayUntrusted.js';
2
2
  const BAD_TURN_PREVIEW_MAX = 60;
3
3
  export function toolHistoryBadTurnSentence(promptText) {
4
4
  const text = typeof promptText === 'string' ? promptText : '';
5
5
  const washed = displayUntrusted(stripDisplayTagBlocks(text), { mark: 'dot' }).replace(/\s+/g, ' ').trim();
6
6
  const points = Array.from(washed);
7
- const preview = points.length > BAD_TURN_PREVIEW_MAX ? `${points.slice(0, BAD_TURN_PREVIEW_MAX).join('')}...` : washed;
7
+ const head = points.length > BAD_TURN_PREVIEW_MAX ? points.slice(0, BAD_TURN_PREVIEW_MAX).join('') : undefined;
8
+ const preview = head === undefined ? washed : `${washed.slice(0, markerSafeCut(washed, head.length))}...`;
8
9
  return preview.length > 0
9
10
  ? `The broken record is in the turn you started with "${preview}"; /rewind has that prompt preselected, so restore the conversation to before it.`
10
11
  : 'The broken record is in the turn /rewind has preselected; restore the conversation to before it.';
@@ -92,6 +92,17 @@ export interface ToolResultBody {
92
92
  degraded?: typeof TOOL_RESULT_DEGRADED_WIRE_NO_OUTPUT;
93
93
  }
94
94
  export declare function degradedToolResultBody(isError: boolean): ToolResultBody;
95
+ export type ToolCardDegradedCause = 'not-executed' | 'error-without-detail' | 'no-result' | 'unrecognised';
96
+ export type ToolCardOutcomeReading = {
97
+ readonly kind: 'normal';
98
+ } | {
99
+ readonly kind: 'degraded';
100
+ readonly cause: ToolCardDegradedCause;
101
+ readonly text: string;
102
+ } | {
103
+ readonly kind: 'unreadable';
104
+ };
105
+ export declare function readToolCardOutcome(record: object | null | undefined): ToolCardOutcomeReading;
95
106
  export declare function wireOutputToBody(toolName: string, output: unknown, isError: boolean, truncated: boolean, flatten: FlattenWireOutput, structured?: unknown, leaderLedger?: boolean): ToolResultBody;
96
107
  export declare function structuredToToolUseResult(structured: unknown, modelText?: string, leaderLedger?: boolean): {
97
108
  toolUseResult: unknown;
@@ -4,6 +4,7 @@ import { parseWorkflowPollEnvelope, projectWorkflowTaskOutput } from './workflow
4
4
  import { asModelFallbackReason } from './engineErrorCodes.js';
5
5
  import { frozenSet } from './frozenSet.js';
6
6
  import { bashExitOf, bashExitReadingFailed } from './bashExitReading.js';
7
+ import { readFrameTrueMark } from './ownKey.js';
7
8
  import { isCoreSemaTaskTerminal } from './terminalStatuses.js';
8
9
  import { CORE_ENGINE_CARD_TYPES } from './generated/engineFactTables.js';
9
10
  export const STRUCTURED_DETAIL_TYPES = frozenSet(CORE_ENGINE_CARD_TYPES);
@@ -276,6 +277,58 @@ export const TOOL_RESULT_DEGRADED_WIRE_NO_OUTPUT = 'wire_carried_no_output';
276
277
  export function degradedToolResultBody(isError) {
277
278
  return { content: '', isError, degraded: TOOL_RESULT_DEGRADED_WIRE_NO_OUTPUT };
278
279
  }
280
+ const TOOL_CARD_DEGRADED_TEXT = {
281
+ 'not-executed': 'This tool call did not run: the engine closed it without executing it.',
282
+ 'error-without-detail': 'This tool call reported an error but returned no details.',
283
+ 'no-result': 'No result was reported for this tool call, so whether it ran and what it did is not shown here — check before running it again.',
284
+ unrecognised: 'This tool call carries a result marker this client does not recognise, so no result is shown for it.',
285
+ };
286
+ const cardDegraded = (cause) => ({ kind: 'degraded', cause, text: TOOL_CARD_DEGRADED_TEXT[cause] });
287
+ function cardOwnData(o, key) {
288
+ const d = Object.getOwnPropertyDescriptor(o, key);
289
+ if (d === undefined)
290
+ return undefined;
291
+ if (!Object.hasOwn(d, 'value'))
292
+ throw new TypeError(`own property "${key}" is an accessor`);
293
+ return d.value;
294
+ }
295
+ const isCardRecordObject = (v) => typeof v === 'object' && v !== null && !Array.isArray(v);
296
+ function toolResultBlockOf(record) {
297
+ const message = cardOwnData(record, 'message');
298
+ if (!isCardRecordObject(message))
299
+ return undefined;
300
+ const content = cardOwnData(message, 'content');
301
+ if (!Array.isArray(content))
302
+ return undefined;
303
+ for (let i = 0; i < content.length; i++) {
304
+ const block = cardOwnData(content, String(i));
305
+ if (isCardRecordObject(block) && cardOwnData(block, 'type') === 'tool_result')
306
+ return block;
307
+ }
308
+ return undefined;
309
+ }
310
+ export function readToolCardOutcome(record) {
311
+ try {
312
+ if (!isCardRecordObject(record))
313
+ return { kind: 'unreadable' };
314
+ const block = toolResultBlockOf(record);
315
+ if (block === undefined)
316
+ return { kind: 'unreadable' };
317
+ if (readFrameTrueMark(record, '_sema_not_executed'))
318
+ return cardDegraded('not-executed');
319
+ const markerDesc = Object.getOwnPropertyDescriptor(record, '_sema_degraded');
320
+ if (markerDesc === undefined)
321
+ return { kind: 'normal' };
322
+ if (!Object.hasOwn(markerDesc, 'value'))
323
+ return { kind: 'unreadable' };
324
+ if (markerDesc.value !== TOOL_RESULT_DEGRADED_WIRE_NO_OUTPUT)
325
+ return cardDegraded('unrecognised');
326
+ return cardDegraded(cardOwnData(block, 'is_error') === true ? 'error-without-detail' : 'no-result');
327
+ }
328
+ catch {
329
+ return { kind: 'unreadable' };
330
+ }
331
+ }
279
332
  export function wireOutputToBody(toolName, output, isError, truncated, flatten, structured, leaderLedger = true) {
280
333
  const text = flatten(output);
281
334
  const name = (toolName || '').toLowerCase();
@@ -1,5 +1,7 @@
1
1
  export type UserInvokedSkillsReading = {
2
2
  kind: 'unobserved';
3
+ } | {
4
+ kind: 'unreadable';
3
5
  } | {
4
6
  kind: 'not_reported';
5
7
  } | {
@@ -1,5 +1,5 @@
1
1
  import { engineWireTarget } from './engineWireTarget.js';
2
- import { createEngineCapReader } from './engineCapReader.js';
2
+ import { createEngineCapReader, unreadableReadingDetail } from './engineCapReader.js';
3
3
  import { ownDataField } from './ownKey.js';
4
4
  export function projectUserInvokedSkillsCapability(caps) {
5
5
  try {
@@ -19,7 +19,6 @@ export function projectUserInvokedSkillsCapability(caps) {
19
19
  const reader = createEngineCapReader({
20
20
  name: 'userInvokedSkills',
21
21
  project: projectUserInvokedSkillsCapability,
22
- makeUnobserved: () => ({ kind: 'unobserved' }),
23
22
  });
24
23
  export function noteEngineCapsForUserInvokedSkills(baseUrl, caps, opts) {
25
24
  reader.note(baseUrl, caps, opts);
@@ -36,6 +35,8 @@ export function userInvokedSkillsAvailable(reading) {
36
35
  }
37
36
  export function userInvokedSkillsDoctorDetail(reading) {
38
37
  switch (reading.kind) {
38
+ case 'unreadable':
39
+ return unreadableReadingDetail('user-invoked skills');
39
40
  case 'unobserved':
40
41
  return 'user-invoked skills not observed — the engine reports it on /v1/capabilities (userInvokedSkills); 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)';
41
42
  case 'not_reported':
@@ -4,6 +4,8 @@ export interface WebSearchBackendCapabilityView {
4
4
  }
5
5
  export type WebSearchBackendReading = {
6
6
  kind: 'unobserved';
7
+ } | {
8
+ kind: 'unreadable';
7
9
  } | {
8
10
  kind: 'not_reported';
9
11
  } | {
@@ -1,6 +1,6 @@
1
1
  import { capForDisplay } from './fleetTaskDesc.js';
2
2
  import { engineWireTarget } from './engineWireTarget.js';
3
- import { createEngineCapReader } from './engineCapReader.js';
3
+ import { createEngineCapReader, unreadableReadingDetail } from './engineCapReader.js';
4
4
  import { ownDataField } from './ownKey.js';
5
5
  export const WEB_SEARCH_BACKEND_NONE = 'none';
6
6
  export function projectWebSearchBackendCapability(caps) {
@@ -28,7 +28,6 @@ export function projectWebSearchBackendCapability(caps) {
28
28
  const reader = createEngineCapReader({
29
29
  name: 'webSearch.backend',
30
30
  project: projectWebSearchBackendCapability,
31
- makeUnobserved: () => ({ kind: 'unobserved' }),
32
31
  });
33
32
  export function noteEngineCapsForWebSearchBackend(baseUrl, caps, opts) {
34
33
  reader.note(baseUrl, caps, opts);
@@ -40,6 +39,8 @@ const WS_DETAIL_MAX = 40;
40
39
  const DEPLOY_ENV = 'WEB_SEARCH_PROVIDER';
41
40
  export function webSearchBackendDoctorDetail(reading) {
42
41
  switch (reading.kind) {
42
+ case 'unreadable':
43
+ return unreadableReadingDetail('deployment default backend');
43
44
  case 'unobserved':
44
45
  return ('deployment default backend not observed — the engine reports it on /v1/capabilities; ' +
45
46
  '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)');
@@ -1,27 +1,51 @@
1
- import { readBlockedBy, readErrorNumber, readErrorString, readErrorStringList } from './wireFailureShape.js';
1
+ import { readBlockedBy, readErrorNumber, readErrorString, readErrorStringList, readThrownSlot, thrownIsInstanceOf, THROWN_SLOT_UNREADABLE, WIRE_FAILURE_UNRENDERABLE_TEXT, } from './wireFailureShape.js';
2
2
  import { capForDisplay, escapeDisplayControlChars } from './fleetTaskDesc.js';
3
3
  import { readOwnDataValue } from './ownKey.js';
4
4
  import { fleetLeaseUnavailableFromError } from './wireRefusalCopy.js';
5
- import { DRAINING_ERROR_CODE, isCorruptSessionCode, RESUME_AT_ERROR_CODE_PREFIX, RESUME_POLICY_FOLD_CODE, RESUME_RETRY_LATER_CODES, RESUME_USAGE_WINDOW_EXHAUSTED, SCENARIO_NOT_ALLOWED_ERROR_CODE, } from './engineErrorCodes.js';
5
+ import { DRAINING_ERROR_CODE, FLEET_LEASE_UNAVAILABLE, isCorruptSessionCode, RESUME_AT_ERROR_CODE_PREFIX, RESUME_POLICY_FOLD_CODE, RESUME_RETRY_LATER_CODES, RESUME_USAGE_WINDOW_EXHAUSTED, SCENARIO_NOT_ALLOWED_ERROR_CODE, } from './engineErrorCodes.js';
6
6
  export const WIRE_NETWORK_ERROR_PATTERN = /fetch failed|ECONNREFUSED|ECONNRESET|ETIMEDOUT|EAI_AGAIN|ENOTFOUND|EHOSTUNREACH|ENETUNREACH|EPIPE|socket hang up|UND_ERR|\bterminated\b|\bother side closed\b/i;
7
- function wireErrorDetail(err) {
8
- const e = err;
9
- const cause = e?.cause;
10
- return ((typeof cause?.message === 'string' && cause.message.length > 0 && cause.message) ||
11
- (typeof e?.message === 'string' && e.message.length > 0 && e.message) ||
12
- String(err));
7
+ function readTurnErrorSlots(err) {
8
+ if (err === null || err === undefined)
9
+ return { status: undefined, errorCode: undefined, message: undefined, cause: undefined, name: undefined };
10
+ return {
11
+ status: readThrownSlot(err, 'status', 'data'),
12
+ errorCode: readThrownSlot(err, 'errorCode', 'data'),
13
+ message: readThrownSlot(err, 'message'),
14
+ cause: readThrownSlot(err, 'cause'),
15
+ name: typeof err === 'object' ? readThrownSlot(err, 'name') : undefined,
16
+ };
17
+ }
18
+ function renderedText(err) {
19
+ try {
20
+ return String(err);
21
+ }
22
+ catch {
23
+ return WIRE_FAILURE_UNRENDERABLE_TEXT;
24
+ }
25
+ }
26
+ function wireErrorDetailOf(slots, err) {
27
+ const causeMessage = slots.cause === undefined || slots.cause === THROWN_SLOT_UNREADABLE ? undefined : readThrownSlot(slots.cause, 'message');
28
+ return ((typeof causeMessage === 'string' && causeMessage.length > 0 && causeMessage) ||
29
+ (typeof slots.message === 'string' && slots.message.length > 0 && slots.message) ||
30
+ renderedText(err));
31
+ }
32
+ function isTransportShape(slots, detail) {
33
+ if (typeof slots.status === 'number' || slots.status === THROWN_SLOT_UNREADABLE)
34
+ return false;
35
+ return (slots.cause !== undefined && slots.cause !== THROWN_SLOT_UNREADABLE) || WIRE_NETWORK_ERROR_PATTERN.test(detail());
13
36
  }
14
37
  export function classifyTurnWireError(err) {
15
- const e = err;
16
- if (typeof e?.status === 'number') {
17
- const errorCode = typeof e.errorCode === 'string' && e.errorCode.length > 0 ? e.errorCode : undefined;
18
- const message = typeof e.message === 'string' && e.message.length > 0 ? e.message : String(err);
19
- const storedRowWhere = corruptStoredRowWhere(err);
20
- const sessionUnreadable = isCorruptSessionCode(effectiveWireErrorCode(err));
21
- const leaseUnavailable = fleetLeaseUnavailableFromError(err) !== null;
38
+ const slots = readTurnErrorSlots(err);
39
+ if (typeof slots.status === 'number') {
40
+ const errorCode = typeof slots.errorCode === 'string' && slots.errorCode.length > 0 ? slots.errorCode : undefined;
41
+ const message = typeof slots.message === 'string' && slots.message.length > 0 ? slots.message : renderedText(err);
42
+ const effectiveCode = typeof err === 'object' && err !== null ? foldedWireErrorCode(err, errorCode) : undefined;
43
+ const storedRowWhere = typeof err === 'object' && err !== null ? storedRowWhereOf(err, effectiveCode) : undefined;
44
+ const sessionUnreadable = isCorruptSessionCode(effectiveCode);
45
+ const leaseUnavailable = slots.errorCode === FLEET_LEASE_UNAVAILABLE && fleetLeaseUnavailableFromError(err) !== null;
22
46
  return {
23
47
  kind: 'http',
24
- status: e.status,
48
+ status: slots.status,
25
49
  ...(errorCode !== undefined ? { errorCode } : {}),
26
50
  message,
27
51
  ...(storedRowWhere !== undefined ? { storedRowWhere } : {}),
@@ -29,27 +53,21 @@ export function classifyTurnWireError(err) {
29
53
  ...(leaseUnavailable ? { leaseUnavailable: true } : {}),
30
54
  };
31
55
  }
32
- const errName = typeof err === 'object' && err !== null && typeof err.name === 'string'
33
- ? err.name
34
- : undefined;
35
- if (errName === 'StreamEndedWithoutTerminalError') {
56
+ if (slots.status !== THROWN_SLOT_UNREADABLE && slots.name === 'StreamEndedWithoutTerminalError') {
36
57
  return { kind: 'stream-ended-without-terminal' };
37
58
  }
38
- const detail = wireErrorDetail(err);
39
- const isNetwork = e?.cause !== undefined || WIRE_NETWORK_ERROR_PATTERN.test(detail);
40
- if (isNetwork)
59
+ const detail = wireErrorDetailOf(slots, err);
60
+ if (isTransportShape(slots, () => detail))
41
61
  return { kind: 'transport', detail };
42
- return { kind: 'internal', name: err instanceof Error ? err.name : typeof err, detail };
62
+ const name = thrownIsInstanceOf(err, Error) && slots.name !== THROWN_SLOT_UNREADABLE ? slots.name : typeof err;
63
+ return { kind: 'internal', name, detail };
43
64
  }
44
65
  export function isWireTransportError(err) {
45
- const e = err;
46
- if (typeof e?.status === 'number')
47
- return false;
48
- return e?.cause !== undefined || WIRE_NETWORK_ERROR_PATTERN.test(wireErrorDetail(err));
66
+ const slots = readTurnErrorSlots(err);
67
+ return isTransportShape(slots, () => wireErrorDetailOf(slots, err));
49
68
  }
50
69
  export function isPreStreamDrainingReject(err) {
51
- const e = err;
52
- return typeof e?.status === 'number' && e.status === 503 && e.errorCode === DRAINING_ERROR_CODE;
70
+ return readThrownSlot(err, 'status', 'data') === 503 && readThrownSlot(err, 'errorCode', 'data') === DRAINING_ERROR_CODE;
53
71
  }
54
72
  export function effectiveWireErrorCode(err) {
55
73
  if (typeof err !== 'object' || err === null)
@@ -62,13 +80,20 @@ export function effectiveWireErrorCode(err) {
62
80
  outerRaw = undefined;
63
81
  }
64
82
  const outer = typeof outerRaw === 'string' && outerRaw.length > 0 ? outerRaw : undefined;
83
+ return foldedWireErrorCode(err, outer);
84
+ }
85
+ function foldedWireErrorCode(err, outer) {
65
86
  if (outer !== RESUME_POLICY_FOLD_CODE)
66
87
  return outer;
67
88
  const inner = readBlockedBy(err);
68
89
  return inner.kind === 'named' ? inner.code : outer;
69
90
  }
70
91
  export function corruptStoredRowWhere(err) {
71
- if (effectiveWireErrorCode(err) !== 'corrupt')
92
+ const code = effectiveWireErrorCode(err);
93
+ return typeof err === 'object' && err !== null ? storedRowWhereOf(err, code) : undefined;
94
+ }
95
+ function storedRowWhereOf(err, effectiveCode) {
96
+ if (effectiveCode !== 'corrupt')
72
97
  return undefined;
73
98
  const where = readErrorString(err, 'where');
74
99
  return where !== undefined && where.trim().length > 0 ? where : undefined;
@@ -81,7 +106,7 @@ export function isResumeAtRejection(err) {
81
106
  return code !== undefined && code.startsWith(RESUME_AT_ERROR_CODE_PREFIX);
82
107
  }
83
108
  export function drainingRetryDelayMs(err, attempt, opts) {
84
- const ra = err?.retryAfterMs;
109
+ const ra = readThrownSlot(err, 'retryAfterMs', 'data');
85
110
  if (typeof ra === 'number' && Number.isFinite(ra) && ra >= 0) {
86
111
  return Math.min(ra, opts?.retryAfterCapMs ?? 15_000);
87
112
  }
@@ -183,8 +208,7 @@ export function scenarioNotAllowedContent(detail, requestedScenario, surface) {
183
208
  export function resumeRetryLaterFromError(err) {
184
209
  if (typeof err !== 'object' || err === null)
185
210
  return null;
186
- const e = err;
187
- const code = e.errorCode;
211
+ const code = readThrownSlot(err, 'errorCode', 'data');
188
212
  if (typeof code !== 'string' || !RESUME_RETRY_LATER_CODES.includes(code))
189
213
  return null;
190
214
  const sec = readErrorNumber(err, 'retryAfterSec');
@@ -10,7 +10,7 @@ interface WireFailureShape {
10
10
  message: string;
11
11
  }
12
12
  export declare const THROWN_SLOT_UNREADABLE: unique symbol;
13
- export declare function readThrownSlot(o: unknown, key: string, own?: boolean): unknown;
13
+ export declare function readThrownSlot(o: unknown, key: string, own?: boolean | 'data'): unknown;
14
14
  export declare function thrownIsInstanceOf<C extends abstract new (...args: never[]) => unknown>(e: unknown, cls: C): e is InstanceType<C>;
15
15
  export type ThrownExtraReading = {
16
16
  readonly state: 'object';
@@ -1,6 +1,12 @@
1
+ import { guardedRead, ownDataField, readOwnDataValue } from './ownKey.js';
1
2
  export const THROWN_SLOT_UNREADABLE = Symbol('thrown-slot-unreadable');
2
3
  export function readThrownSlot(o, key, own = false) {
3
4
  try {
5
+ if (own === 'data') {
6
+ if (o === null || o === undefined)
7
+ return THROWN_SLOT_UNREADABLE;
8
+ return typeof o === 'object' || typeof o === 'function' ? ownDataField(o, key) : undefined;
9
+ }
4
10
  if (own && !Object.hasOwn(o, key))
5
11
  return undefined;
6
12
  return o[key];
@@ -21,12 +27,75 @@ export function thrownIsInstanceOf(e, cls) {
21
27
  return false;
22
28
  }
23
29
  }
30
+ const EXTRA_KEY = 'extra';
31
+ const EXTRA_CHAIN_DEPTH_MAX = 64;
32
+ function extraSlotOf(o) {
33
+ let node = o;
34
+ for (let depth = 0; node !== null; depth++) {
35
+ if (depth > EXTRA_CHAIN_DEPTH_MAX)
36
+ throw new RangeError('prototype chain too deep to read');
37
+ const d = Object.getOwnPropertyDescriptor(node, EXTRA_KEY);
38
+ if (d !== undefined) {
39
+ const isData = Object.hasOwn(d, 'value');
40
+ if (node === o)
41
+ return isData ? { kind: 'own-data', value: d.value } : { kind: 'own-accessor' };
42
+ return !isData && typeof d.get === 'function' && isSdkErrorClassPrototype(node) ? { kind: 'sdk-class' } : { kind: 'none' };
43
+ }
44
+ node = Object.getPrototypeOf(node);
45
+ }
46
+ return { kind: 'none' };
47
+ }
48
+ function isSdkErrorClassPrototype(holder) {
49
+ if (holder === Object.prototype || !isClassPrototype(holder))
50
+ return false;
51
+ let node = Object.getPrototypeOf(holder);
52
+ for (let depth = 0; node !== null; depth++) {
53
+ if (depth > EXTRA_CHAIN_DEPTH_MAX)
54
+ throw new RangeError('prototype chain too deep to read');
55
+ if (isBuiltinErrorPrototype(node))
56
+ return true;
57
+ node = Object.getPrototypeOf(node);
58
+ }
59
+ return false;
60
+ }
61
+ function classConstructorOf(node) {
62
+ const ctor = Object.getOwnPropertyDescriptor(node, 'constructor');
63
+ if (ctor === undefined || !Object.hasOwn(ctor, 'value') || typeof ctor.value !== 'function')
64
+ return undefined;
65
+ const fn = ctor.value;
66
+ const p = Object.getOwnPropertyDescriptor(fn, 'prototype');
67
+ return p !== undefined && Object.hasOwn(p, 'value') && p.value === node ? fn : undefined;
68
+ }
69
+ function isClassPrototype(node) {
70
+ return classConstructorOf(node) !== undefined;
71
+ }
72
+ const BUILTIN_ERROR_SOURCE = /^function Error\(\)\s*\{\s*\[native code\]\s*\}$/;
73
+ function isBuiltinErrorPrototype(node) {
74
+ const fn = classConstructorOf(node);
75
+ if (fn === undefined)
76
+ return false;
77
+ const n = Object.getOwnPropertyDescriptor(fn, 'name');
78
+ if (n === undefined || !Object.hasOwn(n, 'value') || n.value !== 'Error')
79
+ return false;
80
+ if (!BUILTIN_ERROR_SOURCE.test(Function.prototype.toString.call(fn)))
81
+ return false;
82
+ return ['message', 'name', 'toString'].every((k) => Object.getOwnPropertyDescriptor(node, k) !== undefined);
83
+ }
24
84
  export function readThrownExtra(o) {
25
- if (o === null || o === undefined)
85
+ if (o === null || o === undefined || (typeof o !== 'object' && typeof o !== 'function'))
26
86
  return { state: 'absent' };
27
- const slot = readThrownSlot(o, 'extra');
28
- if (slot === THROWN_SLOT_UNREADABLE)
87
+ let slot;
88
+ try {
89
+ const at = extraSlotOf(o);
90
+ if (at.kind === 'own-accessor')
91
+ return { state: 'unreadable' };
92
+ if (at.kind === 'none')
93
+ return { state: 'absent' };
94
+ slot = at.kind === 'own-data' ? at.value : Reflect.get(o, EXTRA_KEY);
95
+ }
96
+ catch {
29
97
  return { state: 'unreadable' };
98
+ }
30
99
  try {
31
100
  if (typeof slot !== 'object' || slot === null || Array.isArray(slot))
32
101
  return { state: 'absent' };
@@ -38,27 +107,15 @@ export function readThrownExtra(o) {
38
107
  }
39
108
  function readErrorSlot(obj, key, accept) {
40
109
  try {
41
- const o = obj;
42
- let top;
43
- try {
44
- top = o[key];
45
- }
46
- catch {
47
- top = undefined;
48
- }
110
+ const topRaw = readThrownSlot(obj, key, 'data');
111
+ const top = topRaw === THROWN_SLOT_UNREADABLE ? undefined : topRaw;
49
112
  if (accept(top))
50
113
  return top;
51
114
  const reading = readThrownExtra(obj);
52
115
  if (reading.state !== 'object')
53
116
  return undefined;
54
117
  const extra = reading.value;
55
- let fromExtra;
56
- try {
57
- fromExtra = Object.hasOwn(extra, key) ? extra[key] : undefined;
58
- }
59
- catch {
60
- fromExtra = undefined;
61
- }
118
+ const fromExtra = guardedRead(() => readOwnDataValue(extra, key));
62
119
  return accept(fromExtra) ? fromExtra : undefined;
63
120
  }
64
121
  catch {
@@ -217,13 +274,7 @@ export function readBlockedBy(o) {
217
274
  }
218
275
  export function readRefusalField(o) {
219
276
  const str = (rec) => {
220
- let v;
221
- try {
222
- v = rec.field;
223
- }
224
- catch {
225
- return undefined;
226
- }
277
+ const v = guardedRead(() => readOwnDataValue(rec, 'field'));
227
278
  return typeof v === 'string' && v !== '' ? v : undefined;
228
279
  };
229
280
  const reading = readThrownExtra(o);
@@ -1,5 +1,7 @@
1
1
  export type WorkflowsJournalReading = {
2
2
  kind: 'unobserved';
3
+ } | {
4
+ kind: 'unreadable';
3
5
  } | {
4
6
  kind: 'not_reported';
5
7
  } | {
@@ -1,5 +1,5 @@
1
1
  import { engineWireTarget } from './engineWireTarget.js';
2
- import { createEngineCapReader } from './engineCapReader.js';
2
+ import { createEngineCapReader, unreadableReadingDetail } from './engineCapReader.js';
3
3
  import { ownDataField } from './ownKey.js';
4
4
  export function projectWorkflowsJournalCapability(caps) {
5
5
  try {
@@ -19,7 +19,6 @@ export function projectWorkflowsJournalCapability(caps) {
19
19
  const reader = createEngineCapReader({
20
20
  name: 'workflowsJournal',
21
21
  project: projectWorkflowsJournalCapability,
22
- makeUnobserved: () => ({ kind: 'unobserved' }),
23
22
  });
24
23
  export function noteEngineCapsForWorkflowsJournal(baseUrl, caps, opts) {
25
24
  reader.note(baseUrl, caps, opts);
@@ -36,6 +35,8 @@ export function workflowsJournalAvailable(reading) {
36
35
  }
37
36
  export function workflowsJournalDoctorDetail(reading) {
38
37
  switch (reading.kind) {
38
+ case 'unreadable':
39
+ return unreadableReadingDetail('workflow journal');
39
40
  case 'unobserved':
40
41
  return 'workflow journal not observed — the engine reports it on /v1/capabilities (workflowsJournal); 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)';
41
42
  case 'not_reported':
@@ -3,6 +3,8 @@ export interface WriteProtectionCapabilityView extends Pick<WriteProtectionCapab
3
3
  }
4
4
  export type WriteProtectionReading = {
5
5
  kind: 'unobserved';
6
+ } | {
7
+ kind: 'unreadable';
6
8
  } | {
7
9
  kind: 'not_reported';
8
10
  } | {
@@ -1,6 +1,6 @@
1
1
  import { capForDisplay } from './fleetTaskDesc.js';
2
2
  import { engineWireTarget } from './engineWireTarget.js';
3
- import { createEngineCapReader } from './engineCapReader.js';
3
+ import { createEngineCapReader, unreadableReadingDetail } from './engineCapReader.js';
4
4
  import { ownDataField } from './ownKey.js';
5
5
  export function projectWriteProtectionCapability(caps) {
6
6
  try {
@@ -65,7 +65,6 @@ export function projectWriteProtectionPosture(wiring) {
65
65
  const reader = createEngineCapReader({
66
66
  name: 'writeProtection',
67
67
  project: projectWriteProtectionCapability,
68
- makeUnobserved: () => ({ kind: 'unobserved' }),
69
68
  });
70
69
  export function noteEngineCapsForWriteProtection(baseUrl, caps, opts) {
71
70
  reader.note(baseUrl, caps, opts);
@@ -76,6 +75,8 @@ export function observedWriteProtection(baseUrl = engineWireTarget()?.baseUrl) {
76
75
  const WP_DETAIL_MAX = 40;
77
76
  export function writeProtectionDoctorDetail(reading) {
78
77
  switch (reading.kind) {
78
+ case 'unreadable':
79
+ return unreadableReadingDetail();
79
80
  case 'unobserved':
80
81
  return ('not observed — the engine reports it on /v1/capabilities; this process has no usable ' +
81
82
  '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)');