@sema-agent/client-core 0.91.0 → 0.93.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (195) hide show
  1. package/CHANGELOG.md +351 -0
  2. package/README.md +51 -34
  3. package/dist/adapt/arms.js +6 -12
  4. package/dist/adapt/panelTasks.d.ts +0 -2
  5. package/dist/adapt/panelTasks.js +6 -26
  6. package/dist/adapt/toolCards.js +6 -4
  7. package/dist/adapt.d.ts +1 -1
  8. package/dist/adapt.js +3 -3
  9. package/dist/adapter/activeRunSelfHeal.d.ts +0 -2
  10. package/dist/adapter/activeRunSelfHeal.js +5 -27
  11. package/dist/adapter/downstream/terminalToSdkResult.js +16 -7
  12. package/dist/adapter/runStream.js +6 -2
  13. package/dist/agentsWireCaps.js +1 -1
  14. package/dist/approvalDecidedByCapability.d.ts +16 -0
  15. package/dist/approvalDecidedByCapability.js +47 -0
  16. package/dist/approvalsStreamLiveCapability.js +3 -3
  17. package/dist/askSurvivesStandingAnswer.d.ts +4 -1
  18. package/dist/askSurvivesStandingAnswer.js +13 -0
  19. package/dist/autoModeUnavailable.js +3 -2
  20. package/dist/centerWiringCapability.js +1 -1
  21. package/dist/cloudConfigWireCaps.js +10 -9
  22. package/dist/compensations.js +7 -7
  23. package/dist/controlRouter.d.ts +23 -23
  24. package/dist/controlRouter.js +114 -49
  25. package/dist/coreValuePorts.d.ts +4 -2
  26. package/dist/coreValuePorts.js +5 -0
  27. package/dist/decideFailureNote.js +4 -2
  28. package/dist/decideReceipt.d.ts +11 -0
  29. package/dist/decideReceipt.js +95 -9
  30. package/dist/detachWire.d.ts +2 -14
  31. package/dist/detachWire.js +1 -47
  32. package/dist/deviceExecutorManagementCapability.d.ts +6 -2
  33. package/dist/deviceExecutorManagementCapability.js +61 -15
  34. package/dist/displayUntrusted.js +2 -1
  35. package/dist/effectiveFacts.d.ts +14 -4
  36. package/dist/effectiveFacts.js +45 -5
  37. package/dist/engineAgentAbsence.js +2 -1
  38. package/dist/engineCapReader.js +16 -10
  39. package/dist/engineCapsCache.d.ts +2 -0
  40. package/dist/engineCapsCache.js +13 -2
  41. package/dist/engineConfigDrift.d.ts +20 -0
  42. package/dist/engineConfigDrift.js +54 -0
  43. package/dist/engineErrorCodes.d.ts +17 -0
  44. package/dist/engineErrorCodes.js +45 -0
  45. package/dist/engineInlineTaskStats.d.ts +1 -0
  46. package/dist/engineNoticeCodes.d.ts +16 -2
  47. package/dist/engineNoticeCodes.js +71 -0
  48. package/dist/engineWireFor.d.ts +22 -0
  49. package/dist/engineWireFor.js +154 -9
  50. package/dist/engineWireSdk.d.ts +0 -1
  51. package/dist/engineWireSdk.js +0 -3
  52. package/dist/executionLaneCapability.js +4 -2
  53. package/dist/fileHistoryCaptureCapability.d.ts +1 -1
  54. package/dist/fileHistoryCaptureCapability.js +1 -6
  55. package/dist/fileHistoryLegNotice.d.ts +1 -1
  56. package/dist/fileHistoryLegNotice.js +1 -6
  57. package/dist/gateOutcome.js +2 -17
  58. package/dist/gateVocabulary.d.ts +2 -8
  59. package/dist/gateVocabulary.js +6 -32
  60. package/dist/generated/engineFactTables.d.ts +17 -1
  61. package/dist/generated/engineFactTables.js +91 -0
  62. package/dist/generated/engineNoticeTables.d.ts +1 -1
  63. package/dist/generated/engineNoticeTables.js +4 -1
  64. package/dist/generated/settingsSchemaTables.d.ts +8 -0
  65. package/dist/generated/settingsSchemaTables.js +40 -0
  66. package/dist/goalStopHook.d.ts +1 -8
  67. package/dist/goalStopHook.js +2 -58
  68. package/dist/headlessPermissionModeWire.d.ts +3 -2
  69. package/dist/headlessPermissionModeWire.js +46 -5
  70. package/dist/hitl/allowRuleShadow.d.ts +21 -0
  71. package/dist/hitl/allowRuleShadow.js +167 -0
  72. package/dist/hitl/askClassPair.d.ts +14 -0
  73. package/dist/hitl/askClassPair.js +42 -0
  74. package/dist/hitl/askGateWire.js +1 -0
  75. package/dist/hitl/askParkRowRouting.js +2 -2
  76. package/dist/hitl/askSurvivesPosture.d.ts +5 -0
  77. package/dist/hitl/askSurvivesPosture.js +17 -0
  78. package/dist/hitl/automaticAnswerVerdict.d.ts +21 -0
  79. package/dist/hitl/automaticAnswerVerdict.js +143 -0
  80. package/dist/hitl/crashConverged.d.ts +1 -0
  81. package/dist/hitl/crashConverged.js +1 -1
  82. package/dist/hitl/frameRouter.d.ts +2 -0
  83. package/dist/hitl/frameRouter.js +73 -16
  84. package/dist/hitl/gateLedger.d.ts +7 -0
  85. package/dist/hitl/gateLedger.js +37 -5
  86. package/dist/hitl/hitlBridge.d.ts +1 -0
  87. package/dist/hitl/hitlBridge.js +6 -1
  88. package/dist/hitl/hitlHostSurface.d.ts +5 -2
  89. package/dist/hitl/hitlHostSurface.js +25 -3
  90. package/dist/hitl/livePendingAsk.js +24 -5
  91. package/dist/hitl/parkResolver.js +24 -4
  92. package/dist/hitl/persistedRulesWire.d.ts +4 -1
  93. package/dist/hitl/persistedRulesWire.js +38 -19
  94. package/dist/hitl/planReviewWire.d.ts +0 -2
  95. package/dist/hitl/planReviewWire.js +3 -20
  96. package/dist/hitl/replayedApproval.d.ts +21 -0
  97. package/dist/hitl/replayedApproval.js +89 -0
  98. package/dist/hitl/sessionPolicyDeliverable.js +20 -2
  99. package/dist/hitl/sessionPolicyWire.d.ts +10 -0
  100. package/dist/hitl/sessionPolicyWire.js +19 -6
  101. package/dist/hitl/toolApprovalWire.d.ts +27 -7
  102. package/dist/hitl/toolApprovalWire.js +153 -94
  103. package/dist/hookMatcherVerdict.js +2 -1
  104. package/dist/hooksWireCaps.d.ts +1 -1
  105. package/dist/hooksWireCaps.js +1 -1
  106. package/dist/humanTurn.js +3 -4
  107. package/dist/index.d.ts +21 -6
  108. package/dist/index.js +17 -4
  109. package/dist/inheritEnvWire.d.ts +1 -4
  110. package/dist/inheritEnvWire.js +3 -22
  111. package/dist/limitsWire.d.ts +0 -6
  112. package/dist/limitsWire.js +0 -38
  113. package/dist/mcpLiveness.js +2 -1
  114. package/dist/mcpProbeCapability.js +1 -1
  115. package/dist/mcpProbeWire.js +10 -12
  116. package/dist/mcpReconnect.d.ts +5 -0
  117. package/dist/mcpReconnect.js +28 -0
  118. package/dist/memoryComplianceCapability.js +2 -2
  119. package/dist/memoryOriginCapability.js +2 -2
  120. package/dist/memoryVerbsWire.d.ts +1 -1
  121. package/dist/memoryVerbsWire.js +17 -13
  122. package/dist/model/catalog.js +2 -1
  123. package/dist/model/providerPresets.d.ts +3 -1
  124. package/dist/model/tierVocabulary.d.ts +2 -1
  125. package/dist/model/tierVocabulary.js +3 -8
  126. package/dist/ownKey.d.ts +2 -0
  127. package/dist/ownKey.js +15 -0
  128. package/dist/peerFrames.js +2 -2
  129. package/dist/peerLaneCapability.js +2 -2
  130. package/dist/permissionModesCapability.d.ts +16 -0
  131. package/dist/permissionModesCapability.js +71 -0
  132. package/dist/permissionRuleIssue.js +10 -7
  133. package/dist/permissionRulesWriteCapability.js +2 -2
  134. package/dist/permissionWireCaps.d.ts +2 -0
  135. package/dist/permissionWireCaps.js +8 -1
  136. package/dist/permissionsAllowGrantCapability.js +7 -2
  137. package/dist/permissionsDeclaration.d.ts +7 -1
  138. package/dist/permissionsDeclaration.js +29 -20
  139. package/dist/pluginHooksWire.js +2 -11
  140. package/dist/postureKnob.js +1 -1
  141. package/dist/promptProfileWireCaps.d.ts +2 -1
  142. package/dist/protocolSegment.d.ts +11 -0
  143. package/dist/protocolSegment.js +31 -0
  144. package/dist/readFacePosture.js +1 -1
  145. package/dist/request/taskRequest.js +1 -15
  146. package/dist/resumeRefusalCopy.d.ts +1 -0
  147. package/dist/resumeRefusalCopy.js +26 -3
  148. package/dist/retryStatus.js +2 -1
  149. package/dist/rewindArchiveCapability.js +2 -2
  150. package/dist/ruleCompileVerdict.d.ts +2 -0
  151. package/dist/ruleCompileVerdict.js +13 -0
  152. package/dist/ruleRemovalConsequence.d.ts +2 -1
  153. package/dist/runCancelContext.d.ts +12 -0
  154. package/dist/runCancelContext.js +83 -1
  155. package/dist/runTerminal.d.ts +16 -0
  156. package/dist/runTerminal.js +32 -3
  157. package/dist/seam.d.ts +1 -0
  158. package/dist/seam.js +1 -1
  159. package/dist/seatContract.d.ts +2 -1
  160. package/dist/sessionMemoryStatus.d.ts +2 -4
  161. package/dist/sessionPolicyCapability.js +1 -1
  162. package/dist/sessionSyncFileHistoryCapability.d.ts +18 -0
  163. package/dist/sessionSyncFileHistoryCapability.js +50 -0
  164. package/dist/skillToolListsCapability.d.ts +18 -0
  165. package/dist/skillToolListsCapability.js +50 -0
  166. package/dist/sqlEngineCapability.js +2 -9
  167. package/dist/steerPriorityCapability.d.ts +18 -0
  168. package/dist/steerPriorityCapability.js +80 -0
  169. package/dist/steerReceipt.d.ts +9 -0
  170. package/dist/steerReceipt.js +25 -0
  171. package/dist/storePostureCapability.js +2 -2
  172. package/dist/subagent/engineSubagentSteer.js +2 -9
  173. package/dist/supportFloor.d.ts +1 -0
  174. package/dist/supportFloor.js +15 -5
  175. package/dist/taskRequestWords.d.ts +4 -2
  176. package/dist/taskRequestWords.js +1 -1
  177. package/dist/toolHistoryBadTurn.js +1 -2
  178. package/dist/toolResult.d.ts +10 -1
  179. package/dist/toolResult.js +80 -6
  180. package/dist/types/engineState.d.ts +2 -12
  181. package/dist/userInvokedSkillsCapability.d.ts +18 -0
  182. package/dist/userInvokedSkillsCapability.js +50 -0
  183. package/dist/webSearchBackendCapability.js +2 -2
  184. package/dist/webSearchWireCaps.d.ts +1 -1
  185. package/dist/webSearchWireCaps.js +40 -2
  186. package/dist/wireFailureShape.d.ts +2 -0
  187. package/dist/wireFailureShape.js +6 -2
  188. package/dist/wireRefusalCopy.d.ts +9 -3
  189. package/dist/wireRefusalCopy.js +41 -4
  190. package/dist/workflowsJournalCapability.d.ts +18 -0
  191. package/dist/workflowsJournalCapability.js +50 -0
  192. package/dist/writeProtectionCapability.d.ts +2 -4
  193. package/dist/writeProtectionCapability.js +1 -1
  194. package/docs/INTEGRATION-CLIENTS.md +1516 -18
  195. package/package.json +2 -2
@@ -1,60 +1,14 @@
1
1
  import { hostEnv } from './hostEnv.js';
2
2
  import { envFlagOff } from './envFlag.js';
3
- import { versionSupportsLimits } from './limitsWire.js';
4
3
  import { resolveWireAuth } from './engineWireSdk.js';
5
4
  export const DETACH_HEADER = 'x-detach-on-disconnect';
6
5
  export const HEADLESS_DETACH_ENV = 'SEMA_HEADLESS_DETACH';
7
- export const DETACH_WIRE_MIN_ENGINE = [1, 196, 0];
8
- export const versionSupportsDetach = versionSupportsLimits;
9
6
  export function headlessDetachDisabledByEnv(env = hostEnv()) {
10
7
  return envFlagOff(env[HEADLESS_DETACH_ENV]);
11
8
  }
12
- export async function probeEngineDetachSupport(baseUrl, opts) {
13
- const fetchImpl = opts?.fetchImpl ?? fetch;
14
- const controller = new AbortController();
15
- const timer = setTimeout(() => controller.abort(), opts?.timeoutMs ?? 1500);
16
- try {
17
- const res = await fetchImpl(`${baseUrl.replace(/\/+$/, '')}/health`, {
18
- method: 'GET',
19
- signal: controller.signal,
20
- });
21
- if (!res.ok)
22
- return 'unknown';
23
- const body = await res.json();
24
- if (body === null || typeof body !== 'object' || Array.isArray(body))
25
- return 'unknown';
26
- if (!('version' in body))
27
- return 'unsupported';
28
- const version = body.version;
29
- if (typeof version !== 'string' || !/^\d+\.\d+\.\d+/.test(version))
30
- return 'unknown';
31
- if (versionSupportsDetach(version))
32
- return 'supported';
33
- return 'unsupported';
34
- }
35
- catch {
36
- return 'unknown';
37
- }
38
- finally {
39
- clearTimeout(timer);
40
- }
41
- }
42
- export function detachSupportDisclosure(support) {
43
- if (support !== 'unknown')
44
- return undefined;
45
- return 'could not confirm whether this engine supports detach (its /health did not answer usably); sending the detach header anyway — it is harmless on the wire, and a dead engine fails the request loudly';
46
- }
47
- export async function engineSupportsDetach(baseUrl, opts) {
48
- return (await probeEngineDetachSupport(baseUrl, opts)) !== 'unsupported';
49
- }
50
- export async function resolveHeadlessDetach(baseUrl, env = hostEnv(), opts) {
9
+ export async function resolveHeadlessDetach(_baseUrl, env = hostEnv(), _opts) {
51
10
  if (headlessDetachDisabledByEnv(env))
52
11
  return { on: false, reason: 'env-off' };
53
- if (env.SEMA_ENGINE_URL) {
54
- const ok = await engineSupportsDetach(baseUrl, opts);
55
- if (!ok)
56
- return { on: false, reason: 'old-engine' };
57
- }
58
12
  return { on: true, reason: 'default-on' };
59
13
  }
60
14
  export const DETACH_DURABLE_OFF_400_ANCHOR = 'x-detach-on-disconnect requires a durable run';
@@ -2,12 +2,15 @@ export type DeviceExecutorManagementReading = {
2
2
  kind: 'unobserved';
3
3
  } | {
4
4
  kind: 'not_reported';
5
- why: 'capability_absent' | 'management_absent';
5
+ why: 'capability_absent';
6
6
  } | {
7
7
  kind: 'lane_absent';
8
8
  } | {
9
9
  kind: 'present';
10
- management: boolean;
10
+ management: 'present-true' | 'present-false' | 'absent';
11
+ protocolVersion?: number;
12
+ maxInflightPerDevice?: number;
13
+ wsPath?: string;
11
14
  };
12
15
  export declare function projectDeviceExecutorManagementCapability(caps: unknown): DeviceExecutorManagementReading | undefined;
13
16
  export declare function noteEngineCapsForDeviceExecutorManagement(baseUrl: string, caps: unknown, opts?: {
@@ -15,6 +18,7 @@ export declare function noteEngineCapsForDeviceExecutorManagement(baseUrl: strin
15
18
  }): void;
16
19
  export declare function observedDeviceExecutorManagement(baseUrl?: string | undefined): DeviceExecutorManagementReading;
17
20
  export declare function deviceManagementVerbsAvailable(reading: DeviceExecutorManagementReading): 'yes' | 'no' | 'unknown';
21
+ export declare function deviceLaneOpen(reading: DeviceExecutorManagementReading): 'yes' | 'no' | 'unknown';
18
22
  export declare function deviceExecutorManagementDoctorDetail(reading: DeviceExecutorManagementReading): string;
19
23
  export declare function forgetDeviceExecutorManagementReading(baseUrl: string | undefined): void;
20
24
  export declare function __resetDeviceExecutorManagementReadingsForTests(): void;
@@ -1,5 +1,9 @@
1
1
  import { engineWireTarget } from './engineWireTarget.js';
2
2
  import { createEngineCapReader } from './engineCapReader.js';
3
+ import { capForDisplay } from './fleetTaskDesc.js';
4
+ function ownRead(o, key) {
5
+ return Object.hasOwn(o, key) ? o[key] : undefined;
6
+ }
3
7
  export function projectDeviceExecutorManagementCapability(caps) {
4
8
  if (caps === null || typeof caps !== 'object' || Array.isArray(caps))
5
9
  return undefined;
@@ -14,14 +18,28 @@ export function projectDeviceExecutorManagementCapability(caps) {
14
18
  if (d === null || typeof d !== 'object' || Array.isArray(d))
15
19
  return undefined;
16
20
  const o = d;
17
- if (!Object.hasOwn(o, 'management'))
18
- return { kind: 'not_reported', why: 'management_absent' };
19
- const mgmt = o.management;
21
+ if (ownRead(o, 'enabled') !== true)
22
+ return undefined;
23
+ const mgmt = ownRead(o, 'management');
24
+ let management;
20
25
  if (mgmt === undefined)
21
- return { kind: 'not_reported', why: 'management_absent' };
22
- if (typeof mgmt !== 'boolean')
26
+ management = 'absent';
27
+ else if (mgmt === true)
28
+ management = 'present-true';
29
+ else if (mgmt === false)
30
+ management = 'present-false';
31
+ else
23
32
  return undefined;
24
- return { kind: 'present', management: mgmt };
33
+ const pv = ownRead(o, 'protocolVersion');
34
+ const mi = ownRead(o, 'maxInflightPerDevice');
35
+ const ws = ownRead(o, 'wsPath');
36
+ return {
37
+ kind: 'present',
38
+ management,
39
+ ...(typeof pv === 'number' && Number.isFinite(pv) ? { protocolVersion: pv } : {}),
40
+ ...(typeof mi === 'number' && Number.isFinite(mi) && mi >= 0 ? { maxInflightPerDevice: mi } : {}),
41
+ ...(typeof ws === 'string' && ws.length > 0 ? { wsPath: ws } : {}),
42
+ };
25
43
  }
26
44
  const reader = createEngineCapReader({
27
45
  name: 'deviceExecutor.management',
@@ -35,26 +53,54 @@ export function observedDeviceExecutorManagement(baseUrl = engineWireTarget()?.b
35
53
  return reader.observed(baseUrl);
36
54
  }
37
55
  export function deviceManagementVerbsAvailable(reading) {
56
+ if (reading.kind === 'present') {
57
+ if (reading.management === 'present-true')
58
+ return 'yes';
59
+ if (reading.management === 'present-false')
60
+ return 'no';
61
+ return 'unknown';
62
+ }
63
+ if (reading.kind === 'lane_absent')
64
+ return 'no';
65
+ return 'unknown';
66
+ }
67
+ export function deviceLaneOpen(reading) {
38
68
  if (reading.kind === 'present')
39
- return reading.management ? 'yes' : 'no';
69
+ return 'yes';
40
70
  if (reading.kind === 'lane_absent')
41
71
  return 'no';
42
72
  return 'unknown';
43
73
  }
74
+ const WS_PATH_DETAIL_MAX = 64;
75
+ function laneFactsSuffix(r) {
76
+ const parts = [];
77
+ if (r.protocolVersion !== undefined)
78
+ parts.push(`protocol ${r.protocolVersion}`);
79
+ if (r.maxInflightPerDevice !== undefined)
80
+ parts.push(`${r.maxInflightPerDevice} in flight per device`);
81
+ if (r.wsPath !== undefined)
82
+ parts.push(`ws path ${capForDisplay(r.wsPath, WS_PATH_DETAIL_MAX)}`);
83
+ return parts.length === 0 ? '' : ` (${parts.join(', ')})`;
84
+ }
44
85
  export function deviceExecutorManagementDoctorDetail(reading) {
45
86
  switch (reading.kind) {
46
87
  case 'unobserved':
47
- return 'device management face not observed — the engine reports it on /v1/capabilities (deviceExecutor.management); this process has no usable capabilities reading cached for it (none received, or the last one was unreadable)';
88
+ return 'device management face not observed — the engine reports it on /v1/capabilities (deviceExecutor.management); 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)';
48
89
  case 'not_reported':
49
- return reading.why === 'management_absent'
50
- ? 'device management face not reported by this engine — the device lane is advertised but only newer engines say whether the /v1/devices management verbs exist; this does not say whether they exist, probe them directly'
51
- : 'device executor capability not reported by this engine — only newer engines advertise the device lane at all; this does not say whether it exists';
90
+ return 'device executor capability not reported by this engine; this does not say whether a device lane exists';
52
91
  case 'lane_absent':
53
92
  return 'no device lane on this deployment — the /v1/devices management verbs are unavailable (capability.device_lane_required)';
54
- case 'present':
55
- return reading.management
56
- ? 'device management face on — the /v1/devices management verbs are available on this engine'
57
- : 'device lane on but the /v1/devices management verbs are off on this deployment';
93
+ case 'present': {
94
+ const facts = laneFactsSuffix(reading);
95
+ switch (reading.management) {
96
+ case 'present-true':
97
+ return `device management face on — the /v1/devices management verbs are available on this engine${facts}`;
98
+ case 'present-false':
99
+ return `device lane on but the /v1/devices management verbs are off on this deployment${facts}`;
100
+ case 'absent':
101
+ return `device lane on, but this engine does not report the /v1/devices management face; this does not say whether the management verbs exist, probe them directly${facts}`;
102
+ }
103
+ }
58
104
  }
59
105
  }
60
106
  export function forgetDeviceExecutorManagementReading(baseUrl) {
@@ -1,3 +1,4 @@
1
+ import { SETTINGS_SECRET_LITERAL_RE } from './generated/settingsSchemaTables.js';
1
2
  export const REDACTION_MARKER_PREFIX = '\u00abredacted';
2
3
  const MARKER_RE = /^\u00abredacted(?::[a-z-]{1,16}){0,2}\u00bb$/;
3
4
  const REDACTED_USERINFO = '\u00abredacted:userinfo\u00bb';
@@ -26,7 +27,7 @@ function pushEdit(edits, src, start, end, text) {
26
27
  const UNIT_NONE = 0;
27
28
  const UNIT_SEQUENCE = 1;
28
29
  const UNIT_SINGLE = 2;
29
- const SECRET_LITERAL_RE = /^(sk-|gh[opus]_|github_pat_|xox[baprse]-|xapp-|bearer\s|basic\s|eyJ[A-Za-z0-9_-]{10,}\.|AKIA[0-9A-Z]{12,}|AIza[0-9A-Za-z_-]{20,}|-----BEGIN[A-Z0-9 ]*PRIVATE KEY)/i;
30
+ const SECRET_LITERAL_RE = SETTINGS_SECRET_LITERAL_RE;
30
31
  const SCHEME_TOKEN_RE = /(?:^|[^A-Za-z0-9_-])(?:bearer|basic)[ \t]+\S{8,4096}/i;
31
32
  const JWT_RE = /(?:^|[^A-Za-z0-9_-])eyJ[A-Za-z0-9_-]{8,2048}\.[A-Za-z0-9_-]{8,2048}\.[A-Za-z0-9_-]{4,2048}/i;
32
33
  function scanForSecretLiteral(s) {
@@ -7,15 +7,25 @@ export interface EffectiveReasoningView {
7
7
  endpoint: string;
8
8
  dropped?: true;
9
9
  }
10
+ export type EffectiveMemoryProjectKey = {
11
+ readonly scope: string;
12
+ readonly absent?: never;
13
+ } | {
14
+ readonly absent: string;
15
+ readonly scope?: never;
16
+ };
17
+ export interface EffectiveMemoryScopeRow {
18
+ scope: string;
19
+ origin: 'deployment' | 'request';
20
+ shadowed?: number;
21
+ }
10
22
  export interface EffectiveMemoryScopesView {
11
23
  state: 'mounted' | 'memoryless' | 'none';
12
24
  reason?: string;
13
25
  contract?: 'v2' | 'legacy';
14
- scopes: readonly {
15
- scope: string;
16
- origin: 'deployment' | 'request';
17
- }[];
26
+ scopes: readonly EffectiveMemoryScopeRow[];
18
27
  writeScope: string | null;
28
+ projectKey?: EffectiveMemoryProjectKey;
19
29
  materializedResidue?: readonly string[];
20
30
  }
21
31
  export declare function readEffectiveReasoning(v: unknown): EffectiveReasoningView | undefined;
@@ -1,4 +1,37 @@
1
1
  const nonEmpty = (v) => typeof v === 'string' && v.length > 0;
2
+ const nonBlank = (v) => typeof v === 'string' && v.trim().length > 0;
3
+ const UNREADABLE = Symbol('unreadable');
4
+ const protectedRead = (o, key) => {
5
+ try {
6
+ return o[key];
7
+ }
8
+ catch {
9
+ return UNREADABLE;
10
+ }
11
+ };
12
+ function readProjectKey(v) {
13
+ try {
14
+ if (typeof v !== 'object' || v === null || Array.isArray(v))
15
+ return undefined;
16
+ const o = v;
17
+ const scope = protectedRead(o, 'scope');
18
+ const absent = protectedRead(o, 'absent');
19
+ if (scope === UNREADABLE || absent === UNREADABLE)
20
+ return undefined;
21
+ if ((scope === undefined) === (absent === undefined))
22
+ return undefined;
23
+ if (scope !== undefined)
24
+ return nonBlank(scope) ? { scope } : undefined;
25
+ return nonBlank(absent) ? { absent } : undefined;
26
+ }
27
+ catch {
28
+ return undefined;
29
+ }
30
+ }
31
+ function readShadowed(r, isWriteHome) {
32
+ const n = protectedRead(r, 'shadowed');
33
+ return !isWriteHome && typeof n === 'number' && Number.isSafeInteger(n) && n > 0 ? n : undefined;
34
+ }
2
35
  export function readEffectiveReasoning(v) {
3
36
  if (typeof v !== 'object' || v === null)
4
37
  return undefined;
@@ -27,7 +60,8 @@ export function readEffectiveMemoryScopes(v) {
27
60
  return undefined;
28
61
  if (!Array.isArray(o.scopes))
29
62
  return undefined;
30
- if (o.writeScope !== null && typeof o.writeScope !== 'string')
63
+ const writeScope = o.writeScope;
64
+ if (writeScope !== null && typeof writeScope !== 'string')
31
65
  return undefined;
32
66
  const contract = o.contract === 'v2' || o.contract === 'legacy' ? o.contract : undefined;
33
67
  const reason = nonEmpty(o.reason) ? o.reason : undefined;
@@ -39,13 +73,19 @@ export function readEffectiveMemoryScopes(v) {
39
73
  if (typeof row !== 'object' || row === null)
40
74
  continue;
41
75
  const r = row;
42
- if (!nonEmpty(r.scope) || typeof r.origin !== 'string' || !ORIGINS.has(r.origin))
76
+ const scope = r.scope;
77
+ if (!nonEmpty(scope))
78
+ continue;
79
+ const origin = r.origin;
80
+ if (typeof origin !== 'string' || !ORIGINS.has(origin))
43
81
  continue;
44
- scopes.push({ scope: r.scope, origin: r.origin });
82
+ const shadowed = readShadowed(r, scope === writeScope);
83
+ scopes.push({ scope, origin: origin, ...(shadowed !== undefined ? { shadowed } : {}) });
45
84
  }
46
- return { state: 'mounted', contract, scopes, writeScope: o.writeScope };
85
+ const projectKey = readProjectKey(protectedRead(o, 'projectKey'));
86
+ return { state: 'mounted', contract, scopes, writeScope, ...(projectKey !== undefined ? { projectKey } : {}) };
47
87
  }
48
- if (o.scopes.length !== 0 || o.writeScope !== null)
88
+ if (o.scopes.length !== 0 || writeScope !== null)
49
89
  return undefined;
50
90
  if (o.state === 'memoryless') {
51
91
  if (reason !== 'mount-failed' && reason !== 'no-backend')
@@ -2,6 +2,7 @@ import { registryClockNowMs, registryListingProvenanceOf } from './agentSession/
2
2
  import { displayUntrusted } from './displayUntrusted.js';
3
3
  import { ABSENT_SETTLE_MS } from './fleetAgentPanelProjection.js';
4
4
  import { isEnginePanelTaskResident, isStaleEngineAgentPanelEnd, } from './engineAgentPanelStore.js';
5
+ import { CORE_DURABLE_AGENT_HANDLE_RE } from './generated/engineFactTables.js';
5
6
  export const ENGINE_AGENT_ABSENT_ROW_TEXT = 'engine no longer reports this agent · it may still be running';
6
7
  export const ENGINE_AGENT_ABSENCE_TTL_MS = 30 * 60_000;
7
8
  function effectiveTtl(ttlMs) {
@@ -132,7 +133,7 @@ export function engineAgentTerminalAfterDropLine(label, status, hasReport) {
132
133
  return `${displayUntrusted(label)} reported ${displayUntrusted(status)} after it was dropped from the task panel${tail}`;
133
134
  }
134
135
  const REGISTRY_LIST_LIMIT = 500;
135
- const REGISTRY_AGENT_HANDLE_RE = /^a[0-9a-f]{6,32}$/;
136
+ const REGISTRY_AGENT_HANDLE_RE = CORE_DURABLE_AGENT_HANDLE_RE;
136
137
  const REGISTRY_AGENT_TYPE = 'background_agent';
137
138
  function registryStatusReading(status) {
138
139
  const s = status;
@@ -1,4 +1,5 @@
1
1
  import { snapshotCapsGeneration, capsGenerationStillCurrent } from './engineCapsGenerationGuard.js';
2
+ import { capsGenerationMarkOf, retainCapsGenerationMark } from './engineCapsCache.js';
2
3
  function freezeReading(reading, seen = new Set()) {
3
4
  if (reading === null || typeof reading !== 'object' || seen.has(reading))
4
5
  return reading;
@@ -11,7 +12,7 @@ function freezeReading(reading, seen = new Set()) {
11
12
  return reading;
12
13
  }
13
14
  export function createEngineCapReader(spec) {
14
- const readingByBase = new Map();
15
+ const cellByBase = new Map();
15
16
  return {
16
17
  note(baseUrl, caps, opts) {
17
18
  if (typeof baseUrl !== 'string' || baseUrl === '')
@@ -21,6 +22,7 @@ export function createEngineCapReader(spec) {
21
22
  return;
22
23
  if (!capsGenerationStillCurrent(baseUrl, gen))
23
24
  return;
25
+ const mark = retainCapsGenerationMark(baseUrl);
24
26
  let reading;
25
27
  try {
26
28
  reading = spec.project(caps);
@@ -28,29 +30,33 @@ export function createEngineCapReader(spec) {
28
30
  catch {
29
31
  reading = undefined;
30
32
  }
31
- if (!capsGenerationStillCurrent(baseUrl, gen))
33
+ if (capsGenerationMarkOf(baseUrl) !== mark)
32
34
  return;
33
35
  if (reading === undefined) {
34
- readingByBase.delete(baseUrl);
36
+ cellByBase.delete(baseUrl);
35
37
  return;
36
38
  }
37
- readingByBase.set(baseUrl, freezeReading(reading));
39
+ cellByBase.set(baseUrl, { reading: freezeReading(reading), mark });
38
40
  },
39
41
  observed(baseUrl) {
40
42
  if (typeof baseUrl !== 'string' || baseUrl === '')
41
43
  return spec.makeUnobserved();
42
- const hit = readingByBase.get(baseUrl);
43
- if (hit !== undefined)
44
- return hit;
45
- return spec.makeUnobserved();
44
+ const cell = cellByBase.get(baseUrl);
45
+ if (cell === undefined)
46
+ return spec.makeUnobserved();
47
+ if (cell.mark !== capsGenerationMarkOf(baseUrl)) {
48
+ cellByBase.delete(baseUrl);
49
+ return spec.makeUnobserved();
50
+ }
51
+ return cell.reading;
46
52
  },
47
53
  forget(baseUrl) {
48
54
  if (typeof baseUrl !== 'string' || baseUrl === '')
49
55
  return;
50
- readingByBase.delete(baseUrl);
56
+ cellByBase.delete(baseUrl);
51
57
  },
52
58
  __resetForTests() {
53
- readingByBase.clear();
59
+ cellByBase.clear();
54
60
  },
55
61
  };
56
62
  }
@@ -1,4 +1,6 @@
1
1
  export declare function engineCapsGeneration(baseUrl: string): number;
2
+ export declare function capsGenerationMarkOf(baseUrl: string): object | undefined;
3
+ export declare function retainCapsGenerationMark(baseUrl: string): object;
2
4
  export declare function kickEngineCapsProbe(baseUrl: string, probe: () => Promise<unknown>): void;
3
5
  export declare function engineCapsSettled(baseUrl: string | undefined, opts?: {
4
6
  withinMs?: number;
@@ -3,11 +3,22 @@ const inFlight = new Set();
3
3
  const settleByBase = new Map();
4
4
  const genByBase = new Map();
5
5
  function capsGeneration(baseUrl) {
6
- return genByBase.get(baseUrl) ?? 0;
6
+ return genByBase.get(baseUrl)?.n ?? 0;
7
7
  }
8
8
  export function engineCapsGeneration(baseUrl) {
9
9
  return capsGeneration(baseUrl);
10
10
  }
11
+ export function capsGenerationMarkOf(baseUrl) {
12
+ return genByBase.get(baseUrl);
13
+ }
14
+ export function retainCapsGenerationMark(baseUrl) {
15
+ let mark = genByBase.get(baseUrl);
16
+ if (mark === undefined) {
17
+ mark = Object.freeze({ n: 0 });
18
+ genByBase.set(baseUrl, mark);
19
+ }
20
+ return mark;
21
+ }
11
22
  export function kickEngineCapsProbe(baseUrl, probe) {
12
23
  if (!baseUrl || capsByBase.has(baseUrl) || inFlight.has(baseUrl))
13
24
  return;
@@ -165,7 +176,7 @@ export function invalidateEngineCaps(baseUrl, probe) {
165
176
  settleByBase.has(baseUrl) ||
166
177
  genByBase.has(baseUrl);
167
178
  if (hadState) {
168
- genByBase.set(baseUrl, capsGeneration(baseUrl) + 1);
179
+ genByBase.set(baseUrl, Object.freeze({ n: capsGeneration(baseUrl) + 1 }));
169
180
  capsByBase.delete(baseUrl);
170
181
  inFlight.delete(baseUrl);
171
182
  settleByBase.get(baseUrl)?.wake();
@@ -0,0 +1,20 @@
1
+ import type { HealthResponse } from './types/engineState.js';
2
+ export interface EngineConfigApplyState {
3
+ readonly configTargetOrdinal: number;
4
+ readonly configAppliedOrdinal: number;
5
+ readonly configTargetVersion?: number;
6
+ readonly configAppliedVersion?: number;
7
+ readonly configApplyStaleMs?: number;
8
+ }
9
+ export declare function readEngineConfigApplyState(health: unknown): EngineConfigApplyState | null;
10
+ export type ConfigDriftVerdict = 'skip' | 'in-sync' | 'ask' | 'advance-baseline';
11
+ export interface ConfigDriftHealthView extends Pick<HealthResponse, 'configHash' | 'instanceId' | 'restartRequired'> {
12
+ configTargetOrdinal?: number | undefined;
13
+ configAppliedOrdinal?: number | undefined;
14
+ }
15
+ export interface ConfigDriftInput {
16
+ baselineConfigHash?: string | undefined;
17
+ baselineInstanceId?: string | undefined;
18
+ health?: ConfigDriftHealthView | undefined;
19
+ }
20
+ export declare function configDriftVerdict(input: ConfigDriftInput): ConfigDriftVerdict;
@@ -0,0 +1,54 @@
1
+ function countOf(v) {
2
+ return typeof v === 'number' && Number.isInteger(v) && v >= 0 ? v : undefined;
3
+ }
4
+ function ownValue(o, key) {
5
+ const d = Object.getOwnPropertyDescriptor(o, key);
6
+ return d !== undefined && 'value' in d ? d.value : undefined;
7
+ }
8
+ export function readEngineConfigApplyState(health) {
9
+ try {
10
+ if (typeof health !== 'object' || health === null || Array.isArray(health))
11
+ return null;
12
+ const configTargetOrdinal = countOf(ownValue(health, 'configTargetOrdinal'));
13
+ const configAppliedOrdinal = countOf(ownValue(health, 'configAppliedOrdinal'));
14
+ if (configTargetOrdinal === undefined || configAppliedOrdinal === undefined)
15
+ return null;
16
+ const configTargetVersion = countOf(ownValue(health, 'configTargetVersion'));
17
+ const configAppliedVersion = countOf(ownValue(health, 'configAppliedVersion'));
18
+ const configApplyStaleMs = countOf(ownValue(health, 'configApplyStaleMs'));
19
+ return {
20
+ configTargetOrdinal,
21
+ configAppliedOrdinal,
22
+ ...(configTargetVersion !== undefined && configAppliedVersion !== undefined ? { configTargetVersion, configAppliedVersion } : {}),
23
+ ...(configApplyStaleMs !== undefined ? { configApplyStaleMs } : {}),
24
+ };
25
+ }
26
+ catch {
27
+ return null;
28
+ }
29
+ }
30
+ export function configDriftVerdict(input) {
31
+ try {
32
+ const { baselineConfigHash, baselineInstanceId, health } = input;
33
+ const view = typeof health === 'object' && health !== null ? health : undefined;
34
+ if (view !== undefined && ownValue(view, 'restartRequired') === true)
35
+ return 'ask';
36
+ const hashRaw = view === undefined ? undefined : ownValue(view, 'configHash');
37
+ const nowHash = typeof hashRaw === 'string' ? hashRaw : undefined;
38
+ if (!baselineConfigHash || !nowHash)
39
+ return 'skip';
40
+ if (nowHash === baselineConfigHash)
41
+ return 'in-sync';
42
+ const instanceRaw = view === undefined ? undefined : ownValue(view, 'instanceId');
43
+ const nowInstance = typeof instanceRaw === 'string' ? instanceRaw : undefined;
44
+ if (!baselineInstanceId || !nowInstance || nowInstance !== baselineInstanceId)
45
+ return 'ask';
46
+ const apply = readEngineConfigApplyState(view);
47
+ if (apply === null)
48
+ return 'ask';
49
+ return apply.configTargetOrdinal === apply.configAppliedOrdinal ? 'advance-baseline' : 'ask';
50
+ }
51
+ catch {
52
+ return 'ask';
53
+ }
54
+ }
@@ -14,6 +14,8 @@ export declare const CONFIG_DELEGATION_ENTRY_CAPS = "config.delegation_entry_cap
14
14
  export declare const CONFIG_MEMORY_PROJECT_KEY_SPELLING = "config.memory_project_key_spelling";
15
15
  export declare const CONFIG_MEMORY_WRITE_SCOPE_MISMATCH = "config.memory_write_scope_mismatch";
16
16
  export declare const CONFIG_LEGACY_TOOL_NAME = "config.legacy_tool_name";
17
+ export declare const CONFIG_IMAGE_INVALID = "config.image_invalid";
18
+ export declare function imageInvalidFailureNoteOf(code: string | undefined): string | undefined;
17
19
  export declare const CONFIG_REFUSAL_CODES: ReadonlySet<string>;
18
20
  export declare const RULES_LEGACY_TOOL_NAME = "rules.legacy_tool_name";
19
21
  export declare function isRulesRefusalCode(code: string | undefined): boolean;
@@ -63,16 +65,31 @@ export declare const RESUME_REOPEN_CODES: readonly string[];
63
65
  export declare const PARKED_RESUME_STARTUP_FAILED = "parked_resume.startup_failed";
64
66
  export declare const DECIDE_WORKFLOW_HOST_UNKNOWN = "decide.workflow_host_unknown";
65
67
  export declare const DECIDE_WORKFLOW_REMEMBER_UNSUPPORTED = "decide.workflow_remember_unsupported";
68
+ export declare const DECIDE_WORKFLOW_PARK_FORKED = "decide.workflow_park_forked";
69
+ export declare const DECIDE_WORKFLOW_PARKS_UNREADABLE = "decide.workflow_parks_unreadable";
66
70
  export declare const DECIDE_WORKFLOW_LANE_CODES: readonly string[];
67
71
  export declare const DECIDE_NOT_PARKED = "decide.not_parked";
68
72
  export declare const DECIDE_GATE_MOVED = "decide.gate_moved";
69
73
  export declare const DECIDE_CLAIM_LOST = "decide.claim_lost";
70
74
  export declare const DECIDE_PARK_MOVED_CODES: readonly string[];
71
75
  export declare function isDecideParkMovedCode(code: string | null | undefined): boolean;
76
+ export declare const ASK_GONE = "gone.ask";
77
+ export declare const ASK_GONE_DENIED_WORD = "routing_failure_fail_closed";
78
+ export declare const RUN_STALLED = "run.stalled";
79
+ export declare const RUN_ORPHANED = "run.orphaned";
80
+ export declare const APPROVAL_EXPIRED = "approval.expired";
81
+ export declare const RUN_DEATH_VERDICT_CODES: readonly ["run.stalled", "run.orphaned", "approval.expired"];
82
+ export type RunDeathVerdictCode = (typeof RUN_DEATH_VERDICT_CODES)[number];
83
+ export declare function runDeathVerdictNoteOf(code: string | undefined): string | undefined;
84
+ export declare const CAPABILITY_OPERATOR_PRINCIPALS_REQUIRED = "capability.operator_principals_required";
85
+ export declare function isUnavailableFaceCode(code: string | undefined): boolean;
86
+ export type OperatorGateRefusal = 'operator_only' | 'operators_unconfigured';
87
+ export declare function operatorGateRefusalContent(cause: OperatorGateRefusal): string | undefined;
72
88
  export declare const WORKFLOW_PARK_REFUSAL_CODES: readonly string[];
73
89
  export declare function isWorkflowParkRefusalCode(code: unknown): boolean;
74
90
  export declare const DRAINING_ERROR_CODE = "draining";
75
91
  export declare const SCENARIO_NOT_ALLOWED_ERROR_CODE = "scenario_not_allowed";
92
+ export declare const SCENARIO_ASSIGNMENT_UNKNOWN_ERROR_CODE = "state.scenario_assignment_unknown";
76
93
  export declare const STREAM_MAX_DURATION = "STREAM_MAX_DURATION";
77
94
  export type ModelFallbackReason = 'inherit_no_tier_binding';
78
95
  export declare const MODEL_FALLBACK_INHERIT_NO_TIER_BINDING: ModelFallbackReason;
@@ -19,6 +19,12 @@ export const CONFIG_DELEGATION_ENTRY_CAPS = 'config.delegation_entry_caps';
19
19
  export const CONFIG_MEMORY_PROJECT_KEY_SPELLING = 'config.memory_project_key_spelling';
20
20
  export const CONFIG_MEMORY_WRITE_SCOPE_MISMATCH = 'config.memory_write_scope_mismatch';
21
21
  export const CONFIG_LEGACY_TOOL_NAME = 'config.legacy_tool_name';
22
+ export const CONFIG_IMAGE_INVALID = 'config.image_invalid';
23
+ const IMAGE_INVALID_FAILURE_NOTE = 'This run did not start: an image sent with the message was refused before the model was called — the engine’s own error text says which image and what is wrong with it. ' +
24
+ 'Nothing was sent to the model; remove or replace that image, then send the message again.';
25
+ export function imageInvalidFailureNoteOf(code) {
26
+ return code === CONFIG_IMAGE_INVALID ? IMAGE_INVALID_FAILURE_NOTE : undefined;
27
+ }
22
28
  export const CONFIG_REFUSAL_CODES = frozenSet([
23
29
  CONFIG_LIMIT_INVALID,
24
30
  CONFIG_STRATEGY_FIND_LIMIT_INVALID,
@@ -28,6 +34,7 @@ export const CONFIG_REFUSAL_CODES = frozenSet([
28
34
  CONFIG_MEMORY_PROJECT_KEY_SPELLING,
29
35
  CONFIG_MEMORY_WRITE_SCOPE_MISMATCH,
30
36
  CONFIG_LEGACY_TOOL_NAME,
37
+ CONFIG_IMAGE_INVALID,
31
38
  ...CORE_TOOL_DECLARATION_CODES,
32
39
  ]);
33
40
  export const RULES_LEGACY_TOOL_NAME = 'rules.legacy_tool_name';
@@ -134,9 +141,13 @@ export const RESUME_REOPEN_CODES = Object.freeze([
134
141
  export const PARKED_RESUME_STARTUP_FAILED = 'parked_resume.startup_failed';
135
142
  export const DECIDE_WORKFLOW_HOST_UNKNOWN = 'decide.workflow_host_unknown';
136
143
  export const DECIDE_WORKFLOW_REMEMBER_UNSUPPORTED = 'decide.workflow_remember_unsupported';
144
+ export const DECIDE_WORKFLOW_PARK_FORKED = 'decide.workflow_park_forked';
145
+ export const DECIDE_WORKFLOW_PARKS_UNREADABLE = 'decide.workflow_parks_unreadable';
137
146
  export const DECIDE_WORKFLOW_LANE_CODES = Object.freeze([
138
147
  DECIDE_WORKFLOW_HOST_UNKNOWN,
139
148
  DECIDE_WORKFLOW_REMEMBER_UNSUPPORTED,
149
+ DECIDE_WORKFLOW_PARKS_UNREADABLE,
150
+ DECIDE_WORKFLOW_PARK_FORKED,
140
151
  ]);
141
152
  export const DECIDE_NOT_PARKED = 'decide.not_parked';
142
153
  export const DECIDE_GATE_MOVED = 'decide.gate_moved';
@@ -149,6 +160,39 @@ export const DECIDE_PARK_MOVED_CODES = Object.freeze([
149
160
  export function isDecideParkMovedCode(code) {
150
161
  return typeof code === 'string' && DECIDE_PARK_MOVED_CODES.includes(code);
151
162
  }
163
+ export const ASK_GONE = 'gone.ask';
164
+ export const ASK_GONE_DENIED_WORD = 'routing_failure_fail_closed';
165
+ export const RUN_STALLED = 'run.stalled';
166
+ export const RUN_ORPHANED = 'run.orphaned';
167
+ export const APPROVAL_EXPIRED = 'approval.expired';
168
+ export const RUN_DEATH_VERDICT_CODES = Object.freeze([RUN_STALLED, RUN_ORPHANED, APPROVAL_EXPIRED]);
169
+ const RUN_HOLDER_LOST_OUTLET = 'The request itself was not at fault, but this run cannot be picked up again; submit the work again as a new task.';
170
+ const RUN_ORPHANED_NOTE = 'This run ended because the engine process that was running it went away (it was restarted) before the run finished. ' + RUN_HOLDER_LOST_OUTLET;
171
+ const RUN_STALLED_NOTE = 'This run ended because the engine process that was running it stopped reporting in before the run finished. ' + RUN_HOLDER_LOST_OUTLET;
172
+ const RUN_APPROVAL_EXPIRED_NOTE = 'This run ended because it was waiting on an approval for too long and the engine retired it. ' +
173
+ 'The request itself was not at fault, but this run cannot be picked up again; submit the work again as a new task, and it will ask for the approval again.';
174
+ export function runDeathVerdictNoteOf(code) {
175
+ if (code === RUN_ORPHANED)
176
+ return RUN_ORPHANED_NOTE;
177
+ if (code === RUN_STALLED)
178
+ return RUN_STALLED_NOTE;
179
+ if (code === APPROVAL_EXPIRED)
180
+ return RUN_APPROVAL_EXPIRED_NOTE;
181
+ return undefined;
182
+ }
183
+ export const CAPABILITY_OPERATOR_PRINCIPALS_REQUIRED = 'capability.operator_principals_required';
184
+ export function isUnavailableFaceCode(code) {
185
+ return typeof code === 'string' && (code.startsWith('capability.') || code.startsWith('feature.'));
186
+ }
187
+ export function operatorGateRefusalContent(cause) {
188
+ if (cause === 'operator_only') {
189
+ return 'Nothing was done: this is an operator-only action and the caller is not one of this deployment’s operators.';
190
+ }
191
+ if (cause === 'operators_unconfigured') {
192
+ return 'Nothing was done: this is an operator-only action and this deployment has no operators configured, so no caller can perform it here — whoever runs the deployment has to name its operators first.';
193
+ }
194
+ return undefined;
195
+ }
152
196
  const WORKFLOW_PARK_TRUTH_UNREADABLE = 'workflow.park_truth_unreadable';
153
197
  const WORKFLOW_PARK_NOT_PENDING = 'workflow.park_not_pending';
154
198
  const WORKFLOW_PARK_BINDING_BROKEN = 'workflow.park_binding_broken';
@@ -165,6 +209,7 @@ export function isWorkflowParkRefusalCode(code) {
165
209
  }
166
210
  export const DRAINING_ERROR_CODE = 'draining';
167
211
  export const SCENARIO_NOT_ALLOWED_ERROR_CODE = 'scenario_not_allowed';
212
+ export const SCENARIO_ASSIGNMENT_UNKNOWN_ERROR_CODE = 'state.scenario_assignment_unknown';
168
213
  export const STREAM_MAX_DURATION = 'STREAM_MAX_DURATION';
169
214
  export const MODEL_FALLBACK_INHERIT_NO_TIER_BINDING = 'inherit_no_tier_binding';
170
215
  export function asModelFallbackReason(v) {
@@ -4,6 +4,7 @@ export interface EngineInlineTaskStats {
4
4
  totalTokens: number;
5
5
  durationMs: number;
6
6
  currentAction?: string;
7
+ model?: string;
7
8
  done: boolean;
8
9
  isError: boolean;
9
10
  }