@sema-agent/client-core 0.95.0 → 0.97.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 (233) hide show
  1. package/CHANGELOG.md +269 -0
  2. package/README.md +61 -31
  3. package/dist/adapt/arms.js +7 -1
  4. package/dist/adapt/toolCards.d.ts +1 -0
  5. package/dist/adapt/toolCards.js +16 -3
  6. package/dist/adapt/wireShapes.js +2 -16
  7. package/dist/adapter/activeRunSelfHeal.d.ts +4 -2
  8. package/dist/adapter/activeRunSelfHeal.js +32 -6
  9. package/dist/adapter/downstream/eventToSdkMessage.js +11 -3
  10. package/dist/adapter/downstream/terminalToSdkResult.js +14 -11
  11. package/dist/adapter/runStream.js +30 -47
  12. package/dist/agentSession/backgroundView.js +2 -15
  13. package/dist/agentSession/engineAgentRegistryRead.js +5 -4
  14. package/dist/agentSession/engineSessionBackgroundStop.js +22 -15
  15. package/dist/agentsWireCaps.d.ts +1 -1
  16. package/dist/agentsWireCaps.js +29 -12
  17. package/dist/approvalDecidedByCapability.d.ts +2 -0
  18. package/dist/approvalDecidedByCapability.js +0 -1
  19. package/dist/approvalsStreamLiveCapability.d.ts +2 -0
  20. package/dist/approvalsStreamLiveCapability.js +3 -2
  21. package/dist/attachmentSeatCapability.d.ts +2 -0
  22. package/dist/attachmentSeatCapability.js +0 -1
  23. package/dist/callerCwdCapability.d.ts +2 -4
  24. package/dist/callerCwdCapability.js +0 -7
  25. package/dist/centerWiringCapability.d.ts +2 -4
  26. package/dist/centerWiringCapability.js +4 -9
  27. package/dist/classifierVerdictWire.js +4 -16
  28. package/dist/clientSlice.js +1 -1
  29. package/dist/cloudConfigWireCaps.d.ts +4 -4
  30. package/dist/cloudConfigWireCaps.js +241 -85
  31. package/dist/coreValuePorts.d.ts +11 -7
  32. package/dist/coreValuePorts.js +5 -8
  33. package/dist/credentialProvenance.d.ts +28 -0
  34. package/dist/credentialProvenance.js +76 -0
  35. package/dist/decideFailureNote.js +3 -1
  36. package/dist/decideReceipt.js +7 -10
  37. package/dist/declared/supportFloorDeclared.js +3 -3
  38. package/dist/deviceExecutorManagementCapability.d.ts +2 -0
  39. package/dist/deviceExecutorManagementCapability.js +3 -2
  40. package/dist/displayUntrusted.d.ts +10 -3
  41. package/dist/displayUntrusted.js +371 -60
  42. package/dist/engineCapReader.d.ts +8 -2
  43. package/dist/engineCapReader.js +15 -7
  44. package/dist/engineCapsCache.d.ts +17 -3
  45. package/dist/engineCapsCache.js +268 -43
  46. package/dist/engineDirectory.d.ts +79 -0
  47. package/dist/engineDirectory.js +186 -0
  48. package/dist/engineErrorCodes.d.ts +17 -1
  49. package/dist/engineErrorCodes.js +46 -16
  50. package/dist/engineNoticeCodes.d.ts +17 -0
  51. package/dist/engineNoticeCodes.js +54 -1
  52. package/dist/executionLaneCapability.d.ts +2 -0
  53. package/dist/executionLaneCapability.js +3 -2
  54. package/dist/fileHistoryCaptureCapability.d.ts +16 -0
  55. package/dist/fileHistoryCaptureCapability.js +98 -2
  56. package/dist/fileHistoryLegNotice.js +4 -0
  57. package/dist/fleet/bgSubagentRow.d.ts +15 -0
  58. package/dist/fleet/bgSubagentRow.js +67 -0
  59. package/dist/fleet/fleetLedger.d.ts +1 -0
  60. package/dist/fleet/fleetLedger.js +164 -126
  61. package/dist/fleet/fleetProjection.d.ts +1 -0
  62. package/dist/fleet/fleetProjection.js +10 -3
  63. package/dist/fleetTaskDesc.js +4 -17
  64. package/dist/gateOutcome.d.ts +12 -1
  65. package/dist/gateOutcome.js +56 -1
  66. package/dist/gateVocabulary.d.ts +2 -2
  67. package/dist/gateVocabulary.js +4 -3
  68. package/dist/generated/engineAskFaceTables.js +1 -1
  69. package/dist/generated/engineFactTables.d.ts +5 -3
  70. package/dist/generated/engineFactTables.js +17 -4
  71. package/dist/generated/engineNoticeTables.js +12 -3
  72. package/dist/generated/sdkFactTables.d.ts +2 -0
  73. package/dist/generated/sdkFactTables.js +7 -0
  74. package/dist/generated/settingsSchemaFns.d.ts +3 -0
  75. package/dist/generated/settingsSchemaFns.js +53 -0
  76. package/dist/generated/toolNameTables.d.ts +1 -1
  77. package/dist/generated/toolNameTables.js +1 -42
  78. package/dist/hitl/approvalDecisionNoteAudit.js +2 -2
  79. package/dist/hitl/approvalEndingCause.d.ts +2 -0
  80. package/dist/hitl/approvalEndingCause.js +26 -21
  81. package/dist/hitl/approvalHolds.d.ts +16 -1
  82. package/dist/hitl/approvalHolds.js +52 -12
  83. package/dist/hitl/askGateWire.js +1 -0
  84. package/dist/hitl/askParkRowRouting.js +1 -1
  85. package/dist/hitl/automaticAnswerVerdict.d.ts +1 -1
  86. package/dist/hitl/automaticAnswerVerdict.js +13 -10
  87. package/dist/hitl/decisionConflict.js +4 -5
  88. package/dist/hitl/decisionRefusal.d.ts +8 -0
  89. package/dist/hitl/decisionRefusal.js +55 -14
  90. package/dist/hitl/frameRouter.d.ts +3 -1
  91. package/dist/hitl/frameRouter.js +58 -39
  92. package/dist/hitl/gateLedger.d.ts +0 -5
  93. package/dist/hitl/gateLedger.js +0 -21
  94. package/dist/hitl/hitlBridge.d.ts +6 -2
  95. package/dist/hitl/hitlBridge.js +46 -11
  96. package/dist/hitl/localAllowRule.d.ts +1 -0
  97. package/dist/hitl/localAllowRule.js +2 -2
  98. package/dist/hitl/noAllowCause.d.ts +2 -1
  99. package/dist/hitl/noAllowCause.js +3 -2
  100. package/dist/hitl/parkResolver.d.ts +1 -0
  101. package/dist/hitl/parkResolver.js +14 -56
  102. package/dist/hitl/parkRowBirthWait.d.ts +1 -0
  103. package/dist/hitl/parkRowBirthWait.js +2 -2
  104. package/dist/hitl/planReviewWire.d.ts +1 -0
  105. package/dist/hitl/planReviewWire.js +98 -20
  106. package/dist/hitl/replayedApproval.d.ts +3 -3
  107. package/dist/hitl/replayedApproval.js +21 -16
  108. package/dist/hitl/sessionPolicyDeliverable.d.ts +0 -1
  109. package/dist/hitl/sessionPolicyDeliverable.js +17 -17
  110. package/dist/hitl/sessionPolicyWire.d.ts +2 -0
  111. package/dist/hitl/sessionPolicyWire.js +15 -3
  112. package/dist/hitl/standingRows.d.ts +19 -0
  113. package/dist/hitl/standingRows.js +148 -0
  114. package/dist/hitl/suspendedReopen.js +2 -1
  115. package/dist/hitl/toolApprovalWire.d.ts +22 -10
  116. package/dist/hitl/toolApprovalWire.js +286 -47
  117. package/dist/hookMatcherVerdict.d.ts +1 -9
  118. package/dist/hookMatcherVerdict.js +21 -61
  119. package/dist/hooksWireCaps.js +2 -2
  120. package/dist/hostCallbackGuard.d.ts +1 -0
  121. package/dist/hostCallbackGuard.js +6 -0
  122. package/dist/index.d.ts +26 -12
  123. package/dist/index.js +20 -10
  124. package/dist/liveModelCatalog.d.ts +13 -0
  125. package/dist/liveModelCatalog.js +56 -0
  126. package/dist/mcpProbeCapability.d.ts +2 -4
  127. package/dist/mcpProbeCapability.js +3 -8
  128. package/dist/mcpWireCaps.d.ts +1 -0
  129. package/dist/mcpWireCaps.js +4 -1
  130. package/dist/memoryComplianceCapability.d.ts +2 -4
  131. package/dist/memoryComplianceCapability.js +3 -8
  132. package/dist/memoryOriginCapability.d.ts +2 -4
  133. package/dist/memoryOriginCapability.js +3 -8
  134. package/dist/memorySpecWire.js +2 -2
  135. package/dist/modelIdentityResolvability.d.ts +2 -2
  136. package/dist/modelIdentityResolvability.js +14 -5
  137. package/dist/noticePresentation.d.ts +68 -0
  138. package/dist/noticePresentation.js +247 -0
  139. package/dist/outputStyleSeatCapability.d.ts +2 -1
  140. package/dist/outputStyleSeatCapability.js +0 -4
  141. package/dist/ownKey.d.ts +2 -0
  142. package/dist/ownKey.js +18 -0
  143. package/dist/peerFrames.js +13 -9
  144. package/dist/peerLaneCapability.d.ts +2 -0
  145. package/dist/peerLaneCapability.js +3 -2
  146. package/dist/permissionModesCapability.d.ts +2 -4
  147. package/dist/permissionModesCapability.js +0 -7
  148. package/dist/permissionRuleIssue.js +0 -3
  149. package/dist/permissionRulesWriteCapability.d.ts +2 -0
  150. package/dist/permissionRulesWriteCapability.js +3 -2
  151. package/dist/permissionsAllowGrantCapability.d.ts +2 -0
  152. package/dist/permissionsAllowGrantCapability.js +4 -2
  153. package/dist/permissionsDeclaration.d.ts +2 -0
  154. package/dist/permissionsDeclaration.js +72 -59
  155. package/dist/printPermissionOutcome.d.ts +12 -0
  156. package/dist/printPermissionOutcome.js +50 -0
  157. package/dist/printToolResultFrame.d.ts +1 -0
  158. package/dist/printToolResultFrame.js +5 -9
  159. package/dist/promptBlockedCopy.d.ts +5 -0
  160. package/dist/promptBlockedCopy.js +35 -0
  161. package/dist/protocolSegment.d.ts +9 -6
  162. package/dist/protocolSegment.js +31 -21
  163. package/dist/providerRejection.d.ts +4 -0
  164. package/dist/providerRejection.js +75 -14
  165. package/dist/replayBody.d.ts +12 -0
  166. package/dist/replayBody.js +25 -0
  167. package/dist/request/taskRequest.d.ts +1 -4
  168. package/dist/request/taskRequest.js +74 -19
  169. package/dist/resumeRefusalCopy.js +9 -25
  170. package/dist/retryStatus.d.ts +9 -1
  171. package/dist/retryStatus.js +9 -2
  172. package/dist/rewindArchiveCapability.d.ts +3 -13
  173. package/dist/rewindArchiveCapability.js +12 -58
  174. package/dist/rewindArchiveReading.d.ts +17 -0
  175. package/dist/rewindArchiveReading.js +55 -0
  176. package/dist/ruleCompileVerdict.d.ts +9 -1
  177. package/dist/ruleCompileVerdict.js +29 -4
  178. package/dist/runTerminal.d.ts +48 -5
  179. package/dist/runTerminal.js +215 -12
  180. package/dist/sandboxWire.js +13 -0
  181. package/dist/sdkWireTransit.d.ts +2 -1
  182. package/dist/sdkWireTransit.js +1 -0
  183. package/dist/sealedKeyCapability.d.ts +2 -4
  184. package/dist/sealedKeyCapability.js +0 -7
  185. package/dist/seam.js +4 -2
  186. package/dist/seatContract.d.ts +76 -11
  187. package/dist/seatContract.js +222 -27
  188. package/dist/sessionPolicyCapability.d.ts +2 -0
  189. package/dist/sessionPolicyCapability.js +3 -2
  190. package/dist/sessionReadRedactionCapability.d.ts +2 -4
  191. package/dist/sessionReadRedactionCapability.js +0 -7
  192. package/dist/sessionSyncFileHistory.d.ts +4 -0
  193. package/dist/sessionSyncFileHistory.js +66 -0
  194. package/dist/sessionSyncFileHistoryCapability.d.ts +2 -1
  195. package/dist/sessionSyncFileHistoryCapability.js +3 -5
  196. package/dist/skillToolListsCapability.d.ts +2 -1
  197. package/dist/skillToolListsCapability.js +3 -5
  198. package/dist/sqlEngineCapability.d.ts +2 -0
  199. package/dist/sqlEngineCapability.js +4 -3
  200. package/dist/steerPriorityCapability.d.ts +2 -1
  201. package/dist/steerPriorityCapability.js +3 -5
  202. package/dist/storePostureCapability.d.ts +2 -4
  203. package/dist/storePostureCapability.js +4 -9
  204. package/dist/subagent/engineSubagentSteer.js +7 -5
  205. package/dist/subagentContentStore.js +4 -15
  206. package/dist/supportFloor.d.ts +1 -0
  207. package/dist/supportFloor.js +13 -9
  208. package/dist/systemReminderTag.d.ts +1 -0
  209. package/dist/systemReminderTag.js +8 -0
  210. package/dist/toolHistoryBadTurn.js +3 -2
  211. package/dist/toolHistoryMismatch.d.ts +0 -3
  212. package/dist/toolHistoryMismatch.js +3 -7
  213. package/dist/toolResult.d.ts +12 -1
  214. package/dist/toolResult.js +55 -1
  215. package/dist/toolResultContent.d.ts +2 -0
  216. package/dist/toolResultContent.js +63 -0
  217. package/dist/usageAnalytics.js +40 -16
  218. package/dist/userInvokedSkillsCapability.d.ts +2 -1
  219. package/dist/userInvokedSkillsCapability.js +3 -5
  220. package/dist/webSearchBackendCapability.d.ts +2 -0
  221. package/dist/webSearchBackendCapability.js +3 -2
  222. package/dist/wireErrorTriage.d.ts +2 -0
  223. package/dist/wireErrorTriage.js +91 -38
  224. package/dist/wireFailureShape.d.ts +20 -3
  225. package/dist/wireFailureShape.js +128 -72
  226. package/dist/workflowsJournalCapability.d.ts +2 -0
  227. package/dist/workflowsJournalCapability.js +3 -2
  228. package/dist/writeProtectionCapability.d.ts +2 -0
  229. package/dist/writeProtectionCapability.js +3 -2
  230. package/docs/INTEGRATION-CLIENTS.md +1784 -20
  231. package/package.json +5 -5
  232. package/dist/engineRefusedToolName.d.ts +0 -1
  233. package/dist/engineRefusedToolName.js +0 -8
@@ -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();
@@ -355,8 +408,9 @@ export function wireOutputToBody(toolName, output, isError, truncated, flatten,
355
408
  const body = truncated ? `${text}\n…(truncated)` : text;
356
409
  const parsed = parseModelFacingTaskOutput(text);
357
410
  const wrap = (task) => ({
358
- content: { retrieval_status: 'success', task },
411
+ content: body,
359
412
  isError,
413
+ toolUseResult: { retrieval_status: 'success', task },
360
414
  });
361
415
  if (parsed.kind === 'agent') {
362
416
  return wrap({
@@ -0,0 +1,2 @@
1
+ export declare function toolResultBlocksOf(output: unknown, truncated: boolean): unknown[] | undefined;
2
+ export declare function toolEndOutputText(output: unknown): string | undefined;
@@ -0,0 +1,63 @@
1
+ const IMAGE_MEDIA_TYPES = Object.freeze(['image/jpeg', 'image/png', 'image/gif', 'image/webp']);
2
+ const OMITTED_CONTENT_NOTE = '[unsupported content omitted]';
3
+ const IMAGE_TEXT_PLACEHOLDER = '[image]';
4
+ function blockOf(raw) {
5
+ if (raw === null || typeof raw !== 'object' || Array.isArray(raw))
6
+ return null;
7
+ const b = raw;
8
+ if (b.type === 'text')
9
+ return typeof b.text === 'string' ? { type: 'text', text: b.text } : null;
10
+ if (b.type !== 'image')
11
+ return null;
12
+ const data = b.data;
13
+ const mediaType = b.mimeType;
14
+ if (typeof data !== 'string')
15
+ return null;
16
+ if (typeof mediaType !== 'string' || !IMAGE_MEDIA_TYPES.includes(mediaType))
17
+ return null;
18
+ return { type: 'image', source: { type: 'base64', media_type: mediaType, data } };
19
+ }
20
+ const TRUNCATED_NOTE = '…(truncated)';
21
+ function toolResultContentOf(output) {
22
+ if (typeof output === 'string')
23
+ return output;
24
+ if (!Array.isArray(output))
25
+ return undefined;
26
+ const blocks = [];
27
+ let omitted = 0;
28
+ let images = 0;
29
+ for (const raw of output) {
30
+ const block = blockOf(raw);
31
+ if (block === null)
32
+ omitted++;
33
+ else {
34
+ if (block.type === 'image')
35
+ images++;
36
+ blocks.push(block);
37
+ }
38
+ }
39
+ if (images === 0 && omitted === 0)
40
+ return blocks.map((b) => b.text).join('');
41
+ if (omitted > 0)
42
+ blocks.push({ type: 'text', text: OMITTED_CONTENT_NOTE });
43
+ return blocks;
44
+ }
45
+ export function toolResultBlocksOf(output, truncated) {
46
+ const content = toolResultContentOf(output);
47
+ if (!Array.isArray(content))
48
+ return undefined;
49
+ if (truncated)
50
+ content.push({ type: 'text', text: TRUNCATED_NOTE });
51
+ return content;
52
+ }
53
+ export function toolEndOutputText(output) {
54
+ const content = toolResultContentOf(output);
55
+ if (content === undefined || typeof content === 'string')
56
+ return content;
57
+ return content
58
+ .map((b) => {
59
+ const block = b;
60
+ return block.type === 'image' ? IMAGE_TEXT_PLACEHOLDER : (block.text ?? '');
61
+ })
62
+ .join('');
63
+ }
@@ -75,7 +75,7 @@ export function projectUsageSeries(body) {
75
75
  const points = [];
76
76
  let unreadable = 0;
77
77
  for (const raw of series) {
78
- if (!isRecord(raw) || !nonEmpty(raw.t) || !nonNeg(raw.v)) {
78
+ if (!isRecord(raw) || typeof raw.t !== 'string' || usageInstantOf(raw.t) === undefined || !nonNeg(raw.v)) {
79
79
  unreadable++;
80
80
  continue;
81
81
  }
@@ -180,31 +180,55 @@ function unavailableCauseOf(v) {
180
180
  function modelsUnavailable(cause) {
181
181
  return { state: 'unavailable', cause, sentence: cause === 'no_backend_face' ? USAGE_SENTENCES.modelsUnavailable : USAGE_SENTENCES.modelsUnread };
182
182
  }
183
- const DAY_KEY_RE = /^(\d{4})-(\d{2})-(\d{2})(?:[T ]|$)/;
184
- function dayKeyOf(iso) {
185
- const m = DAY_KEY_RE.exec(iso);
183
+ const USAGE_TS_RE = /^(\d{4})-(\d{2})-(\d{2})(?:[Tt ](\d{2}):(\d{2})(?::(\d{2})(?:\.\d+)?)?([Zz]|[+-]\d{2}:?\d{2}))?$/;
184
+ const OFFSET_RE = /^([+-])(\d{2}):?(\d{2})$/;
185
+ function usageInstantOf(t) {
186
+ if (typeof t !== 'string')
187
+ return undefined;
188
+ const m = USAGE_TS_RE.exec(t);
186
189
  if (m === null)
187
190
  return undefined;
188
191
  const y = Number(m[1]);
189
192
  const mo = Number(m[2]);
190
193
  const d = Number(m[3]);
191
- const at = new Date(Date.UTC(y, mo - 1, d));
192
- return at.getUTCFullYear() === y && at.getUTCMonth() === mo - 1 && at.getUTCDate() === d ? iso.slice(0, 10) : undefined;
194
+ const date = new Date(Date.UTC(y, mo - 1, d));
195
+ if (date.getUTCFullYear() !== y || date.getUTCMonth() !== mo - 1 || date.getUTCDate() !== d)
196
+ return undefined;
197
+ if (m[4] === undefined)
198
+ return { dayKey: t.slice(0, 10), hourUtc: 0 };
199
+ const hh = Number(m[4]);
200
+ const mi = Number(m[5]);
201
+ const ss = m[6] === undefined ? 0 : Number(m[6]);
202
+ if (hh > 23 || mi > 59 || ss > 59)
203
+ return undefined;
204
+ let offsetMin = 0;
205
+ const zone = m[7];
206
+ if (zone !== 'Z' && zone !== 'z') {
207
+ const o = OFFSET_RE.exec(zone);
208
+ if (o === null)
209
+ return undefined;
210
+ const oh = Number(o[2]);
211
+ const om = Number(o[3]);
212
+ if (oh > 23 || om > 59)
213
+ return undefined;
214
+ offsetMin = (o[1] === '-' ? -1 : 1) * (oh * 60 + om);
215
+ }
216
+ const at = new Date(date.getTime() + ((hh * 60 + mi - offsetMin) * 60 + ss) * 1000);
217
+ const iso = at.toISOString();
218
+ if (!/^\d{4}-/.test(iso))
219
+ return undefined;
220
+ return { dayKey: iso.slice(0, 10), hourUtc: at.getUTCHours() };
193
221
  }
194
222
  const isWhole = (v) => v.unreadable === 0 && !v.truncated;
195
- function hourOfDayUtc(iso) {
196
- const d = new Date(iso);
197
- return Number.isNaN(d.getTime()) ? undefined : d.getUTCHours();
198
- }
199
223
  function peakHourOf(points) {
200
224
  if (points.length === 0)
201
225
  return undefined;
202
226
  const perHour = new Array(24).fill(0);
203
227
  for (const p of points) {
204
- const h = hourOfDayUtc(p.t);
205
- if (h === undefined)
228
+ const at = usageInstantOf(p.t);
229
+ if (at === undefined)
206
230
  return undefined;
207
- perHour[h] = (perHour[h] ?? 0) + p.v;
231
+ perHour[at.hourUtc] = (perHour[at.hourUtc] ?? 0) + p.v;
208
232
  }
209
233
  let peakHour = -1;
210
234
  let peakValue = -1;
@@ -262,11 +286,11 @@ export function projectUsageAnalytics(inputs, window) {
262
286
  const dayValues = new Map();
263
287
  let allKeysReadable = true;
264
288
  for (const p of day.value.points) {
265
- const key = dayKeyOf(p.t);
266
- if (key === undefined)
289
+ const at = usageInstantOf(p.t);
290
+ if (at === undefined)
267
291
  allKeysReadable = false;
268
292
  else
269
- dayValues.set(key, (dayValues.get(key) ?? 0) + p.v);
293
+ dayValues.set(at.dayKey, (dayValues.get(at.dayKey) ?? 0) + p.v);
270
294
  }
271
295
  if (allKeysReadable) {
272
296
  readings.activeDays = [...dayValues.values()].filter((v) => v > 0).length;
@@ -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
  } | {
@@ -14,4 +16,3 @@ export declare function noteEngineCapsForUserInvokedSkills(baseUrl: string, caps
14
16
  export declare function observedUserInvokedSkills(baseUrl?: string | undefined): UserInvokedSkillsReading;
15
17
  export declare function userInvokedSkillsAvailable(reading: UserInvokedSkillsReading): 'yes' | 'no' | 'unknown';
16
18
  export declare function userInvokedSkillsDoctorDetail(reading: UserInvokedSkillsReading): string;
17
- export declare function __resetUserInvokedSkillsReadingsForTests(): void;
@@ -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':
@@ -46,6 +47,3 @@ export function userInvokedSkillsDoctorDetail(reading) {
46
47
  return 'user-invoked skills on — skills the user names on a request take effect when the run starts';
47
48
  }
48
49
  }
49
- export function __resetUserInvokedSkillsReadingsForTests() {
50
- reader.__resetForTests();
51
- }
@@ -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)');
@@ -43,6 +43,8 @@ export interface ScenarioDenyDetail {
43
43
  allowlist: string[];
44
44
  }
45
45
  export declare function scenarioDenyFromError(err: unknown): ScenarioDenyDetail | null;
46
+ export type ScenarioDenySurface = 'request' | 'resumed_work';
47
+ export declare function scenarioNotAllowedContent(detail: ScenarioDenyDetail, requestedScenario?: string, surface?: ScenarioDenySurface): string;
46
48
  export interface ResumeRetryLaterDetail {
47
49
  code: string;
48
50
  retryAfterSec?: number;
@@ -1,27 +1,51 @@
1
- import { readErrorNumber, readErrorString, readErrorStringList } from './wireFailureShape.js';
2
- import { capForDisplay } from './fleetTaskDesc.js';
1
+ import { readBlockedBy, readErrorNumber, readErrorString, readErrorStringList, readThrownSlot, thrownIsInstanceOf, THROWN_SLOT_UNREADABLE, WIRE_FAILURE_UNRENDERABLE_TEXT, } from './wireFailureShape.js';
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';
6
- export const WIRE_NETWORK_ERROR_PATTERN = /fetch failed|ECONNREFUSED|ECONNRESET|ETIMEDOUT|EAI_AGAIN|ENOTFOUND|EHOSTUNREACH|ENETUNREACH|EPIPE|socket hang up|UND_ERR|terminated|other side closed/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));
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
+ 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 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
- const inner = readErrorString(err, 'blockedBy');
68
- return inner !== undefined && inner.length > 0 ? inner : outer;
88
+ const inner = readBlockedBy(err);
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
  }
@@ -151,11 +176,39 @@ export function scenarioDenyFromError(err) {
151
176
  const allowlist = (readErrorStringList(err, 'allowlist') ?? []).filter((x) => x.length > 0);
152
177
  return { allowlist };
153
178
  }
179
+ export function scenarioNotAllowedContent(detail, requestedScenario, surface) {
180
+ const resumed = surface === 'resumed_work';
181
+ const names = [];
182
+ try {
183
+ const raw = detail?.allowlist;
184
+ if (Array.isArray(raw)) {
185
+ const n = raw.length;
186
+ for (let i = 0; i < n; i++) {
187
+ const item = raw[i];
188
+ if (typeof item === 'string' && item.length > 0)
189
+ names.push(escapeDisplayControlChars(item));
190
+ }
191
+ }
192
+ }
193
+ catch {
194
+ names.length = 0;
195
+ }
196
+ const subject = typeof requestedScenario === 'string' && requestedScenario.length > 0
197
+ ? `Scenario "${escapeDisplayControlChars(requestedScenario)}" is not in your allowed list`
198
+ : resumed
199
+ ? 'The scenario this work resumes under is not in your allowed list'
200
+ : 'The requested scenario is not in your allowed list';
201
+ const parts = [subject];
202
+ if (names.length > 0)
203
+ parts.push(`Available: ${names.join(', ')}`);
204
+ if (!resumed)
205
+ parts.push('You can also omit the scenario to run on your default assignment');
206
+ return parts.join(' · ');
207
+ }
154
208
  export function resumeRetryLaterFromError(err) {
155
209
  if (typeof err !== 'object' || err === null)
156
210
  return null;
157
- const e = err;
158
- const code = e.errorCode;
211
+ const code = readThrownSlot(err, 'errorCode', 'data');
159
212
  if (typeof code !== 'string' || !RESUME_RETRY_LATER_CODES.includes(code))
160
213
  return null;
161
214
  const sec = readErrorNumber(err, 'retryAfterSec');
@@ -8,21 +8,38 @@ interface WireFailureShape {
8
8
  bodyVerdict?: string;
9
9
  bodyCurrentName?: string;
10
10
  message: string;
11
- ownMessage?: string;
12
11
  }
13
12
  export declare const THROWN_SLOT_UNREADABLE: unique symbol;
14
- export declare function readThrownSlot(o: unknown, key: string, own?: boolean): unknown;
13
+ export declare function readThrownSlot(o: unknown, key: string, own?: boolean | 'data'): unknown;
15
14
  export declare function thrownIsInstanceOf<C extends abstract new (...args: never[]) => unknown>(e: unknown, cls: C): e is InstanceType<C>;
15
+ export type ThrownExtraReading = {
16
+ readonly state: 'object';
17
+ readonly value: object;
18
+ } | {
19
+ readonly state: 'absent';
20
+ } | {
21
+ readonly state: 'unreadable';
22
+ };
23
+ export declare function readThrownExtra(o: {} | null | undefined): ThrownExtraReading;
16
24
  export declare function readErrorNumber(o: object, key: string): number | undefined;
17
25
  export declare function readErrorRecord(o: object, key: string): object | undefined;
18
26
  export declare function readErrorString(o: object, key: string): string | undefined;
19
27
  export declare function readErrorStringList(o: object, key: string): readonly string[] | undefined;
20
28
  export declare function readErrorStrictStringList(o: object, key: string): readonly string[] | undefined;
21
- export declare function wireFailureShapeOf(e: unknown): WireFailureShape;
22
29
  export declare const WIRE_FAILURE_UNRENDERABLE_TEXT = "the call failed with an error this client could not render";
30
+ export declare function wireFailureShapeOf(e: unknown): WireFailureShape;
23
31
  export declare function wireFailureTextsOf(e: unknown): {
24
32
  reason: string;
25
33
  log: string;
26
34
  };
35
+ export type BlockedByReading = {
36
+ kind: 'named';
37
+ code: string;
38
+ } | {
39
+ kind: 'absent';
40
+ } | {
41
+ kind: 'unreadable';
42
+ };
43
+ export declare function readBlockedBy(o: object): BlockedByReading;
27
44
  export declare function readRefusalField(o: object): string | undefined;
28
45
  export {};