@odla-ai/harness 0.8.1 → 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 +11 -0
- package/dist/{chunk-IWVGSWY6.js → chunk-NG7AYYH3.js} +268 -103
- package/dist/chunk-NG7AYYH3.js.map +1 -0
- package/dist/code-runtime-cli.cjs +262 -98
- package/dist/code-runtime-cli.cjs.map +1 -1
- package/dist/code-runtime-cli.js +3 -1
- package/dist/code-runtime-cli.js.map +1 -1
- package/dist/node.cjs +265 -98
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.cts +65 -15
- package/dist/node.d.ts +65 -15
- package/dist/node.js +5 -1
- package/dist/node.js.map +1 -1
- package/package.json +2 -2
- package/dist/chunk-IWVGSWY6.js.map +0 -1
package/dist/code-runtime-cli.js
CHANGED
|
@@ -5,8 +5,9 @@ import {
|
|
|
5
5
|
TheseusRuntimeEngine,
|
|
6
6
|
assertCodeBuildRecipe,
|
|
7
7
|
createCodeRuntimeControlClient,
|
|
8
|
+
createCodeRuntimeSessionSkillLoader,
|
|
8
9
|
runCodeRuntimeHeartbeatLoop
|
|
9
|
-
} from "./chunk-
|
|
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":"
|
|
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) {
|
|
@@ -2241,6 +2354,36 @@ Finish with a concise, non-empty answer to the owner. Do not call tools or promi
|
|
|
2241
2354
|
}
|
|
2242
2355
|
|
|
2243
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
|
+
}
|
|
2244
2387
|
async function sessionSkillsFor(options, command) {
|
|
2245
2388
|
try {
|
|
2246
2389
|
return await options.sessionSkills?.(command) ?? [];
|
|
@@ -3470,6 +3613,25 @@ function codeToolResultPresentation(request, response2) {
|
|
|
3470
3613
|
};
|
|
3471
3614
|
}
|
|
3472
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
|
+
|
|
3473
3635
|
// src/code-runtime-engine.ts
|
|
3474
3636
|
var TheseusRuntimeEngine = class {
|
|
3475
3637
|
constructor(options) {
|
|
@@ -3500,6 +3662,8 @@ var TheseusRuntimeEngine = class {
|
|
|
3500
3662
|
const active = this.#active.get(command.sessionId);
|
|
3501
3663
|
if (!active || result.status !== "running") return;
|
|
3502
3664
|
active.acknowledged = true;
|
|
3665
|
+
active.startGate?.release(true);
|
|
3666
|
+
active.startGate = void 0;
|
|
3503
3667
|
if (active.failure) await this.options.control.reportSessionFailure(command.sessionId, active.failure).catch(() => void 0);
|
|
3504
3668
|
}
|
|
3505
3669
|
async close() {
|
|
@@ -3519,13 +3683,14 @@ var TheseusRuntimeEngine = class {
|
|
|
3519
3683
|
control: this.options.control,
|
|
3520
3684
|
...this.options.localSource ? { localSource: this.options.localSource } : {}
|
|
3521
3685
|
});
|
|
3522
|
-
const abort = new AbortController();
|
|
3686
|
+
const abort = new AbortController(), startGate = codeRuntimeAcknowledgementGate(abort.signal);
|
|
3523
3687
|
const conversationRefs = [];
|
|
3524
3688
|
const active = {
|
|
3525
3689
|
workspace,
|
|
3526
3690
|
abort,
|
|
3527
3691
|
conversationRefs,
|
|
3528
3692
|
acknowledged: false,
|
|
3693
|
+
startGate,
|
|
3529
3694
|
role: metadata.role,
|
|
3530
3695
|
title: metadata.title,
|
|
3531
3696
|
maxTokensPerInteraction: metadata.maxTokensPerInteraction,
|
|
@@ -3549,7 +3714,7 @@ var TheseusRuntimeEngine = class {
|
|
|
3549
3714
|
body: `Source snapshot: local checkout ${requestedLocal.snapshotDigest} \xB7 ${requestedLocal.modified ? "modified" : "clean"} \xB7 Git ${requestedLocal.headCommitSha}`
|
|
3550
3715
|
}, conversationRefs);
|
|
3551
3716
|
}
|
|
3552
|
-
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) => {
|
|
3553
3718
|
const detail = runtimeErrorMessage(cause);
|
|
3554
3719
|
await this.#event(command, { type: "message", actor: "system", body: detail }, conversationRefs).catch(() => void 0);
|
|
3555
3720
|
await this.#diagnostic(command, active, detail);
|
|
@@ -4086,6 +4251,7 @@ async function installedDependencies(repoRoot) {
|
|
|
4086
4251
|
codeSkill,
|
|
4087
4252
|
createCodeRuntimeControlClient,
|
|
4088
4253
|
createCodeRuntimeInference,
|
|
4254
|
+
createCodeRuntimeSessionSkillLoader,
|
|
4089
4255
|
createCodeToolBroker,
|
|
4090
4256
|
createCodeWorkspaceCheckpoint,
|
|
4091
4257
|
createContainerRecipeExecutor,
|
|
@@ -4122,6 +4288,7 @@ async function installedDependencies(repoRoot) {
|
|
|
4122
4288
|
safeWorkspaceLabel,
|
|
4123
4289
|
selectContainerEngine,
|
|
4124
4290
|
selectWinner,
|
|
4291
|
+
sessionSkillsFor,
|
|
4125
4292
|
stageWorkspace,
|
|
4126
4293
|
stageWorkspacePair,
|
|
4127
4294
|
straySubGoalFiles,
|