@odla-ai/harness 0.5.0 → 0.5.2
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/dist/{chunk-UVGZHNLW.js → chunk-5HX5LWTG.js} +48 -51
- package/dist/chunk-5HX5LWTG.js.map +1 -0
- package/dist/code-runtime-cli.cjs +49 -50
- package/dist/code-runtime-cli.cjs.map +1 -1
- package/dist/code-runtime-cli.js +1 -1
- package/dist/node.cjs +49 -50
- package/dist/node.cjs.map +1 -1
- package/dist/node.d.cts +0 -1
- package/dist/node.d.ts +0 -1
- package/dist/node.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-UVGZHNLW.js.map +0 -1
|
@@ -277,6 +277,7 @@ function parseSnapshot(value) {
|
|
|
277
277
|
return { host, bindings, commands };
|
|
278
278
|
}
|
|
279
279
|
async function parseSource(value) {
|
|
280
|
+
const repositoryLimits = { maximumFiles: 1e5, maximumBytes: 80 * 1024 * 1024 };
|
|
280
281
|
const snapshot = record(record(value)?.snapshot);
|
|
281
282
|
if (!snapshot || typeof snapshot.repository !== "string" || typeof snapshot.commitSha !== "string" || typeof snapshot.treeDigest !== "string" || !Array.isArray(snapshot.files)) throw invalid("source");
|
|
282
283
|
const files = snapshot.files.map((value2) => {
|
|
@@ -298,12 +299,12 @@ async function parseSource(value) {
|
|
|
298
299
|
return { path: file.path, content: file.content };
|
|
299
300
|
});
|
|
300
301
|
const source2 = { repository: reference.repository, commitSha: reference.commitSha, files: referenceFiles };
|
|
301
|
-
const referenceDigest = await digestCodeRepositorySnapshot(source2,
|
|
302
|
+
const referenceDigest = await digestCodeRepositorySnapshot(source2, repositoryLimits);
|
|
302
303
|
if (referenceDigest !== reference.treeDigest) throw invalid("reference source digest");
|
|
303
304
|
references.push({ alias: reference.alias, ...source2, treeDigest: referenceDigest });
|
|
304
305
|
}
|
|
305
306
|
const source = { repository: snapshot.repository, commitSha: snapshot.commitSha, files };
|
|
306
|
-
const digest = await digestCodeRepositorySnapshot(source,
|
|
307
|
+
const digest = await digestCodeRepositorySnapshot(source, repositoryLimits);
|
|
307
308
|
if (digest !== snapshot.treeDigest) throw invalid("source digest");
|
|
308
309
|
return { ...source, treeDigest: digest, ...references.length ? { references } : {} };
|
|
309
310
|
}
|
|
@@ -999,8 +1000,11 @@ import { tmpdir } from "os";
|
|
|
999
1000
|
import { dirname, join as join2, resolve as resolve3, sep as sep2 } from "path";
|
|
1000
1001
|
var RESERVED2 = /* @__PURE__ */ new Set([".git", ".odla", ".wrangler", "node_modules", "dist", "coverage"]);
|
|
1001
1002
|
var SECRET2 = /^(?:\.env(?:\..+)?|\.dev\.vars|credentials(?:\..+)?\.json|dev-token(?:\..+)?\.json)$/i;
|
|
1003
|
+
var SOURCE_MAX_FILES = 1e5;
|
|
1004
|
+
var SOURCE_MAX_BYTES = 80 * 1024 * 1024;
|
|
1005
|
+
var SOURCE_SET_MAX_BYTES = 480 * 1024 * 1024;
|
|
1002
1006
|
async function materializeCodeRuntimeSource(snapshot, tempRoot = tmpdir()) {
|
|
1003
|
-
if (!snapshot.files.length || snapshot.files.length >
|
|
1007
|
+
if (!snapshot.files.length || snapshot.files.length > SOURCE_MAX_FILES) throw new TypeError("Code source file count is invalid");
|
|
1004
1008
|
const root = await mkdtemp(join2(tempRoot, "odla-code-source-"));
|
|
1005
1009
|
const sourceDir = join2(root, "source");
|
|
1006
1010
|
await mkdir(sourceDir);
|
|
@@ -1012,7 +1016,7 @@ async function materializeCodeRuntimeSource(snapshot, tempRoot = tmpdir()) {
|
|
|
1012
1016
|
if (seen.has(file.path)) throw new TypeError("Code source repeats a path");
|
|
1013
1017
|
seen.add(file.path);
|
|
1014
1018
|
bytes += Buffer.byteLength(file.path) + Buffer.byteLength(file.content);
|
|
1015
|
-
if (bytes >
|
|
1019
|
+
if (bytes > SOURCE_MAX_BYTES) throw new TypeError("Code source exceeds its byte bound");
|
|
1016
1020
|
const target = resolve3(sourceDir, file.path);
|
|
1017
1021
|
if (!target.startsWith(`${resolve3(sourceDir)}${sep2}`)) throw new TypeError("Code source path escapes its root");
|
|
1018
1022
|
await mkdir(dirname(target), { recursive: true });
|
|
@@ -1020,14 +1024,14 @@ async function materializeCodeRuntimeSource(snapshot, tempRoot = tmpdir()) {
|
|
|
1020
1024
|
}
|
|
1021
1025
|
for (const reference of snapshot.references ?? []) {
|
|
1022
1026
|
validateAlias(reference.alias);
|
|
1023
|
-
if (!reference.files.length || reference.files.length >
|
|
1027
|
+
if (!reference.files.length || reference.files.length > SOURCE_MAX_FILES) throw new TypeError("Code reference file count is invalid");
|
|
1024
1028
|
for (const file of reference.files) {
|
|
1025
1029
|
validatePath(file.path);
|
|
1026
1030
|
const path = `.odla-references/${reference.alias}/${file.path}`;
|
|
1027
1031
|
if (seen.has(path)) throw new TypeError("Code reference repeats a path");
|
|
1028
1032
|
seen.add(path);
|
|
1029
1033
|
bytes += Buffer.byteLength(path) + Buffer.byteLength(file.content);
|
|
1030
|
-
if (bytes >
|
|
1034
|
+
if (bytes > SOURCE_SET_MAX_BYTES) throw new TypeError("Code source set exceeds its byte bound");
|
|
1031
1035
|
const target = resolve3(sourceDir, path);
|
|
1032
1036
|
if (!target.startsWith(`${resolve3(sourceDir)}${sep2}`)) throw new TypeError("Code reference path escapes its root");
|
|
1033
1037
|
await mkdir(dirname(target), { recursive: true });
|
|
@@ -1053,7 +1057,7 @@ async function attachCodeRuntimeReferences(workspace, references) {
|
|
|
1053
1057
|
validatePath(file.path);
|
|
1054
1058
|
const path = `.odla-references/${reference.alias}/${file.path}`;
|
|
1055
1059
|
bytes += Buffer.byteLength(path) + Buffer.byteLength(file.content);
|
|
1056
|
-
if (bytes >
|
|
1060
|
+
if (bytes > SOURCE_SET_MAX_BYTES - SOURCE_MAX_BYTES) throw new TypeError("Code reference set exceeds its byte bound");
|
|
1057
1061
|
for (const root of [workspace.baselineDir, workspace.workspaceDir]) {
|
|
1058
1062
|
const target = resolve3(root, path);
|
|
1059
1063
|
if (!target.startsWith(`${resolve3(root)}${sep2}`)) throw new TypeError("Code reference path escapes its root");
|
|
@@ -1103,7 +1107,10 @@ async function materializeCommandWorkspace(input) {
|
|
|
1103
1107
|
trustedBaseDir: materialized.sourceDir,
|
|
1104
1108
|
trustedBaseCommitSha: source.commitSha,
|
|
1105
1109
|
checkpoint: codeCheckpointPayload(command.payload)
|
|
1106
|
-
})).workspace : await stageWorkspace(materialized.sourceDir
|
|
1110
|
+
})).workspace : await stageWorkspace(materialized.sourceDir, {
|
|
1111
|
+
maxFiles: SOURCE_MAX_FILES,
|
|
1112
|
+
maxBytes: SOURCE_SET_MAX_BYTES
|
|
1113
|
+
});
|
|
1107
1114
|
return { workspace, sourceDigest: source.treeDigest, requestedLocal: null };
|
|
1108
1115
|
} finally {
|
|
1109
1116
|
await materialized.cleanup();
|
|
@@ -1309,8 +1316,10 @@ async function runCodeAgent(options) {
|
|
|
1309
1316
|
}
|
|
1310
1317
|
|
|
1311
1318
|
// src/code-runtime-attempt.ts
|
|
1319
|
+
import { extractText } from "@odla-ai/ai";
|
|
1312
1320
|
async function runCodeAgentAttempt(options) {
|
|
1313
1321
|
try {
|
|
1322
|
+
const surface = options.surface ?? "v2";
|
|
1314
1323
|
const { run } = await runCodeAgent({
|
|
1315
1324
|
inference: options.inference,
|
|
1316
1325
|
broker: options.broker,
|
|
@@ -1320,17 +1329,31 @@ async function runCodeAgentAttempt(options) {
|
|
|
1320
1329
|
// The brokered route resolves the real model from platform policy; this
|
|
1321
1330
|
// id only labels the request the control plane is about to rewrite.
|
|
1322
1331
|
model: "brokered",
|
|
1323
|
-
surface
|
|
1332
|
+
surface,
|
|
1324
1333
|
...options.maxSteps === void 0 ? {} : { maxSteps: options.maxSteps },
|
|
1325
1334
|
...options.budget ? { budget: options.budget } : {},
|
|
1326
1335
|
...options.signal ? { signal: options.signal } : {},
|
|
1327
1336
|
...options.onToolCall ? { onToolCall: options.onToolCall } : {}
|
|
1328
1337
|
});
|
|
1338
|
+
let finalText = run.finalText.trim();
|
|
1339
|
+
if (!finalText && run.stoppedReason !== "refusal") {
|
|
1340
|
+
const closing = await options.inference.chat({
|
|
1341
|
+
model: "brokered",
|
|
1342
|
+
system: `${SYSTEM_PROMPT_FOR[surface]}
|
|
1343
|
+
|
|
1344
|
+
Finish with a concise, non-empty answer to the owner. Do not call tools or promise future work.`,
|
|
1345
|
+
messages: [...run.messages, { role: "user", content: "Give the owner the closing answer now, grounded in the repository evidence and tool results above." }],
|
|
1346
|
+
maxTokens: 16384,
|
|
1347
|
+
...options.signal ? { signal: options.signal } : {}
|
|
1348
|
+
});
|
|
1349
|
+
finalText = extractText(closing.content).trim();
|
|
1350
|
+
}
|
|
1351
|
+
const missingClosing = !finalText && run.stoppedReason !== "refusal";
|
|
1329
1352
|
return {
|
|
1330
|
-
status: run.stoppedReason === "refusal" ? "failed" : "completed",
|
|
1331
|
-
finalText
|
|
1353
|
+
status: run.stoppedReason === "refusal" || missingClosing ? "failed" : "completed",
|
|
1354
|
+
finalText,
|
|
1332
1355
|
stoppedReason: run.stoppedReason,
|
|
1333
|
-
...run.stoppedReason === "refusal" ? { error:
|
|
1356
|
+
...run.stoppedReason === "refusal" ? { error: finalText || "the agent refused the task" } : missingClosing ? { error: "the Code agent did not produce a closing answer" } : {}
|
|
1334
1357
|
};
|
|
1335
1358
|
} catch (cause) {
|
|
1336
1359
|
const error = (cause instanceof Error ? cause.message : String(cause)).slice(0, 2e3);
|
|
@@ -1340,31 +1363,7 @@ async function runCodeAgentAttempt(options) {
|
|
|
1340
1363
|
|
|
1341
1364
|
// src/code-runtime-inference.ts
|
|
1342
1365
|
async function handleCodeRuntimeInference(input) {
|
|
1343
|
-
const { command,
|
|
1344
|
-
if (state.tokens >= metadata.maxTokensPerInteraction) {
|
|
1345
|
-
if (!state.noticeEmitted) {
|
|
1346
|
-
state.noticeEmitted = true;
|
|
1347
|
-
await input.event({
|
|
1348
|
-
type: "message",
|
|
1349
|
-
actor: "system",
|
|
1350
|
-
body: `The agent paused at the ${metadata.maxTokensPerInteraction.toLocaleString("en-US")}-token per-interaction limit. Send a new instruction to continue.`
|
|
1351
|
-
}).catch(() => void 0);
|
|
1352
|
-
}
|
|
1353
|
-
return {
|
|
1354
|
-
protocolVersion: HARNESS_PROTOCOL_VERSION,
|
|
1355
|
-
type: "inference.response",
|
|
1356
|
-
requestId: request.requestId,
|
|
1357
|
-
response: {
|
|
1358
|
-
id: `budget:${command.commandId}`,
|
|
1359
|
-
provider: "openai",
|
|
1360
|
-
model: "interaction-budget",
|
|
1361
|
-
role: "assistant",
|
|
1362
|
-
content: [{ type: "text", text: "Pause now. The owner-set token limit for this interaction has been reached." }],
|
|
1363
|
-
stopReason: "end_turn",
|
|
1364
|
-
usage: { inputTokens: 0, outputTokens: 0 }
|
|
1365
|
-
}
|
|
1366
|
-
};
|
|
1367
|
-
}
|
|
1366
|
+
const { command, request, state } = input;
|
|
1368
1367
|
const startedAt = Date.now();
|
|
1369
1368
|
const response2 = await input.control.infer(command.sessionId, {
|
|
1370
1369
|
requestId: request.requestId,
|
|
@@ -1384,7 +1383,6 @@ async function handleCodeRuntimeInference(input) {
|
|
|
1384
1383
|
durationMs: Date.now() - startedAt,
|
|
1385
1384
|
interactionId: command.commandId,
|
|
1386
1385
|
interactionTokens: state.tokens,
|
|
1387
|
-
interactionMaxTokens: metadata.maxTokensPerInteraction,
|
|
1388
1386
|
...costUsd === void 0 ? {} : { costUsd },
|
|
1389
1387
|
...state.costKnown ? { interactionCostUsd: state.costUsd } : {}
|
|
1390
1388
|
}).catch(() => void 0);
|
|
@@ -2530,7 +2528,7 @@ var CodePiRuntimeEngine = class {
|
|
|
2530
2528
|
recipeAuthorization: this.options.recipeAuthorization
|
|
2531
2529
|
}, lease, metadata.role));
|
|
2532
2530
|
const startedAt = Date.now();
|
|
2533
|
-
const interaction = { tokens: 0,
|
|
2531
|
+
const interaction = { tokens: 0, costUsd: 0, costKnown: true };
|
|
2534
2532
|
const inference = createCodeRuntimeInference({
|
|
2535
2533
|
command,
|
|
2536
2534
|
metadata,
|
|
@@ -2545,31 +2543,30 @@ var CodePiRuntimeEngine = class {
|
|
|
2545
2543
|
lease,
|
|
2546
2544
|
workspaceDir: active.workspace.workspaceDir,
|
|
2547
2545
|
prompt: metadata.prompt,
|
|
2548
|
-
signal: active.abort.signal
|
|
2549
|
-
// The owner's per-interaction allowance, enforced by runAgent against
|
|
2550
|
-
// INCREMENTAL usage. The control plane still reserves against the same
|
|
2551
|
-
// ceiling, but this is what stops the loop cleanly at the boundary rather
|
|
2552
|
-
// than letting it discover the limit through a synthesized pause reply.
|
|
2553
|
-
budget: { maxTotalTokens: metadata.maxTokensPerInteraction }
|
|
2546
|
+
signal: active.abort.signal
|
|
2554
2547
|
});
|
|
2555
|
-
const
|
|
2548
|
+
const closing = result.finalText.trim();
|
|
2549
|
+
const completed = result.status === "completed" && Boolean(closing);
|
|
2550
|
+
const detail = result.error?.trim() || (closing ? "the Code agent failed" : "the Code agent did not produce a closing answer");
|
|
2551
|
+
const body = closing || detail;
|
|
2556
2552
|
await this.#event(command, {
|
|
2557
2553
|
type: "message",
|
|
2558
|
-
actor:
|
|
2554
|
+
actor: completed ? "agent" : "system",
|
|
2559
2555
|
body
|
|
2560
2556
|
}, active.conversationRefs).catch(() => void 0);
|
|
2561
2557
|
await this.#event(command, {
|
|
2562
2558
|
type: "status",
|
|
2563
|
-
status:
|
|
2559
|
+
status: completed ? "idle" : "failed",
|
|
2564
2560
|
durationMs: Date.now() - startedAt
|
|
2565
2561
|
}, active.conversationRefs).catch(() => void 0);
|
|
2566
|
-
if (
|
|
2567
|
-
const detail = (result.error ?? "").trim() || "the Code agent failed";
|
|
2562
|
+
if (!completed) {
|
|
2568
2563
|
await this.#diagnostic(command, active, detail);
|
|
2569
2564
|
await this.#failure(command, active, detail);
|
|
2570
2565
|
}
|
|
2571
2566
|
return {
|
|
2572
2567
|
...result,
|
|
2568
|
+
status: completed ? "completed" : "failed",
|
|
2569
|
+
...!completed ? { error: detail } : {},
|
|
2573
2570
|
tokens: interaction.tokens,
|
|
2574
2571
|
...interaction.costKnown ? { costUsd: interaction.costUsd } : {}
|
|
2575
2572
|
};
|
|
@@ -2666,4 +2663,4 @@ export {
|
|
|
2666
2663
|
runGoal,
|
|
2667
2664
|
CodePiRuntimeEngine
|
|
2668
2665
|
};
|
|
2669
|
-
//# sourceMappingURL=chunk-
|
|
2666
|
+
//# sourceMappingURL=chunk-5HX5LWTG.js.map
|