@openscout/protocol 0.2.64 → 0.2.82

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 (214) hide show
  1. package/LICENSE +202 -0
  2. package/README.md +103 -52
  3. package/dist/a2a.d.ts +224 -0
  4. package/dist/a2a.d.ts.map +1 -0
  5. package/dist/a2a.js +225 -0
  6. package/dist/activity.d.ts +70 -0
  7. package/dist/activity.d.ts.map +1 -0
  8. package/dist/activity.js +1 -0
  9. package/dist/actors.d.ts +7 -3
  10. package/dist/actors.d.ts.map +1 -0
  11. package/dist/actors.js +15 -1
  12. package/dist/agent-broker-feed.d.ts +84 -0
  13. package/dist/agent-broker-feed.d.ts.map +1 -0
  14. package/dist/agent-broker-feed.js +1 -0
  15. package/dist/agent-identity.d.ts +23 -0
  16. package/dist/agent-identity.d.ts.map +1 -0
  17. package/dist/agent-identity.js +122 -8
  18. package/dist/agent-runs.d.ts +191 -0
  19. package/dist/agent-runs.d.ts.map +1 -0
  20. package/dist/agent-runs.js +365 -0
  21. package/dist/assigned-roles.d.ts +205 -0
  22. package/dist/assigned-roles.d.ts.map +1 -0
  23. package/dist/assigned-roles.js +228 -0
  24. package/dist/broker-routes.d.ts +40 -0
  25. package/dist/broker-routes.d.ts.map +1 -0
  26. package/dist/broker-routes.js +56 -0
  27. package/dist/budget.d.ts +65 -0
  28. package/dist/budget.d.ts.map +1 -0
  29. package/dist/budget.js +19 -0
  30. package/dist/capability-matrix.d.ts +230 -0
  31. package/dist/capability-matrix.d.ts.map +1 -0
  32. package/dist/capability-matrix.js +304 -0
  33. package/dist/channel-identity.d.ts +40 -0
  34. package/dist/channel-identity.d.ts.map +1 -0
  35. package/dist/channel-identity.js +108 -0
  36. package/dist/collaboration.d.ts +45 -16
  37. package/dist/collaboration.d.ts.map +1 -0
  38. package/dist/collaboration.js +39 -23
  39. package/dist/common.d.ts +4 -3
  40. package/dist/common.d.ts.map +1 -0
  41. package/dist/conversations.d.ts +1 -0
  42. package/dist/conversations.d.ts.map +1 -0
  43. package/dist/cursor-transport.d.ts +22 -0
  44. package/dist/cursor-transport.d.ts.map +1 -0
  45. package/dist/cursor-transport.js +10 -0
  46. package/dist/debug-attach.d.ts +29 -0
  47. package/dist/debug-attach.d.ts.map +1 -0
  48. package/dist/debug-attach.js +6 -0
  49. package/dist/deliveries.d.ts +16 -2
  50. package/dist/deliveries.d.ts.map +1 -0
  51. package/dist/durable-actions.d.ts +94 -0
  52. package/dist/durable-actions.d.ts.map +1 -0
  53. package/dist/durable-actions.js +1 -0
  54. package/dist/events.d.ts +27 -1
  55. package/dist/events.d.ts.map +1 -0
  56. package/dist/events.js +14 -1
  57. package/dist/harness-feature-support.d.ts +76 -0
  58. package/dist/harness-feature-support.d.ts.map +1 -0
  59. package/dist/harness-feature-support.js +29 -0
  60. package/dist/host-integrations.d.ts +22 -0
  61. package/dist/host-integrations.d.ts.map +1 -0
  62. package/dist/host-integrations.js +64 -0
  63. package/dist/inbox.d.ts +50 -0
  64. package/dist/inbox.d.ts.map +1 -0
  65. package/dist/inbox.js +9 -0
  66. package/dist/index.d.ts +35 -2
  67. package/dist/index.d.ts.map +1 -0
  68. package/dist/index.js +34 -2
  69. package/dist/invocations.d.ts +119 -4
  70. package/dist/invocations.d.ts.map +1 -0
  71. package/dist/invocations.js +201 -1
  72. package/dist/mesh.d.ts +98 -0
  73. package/dist/mesh.d.ts.map +1 -0
  74. package/dist/mesh.js +18 -1
  75. package/dist/messages.d.ts +3 -0
  76. package/dist/messages.d.ts.map +1 -0
  77. package/dist/native-interactions.d.ts +30 -0
  78. package/dist/native-interactions.d.ts.map +1 -0
  79. package/dist/native-interactions.js +51 -0
  80. package/dist/observed-status.d.ts +33 -0
  81. package/dist/observed-status.d.ts.map +1 -0
  82. package/dist/observed-status.js +6 -0
  83. package/dist/orchestrator-prompt.d.ts +10 -0
  84. package/dist/orchestrator-prompt.d.ts.map +1 -0
  85. package/dist/orchestrator-prompt.js +36 -0
  86. package/dist/permission-policy.d.ts +5 -0
  87. package/dist/permission-policy.d.ts.map +1 -0
  88. package/dist/permission-policy.js +15 -0
  89. package/dist/provisional-agent-names.d.ts +30 -0
  90. package/dist/provisional-agent-names.d.ts.map +1 -0
  91. package/dist/provisional-agent-names.js +224 -0
  92. package/dist/read-receipts.d.ts +12 -0
  93. package/dist/read-receipts.d.ts.map +1 -0
  94. package/dist/read-receipts.js +1 -0
  95. package/dist/relay-agent-card.d.ts +10 -0
  96. package/dist/relay-agent-card.d.ts.map +1 -0
  97. package/dist/rendezvous.d.ts +97 -0
  98. package/dist/rendezvous.d.ts.map +1 -0
  99. package/dist/rendezvous.js +35 -0
  100. package/dist/reserved-vocabulary.d.ts +21 -0
  101. package/dist/reserved-vocabulary.d.ts.map +1 -0
  102. package/dist/reserved-vocabulary.js +101 -0
  103. package/dist/route-aliases.d.ts +112 -0
  104. package/dist/route-aliases.d.ts.map +1 -0
  105. package/dist/route-aliases.js +1 -0
  106. package/dist/runtime-catalog-contract.d.ts +39 -0
  107. package/dist/runtime-catalog-contract.d.ts.map +1 -0
  108. package/dist/runtime-catalog-contract.js +17 -0
  109. package/dist/runtime-catalog.d.ts +11 -0
  110. package/dist/runtime-catalog.d.ts.map +1 -0
  111. package/dist/runtime-catalog.generated.d.ts +230 -0
  112. package/dist/runtime-catalog.generated.d.ts.map +1 -0
  113. package/dist/runtime-catalog.generated.js +299 -0
  114. package/dist/runtime-catalog.js +192 -0
  115. package/dist/runtime-execution.d.ts +161 -0
  116. package/dist/runtime-execution.d.ts.map +1 -0
  117. package/dist/runtime-execution.js +327 -0
  118. package/dist/runtime-profiles.d.ts +12 -0
  119. package/dist/runtime-profiles.d.ts.map +1 -0
  120. package/dist/runtime-profiles.js +20 -0
  121. package/dist/scout-agent-card.d.ts +10 -0
  122. package/dist/scout-agent-card.d.ts.map +1 -0
  123. package/dist/scout-composer.d.ts +27 -0
  124. package/dist/scout-composer.d.ts.map +1 -0
  125. package/dist/scout-composer.js +192 -0
  126. package/dist/scout-delivery.d.ts +99 -4
  127. package/dist/scout-delivery.d.ts.map +1 -0
  128. package/dist/scout-dispatch.d.ts +40 -3
  129. package/dist/scout-dispatch.d.ts.map +1 -0
  130. package/dist/scout-reply-context.d.ts +1 -0
  131. package/dist/scout-reply-context.d.ts.map +1 -0
  132. package/dist/session-display-state.d.ts +132 -0
  133. package/dist/session-display-state.d.ts.map +1 -0
  134. package/dist/session-display-state.js +94 -0
  135. package/dist/terminal-host-topology.d.ts +119 -0
  136. package/dist/terminal-host-topology.d.ts.map +1 -0
  137. package/dist/terminal-host-topology.js +21 -0
  138. package/dist/terminal-sessions.d.ts +142 -0
  139. package/dist/terminal-sessions.d.ts.map +1 -0
  140. package/dist/terminal-sessions.js +81 -0
  141. package/dist/terminal-surface-id.d.ts +73 -0
  142. package/dist/terminal-surface-id.d.ts.map +1 -0
  143. package/dist/terminal-surface-id.js +162 -0
  144. package/dist/terminal-workspaces.d.ts +199 -0
  145. package/dist/terminal-workspaces.d.ts.map +1 -0
  146. package/dist/terminal-workspaces.js +287 -0
  147. package/dist/thread-events.d.ts +1 -0
  148. package/dist/thread-events.d.ts.map +1 -0
  149. package/dist/time.d.ts +16 -0
  150. package/dist/time.d.ts.map +1 -0
  151. package/dist/time.js +33 -0
  152. package/dist/transports.d.ts +1 -0
  153. package/dist/transports.d.ts.map +1 -0
  154. package/package.json +37 -9
  155. package/src/a2a.ts +471 -0
  156. package/src/activity.ts +113 -0
  157. package/src/actors.ts +42 -8
  158. package/src/agent-broker-feed.ts +102 -0
  159. package/src/agent-identity.ts +143 -8
  160. package/src/agent-runs.ts +675 -0
  161. package/src/assigned-roles.ts +437 -0
  162. package/src/broker-routes.ts +62 -0
  163. package/src/budget.ts +88 -0
  164. package/src/capability-matrix.ts +648 -0
  165. package/src/channel-identity.ts +147 -0
  166. package/src/collaboration.ts +78 -48
  167. package/src/common.ts +24 -5
  168. package/src/cursor-transport.ts +34 -0
  169. package/src/debug-attach.ts +38 -0
  170. package/src/deliveries.ts +16 -1
  171. package/src/durable-actions.ts +125 -0
  172. package/src/events.ts +31 -0
  173. package/src/harness-feature-support.ts +116 -0
  174. package/src/host-integrations.ts +104 -0
  175. package/src/inbox.ts +68 -0
  176. package/src/index.ts +34 -2
  177. package/src/invocations.ts +351 -4
  178. package/src/mesh.ts +130 -0
  179. package/src/messages.ts +2 -0
  180. package/src/native-interactions.ts +100 -0
  181. package/src/observed-status.ts +90 -0
  182. package/src/orchestrator-prompt.ts +47 -0
  183. package/src/permission-policy.ts +21 -0
  184. package/src/provisional-agent-names.ts +272 -0
  185. package/src/read-receipts.ts +12 -0
  186. package/src/relay-agent-card.ts +73 -63
  187. package/src/rendezvous.ts +154 -0
  188. package/src/reserved-vocabulary.ts +135 -0
  189. package/src/route-aliases.ts +130 -0
  190. package/src/runtime-catalog-contract.ts +60 -0
  191. package/src/runtime-catalog.generated.ts +300 -0
  192. package/src/runtime-catalog.md +21 -0
  193. package/src/runtime-catalog.ts +193 -0
  194. package/src/runtime-catalog.v1.json +81 -0
  195. package/src/runtime-execution.ts +545 -0
  196. package/src/runtime-profiles.ts +37 -0
  197. package/src/scout-agent-card.ts +10 -0
  198. package/src/scout-composer.ts +249 -0
  199. package/src/scout-delivery.ts +113 -3
  200. package/src/scout-dispatch.ts +33 -2
  201. package/src/session-display-state.ts +202 -0
  202. package/src/terminal-host-topology.ts +132 -0
  203. package/src/terminal-sessions.ts +187 -0
  204. package/src/terminal-surface-id.ts +189 -0
  205. package/src/terminal-workspaces.ts +455 -0
  206. package/src/time.ts +49 -0
  207. package/dist/agent-address.d.ts +0 -1
  208. package/dist/agent-address.js +0 -1
  209. package/dist/agent-selectors.d.ts +0 -1
  210. package/dist/agent-selectors.js +0 -1
  211. package/src/agent-address.ts +0 -1
  212. package/src/agent-identity.test.ts +0 -435
  213. package/src/agent-selectors.ts +0 -1
  214. package/src/scout-agent-card.test.ts +0 -54
@@ -0,0 +1,545 @@
1
+ import { SCOUT_RUNTIME_CATALOG_DATA } from "./runtime-catalog.generated.js";
2
+ import {
3
+ SCOUT_LAUNCHABLE_HARNESSES,
4
+ SCOUT_REASONING_EFFORT_LABELS,
5
+ SCOUT_REASONING_EFFORTS,
6
+ type ScoutLaunchableHarness,
7
+ type ScoutOwnedRuntimeCatalog,
8
+ type ScoutOwnedRuntimeHarness,
9
+ type ScoutReasoningEffort,
10
+ } from "./runtime-catalog-contract.js";
11
+ export * from "./runtime-catalog-contract.js";
12
+
13
+ export interface ScoutRuntimeHarnessDefaults {
14
+ model: string | null;
15
+ reasoningEffort: ScoutReasoningEffort | null;
16
+ }
17
+
18
+ /**
19
+ * Scout's versioned product catalog. Harness vendors are execution adapters,
20
+ * not catalog authorities: availability, ordering, labels, defaults, and the
21
+ * per-model effort ladder come from runtime-catalog.v1.json. Running brokers
22
+ * may replace this bundled last-known-good seed with a newer valid revision.
23
+ */
24
+ export const SCOUT_RUNTIME_CATALOG: ScoutOwnedRuntimeCatalog = SCOUT_RUNTIME_CATALOG_DATA;
25
+
26
+ export function scoutRuntimeHarness(
27
+ harness: string,
28
+ catalog: ScoutOwnedRuntimeCatalog = SCOUT_RUNTIME_CATALOG,
29
+ ): ScoutOwnedRuntimeHarness | undefined {
30
+ return catalog.harnesses.find((entry) => entry.id === harness);
31
+ }
32
+
33
+ export function isScoutRuntimeHarnessEnabled(
34
+ harness: string,
35
+ catalog: ScoutOwnedRuntimeCatalog = SCOUT_RUNTIME_CATALOG,
36
+ ): harness is ScoutLaunchableHarness {
37
+ return scoutRuntimeHarness(harness, catalog)?.enabled === true;
38
+ }
39
+
40
+ /** Enabled and offered as its own picker row. Hidden transports remain legal. */
41
+ export function isScoutRuntimeHarnessListed(
42
+ harness: string,
43
+ catalog: ScoutOwnedRuntimeCatalog = SCOUT_RUNTIME_CATALOG,
44
+ ): boolean {
45
+ const entry = scoutRuntimeHarness(harness, catalog);
46
+ return entry?.enabled === true && entry.listed !== false;
47
+ }
48
+
49
+ export function scoutRuntimeDefaultHarness(
50
+ catalog: ScoutOwnedRuntimeCatalog = SCOUT_RUNTIME_CATALOG,
51
+ ): ScoutLaunchableHarness | null {
52
+ return catalog.harnesses.find((entry) => entry.enabled && entry.default)?.id
53
+ ?? catalog.harnesses.find((entry) => entry.enabled)?.id
54
+ ?? null;
55
+ }
56
+
57
+ export function scoutRuntimeDefaultModel(
58
+ harness: string,
59
+ catalog: ScoutOwnedRuntimeCatalog = SCOUT_RUNTIME_CATALOG,
60
+ ): string | null {
61
+ const entry = scoutRuntimeHarness(harness, catalog);
62
+ return entry?.models.find((model) => model.enabled && model.default)?.id
63
+ ?? entry?.models.find((model) => model.enabled)?.id
64
+ ?? null;
65
+ }
66
+
67
+ export function scoutRuntimeReasoningEfforts(
68
+ harness: string,
69
+ model?: string | null,
70
+ catalog: ScoutOwnedRuntimeCatalog = SCOUT_RUNTIME_CATALOG,
71
+ ): readonly ScoutReasoningEffort[] | null {
72
+ const entry = scoutRuntimeHarness(harness, catalog);
73
+ if (!entry || !entry.enabled) return null;
74
+ const selected = model
75
+ ? entry.models.find((candidate) => candidate.enabled && candidate.id === model)
76
+ : undefined;
77
+ return selected?.reasoningEfforts === null
78
+ ? null
79
+ : selected?.reasoningEfforts ?? entry.reasoningEfforts;
80
+ }
81
+
82
+ export function scoutRuntimeDefaultReasoningEffort(
83
+ harness: string,
84
+ model?: string | null,
85
+ catalog: ScoutOwnedRuntimeCatalog = SCOUT_RUNTIME_CATALOG,
86
+ ): ScoutReasoningEffort | null {
87
+ const entry = scoutRuntimeHarness(harness, catalog);
88
+ const selected = model
89
+ ? entry?.models.find((candidate) => candidate.enabled && candidate.id === model)
90
+ : undefined;
91
+ const efforts = scoutRuntimeReasoningEfforts(harness, model, catalog);
92
+ const preferred = selected?.defaultReasoningEffort ?? entry?.defaultReasoningEffort ?? null;
93
+ return preferred && efforts?.includes(preferred) ? preferred : efforts?.[0] ?? null;
94
+ }
95
+
96
+ export function scoutRuntimeDefaultsByHarness(
97
+ catalog: ScoutOwnedRuntimeCatalog = SCOUT_RUNTIME_CATALOG,
98
+ ): Readonly<Partial<Record<ScoutLaunchableHarness, ScoutRuntimeHarnessDefaults>>> {
99
+ return Object.fromEntries(
100
+ catalog.harnesses
101
+ .filter((entry) => entry.enabled)
102
+ .map((entry) => {
103
+ const model = scoutRuntimeDefaultModel(entry.id, catalog);
104
+ return [entry.id, {
105
+ model,
106
+ reasoningEffort: scoutRuntimeDefaultReasoningEffort(entry.id, model, catalog),
107
+ }];
108
+ }),
109
+ ) as Partial<Record<ScoutLaunchableHarness, ScoutRuntimeHarnessDefaults>>;
110
+ }
111
+
112
+ export const SCOUT_RUNTIME_DEFAULTS_BY_HARNESS = scoutRuntimeDefaultsByHarness();
113
+
114
+ export const SCOUT_REASONING_EFFORTS_BY_HARNESS: Readonly<
115
+ Partial<Record<ScoutLaunchableHarness, readonly ScoutReasoningEffort[]>>
116
+ > = Object.fromEntries(
117
+ SCOUT_RUNTIME_CATALOG.harnesses
118
+ .filter((entry) => entry.enabled)
119
+ .map((entry) => {
120
+ const supported = SCOUT_REASONING_EFFORTS.filter((effort) =>
121
+ entry.reasoningEfforts?.includes(effort)
122
+ || entry.models.some((model) => model.enabled && model.reasoningEfforts?.includes(effort))
123
+ );
124
+ return [entry.id, supported];
125
+ }),
126
+ ) as Partial<Record<ScoutLaunchableHarness, readonly ScoutReasoningEffort[]>>;
127
+
128
+ export type ScoutRuntimeResolutionSource =
129
+ | "flag"
130
+ | "literal"
131
+ | "profile"
132
+ | "endpoint"
133
+ | "config"
134
+ | "default";
135
+
136
+ export type ScoutRuntimeDriftState =
137
+ | "unknown"
138
+ | "match"
139
+ | "mismatch";
140
+
141
+ export interface ScoutRuntimeDimensionResolution {
142
+ requested?: string;
143
+ resolved?: string;
144
+ source?: ScoutRuntimeResolutionSource;
145
+ observed?: string;
146
+ observedAt?: number;
147
+ drift: ScoutRuntimeDriftState;
148
+ }
149
+
150
+ /**
151
+ * Durable execution truth for one concrete session. `requested` is caller
152
+ * intent, `resolved` is the spawn value after the launch ladder, and
153
+ * `observed` is populated only from harness-owned evidence.
154
+ */
155
+ export interface ScoutExecutionResolution {
156
+ schemaVersion: "openscout.execution-resolution.v1";
157
+ harness: ScoutRuntimeDimensionResolution;
158
+ model: ScoutRuntimeDimensionResolution;
159
+ reasoningEffort: ScoutRuntimeDimensionResolution;
160
+ sessionId?: string;
161
+ resolvedAt?: number;
162
+ observedAt?: number;
163
+ }
164
+
165
+ export interface ScoutRuntimeModelOption {
166
+ id: string;
167
+ label: string;
168
+ description?: string;
169
+ harnesses: ScoutLaunchableHarness[];
170
+ source: "catalog" | "observed" | "configured" | "default";
171
+ family?: string;
172
+ version?: string;
173
+ }
174
+
175
+ export interface ScoutRuntimeEffortOption {
176
+ id: ScoutReasoningEffort;
177
+ label: string;
178
+ description?: string;
179
+ harnesses: ScoutLaunchableHarness[];
180
+ /**
181
+ * Model-scoped restriction, interpreted per harness: the rung is withheld
182
+ * only from catalog models of a harness that has at least one model named
183
+ * here. `max` naming `gpt-5.6-*` ids restricts Codex models but leaves
184
+ * Claude's ladder untouched. Empty/absent means every model of every listed
185
+ * harness supports the rung.
186
+ */
187
+ models?: string[];
188
+ }
189
+
190
+ export interface ScoutRuntimeHarnessOption {
191
+ id: ScoutLaunchableHarness;
192
+ name?: string;
193
+ label: string;
194
+ description?: string | null;
195
+ state?: "ready" | "configured" | "installed" | "missing" | null;
196
+ ready?: boolean | null;
197
+ detail?: string | null;
198
+ }
199
+
200
+ export interface ScoutRuntimeCapabilityCatalog {
201
+ schemaVersion: "openscout.runtime-capabilities.v1";
202
+ catalogVersion?: ScoutOwnedRuntimeCatalog["schemaVersion"];
203
+ catalogRevision?: string;
204
+ generatedAt: number;
205
+ scope: "global" | "project" | "global+project";
206
+ projectRoot?: string;
207
+ harnesses: ScoutRuntimeHarnessOption[];
208
+ models: ScoutRuntimeModelOption[];
209
+ efforts: ScoutRuntimeEffortOption[];
210
+ defaults?: {
211
+ harness?: ScoutLaunchableHarness;
212
+ model?: string | null;
213
+ reasoningEffort?: ScoutReasoningEffort | null;
214
+ };
215
+ defaultsByHarness?: Partial<Record<ScoutLaunchableHarness, ScoutRuntimeHarnessDefaults>>;
216
+ warnings?: string[];
217
+ }
218
+
219
+ /** Project one nested catalog into the flat API model list. */
220
+ export function scoutRuntimeModelCatalog(
221
+ catalog: ScoutOwnedRuntimeCatalog = SCOUT_RUNTIME_CATALOG,
222
+ ): ScoutRuntimeModelOption[] {
223
+ const models = new Map<string, ScoutRuntimeModelOption>();
224
+ for (const harness of catalog.harnesses) {
225
+ if (!harness.enabled) continue;
226
+ for (const model of harness.models) {
227
+ if (!model.enabled) continue;
228
+ const existing = models.get(model.id);
229
+ if (existing) {
230
+ if (!existing.harnesses.includes(harness.id)) existing.harnesses.push(harness.id);
231
+ continue;
232
+ }
233
+ models.set(model.id, {
234
+ id: model.id,
235
+ label: model.label,
236
+ ...(model.description ? { description: model.description } : {}),
237
+ harnesses: [harness.id],
238
+ source: "default",
239
+ ...(model.family ? { family: model.family } : {}),
240
+ ...(model.version ? { version: model.version } : {}),
241
+ });
242
+ }
243
+ }
244
+ return Array.from(models.values());
245
+ }
246
+
247
+ /** Projections retained for API compatibility; SCOUT_RUNTIME_CATALOG owns them. */
248
+ export const SCOUT_RUNTIME_MODEL_CATALOG: readonly ScoutRuntimeModelOption[] = scoutRuntimeModelCatalog();
249
+
250
+ const SCOUT_RUNTIME_EFFORT_DESCRIPTIONS: Readonly<Record<ScoutReasoningEffort, string>> = {
251
+ none: "No extra thinking",
252
+ minimal: "Smallest reasoning budget",
253
+ low: "Fast responses with lighter reasoning",
254
+ medium: "Balanced speed and reasoning depth",
255
+ high: "Greater reasoning depth for complex work",
256
+ xhigh: "Extra high reasoning depth",
257
+ max: "Maximum reasoning depth",
258
+ ultra: "Maximum reasoning with delegation",
259
+ };
260
+
261
+ export function scoutRuntimeEffortCatalog(
262
+ catalog: ScoutOwnedRuntimeCatalog = SCOUT_RUNTIME_CATALOG,
263
+ ): ScoutRuntimeEffortOption[] {
264
+ return SCOUT_REASONING_EFFORTS.flatMap((id): ScoutRuntimeEffortOption[] => {
265
+ const harnesses: ScoutLaunchableHarness[] = [];
266
+ const restrictedModels: string[] = [];
267
+ for (const harness of catalog.harnesses) {
268
+ if (!harness.enabled) continue;
269
+ const enabledModels = harness.models.filter((model) => model.enabled);
270
+ const supportingModels = enabledModels.filter((model) =>
271
+ (model.reasoningEfforts ?? harness.reasoningEfforts)?.includes(id)
272
+ );
273
+ const supportedWithoutModel = enabledModels.length === 0 && harness.reasoningEfforts?.includes(id);
274
+ if (supportingModels.length === 0 && !supportedWithoutModel) continue;
275
+ harnesses.push(harness.id);
276
+ if (enabledModels.length > 0 && supportingModels.length < enabledModels.length) {
277
+ restrictedModels.push(...supportingModels.map((model) => model.id));
278
+ }
279
+ }
280
+ if (harnesses.length === 0) return [];
281
+ return [{
282
+ id,
283
+ label: SCOUT_REASONING_EFFORT_LABELS[id],
284
+ description: SCOUT_RUNTIME_EFFORT_DESCRIPTIONS[id],
285
+ harnesses,
286
+ ...(restrictedModels.length > 0 ? { models: restrictedModels } : {}),
287
+ }];
288
+ });
289
+ }
290
+
291
+ export const SCOUT_RUNTIME_EFFORT_CATALOG: readonly ScoutRuntimeEffortOption[] = scoutRuntimeEffortCatalog();
292
+
293
+ export type ScoutRuntimeTuple = {
294
+ harness?: string | null;
295
+ model?: string | null;
296
+ reasoningEffort?: string | null;
297
+ };
298
+
299
+ export interface ScoutRuntimeSpec {
300
+ harness: ScoutLaunchableHarness;
301
+ model?: string;
302
+ reasoningEffort?: ScoutReasoningEffort;
303
+ }
304
+
305
+ export type ScoutRuntimeSpecParseResult =
306
+ | { ok: true; value: ScoutRuntimeSpec }
307
+ | { ok: false; error: string };
308
+
309
+ export type ScoutRuntimeModelNormalization =
310
+ | { ok: true; requested: string; resolved: string }
311
+ | { ok: false; requested: string; error: string; candidates?: string[] };
312
+
313
+ /** Canonical model aliases shared by every request boundary and spawn path. */
314
+ export function normalizeScoutRuntimeModel(
315
+ harness: string,
316
+ input: string,
317
+ ): ScoutRuntimeModelNormalization {
318
+ const requested = input.trim();
319
+ if (!requested) {
320
+ return { ok: false, requested, error: "model cannot be empty" };
321
+ }
322
+ const normalizedHarness = harness.trim().toLowerCase();
323
+ const lower = requested.toLowerCase();
324
+ if (normalizedHarness === "codex") {
325
+ if (lower === "5.6" || lower === "gpt-5.6") {
326
+ return { ok: true, requested, resolved: "gpt-5.6-sol" };
327
+ }
328
+ if (/^\d+(?:\.\d+)*(?:-[a-z0-9][a-z0-9._-]*)?$/u.test(lower)) {
329
+ return { ok: true, requested, resolved: `gpt-${lower}` };
330
+ }
331
+ return { ok: true, requested, resolved: requested };
332
+ }
333
+ if (normalizedHarness === "claude") {
334
+ const aliases: Record<string, string> = {
335
+ fable: "claude-fable-5",
336
+ opus: "claude-opus-5",
337
+ sonnet: "claude-sonnet-4-6",
338
+ haiku: "claude-haiku-4-5",
339
+ };
340
+ return { ok: true, requested, resolved: aliases[lower] ?? requested };
341
+ }
342
+ return { ok: true, requested, resolved: requested };
343
+ }
344
+
345
+ /** Parse the shell-safe `<harness>[/<model>[/<effort>]]` production. */
346
+ export function parseScoutRuntimeSpec(input: string): ScoutRuntimeSpecParseResult {
347
+ const raw = input.trim();
348
+ const parts = raw.split("/");
349
+ if (!raw || parts.length > 3 || parts.some((part) => !part.trim())) {
350
+ return {
351
+ ok: false,
352
+ error: "runtime must be <harness>[/<model>[/<effort>]]",
353
+ };
354
+ }
355
+ const harness = parts[0]!.trim().toLowerCase();
356
+ if (!isScoutLaunchableHarness(harness)) {
357
+ return {
358
+ ok: false,
359
+ error: `unsupported runtime harness "${parts[0]}"; expected one of: ${SCOUT_LAUNCHABLE_HARNESSES.join(", ")}`,
360
+ };
361
+ }
362
+ const model = parts[1]?.trim();
363
+ const effortRaw = parts[2]?.trim();
364
+ const reasoningEffort = effortRaw ? normalizeScoutReasoningEffort(effortRaw) : null;
365
+ if (effortRaw && !reasoningEffort) {
366
+ return {
367
+ ok: false,
368
+ error: `unsupported reasoning effort "${effortRaw}"; expected one of: ${SCOUT_REASONING_EFFORTS.join(", ")}`,
369
+ };
370
+ }
371
+ const issues = validateScoutRuntimeTuple({ harness, model, reasoningEffort });
372
+ if (issues.length > 0) {
373
+ return { ok: false, error: issues.map((issue) => issue.message).join("; ") };
374
+ }
375
+ return {
376
+ ok: true,
377
+ value: {
378
+ harness,
379
+ ...(model ? { model } : {}),
380
+ ...(reasoningEffort ? { reasoningEffort } : {}),
381
+ },
382
+ };
383
+ }
384
+
385
+ export function formatScoutRuntimeSpec(spec: ScoutRuntimeSpec): string {
386
+ if (spec.reasoningEffort && !spec.model) {
387
+ throw new Error("runtime literal cannot encode effort without a model; use --harness and --effort");
388
+ }
389
+ return [spec.harness, spec.model, spec.reasoningEffort]
390
+ .filter((part): part is string => Boolean(part))
391
+ .join("/");
392
+ }
393
+
394
+ export type ScoutRuntimeTupleIssue = {
395
+ code:
396
+ | "unsupported_harness"
397
+ | "unsupported_reasoning_effort"
398
+ | "reasoning_effort_harness_mismatch"
399
+ | "unsupported_model_dimension"
400
+ | "model_harness_mismatch";
401
+ dimension: "harness" | "model" | "reasoningEffort";
402
+ message: string;
403
+ };
404
+
405
+ export function isScoutLaunchableHarness(value: string | null | undefined): value is ScoutLaunchableHarness {
406
+ return Boolean(value)
407
+ && SCOUT_LAUNCHABLE_HARNESSES.includes(value!.trim().toLowerCase() as ScoutLaunchableHarness);
408
+ }
409
+
410
+ export function normalizeScoutReasoningEffort(
411
+ value: string | null | undefined,
412
+ ): ScoutReasoningEffort | null {
413
+ const normalized = value?.trim().toLowerCase();
414
+ return normalized && SCOUT_REASONING_EFFORTS.includes(normalized as ScoutReasoningEffort)
415
+ ? normalized as ScoutReasoningEffort
416
+ : null;
417
+ }
418
+
419
+ export function runtimeDimensionResolution(input: {
420
+ requested?: string | null;
421
+ resolved?: string | null;
422
+ source?: ScoutRuntimeResolutionSource;
423
+ observed?: string | null;
424
+ observedAt?: number;
425
+ }): ScoutRuntimeDimensionResolution {
426
+ const requested = input.requested?.trim() || undefined;
427
+ const resolved = input.resolved?.trim() || undefined;
428
+ const observed = input.observed?.trim() || undefined;
429
+ const drift: ScoutRuntimeDriftState = !observed || !resolved
430
+ ? "unknown"
431
+ : observed.toLowerCase() === resolved.toLowerCase()
432
+ ? "match"
433
+ : "mismatch";
434
+ return {
435
+ ...(requested ? { requested } : {}),
436
+ ...(resolved ? { resolved } : {}),
437
+ ...(input.source && resolved ? { source: input.source } : {}),
438
+ ...(observed ? { observed } : {}),
439
+ ...(observed && input.observedAt !== undefined ? { observedAt: input.observedAt } : {}),
440
+ drift,
441
+ };
442
+ }
443
+
444
+ export function createScoutExecutionResolution(input: {
445
+ requested?: ScoutRuntimeTuple;
446
+ resolved?: ScoutRuntimeTuple;
447
+ source?: Partial<Record<"harness" | "model" | "reasoningEffort", ScoutRuntimeResolutionSource>>;
448
+ observed?: ScoutRuntimeTuple;
449
+ sessionId?: string;
450
+ resolvedAt?: number;
451
+ observedAt?: number;
452
+ }): ScoutExecutionResolution {
453
+ const dimension = (key: "harness" | "model" | "reasoningEffort") => runtimeDimensionResolution({
454
+ requested: input.requested?.[key],
455
+ resolved: input.resolved?.[key],
456
+ source: input.source?.[key],
457
+ observed: input.observed?.[key],
458
+ observedAt: input.observedAt,
459
+ });
460
+ return {
461
+ schemaVersion: "openscout.execution-resolution.v1",
462
+ harness: dimension("harness"),
463
+ model: dimension("model"),
464
+ reasoningEffort: dimension("reasoningEffort"),
465
+ ...(input.sessionId?.trim() ? { sessionId: input.sessionId.trim() } : {}),
466
+ ...(input.resolvedAt !== undefined ? { resolvedAt: input.resolvedAt } : {}),
467
+ ...(input.observedAt !== undefined ? { observedAt: input.observedAt } : {}),
468
+ };
469
+ }
470
+
471
+ export function validateScoutRuntimeTuple(
472
+ input: ScoutRuntimeTuple,
473
+ catalog?: Pick<ScoutRuntimeCapabilityCatalog, "models" | "efforts">,
474
+ ): ScoutRuntimeTupleIssue[] {
475
+ const harness = input.harness?.trim().toLowerCase();
476
+ const model = input.model?.trim();
477
+ const effortRaw = input.reasoningEffort?.trim();
478
+ const issues: ScoutRuntimeTupleIssue[] = [];
479
+
480
+ if (harness && !isScoutLaunchableHarness(harness)) {
481
+ issues.push({
482
+ code: "unsupported_harness",
483
+ dimension: "harness",
484
+ message: `unsupported harness "${input.harness}"; expected one of: ${SCOUT_LAUNCHABLE_HARNESSES.join(", ")}`,
485
+ });
486
+ return issues;
487
+ }
488
+
489
+ const effort = effortRaw ? normalizeScoutReasoningEffort(effortRaw) : null;
490
+ if (effortRaw && !effort) {
491
+ issues.push({
492
+ code: "unsupported_reasoning_effort",
493
+ dimension: "reasoningEffort",
494
+ message: `unsupported reasoning effort "${effortRaw}"; expected one of: ${SCOUT_REASONING_EFFORTS.join(", ")}`,
495
+ });
496
+ } else if (effort && harness) {
497
+ const catalogEffort = catalog?.efforts.find((candidate) => candidate.id === effort);
498
+ let supported = catalogEffort
499
+ ? catalogEffort.harnesses.includes(harness as ScoutLaunchableHarness)
500
+ : (scoutRuntimeReasoningEfforts(harness, model) ?? []).includes(effort);
501
+ if (supported && catalogEffort?.models?.length && model) {
502
+ const harnessModels = new Set(
503
+ catalog?.models
504
+ .filter((candidate) => candidate.harnesses.includes(harness as ScoutLaunchableHarness))
505
+ .map((candidate) => candidate.id.toLowerCase()) ?? [],
506
+ );
507
+ const scopedModels = catalogEffort.models.filter((candidate) => (
508
+ harnessModels.has(candidate.toLowerCase())
509
+ ));
510
+ if (harnessModels.has(model.toLowerCase()) && scopedModels.length > 0) {
511
+ supported = scopedModels.some((candidate) => candidate.toLowerCase() === model.toLowerCase());
512
+ }
513
+ }
514
+ if (!supported) {
515
+ issues.push({
516
+ code: "reasoning_effort_harness_mismatch",
517
+ dimension: "reasoningEffort",
518
+ message: `reasoning effort "${effort}" is not supported by harness "${harness}"`,
519
+ });
520
+ }
521
+ }
522
+
523
+ const modelSelectableHarness = harness === "claude"
524
+ || harness === "codex"
525
+ || harness === "grok"
526
+ || harness === "grok-acp";
527
+ if (model && harness && !modelSelectableHarness) {
528
+ issues.push({
529
+ code: "unsupported_model_dimension",
530
+ dimension: "model",
531
+ message: `model selection is not supported by harness "${harness}"`,
532
+ });
533
+ } else if (model && harness && catalog) {
534
+ const known = catalog.models.find((candidate) => candidate.id.toLowerCase() === model.toLowerCase());
535
+ if (known && !known.harnesses.includes(harness as ScoutLaunchableHarness)) {
536
+ issues.push({
537
+ code: "model_harness_mismatch",
538
+ dimension: "model",
539
+ message: `model "${model}" is not supported by harness "${harness}"`,
540
+ });
541
+ }
542
+ }
543
+
544
+ return issues;
545
+ }
@@ -0,0 +1,37 @@
1
+ import { normalizeAgentSelectorSegment } from "./agent-identity.js";
2
+ import {
3
+ normalizeScoutReasoningEffort,
4
+ SCOUT_REASONING_EFFORTS,
5
+ type ScoutReasoningEffort,
6
+ } from "./runtime-execution.js";
7
+
8
+ /**
9
+ * Reserved natural-language profile names. Their execution definitions stay
10
+ * broker-owned; clients use this list only to recognize unambiguous syntax.
11
+ */
12
+ export const SCOUT_RESERVED_RUNTIME_PROFILE_IDS = [
13
+ "fable",
14
+ "kimi",
15
+ "grok",
16
+ "opus",
17
+ ] as const;
18
+
19
+ export type ScoutReservedRuntimeProfileId =
20
+ (typeof SCOUT_RESERVED_RUNTIME_PROFILE_IDS)[number];
21
+
22
+ export const SCOUT_RUNTIME_PROFILE_REASONING_EFFORTS = SCOUT_REASONING_EFFORTS;
23
+
24
+ export type ScoutRuntimeProfileReasoningEffort = ScoutReasoningEffort;
25
+
26
+ export function normalizeReservedRuntimeProfileId(
27
+ value: string,
28
+ ): ScoutReservedRuntimeProfileId | null {
29
+ const normalized = normalizeAgentSelectorSegment(value);
30
+ return SCOUT_RESERVED_RUNTIME_PROFILE_IDS.find((id) => id === normalized) ?? null;
31
+ }
32
+
33
+ export function normalizeRuntimeProfileReasoningEffort(
34
+ value: string,
35
+ ): ScoutRuntimeProfileReasoningEffort | null {
36
+ return normalizeScoutReasoningEffort(normalizeAgentSelectorSegment(value));
37
+ }
@@ -45,6 +45,15 @@ export interface ScoutReturnAddress {
45
45
  metadata?: MetadataMap;
46
46
  }
47
47
 
48
+ export interface ScoutAgentCardLifecycle {
49
+ kind: "persistent" | "one_time";
50
+ createdAt?: number;
51
+ createdById?: ScoutId;
52
+ expiresAt?: number;
53
+ maxUses?: number;
54
+ inboxConversationId?: ScoutId;
55
+ }
56
+
48
57
  /**
49
58
  * Scout's local discovery and routing card for one addressable agent target.
50
59
  *
@@ -81,6 +90,7 @@ export interface ScoutAgentCard {
81
90
  createdById?: ScoutId;
82
91
  brokerRegistered: boolean;
83
92
  inboxConversationId?: ScoutId;
93
+ lifecycle?: ScoutAgentCardLifecycle;
84
94
  returnAddress: ScoutReturnAddress;
85
95
  metadata?: MetadataMap;
86
96
  }