@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.
@@ -5,8 +5,9 @@ import {
5
5
  TheseusRuntimeEngine,
6
6
  assertCodeBuildRecipe,
7
7
  createCodeRuntimeControlClient,
8
+ createCodeRuntimeSessionSkillLoader,
8
9
  runCodeRuntimeHeartbeatLoop
9
- } from "./chunk-ISR434K7.js";
10
+ } from "./chunk-NG7AYYH3.js";
10
11
  import {
11
12
  assertPinnedImage,
12
13
  selectContainerEngine
@@ -91,6 +92,7 @@ async function main() {
91
92
  engine,
92
93
  recipes: policy.recipes,
93
94
  recipeAuthorization: policy.recipeAuthorization,
95
+ sessionSkills: createCodeRuntimeSessionSkillLoader(control),
94
96
  onDiagnostic: (message) => process.stderr.write(`[odla-code-runtime] agent failed \xB7 ${message}
95
97
  `)
96
98
  });
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/code-runtime-cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { cpus, totalmem } from \"node:os\";\nimport { readFile } from \"node:fs/promises\";\nimport {\n CODE_RUNTIME_PROTOCOL_VERSION,\n CodeRuntimeReconciler,\n createCodeRuntimeControlClient,\n runCodeRuntimeHeartbeatLoop,\n type CodeRuntimeCapabilities,\n} from \"./code-runtime\";\nimport { TheseusRuntimeEngine } from \"./code-runtime-engine\";\nimport { assertPinnedImage, selectContainerEngine, type ContainerEngine } from \"./container\";\nimport { assertCodeBuildRecipe } from \"./recipe-container\";\nimport type { CodeBuildRecipe } from \"./code-tool-types\";\n\nconst VERSION = \"0.1.0\";\n\nfunction usage(): string {\n return `Usage:\n ODLA_CODE_HOST_TOKEN=odla_code_host_... odla-code-runtime \\\\\n --endpoint https://odla.ai --image registry/odla-pi@sha256:... \\\\\n --build-policy ./odla-code-build.json [--engine auto|container|podman|docker] [--once]\n\nThe host token is read only from ODLA_CODE_HOST_TOKEN. The runtime makes\noutbound HTTPS heartbeats and never opens a listener.`;\n}\n\nfunction parse(argv: string[]): {\n endpoint: string; engine: ContainerEngine | \"auto\"; image: string;\n buildPolicy: string; heartbeatMs: number; once: boolean;\n} {\n const values = new Map<string, string>();\n const flags = new Set<string>();\n for (let index = 0; index < argv.length; index++) {\n const arg = argv[index]!;\n if (arg === \"--once\") { flags.add(arg); continue; }\n if (!arg.startsWith(\"--\") || !argv[index + 1]) throw new TypeError(usage());\n values.set(arg, argv[++index]!);\n }\n const endpoint = values.get(\"--endpoint\");\n const image = values.get(\"--image\");\n const buildPolicy = values.get(\"--build-policy\");\n const engine = values.get(\"--engine\") ?? \"auto\";\n const heartbeatMs = Number(values.get(\"--heartbeat-ms\") ?? 15_000);\n if (!endpoint || !image || !buildPolicy || ![\"auto\", \"container\", \"podman\", \"docker\"].includes(engine)) {\n throw new TypeError(usage());\n }\n assertPinnedImage(image);\n if (!Number.isSafeInteger(heartbeatMs) || heartbeatMs < 1_000 || heartbeatMs > 300_000) {\n throw new TypeError(\"--heartbeat-ms must be an integer from 1000 to 300000\");\n }\n return { endpoint, image, buildPolicy, engine: engine as ContainerEngine | \"auto\",\n heartbeatMs, once: flags.has(\"--once\") };\n}\n\nasync function readPolicy(path: string): Promise<{\n recipes: CodeBuildRecipe[]; recipeAuthorization: \"registered_recipe\" | \"exact_approval\";\n}> {\n const value = JSON.parse(await readFile(path, \"utf8\")) as Record<string, unknown>;\n if (!value || Object.keys(value).some((key) => ![\"recipes\", \"recipeAuthorization\"].includes(key))\n || !Array.isArray(value.recipes) || !value.recipes.length\n || (value.recipeAuthorization !== undefined && value.recipeAuthorization !== \"registered_recipe\"\n && value.recipeAuthorization !== \"exact_approval\")) throw new TypeError(\"invalid Code build policy file\");\n const recipes = value.recipes as CodeBuildRecipe[];\n for (const recipe of recipes) assertCodeBuildRecipe(recipe);\n const recipeAuthorization = value.recipeAuthorization === \"exact_approval\"\n ? \"exact_approval\" : \"registered_recipe\";\n return { recipes, recipeAuthorization };\n}\n\nasync function main(): Promise<void> {\n const token = process.env.ODLA_CODE_HOST_TOKEN;\n if (!token) throw new TypeError(\"ODLA_CODE_HOST_TOKEN is required\");\n const options = parse(process.argv.slice(2));\n if (process.platform !== \"darwin\" && process.platform !== \"linux\") throw new TypeError(\"Code runtime requires macOS or Linux\");\n const engine = await selectContainerEngine(options.engine);\n const policy = await readPolicy(options.buildPolicy);\n const capabilities: CodeRuntimeCapabilities = {\n protocolVersion: CODE_RUNTIME_PROTOCOL_VERSION,\n platform: process.platform === \"darwin\" ? \"macos\" : \"linux\",\n arch: process.arch,\n engines: [engine],\n cpuCount: cpus().length,\n memoryBytes: totalmem(),\n };\n const controller = new AbortController();\n for (const signal of [\"SIGINT\", \"SIGTERM\"] as const) process.once(signal, () => controller.abort(signal));\n // The heartbeat stops on the process signal, but the client must remain able\n // to report the active attempt's terminal events during engine.close().\n const control = createCodeRuntimeControlClient({ endpoint: options.endpoint, token });\n const commandEngine = new TheseusRuntimeEngine({\n control, engine, recipes: policy.recipes,\n recipeAuthorization: policy.recipeAuthorization,\n onDiagnostic: (message) => process.stderr.write(`[odla-code-runtime] agent failed · ${message}\\n`),\n });\n const reconciler = new CodeRuntimeReconciler(control, commandEngine);\n try {\n await runCodeRuntimeHeartbeatLoop({\n control, runtimeVersion: VERSION, capabilities, heartbeatMs: options.heartbeatMs,\n once: options.once, signal: controller.signal,\n onSnapshot: async (snapshot) => {\n process.stderr.write(\n `[odla-code-runtime] host ${snapshot.host.hostId} online · ${snapshot.bindings.length} active binding(s) · ${snapshot.commands.length} command(s)\\n`,\n );\n if (options.once && snapshot.commands.length) {\n throw new TypeError(\"--once is diagnostic-only and refuses pending Code commands\");\n }\n await reconciler.reconcile(snapshot);\n },\n onRetry: (error, delayMs) => {\n process.stderr.write(\n `[odla-code-runtime] control plane unavailable; retrying in ${delayMs}ms · ${error instanceof Error ? error.message : String(error)}\\n`,\n );\n },\n });\n } finally { await commandEngine.close(); }\n}\n\nmain().catch((error) => {\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\n});\n"],"mappings":"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","names":[]}
1
+ {"version":3,"sources":["../src/code-runtime-cli.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { cpus, totalmem } from \"node:os\";\nimport { readFile } from \"node:fs/promises\";\nimport {\n CODE_RUNTIME_PROTOCOL_VERSION,\n CodeRuntimeReconciler,\n createCodeRuntimeControlClient,\n runCodeRuntimeHeartbeatLoop,\n type CodeRuntimeCapabilities,\n} from \"./code-runtime\";\nimport { TheseusRuntimeEngine } from \"./code-runtime-engine\";\nimport { createCodeRuntimeSessionSkillLoader } from \"./code-runtime-session-skills\";\nimport { assertPinnedImage, selectContainerEngine, type ContainerEngine } from \"./container\";\nimport { assertCodeBuildRecipe } from \"./recipe-container\";\nimport type { CodeBuildRecipe } from \"./code-tool-types\";\n\nconst VERSION = \"0.1.0\";\n\nfunction usage(): string {\n return `Usage:\n ODLA_CODE_HOST_TOKEN=odla_code_host_... odla-code-runtime \\\\\n --endpoint https://odla.ai --image registry/odla-pi@sha256:... \\\\\n --build-policy ./odla-code-build.json [--engine auto|container|podman|docker] [--once]\n\nThe host token is read only from ODLA_CODE_HOST_TOKEN. The runtime makes\noutbound HTTPS heartbeats and never opens a listener.`;\n}\n\nfunction parse(argv: string[]): {\n endpoint: string; engine: ContainerEngine | \"auto\"; image: string;\n buildPolicy: string; heartbeatMs: number; once: boolean;\n} {\n const values = new Map<string, string>();\n const flags = new Set<string>();\n for (let index = 0; index < argv.length; index++) {\n const arg = argv[index]!;\n if (arg === \"--once\") { flags.add(arg); continue; }\n if (!arg.startsWith(\"--\") || !argv[index + 1]) throw new TypeError(usage());\n values.set(arg, argv[++index]!);\n }\n const endpoint = values.get(\"--endpoint\");\n const image = values.get(\"--image\");\n const buildPolicy = values.get(\"--build-policy\");\n const engine = values.get(\"--engine\") ?? \"auto\";\n const heartbeatMs = Number(values.get(\"--heartbeat-ms\") ?? 15_000);\n if (!endpoint || !image || !buildPolicy || ![\"auto\", \"container\", \"podman\", \"docker\"].includes(engine)) {\n throw new TypeError(usage());\n }\n assertPinnedImage(image);\n if (!Number.isSafeInteger(heartbeatMs) || heartbeatMs < 1_000 || heartbeatMs > 300_000) {\n throw new TypeError(\"--heartbeat-ms must be an integer from 1000 to 300000\");\n }\n return { endpoint, image, buildPolicy, engine: engine as ContainerEngine | \"auto\",\n heartbeatMs, once: flags.has(\"--once\") };\n}\n\nasync function readPolicy(path: string): Promise<{\n recipes: CodeBuildRecipe[]; recipeAuthorization: \"registered_recipe\" | \"exact_approval\";\n}> {\n const value = JSON.parse(await readFile(path, \"utf8\")) as Record<string, unknown>;\n if (!value || Object.keys(value).some((key) => ![\"recipes\", \"recipeAuthorization\"].includes(key))\n || !Array.isArray(value.recipes) || !value.recipes.length\n || (value.recipeAuthorization !== undefined && value.recipeAuthorization !== \"registered_recipe\"\n && value.recipeAuthorization !== \"exact_approval\")) throw new TypeError(\"invalid Code build policy file\");\n const recipes = value.recipes as CodeBuildRecipe[];\n for (const recipe of recipes) assertCodeBuildRecipe(recipe);\n const recipeAuthorization = value.recipeAuthorization === \"exact_approval\"\n ? \"exact_approval\" : \"registered_recipe\";\n return { recipes, recipeAuthorization };\n}\n\nasync function main(): Promise<void> {\n const token = process.env.ODLA_CODE_HOST_TOKEN;\n if (!token) throw new TypeError(\"ODLA_CODE_HOST_TOKEN is required\");\n const options = parse(process.argv.slice(2));\n if (process.platform !== \"darwin\" && process.platform !== \"linux\") throw new TypeError(\"Code runtime requires macOS or Linux\");\n const engine = await selectContainerEngine(options.engine);\n const policy = await readPolicy(options.buildPolicy);\n const capabilities: CodeRuntimeCapabilities = {\n protocolVersion: CODE_RUNTIME_PROTOCOL_VERSION,\n platform: process.platform === \"darwin\" ? \"macos\" : \"linux\",\n arch: process.arch,\n engines: [engine],\n cpuCount: cpus().length,\n memoryBytes: totalmem(),\n };\n const controller = new AbortController();\n for (const signal of [\"SIGINT\", \"SIGTERM\"] as const) process.once(signal, () => controller.abort(signal));\n // The heartbeat stops on the process signal, but the client must remain able\n // to report the active attempt's terminal events during engine.close().\n const control = createCodeRuntimeControlClient({ endpoint: options.endpoint, token });\n const commandEngine = new TheseusRuntimeEngine({\n control, engine, recipes: policy.recipes,\n recipeAuthorization: policy.recipeAuthorization,\n sessionSkills: createCodeRuntimeSessionSkillLoader(control),\n onDiagnostic: (message) => process.stderr.write(`[odla-code-runtime] agent failed · ${message}\\n`),\n });\n const reconciler = new CodeRuntimeReconciler(control, commandEngine);\n try {\n await runCodeRuntimeHeartbeatLoop({\n control, runtimeVersion: VERSION, capabilities, heartbeatMs: options.heartbeatMs,\n once: options.once, signal: controller.signal,\n onSnapshot: async (snapshot) => {\n process.stderr.write(\n `[odla-code-runtime] host ${snapshot.host.hostId} online · ${snapshot.bindings.length} active binding(s) · ${snapshot.commands.length} command(s)\\n`,\n );\n if (options.once && snapshot.commands.length) {\n throw new TypeError(\"--once is diagnostic-only and refuses pending Code commands\");\n }\n await reconciler.reconcile(snapshot);\n },\n onRetry: (error, delayMs) => {\n process.stderr.write(\n `[odla-code-runtime] control plane unavailable; retrying in ${delayMs}ms · ${error instanceof Error ? error.message : String(error)}\\n`,\n );\n },\n });\n } finally { await commandEngine.close(); }\n}\n\nmain().catch((error) => {\n process.stderr.write(`${error instanceof Error ? error.message : String(error)}\\n`);\n process.exitCode = 1;\n});\n"],"mappings":"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","names":[]}
package/dist/node.cjs CHANGED
@@ -43,6 +43,7 @@ __export(node_exports, {
43
43
  codeSkill: () => codeSkill,
44
44
  createCodeRuntimeControlClient: () => createCodeRuntimeControlClient,
45
45
  createCodeRuntimeInference: () => createCodeRuntimeInference,
46
+ createCodeRuntimeSessionSkillLoader: () => createCodeRuntimeSessionSkillLoader,
46
47
  createCodeToolBroker: () => createCodeToolBroker,
47
48
  createCodeWorkspaceCheckpoint: () => createCodeWorkspaceCheckpoint,
48
49
  createContainerRecipeExecutor: () => createContainerRecipeExecutor,
@@ -79,6 +80,7 @@ __export(node_exports, {
79
80
  safeWorkspaceLabel: () => safeWorkspaceLabel,
80
81
  selectContainerEngine: () => selectContainerEngine,
81
82
  selectWinner: () => selectWinner,
83
+ sessionSkillsFor: () => sessionSkillsFor,
82
84
  stageWorkspace: () => stageWorkspace,
83
85
  stageWorkspacePair: () => stageWorkspacePair,
84
86
  straySubGoalFiles: () => straySubGoalFiles,
@@ -892,7 +894,7 @@ async function runHarnessRunner(options) {
892
894
  } while (!options.signal?.aborted);
893
895
  }
894
896
 
895
- // src/code-runtime-client.ts
897
+ // src/code-runtime-client-validation.ts
896
898
  var import_code = require("@odla-ai/camel/code");
897
899
  var CodeRuntimeControlError = class extends Error {
898
900
  constructor(message2, status, code = "control_error") {
@@ -904,101 +906,6 @@ var CodeRuntimeControlError = class extends Error {
904
906
  code;
905
907
  name = "CodeRuntimeControlError";
906
908
  };
907
- function createCodeRuntimeControlClient(options) {
908
- const endpoint = validatedEndpoint(options.endpoint);
909
- if (!/^odla_code_host_[0-9a-f]{64}$/.test(options.token)) throw new TypeError("invalid Code host credential");
910
- const requestTimeoutMs = options.requestTimeoutMs ?? 3e4;
911
- if (!Number.isSafeInteger(requestTimeoutMs) || requestTimeoutMs < 1e3 || requestTimeoutMs > 12e4) {
912
- throw new TypeError("requestTimeoutMs must be an integer from 1000 to 120000");
913
- }
914
- const modelRequestTimeoutMs = options.modelRequestTimeoutMs ?? 15 * 6e4;
915
- if (!Number.isSafeInteger(modelRequestTimeoutMs) || modelRequestTimeoutMs < 3e4 || modelRequestTimeoutMs > 30 * 6e4) {
916
- throw new TypeError("modelRequestTimeoutMs must be an integer from 30000 to 1800000");
917
- }
918
- const request = options.fetch ?? fetch;
919
- const call = async (path, body, timeoutMs = requestTimeoutMs) => {
920
- const timeout = AbortSignal.timeout(timeoutMs);
921
- const signal = options.signal ? AbortSignal.any([options.signal, timeout]) : timeout;
922
- let response2;
923
- try {
924
- response2 = await request(`${endpoint}${path}`, {
925
- method: "POST",
926
- headers: { authorization: `Bearer ${options.token}`, "content-type": "application/json" },
927
- body: JSON.stringify(body),
928
- redirect: "error",
929
- signal
930
- });
931
- } catch (cause) {
932
- if (options.signal?.aborted) throw cause;
933
- throw new CodeRuntimeControlError("Code runtime control plane is unavailable", 503, "transport_unavailable");
934
- }
935
- const value = await response2.json().catch(() => null);
936
- if (!response2.ok) {
937
- const problem = record2(record2(value)?.error);
938
- throw new CodeRuntimeControlError(
939
- typeof problem?.message === "string" ? problem.message : `Code runtime request failed (${response2.status})`,
940
- response2.status,
941
- typeof problem?.code === "string" ? problem.code : void 0
942
- );
943
- }
944
- return value;
945
- };
946
- return {
947
- heartbeat: async (version, capabilities) => {
948
- validateHeartbeat(version, capabilities);
949
- return parseSnapshot(await call("/registry/code/runtime/heartbeat", { runtimeVersion: version, capabilities }));
950
- },
951
- acknowledge: async (commandId, result) => {
952
- if (!/^ccmd_[0-9a-f]{32}$/.test(commandId)) throw new TypeError("invalid Code runtime command id");
953
- await call(`/registry/code/runtime/commands/${commandId}/ack`, result);
954
- },
955
- source: async (sessionId) => parseSource(
956
- await call(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/source`, {})
957
- ),
958
- infer: async (sessionId, inference) => {
959
- const value = record2(await call(
960
- `/registry/code/runtime/sessions/${validSessionId(sessionId)}/inference`,
961
- inference,
962
- modelRequestTimeoutMs
963
- ));
964
- if (!value || value.requestId !== inference.requestId || !record2(value.response) || !record2(value.receipt)) {
965
- throw new CodeRuntimeControlError("invalid Code inference response", 502, "invalid_response");
966
- }
967
- return value;
968
- },
969
- review: async (sessionId, review) => parseReview(
970
- await call(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/review`, review, modelRequestTimeoutMs)
971
- ),
972
- submitCandidate: async (sessionId, checkpointId, verification) => {
973
- if (!/^cpoint_[0-9a-f]{32}$/.test(checkpointId)) throw new TypeError("invalid Code checkpoint id");
974
- return parseCandidate(await call(
975
- `/registry/code/runtime/sessions/${validSessionId(sessionId)}/candidates`,
976
- { checkpointId, verification }
977
- ));
978
- },
979
- appendSessionEvent: async (sessionId, eventId, event) => {
980
- const serialized = JSON.stringify(event);
981
- if (!/^[A-Za-z0-9._:-]{1,120}$/.test(eventId) || !event || typeof event !== "object" || new TextEncoder().encode(serialized).byteLength > 24e3) {
982
- throw new TypeError("invalid Code session event");
983
- }
984
- await call(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/chat/events`, { eventId, event });
985
- },
986
- recallMemories: async (sessionId, subjects, limit) => {
987
- const response2 = await call(
988
- `/registry/code/runtime/sessions/${validSessionId(sessionId)}/recall`,
989
- { subjects: [...subjects], limit }
990
- );
991
- return Array.isArray(response2.memories) ? response2.memories : [];
992
- },
993
- rememberMemory: async (sessionId, memory) => {
994
- await call(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/remember`, memory);
995
- },
996
- reportSessionFailure: async (sessionId, message2) => {
997
- if (!message2.trim() || message2.length > 2e3) throw new TypeError("invalid Code session failure");
998
- await call(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/failure`, { message: message2 });
999
- }
1000
- };
1001
- }
1002
909
  function validatedEndpoint(value) {
1003
910
  const endpoint = value.replace(/\/+$/, "");
1004
911
  let url;
@@ -1017,6 +924,10 @@ function validSessionId(value) {
1017
924
  if (!/^csess_[0-9a-f]{32}$/.test(value)) throw new TypeError("invalid Code session id");
1018
925
  return value;
1019
926
  }
927
+ function validCommandId(value) {
928
+ if (!/^ccmd_[0-9a-f]{32}$/.test(value)) throw new TypeError("invalid Code runtime command id");
929
+ return value;
930
+ }
1020
931
  function validateHeartbeat(version, capabilities) {
1021
932
  if (!version.trim() || version.length > 80) throw new TypeError("runtimeVersion is required and at most 80 characters");
1022
933
  if (capabilities.protocolVersion !== CODE_RUNTIME_PROTOCOL_VERSION) throw new TypeError("unsupported Code runtime protocol version");
@@ -1098,9 +1009,211 @@ function parseCandidate(value) {
1098
1009
  }
1099
1010
  return { candidateId: candidate.candidateId, status: candidate.status };
1100
1011
  }
1012
+ function parseCollaborationSkills(value) {
1013
+ const items = record2(value)?.skills;
1014
+ if (!Array.isArray(items) || items.length > 16) throw invalid("collaboration skills");
1015
+ const skillNames = /* @__PURE__ */ new Set();
1016
+ const toolNames = /* @__PURE__ */ new Set();
1017
+ return items.map((item) => {
1018
+ const skill = record2(item);
1019
+ 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) {
1020
+ throw invalid("collaboration skill");
1021
+ }
1022
+ skillNames.add(skill.name);
1023
+ const tools = skill.tools.map((candidate) => {
1024
+ const tool = record2(candidate);
1025
+ const inputSchema = record2(tool?.inputSchema);
1026
+ 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") {
1027
+ throw invalid("collaboration tool");
1028
+ }
1029
+ const outputTaint = parseTaintLabels(tool.outputTaint);
1030
+ const acceptsTaint = parseTaintLabels(tool.acceptsTaint);
1031
+ toolNames.add(tool.name);
1032
+ return {
1033
+ name: tool.name,
1034
+ description: tool.description,
1035
+ inputSchema,
1036
+ ...tool.concurrency === "parallel" ? { concurrency: "parallel" } : {},
1037
+ ...outputTaint ? { outputTaint } : {},
1038
+ ...acceptsTaint ? { acceptsTaint } : {}
1039
+ };
1040
+ });
1041
+ return {
1042
+ name: skill.name,
1043
+ ...typeof skill.instructions === "string" ? { instructions: skill.instructions } : {},
1044
+ tools
1045
+ };
1046
+ });
1047
+ }
1048
+ function validateCollaborationToolRequest(value) {
1049
+ validCommandId(value.commandId);
1050
+ if (typeof value.toolCallId !== "string" || value.toolCallId.length > 256 || !/^[^\s\u0000-\u001f\u007f]+$/.test(value.toolCallId) || !validManifestName(value.skill) || !validManifestName(value.tool) || !record2(value.input) || jsonBytes(value.input) > 128e3) {
1051
+ throw new TypeError("invalid Code collaboration tool request");
1052
+ }
1053
+ }
1054
+ function parseCollaborationToolOutput(value) {
1055
+ const output = record2(record2(value)?.output);
1056
+ if (!output || output.isError !== void 0 && typeof output.isError !== "boolean") {
1057
+ throw invalid("collaboration tool");
1058
+ }
1059
+ if (typeof output.content === "string") {
1060
+ if (utf8Bytes(output.content) > 1e6) throw invalid("collaboration tool");
1061
+ return { content: output.content, ...output.isError === true ? { isError: true } : {} };
1062
+ }
1063
+ if (!Array.isArray(output.content) || output.content.length > 64 || jsonBytes(output.content) > 1e6 || !output.content.every((block) => {
1064
+ const item = record2(block);
1065
+ return item && ["text", "image", "audio", "document", "tool_use", "tool_result", "thinking"].includes(String(item.type));
1066
+ })) throw invalid("collaboration tool");
1067
+ return {
1068
+ content: output.content,
1069
+ ...output.isError === true ? { isError: true } : {}
1070
+ };
1071
+ }
1072
+ function parseTaintLabels(value) {
1073
+ if (value === void 0) return void 0;
1074
+ if (!Array.isArray(value) || value.length > 16) throw invalid("collaboration tool taint");
1075
+ const labels = value.map((item) => {
1076
+ if (item === "web_untrusted" || item === "operator_pasted_untrusted" || item === "llm_inherited") return item;
1077
+ if (typeof item === "string" && /^tool_untrusted:[^\s\u0000-\u001f\u007f]{1,100}$/.test(item)) {
1078
+ return item;
1079
+ }
1080
+ throw invalid("collaboration tool taint");
1081
+ });
1082
+ return [...new Set(labels)];
1083
+ }
1084
+ function validManifestName(value) {
1085
+ return typeof value === "string" && /^[A-Za-z][A-Za-z0-9._:-]{0,127}$/.test(value);
1086
+ }
1087
+ function utf8Bytes(value) {
1088
+ return new TextEncoder().encode(value).byteLength;
1089
+ }
1090
+ function jsonBytes(value) {
1091
+ try {
1092
+ return utf8Bytes(JSON.stringify(value));
1093
+ } catch {
1094
+ return Number.POSITIVE_INFINITY;
1095
+ }
1096
+ }
1101
1097
  var record2 = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
1102
1098
  var invalid = (part) => new CodeRuntimeControlError(`invalid Code runtime ${part} response`, 502, "invalid_response");
1103
1099
 
1100
+ // src/code-runtime-client.ts
1101
+ function createCodeRuntimeControlClient(options) {
1102
+ const endpoint = validatedEndpoint(options.endpoint);
1103
+ if (!/^odla_code_host_[0-9a-f]{64}$/.test(options.token)) throw new TypeError("invalid Code host credential");
1104
+ const requestTimeoutMs = options.requestTimeoutMs ?? 3e4;
1105
+ if (!Number.isSafeInteger(requestTimeoutMs) || requestTimeoutMs < 1e3 || requestTimeoutMs > 12e4) {
1106
+ throw new TypeError("requestTimeoutMs must be an integer from 1000 to 120000");
1107
+ }
1108
+ const modelRequestTimeoutMs = options.modelRequestTimeoutMs ?? 15 * 6e4;
1109
+ if (!Number.isSafeInteger(modelRequestTimeoutMs) || modelRequestTimeoutMs < 3e4 || modelRequestTimeoutMs > 30 * 6e4) {
1110
+ throw new TypeError("modelRequestTimeoutMs must be an integer from 30000 to 1800000");
1111
+ }
1112
+ const request = options.fetch ?? fetch;
1113
+ const call = async (path, body, timeoutMs = requestTimeoutMs, operationSignal) => {
1114
+ const timeout = AbortSignal.timeout(timeoutMs);
1115
+ const signals = [options.signal, operationSignal, timeout].filter((item) => Boolean(item));
1116
+ const signal = signals.length === 1 ? signals[0] : AbortSignal.any(signals);
1117
+ let response2;
1118
+ try {
1119
+ response2 = await request(`${endpoint}${path}`, {
1120
+ method: "POST",
1121
+ headers: { authorization: `Bearer ${options.token}`, "content-type": "application/json" },
1122
+ body: JSON.stringify(body),
1123
+ redirect: "error",
1124
+ signal
1125
+ });
1126
+ } catch (cause) {
1127
+ if (options.signal?.aborted || operationSignal?.aborted) throw cause;
1128
+ throw new CodeRuntimeControlError("Code runtime control plane is unavailable", 503, "transport_unavailable");
1129
+ }
1130
+ const value = await response2.json().catch(() => null);
1131
+ if (!response2.ok) {
1132
+ const problem = record2(record2(value)?.error);
1133
+ throw new CodeRuntimeControlError(
1134
+ typeof problem?.message === "string" ? problem.message : `Code runtime request failed (${response2.status})`,
1135
+ response2.status,
1136
+ typeof problem?.code === "string" ? problem.code : void 0
1137
+ );
1138
+ }
1139
+ return value;
1140
+ };
1141
+ return {
1142
+ heartbeat: async (version, capabilities) => {
1143
+ validateHeartbeat(version, capabilities);
1144
+ return parseSnapshot(await call("/registry/code/runtime/heartbeat", { runtimeVersion: version, capabilities }));
1145
+ },
1146
+ acknowledge: async (commandId, result) => {
1147
+ await call(`/registry/code/runtime/commands/${validCommandId(commandId)}/ack`, result);
1148
+ },
1149
+ source: async (sessionId) => parseSource(
1150
+ await call(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/source`, {})
1151
+ ),
1152
+ infer: async (sessionId, inference) => {
1153
+ const value = record2(await call(
1154
+ `/registry/code/runtime/sessions/${validSessionId(sessionId)}/inference`,
1155
+ inference,
1156
+ modelRequestTimeoutMs
1157
+ ));
1158
+ if (!value || value.requestId !== inference.requestId || !record2(value.response) || !record2(value.receipt)) {
1159
+ throw new CodeRuntimeControlError("invalid Code inference response", 502, "invalid_response");
1160
+ }
1161
+ return value;
1162
+ },
1163
+ review: async (sessionId, review) => parseReview(
1164
+ await call(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/review`, review, modelRequestTimeoutMs)
1165
+ ),
1166
+ submitCandidate: async (sessionId, checkpointId, verification) => {
1167
+ if (!/^cpoint_[0-9a-f]{32}$/.test(checkpointId)) throw new TypeError("invalid Code checkpoint id");
1168
+ return parseCandidate(await call(
1169
+ `/registry/code/runtime/sessions/${validSessionId(sessionId)}/candidates`,
1170
+ { checkpointId, verification }
1171
+ ));
1172
+ },
1173
+ appendSessionEvent: async (sessionId, eventId, event) => {
1174
+ const serialized = JSON.stringify(event);
1175
+ if (!/^[A-Za-z0-9._:-]{1,120}$/.test(eventId) || !event || typeof event !== "object" || new TextEncoder().encode(serialized).byteLength > 24e3) {
1176
+ throw new TypeError("invalid Code session event");
1177
+ }
1178
+ await call(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/chat/events`, { eventId, event });
1179
+ },
1180
+ recallMemories: async (sessionId, subjects, limit) => {
1181
+ const response2 = await call(
1182
+ `/registry/code/runtime/sessions/${validSessionId(sessionId)}/recall`,
1183
+ { subjects: [...subjects], limit }
1184
+ );
1185
+ return Array.isArray(response2.memories) ? response2.memories : [];
1186
+ },
1187
+ rememberMemory: async (sessionId, memory) => {
1188
+ await call(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/remember`, memory);
1189
+ },
1190
+ collaborationSkills: async (sessionId, commandId) => {
1191
+ try {
1192
+ return parseCollaborationSkills(await call(
1193
+ `/registry/code/runtime/sessions/${validSessionId(sessionId)}/collaboration/skills`,
1194
+ { commandId: validCommandId(commandId) }
1195
+ ));
1196
+ } catch (cause) {
1197
+ if (cause instanceof CodeRuntimeControlError && cause.status === 404 && cause.code === "not_found") return [];
1198
+ throw cause;
1199
+ }
1200
+ },
1201
+ executeCollaborationTool: async (sessionId, collaboration, signal) => {
1202
+ validateCollaborationToolRequest(collaboration);
1203
+ return parseCollaborationToolOutput(await call(
1204
+ `/registry/code/runtime/sessions/${validSessionId(sessionId)}/collaboration/tools`,
1205
+ collaboration,
1206
+ requestTimeoutMs,
1207
+ signal
1208
+ ));
1209
+ },
1210
+ reportSessionFailure: async (sessionId, message2) => {
1211
+ if (!message2.trim() || message2.length > 2e3) throw new TypeError("invalid Code session failure");
1212
+ await call(`/registry/code/runtime/sessions/${validSessionId(sessionId)}/failure`, { message: message2 });
1213
+ }
1214
+ };
1215
+ }
1216
+
1104
1217
  // src/code-runtime.ts
1105
1218
  var CODE_RUNTIME_PROTOCOL_VERSION = 1;
1106
1219
  async function runCodeRuntimeHeartbeatLoop(options) {
@@ -2208,6 +2321,7 @@ async function runCodeAgentAttempt(options) {
2208
2321
  model: "brokered",
2209
2322
  surface,
2210
2323
  ...options.recipeIds ? { recipeIds: options.recipeIds } : {},
2324
+ ...options.extraSkills ? { extraSkills: options.extraSkills } : {},
2211
2325
  ...options.maxSteps === void 0 ? {} : { maxSteps: options.maxSteps },
2212
2326
  ...options.budget ? { budget: options.budget } : {},
2213
2327
  ...options.signal ? { signal: options.signal } : {},
@@ -2239,6 +2353,48 @@ Finish with a concise, non-empty answer to the owner. Do not call tools or promi
2239
2353
  }
2240
2354
  }
2241
2355
 
2356
+ // src/code-runtime-session-skills.ts
2357
+ function createCodeRuntimeSessionSkillLoader(control) {
2358
+ const load = control.collaborationSkills?.bind(control);
2359
+ const execute2 = control.executeCollaborationTool?.bind(control);
2360
+ if (!load || !execute2) return async () => [];
2361
+ return async (command) => {
2362
+ const manifests = await load(command.sessionId, command.commandId);
2363
+ return manifests.map((manifest) => ({
2364
+ name: manifest.name,
2365
+ ...manifest.instructions === void 0 ? {} : { instructions: manifest.instructions },
2366
+ tools: manifest.tools.map((tool) => ({
2367
+ name: tool.name,
2368
+ description: tool.description,
2369
+ inputSchema: tool.inputSchema,
2370
+ ...tool.concurrency === void 0 ? {} : { concurrency: tool.concurrency },
2371
+ ...tool.outputTaint === void 0 ? {} : { outputTaint: tool.outputTaint },
2372
+ ...tool.acceptsTaint === void 0 ? {} : { acceptsTaint: tool.acceptsTaint },
2373
+ handler: async (input, context) => {
2374
+ if (!context.toolCallId) throw new TypeError("collaboration tool call identity is required");
2375
+ return execute2(command.sessionId, {
2376
+ commandId: command.commandId,
2377
+ toolCallId: context.toolCallId,
2378
+ skill: manifest.name,
2379
+ tool: tool.name,
2380
+ input
2381
+ }, context.signal);
2382
+ }
2383
+ }))
2384
+ }));
2385
+ };
2386
+ }
2387
+ async function sessionSkillsFor(options, command) {
2388
+ try {
2389
+ return await options.sessionSkills?.(command) ?? [];
2390
+ } catch (cause) {
2391
+ options.onDiagnostic?.(
2392
+ `session skills unavailable, continuing with code tools only: ${cause instanceof Error ? cause.message : String(cause)}`
2393
+ );
2394
+ return [];
2395
+ }
2396
+ }
2397
+
2242
2398
  // src/code-runtime-inference.ts
2243
2399
  async function handleCodeRuntimeInference(input) {
2244
2400
  const { command, request, state } = input;
@@ -3457,6 +3613,25 @@ function codeToolResultPresentation(request, response2) {
3457
3613
  };
3458
3614
  }
3459
3615
 
3616
+ // src/code-runtime-acknowledgement-gate.ts
3617
+ function codeRuntimeAcknowledgementGate(signal) {
3618
+ let settle;
3619
+ let settled = false;
3620
+ const ready = new Promise((resolve7) => {
3621
+ settle = resolve7;
3622
+ });
3623
+ const release = (run) => {
3624
+ if (settled) return;
3625
+ settled = true;
3626
+ signal.removeEventListener("abort", onAbort);
3627
+ settle(run);
3628
+ };
3629
+ const onAbort = () => release(false);
3630
+ if (signal.aborted) release(false);
3631
+ else signal.addEventListener("abort", onAbort, { once: true });
3632
+ return { ready, release };
3633
+ }
3634
+
3460
3635
  // src/code-runtime-engine.ts
3461
3636
  var TheseusRuntimeEngine = class {
3462
3637
  constructor(options) {
@@ -3487,6 +3662,8 @@ var TheseusRuntimeEngine = class {
3487
3662
  const active = this.#active.get(command.sessionId);
3488
3663
  if (!active || result.status !== "running") return;
3489
3664
  active.acknowledged = true;
3665
+ active.startGate?.release(true);
3666
+ active.startGate = void 0;
3490
3667
  if (active.failure) await this.options.control.reportSessionFailure(command.sessionId, active.failure).catch(() => void 0);
3491
3668
  }
3492
3669
  async close() {
@@ -3506,13 +3683,14 @@ var TheseusRuntimeEngine = class {
3506
3683
  control: this.options.control,
3507
3684
  ...this.options.localSource ? { localSource: this.options.localSource } : {}
3508
3685
  });
3509
- const abort = new AbortController();
3686
+ const abort = new AbortController(), startGate = codeRuntimeAcknowledgementGate(abort.signal);
3510
3687
  const conversationRefs = [];
3511
3688
  const active = {
3512
3689
  workspace,
3513
3690
  abort,
3514
3691
  conversationRefs,
3515
3692
  acknowledged: false,
3693
+ startGate,
3516
3694
  role: metadata.role,
3517
3695
  title: metadata.title,
3518
3696
  maxTokensPerInteraction: metadata.maxTokensPerInteraction,
@@ -3536,7 +3714,7 @@ var TheseusRuntimeEngine = class {
3536
3714
  body: `Source snapshot: local checkout ${requestedLocal.snapshotDigest} \xB7 ${requestedLocal.modified ? "modified" : "clean"} \xB7 Git ${requestedLocal.headCommitSha}`
3537
3715
  }, conversationRefs);
3538
3716
  }
3539
- active.done = this.#runAttempt(command, metadata, active).catch(async (cause) => {
3717
+ active.done = startGate.ready.then((run) => run ? this.#runAttempt(command, metadata, active) : null).catch(async (cause) => {
3540
3718
  const detail = runtimeErrorMessage(cause);
3541
3719
  await this.#event(command, { type: "message", actor: "system", body: detail }, conversationRefs).catch(() => void 0);
3542
3720
  await this.#diagnostic(command, active, detail);
@@ -3651,6 +3829,7 @@ var TheseusRuntimeEngine = class {
3651
3829
  event: (event) => this.#event(command, event, active.conversationRefs)
3652
3830
  });
3653
3831
  await this.#event(command, { type: "status", status: "running" }, active.conversationRefs);
3832
+ const extraSkills = await sessionSkillsFor(this.options, command);
3654
3833
  const result = await this.#attempt({
3655
3834
  inference,
3656
3835
  broker,
@@ -3658,7 +3837,8 @@ var TheseusRuntimeEngine = class {
3658
3837
  workspaceDir: active.workspace.workspaceDir,
3659
3838
  prompt: metadata.prompt,
3660
3839
  signal: active.abort.signal,
3661
- recipeIds: this.options.recipes.map((recipe2) => recipe2.id)
3840
+ recipeIds: this.options.recipes.map((recipe2) => recipe2.id),
3841
+ ...extraSkills.length ? { extraSkills } : {}
3662
3842
  });
3663
3843
  const closing = result.finalText.trim();
3664
3844
  const completed = result.status === "completed" && Boolean(closing);
@@ -4071,6 +4251,7 @@ async function installedDependencies(repoRoot) {
4071
4251
  codeSkill,
4072
4252
  createCodeRuntimeControlClient,
4073
4253
  createCodeRuntimeInference,
4254
+ createCodeRuntimeSessionSkillLoader,
4074
4255
  createCodeToolBroker,
4075
4256
  createCodeWorkspaceCheckpoint,
4076
4257
  createContainerRecipeExecutor,
@@ -4107,6 +4288,7 @@ async function installedDependencies(repoRoot) {
4107
4288
  safeWorkspaceLabel,
4108
4289
  selectContainerEngine,
4109
4290
  selectWinner,
4291
+ sessionSkillsFor,
4110
4292
  stageWorkspace,
4111
4293
  stageWorkspacePair,
4112
4294
  straySubGoalFiles,