@odla-ai/harness 0.8.1 → 0.9.1
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-4EPJJMFG.js} +330 -106
- package/dist/chunk-4EPJJMFG.js.map +1 -0
- package/dist/{chunk-NWNBSX56.js → chunk-CIKYMC67.js} +4 -4
- package/dist/{chunk-CR6RE3A2.js → chunk-HDIR4MM5.js} +3 -3
- package/dist/{chunk-RXNHCGWE.js → chunk-I43KTCJ2.js} +1 -1
- package/dist/{chunk-RXNHCGWE.js.map → chunk-I43KTCJ2.js.map} +1 -1
- package/dist/{chunk-Q7CKOT7T.js → chunk-VGNIDRKM.js} +2 -2
- package/dist/cli.cjs.map +1 -1
- package/dist/cli.js +4 -4
- package/dist/code-runtime-cli.cjs +330 -102
- package/dist/code-runtime-cli.cjs.map +1 -1
- package/dist/code-runtime-cli.js +12 -5
- package/dist/code-runtime-cli.js.map +1 -1
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -2
- package/dist/index.d.ts +2 -2
- package/dist/index.js +2 -2
- package/dist/node.cjs +327 -101
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.cts +71 -17
- package/dist/node.d.ts +71 -17
- package/dist/node.js +9 -5
- package/dist/node.js.map +1 -1
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.d.cts +1 -1
- package/dist/testing.d.ts +1 -1
- package/dist/testing.js +1 -1
- package/dist/{types-BNJikP5h.d.cts → types-BazqxWK8.d.cts} +14 -0
- package/dist/{types-BNJikP5h.d.ts → types-BazqxWK8.d.ts} +14 -0
- package/package.json +2 -2
- package/dist/chunk-IWVGSWY6.js.map +0 -1
- /package/dist/{chunk-NWNBSX56.js.map → chunk-CIKYMC67.js.map} +0 -0
- /package/dist/{chunk-CR6RE3A2.js.map → chunk-HDIR4MM5.js.map} +0 -0
- /package/dist/{chunk-Q7CKOT7T.js.map → chunk-VGNIDRKM.js.map} +0 -0
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:
|
|
@@ -4,10 +4,10 @@ import {
|
|
|
4
4
|
stageWorkspace,
|
|
5
5
|
stageWorkspacePair,
|
|
6
6
|
verifyContainerEngineBoundary
|
|
7
|
-
} from "./chunk-
|
|
7
|
+
} from "./chunk-HDIR4MM5.js";
|
|
8
8
|
import {
|
|
9
9
|
HARNESS_PROTOCOL_VERSION
|
|
10
|
-
} from "./chunk-
|
|
10
|
+
} from "./chunk-I43KTCJ2.js";
|
|
11
11
|
|
|
12
12
|
// src/workspace-digest.ts
|
|
13
13
|
import { createHash } from "crypto";
|
|
@@ -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
|
|
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
|
-
|
|
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,124 @@ 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, onDiagnostic) {
|
|
190
|
+
this.control = control;
|
|
191
|
+
this.engine = engine;
|
|
192
|
+
this.onDiagnostic = onDiagnostic;
|
|
193
|
+
}
|
|
194
|
+
control;
|
|
195
|
+
engine;
|
|
196
|
+
onDiagnostic;
|
|
197
|
+
results = /* @__PURE__ */ new Map();
|
|
198
|
+
async reconcile(snapshot) {
|
|
199
|
+
for (const command of snapshot.commands) {
|
|
200
|
+
let completed = this.results.get(command.commandId);
|
|
201
|
+
if (!completed) {
|
|
202
|
+
let result;
|
|
203
|
+
try {
|
|
204
|
+
result = await this.engine.execute(command);
|
|
205
|
+
} catch (error) {
|
|
206
|
+
result = { status: "failed", message: (error instanceof Error ? error.message : String(error)).slice(0, 2e3) };
|
|
207
|
+
}
|
|
208
|
+
completed = { result, notified: false };
|
|
209
|
+
this.results.set(command.commandId, completed);
|
|
210
|
+
if (this.results.size > 1024) this.results.delete(this.results.keys().next().value);
|
|
211
|
+
}
|
|
212
|
+
await this.control.acknowledge(command.commandId, completed.result);
|
|
213
|
+
if (!completed.notified) {
|
|
214
|
+
try {
|
|
215
|
+
await this.engine.acknowledged?.(command, completed.result);
|
|
216
|
+
} catch (error) {
|
|
217
|
+
this.onDiagnostic?.(
|
|
218
|
+
`command ${command.commandId} acknowledged handling failed \xB7 ${error instanceof Error ? error.message : String(error)}`
|
|
219
|
+
);
|
|
220
|
+
}
|
|
221
|
+
completed.notified = true;
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
};
|
|
226
|
+
function retryableControlFailure(value) {
|
|
227
|
+
if (!value || typeof value !== "object") return false;
|
|
228
|
+
const failure = value;
|
|
229
|
+
if (failure.code === "invalid_response" || typeof failure.status !== "number") return false;
|
|
230
|
+
return failure.status === 408 || failure.status === 425 || failure.status === 429 || failure.status >= 500;
|
|
231
|
+
}
|
|
232
|
+
function wait(ms, signal) {
|
|
233
|
+
return new Promise((resolve5) => {
|
|
234
|
+
if (signal?.aborted) return resolve5();
|
|
235
|
+
const timer = setTimeout(resolve5, ms);
|
|
236
|
+
signal?.addEventListener("abort", () => {
|
|
237
|
+
clearTimeout(timer);
|
|
238
|
+
resolve5();
|
|
239
|
+
}, { once: true });
|
|
240
|
+
});
|
|
241
|
+
}
|
|
242
|
+
|
|
243
|
+
// src/code-runtime-client-validation.ts
|
|
244
|
+
var CodeRuntimeControlError = class extends Error {
|
|
245
|
+
constructor(message2, status, code = "control_error") {
|
|
246
|
+
super(message2);
|
|
247
|
+
this.status = status;
|
|
248
|
+
this.code = code;
|
|
249
|
+
}
|
|
250
|
+
status;
|
|
251
|
+
code;
|
|
252
|
+
name = "CodeRuntimeControlError";
|
|
253
|
+
};
|
|
224
254
|
function validatedEndpoint(value) {
|
|
225
255
|
const endpoint = value.replace(/\/+$/, "");
|
|
226
256
|
let url;
|
|
@@ -239,6 +269,10 @@ function validSessionId(value) {
|
|
|
239
269
|
if (!/^csess_[0-9a-f]{32}$/.test(value)) throw new TypeError("invalid Code session id");
|
|
240
270
|
return value;
|
|
241
271
|
}
|
|
272
|
+
function validCommandId(value) {
|
|
273
|
+
if (!/^ccmd_[0-9a-f]{32}$/.test(value)) throw new TypeError("invalid Code runtime command id");
|
|
274
|
+
return value;
|
|
275
|
+
}
|
|
242
276
|
function validateHeartbeat(version, capabilities) {
|
|
243
277
|
if (!version.trim() || version.length > 80) throw new TypeError("runtimeVersion is required and at most 80 characters");
|
|
244
278
|
if (capabilities.protocolVersion !== CODE_RUNTIME_PROTOCOL_VERSION) throw new TypeError("unsupported Code runtime protocol version");
|
|
@@ -320,6 +354,91 @@ function parseCandidate(value) {
|
|
|
320
354
|
}
|
|
321
355
|
return { candidateId: candidate.candidateId, status: candidate.status };
|
|
322
356
|
}
|
|
357
|
+
function parseCollaborationSkills(value) {
|
|
358
|
+
const items = record(value)?.skills;
|
|
359
|
+
if (!Array.isArray(items) || items.length > 16) throw invalid("collaboration skills");
|
|
360
|
+
const skillNames = /* @__PURE__ */ new Set();
|
|
361
|
+
const toolNames = /* @__PURE__ */ new Set();
|
|
362
|
+
return items.map((item) => {
|
|
363
|
+
const skill = record(item);
|
|
364
|
+
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) {
|
|
365
|
+
throw invalid("collaboration skill");
|
|
366
|
+
}
|
|
367
|
+
skillNames.add(skill.name);
|
|
368
|
+
const tools = skill.tools.map((candidate) => {
|
|
369
|
+
const tool = record(candidate);
|
|
370
|
+
const inputSchema = record(tool?.inputSchema);
|
|
371
|
+
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") {
|
|
372
|
+
throw invalid("collaboration tool");
|
|
373
|
+
}
|
|
374
|
+
const outputTaint = parseTaintLabels(tool.outputTaint);
|
|
375
|
+
const acceptsTaint = parseTaintLabels(tool.acceptsTaint);
|
|
376
|
+
toolNames.add(tool.name);
|
|
377
|
+
return {
|
|
378
|
+
name: tool.name,
|
|
379
|
+
description: tool.description,
|
|
380
|
+
inputSchema,
|
|
381
|
+
...tool.concurrency === "parallel" ? { concurrency: "parallel" } : {},
|
|
382
|
+
...outputTaint ? { outputTaint } : {},
|
|
383
|
+
...acceptsTaint ? { acceptsTaint } : {}
|
|
384
|
+
};
|
|
385
|
+
});
|
|
386
|
+
return {
|
|
387
|
+
name: skill.name,
|
|
388
|
+
...typeof skill.instructions === "string" ? { instructions: skill.instructions } : {},
|
|
389
|
+
tools
|
|
390
|
+
};
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
function validateCollaborationToolRequest(value) {
|
|
394
|
+
validCommandId(value.commandId);
|
|
395
|
+
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) {
|
|
396
|
+
throw new TypeError("invalid Code collaboration tool request");
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
function parseCollaborationToolOutput(value) {
|
|
400
|
+
const output = record(record(value)?.output);
|
|
401
|
+
if (!output || output.isError !== void 0 && typeof output.isError !== "boolean") {
|
|
402
|
+
throw invalid("collaboration tool");
|
|
403
|
+
}
|
|
404
|
+
if (typeof output.content === "string") {
|
|
405
|
+
if (utf8Bytes(output.content) > 1e6) throw invalid("collaboration tool");
|
|
406
|
+
return { content: output.content, ...output.isError === true ? { isError: true } : {} };
|
|
407
|
+
}
|
|
408
|
+
if (!Array.isArray(output.content) || output.content.length > 64 || jsonBytes(output.content) > 1e6 || !output.content.every((block) => {
|
|
409
|
+
const item = record(block);
|
|
410
|
+
return item && ["text", "image", "audio", "document", "tool_use", "tool_result", "thinking"].includes(String(item.type));
|
|
411
|
+
})) throw invalid("collaboration tool");
|
|
412
|
+
return {
|
|
413
|
+
content: output.content,
|
|
414
|
+
...output.isError === true ? { isError: true } : {}
|
|
415
|
+
};
|
|
416
|
+
}
|
|
417
|
+
function parseTaintLabels(value) {
|
|
418
|
+
if (value === void 0) return void 0;
|
|
419
|
+
if (!Array.isArray(value) || value.length > 16) throw invalid("collaboration tool taint");
|
|
420
|
+
const labels = value.map((item) => {
|
|
421
|
+
if (item === "web_untrusted" || item === "operator_pasted_untrusted" || item === "llm_inherited") return item;
|
|
422
|
+
if (typeof item === "string" && /^tool_untrusted:[^\s\u0000-\u001f\u007f]{1,100}$/.test(item)) {
|
|
423
|
+
return item;
|
|
424
|
+
}
|
|
425
|
+
throw invalid("collaboration tool taint");
|
|
426
|
+
});
|
|
427
|
+
return [...new Set(labels)];
|
|
428
|
+
}
|
|
429
|
+
function validManifestName(value) {
|
|
430
|
+
return typeof value === "string" && /^[A-Za-z][A-Za-z0-9._:-]{0,127}$/.test(value);
|
|
431
|
+
}
|
|
432
|
+
function utf8Bytes(value) {
|
|
433
|
+
return new TextEncoder().encode(value).byteLength;
|
|
434
|
+
}
|
|
435
|
+
function jsonBytes(value) {
|
|
436
|
+
try {
|
|
437
|
+
return utf8Bytes(JSON.stringify(value));
|
|
438
|
+
} catch {
|
|
439
|
+
return Number.POSITIVE_INFINITY;
|
|
440
|
+
}
|
|
441
|
+
}
|
|
323
442
|
var record = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : null;
|
|
324
443
|
var invalid = (part) => new CodeRuntimeControlError(`invalid Code runtime ${part} response`, 502, "invalid_response");
|
|
325
444
|
|
|
@@ -1390,6 +1509,48 @@ Finish with a concise, non-empty answer to the owner. Do not call tools or promi
|
|
|
1390
1509
|
}
|
|
1391
1510
|
}
|
|
1392
1511
|
|
|
1512
|
+
// src/code-runtime-session-skills.ts
|
|
1513
|
+
function createCodeRuntimeSessionSkillLoader(control) {
|
|
1514
|
+
const load = control.collaborationSkills?.bind(control);
|
|
1515
|
+
const execute2 = control.executeCollaborationTool?.bind(control);
|
|
1516
|
+
if (!load || !execute2) return async () => [];
|
|
1517
|
+
return async (command) => {
|
|
1518
|
+
const manifests = await load(command.sessionId, command.commandId);
|
|
1519
|
+
return manifests.map((manifest) => ({
|
|
1520
|
+
name: manifest.name,
|
|
1521
|
+
...manifest.instructions === void 0 ? {} : { instructions: manifest.instructions },
|
|
1522
|
+
tools: manifest.tools.map((tool) => ({
|
|
1523
|
+
name: tool.name,
|
|
1524
|
+
description: tool.description,
|
|
1525
|
+
inputSchema: tool.inputSchema,
|
|
1526
|
+
...tool.concurrency === void 0 ? {} : { concurrency: tool.concurrency },
|
|
1527
|
+
...tool.outputTaint === void 0 ? {} : { outputTaint: tool.outputTaint },
|
|
1528
|
+
...tool.acceptsTaint === void 0 ? {} : { acceptsTaint: tool.acceptsTaint },
|
|
1529
|
+
handler: async (input, context) => {
|
|
1530
|
+
if (!context.toolCallId) throw new TypeError("collaboration tool call identity is required");
|
|
1531
|
+
return execute2(command.sessionId, {
|
|
1532
|
+
commandId: command.commandId,
|
|
1533
|
+
toolCallId: context.toolCallId,
|
|
1534
|
+
skill: manifest.name,
|
|
1535
|
+
tool: tool.name,
|
|
1536
|
+
input
|
|
1537
|
+
}, context.signal);
|
|
1538
|
+
}
|
|
1539
|
+
}))
|
|
1540
|
+
}));
|
|
1541
|
+
};
|
|
1542
|
+
}
|
|
1543
|
+
async function sessionSkillsFor(options, command) {
|
|
1544
|
+
try {
|
|
1545
|
+
return await options.sessionSkills?.(command) ?? [];
|
|
1546
|
+
} catch (cause) {
|
|
1547
|
+
options.onDiagnostic?.(
|
|
1548
|
+
`session skills unavailable, continuing with code tools only: ${cause instanceof Error ? cause.message : String(cause)}`
|
|
1549
|
+
);
|
|
1550
|
+
return [];
|
|
1551
|
+
}
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1393
1554
|
// src/code-runtime-inference.ts
|
|
1394
1555
|
async function handleCodeRuntimeInference(input) {
|
|
1395
1556
|
const { command, request, state } = input;
|
|
@@ -2324,18 +2485,6 @@ function assertBudget(budget) {
|
|
|
2324
2485
|
}
|
|
2325
2486
|
}
|
|
2326
2487
|
|
|
2327
|
-
// src/code-runtime-session-skills.ts
|
|
2328
|
-
async function sessionSkillsFor(options, command) {
|
|
2329
|
-
try {
|
|
2330
|
-
return await options.sessionSkills?.(command) ?? [];
|
|
2331
|
-
} catch (cause) {
|
|
2332
|
-
options.onDiagnostic?.(
|
|
2333
|
-
`session skills unavailable, continuing with code tools only: ${cause instanceof Error ? cause.message : String(cause)}`
|
|
2334
|
-
);
|
|
2335
|
-
return [];
|
|
2336
|
-
}
|
|
2337
|
-
}
|
|
2338
|
-
|
|
2339
2488
|
// src/code-runtime-broker.ts
|
|
2340
2489
|
function createCodeRuntimeToolBroker(input, lease, role) {
|
|
2341
2490
|
const broker = createCodeToolBroker({
|
|
@@ -2635,6 +2784,76 @@ function codeToolResultPresentation(request, response2) {
|
|
|
2635
2784
|
};
|
|
2636
2785
|
}
|
|
2637
2786
|
|
|
2787
|
+
// src/code-runtime-acknowledgement-gate.ts
|
|
2788
|
+
function codeRuntimeAcknowledgementGate(signal) {
|
|
2789
|
+
let settle;
|
|
2790
|
+
let settled = false;
|
|
2791
|
+
const ready = new Promise((resolve5) => {
|
|
2792
|
+
settle = resolve5;
|
|
2793
|
+
});
|
|
2794
|
+
const release = (run) => {
|
|
2795
|
+
if (settled) return;
|
|
2796
|
+
settled = true;
|
|
2797
|
+
signal.removeEventListener("abort", onAbort);
|
|
2798
|
+
settle(run);
|
|
2799
|
+
};
|
|
2800
|
+
const onAbort = () => release(false);
|
|
2801
|
+
if (signal.aborted) release(false);
|
|
2802
|
+
else signal.addEventListener("abort", onAbort, { once: true });
|
|
2803
|
+
return { ready, release };
|
|
2804
|
+
}
|
|
2805
|
+
|
|
2806
|
+
// src/code-runtime-session-activity.ts
|
|
2807
|
+
function observeCodeRuntimeSessionSkills(command, skills, emit) {
|
|
2808
|
+
return skills.map((skill) => ({
|
|
2809
|
+
...skill,
|
|
2810
|
+
tools: skill.tools.map((tool) => {
|
|
2811
|
+
if (!tool.handler) return tool;
|
|
2812
|
+
const handler = tool.handler;
|
|
2813
|
+
return {
|
|
2814
|
+
...tool,
|
|
2815
|
+
handler: async (input, context) => {
|
|
2816
|
+
const startedAt = Date.now();
|
|
2817
|
+
const operationId = digestRuntimeValue(
|
|
2818
|
+
`${command.commandId}:${skill.name}:${tool.name}:${context.toolCallId ?? "missing"}`
|
|
2819
|
+
);
|
|
2820
|
+
await emit({
|
|
2821
|
+
type: "collaboration",
|
|
2822
|
+
phase: "started",
|
|
2823
|
+
skill: skill.name,
|
|
2824
|
+
tool: tool.name,
|
|
2825
|
+
operationId
|
|
2826
|
+
}).catch(() => void 0);
|
|
2827
|
+
try {
|
|
2828
|
+
const output = await handler(input, context);
|
|
2829
|
+
await emit({
|
|
2830
|
+
type: "collaboration",
|
|
2831
|
+
phase: "completed",
|
|
2832
|
+
skill: skill.name,
|
|
2833
|
+
tool: tool.name,
|
|
2834
|
+
operationId,
|
|
2835
|
+
ok: output.isError !== true,
|
|
2836
|
+
durationMs: Date.now() - startedAt
|
|
2837
|
+
}).catch(() => void 0);
|
|
2838
|
+
return output;
|
|
2839
|
+
} catch (cause) {
|
|
2840
|
+
await emit({
|
|
2841
|
+
type: "collaboration",
|
|
2842
|
+
phase: "completed",
|
|
2843
|
+
skill: skill.name,
|
|
2844
|
+
tool: tool.name,
|
|
2845
|
+
operationId,
|
|
2846
|
+
ok: false,
|
|
2847
|
+
durationMs: Date.now() - startedAt
|
|
2848
|
+
}).catch(() => void 0);
|
|
2849
|
+
throw cause;
|
|
2850
|
+
}
|
|
2851
|
+
}
|
|
2852
|
+
};
|
|
2853
|
+
})
|
|
2854
|
+
}));
|
|
2855
|
+
}
|
|
2856
|
+
|
|
2638
2857
|
// src/code-runtime-engine.ts
|
|
2639
2858
|
var TheseusRuntimeEngine = class {
|
|
2640
2859
|
constructor(options) {
|
|
@@ -2665,6 +2884,8 @@ var TheseusRuntimeEngine = class {
|
|
|
2665
2884
|
const active = this.#active.get(command.sessionId);
|
|
2666
2885
|
if (!active || result.status !== "running") return;
|
|
2667
2886
|
active.acknowledged = true;
|
|
2887
|
+
active.startGate?.release(true);
|
|
2888
|
+
active.startGate = void 0;
|
|
2668
2889
|
if (active.failure) await this.options.control.reportSessionFailure(command.sessionId, active.failure).catch(() => void 0);
|
|
2669
2890
|
}
|
|
2670
2891
|
async close() {
|
|
@@ -2684,13 +2905,14 @@ var TheseusRuntimeEngine = class {
|
|
|
2684
2905
|
control: this.options.control,
|
|
2685
2906
|
...this.options.localSource ? { localSource: this.options.localSource } : {}
|
|
2686
2907
|
});
|
|
2687
|
-
const abort = new AbortController();
|
|
2908
|
+
const abort = new AbortController(), startGate = codeRuntimeAcknowledgementGate(abort.signal);
|
|
2688
2909
|
const conversationRefs = [];
|
|
2689
2910
|
const active = {
|
|
2690
2911
|
workspace,
|
|
2691
2912
|
abort,
|
|
2692
2913
|
conversationRefs,
|
|
2693
2914
|
acknowledged: false,
|
|
2915
|
+
startGate,
|
|
2694
2916
|
role: metadata.role,
|
|
2695
2917
|
title: metadata.title,
|
|
2696
2918
|
maxTokensPerInteraction: metadata.maxTokensPerInteraction,
|
|
@@ -2714,7 +2936,7 @@ var TheseusRuntimeEngine = class {
|
|
|
2714
2936
|
body: `Source snapshot: local checkout ${requestedLocal.snapshotDigest} \xB7 ${requestedLocal.modified ? "modified" : "clean"} \xB7 Git ${requestedLocal.headCommitSha}`
|
|
2715
2937
|
}, conversationRefs);
|
|
2716
2938
|
}
|
|
2717
|
-
active.done = this.#runAttempt(command, metadata, active).catch(async (cause) => {
|
|
2939
|
+
active.done = startGate.ready.then((run) => run ? this.#runAttempt(command, metadata, active) : null).catch(async (cause) => {
|
|
2718
2940
|
const detail = runtimeErrorMessage(cause);
|
|
2719
2941
|
await this.#event(command, { type: "message", actor: "system", body: detail }, conversationRefs).catch(() => void 0);
|
|
2720
2942
|
await this.#diagnostic(command, active, detail);
|
|
@@ -2829,7 +3051,7 @@ var TheseusRuntimeEngine = class {
|
|
|
2829
3051
|
event: (event) => this.#event(command, event, active.conversationRefs)
|
|
2830
3052
|
});
|
|
2831
3053
|
await this.#event(command, { type: "status", status: "running" }, active.conversationRefs);
|
|
2832
|
-
const extraSkills = await sessionSkillsFor(this.options, command);
|
|
3054
|
+
const extraSkills = observeCodeRuntimeSessionSkills(command, await sessionSkillsFor(this.options, command), (event) => this.#event(command, event, active.conversationRefs));
|
|
2833
3055
|
const result = await this.#attempt({
|
|
2834
3056
|
inference,
|
|
2835
3057
|
broker,
|
|
@@ -2958,6 +3180,8 @@ export {
|
|
|
2958
3180
|
codeSkill,
|
|
2959
3181
|
runCodeAgent,
|
|
2960
3182
|
runCodeAgentAttempt,
|
|
3183
|
+
createCodeRuntimeSessionSkillLoader,
|
|
3184
|
+
sessionSkillsFor,
|
|
2961
3185
|
createCodeRuntimeInference,
|
|
2962
3186
|
registeredFiles,
|
|
2963
3187
|
createCodeToolBroker,
|
|
@@ -2969,4 +3193,4 @@ export {
|
|
|
2969
3193
|
runGoal,
|
|
2970
3194
|
TheseusRuntimeEngine
|
|
2971
3195
|
};
|
|
2972
|
-
//# sourceMappingURL=chunk-
|
|
3196
|
+
//# sourceMappingURL=chunk-4EPJJMFG.js.map
|