@sema-agent/client-core 0.95.0 → 0.96.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 (181) hide show
  1. package/CHANGELOG.md +180 -0
  2. package/README.md +49 -25
  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 -0
  8. package/dist/adapter/activeRunSelfHeal.js +30 -4
  9. package/dist/adapter/downstream/eventToSdkMessage.js +11 -3
  10. package/dist/adapter/downstream/terminalToSdkResult.js +8 -9
  11. package/dist/adapter/runStream.js +30 -47
  12. package/dist/agentSession/engineAgentRegistryRead.js +5 -4
  13. package/dist/agentSession/engineSessionBackgroundStop.js +22 -15
  14. package/dist/agentsWireCaps.js +13 -2
  15. package/dist/callerCwdCapability.d.ts +0 -4
  16. package/dist/callerCwdCapability.js +0 -6
  17. package/dist/centerWiringCapability.d.ts +0 -4
  18. package/dist/centerWiringCapability.js +0 -6
  19. package/dist/classifierVerdictWire.js +4 -16
  20. package/dist/clientSlice.js +1 -1
  21. package/dist/cloudConfigWireCaps.d.ts +3 -3
  22. package/dist/cloudConfigWireCaps.js +65 -45
  23. package/dist/coreValuePorts.d.ts +11 -7
  24. package/dist/coreValuePorts.js +5 -8
  25. package/dist/credentialProvenance.d.ts +28 -0
  26. package/dist/credentialProvenance.js +76 -0
  27. package/dist/decideFailureNote.js +3 -1
  28. package/dist/decideReceipt.js +7 -10
  29. package/dist/declared/supportFloorDeclared.js +3 -3
  30. package/dist/displayUntrusted.d.ts +7 -3
  31. package/dist/displayUntrusted.js +356 -60
  32. package/dist/engineCapsCache.d.ts +6 -0
  33. package/dist/engineCapsCache.js +226 -32
  34. package/dist/engineDirectory.d.ts +79 -0
  35. package/dist/engineDirectory.js +186 -0
  36. package/dist/engineErrorCodes.d.ts +14 -1
  37. package/dist/engineErrorCodes.js +37 -15
  38. package/dist/engineNoticeCodes.d.ts +17 -0
  39. package/dist/engineNoticeCodes.js +57 -3
  40. package/dist/engineWordRenames.d.ts +8 -0
  41. package/dist/engineWordRenames.js +13 -0
  42. package/dist/fileHistoryCaptureCapability.d.ts +14 -0
  43. package/dist/fileHistoryCaptureCapability.js +70 -0
  44. package/dist/fleet/bgSubagentRow.d.ts +15 -0
  45. package/dist/fleet/bgSubagentRow.js +67 -0
  46. package/dist/fleet/fleetLedger.d.ts +1 -0
  47. package/dist/fleet/fleetLedger.js +103 -89
  48. package/dist/fleet/fleetProjection.d.ts +1 -0
  49. package/dist/fleet/fleetProjection.js +10 -3
  50. package/dist/fleetTaskDesc.js +4 -17
  51. package/dist/gateOutcome.d.ts +12 -1
  52. package/dist/gateOutcome.js +58 -1
  53. package/dist/gateVocabulary.d.ts +7 -2
  54. package/dist/gateVocabulary.js +5 -1
  55. package/dist/generated/engineAskFaceTables.js +1 -1
  56. package/dist/generated/engineFactTables.d.ts +5 -3
  57. package/dist/generated/engineFactTables.js +17 -4
  58. package/dist/generated/engineNoticeTables.js +12 -3
  59. package/dist/generated/settingsSchemaFns.d.ts +3 -0
  60. package/dist/generated/settingsSchemaFns.js +53 -0
  61. package/dist/generated/toolNameTables.d.ts +1 -0
  62. package/dist/generated/toolNameTables.js +1 -0
  63. package/dist/hitl/approvalEndingCause.d.ts +2 -0
  64. package/dist/hitl/approvalEndingCause.js +31 -21
  65. package/dist/hitl/askParkRowRouting.js +1 -1
  66. package/dist/hitl/automaticAnswerVerdict.d.ts +1 -1
  67. package/dist/hitl/automaticAnswerVerdict.js +13 -8
  68. package/dist/hitl/decisionConflict.js +0 -2
  69. package/dist/hitl/decisionRefusal.d.ts +8 -0
  70. package/dist/hitl/decisionRefusal.js +48 -14
  71. package/dist/hitl/frameRouter.d.ts +0 -1
  72. package/dist/hitl/frameRouter.js +6 -14
  73. package/dist/hitl/hitlBridge.d.ts +6 -2
  74. package/dist/hitl/hitlBridge.js +28 -7
  75. package/dist/hitl/localAllowRule.d.ts +1 -0
  76. package/dist/hitl/localAllowRule.js +2 -2
  77. package/dist/hitl/noAllowCause.d.ts +2 -1
  78. package/dist/hitl/noAllowCause.js +3 -2
  79. package/dist/hitl/parkResolver.d.ts +1 -0
  80. package/dist/hitl/parkResolver.js +8 -54
  81. package/dist/hitl/parkRowBirthWait.d.ts +1 -0
  82. package/dist/hitl/parkRowBirthWait.js +2 -2
  83. package/dist/hitl/planReviewWire.d.ts +1 -0
  84. package/dist/hitl/planReviewWire.js +98 -20
  85. package/dist/hitl/replayedApproval.d.ts +1 -0
  86. package/dist/hitl/replayedApproval.js +14 -0
  87. package/dist/hitl/sessionPolicyDeliverable.js +8 -6
  88. package/dist/hitl/standingRows.d.ts +18 -0
  89. package/dist/hitl/standingRows.js +127 -0
  90. package/dist/hitl/toolApprovalWire.d.ts +15 -3
  91. package/dist/hitl/toolApprovalWire.js +238 -25
  92. package/dist/hookMatcherVerdict.d.ts +1 -9
  93. package/dist/hookMatcherVerdict.js +21 -61
  94. package/dist/hooksWireCaps.js +2 -2
  95. package/dist/hostCallbackGuard.d.ts +1 -0
  96. package/dist/hostCallbackGuard.js +6 -0
  97. package/dist/index.d.ts +21 -9
  98. package/dist/index.js +17 -8
  99. package/dist/mcpProbeCapability.d.ts +0 -4
  100. package/dist/mcpProbeCapability.js +0 -6
  101. package/dist/memoryComplianceCapability.d.ts +0 -4
  102. package/dist/memoryComplianceCapability.js +0 -6
  103. package/dist/memoryOriginCapability.d.ts +0 -4
  104. package/dist/memoryOriginCapability.js +0 -6
  105. package/dist/memorySpecWire.js +2 -2
  106. package/dist/modelIdentityResolvability.d.ts +2 -2
  107. package/dist/modelIdentityResolvability.js +12 -3
  108. package/dist/noticePresentation.d.ts +68 -0
  109. package/dist/noticePresentation.js +247 -0
  110. package/dist/outputStyleSeatCapability.d.ts +0 -1
  111. package/dist/outputStyleSeatCapability.js +0 -3
  112. package/dist/ownKey.d.ts +2 -0
  113. package/dist/ownKey.js +18 -0
  114. package/dist/peerFrames.js +13 -9
  115. package/dist/permissionModesCapability.d.ts +0 -4
  116. package/dist/permissionModesCapability.js +0 -6
  117. package/dist/permissionRuleIssue.js +0 -3
  118. package/dist/permissionsDeclaration.d.ts +2 -0
  119. package/dist/permissionsDeclaration.js +56 -41
  120. package/dist/printPermissionOutcome.d.ts +12 -0
  121. package/dist/printPermissionOutcome.js +50 -0
  122. package/dist/printToolResultFrame.d.ts +1 -0
  123. package/dist/printToolResultFrame.js +5 -9
  124. package/dist/promptBlockedCopy.d.ts +5 -0
  125. package/dist/promptBlockedCopy.js +35 -0
  126. package/dist/protocolSegment.d.ts +9 -6
  127. package/dist/protocolSegment.js +31 -21
  128. package/dist/providerRejection.d.ts +4 -0
  129. package/dist/providerRejection.js +75 -14
  130. package/dist/replayBody.d.ts +12 -0
  131. package/dist/replayBody.js +25 -0
  132. package/dist/resumeRefusalCopy.js +5 -21
  133. package/dist/retryStatus.d.ts +9 -1
  134. package/dist/retryStatus.js +9 -2
  135. package/dist/rewindArchiveCapability.d.ts +3 -13
  136. package/dist/rewindArchiveCapability.js +7 -58
  137. package/dist/rewindArchiveReading.d.ts +15 -0
  138. package/dist/rewindArchiveReading.js +56 -0
  139. package/dist/ruleCompileVerdict.d.ts +9 -1
  140. package/dist/ruleCompileVerdict.js +29 -4
  141. package/dist/runTerminal.d.ts +15 -1
  142. package/dist/runTerminal.js +56 -8
  143. package/dist/sandboxWire.js +13 -0
  144. package/dist/sealedKeyCapability.d.ts +0 -4
  145. package/dist/sealedKeyCapability.js +0 -6
  146. package/dist/seam.js +4 -2
  147. package/dist/seatContract.d.ts +73 -11
  148. package/dist/seatContract.js +195 -14
  149. package/dist/sessionReadRedactionCapability.d.ts +0 -4
  150. package/dist/sessionReadRedactionCapability.js +0 -6
  151. package/dist/sessionSyncFileHistory.d.ts +4 -0
  152. package/dist/sessionSyncFileHistory.js +66 -0
  153. package/dist/sessionSyncFileHistoryCapability.d.ts +0 -1
  154. package/dist/sessionSyncFileHistoryCapability.js +0 -3
  155. package/dist/skillToolListsCapability.d.ts +0 -1
  156. package/dist/skillToolListsCapability.js +0 -3
  157. package/dist/steerPriorityCapability.d.ts +0 -1
  158. package/dist/steerPriorityCapability.js +0 -3
  159. package/dist/storePostureCapability.d.ts +0 -4
  160. package/dist/storePostureCapability.js +0 -6
  161. package/dist/subagent/engineSubagentSteer.js +7 -5
  162. package/dist/subagentContentStore.js +4 -15
  163. package/dist/supportFloor.d.ts +1 -0
  164. package/dist/supportFloor.js +13 -9
  165. package/dist/systemReminderTag.d.ts +1 -0
  166. package/dist/systemReminderTag.js +8 -0
  167. package/dist/toolHistoryMismatch.d.ts +0 -3
  168. package/dist/toolHistoryMismatch.js +3 -7
  169. package/dist/toolResult.d.ts +1 -1
  170. package/dist/toolResult.js +2 -1
  171. package/dist/toolResultContent.d.ts +2 -0
  172. package/dist/toolResultContent.js +63 -0
  173. package/dist/usageAnalytics.js +40 -16
  174. package/dist/userInvokedSkillsCapability.d.ts +0 -1
  175. package/dist/userInvokedSkillsCapability.js +0 -3
  176. package/dist/wireErrorTriage.d.ts +2 -0
  177. package/dist/wireErrorTriage.js +34 -5
  178. package/dist/wireFailureShape.d.ts +19 -2
  179. package/dist/wireFailureShape.js +55 -50
  180. package/docs/INTEGRATION-CLIENTS.md +1262 -17
  181. package/package.json +5 -5
@@ -11,7 +11,8 @@ function releaseTriple(v) {
11
11
  const m = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)$/.exec(v);
12
12
  if (m === null)
13
13
  return undefined;
14
- return [Number(m[1]), Number(m[2]), Number(m[3])];
14
+ const t = [Number(m[1]), Number(m[2]), Number(m[3])];
15
+ return t.every(Number.isSafeInteger) ? t : undefined;
15
16
  }
16
17
  function compareTriple(a, b) {
17
18
  for (let i = 0; i < 3; i++) {
@@ -22,28 +23,31 @@ function compareTriple(a, b) {
22
23
  }
23
24
  return 0;
24
25
  }
25
- function versionTierAgainst(version, base, floor, caller) {
26
+ function judgeAgainst(version, base, floor, caller) {
26
27
  const baseTriple = releaseTriple(base);
27
28
  if (baseTriple === undefined) {
28
29
  throw new TypeError(`${caller}: 门槛只接受纯 x.y.z 版本串(整串、无前导零、无前后缀)—— 收到 typeof=${base === null ? 'null' : typeof base}。错误文本只报形状,不回显值。`);
29
30
  }
30
- let need = baseTriple;
31
+ let need = { triple: baseTriple, text: base };
31
32
  if (floor !== undefined) {
32
33
  const own = releaseTriple(floor);
33
34
  if (own === undefined) {
34
35
  throw new TypeError(`${caller}: floor 只接受纯 x.y.z 版本串(整串、无前导零、无前后缀)或缺席 —— 收到 typeof=${floor === null ? 'null' : typeof floor}。错误文本只报形状,不回显值。`);
35
36
  }
36
- if (compareTriple(own, need) > 0)
37
- need = own;
37
+ if (compareTriple(own, need.triple) > 0)
38
+ need = { triple: own, text: floor };
38
39
  }
39
40
  const got = releaseTriple(version);
40
41
  if (got === undefined)
41
- return 'unknown';
42
- return compareTriple(got, need) >= 0 ? 'engine' : 'legacy';
42
+ return { need: need.text, tier: 'unknown' };
43
+ return { need: need.text, tier: compareTriple(got, need.triple) >= 0 ? 'engine' : 'legacy' };
43
44
  }
44
45
  export function engineVersionTier(version, floor) {
45
- return versionTierAgainst(version, SUPPORT_FLOOR.server, floor, 'engineVersionTier');
46
+ return judgeAgainst(version, SUPPORT_FLOOR.server, floor, 'engineVersionTier').tier;
47
+ }
48
+ export function engineSupportFloorEffective(floor) {
49
+ return judgeAgainst(undefined, SUPPORT_FLOOR.server, floor, 'engineSupportFloorEffective').need;
46
50
  }
47
51
  export function coreVersionTier(version, floor) {
48
- return versionTierAgainst(version, SUPPORT_FLOOR.core, floor, 'coreVersionTier');
52
+ return judgeAgainst(version, SUPPORT_FLOOR.core, floor, 'coreVersionTier').tier;
49
53
  }
@@ -5,3 +5,4 @@ export interface SystemReminderOpenTagSpan {
5
5
  export declare function findSystemReminderOpenTag(text: string, from?: number): SystemReminderOpenTagSpan | null;
6
6
  export declare function unwrapSystemReminder(text: string): string;
7
7
  export declare function stripSystemReminderBlocks(text: string): string;
8
+ export declare function stripSystemReminderTagTokens(text: string): string;
@@ -39,3 +39,11 @@ export function stripSystemReminderBlocks(text) {
39
39
  }
40
40
  return pos === 0 ? text : out + text.slice(pos);
41
41
  }
42
+ const SYSTEM_REMINDER_TAG_TOKEN = /<[^A-Za-z0-9>]{0,12}system-reminder(?:[^>]{0,200}>)?/gi;
43
+ const SYSTEM_REMINDER_TAG_HEAD = /<[^A-Za-z0-9>]{0,12}system-reminder/i;
44
+ export function stripSystemReminderTagTokens(text) {
45
+ if (typeof text !== 'string')
46
+ return text;
47
+ const once = text.replace(SYSTEM_REMINDER_TAG_TOKEN, ' ');
48
+ return SYSTEM_REMINDER_TAG_HEAD.test(once) ? once.replace(/</g, '&lt;') : once;
49
+ }
@@ -18,8 +18,6 @@ export declare const TOOL_HISTORY_MISMATCH_ANCHORS: readonly ToolHistoryMismatch
18
18
  export declare function classifyToolHistoryMismatch(err: ToolHistoryErrorCarrier | null | undefined): ToolHistoryMismatch | null;
19
19
  export declare const TOOL_HISTORY_REWIND_SENTENCE = "Run /rewind to recover the conversation.";
20
20
  export declare function toolHistoryRepeatSentence(n: number): string;
21
- type ConversationRewindVerdict = 'available' | 'unavailable' | 'unknown';
22
- export declare function _wireConversationRewindJudge(judge: (engineBaseUrl: string) => ConversationRewindVerdict): void;
23
21
  export declare function toolHistoryRewindOffered(declared: boolean | {
24
22
  readonly engineBaseUrl: string;
25
23
  } | undefined): boolean;
@@ -61,4 +59,3 @@ export type ToolHistoryRewindResolution<R> = {
61
59
  undecidable: ToolHistoryUndecidableReason;
62
60
  };
63
61
  export declare function resolveToolHistoryRewindTarget<R extends ToolHistoryRow>(rows: readonly (R | null | undefined)[] | null | undefined, mismatch: ToolHistoryMismatch | null | undefined): ToolHistoryRewindResolution<R>;
64
- export {};
@@ -1,3 +1,4 @@
1
+ import { rewindArchiveReadingAt, rewindConversationAvailability } from './rewindArchiveReading.js';
1
2
  export const TOOL_HISTORY_MISMATCH_KINDS = Object.freeze([
2
3
  'tool_use_without_result',
3
4
  'orphan_tool_result',
@@ -224,10 +225,6 @@ export const TOOL_HISTORY_REWIND_SENTENCE = 'Run /rewind to recover the conversa
224
225
  export function toolHistoryRepeatSentence(n) {
225
226
  return `The same error has now happened ${n} times in a row; /rewind is the only way to recover this conversation.`;
226
227
  }
227
- let conversationRewindJudge;
228
- export function _wireConversationRewindJudge(judge) {
229
- conversationRewindJudge = judge;
230
- }
231
228
  export function toolHistoryRewindOffered(declared) {
232
229
  const decl = declared;
233
230
  if (decl === true)
@@ -238,10 +235,9 @@ export function toolHistoryRewindOffered(declared) {
238
235
  if (Array.isArray(decl))
239
236
  return false;
240
237
  const base = decl.engineBaseUrl;
241
- const judge = conversationRewindJudge;
242
- if (typeof base !== 'string' || base.length === 0 || judge === undefined)
238
+ if (typeof base !== 'string' || base.length === 0)
243
239
  return true;
244
- return judge(base) !== 'unavailable';
240
+ return rewindConversationAvailability(rewindArchiveReadingAt(base)) !== 'unavailable';
245
241
  }
246
242
  catch {
247
243
  return true;
@@ -86,7 +86,7 @@ export declare function _resetBackgroundReceiptParseCountForTest(): void;
86
86
  export type FlattenWireOutput = (output: unknown) => string;
87
87
  export declare const TOOL_RESULT_DEGRADED_WIRE_NO_OUTPUT: "wire_carried_no_output";
88
88
  export interface ToolResultBody {
89
- content: unknown;
89
+ content: string | unknown[];
90
90
  isError: boolean;
91
91
  toolUseResult?: unknown;
92
92
  degraded?: typeof TOOL_RESULT_DEGRADED_WIRE_NO_OUTPUT;
@@ -355,8 +355,9 @@ export function wireOutputToBody(toolName, output, isError, truncated, flatten,
355
355
  const body = truncated ? `${text}\n…(truncated)` : text;
356
356
  const parsed = parseModelFacingTaskOutput(text);
357
357
  const wrap = (task) => ({
358
- content: { retrieval_status: 'success', task },
358
+ content: body,
359
359
  isError,
360
+ toolUseResult: { retrieval_status: 'success', task },
360
361
  });
361
362
  if (parsed.kind === 'agent') {
362
363
  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;
@@ -14,4 +14,3 @@ export declare function noteEngineCapsForUserInvokedSkills(baseUrl: string, caps
14
14
  export declare function observedUserInvokedSkills(baseUrl?: string | undefined): UserInvokedSkillsReading;
15
15
  export declare function userInvokedSkillsAvailable(reading: UserInvokedSkillsReading): 'yes' | 'no' | 'unknown';
16
16
  export declare function userInvokedSkillsDoctorDetail(reading: UserInvokedSkillsReading): string;
17
- export declare function __resetUserInvokedSkillsReadingsForTests(): void;
@@ -46,6 +46,3 @@ export function userInvokedSkillsDoctorDetail(reading) {
46
46
  return 'user-invoked skills on — skills the user names on a request take effect when the run starts';
47
47
  }
48
48
  }
49
- export function __resetUserInvokedSkillsReadingsForTests() {
50
- reader.__resetForTests();
51
- }
@@ -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,9 +1,9 @@
1
- import { readErrorNumber, readErrorString, readErrorStringList } from './wireFailureShape.js';
2
- import { capForDisplay } from './fleetTaskDesc.js';
1
+ import { readBlockedBy, readErrorNumber, readErrorString, readErrorStringList } 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
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;
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
7
  function wireErrorDetail(err) {
8
8
  const e = err;
9
9
  const cause = e?.cause;
@@ -64,8 +64,8 @@ export function effectiveWireErrorCode(err) {
64
64
  const outer = typeof outerRaw === 'string' && outerRaw.length > 0 ? outerRaw : undefined;
65
65
  if (outer !== RESUME_POLICY_FOLD_CODE)
66
66
  return outer;
67
- const inner = readErrorString(err, 'blockedBy');
68
- return inner !== undefined && inner.length > 0 ? inner : outer;
67
+ const inner = readBlockedBy(err);
68
+ return inner.kind === 'named' ? inner.code : outer;
69
69
  }
70
70
  export function corruptStoredRowWhere(err) {
71
71
  if (effectiveWireErrorCode(err) !== 'corrupt')
@@ -151,6 +151,35 @@ export function scenarioDenyFromError(err) {
151
151
  const allowlist = (readErrorStringList(err, 'allowlist') ?? []).filter((x) => x.length > 0);
152
152
  return { allowlist };
153
153
  }
154
+ export function scenarioNotAllowedContent(detail, requestedScenario, surface) {
155
+ const resumed = surface === 'resumed_work';
156
+ const names = [];
157
+ try {
158
+ const raw = detail?.allowlist;
159
+ if (Array.isArray(raw)) {
160
+ const n = raw.length;
161
+ for (let i = 0; i < n; i++) {
162
+ const item = raw[i];
163
+ if (typeof item === 'string' && item.length > 0)
164
+ names.push(escapeDisplayControlChars(item));
165
+ }
166
+ }
167
+ }
168
+ catch {
169
+ names.length = 0;
170
+ }
171
+ const subject = typeof requestedScenario === 'string' && requestedScenario.length > 0
172
+ ? `Scenario "${escapeDisplayControlChars(requestedScenario)}" is not in your allowed list`
173
+ : resumed
174
+ ? 'The scenario this work resumes under is not in your allowed list'
175
+ : 'The requested scenario is not in your allowed list';
176
+ const parts = [subject];
177
+ if (names.length > 0)
178
+ parts.push(`Available: ${names.join(', ')}`);
179
+ if (!resumed)
180
+ parts.push('You can also omit the scenario to run on your default assignment');
181
+ return parts.join(' · ');
182
+ }
154
183
  export function resumeRetryLaterFromError(err) {
155
184
  if (typeof err !== 'object' || err === null)
156
185
  return null;
@@ -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
13
  export declare function readThrownSlot(o: unknown, key: string, own?: boolean): 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 {};
@@ -21,6 +21,21 @@ export function thrownIsInstanceOf(e, cls) {
21
21
  return false;
22
22
  }
23
23
  }
24
+ export function readThrownExtra(o) {
25
+ if (o === null || o === undefined)
26
+ return { state: 'absent' };
27
+ const slot = readThrownSlot(o, 'extra');
28
+ if (slot === THROWN_SLOT_UNREADABLE)
29
+ return { state: 'unreadable' };
30
+ try {
31
+ if (typeof slot !== 'object' || slot === null || Array.isArray(slot))
32
+ return { state: 'absent' };
33
+ }
34
+ catch {
35
+ return { state: 'unreadable' };
36
+ }
37
+ return { state: 'object', value: slot };
38
+ }
24
39
  function readErrorSlot(obj, key, accept) {
25
40
  try {
26
41
  const o = obj;
@@ -33,15 +48,10 @@ function readErrorSlot(obj, key, accept) {
33
48
  }
34
49
  if (accept(top))
35
50
  return top;
36
- let extra;
37
- try {
38
- extra = o['extra'];
39
- }
40
- catch {
41
- extra = undefined;
42
- }
43
- if (typeof extra !== 'object' || extra === null || Array.isArray(extra))
51
+ const reading = readThrownExtra(obj);
52
+ if (reading.state !== 'object')
44
53
  return undefined;
54
+ const extra = reading.value;
45
55
  let fromExtra;
46
56
  try {
47
57
  fromExtra = Object.hasOwn(extra, key) ? extra[key] : undefined;
@@ -98,28 +108,25 @@ export function readErrorStrictStringList(o, key) {
98
108
  return undefined;
99
109
  }
100
110
  }
111
+ export const WIRE_FAILURE_UNRENDERABLE_TEXT = 'the call failed with an error this client could not render';
112
+ function userFacingReasonOf(e, ownMessage) {
113
+ if (ownMessage !== undefined)
114
+ return ownMessage;
115
+ if (typeof e === 'string')
116
+ return e !== '' ? e : WIRE_FAILURE_UNRENDERABLE_TEXT;
117
+ if (typeof e === 'number' || typeof e === 'boolean' || typeof e === 'bigint')
118
+ return String(e);
119
+ return WIRE_FAILURE_UNRENDERABLE_TEXT;
120
+ }
101
121
  export function wireFailureShapeOf(e) {
102
122
  const o = e ?? {};
103
123
  const status = readGuarded(o, 'status');
104
124
  const errorCode = readGuarded(o, 'errorCode');
105
125
  const rawMessage = readGuarded(o, 'message');
106
126
  const retryAfterMs = readGuarded(o, 'retryAfterMs');
107
- let extra;
108
- let extraUnreadable = false;
109
- try {
110
- extra = o['extra'];
111
- }
112
- catch {
113
- extraUnreadable = true;
114
- }
115
- let extraObj;
116
- try {
117
- extraObj = typeof extra === 'object' && extra !== null && !Array.isArray(extra) ? extra : undefined;
118
- }
119
- catch {
120
- extraObj = undefined;
121
- extraUnreadable = true;
122
- }
127
+ const extraReading = readThrownExtra(e);
128
+ let extraUnreadable = extraReading.state === 'unreadable';
129
+ const extraObj = extraReading.state === 'object' ? extraReading.value : undefined;
123
130
  let committedPresent = false;
124
131
  let committedRaw;
125
132
  if (extraObj !== undefined) {
@@ -156,13 +163,7 @@ export function wireFailureShapeOf(e) {
156
163
  const bodyVerdict = ownString('verdict');
157
164
  const bodyCurrentName = ownString('currentName');
158
165
  const ownMessage = typeof rawMessage === 'string' && rawMessage !== '' ? rawMessage : undefined;
159
- let message;
160
- try {
161
- message = ownMessage !== undefined ? ownMessage : String(e);
162
- }
163
- catch {
164
- message = WIRE_FAILURE_UNRENDERABLE_TEXT;
165
- }
166
+ const message = userFacingReasonOf(e, ownMessage);
166
167
  const sec = typeof retryAfterMs === 'number' && Number.isFinite(retryAfterMs) && retryAfterMs >= 0
167
168
  ? Math.ceil(retryAfterMs / 1000)
168
169
  : undefined;
@@ -183,12 +184,10 @@ export function wireFailureShapeOf(e) {
183
184
  ...(bodyVerdict !== undefined ? { bodyVerdict } : {}),
184
185
  ...(bodyCurrentName !== undefined ? { bodyCurrentName } : {}),
185
186
  message,
186
- ...(ownMessage !== undefined ? { ownMessage } : {}),
187
187
  };
188
188
  }
189
- export const WIRE_FAILURE_UNRENDERABLE_TEXT = 'the call failed with an error this client could not render';
190
189
  export function wireFailureTextsOf(e) {
191
- const { ownMessage } = wireFailureShapeOf(e);
190
+ const { message } = wireFailureShapeOf(e);
192
191
  let log;
193
192
  try {
194
193
  log = String(e).slice(0, 300);
@@ -196,13 +195,25 @@ export function wireFailureTextsOf(e) {
196
195
  catch {
197
196
  log = '<unprintable thrown value>';
198
197
  }
199
- if (ownMessage !== undefined)
200
- return { reason: ownMessage, log };
201
- if (typeof e === 'string')
202
- return { reason: e !== '' ? e : WIRE_FAILURE_UNRENDERABLE_TEXT, log };
203
- if (typeof e === 'number' || typeof e === 'boolean' || typeof e === 'bigint')
204
- return { reason: String(e), log };
205
- return { reason: WIRE_FAILURE_UNRENDERABLE_TEXT, log };
198
+ return { reason: message, log };
199
+ }
200
+ export function readBlockedBy(o) {
201
+ const judge = (v) => (typeof v === 'string' && v.length > 0 ? { kind: 'named', code: v } : { kind: 'unreadable' });
202
+ try {
203
+ const top = o['blockedBy'];
204
+ if (top !== undefined)
205
+ return judge(top);
206
+ const reading = readThrownExtra(o);
207
+ if (reading.state === 'unreadable')
208
+ return { kind: 'unreadable' };
209
+ if (reading.state === 'object' && Object.hasOwn(reading.value, 'blockedBy')) {
210
+ return judge(reading.value['blockedBy']);
211
+ }
212
+ return { kind: 'absent' };
213
+ }
214
+ catch {
215
+ return { kind: 'unreadable' };
216
+ }
206
217
  }
207
218
  export function readRefusalField(o) {
208
219
  const str = (rec) => {
@@ -215,15 +226,9 @@ export function readRefusalField(o) {
215
226
  }
216
227
  return typeof v === 'string' && v !== '' ? v : undefined;
217
228
  };
218
- let extra;
219
- try {
220
- extra = o.extra;
221
- }
222
- catch {
223
- extra = undefined;
224
- }
225
- if (typeof extra === 'object' && extra !== null && !Array.isArray(extra)) {
226
- const fromExtra = str(extra);
229
+ const reading = readThrownExtra(o);
230
+ if (reading.state === 'object') {
231
+ const fromExtra = str(reading.value);
227
232
  if (fromExtra !== undefined)
228
233
  return fromExtra;
229
234
  }