@qwen-code/arena-agent 0.0.10-dev.6 → 0.0.10-dev.8
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/.env.example +20 -9
- package/CHANGELOG.md +188 -0
- package/README.md +21 -19
- package/dist/agent.d.ts +8 -0
- package/dist/agent.js +32 -12
- package/dist/agent.js.map +1 -1
- package/dist/cli.js +87 -20
- package/dist/cli.js.map +1 -1
- package/dist/code-cli.js +0 -0
- package/dist/code-tools.d.ts +5 -0
- package/dist/code-tools.js +254 -64
- package/dist/code-tools.js.map +1 -1
- package/dist/compaction.d.ts +5 -0
- package/dist/compaction.js +57 -6
- package/dist/compaction.js.map +1 -1
- package/dist/config.d.ts +0 -2
- package/dist/config.js +1 -3
- package/dist/config.js.map +1 -1
- package/dist/file-edit.d.ts +2 -0
- package/dist/file-edit.js +9 -4
- package/dist/file-edit.js.map +1 -1
- package/dist/history.js +17 -0
- package/dist/history.js.map +1 -1
- package/dist/midturn-checkpoint-hook.d.ts +16 -0
- package/dist/midturn-checkpoint-hook.js +30 -0
- package/dist/midturn-checkpoint-hook.js.map +1 -0
- package/dist/provider.d.ts +0 -1
- package/dist/provider.js +13 -42
- package/dist/provider.js.map +1 -1
- package/dist/replay-responses.d.ts +17 -0
- package/dist/replay-responses.js +100 -0
- package/dist/replay-responses.js.map +1 -0
- package/dist/routify-web-fetch.js +18 -4
- package/dist/routify-web-fetch.js.map +1 -1
- package/dist/snapshot-client.d.ts +10 -0
- package/dist/snapshot-client.js +39 -0
- package/dist/snapshot-client.js.map +1 -0
- package/dist/tools.d.ts +2 -0
- package/dist/tools.js +134 -23
- package/dist/tools.js.map +1 -1
- package/dist/tui.js +1 -1
- package/dist/tui.js.map +1 -1
- package/dist/web-fetch-output.d.ts +9 -0
- package/dist/web-fetch-output.js +38 -0
- package/dist/web-fetch-output.js.map +1 -0
- package/docs/BINARY_DISTRIBUTION.md +25 -16
- package/docs/MODES_AND_RELEASES.md +28 -5
- package/package.json +5 -1
- package/scripts/README.md +62 -0
- package/scripts/check-changelog.mjs +66 -0
- package/dist/web/app.d.ts +0 -1
|
@@ -0,0 +1,100 @@
|
|
|
1
|
+
import { readFileSync } from "node:fs";
|
|
2
|
+
// Nondeterministic network/media tools across both arenas. generate_image and
|
|
3
|
+
// generate_speech write files, but their side effects are reproduced through
|
|
4
|
+
// recorded artifacts, so they replay safely.
|
|
5
|
+
const REPLAYABLE_TOOLS = new Set([
|
|
6
|
+
"fetch_media",
|
|
7
|
+
"fetch_page",
|
|
8
|
+
"generate_image",
|
|
9
|
+
"generate_speech",
|
|
10
|
+
"image_search",
|
|
11
|
+
"web_fetch",
|
|
12
|
+
"web_search",
|
|
13
|
+
]);
|
|
14
|
+
let cached;
|
|
15
|
+
let cachedSource;
|
|
16
|
+
let stats = { served: 0, missed: [] };
|
|
17
|
+
function stableStringify(value) {
|
|
18
|
+
if (Array.isArray(value)) {
|
|
19
|
+
return `[${value.map(stableStringify).join(",")}]`;
|
|
20
|
+
}
|
|
21
|
+
if (value !== null && typeof value === "object") {
|
|
22
|
+
const entries = Object.entries(value)
|
|
23
|
+
.sort(([a], [b]) => (a < b ? -1 : a > b ? 1 : 0))
|
|
24
|
+
.map(([key, item]) => `${JSON.stringify(key)}:${stableStringify(item)}`);
|
|
25
|
+
return `{${entries.join(",")}}`;
|
|
26
|
+
}
|
|
27
|
+
return JSON.stringify(value);
|
|
28
|
+
}
|
|
29
|
+
function loadReplayResponses() {
|
|
30
|
+
const file = process.env.CODE_HARNESS_REPLAY_RESPONSES;
|
|
31
|
+
if (cached !== undefined && cachedSource === file)
|
|
32
|
+
return cached;
|
|
33
|
+
cachedSource = file;
|
|
34
|
+
cached = null;
|
|
35
|
+
stats = { served: 0, missed: [] };
|
|
36
|
+
if (file) {
|
|
37
|
+
try {
|
|
38
|
+
const parsed = JSON.parse(readFileSync(file, "utf8"));
|
|
39
|
+
const map = new Map();
|
|
40
|
+
const nonReplayable = new Set();
|
|
41
|
+
for (const entry of parsed.entries ?? []) {
|
|
42
|
+
if (!REPLAYABLE_TOOLS.has(entry.tool)) {
|
|
43
|
+
nonReplayable.add(entry.tool);
|
|
44
|
+
continue;
|
|
45
|
+
}
|
|
46
|
+
const key = `${entry.tool}|${stableStringify(entry.arguments)}`;
|
|
47
|
+
const queue = map.get(key);
|
|
48
|
+
if (queue)
|
|
49
|
+
queue.push(entry);
|
|
50
|
+
else
|
|
51
|
+
map.set(key, [entry]);
|
|
52
|
+
}
|
|
53
|
+
if (nonReplayable.size) {
|
|
54
|
+
console.error(`[replay-responses] ignoring recorded entries for non-replayable tool(s): ${[...nonReplayable].sort().join(", ")}`);
|
|
55
|
+
}
|
|
56
|
+
cached = map;
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
cached = null;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
return cached;
|
|
63
|
+
}
|
|
64
|
+
export function replayResponseFor(tool, args) {
|
|
65
|
+
const map = loadReplayResponses();
|
|
66
|
+
if (!map)
|
|
67
|
+
return undefined;
|
|
68
|
+
if (!REPLAYABLE_TOOLS.has(tool))
|
|
69
|
+
return undefined;
|
|
70
|
+
const argumentsKey = stableStringify(args);
|
|
71
|
+
// Repeated calls with identical arguments consume recorded entries in
|
|
72
|
+
// source order.
|
|
73
|
+
const queue = map.get(`${tool}|${argumentsKey}`);
|
|
74
|
+
if (!queue || !queue.length) {
|
|
75
|
+
stats.missed.push({ tool, arguments: argumentsKey });
|
|
76
|
+
console.error(`[replay-responses] no recorded response for ${tool} ${argumentsKey}; falling through to live execution`);
|
|
77
|
+
return undefined;
|
|
78
|
+
}
|
|
79
|
+
const entry = queue.shift();
|
|
80
|
+
stats.served += 1;
|
|
81
|
+
return { found: true, output: entry.output, artifacts: entry.artifacts };
|
|
82
|
+
}
|
|
83
|
+
// Hit/miss counters for the current recording. Reset whenever a different
|
|
84
|
+
// recording file is loaded.
|
|
85
|
+
export function replayResponseStats() {
|
|
86
|
+
return { served: stats.served, missed: [...stats.missed] };
|
|
87
|
+
}
|
|
88
|
+
// With replay mode on from process start, emit a one-line hit-rate summary at
|
|
89
|
+
// exit so replay drivers can flag recordings that partially fell through to
|
|
90
|
+
// live execution.
|
|
91
|
+
if (process.env.CODE_HARNESS_REPLAY_RESPONSES) {
|
|
92
|
+
process.once("exit", () => {
|
|
93
|
+
const total = stats.served + stats.missed.length;
|
|
94
|
+
if (total === 0)
|
|
95
|
+
return;
|
|
96
|
+
const rate = Math.round((stats.served / total) * 100);
|
|
97
|
+
console.error(`[replay-responses] replay summary: served=${stats.served} missed=${stats.missed.length} hit-rate=${rate}%`);
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
//# sourceMappingURL=replay-responses.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"replay-responses.js","sourceRoot":"","sources":["../src/replay-responses.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { parseHTML } from "linkedom";
|
|
1
2
|
import { splitMarkdown } from "./fetch-page.js";
|
|
2
3
|
function record(value) {
|
|
3
4
|
return value !== null && typeof value === "object" && !Array.isArray(value)
|
|
@@ -46,9 +47,18 @@ const maxFetchPageCacheEntries = 16;
|
|
|
46
47
|
export function routifyWebFetchEnabled(value = process.env.CODE_HARNESS_ROUTIFY_WEB_FETCH_ENABLED) {
|
|
47
48
|
return ["1", "true", "yes", "on"].includes(value?.trim().toLowerCase() || "");
|
|
48
49
|
}
|
|
50
|
+
function htmlToText(html) {
|
|
51
|
+
// Firecrawl accepts html, not text. Handle both fragments and full documents;
|
|
52
|
+
// innerText preserves block/line breaks and the parser decodes HTML entities.
|
|
53
|
+
const { document } = parseHTML(`<html><body>${html}</body></html>`);
|
|
54
|
+
for (const element of document.querySelectorAll("head, title, script, style, noscript, template")) {
|
|
55
|
+
element.remove();
|
|
56
|
+
}
|
|
57
|
+
return document.body.innerText.trim();
|
|
58
|
+
}
|
|
49
59
|
async function firecrawl(url, format, options) {
|
|
50
60
|
const fetchImpl = options.fetchImpl || globalThis.fetch;
|
|
51
|
-
const requestedFormat = format;
|
|
61
|
+
const requestedFormat = format === "text" ? "html" : format;
|
|
52
62
|
const response = await fetchImpl(routifyReadPageUrl, {
|
|
53
63
|
method: "POST",
|
|
54
64
|
headers: {
|
|
@@ -79,7 +89,7 @@ async function firecrawl(url, format, options) {
|
|
|
79
89
|
}
|
|
80
90
|
return {
|
|
81
91
|
title: stringValue(metadata.title) || "No Title Found",
|
|
82
|
-
content,
|
|
92
|
+
content: format === "text" ? htmlToText(content) : content,
|
|
83
93
|
};
|
|
84
94
|
}
|
|
85
95
|
async function jinaReader(url, format, options) {
|
|
@@ -107,12 +117,16 @@ async function jinaReader(url, format, options) {
|
|
|
107
117
|
throw new Error(`Jina Reader returned code ${String(payload.code || "unknown")}`);
|
|
108
118
|
}
|
|
109
119
|
const data = record(payload.data);
|
|
110
|
-
|
|
120
|
+
// Jina uses text/html fields for those formats; some gateways normalize all
|
|
121
|
+
// formats into content. Markdown continues to use content.
|
|
122
|
+
const field = format === "markdown" ? "content" : format;
|
|
123
|
+
const content = typeof data[field] === "string" ? data[field] : data.content;
|
|
124
|
+
if (typeof content !== "string") {
|
|
111
125
|
throw new Error("Jina Reader response is missing content");
|
|
112
126
|
}
|
|
113
127
|
return {
|
|
114
128
|
title: stringValue(data.title) || "No Title Found",
|
|
115
|
-
content
|
|
129
|
+
content,
|
|
116
130
|
};
|
|
117
131
|
}
|
|
118
132
|
export async function executeRoutifyWebFetch(url, format, options = {}) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routify-web-fetch.js","sourceRoot":"","sources":["../src/routify-web-fetch.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAEhD,SAAS,MAAM,CAAC,KAAc;IAC5B,OAAO,KAAK,KAAK,IAAI,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QACzE,CAAC,CAAE,KAAiC;QACpC,CAAC,CAAC,EAAE,CAAC;AACT,CAAC;AAED,SAAS,WAAW,CAAC,KAAc;IACjC,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC;AAChD,CAAC;AAED,SAAS,YAAY,CAAC,KAAc;IAClC,OAAO,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC;AAChE,CAAC;AAED,SAAS,MAAM;IACb,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,IAAI,EAAE,CAAC;IAClD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACjE,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,mBAAmB,CAAC,KAAa;IACxC,OAAO,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,KAAK,EAAE,CAAC;AAC/D,CAAC;AAED,SAAS,cAAc,CAAC,OAAe;IACrC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;QAC5C,OAAO,CACL,WAAW,CAAC,OAAO,CAAC,OAAO,CAAC;YAC5B,WAAW,CAAC,OAAO,CAAC,aAAa,CAAC;YAClC,WAAW,CAAC,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,OAAO,CAAC;YAC1C,OAAO,CACR,CAAC;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,OAAO,CAAC;IACjB,CAAC;AACH,CAAC;AAED,SAAS,SAAS,CAAC,OAAe,EAAE,QAAgB;IAClD,IAAI,CAAC;QACH,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC;IACrC,CAAC;IAAC,MAAM,CAAC;QACP,MAAM,IAAI,KAAK,CAAC,GAAG,QAAQ,0BAA0B,CAAC,CAAC;IACzD,CAAC;AACH,CAAC;AAED,MAAM,kBAAkB,GACtB,2DAA2D,CAAC;AAC9D,MAAM,kBAAkB,GAAG,KAAK,CAAC;AACjC,MAAM,wBAAwB,GAAG,EAAE,CAAC;AAcpC,MAAM,UAAU,sBAAsB,CACpC,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,sCAAsC;IAE1D,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,QAAQ,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,IAAI,EAAE,CAAC,CAAC;AAChF,CAAC;AAED,KAAK,UAAU,SAAS,CACtB,GAAW,EACX,MAAsB,EACtB,OAA+B;IAE/B,MAAM,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,UAAU,CAAC,KAAK,CAAC;IACxD,MAAM,eAAe,GAAG,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"routify-web-fetch.js","sourceRoot":"","sources":["../src/routify-web-fetch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { MidturnCheckpointHookEvent } from "./midturn-checkpoint-hook.js";
|
|
2
|
+
export declare const HARBOR_REMOTE_COMMAND_BASE_URL_ENV: "HARBOR_REMOTE_COMMAND_BASE_URL";
|
|
3
|
+
export declare const HARBOR_REMOTE_COMMAND_API_KEY_ENV: "HARBOR_REMOTE_COMMAND_API_KEY";
|
|
4
|
+
export interface HarborSnapshotRequestOptions {
|
|
5
|
+
event: MidturnCheckpointHookEvent;
|
|
6
|
+
env?: NodeJS.ProcessEnv;
|
|
7
|
+
fetch?: typeof globalThis.fetch;
|
|
8
|
+
}
|
|
9
|
+
/** Ask Harbor to capture the current container and wait for the response. */
|
|
10
|
+
export declare function requestHarborSnapshot(options: HarborSnapshotRequestOptions): Promise<void>;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
export const HARBOR_REMOTE_COMMAND_BASE_URL_ENV = "HARBOR_REMOTE_COMMAND_BASE_URL";
|
|
2
|
+
export const HARBOR_REMOTE_COMMAND_API_KEY_ENV = "HARBOR_REMOTE_COMMAND_API_KEY";
|
|
3
|
+
/** Ask Harbor to capture the current container and wait for the response. */
|
|
4
|
+
export async function requestHarborSnapshot(options) {
|
|
5
|
+
const env = options.env ?? process.env;
|
|
6
|
+
const baseUrl = env[HARBOR_REMOTE_COMMAND_BASE_URL_ENV]?.trim();
|
|
7
|
+
const apiKey = env[HARBOR_REMOTE_COMMAND_API_KEY_ENV]?.trim();
|
|
8
|
+
if (!baseUrl) {
|
|
9
|
+
throw new Error(`${HARBOR_REMOTE_COMMAND_BASE_URL_ENV} is required to create a checkpoint`);
|
|
10
|
+
}
|
|
11
|
+
if (!apiKey) {
|
|
12
|
+
throw new Error(`${HARBOR_REMOTE_COMMAND_API_KEY_ENV} is required to create a checkpoint`);
|
|
13
|
+
}
|
|
14
|
+
const endpoint = `${baseUrl.replace(/\/+$/, "")}/v1/remote/command`;
|
|
15
|
+
let response;
|
|
16
|
+
try {
|
|
17
|
+
response = await (options.fetch ?? globalThis.fetch)(endpoint, {
|
|
18
|
+
method: "POST",
|
|
19
|
+
headers: {
|
|
20
|
+
authorization: `Bearer ${apiKey}`,
|
|
21
|
+
"content-type": "application/json",
|
|
22
|
+
},
|
|
23
|
+
body: JSON.stringify({
|
|
24
|
+
command: "make_snapshot",
|
|
25
|
+
arguments: [options.event],
|
|
26
|
+
}),
|
|
27
|
+
});
|
|
28
|
+
}
|
|
29
|
+
catch (error) {
|
|
30
|
+
throw new Error("Harbor snapshot request failed", { cause: error });
|
|
31
|
+
}
|
|
32
|
+
// Consume the body before returning so streamed responses are fully complete.
|
|
33
|
+
const responseBody = await response.text();
|
|
34
|
+
if (!response.ok) {
|
|
35
|
+
const detail = responseBody.trim();
|
|
36
|
+
throw new Error(`Harbor snapshot request failed (${response.status}${response.statusText ? ` ${response.statusText}` : ""})${detail ? `: ${detail}` : ""}`);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=snapshot-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"snapshot-client.js","sourceRoot":"","sources":["../src/snapshot-client.ts"],"names":[],"mappings":"AAEA,MAAM,CAAC,MAAM,kCAAkC,GAC7C,gCAAyC,CAAC;AAC5C,MAAM,CAAC,MAAM,iCAAiC,GAC5C,+BAAwC,CAAC;AAQ3C,6EAA6E;AAC7E,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,OAAqC;IAErC,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,IAAI,OAAO,CAAC,GAAG,CAAC;IACvC,MAAM,OAAO,GAAG,GAAG,CAAC,kCAAkC,CAAC,EAAE,IAAI,EAAE,CAAC;IAChE,MAAM,MAAM,GAAG,GAAG,CAAC,iCAAiC,CAAC,EAAE,IAAI,EAAE,CAAC;IAC9D,IAAI,CAAC,OAAO,EAAE,CAAC;QACb,MAAM,IAAI,KAAK,CACb,GAAG,kCAAkC,qCAAqC,CAC3E,CAAC;IACJ,CAAC;IACD,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,MAAM,IAAI,KAAK,CACb,GAAG,iCAAiC,qCAAqC,CAC1E,CAAC;IACJ,CAAC;IAED,MAAM,QAAQ,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,oBAAoB,CAAC;IACpE,IAAI,QAAkB,CAAC;IACvB,IAAI,CAAC;QACH,QAAQ,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,IAAI,UAAU,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE;YAC7D,MAAM,EAAE,MAAM;YACd,OAAO,EAAE;gBACP,aAAa,EAAE,UAAU,MAAM,EAAE;gBACjC,cAAc,EAAE,kBAAkB;aACnC;YACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC;gBACnB,OAAO,EAAE,eAAe;gBACxB,SAAS,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;aAC3B,CAAC;SACH,CAAC,CAAC;IACL,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,IAAI,KAAK,CAAC,gCAAgC,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC,CAAC;IACtE,CAAC;IAED,8EAA8E;IAC9E,MAAM,YAAY,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAC;IAC3C,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;QACjB,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CACb,mCAAmC,QAAQ,CAAC,MAAM,GAChD,QAAQ,CAAC,UAAU,CAAC,CAAC,CAAC,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC,CAAC,EACpD,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,EAAE,CAClC,CAAC;IACJ,CAAC;AACH,CAAC"}
|
package/dist/tools.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { type ArenaConfig } from "./config.js";
|
|
2
2
|
import { type ModelConnectionOptions } from "./provider.js";
|
|
3
|
+
import type { CheckpointHookToolCall } from "./midturn-checkpoint-hook.js";
|
|
3
4
|
import type { AskUserHandler, AskUserContext, MultimodalUserMessage, ModelClient, ToolCall, ToolDefinition, ToolMessage, WorkspaceContext } from "./types.js";
|
|
4
5
|
interface ToolExecutorOptions {
|
|
5
6
|
askUserHandler?: AskUserHandler;
|
|
@@ -20,6 +21,7 @@ export declare class ToolExecutor {
|
|
|
20
21
|
get workspace(): string;
|
|
21
22
|
get askUserEnabled(): boolean;
|
|
22
23
|
availableTools(): ToolDefinition[];
|
|
24
|
+
inspect(call: ToolCall): CheckpointHookToolCall;
|
|
23
25
|
execute(call: ToolCall, context?: AskUserContext): Promise<ToolMessage>;
|
|
24
26
|
takeVisualMessage(toolCallIds: string[]): MultimodalUserMessage | undefined;
|
|
25
27
|
}
|
package/dist/tools.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { spawn } from "node:child_process";
|
|
2
|
-
import { existsSync, mkdirSync, realpathSync } from "node:fs";
|
|
2
|
+
import { copyFileSync, existsSync, mkdirSync, realpathSync } from "node:fs";
|
|
3
3
|
import { open, readFile, realpath, stat, writeFile } from "node:fs/promises";
|
|
4
4
|
import path from "node:path";
|
|
5
5
|
import { Ajv } from "ajv";
|
|
@@ -20,6 +20,7 @@ import { isCodeArenaMode } from "./mode.js";
|
|
|
20
20
|
import { generateImageWithModelRouter, generateSpeechWithModelRouter, } from "./model-router-media.js";
|
|
21
21
|
import { processManagerForWorkspace, } from "./process-manager.js";
|
|
22
22
|
import { HttpModelClient } from "./provider.js";
|
|
23
|
+
import { replayResponseFor, } from "./replay-responses.js";
|
|
23
24
|
import { RoutifyFetchPageReader, routifyWebFetchEnabled, } from "./routify-web-fetch.js";
|
|
24
25
|
import { toolDefinitions } from "./spec.js";
|
|
25
26
|
import { createSandboxFile, privilegedFileCreationEnabled } from "./sandbox-file-write.js";
|
|
@@ -672,6 +673,87 @@ class ArenaToolExecutor {
|
|
|
672
673
|
const disallowed = new Set(this.config.disallowedTools || []);
|
|
673
674
|
return definitions.filter((definition) => !disallowed.has(definition.function.name));
|
|
674
675
|
}
|
|
676
|
+
parseArguments(call) {
|
|
677
|
+
const rawArguments = typeof call.function?.arguments === "string"
|
|
678
|
+
? call.function.arguments
|
|
679
|
+
: "{}";
|
|
680
|
+
let value;
|
|
681
|
+
try {
|
|
682
|
+
value = JSON.parse(rawArguments);
|
|
683
|
+
}
|
|
684
|
+
catch (error) {
|
|
685
|
+
return { rawArguments, invalidJsonText: rawArguments, error };
|
|
686
|
+
}
|
|
687
|
+
const malformedArguments = value !== null && typeof value === "object" && !Array.isArray(value)
|
|
688
|
+
? value.__malformedToolArguments
|
|
689
|
+
: undefined;
|
|
690
|
+
if (typeof malformedArguments === "string") {
|
|
691
|
+
try {
|
|
692
|
+
JSON.parse(malformedArguments);
|
|
693
|
+
}
|
|
694
|
+
catch (error) {
|
|
695
|
+
return { rawArguments, invalidJsonText: malformedArguments, error };
|
|
696
|
+
}
|
|
697
|
+
}
|
|
698
|
+
return { rawArguments, value };
|
|
699
|
+
}
|
|
700
|
+
validateArguments(name, value, validate) {
|
|
701
|
+
const validatedArguments = structuredClone(value);
|
|
702
|
+
if (!validate(validatedArguments)) {
|
|
703
|
+
return {
|
|
704
|
+
validationMessage: arenaValidationError(name, value, validate.errors),
|
|
705
|
+
};
|
|
706
|
+
}
|
|
707
|
+
return { value: validatedArguments };
|
|
708
|
+
}
|
|
709
|
+
inspect(call) {
|
|
710
|
+
const id = String(call.id || "");
|
|
711
|
+
const name = String(call.function?.name || "");
|
|
712
|
+
const originalRawArguments = typeof call.function?.arguments === "string"
|
|
713
|
+
? call.function.arguments
|
|
714
|
+
: "{}";
|
|
715
|
+
const parsed = this.parseArguments(call);
|
|
716
|
+
const validate = this.validators.get(name);
|
|
717
|
+
if (this.config.disallowedTools?.includes(name) || !validate) {
|
|
718
|
+
return {
|
|
719
|
+
id,
|
|
720
|
+
name,
|
|
721
|
+
rawArguments: originalRawArguments,
|
|
722
|
+
...(parsed.error === undefined ? { arguments: parsed.value } : {}),
|
|
723
|
+
validation: "unknown_tool",
|
|
724
|
+
validationMessage: this.config.disallowedTools?.includes(name)
|
|
725
|
+
? `tool is disallowed: ${name}`
|
|
726
|
+
: unavailableToolError(name, toolDefinitions(this.workspaceContext).map((definition) => definition.function.name)),
|
|
727
|
+
};
|
|
728
|
+
}
|
|
729
|
+
if (parsed.error !== undefined) {
|
|
730
|
+
return {
|
|
731
|
+
id,
|
|
732
|
+
name,
|
|
733
|
+
rawArguments: parsed.rawArguments,
|
|
734
|
+
validation: "invalid_json",
|
|
735
|
+
validationMessage: arenaJsonParsingError(name, parsed.invalidJsonText, parsed.error),
|
|
736
|
+
};
|
|
737
|
+
}
|
|
738
|
+
const validated = this.validateArguments(name, parsed.value, validate);
|
|
739
|
+
if (validated.validationMessage !== undefined) {
|
|
740
|
+
return {
|
|
741
|
+
id,
|
|
742
|
+
name,
|
|
743
|
+
rawArguments: parsed.rawArguments,
|
|
744
|
+
arguments: parsed.value,
|
|
745
|
+
validation: "invalid_arguments",
|
|
746
|
+
validationMessage: validated.validationMessage,
|
|
747
|
+
};
|
|
748
|
+
}
|
|
749
|
+
return {
|
|
750
|
+
id,
|
|
751
|
+
name,
|
|
752
|
+
rawArguments: parsed.rawArguments,
|
|
753
|
+
arguments: parsed.value,
|
|
754
|
+
validation: "valid",
|
|
755
|
+
};
|
|
756
|
+
}
|
|
675
757
|
async execute(call, context) {
|
|
676
758
|
const callId = String(call.id || "");
|
|
677
759
|
const name = String(call.function?.name || "");
|
|
@@ -697,45 +779,54 @@ class ArenaToolExecutor {
|
|
|
697
779
|
content: unavailableToolError(name, toolDefinitions(this.workspaceContext).map((definition) => definition.function.name)),
|
|
698
780
|
};
|
|
699
781
|
}
|
|
700
|
-
const
|
|
701
|
-
|
|
702
|
-
: "{}";
|
|
703
|
-
let argumentsValue;
|
|
704
|
-
try {
|
|
705
|
-
argumentsValue = JSON.parse(argumentsText);
|
|
706
|
-
}
|
|
707
|
-
catch (error) {
|
|
782
|
+
const parsed = this.parseArguments(call);
|
|
783
|
+
if (parsed.error !== undefined) {
|
|
708
784
|
return {
|
|
709
785
|
role: "tool",
|
|
710
786
|
tool_call_id: callId,
|
|
711
|
-
content: arenaJsonParsingError(name,
|
|
787
|
+
content: arenaJsonParsingError(name, parsed.invalidJsonText, parsed.error),
|
|
712
788
|
};
|
|
713
789
|
}
|
|
714
|
-
const
|
|
715
|
-
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
|
|
719
|
-
|
|
720
|
-
|
|
721
|
-
|
|
790
|
+
const argumentsValue = parsed.value;
|
|
791
|
+
// Replay mode (CODE_HARNESS_REPLAY_RESPONSES set): serve recorded
|
|
792
|
+
// outputs BEFORE schema validation. Recorded arguments can violate the
|
|
793
|
+
// current schema — PII-redacted placeholder URLs fail format=url, or
|
|
794
|
+
// the schema evolved since recording (voice_identity vs voice_id) —
|
|
795
|
+
// and the recording must still replay verbatim. Canned lookup consumes
|
|
796
|
+
// the entry, so this must be the single serving point: dispatch() only
|
|
797
|
+
// sees calls without a recorded response. Unlisted calls fall through
|
|
798
|
+
// to validation and real execution.
|
|
799
|
+
const replayed = replayResponseFor(name, argumentsValue);
|
|
800
|
+
if (replayed) {
|
|
801
|
+
for (const artifact of replayed.artifacts ?? []) {
|
|
802
|
+
this.materializeReplayArtifact(artifact);
|
|
722
803
|
}
|
|
723
|
-
|
|
804
|
+
const replayContent = typeof replayed.output === "string"
|
|
805
|
+
? replayed.output
|
|
806
|
+
: json(replayed.output);
|
|
807
|
+
if (replayContent.length > toolResultCharacterLimit) {
|
|
724
808
|
return {
|
|
725
809
|
role: "tool",
|
|
726
810
|
tool_call_id: callId,
|
|
727
|
-
content:
|
|
811
|
+
content: json({
|
|
812
|
+
status: "error",
|
|
813
|
+
message: `Tool result from ${name} (${replayContent.length} characters) exceeds the ` +
|
|
814
|
+
`maximum allowed size (${toolResultCharacterLimit} characters). ` +
|
|
815
|
+
"Retry with narrower arguments or inspect the data in smaller portions.",
|
|
816
|
+
}),
|
|
728
817
|
};
|
|
729
818
|
}
|
|
819
|
+
return { role: "tool", tool_call_id: callId, content: replayContent };
|
|
730
820
|
}
|
|
731
|
-
const
|
|
732
|
-
if (
|
|
821
|
+
const validated = this.validateArguments(name, argumentsValue, validate);
|
|
822
|
+
if (validated.validationMessage !== undefined) {
|
|
733
823
|
return {
|
|
734
824
|
role: "tool",
|
|
735
825
|
tool_call_id: callId,
|
|
736
|
-
content:
|
|
826
|
+
content: validated.validationMessage,
|
|
737
827
|
};
|
|
738
828
|
}
|
|
829
|
+
const validatedArguments = validated.value;
|
|
739
830
|
const startedAt = Date.now();
|
|
740
831
|
let result;
|
|
741
832
|
try {
|
|
@@ -879,6 +970,8 @@ class ArenaToolExecutor {
|
|
|
879
970
|
};
|
|
880
971
|
}
|
|
881
972
|
async dispatch(name, values, toolCallId, context) {
|
|
973
|
+
// Canned replay responses are served in execute() before schema
|
|
974
|
+
// validation (the lookup consumes entries — single serving point).
|
|
882
975
|
switch (name) {
|
|
883
976
|
case "bash":
|
|
884
977
|
return this.bash(String(values.command), String(values.cwd ||
|
|
@@ -931,6 +1024,21 @@ class ArenaToolExecutor {
|
|
|
931
1024
|
throw new Error(`unknown tool: ${name}`);
|
|
932
1025
|
}
|
|
933
1026
|
}
|
|
1027
|
+
// Copy a pre-staged replay artifact blob into the workspace. Recorded
|
|
1028
|
+
// artifact paths must stay workspace-relative: an absolute path or one
|
|
1029
|
+
// escaping the workspace is a corrupt recording, so reject it loudly.
|
|
1030
|
+
materializeReplayArtifact(artifact) {
|
|
1031
|
+
const normalized = path.posix.normalize(artifact.path);
|
|
1032
|
+
if (path.posix.isAbsolute(artifact.path) ||
|
|
1033
|
+
path.posix.isAbsolute(normalized) ||
|
|
1034
|
+
normalized === ".." ||
|
|
1035
|
+
normalized.startsWith("../")) {
|
|
1036
|
+
throw new Error(`replay artifact path escapes the workspace: ${JSON.stringify(artifact.path)}`);
|
|
1037
|
+
}
|
|
1038
|
+
const target = path.resolve(this.workspace, normalized);
|
|
1039
|
+
mkdirSync(path.dirname(target), { recursive: true });
|
|
1040
|
+
copyFileSync(artifact.file, target);
|
|
1041
|
+
}
|
|
934
1042
|
async confinedPath(raw) {
|
|
935
1043
|
if (!raw)
|
|
936
1044
|
throw new Error("path must not be empty");
|
|
@@ -1638,6 +1746,9 @@ export class ToolExecutor {
|
|
|
1638
1746
|
availableTools() {
|
|
1639
1747
|
return this.implementation.availableTools();
|
|
1640
1748
|
}
|
|
1749
|
+
inspect(call) {
|
|
1750
|
+
return this.implementation.inspect(call);
|
|
1751
|
+
}
|
|
1641
1752
|
execute(call, context) {
|
|
1642
1753
|
return this.implementation.execute(call, context);
|
|
1643
1754
|
}
|