@odla-ai/harness 0.8.0 → 0.9.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.
package/README.md CHANGED
@@ -126,6 +126,17 @@ on stdout. Version 1 supports task.start, typed event messages,
126
126
  inference.request/inference.response, tool.request/tool.response,
127
127
  attempt.cancel, and attempt.complete.
128
128
 
129
+ ### Registry-brokered collaboration
130
+
131
+ `createCodeRuntimeSessionSkillLoader(control)` loads PM and Discussion tool
132
+ manifests for each accepted Code command and turns them into ordinary agent
133
+ skills. Every handler proxies the exact `commandId` and provider-issued
134
+ `toolCallId` back through the authenticated host control plane. The Registry
135
+ executes the effect and returns only bounded tool output, so neither Theseus nor
136
+ its networkless container receives an app key, tenant credential, or direct
137
+ database client. Initial work waits for the Registry's persisted `running` ACK
138
+ before manifests are requested.
139
+
129
140
  ## CaMeL tool and build boundary
130
141
 
131
142
  `createCodeToolBroker` is the trusted implementation for the three Theseus tools:
@@ -40,92 +40,10 @@ async function digestStagedWorkspace(root, limits) {
40
40
  return `sha256:${hash.digest("hex")}`;
41
41
  }
42
42
 
43
- // src/code-runtime-client.ts
43
+ // src/code-runtime-client-validation.ts
44
44
  import { digestCodeRepositorySnapshot } from "@odla-ai/camel/code";
45
45
 
46
- // src/code-runtime.ts
47
- var CODE_RUNTIME_PROTOCOL_VERSION = 1;
48
- async function runCodeRuntimeHeartbeatLoop(options) {
49
- const heartbeatMs = options.heartbeatMs ?? 15e3;
50
- if (!Number.isSafeInteger(heartbeatMs) || heartbeatMs < 1e3 || heartbeatMs > 3e5) {
51
- throw new TypeError("heartbeatMs must be an integer from 1000 to 300000");
52
- }
53
- let retryMs = 1e3;
54
- do {
55
- if (options.signal?.aborted) return;
56
- try {
57
- const snapshot = await options.control.heartbeat(options.runtimeVersion, options.capabilities);
58
- await options.onSnapshot?.(snapshot);
59
- retryMs = 1e3;
60
- if (options.once) return;
61
- await wait(heartbeatMs, options.signal);
62
- } catch (error) {
63
- if (options.signal?.aborted) return;
64
- if (options.once || !retryableControlFailure(error)) throw error;
65
- await options.onRetry?.(error, retryMs);
66
- await wait(retryMs, options.signal);
67
- retryMs = Math.min(retryMs * 2, 3e4);
68
- }
69
- } while (!options.signal?.aborted);
70
- }
71
- var CodeRuntimeReconciler = class {
72
- constructor(control, engine) {
73
- this.control = control;
74
- this.engine = engine;
75
- }
76
- control;
77
- engine;
78
- results = /* @__PURE__ */ new Map();
79
- async reconcile(snapshot) {
80
- for (const command of snapshot.commands) {
81
- let completed = this.results.get(command.commandId);
82
- if (!completed) {
83
- let result;
84
- try {
85
- result = await this.engine.execute(command);
86
- } catch (error) {
87
- result = { status: "failed", message: (error instanceof Error ? error.message : String(error)).slice(0, 2e3) };
88
- }
89
- completed = { result, notified: false };
90
- this.results.set(command.commandId, completed);
91
- if (this.results.size > 1024) this.results.delete(this.results.keys().next().value);
92
- }
93
- await this.control.acknowledge(command.commandId, completed.result);
94
- if (!completed.notified) {
95
- await this.engine.acknowledged?.(command, completed.result);
96
- completed.notified = true;
97
- }
98
- }
99
- }
100
- };
101
- function retryableControlFailure(value) {
102
- if (!value || typeof value !== "object") return false;
103
- const failure = value;
104
- if (failure.code === "invalid_response" || typeof failure.status !== "number") return false;
105
- return failure.status === 408 || failure.status === 425 || failure.status === 429 || failure.status >= 500;
106
- }
107
- function wait(ms, signal) {
108
- return new Promise((resolve5) => {
109
- if (signal?.aborted) return resolve5();
110
- const timer = setTimeout(resolve5, ms);
111
- signal?.addEventListener("abort", () => {
112
- clearTimeout(timer);
113
- resolve5();
114
- }, { once: true });
115
- });
116
- }
117
-
118
46
  // src/code-runtime-client.ts
119
- var CodeRuntimeControlError = class extends Error {
120
- constructor(message2, status, code = "control_error") {
121
- super(message2);
122
- this.status = status;
123
- this.code = code;
124
- }
125
- status;
126
- code;
127
- name = "CodeRuntimeControlError";
128
- };
129
47
  function createCodeRuntimeControlClient(options) {
130
48
  const endpoint = validatedEndpoint(options.endpoint);
131
49
  if (!/^odla_code_host_[0-9a-f]{64}$/.test(options.token)) throw new TypeError("invalid Code host credential");
@@ -138,9 +56,10 @@ function createCodeRuntimeControlClient(options) {
138
56
  throw new TypeError("modelRequestTimeoutMs must be an integer from 30000 to 1800000");
139
57
  }
140
58
  const request = options.fetch ?? fetch;
141
- const call = async (path, body, timeoutMs = requestTimeoutMs) => {
59
+ const call = async (path, body, timeoutMs = requestTimeoutMs, operationSignal) => {
142
60
  const timeout = AbortSignal.timeout(timeoutMs);
143
- const signal = options.signal ? AbortSignal.any([options.signal, timeout]) : timeout;
61
+ const signals = [options.signal, operationSignal, timeout].filter((item) => Boolean(item));
62
+ const signal = signals.length === 1 ? signals[0] : AbortSignal.any(signals);
144
63
  let response2;
145
64
  try {
146
65
  response2 = await request(`${endpoint}${path}`, {
@@ -151,7 +70,7 @@ function createCodeRuntimeControlClient(options) {
151
70
  signal
152
71
  });
153
72
  } catch (cause) {
154
- if (options.signal?.aborted) throw cause;
73
+ if (options.signal?.aborted || operationSignal?.aborted) throw cause;
155
74
  throw new CodeRuntimeControlError("Code runtime control plane is unavailable", 503, "transport_unavailable");
156
75
  }
157
76
  const value = await response2.json().catch(() => null);
@@ -171,8 +90,7 @@ function createCodeRuntimeControlClient(options) {
171
90
  return parseSnapshot(await call("/registry/code/runtime/heartbeat", { runtimeVersion: version, capabilities }));
172
91
  },
173
92
  acknowledge: async (commandId, result) => {
174
- if (!/^ccmd_[0-9a-f]{32}$/.test(commandId)) throw new TypeError("invalid Code runtime command id");
175
- await call(`/registry/code/runtime/commands/${commandId}/ack`, result);
93
+ await call(`/registry/code/runtime/commands/${validCommandId(commandId)}/ack`, result);
176
94
  },
177
95
  source: async (sessionId) => parseSource(
178
96
  await call(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/source`, {})
@@ -215,12 +133,116 @@ function createCodeRuntimeControlClient(options) {
215
133
  rememberMemory: async (sessionId, memory) => {
216
134
  await call(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/remember`, memory);
217
135
  },
136
+ collaborationSkills: async (sessionId, commandId) => {
137
+ try {
138
+ return parseCollaborationSkills(await call(
139
+ `/registry/code/runtime/sessions/${validSessionId(sessionId)}/collaboration/skills`,
140
+ { commandId: validCommandId(commandId) }
141
+ ));
142
+ } catch (cause) {
143
+ if (cause instanceof CodeRuntimeControlError && cause.status === 404 && cause.code === "not_found") return [];
144
+ throw cause;
145
+ }
146
+ },
147
+ executeCollaborationTool: async (sessionId, collaboration, signal) => {
148
+ validateCollaborationToolRequest(collaboration);
149
+ return parseCollaborationToolOutput(await call(
150
+ `/registry/code/runtime/sessions/${validSessionId(sessionId)}/collaboration/tools`,
151
+ collaboration,
152
+ requestTimeoutMs,
153
+ signal
154
+ ));
155
+ },
218
156
  reportSessionFailure: async (sessionId, message2) => {
219
157
  if (!message2.trim() || message2.length > 2e3) throw new TypeError("invalid Code session failure");
220
158
  await call(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/failure`, { message: message2 });
221
159
  }
222
160
  };
223
161
  }
162
+
163
+ // src/code-runtime.ts
164
+ var CODE_RUNTIME_PROTOCOL_VERSION = 1;
165
+ async function runCodeRuntimeHeartbeatLoop(options) {
166
+ const heartbeatMs = options.heartbeatMs ?? 15e3;
167
+ if (!Number.isSafeInteger(heartbeatMs) || heartbeatMs < 1e3 || heartbeatMs > 3e5) {
168
+ throw new TypeError("heartbeatMs must be an integer from 1000 to 300000");
169
+ }
170
+ let retryMs = 1e3;
171
+ do {
172
+ if (options.signal?.aborted) return;
173
+ try {
174
+ const snapshot = await options.control.heartbeat(options.runtimeVersion, options.capabilities);
175
+ await options.onSnapshot?.(snapshot);
176
+ retryMs = 1e3;
177
+ if (options.once) return;
178
+ await wait(heartbeatMs, options.signal);
179
+ } catch (error) {
180
+ if (options.signal?.aborted) return;
181
+ if (options.once || !retryableControlFailure(error)) throw error;
182
+ await options.onRetry?.(error, retryMs);
183
+ await wait(retryMs, options.signal);
184
+ retryMs = Math.min(retryMs * 2, 3e4);
185
+ }
186
+ } while (!options.signal?.aborted);
187
+ }
188
+ var CodeRuntimeReconciler = class {
189
+ constructor(control, engine) {
190
+ this.control = control;
191
+ this.engine = engine;
192
+ }
193
+ control;
194
+ engine;
195
+ results = /* @__PURE__ */ new Map();
196
+ async reconcile(snapshot) {
197
+ for (const command of snapshot.commands) {
198
+ let completed = this.results.get(command.commandId);
199
+ if (!completed) {
200
+ let result;
201
+ try {
202
+ result = await this.engine.execute(command);
203
+ } catch (error) {
204
+ result = { status: "failed", message: (error instanceof Error ? error.message : String(error)).slice(0, 2e3) };
205
+ }
206
+ completed = { result, notified: false };
207
+ this.results.set(command.commandId, completed);
208
+ if (this.results.size > 1024) this.results.delete(this.results.keys().next().value);
209
+ }
210
+ await this.control.acknowledge(command.commandId, completed.result);
211
+ if (!completed.notified) {
212
+ await this.engine.acknowledged?.(command, completed.result);
213
+ completed.notified = true;
214
+ }
215
+ }
216
+ }
217
+ };
218
+ function retryableControlFailure(value) {
219
+ if (!value || typeof value !== "object") return false;
220
+ const failure = value;
221
+ if (failure.code === "invalid_response" || typeof failure.status !== "number") return false;
222
+ return failure.status === 408 || failure.status === 425 || failure.status === 429 || failure.status >= 500;
223
+ }
224
+ function wait(ms, signal) {
225
+ return new Promise((resolve5) => {
226
+ if (signal?.aborted) return resolve5();
227
+ const timer = setTimeout(resolve5, ms);
228
+ signal?.addEventListener("abort", () => {
229
+ clearTimeout(timer);
230
+ resolve5();
231
+ }, { once: true });
232
+ });
233
+ }
234
+
235
+ // src/code-runtime-client-validation.ts
236
+ var CodeRuntimeControlError = class extends Error {
237
+ constructor(message2, status, code = "control_error") {
238
+ super(message2);
239
+ this.status = status;
240
+ this.code = code;
241
+ }
242
+ status;
243
+ code;
244
+ name = "CodeRuntimeControlError";
245
+ };
224
246
  function validatedEndpoint(value) {
225
247
  const endpoint = value.replace(/\/+$/, "");
226
248
  let url;
@@ -239,6 +261,10 @@ function validSessionId(value) {
239
261
  if (!/^csess_[0-9a-f]{32}$/.test(value)) throw new TypeError("invalid Code session id");
240
262
  return value;
241
263
  }
264
+ function validCommandId(value) {
265
+ if (!/^ccmd_[0-9a-f]{32}$/.test(value)) throw new TypeError("invalid Code runtime command id");
266
+ return value;
267
+ }
242
268
  function validateHeartbeat(version, capabilities) {
243
269
  if (!version.trim() || version.length > 80) throw new TypeError("runtimeVersion is required and at most 80 characters");
244
270
  if (capabilities.protocolVersion !== CODE_RUNTIME_PROTOCOL_VERSION) throw new TypeError("unsupported Code runtime protocol version");
@@ -320,6 +346,91 @@ function parseCandidate(value) {
320
346
  }
321
347
  return { candidateId: candidate.candidateId, status: candidate.status };
322
348
  }
349
+ function parseCollaborationSkills(value) {
350
+ const items = record(value)?.skills;
351
+ if (!Array.isArray(items) || items.length > 16) throw invalid("collaboration skills");
352
+ const skillNames = /* @__PURE__ */ new Set();
353
+ const toolNames = /* @__PURE__ */ new Set();
354
+ return items.map((item) => {
355
+ const skill = record(item);
356
+ if (!skill || !validManifestName(skill.name) || skillNames.has(skill.name) || skill.instructions !== void 0 && (typeof skill.instructions !== "string" || utf8Bytes(skill.instructions) > 32e3) || !Array.isArray(skill.tools) || !skill.tools.length || skill.tools.length > 128) {
357
+ throw invalid("collaboration skill");
358
+ }
359
+ skillNames.add(skill.name);
360
+ const tools = skill.tools.map((candidate) => {
361
+ const tool = record(candidate);
362
+ const inputSchema = record(tool?.inputSchema);
363
+ if (!tool || !validManifestName(tool.name) || toolNames.has(tool.name) || typeof tool.description !== "string" || utf8Bytes(tool.description) > 8e3 || !inputSchema || jsonBytes(inputSchema) > 64e3 || tool.concurrency !== void 0 && tool.concurrency !== "parallel") {
364
+ throw invalid("collaboration tool");
365
+ }
366
+ const outputTaint = parseTaintLabels(tool.outputTaint);
367
+ const acceptsTaint = parseTaintLabels(tool.acceptsTaint);
368
+ toolNames.add(tool.name);
369
+ return {
370
+ name: tool.name,
371
+ description: tool.description,
372
+ inputSchema,
373
+ ...tool.concurrency === "parallel" ? { concurrency: "parallel" } : {},
374
+ ...outputTaint ? { outputTaint } : {},
375
+ ...acceptsTaint ? { acceptsTaint } : {}
376
+ };
377
+ });
378
+ return {
379
+ name: skill.name,
380
+ ...typeof skill.instructions === "string" ? { instructions: skill.instructions } : {},
381
+ tools
382
+ };
383
+ });
384
+ }
385
+ function validateCollaborationToolRequest(value) {
386
+ validCommandId(value.commandId);
387
+ if (typeof value.toolCallId !== "string" || value.toolCallId.length > 256 || !/^[^\s\u0000-\u001f\u007f]+$/.test(value.toolCallId) || !validManifestName(value.skill) || !validManifestName(value.tool) || !record(value.input) || jsonBytes(value.input) > 128e3) {
388
+ throw new TypeError("invalid Code collaboration tool request");
389
+ }
390
+ }
391
+ function parseCollaborationToolOutput(value) {
392
+ const output = record(record(value)?.output);
393
+ if (!output || output.isError !== void 0 && typeof output.isError !== "boolean") {
394
+ throw invalid("collaboration tool");
395
+ }
396
+ if (typeof output.content === "string") {
397
+ if (utf8Bytes(output.content) > 1e6) throw invalid("collaboration tool");
398
+ return { content: output.content, ...output.isError === true ? { isError: true } : {} };
399
+ }
400
+ if (!Array.isArray(output.content) || output.content.length > 64 || jsonBytes(output.content) > 1e6 || !output.content.every((block) => {
401
+ const item = record(block);
402
+ return item && ["text", "image", "audio", "document", "tool_use", "tool_result", "thinking"].includes(String(item.type));
403
+ })) throw invalid("collaboration tool");
404
+ return {
405
+ content: output.content,
406
+ ...output.isError === true ? { isError: true } : {}
407
+ };
408
+ }
409
+ function parseTaintLabels(value) {
410
+ if (value === void 0) return void 0;
411
+ if (!Array.isArray(value) || value.length > 16) throw invalid("collaboration tool taint");
412
+ const labels = value.map((item) => {
413
+ if (item === "web_untrusted" || item === "operator_pasted_untrusted" || item === "llm_inherited") return item;
414
+ if (typeof item === "string" && /^tool_untrusted:[^\s\u0000-\u001f\u007f]{1,100}$/.test(item)) {
415
+ return item;
416
+ }
417
+ throw invalid("collaboration tool taint");
418
+ });
419
+ return [...new Set(labels)];
420
+ }
421
+ function validManifestName(value) {
422
+ return typeof value === "string" && /^[A-Za-z][A-Za-z0-9._:-]{0,127}$/.test(value);
423
+ }
424
+ function utf8Bytes(value) {
425
+ return new TextEncoder().encode(value).byteLength;
426
+ }
427
+ function jsonBytes(value) {
428
+ try {
429
+ return utf8Bytes(JSON.stringify(value));
430
+ } catch {
431
+ return Number.POSITIVE_INFINITY;
432
+ }
433
+ }
323
434
  var record = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
324
435
  var invalid = (part) => new CodeRuntimeControlError(`invalid Code runtime ${part} response`, 502, "invalid_response");
325
436
 
@@ -1358,6 +1469,7 @@ async function runCodeAgentAttempt(options) {
1358
1469
  model: "brokered",
1359
1470
  surface,
1360
1471
  ...options.recipeIds ? { recipeIds: options.recipeIds } : {},
1472
+ ...options.extraSkills ? { extraSkills: options.extraSkills } : {},
1361
1473
  ...options.maxSteps === void 0 ? {} : { maxSteps: options.maxSteps },
1362
1474
  ...options.budget ? { budget: options.budget } : {},
1363
1475
  ...options.signal ? { signal: options.signal } : {},
@@ -1389,6 +1501,48 @@ Finish with a concise, non-empty answer to the owner. Do not call tools or promi
1389
1501
  }
1390
1502
  }
1391
1503
 
1504
+ // src/code-runtime-session-skills.ts
1505
+ function createCodeRuntimeSessionSkillLoader(control) {
1506
+ const load = control.collaborationSkills?.bind(control);
1507
+ const execute2 = control.executeCollaborationTool?.bind(control);
1508
+ if (!load || !execute2) return async () => [];
1509
+ return async (command) => {
1510
+ const manifests = await load(command.sessionId, command.commandId);
1511
+ return manifests.map((manifest) => ({
1512
+ name: manifest.name,
1513
+ ...manifest.instructions === void 0 ? {} : { instructions: manifest.instructions },
1514
+ tools: manifest.tools.map((tool) => ({
1515
+ name: tool.name,
1516
+ description: tool.description,
1517
+ inputSchema: tool.inputSchema,
1518
+ ...tool.concurrency === void 0 ? {} : { concurrency: tool.concurrency },
1519
+ ...tool.outputTaint === void 0 ? {} : { outputTaint: tool.outputTaint },
1520
+ ...tool.acceptsTaint === void 0 ? {} : { acceptsTaint: tool.acceptsTaint },
1521
+ handler: async (input, context) => {
1522
+ if (!context.toolCallId) throw new TypeError("collaboration tool call identity is required");
1523
+ return execute2(command.sessionId, {
1524
+ commandId: command.commandId,
1525
+ toolCallId: context.toolCallId,
1526
+ skill: manifest.name,
1527
+ tool: tool.name,
1528
+ input
1529
+ }, context.signal);
1530
+ }
1531
+ }))
1532
+ }));
1533
+ };
1534
+ }
1535
+ async function sessionSkillsFor(options, command) {
1536
+ try {
1537
+ return await options.sessionSkills?.(command) ?? [];
1538
+ } catch (cause) {
1539
+ options.onDiagnostic?.(
1540
+ `session skills unavailable, continuing with code tools only: ${cause instanceof Error ? cause.message : String(cause)}`
1541
+ );
1542
+ return [];
1543
+ }
1544
+ }
1545
+
1392
1546
  // src/code-runtime-inference.ts
1393
1547
  async function handleCodeRuntimeInference(input) {
1394
1548
  const { command, request, state } = input;
@@ -2622,6 +2776,25 @@ function codeToolResultPresentation(request, response2) {
2622
2776
  };
2623
2777
  }
2624
2778
 
2779
+ // src/code-runtime-acknowledgement-gate.ts
2780
+ function codeRuntimeAcknowledgementGate(signal) {
2781
+ let settle;
2782
+ let settled = false;
2783
+ const ready = new Promise((resolve5) => {
2784
+ settle = resolve5;
2785
+ });
2786
+ const release = (run) => {
2787
+ if (settled) return;
2788
+ settled = true;
2789
+ signal.removeEventListener("abort", onAbort);
2790
+ settle(run);
2791
+ };
2792
+ const onAbort = () => release(false);
2793
+ if (signal.aborted) release(false);
2794
+ else signal.addEventListener("abort", onAbort, { once: true });
2795
+ return { ready, release };
2796
+ }
2797
+
2625
2798
  // src/code-runtime-engine.ts
2626
2799
  var TheseusRuntimeEngine = class {
2627
2800
  constructor(options) {
@@ -2652,6 +2825,8 @@ var TheseusRuntimeEngine = class {
2652
2825
  const active = this.#active.get(command.sessionId);
2653
2826
  if (!active || result.status !== "running") return;
2654
2827
  active.acknowledged = true;
2828
+ active.startGate?.release(true);
2829
+ active.startGate = void 0;
2655
2830
  if (active.failure) await this.options.control.reportSessionFailure(command.sessionId, active.failure).catch(() => void 0);
2656
2831
  }
2657
2832
  async close() {
@@ -2671,13 +2846,14 @@ var TheseusRuntimeEngine = class {
2671
2846
  control: this.options.control,
2672
2847
  ...this.options.localSource ? { localSource: this.options.localSource } : {}
2673
2848
  });
2674
- const abort = new AbortController();
2849
+ const abort = new AbortController(), startGate = codeRuntimeAcknowledgementGate(abort.signal);
2675
2850
  const conversationRefs = [];
2676
2851
  const active = {
2677
2852
  workspace,
2678
2853
  abort,
2679
2854
  conversationRefs,
2680
2855
  acknowledged: false,
2856
+ startGate,
2681
2857
  role: metadata.role,
2682
2858
  title: metadata.title,
2683
2859
  maxTokensPerInteraction: metadata.maxTokensPerInteraction,
@@ -2701,7 +2877,7 @@ var TheseusRuntimeEngine = class {
2701
2877
  body: `Source snapshot: local checkout ${requestedLocal.snapshotDigest} \xB7 ${requestedLocal.modified ? "modified" : "clean"} \xB7 Git ${requestedLocal.headCommitSha}`
2702
2878
  }, conversationRefs);
2703
2879
  }
2704
- active.done = this.#runAttempt(command, metadata, active).catch(async (cause) => {
2880
+ active.done = startGate.ready.then((run) => run ? this.#runAttempt(command, metadata, active) : null).catch(async (cause) => {
2705
2881
  const detail = runtimeErrorMessage(cause);
2706
2882
  await this.#event(command, { type: "message", actor: "system", body: detail }, conversationRefs).catch(() => void 0);
2707
2883
  await this.#diagnostic(command, active, detail);
@@ -2816,6 +2992,7 @@ var TheseusRuntimeEngine = class {
2816
2992
  event: (event) => this.#event(command, event, active.conversationRefs)
2817
2993
  });
2818
2994
  await this.#event(command, { type: "status", status: "running" }, active.conversationRefs);
2995
+ const extraSkills = await sessionSkillsFor(this.options, command);
2819
2996
  const result = await this.#attempt({
2820
2997
  inference,
2821
2998
  broker,
@@ -2823,7 +3000,8 @@ var TheseusRuntimeEngine = class {
2823
3000
  workspaceDir: active.workspace.workspaceDir,
2824
3001
  prompt: metadata.prompt,
2825
3002
  signal: active.abort.signal,
2826
- recipeIds: this.options.recipes.map((recipe2) => recipe2.id)
3003
+ recipeIds: this.options.recipes.map((recipe2) => recipe2.id),
3004
+ ...extraSkills.length ? { extraSkills } : {}
2827
3005
  });
2828
3006
  const closing = result.finalText.trim();
2829
3007
  const completed = result.status === "completed" && Boolean(closing);
@@ -2943,6 +3121,8 @@ export {
2943
3121
  codeSkill,
2944
3122
  runCodeAgent,
2945
3123
  runCodeAgentAttempt,
3124
+ createCodeRuntimeSessionSkillLoader,
3125
+ sessionSkillsFor,
2946
3126
  createCodeRuntimeInference,
2947
3127
  registeredFiles,
2948
3128
  createCodeToolBroker,
@@ -2954,4 +3134,4 @@ export {
2954
3134
  runGoal,
2955
3135
  TheseusRuntimeEngine
2956
3136
  };
2957
- //# sourceMappingURL=chunk-ISR434K7.js.map
3137
+ //# sourceMappingURL=chunk-NG7AYYH3.js.map