open-agents-ai 0.16.5 → 0.17.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/dist/index.js +2052 -213
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1285,7 +1285,7 @@ ${stdinInput ?? ""}`);
|
|
|
1285
1285
|
}
|
|
1286
1286
|
runCommand(command, timeout, stdinInput) {
|
|
1287
1287
|
const start = performance.now();
|
|
1288
|
-
return new Promise((
|
|
1288
|
+
return new Promise((resolve18) => {
|
|
1289
1289
|
const child = spawn("bash", ["-c", command], {
|
|
1290
1290
|
cwd: this.workingDir,
|
|
1291
1291
|
env: {
|
|
@@ -1338,7 +1338,7 @@ ${stdinInput ?? ""}`);
|
|
|
1338
1338
|
const combined = stdout + stderr;
|
|
1339
1339
|
const looksInteractive = /\? .+[›>]|y\/n|yes\/no|\(Y\/n\)|\[y\/N\]/i.test(combined);
|
|
1340
1340
|
const hint = looksInteractive ? " The command appears to be waiting for interactive input. Use non-interactive flags (e.g., --yes, --no-input) or provide input via the stdin parameter." : "";
|
|
1341
|
-
|
|
1341
|
+
resolve18({
|
|
1342
1342
|
success: false,
|
|
1343
1343
|
output: stdout,
|
|
1344
1344
|
error: `Command timed out after ${timeout}ms.${hint}`,
|
|
@@ -1347,7 +1347,7 @@ ${stdinInput ?? ""}`);
|
|
|
1347
1347
|
return;
|
|
1348
1348
|
}
|
|
1349
1349
|
const success = code === 0;
|
|
1350
|
-
|
|
1350
|
+
resolve18({
|
|
1351
1351
|
success,
|
|
1352
1352
|
output: stdout + (stderr && success ? `
|
|
1353
1353
|
STDERR:
|
|
@@ -1358,7 +1358,7 @@ ${stderr}` : ""),
|
|
|
1358
1358
|
});
|
|
1359
1359
|
child.on("error", (err) => {
|
|
1360
1360
|
clearTimeout(timer);
|
|
1361
|
-
|
|
1361
|
+
resolve18({
|
|
1362
1362
|
success: false,
|
|
1363
1363
|
output: stdout,
|
|
1364
1364
|
error: err.message,
|
|
@@ -1732,15 +1732,24 @@ var init_web_fetch = __esm({
|
|
|
1732
1732
|
});
|
|
1733
1733
|
|
|
1734
1734
|
// packages/execution/dist/tools/web-search.js
|
|
1735
|
-
|
|
1735
|
+
function detectSearchProvider() {
|
|
1736
|
+
if (process.env["TAVILY_API_KEY"])
|
|
1737
|
+
return "tavily";
|
|
1738
|
+
if (process.env["JINA_API_KEY"])
|
|
1739
|
+
return "jina";
|
|
1740
|
+
return "duckduckgo";
|
|
1741
|
+
}
|
|
1742
|
+
var DEFAULT_NUM_RESULTS, DUCKDUCKGO_HTML_URL, TAVILY_API_URL, JINA_SEARCH_URL, WebSearchTool;
|
|
1736
1743
|
var init_web_search = __esm({
|
|
1737
1744
|
"packages/execution/dist/tools/web-search.js"() {
|
|
1738
1745
|
"use strict";
|
|
1739
1746
|
DEFAULT_NUM_RESULTS = 5;
|
|
1740
1747
|
DUCKDUCKGO_HTML_URL = "https://html.duckduckgo.com/html/";
|
|
1748
|
+
TAVILY_API_URL = "https://api.tavily.com/search";
|
|
1749
|
+
JINA_SEARCH_URL = "https://s.jina.ai/";
|
|
1741
1750
|
WebSearchTool = class {
|
|
1742
1751
|
name = "web_search";
|
|
1743
|
-
description = "Search the web for information. Returns
|
|
1752
|
+
description = "Search the web for information. Returns search results with titles, URLs, and snippets. Supports DuckDuckGo (free), Tavily (structured, set TAVILY_API_KEY), and Jina AI (markdown, set JINA_API_KEY).";
|
|
1744
1753
|
parameters = {
|
|
1745
1754
|
type: "object",
|
|
1746
1755
|
properties: {
|
|
@@ -1751,6 +1760,11 @@ var init_web_search = __esm({
|
|
|
1751
1760
|
num_results: {
|
|
1752
1761
|
type: "number",
|
|
1753
1762
|
description: `Number of results to return (default: ${DEFAULT_NUM_RESULTS})`
|
|
1763
|
+
},
|
|
1764
|
+
provider: {
|
|
1765
|
+
type: "string",
|
|
1766
|
+
enum: ["duckduckgo", "tavily", "jina"],
|
|
1767
|
+
description: "Search provider (auto-detected from API keys if omitted). tavily: structured JSON results with AI answer. jina: markdown-formatted results. duckduckgo: free HTML scraping fallback."
|
|
1754
1768
|
}
|
|
1755
1769
|
},
|
|
1756
1770
|
required: ["query"]
|
|
@@ -1758,43 +1772,73 @@ var init_web_search = __esm({
|
|
|
1758
1772
|
async execute(args) {
|
|
1759
1773
|
const query = args["query"];
|
|
1760
1774
|
const numResults = args["num_results"] ?? DEFAULT_NUM_RESULTS;
|
|
1775
|
+
const requestedProvider = args["provider"];
|
|
1761
1776
|
const start = performance.now();
|
|
1777
|
+
const provider = requestedProvider ?? detectSearchProvider();
|
|
1762
1778
|
try {
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
|
|
1774
|
-
success: false,
|
|
1775
|
-
output: "",
|
|
1776
|
-
error: `HTTP ${response.status} ${response.statusText} from DuckDuckGo`,
|
|
1777
|
-
durationMs: performance.now() - start
|
|
1778
|
-
};
|
|
1779
|
+
let response;
|
|
1780
|
+
switch (provider) {
|
|
1781
|
+
case "tavily":
|
|
1782
|
+
response = await this.#searchTavily(query, numResults);
|
|
1783
|
+
break;
|
|
1784
|
+
case "jina":
|
|
1785
|
+
response = await this.#searchJina(query, numResults);
|
|
1786
|
+
break;
|
|
1787
|
+
default:
|
|
1788
|
+
response = await this.#searchDuckDuckGo(query, numResults);
|
|
1789
|
+
break;
|
|
1779
1790
|
}
|
|
1780
|
-
|
|
1781
|
-
const results = this.#parseResults(html, numResults);
|
|
1782
|
-
if (results.length === 0) {
|
|
1791
|
+
if (response.results.length === 0) {
|
|
1783
1792
|
return {
|
|
1784
1793
|
success: true,
|
|
1785
1794
|
output: "No results found.",
|
|
1786
1795
|
durationMs: performance.now() - start
|
|
1787
1796
|
};
|
|
1788
1797
|
}
|
|
1789
|
-
const
|
|
1790
|
-
|
|
1791
|
-
|
|
1798
|
+
const parts = [];
|
|
1799
|
+
if (response.aiAnswer) {
|
|
1800
|
+
parts.push(`AI Answer: ${response.aiAnswer}
|
|
1801
|
+
`);
|
|
1802
|
+
}
|
|
1803
|
+
for (let i = 0; i < response.results.length; i++) {
|
|
1804
|
+
const r = response.results[i];
|
|
1805
|
+
let line = `${i + 1}. ${r.title}
|
|
1806
|
+
URL: ${r.url}`;
|
|
1807
|
+
if (r.score !== void 0) {
|
|
1808
|
+
line += `
|
|
1809
|
+
Relevance: ${(r.score * 100).toFixed(0)}%`;
|
|
1810
|
+
}
|
|
1811
|
+
if (r.snippet) {
|
|
1812
|
+
line += `
|
|
1813
|
+
${r.snippet}`;
|
|
1814
|
+
}
|
|
1815
|
+
parts.push(line);
|
|
1816
|
+
}
|
|
1817
|
+
const providerTag = provider !== "duckduckgo" ? ` [${provider}]` : "";
|
|
1792
1818
|
return {
|
|
1793
1819
|
success: true,
|
|
1794
|
-
output:
|
|
1820
|
+
output: parts.join("\n\n") + providerTag,
|
|
1795
1821
|
durationMs: performance.now() - start
|
|
1796
1822
|
};
|
|
1797
1823
|
} catch (error) {
|
|
1824
|
+
if (provider !== "duckduckgo") {
|
|
1825
|
+
try {
|
|
1826
|
+
const fallback = await this.#searchDuckDuckGo(query, numResults);
|
|
1827
|
+
if (fallback.results.length > 0) {
|
|
1828
|
+
const formatted = fallback.results.map((r, i) => `${i + 1}. ${r.title}
|
|
1829
|
+
URL: ${r.url}
|
|
1830
|
+
${r.snippet}`).join("\n\n");
|
|
1831
|
+
return {
|
|
1832
|
+
success: true,
|
|
1833
|
+
output: `[${provider} failed, fell back to DuckDuckGo]
|
|
1834
|
+
|
|
1835
|
+
${formatted}`,
|
|
1836
|
+
durationMs: performance.now() - start
|
|
1837
|
+
};
|
|
1838
|
+
}
|
|
1839
|
+
} catch {
|
|
1840
|
+
}
|
|
1841
|
+
}
|
|
1798
1842
|
return {
|
|
1799
1843
|
success: false,
|
|
1800
1844
|
output: "",
|
|
@@ -1803,7 +1847,109 @@ var init_web_search = __esm({
|
|
|
1803
1847
|
};
|
|
1804
1848
|
}
|
|
1805
1849
|
}
|
|
1806
|
-
|
|
1850
|
+
// -------------------------------------------------------------------------
|
|
1851
|
+
// Tavily provider — structured JSON search API
|
|
1852
|
+
// -------------------------------------------------------------------------
|
|
1853
|
+
async #searchTavily(query, numResults) {
|
|
1854
|
+
const apiKey = process.env["TAVILY_API_KEY"];
|
|
1855
|
+
if (!apiKey) {
|
|
1856
|
+
throw new Error("TAVILY_API_KEY not set. Set the env var or use provider=duckduckgo.");
|
|
1857
|
+
}
|
|
1858
|
+
const body = {
|
|
1859
|
+
query,
|
|
1860
|
+
max_results: numResults,
|
|
1861
|
+
include_answer: true,
|
|
1862
|
+
search_depth: "basic"
|
|
1863
|
+
};
|
|
1864
|
+
const resp = await fetch(TAVILY_API_URL, {
|
|
1865
|
+
method: "POST",
|
|
1866
|
+
headers: {
|
|
1867
|
+
"Content-Type": "application/json",
|
|
1868
|
+
Authorization: `Bearer ${apiKey}`
|
|
1869
|
+
},
|
|
1870
|
+
body: JSON.stringify(body),
|
|
1871
|
+
signal: AbortSignal.timeout(2e4)
|
|
1872
|
+
});
|
|
1873
|
+
if (!resp.ok) {
|
|
1874
|
+
throw new Error(`Tavily HTTP ${resp.status} ${resp.statusText}`);
|
|
1875
|
+
}
|
|
1876
|
+
const data = await resp.json();
|
|
1877
|
+
const results = (data.results ?? []).map((r) => ({
|
|
1878
|
+
title: r.title ?? "",
|
|
1879
|
+
url: r.url ?? "",
|
|
1880
|
+
snippet: r.content ?? "",
|
|
1881
|
+
score: r.score
|
|
1882
|
+
}));
|
|
1883
|
+
return {
|
|
1884
|
+
provider: "tavily",
|
|
1885
|
+
query,
|
|
1886
|
+
results,
|
|
1887
|
+
aiAnswer: data.answer
|
|
1888
|
+
};
|
|
1889
|
+
}
|
|
1890
|
+
// -------------------------------------------------------------------------
|
|
1891
|
+
// Jina AI provider — markdown-formatted search
|
|
1892
|
+
// -------------------------------------------------------------------------
|
|
1893
|
+
async #searchJina(query, numResults) {
|
|
1894
|
+
const apiKey = process.env["JINA_API_KEY"];
|
|
1895
|
+
if (!apiKey) {
|
|
1896
|
+
throw new Error("JINA_API_KEY not set. Set the env var or use provider=duckduckgo.");
|
|
1897
|
+
}
|
|
1898
|
+
const searchUrl = `${JINA_SEARCH_URL}${encodeURIComponent(query)}`;
|
|
1899
|
+
const headers = {
|
|
1900
|
+
Accept: "application/json",
|
|
1901
|
+
Authorization: `Bearer ${apiKey}`,
|
|
1902
|
+
"X-Retain-Images": "none"
|
|
1903
|
+
};
|
|
1904
|
+
const resp = await fetch(searchUrl, {
|
|
1905
|
+
method: "GET",
|
|
1906
|
+
headers,
|
|
1907
|
+
signal: AbortSignal.timeout(2e4)
|
|
1908
|
+
});
|
|
1909
|
+
if (!resp.ok) {
|
|
1910
|
+
throw new Error(`Jina HTTP ${resp.status} ${resp.statusText}`);
|
|
1911
|
+
}
|
|
1912
|
+
const data = await resp.json();
|
|
1913
|
+
const items = data.data ?? [];
|
|
1914
|
+
const results = items.slice(0, numResults).map((r) => ({
|
|
1915
|
+
title: r.title ?? "",
|
|
1916
|
+
url: r.url ?? "",
|
|
1917
|
+
snippet: r.description ?? r.content ?? ""
|
|
1918
|
+
}));
|
|
1919
|
+
return {
|
|
1920
|
+
provider: "jina",
|
|
1921
|
+
query,
|
|
1922
|
+
results
|
|
1923
|
+
};
|
|
1924
|
+
}
|
|
1925
|
+
// -------------------------------------------------------------------------
|
|
1926
|
+
// DuckDuckGo provider — free HTML scraping fallback
|
|
1927
|
+
// -------------------------------------------------------------------------
|
|
1928
|
+
async #searchDuckDuckGo(query, numResults) {
|
|
1929
|
+
const searchUrl = `${DUCKDUCKGO_HTML_URL}?q=${encodeURIComponent(query)}`;
|
|
1930
|
+
const response = await fetch(searchUrl, {
|
|
1931
|
+
method: "GET",
|
|
1932
|
+
headers: {
|
|
1933
|
+
"User-Agent": "Mozilla/5.0 (compatible; open-coding-agent/1.0; +https://github.com/open-agents)",
|
|
1934
|
+
Accept: "text/html"
|
|
1935
|
+
},
|
|
1936
|
+
signal: AbortSignal.timeout(15e3)
|
|
1937
|
+
});
|
|
1938
|
+
if (!response.ok) {
|
|
1939
|
+
throw new Error(`HTTP ${response.status} ${response.statusText} from DuckDuckGo`);
|
|
1940
|
+
}
|
|
1941
|
+
const html = await response.text();
|
|
1942
|
+
const results = this.#parseDDGResults(html, numResults);
|
|
1943
|
+
return {
|
|
1944
|
+
provider: "duckduckgo",
|
|
1945
|
+
query,
|
|
1946
|
+
results
|
|
1947
|
+
};
|
|
1948
|
+
}
|
|
1949
|
+
// -------------------------------------------------------------------------
|
|
1950
|
+
// DuckDuckGo HTML parsing (unchanged from original)
|
|
1951
|
+
// -------------------------------------------------------------------------
|
|
1952
|
+
#parseDDGResults(html, limit) {
|
|
1807
1953
|
const results = [];
|
|
1808
1954
|
const resultBlockRegex = /<div[^>]+class="[^"]*result[^"]*"[^>]*>([\s\S]*?)<\/div>\s*<\/div>/gi;
|
|
1809
1955
|
let blockMatch;
|
|
@@ -3862,12 +4008,12 @@ var init_image = __esm({
|
|
|
3862
4008
|
if (!existsSync7(fullPath)) {
|
|
3863
4009
|
return { success: false, output: "", error: `File not found: ${rawPath}`, durationMs: Date.now() - start };
|
|
3864
4010
|
}
|
|
3865
|
-
const
|
|
3866
|
-
if (
|
|
4011
|
+
const stat5 = statSync4(fullPath);
|
|
4012
|
+
if (stat5.size > maxSizeKb * 1024) {
|
|
3867
4013
|
return {
|
|
3868
4014
|
success: false,
|
|
3869
4015
|
output: "",
|
|
3870
|
-
error: `File too large: ${(
|
|
4016
|
+
error: `File too large: ${(stat5.size / 1024).toFixed(0)}KB (max: ${maxSizeKb}KB)`,
|
|
3871
4017
|
durationMs: Date.now() - start
|
|
3872
4018
|
};
|
|
3873
4019
|
}
|
|
@@ -3877,7 +4023,7 @@ var init_image = __esm({
|
|
|
3877
4023
|
const base64 = imageToBase64(fullPath);
|
|
3878
4024
|
const mime = getMimeType(fullPath);
|
|
3879
4025
|
const dims = getImageDimensions(fullPath);
|
|
3880
|
-
const sizeKb = (
|
|
4026
|
+
const sizeKb = (stat5.size / 1024).toFixed(1);
|
|
3881
4027
|
const parts = [
|
|
3882
4028
|
`File: ${basename(fullPath)}`,
|
|
3883
4029
|
`Size: ${sizeKb}KB`,
|
|
@@ -3955,12 +4101,12 @@ ${ocrText}`);
|
|
|
3955
4101
|
if (!existsSync7(outputPath)) {
|
|
3956
4102
|
return { success: false, output: "", error: "Screenshot file not created", durationMs: Date.now() - start };
|
|
3957
4103
|
}
|
|
3958
|
-
const
|
|
4104
|
+
const stat5 = statSync4(outputPath);
|
|
3959
4105
|
const base64 = imageToBase64(outputPath);
|
|
3960
4106
|
const dims = getImageDimensions(outputPath);
|
|
3961
4107
|
const parts = [
|
|
3962
4108
|
`Screenshot saved: ${outputPath}`,
|
|
3963
|
-
`Size: ${(
|
|
4109
|
+
`Size: ${(stat5.size / 1024).toFixed(1)}KB`
|
|
3964
4110
|
];
|
|
3965
4111
|
if (dims)
|
|
3966
4112
|
parts.push(`Dimensions: ${dims.width}x${dims.height}`);
|
|
@@ -4265,7 +4411,7 @@ var init_custom_tool = __esm({
|
|
|
4265
4411
|
}
|
|
4266
4412
|
/** Execute a single shell command and return output */
|
|
4267
4413
|
runCommand(command) {
|
|
4268
|
-
return new Promise((
|
|
4414
|
+
return new Promise((resolve18) => {
|
|
4269
4415
|
const child = spawn3("bash", ["-c", command], {
|
|
4270
4416
|
cwd: this.workingDir,
|
|
4271
4417
|
env: { ...process.env, CI: "true", NO_COLOR: "1" },
|
|
@@ -4290,11 +4436,11 @@ var init_custom_tool = __esm({
|
|
|
4290
4436
|
child.kill("SIGTERM");
|
|
4291
4437
|
} catch {
|
|
4292
4438
|
}
|
|
4293
|
-
|
|
4439
|
+
resolve18({ success: false, output: stdout, error: "Command timed out after 60s" });
|
|
4294
4440
|
}, 6e4);
|
|
4295
4441
|
child.on("close", (code) => {
|
|
4296
4442
|
clearTimeout(timer);
|
|
4297
|
-
|
|
4443
|
+
resolve18({
|
|
4298
4444
|
success: code === 0,
|
|
4299
4445
|
output: stdout + (stderr && code === 0 ? `
|
|
4300
4446
|
STDERR:
|
|
@@ -4304,7 +4450,7 @@ ${stderr}` : ""),
|
|
|
4304
4450
|
});
|
|
4305
4451
|
child.on("error", (err) => {
|
|
4306
4452
|
clearTimeout(timer);
|
|
4307
|
-
|
|
4453
|
+
resolve18({ success: false, output: stdout, error: err.message });
|
|
4308
4454
|
});
|
|
4309
4455
|
});
|
|
4310
4456
|
}
|
|
@@ -5240,7 +5386,775 @@ ${result.output}`,
|
|
|
5240
5386
|
return {
|
|
5241
5387
|
success: false,
|
|
5242
5388
|
output: "",
|
|
5243
|
-
error: `Failed to download/transcribe: ${err instanceof Error ? err.message : String(err)}`,
|
|
5389
|
+
error: `Failed to download/transcribe: ${err instanceof Error ? err.message : String(err)}`,
|
|
5390
|
+
durationMs: performance.now() - start
|
|
5391
|
+
};
|
|
5392
|
+
}
|
|
5393
|
+
}
|
|
5394
|
+
};
|
|
5395
|
+
}
|
|
5396
|
+
});
|
|
5397
|
+
|
|
5398
|
+
// packages/execution/dist/tools/structured-file.js
|
|
5399
|
+
import { writeFile as writeFile6, mkdir as mkdir3 } from "node:fs/promises";
|
|
5400
|
+
import { resolve as resolve13, dirname as dirname3, extname as extname4 } from "node:path";
|
|
5401
|
+
function jsonToCSV(data, separator = ",") {
|
|
5402
|
+
if (!Array.isArray(data) || data.length === 0)
|
|
5403
|
+
return "";
|
|
5404
|
+
const headers = Object.keys(data[0]);
|
|
5405
|
+
const esc = (val) => {
|
|
5406
|
+
const str = val === null || val === void 0 ? "" : String(val);
|
|
5407
|
+
if (str.includes(separator) || str.includes('"') || str.includes("\n")) {
|
|
5408
|
+
return `"${str.replace(/"/g, '""')}"`;
|
|
5409
|
+
}
|
|
5410
|
+
return str;
|
|
5411
|
+
};
|
|
5412
|
+
const lines = [
|
|
5413
|
+
headers.map((h) => esc(h)).join(separator),
|
|
5414
|
+
...data.map((row) => {
|
|
5415
|
+
const obj = row;
|
|
5416
|
+
return headers.map((h) => esc(obj[h])).join(separator);
|
|
5417
|
+
})
|
|
5418
|
+
];
|
|
5419
|
+
return lines.join("\n") + "\n";
|
|
5420
|
+
}
|
|
5421
|
+
function jsonToMarkdownTable(data) {
|
|
5422
|
+
if (!Array.isArray(data) || data.length === 0)
|
|
5423
|
+
return "";
|
|
5424
|
+
const headers = Object.keys(data[0]);
|
|
5425
|
+
const headerRow = `| ${headers.join(" | ")} |`;
|
|
5426
|
+
const sepRow = `| ${headers.map(() => "---").join(" | ")} |`;
|
|
5427
|
+
const dataRows = data.map((row) => {
|
|
5428
|
+
const obj = row;
|
|
5429
|
+
return `| ${headers.map((h) => String(obj[h] ?? "")).join(" | ")} |`;
|
|
5430
|
+
});
|
|
5431
|
+
return [headerRow, sepRow, ...dataRows].join("\n") + "\n";
|
|
5432
|
+
}
|
|
5433
|
+
var StructuredFileTool;
|
|
5434
|
+
var init_structured_file = __esm({
|
|
5435
|
+
"packages/execution/dist/tools/structured-file.js"() {
|
|
5436
|
+
"use strict";
|
|
5437
|
+
StructuredFileTool = class {
|
|
5438
|
+
name = "create_structured_file";
|
|
5439
|
+
description = "Create a structured file (CSV, JSON, Markdown table, or Excel-compatible) from data. Provide data as a JSON array of objects. Each object becomes a row, keys become columns.";
|
|
5440
|
+
parameters = {
|
|
5441
|
+
type: "object",
|
|
5442
|
+
properties: {
|
|
5443
|
+
path: {
|
|
5444
|
+
type: "string",
|
|
5445
|
+
description: "Output file path (extension determines format: .csv, .json, .md, .tsv, .xlsx)"
|
|
5446
|
+
},
|
|
5447
|
+
data: {
|
|
5448
|
+
type: "array",
|
|
5449
|
+
description: "Array of objects \u2014 each object is a row, keys are column headers",
|
|
5450
|
+
items: { type: "object" }
|
|
5451
|
+
},
|
|
5452
|
+
format: {
|
|
5453
|
+
type: "string",
|
|
5454
|
+
enum: ["csv", "json", "markdown", "tsv", "xlsx"],
|
|
5455
|
+
description: "Output format (auto-detected from file extension if omitted)"
|
|
5456
|
+
},
|
|
5457
|
+
title: {
|
|
5458
|
+
type: "string",
|
|
5459
|
+
description: "Optional title/heading for markdown output"
|
|
5460
|
+
},
|
|
5461
|
+
sheets: {
|
|
5462
|
+
type: "array",
|
|
5463
|
+
description: "For multi-sheet xlsx: array of {name, data} objects",
|
|
5464
|
+
items: {
|
|
5465
|
+
type: "object",
|
|
5466
|
+
properties: {
|
|
5467
|
+
name: { type: "string" },
|
|
5468
|
+
data: { type: "array", items: { type: "object" } }
|
|
5469
|
+
}
|
|
5470
|
+
}
|
|
5471
|
+
}
|
|
5472
|
+
},
|
|
5473
|
+
required: ["path"]
|
|
5474
|
+
};
|
|
5475
|
+
workingDir;
|
|
5476
|
+
constructor(workingDir) {
|
|
5477
|
+
this.workingDir = workingDir;
|
|
5478
|
+
}
|
|
5479
|
+
async execute(args) {
|
|
5480
|
+
const filePath = args["path"];
|
|
5481
|
+
const data = args["data"] ?? [];
|
|
5482
|
+
const title = args["title"];
|
|
5483
|
+
const sheets = args["sheets"];
|
|
5484
|
+
const start = performance.now();
|
|
5485
|
+
if (!filePath) {
|
|
5486
|
+
return { success: false, output: "", error: "path is required", durationMs: 0 };
|
|
5487
|
+
}
|
|
5488
|
+
const ext = extname4(filePath).toLowerCase();
|
|
5489
|
+
let format = args["format"] ?? "";
|
|
5490
|
+
if (!format) {
|
|
5491
|
+
switch (ext) {
|
|
5492
|
+
case ".csv":
|
|
5493
|
+
format = "csv";
|
|
5494
|
+
break;
|
|
5495
|
+
case ".tsv":
|
|
5496
|
+
format = "tsv";
|
|
5497
|
+
break;
|
|
5498
|
+
case ".json":
|
|
5499
|
+
format = "json";
|
|
5500
|
+
break;
|
|
5501
|
+
case ".md":
|
|
5502
|
+
case ".markdown":
|
|
5503
|
+
format = "markdown";
|
|
5504
|
+
break;
|
|
5505
|
+
case ".xlsx":
|
|
5506
|
+
case ".xls":
|
|
5507
|
+
format = "xlsx";
|
|
5508
|
+
break;
|
|
5509
|
+
default:
|
|
5510
|
+
format = "csv";
|
|
5511
|
+
}
|
|
5512
|
+
}
|
|
5513
|
+
try {
|
|
5514
|
+
const fullPath = resolve13(this.workingDir, filePath);
|
|
5515
|
+
await mkdir3(dirname3(fullPath), { recursive: true });
|
|
5516
|
+
let content;
|
|
5517
|
+
let byteInfo = "";
|
|
5518
|
+
switch (format) {
|
|
5519
|
+
case "csv":
|
|
5520
|
+
content = jsonToCSV(data, ",");
|
|
5521
|
+
byteInfo = `${data.length} rows`;
|
|
5522
|
+
break;
|
|
5523
|
+
case "tsv":
|
|
5524
|
+
case "xlsx":
|
|
5525
|
+
content = jsonToCSV(data, " ");
|
|
5526
|
+
byteInfo = `${data.length} rows (tab-separated)`;
|
|
5527
|
+
break;
|
|
5528
|
+
case "json":
|
|
5529
|
+
content = JSON.stringify(data, null, 2) + "\n";
|
|
5530
|
+
byteInfo = `${data.length} items`;
|
|
5531
|
+
break;
|
|
5532
|
+
case "markdown": {
|
|
5533
|
+
const parts = [];
|
|
5534
|
+
if (title)
|
|
5535
|
+
parts.push(`# ${title}
|
|
5536
|
+
`);
|
|
5537
|
+
if (sheets && sheets.length > 0) {
|
|
5538
|
+
for (const sheet of sheets) {
|
|
5539
|
+
parts.push(`## ${sheet.name}
|
|
5540
|
+
`);
|
|
5541
|
+
parts.push(jsonToMarkdownTable(sheet.data));
|
|
5542
|
+
parts.push("");
|
|
5543
|
+
}
|
|
5544
|
+
} else if (data.length > 0) {
|
|
5545
|
+
parts.push(jsonToMarkdownTable(data));
|
|
5546
|
+
}
|
|
5547
|
+
content = parts.join("\n");
|
|
5548
|
+
byteInfo = sheets ? `${sheets.length} sections, ${sheets.reduce((s, sh) => s + sh.data.length, 0)} total rows` : `${data.length} rows`;
|
|
5549
|
+
break;
|
|
5550
|
+
}
|
|
5551
|
+
default:
|
|
5552
|
+
return {
|
|
5553
|
+
success: false,
|
|
5554
|
+
output: "",
|
|
5555
|
+
error: `Unknown format: ${format}. Use csv, json, markdown, tsv, or xlsx.`,
|
|
5556
|
+
durationMs: performance.now() - start
|
|
5557
|
+
};
|
|
5558
|
+
}
|
|
5559
|
+
await writeFile6(fullPath, content, "utf-8");
|
|
5560
|
+
return {
|
|
5561
|
+
success: true,
|
|
5562
|
+
output: `Created ${format.toUpperCase()} file: ${fullPath} (${byteInfo}, ${content.length} bytes)`,
|
|
5563
|
+
durationMs: performance.now() - start
|
|
5564
|
+
};
|
|
5565
|
+
} catch (error) {
|
|
5566
|
+
return {
|
|
5567
|
+
success: false,
|
|
5568
|
+
output: "",
|
|
5569
|
+
error: error instanceof Error ? error.message : String(error),
|
|
5570
|
+
durationMs: performance.now() - start
|
|
5571
|
+
};
|
|
5572
|
+
}
|
|
5573
|
+
}
|
|
5574
|
+
};
|
|
5575
|
+
}
|
|
5576
|
+
});
|
|
5577
|
+
|
|
5578
|
+
// packages/execution/dist/tools/code-sandbox.js
|
|
5579
|
+
import { spawn as spawn5 } from "node:child_process";
|
|
5580
|
+
import { writeFile as writeFile7, mkdtemp, rm, readdir, stat } from "node:fs/promises";
|
|
5581
|
+
import { join as join14 } from "node:path";
|
|
5582
|
+
import { tmpdir as tmpdir2 } from "node:os";
|
|
5583
|
+
function runProcess(cmd, args, options) {
|
|
5584
|
+
return new Promise((resolve18) => {
|
|
5585
|
+
const proc = spawn5(cmd, args, {
|
|
5586
|
+
cwd: options.cwd,
|
|
5587
|
+
timeout: options.timeout,
|
|
5588
|
+
env: {
|
|
5589
|
+
PATH: process.env["PATH"] ?? "/usr/bin:/bin",
|
|
5590
|
+
HOME: options.cwd,
|
|
5591
|
+
TMPDIR: options.cwd,
|
|
5592
|
+
NODE_ENV: "sandbox",
|
|
5593
|
+
...options.env ?? {}
|
|
5594
|
+
},
|
|
5595
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
5596
|
+
});
|
|
5597
|
+
let stdout = "";
|
|
5598
|
+
let stderr = "";
|
|
5599
|
+
let timedOut = false;
|
|
5600
|
+
proc.stdout.on("data", (d) => {
|
|
5601
|
+
stdout += d.toString();
|
|
5602
|
+
if (stdout.length > 1e5) {
|
|
5603
|
+
stdout = stdout.slice(0, 1e5) + "\n[output truncated at 100KB]";
|
|
5604
|
+
proc.kill("SIGKILL");
|
|
5605
|
+
}
|
|
5606
|
+
});
|
|
5607
|
+
proc.stderr.on("data", (d) => {
|
|
5608
|
+
stderr += d.toString();
|
|
5609
|
+
if (stderr.length > 5e4) {
|
|
5610
|
+
stderr = stderr.slice(0, 5e4) + "\n[stderr truncated at 50KB]";
|
|
5611
|
+
}
|
|
5612
|
+
});
|
|
5613
|
+
proc.on("error", (err) => {
|
|
5614
|
+
resolve18({
|
|
5615
|
+
stdout,
|
|
5616
|
+
stderr: stderr || err.message,
|
|
5617
|
+
exitCode: 1,
|
|
5618
|
+
filesCreated: [],
|
|
5619
|
+
timedOut: false
|
|
5620
|
+
});
|
|
5621
|
+
});
|
|
5622
|
+
proc.on("close", (code, signal) => {
|
|
5623
|
+
if (signal === "SIGTERM" || signal === "SIGKILL") {
|
|
5624
|
+
timedOut = true;
|
|
5625
|
+
}
|
|
5626
|
+
resolve18({
|
|
5627
|
+
stdout,
|
|
5628
|
+
stderr,
|
|
5629
|
+
exitCode: code ?? (timedOut ? 124 : 1),
|
|
5630
|
+
filesCreated: [],
|
|
5631
|
+
timedOut
|
|
5632
|
+
});
|
|
5633
|
+
});
|
|
5634
|
+
if (options.stdin) {
|
|
5635
|
+
proc.stdin.write(options.stdin);
|
|
5636
|
+
}
|
|
5637
|
+
proc.stdin.end();
|
|
5638
|
+
});
|
|
5639
|
+
}
|
|
5640
|
+
async function listCreatedFiles(dir) {
|
|
5641
|
+
const files = [];
|
|
5642
|
+
try {
|
|
5643
|
+
const entries = await readdir(dir);
|
|
5644
|
+
for (const entry of entries) {
|
|
5645
|
+
if (entry.startsWith("_sandbox_script"))
|
|
5646
|
+
continue;
|
|
5647
|
+
const fullPath = join14(dir, entry);
|
|
5648
|
+
const s = await stat(fullPath);
|
|
5649
|
+
if (s.isFile()) {
|
|
5650
|
+
files.push(entry);
|
|
5651
|
+
}
|
|
5652
|
+
}
|
|
5653
|
+
} catch {
|
|
5654
|
+
}
|
|
5655
|
+
return files;
|
|
5656
|
+
}
|
|
5657
|
+
var LANGUAGE_CONFIG, CodeSandboxTool;
|
|
5658
|
+
var init_code_sandbox = __esm({
|
|
5659
|
+
"packages/execution/dist/tools/code-sandbox.js"() {
|
|
5660
|
+
"use strict";
|
|
5661
|
+
LANGUAGE_CONFIG = {
|
|
5662
|
+
javascript: { ext: ".js", cmd: "node", args: (f) => [f] },
|
|
5663
|
+
python: { ext: ".py", cmd: "python3", args: (f) => [f] },
|
|
5664
|
+
bash: { ext: ".sh", cmd: "bash", args: (f) => [f] },
|
|
5665
|
+
typescript: { ext: ".ts", cmd: "npx", args: (f) => ["tsx", f] }
|
|
5666
|
+
};
|
|
5667
|
+
CodeSandboxTool = class {
|
|
5668
|
+
name = "code_sandbox";
|
|
5669
|
+
description = "Execute code in an isolated sandbox environment. Safer than shell for running generated or untrusted code. Supports JavaScript, Python, Bash, and TypeScript. Returns stdout, stderr, exit code, and any files created.";
|
|
5670
|
+
parameters = {
|
|
5671
|
+
type: "object",
|
|
5672
|
+
properties: {
|
|
5673
|
+
code: {
|
|
5674
|
+
type: "string",
|
|
5675
|
+
description: "The code to execute"
|
|
5676
|
+
},
|
|
5677
|
+
language: {
|
|
5678
|
+
type: "string",
|
|
5679
|
+
enum: ["javascript", "python", "bash", "typescript"],
|
|
5680
|
+
description: "Programming language (default: javascript)"
|
|
5681
|
+
},
|
|
5682
|
+
timeout_ms: {
|
|
5683
|
+
type: "number",
|
|
5684
|
+
description: "Execution timeout in milliseconds (default: 30000, max: 120000)"
|
|
5685
|
+
},
|
|
5686
|
+
stdin: {
|
|
5687
|
+
type: "string",
|
|
5688
|
+
description: "Optional input to pass to stdin"
|
|
5689
|
+
},
|
|
5690
|
+
mode: {
|
|
5691
|
+
type: "string",
|
|
5692
|
+
enum: ["subprocess", "docker"],
|
|
5693
|
+
description: "Execution mode. subprocess (default): isolated process. docker: Docker container (requires Docker installed)."
|
|
5694
|
+
}
|
|
5695
|
+
},
|
|
5696
|
+
required: ["code"]
|
|
5697
|
+
};
|
|
5698
|
+
workingDir;
|
|
5699
|
+
constructor(workingDir) {
|
|
5700
|
+
this.workingDir = workingDir;
|
|
5701
|
+
}
|
|
5702
|
+
async execute(args) {
|
|
5703
|
+
const code = args["code"];
|
|
5704
|
+
const language = args["language"] ?? "javascript";
|
|
5705
|
+
const timeoutMs = Math.min(args["timeout_ms"] ?? 3e4, 12e4);
|
|
5706
|
+
const stdin = args["stdin"];
|
|
5707
|
+
const mode = args["mode"] ?? "subprocess";
|
|
5708
|
+
const start = performance.now();
|
|
5709
|
+
if (!code) {
|
|
5710
|
+
return { success: false, output: "", error: "code is required", durationMs: 0 };
|
|
5711
|
+
}
|
|
5712
|
+
const langConfig = LANGUAGE_CONFIG[language];
|
|
5713
|
+
if (!langConfig) {
|
|
5714
|
+
return {
|
|
5715
|
+
success: false,
|
|
5716
|
+
output: "",
|
|
5717
|
+
error: `Unsupported language: ${language}. Use javascript, python, bash, or typescript.`,
|
|
5718
|
+
durationMs: performance.now() - start
|
|
5719
|
+
};
|
|
5720
|
+
}
|
|
5721
|
+
try {
|
|
5722
|
+
let result;
|
|
5723
|
+
if (mode === "docker") {
|
|
5724
|
+
result = await this.#runDocker(code, language, langConfig, timeoutMs, stdin);
|
|
5725
|
+
} else {
|
|
5726
|
+
result = await this.#runSubprocess(code, langConfig, timeoutMs, stdin);
|
|
5727
|
+
}
|
|
5728
|
+
const parts = [];
|
|
5729
|
+
if (result.stdout) {
|
|
5730
|
+
parts.push(result.stdout.trimEnd());
|
|
5731
|
+
}
|
|
5732
|
+
if (result.stderr) {
|
|
5733
|
+
parts.push(`
|
|
5734
|
+
--- stderr ---
|
|
5735
|
+
${result.stderr.trimEnd()}`);
|
|
5736
|
+
}
|
|
5737
|
+
if (result.timedOut) {
|
|
5738
|
+
parts.push(`
|
|
5739
|
+
[Execution timed out after ${timeoutMs}ms]`);
|
|
5740
|
+
}
|
|
5741
|
+
if (result.filesCreated.length > 0) {
|
|
5742
|
+
parts.push(`
|
|
5743
|
+
--- files created ---
|
|
5744
|
+
${result.filesCreated.join("\n")}`);
|
|
5745
|
+
}
|
|
5746
|
+
parts.push(`
|
|
5747
|
+
[exit code: ${result.exitCode}]`);
|
|
5748
|
+
return {
|
|
5749
|
+
success: result.exitCode === 0,
|
|
5750
|
+
output: parts.join(""),
|
|
5751
|
+
error: result.exitCode !== 0 ? `Process exited with code ${result.exitCode}${result.timedOut ? " (timeout)" : ""}` : void 0,
|
|
5752
|
+
durationMs: performance.now() - start
|
|
5753
|
+
};
|
|
5754
|
+
} catch (error) {
|
|
5755
|
+
return {
|
|
5756
|
+
success: false,
|
|
5757
|
+
output: "",
|
|
5758
|
+
error: error instanceof Error ? error.message : String(error),
|
|
5759
|
+
durationMs: performance.now() - start
|
|
5760
|
+
};
|
|
5761
|
+
}
|
|
5762
|
+
}
|
|
5763
|
+
// -------------------------------------------------------------------------
|
|
5764
|
+
// Subprocess mode — temp directory + separate process
|
|
5765
|
+
// -------------------------------------------------------------------------
|
|
5766
|
+
async #runSubprocess(code, langConfig, timeoutMs, stdin) {
|
|
5767
|
+
const sandboxDir = await mkdtemp(join14(tmpdir2(), "oa-sandbox-"));
|
|
5768
|
+
try {
|
|
5769
|
+
const scriptFile = join14(sandboxDir, `_sandbox_script${langConfig.ext}`);
|
|
5770
|
+
await writeFile7(scriptFile, code, "utf-8");
|
|
5771
|
+
const result = await runProcess(langConfig.cmd, langConfig.args(scriptFile), {
|
|
5772
|
+
cwd: sandboxDir,
|
|
5773
|
+
timeout: timeoutMs,
|
|
5774
|
+
stdin
|
|
5775
|
+
});
|
|
5776
|
+
result.filesCreated = await listCreatedFiles(sandboxDir);
|
|
5777
|
+
return result;
|
|
5778
|
+
} finally {
|
|
5779
|
+
await rm(sandboxDir, { recursive: true, force: true }).catch(() => {
|
|
5780
|
+
});
|
|
5781
|
+
}
|
|
5782
|
+
}
|
|
5783
|
+
// -------------------------------------------------------------------------
|
|
5784
|
+
// Docker mode — run in container
|
|
5785
|
+
// -------------------------------------------------------------------------
|
|
5786
|
+
async #runDocker(code, language, langConfig, timeoutMs, stdin) {
|
|
5787
|
+
const images = {
|
|
5788
|
+
javascript: "node:22-slim",
|
|
5789
|
+
typescript: "node:22-slim",
|
|
5790
|
+
python: "python:3.12-slim",
|
|
5791
|
+
bash: "bash:5"
|
|
5792
|
+
};
|
|
5793
|
+
const image = images[language] ?? "node:22-slim";
|
|
5794
|
+
const sandboxDir = await mkdtemp(join14(tmpdir2(), "oa-docker-sandbox-"));
|
|
5795
|
+
try {
|
|
5796
|
+
const scriptFile = `_sandbox_script${langConfig.ext}`;
|
|
5797
|
+
await writeFile7(join14(sandboxDir, scriptFile), code, "utf-8");
|
|
5798
|
+
const dockerArgs = [
|
|
5799
|
+
"run",
|
|
5800
|
+
"--rm",
|
|
5801
|
+
"--network=none",
|
|
5802
|
+
// No network access
|
|
5803
|
+
"--memory=256m",
|
|
5804
|
+
// Memory limit
|
|
5805
|
+
"--cpus=1",
|
|
5806
|
+
// CPU limit
|
|
5807
|
+
"-v",
|
|
5808
|
+
`${sandboxDir}:/sandbox:rw`,
|
|
5809
|
+
"-w",
|
|
5810
|
+
"/sandbox",
|
|
5811
|
+
image,
|
|
5812
|
+
langConfig.cmd,
|
|
5813
|
+
...langConfig.args(`/sandbox/${scriptFile}`)
|
|
5814
|
+
];
|
|
5815
|
+
const result = await runProcess("docker", dockerArgs, {
|
|
5816
|
+
cwd: sandboxDir,
|
|
5817
|
+
timeout: timeoutMs,
|
|
5818
|
+
stdin
|
|
5819
|
+
});
|
|
5820
|
+
result.filesCreated = await listCreatedFiles(sandboxDir);
|
|
5821
|
+
return result;
|
|
5822
|
+
} finally {
|
|
5823
|
+
await rm(sandboxDir, { recursive: true, force: true }).catch(() => {
|
|
5824
|
+
});
|
|
5825
|
+
}
|
|
5826
|
+
}
|
|
5827
|
+
};
|
|
5828
|
+
}
|
|
5829
|
+
});
|
|
5830
|
+
|
|
5831
|
+
// packages/execution/dist/tools/structured-read.js
|
|
5832
|
+
import { readFile as readFile7, stat as stat2 } from "node:fs/promises";
|
|
5833
|
+
import { resolve as resolve14, extname as extname5 } from "node:path";
|
|
5834
|
+
function parseCSV(text, separator = ",") {
|
|
5835
|
+
const lines = text.split("\n").filter((l) => l.trim() !== "");
|
|
5836
|
+
if (lines.length < 2)
|
|
5837
|
+
return [];
|
|
5838
|
+
const parseLine = (line) => {
|
|
5839
|
+
const fields = [];
|
|
5840
|
+
let current = "";
|
|
5841
|
+
let inQuotes = false;
|
|
5842
|
+
for (let i = 0; i < line.length; i++) {
|
|
5843
|
+
const ch = line[i];
|
|
5844
|
+
if (inQuotes) {
|
|
5845
|
+
if (ch === '"' && line[i + 1] === '"') {
|
|
5846
|
+
current += '"';
|
|
5847
|
+
i++;
|
|
5848
|
+
} else if (ch === '"') {
|
|
5849
|
+
inQuotes = false;
|
|
5850
|
+
} else {
|
|
5851
|
+
current += ch;
|
|
5852
|
+
}
|
|
5853
|
+
} else {
|
|
5854
|
+
if (ch === '"') {
|
|
5855
|
+
inQuotes = true;
|
|
5856
|
+
} else if (ch === separator) {
|
|
5857
|
+
fields.push(current);
|
|
5858
|
+
current = "";
|
|
5859
|
+
} else {
|
|
5860
|
+
current += ch;
|
|
5861
|
+
}
|
|
5862
|
+
}
|
|
5863
|
+
}
|
|
5864
|
+
fields.push(current);
|
|
5865
|
+
return fields;
|
|
5866
|
+
};
|
|
5867
|
+
const headers = parseLine(lines[0]).map((h) => h.trim());
|
|
5868
|
+
const rows = [];
|
|
5869
|
+
for (let i = 1; i < lines.length; i++) {
|
|
5870
|
+
const values = parseLine(lines[i]);
|
|
5871
|
+
const row = {};
|
|
5872
|
+
for (let j = 0; j < headers.length; j++) {
|
|
5873
|
+
row[headers[j]] = (values[j] ?? "").trim();
|
|
5874
|
+
}
|
|
5875
|
+
rows.push(row);
|
|
5876
|
+
}
|
|
5877
|
+
return rows;
|
|
5878
|
+
}
|
|
5879
|
+
function parseMarkdownTables(text) {
|
|
5880
|
+
const tables = [];
|
|
5881
|
+
const lines = text.split("\n");
|
|
5882
|
+
let i = 0;
|
|
5883
|
+
while (i < lines.length) {
|
|
5884
|
+
const line = lines[i].trim();
|
|
5885
|
+
if (line.startsWith("|") && line.endsWith("|")) {
|
|
5886
|
+
const nextLine = (lines[i + 1] ?? "").trim();
|
|
5887
|
+
if (nextLine.startsWith("|") && /^\|[\s-:|]+\|$/.test(nextLine)) {
|
|
5888
|
+
let heading;
|
|
5889
|
+
for (let h = i - 1; h >= 0; h--) {
|
|
5890
|
+
const prev = lines[h].trim();
|
|
5891
|
+
if (prev === "")
|
|
5892
|
+
continue;
|
|
5893
|
+
if (prev.startsWith("#")) {
|
|
5894
|
+
heading = prev.replace(/^#+\s*/, "").trim();
|
|
5895
|
+
}
|
|
5896
|
+
break;
|
|
5897
|
+
}
|
|
5898
|
+
const headers = line.split("|").filter((c3) => c3.trim() !== "").map((c3) => c3.trim());
|
|
5899
|
+
const rows = [];
|
|
5900
|
+
i += 2;
|
|
5901
|
+
while (i < lines.length) {
|
|
5902
|
+
const dataLine = lines[i].trim();
|
|
5903
|
+
if (!dataLine.startsWith("|") || !dataLine.endsWith("|"))
|
|
5904
|
+
break;
|
|
5905
|
+
const values = dataLine.split("|").filter((c3) => c3.trim() !== "").map((c3) => c3.trim());
|
|
5906
|
+
const row = {};
|
|
5907
|
+
for (let j = 0; j < headers.length; j++) {
|
|
5908
|
+
row[headers[j]] = values[j] ?? "";
|
|
5909
|
+
}
|
|
5910
|
+
rows.push(row);
|
|
5911
|
+
i++;
|
|
5912
|
+
}
|
|
5913
|
+
if (rows.length > 0) {
|
|
5914
|
+
tables.push({ heading, rows });
|
|
5915
|
+
}
|
|
5916
|
+
continue;
|
|
5917
|
+
}
|
|
5918
|
+
}
|
|
5919
|
+
i++;
|
|
5920
|
+
}
|
|
5921
|
+
return tables;
|
|
5922
|
+
}
|
|
5923
|
+
function detectBinaryFormat(buffer) {
|
|
5924
|
+
if (buffer[0] === 80 && buffer[1] === 75) {
|
|
5925
|
+
const str = buffer.toString("utf-8", 0, Math.min(buffer.length, 2e3));
|
|
5926
|
+
if (str.includes("xl/") || str.includes("spreadsheetml"))
|
|
5927
|
+
return "xlsx";
|
|
5928
|
+
if (str.includes("word/") || str.includes("wordprocessingml"))
|
|
5929
|
+
return "docx";
|
|
5930
|
+
return "zip";
|
|
5931
|
+
}
|
|
5932
|
+
if (buffer[0] === 37 && buffer[1] === 80 && buffer[2] === 68 && buffer[3] === 70) {
|
|
5933
|
+
return "pdf";
|
|
5934
|
+
}
|
|
5935
|
+
return null;
|
|
5936
|
+
}
|
|
5937
|
+
var StructuredReadTool;
|
|
5938
|
+
var init_structured_read = __esm({
|
|
5939
|
+
"packages/execution/dist/tools/structured-read.js"() {
|
|
5940
|
+
"use strict";
|
|
5941
|
+
StructuredReadTool = class {
|
|
5942
|
+
name = "read_structured_file";
|
|
5943
|
+
description = "Read and parse a structured file (CSV, TSV, JSON, Markdown tables). Returns the file content as structured data the agent can work with. For binary formats (XLSX, PDF), detects the format and suggests tools.";
|
|
5944
|
+
parameters = {
|
|
5945
|
+
type: "object",
|
|
5946
|
+
properties: {
|
|
5947
|
+
path: {
|
|
5948
|
+
type: "string",
|
|
5949
|
+
description: "File path to read"
|
|
5950
|
+
},
|
|
5951
|
+
format: {
|
|
5952
|
+
type: "string",
|
|
5953
|
+
enum: ["csv", "tsv", "json", "markdown", "auto"],
|
|
5954
|
+
description: "File format (auto-detected from extension if omitted)"
|
|
5955
|
+
},
|
|
5956
|
+
max_rows: {
|
|
5957
|
+
type: "number",
|
|
5958
|
+
description: "Maximum rows to return (default: 100)"
|
|
5959
|
+
}
|
|
5960
|
+
},
|
|
5961
|
+
required: ["path"]
|
|
5962
|
+
};
|
|
5963
|
+
workingDir;
|
|
5964
|
+
constructor(workingDir) {
|
|
5965
|
+
this.workingDir = workingDir;
|
|
5966
|
+
}
|
|
5967
|
+
async execute(args) {
|
|
5968
|
+
const filePath = args["path"];
|
|
5969
|
+
const maxRows = args["max_rows"] ?? 100;
|
|
5970
|
+
const start = performance.now();
|
|
5971
|
+
if (!filePath) {
|
|
5972
|
+
return { success: false, output: "", error: "path is required", durationMs: 0 };
|
|
5973
|
+
}
|
|
5974
|
+
const fullPath = resolve14(this.workingDir, filePath);
|
|
5975
|
+
try {
|
|
5976
|
+
const fileStat = await stat2(fullPath);
|
|
5977
|
+
if (!fileStat.isFile()) {
|
|
5978
|
+
return {
|
|
5979
|
+
success: false,
|
|
5980
|
+
output: "",
|
|
5981
|
+
error: `Not a file: ${filePath}`,
|
|
5982
|
+
durationMs: performance.now() - start
|
|
5983
|
+
};
|
|
5984
|
+
}
|
|
5985
|
+
if (fileStat.size > 10 * 1024 * 1024) {
|
|
5986
|
+
return {
|
|
5987
|
+
success: false,
|
|
5988
|
+
output: "",
|
|
5989
|
+
error: `File too large (${(fileStat.size / 1024 / 1024).toFixed(1)}MB). Maximum is 10MB.`,
|
|
5990
|
+
durationMs: performance.now() - start
|
|
5991
|
+
};
|
|
5992
|
+
}
|
|
5993
|
+
const ext = extname5(filePath).toLowerCase();
|
|
5994
|
+
let format = args["format"] ?? "auto";
|
|
5995
|
+
if (format === "auto") {
|
|
5996
|
+
switch (ext) {
|
|
5997
|
+
case ".csv":
|
|
5998
|
+
format = "csv";
|
|
5999
|
+
break;
|
|
6000
|
+
case ".tsv":
|
|
6001
|
+
format = "tsv";
|
|
6002
|
+
break;
|
|
6003
|
+
case ".json":
|
|
6004
|
+
format = "json";
|
|
6005
|
+
break;
|
|
6006
|
+
case ".md":
|
|
6007
|
+
case ".markdown":
|
|
6008
|
+
format = "markdown";
|
|
6009
|
+
break;
|
|
6010
|
+
case ".xlsx":
|
|
6011
|
+
case ".xls":
|
|
6012
|
+
format = "xlsx";
|
|
6013
|
+
break;
|
|
6014
|
+
case ".pdf":
|
|
6015
|
+
format = "pdf";
|
|
6016
|
+
break;
|
|
6017
|
+
case ".docx":
|
|
6018
|
+
case ".doc":
|
|
6019
|
+
format = "docx";
|
|
6020
|
+
break;
|
|
6021
|
+
default:
|
|
6022
|
+
format = "auto";
|
|
6023
|
+
break;
|
|
6024
|
+
}
|
|
6025
|
+
}
|
|
6026
|
+
if (format === "xlsx" || format === "pdf" || format === "docx" || format === "auto") {
|
|
6027
|
+
const buffer = await readFile7(fullPath);
|
|
6028
|
+
const detected = detectBinaryFormat(buffer);
|
|
6029
|
+
if (detected === "xlsx") {
|
|
6030
|
+
return {
|
|
6031
|
+
success: true,
|
|
6032
|
+
output: `Detected Excel file (.xlsx), ${(fileStat.size / 1024).toFixed(1)}KB.
|
|
6033
|
+
To parse this file, use the shell tool to run:
|
|
6034
|
+
npx xlsx-cli "${filePath}" --json
|
|
6035
|
+
Or install exceljs for programmatic access.`,
|
|
6036
|
+
durationMs: performance.now() - start
|
|
6037
|
+
};
|
|
6038
|
+
}
|
|
6039
|
+
if (detected === "pdf") {
|
|
6040
|
+
return {
|
|
6041
|
+
success: true,
|
|
6042
|
+
output: `Detected PDF file, ${(fileStat.size / 1024).toFixed(1)}KB.
|
|
6043
|
+
To extract text, use the shell tool to run:
|
|
6044
|
+
pdftotext "${filePath}" -
|
|
6045
|
+
Or install pdf-parse for programmatic access.`,
|
|
6046
|
+
durationMs: performance.now() - start
|
|
6047
|
+
};
|
|
6048
|
+
}
|
|
6049
|
+
if (detected === "docx") {
|
|
6050
|
+
return {
|
|
6051
|
+
success: true,
|
|
6052
|
+
output: `Detected Word document (.docx), ${(fileStat.size / 1024).toFixed(1)}KB.
|
|
6053
|
+
To extract text, use the shell tool to run:
|
|
6054
|
+
pandoc "${filePath}" -t plain
|
|
6055
|
+
Or install mammoth for programmatic access.`,
|
|
6056
|
+
durationMs: performance.now() - start
|
|
6057
|
+
};
|
|
6058
|
+
}
|
|
6059
|
+
if (format === "auto") {
|
|
6060
|
+
const text2 = buffer.toString("utf-8");
|
|
6061
|
+
if (text2.trimStart().startsWith("{") || text2.trimStart().startsWith("[")) {
|
|
6062
|
+
format = "json";
|
|
6063
|
+
} else if (text2.includes(" ") && !text2.includes(",")) {
|
|
6064
|
+
format = "tsv";
|
|
6065
|
+
} else if (text2.includes("|") && /^\|[\s-:|]+\|$/m.test(text2)) {
|
|
6066
|
+
format = "markdown";
|
|
6067
|
+
} else {
|
|
6068
|
+
format = "csv";
|
|
6069
|
+
}
|
|
6070
|
+
}
|
|
6071
|
+
}
|
|
6072
|
+
const text = await readFile7(fullPath, "utf-8");
|
|
6073
|
+
switch (format) {
|
|
6074
|
+
case "csv": {
|
|
6075
|
+
const rows = parseCSV(text, ",");
|
|
6076
|
+
const limited = rows.slice(0, maxRows);
|
|
6077
|
+
const truncated = rows.length > maxRows ? `
|
|
6078
|
+
[showing ${maxRows} of ${rows.length} rows]` : "";
|
|
6079
|
+
return {
|
|
6080
|
+
success: true,
|
|
6081
|
+
output: `CSV: ${rows.length} rows, ${Object.keys(rows[0] ?? {}).length} columns
|
|
6082
|
+
${JSON.stringify(limited, null, 2)}${truncated}`,
|
|
6083
|
+
durationMs: performance.now() - start
|
|
6084
|
+
};
|
|
6085
|
+
}
|
|
6086
|
+
case "tsv": {
|
|
6087
|
+
const rows = parseCSV(text, " ");
|
|
6088
|
+
const limited = rows.slice(0, maxRows);
|
|
6089
|
+
const truncated = rows.length > maxRows ? `
|
|
6090
|
+
[showing ${maxRows} of ${rows.length} rows]` : "";
|
|
6091
|
+
return {
|
|
6092
|
+
success: true,
|
|
6093
|
+
output: `TSV: ${rows.length} rows, ${Object.keys(rows[0] ?? {}).length} columns
|
|
6094
|
+
${JSON.stringify(limited, null, 2)}${truncated}`,
|
|
6095
|
+
durationMs: performance.now() - start
|
|
6096
|
+
};
|
|
6097
|
+
}
|
|
6098
|
+
case "json": {
|
|
6099
|
+
const parsed = JSON.parse(text);
|
|
6100
|
+
const isArray = Array.isArray(parsed);
|
|
6101
|
+
const count = isArray ? parsed.length : Object.keys(parsed).length;
|
|
6102
|
+
let display;
|
|
6103
|
+
if (isArray && parsed.length > maxRows) {
|
|
6104
|
+
display = parsed.slice(0, maxRows);
|
|
6105
|
+
return {
|
|
6106
|
+
success: true,
|
|
6107
|
+
output: `JSON array: ${parsed.length} items
|
|
6108
|
+
${JSON.stringify(display, null, 2)}
|
|
6109
|
+
[showing ${maxRows} of ${parsed.length} items]`,
|
|
6110
|
+
durationMs: performance.now() - start
|
|
6111
|
+
};
|
|
6112
|
+
}
|
|
6113
|
+
return {
|
|
6114
|
+
success: true,
|
|
6115
|
+
output: `JSON ${isArray ? "array" : "object"}: ${count} ${isArray ? "items" : "keys"}
|
|
6116
|
+
${JSON.stringify(parsed, null, 2)}`,
|
|
6117
|
+
durationMs: performance.now() - start
|
|
6118
|
+
};
|
|
6119
|
+
}
|
|
6120
|
+
case "markdown": {
|
|
6121
|
+
const tables = parseMarkdownTables(text);
|
|
6122
|
+
if (tables.length === 0) {
|
|
6123
|
+
return {
|
|
6124
|
+
success: true,
|
|
6125
|
+
output: `Markdown file (no tables found). Content:
|
|
6126
|
+
${text.slice(0, 5e3)}${text.length > 5e3 ? "\n[truncated]" : ""}`,
|
|
6127
|
+
durationMs: performance.now() - start
|
|
6128
|
+
};
|
|
6129
|
+
}
|
|
6130
|
+
const parts = [];
|
|
6131
|
+
for (const table of tables) {
|
|
6132
|
+
const heading = table.heading ? `Table: ${table.heading}` : "Table";
|
|
6133
|
+
const limited = table.rows.slice(0, maxRows);
|
|
6134
|
+
parts.push(`${heading} (${table.rows.length} rows)
|
|
6135
|
+
${JSON.stringify(limited, null, 2)}`);
|
|
6136
|
+
}
|
|
6137
|
+
return {
|
|
6138
|
+
success: true,
|
|
6139
|
+
output: `Markdown: ${tables.length} table(s)
|
|
6140
|
+
|
|
6141
|
+
${parts.join("\n\n")}`,
|
|
6142
|
+
durationMs: performance.now() - start
|
|
6143
|
+
};
|
|
6144
|
+
}
|
|
6145
|
+
default:
|
|
6146
|
+
return {
|
|
6147
|
+
success: false,
|
|
6148
|
+
output: "",
|
|
6149
|
+
error: `Unsupported format: ${format}`,
|
|
6150
|
+
durationMs: performance.now() - start
|
|
6151
|
+
};
|
|
6152
|
+
}
|
|
6153
|
+
} catch (error) {
|
|
6154
|
+
return {
|
|
6155
|
+
success: false,
|
|
6156
|
+
output: "",
|
|
6157
|
+
error: error instanceof Error ? error.message : String(error),
|
|
5244
6158
|
durationMs: performance.now() - start
|
|
5245
6159
|
};
|
|
5246
6160
|
}
|
|
@@ -5353,6 +6267,9 @@ var init_dist2 = __esm({
|
|
|
5353
6267
|
init_tool_creator();
|
|
5354
6268
|
init_skill_tools();
|
|
5355
6269
|
init_transcribe_tool();
|
|
6270
|
+
init_structured_file();
|
|
6271
|
+
init_code_sandbox();
|
|
6272
|
+
init_structured_read();
|
|
5356
6273
|
init_shellRunner();
|
|
5357
6274
|
init_gitWorktree();
|
|
5358
6275
|
init_patchApplier();
|
|
@@ -6467,8 +7384,8 @@ var init_code_retriever = __esm({
|
|
|
6467
7384
|
});
|
|
6468
7385
|
}
|
|
6469
7386
|
async getFileContent(filePath, startLine, endLine) {
|
|
6470
|
-
const { readFile:
|
|
6471
|
-
const content = await
|
|
7387
|
+
const { readFile: readFile11 } = await import("node:fs/promises");
|
|
7388
|
+
const content = await readFile11(filePath, "utf-8");
|
|
6472
7389
|
if (startLine === void 0)
|
|
6473
7390
|
return content;
|
|
6474
7391
|
const lines = content.split("\n");
|
|
@@ -6483,8 +7400,8 @@ var init_code_retriever = __esm({
|
|
|
6483
7400
|
// packages/retrieval/dist/lexicalSearch.js
|
|
6484
7401
|
import { execFile as execFile4 } from "node:child_process";
|
|
6485
7402
|
import { promisify as promisify4 } from "node:util";
|
|
6486
|
-
import { readFile as
|
|
6487
|
-
import { join as
|
|
7403
|
+
import { readFile as readFile8, readdir as readdir2, stat as stat3 } from "node:fs/promises";
|
|
7404
|
+
import { join as join15, extname as extname6 } from "node:path";
|
|
6488
7405
|
async function searchByPath(pathPattern, options) {
|
|
6489
7406
|
const allFiles = await collectFiles(options.rootDir, options.includeGlobs ?? DEFAULT_INCLUDE_GLOBS, options.excludeGlobs ?? DEFAULT_EXCLUDE_GLOBS);
|
|
6490
7407
|
const pattern = options.caseInsensitive ? pathPattern.toLowerCase() : pathPattern;
|
|
@@ -6589,7 +7506,7 @@ async function searchWithNodeFallback(pattern, kind, options) {
|
|
|
6589
7506
|
if (results.length >= maxMatches)
|
|
6590
7507
|
break;
|
|
6591
7508
|
try {
|
|
6592
|
-
const content = await
|
|
7509
|
+
const content = await readFile8(filePath, "utf-8");
|
|
6593
7510
|
const contentLines = content.split("\n");
|
|
6594
7511
|
for (let i = 0; i < contentLines.length; i++) {
|
|
6595
7512
|
if (results.length >= maxMatches)
|
|
@@ -6617,7 +7534,7 @@ async function collectFiles(rootDir, includeGlobs, excludeGlobs) {
|
|
|
6617
7534
|
async function walkForFiles(rootDir, dir, excludeGlobs, results) {
|
|
6618
7535
|
let entries;
|
|
6619
7536
|
try {
|
|
6620
|
-
entries = await
|
|
7537
|
+
entries = await readdir2(dir, { withFileTypes: true, encoding: "utf-8" });
|
|
6621
7538
|
} catch {
|
|
6622
7539
|
return;
|
|
6623
7540
|
}
|
|
@@ -6626,16 +7543,16 @@ async function walkForFiles(rootDir, dir, excludeGlobs, results) {
|
|
|
6626
7543
|
continue;
|
|
6627
7544
|
if (excludeGlobs.some((g) => entry.name === g || matchesGlob(entry.name, g)))
|
|
6628
7545
|
continue;
|
|
6629
|
-
const absPath =
|
|
7546
|
+
const absPath = join15(dir, entry.name);
|
|
6630
7547
|
if (entry.isDirectory()) {
|
|
6631
7548
|
await walkForFiles(rootDir, absPath, excludeGlobs, results);
|
|
6632
7549
|
} else if (entry.isFile()) {
|
|
6633
|
-
const ext =
|
|
7550
|
+
const ext = extname6(entry.name);
|
|
6634
7551
|
if (!ALL_CODE_EXTS.has(ext))
|
|
6635
7552
|
continue;
|
|
6636
7553
|
const relativePath = absPath.startsWith(rootDir) ? absPath.slice(rootDir.length).replace(/^\//, "") : absPath;
|
|
6637
7554
|
try {
|
|
6638
|
-
const s = await
|
|
7555
|
+
const s = await stat3(absPath);
|
|
6639
7556
|
if (s.size > 2e6)
|
|
6640
7557
|
continue;
|
|
6641
7558
|
} catch {
|
|
@@ -6800,8 +7717,8 @@ var init_graphExpand = __esm({
|
|
|
6800
7717
|
});
|
|
6801
7718
|
|
|
6802
7719
|
// packages/retrieval/dist/snippetPacker.js
|
|
6803
|
-
import { readFile as
|
|
6804
|
-
import { join as
|
|
7720
|
+
import { readFile as readFile9 } from "node:fs/promises";
|
|
7721
|
+
import { join as join16 } from "node:path";
|
|
6805
7722
|
async function packSnippets(requests, opts = {}) {
|
|
6806
7723
|
const maxTokens = opts.maxTokens ?? DEFAULT_MAX_TOKENS;
|
|
6807
7724
|
const contextLines = opts.contextLines ?? DEFAULT_CONTEXT_LINES;
|
|
@@ -6827,10 +7744,10 @@ async function packSnippets(requests, opts = {}) {
|
|
|
6827
7744
|
return { packed, dropped, totalTokens };
|
|
6828
7745
|
}
|
|
6829
7746
|
async function extractSnippet(req, repoRoot, contextLines = DEFAULT_CONTEXT_LINES) {
|
|
6830
|
-
const absPath = req.filePath.startsWith("/") ? req.filePath :
|
|
7747
|
+
const absPath = req.filePath.startsWith("/") ? req.filePath : join16(repoRoot, req.filePath);
|
|
6831
7748
|
let content;
|
|
6832
7749
|
try {
|
|
6833
|
-
content = await
|
|
7750
|
+
content = await readFile9(absPath, "utf-8");
|
|
6834
7751
|
} catch {
|
|
6835
7752
|
return null;
|
|
6836
7753
|
}
|
|
@@ -8697,14 +9614,14 @@ ${result.output}`;
|
|
|
8697
9614
|
waitForSudoPassword(timeoutMs = 12e4) {
|
|
8698
9615
|
if (this._sudoPassword)
|
|
8699
9616
|
return Promise.resolve(this._sudoPassword);
|
|
8700
|
-
return new Promise((
|
|
9617
|
+
return new Promise((resolve18) => {
|
|
8701
9618
|
const timer = setTimeout(() => {
|
|
8702
9619
|
this._sudoResolve = null;
|
|
8703
|
-
|
|
9620
|
+
resolve18(null);
|
|
8704
9621
|
}, timeoutMs);
|
|
8705
9622
|
this._sudoResolve = (pw) => {
|
|
8706
9623
|
clearTimeout(timer);
|
|
8707
|
-
|
|
9624
|
+
resolve18(pw);
|
|
8708
9625
|
};
|
|
8709
9626
|
});
|
|
8710
9627
|
}
|
|
@@ -9332,6 +10249,489 @@ ${newerSummary}` : newerSummary;
|
|
|
9332
10249
|
}
|
|
9333
10250
|
});
|
|
9334
10251
|
|
|
10252
|
+
// packages/orchestrator/dist/costTracker.js
|
|
10253
|
+
var DEFAULT_PRICING, CostTracker;
|
|
10254
|
+
var init_costTracker = __esm({
|
|
10255
|
+
"packages/orchestrator/dist/costTracker.js"() {
|
|
10256
|
+
"use strict";
|
|
10257
|
+
DEFAULT_PRICING = [
|
|
10258
|
+
// Cloud providers — typical pricing tiers
|
|
10259
|
+
{ providerId: "openai", label: "OpenAI", inputPer1M: 2.5, outputPer1M: 10 },
|
|
10260
|
+
{ providerId: "together", label: "Together AI", inputPer1M: 0.8, outputPer1M: 0.8 },
|
|
10261
|
+
{ providerId: "groq", label: "Groq", inputPer1M: 0.05, outputPer1M: 0.1 },
|
|
10262
|
+
{ providerId: "openrouter", label: "OpenRouter", inputPer1M: 1, outputPer1M: 2 },
|
|
10263
|
+
{ providerId: "fireworks", label: "Fireworks AI", inputPer1M: 0.2, outputPer1M: 0.8 },
|
|
10264
|
+
{ providerId: "deepinfra", label: "DeepInfra", inputPer1M: 0.1, outputPer1M: 0.4 },
|
|
10265
|
+
{ providerId: "mistral", label: "Mistral AI", inputPer1M: 0.5, outputPer1M: 1.5 },
|
|
10266
|
+
{ providerId: "chutes", label: "Chutes AI", inputPer1M: 0.2, outputPer1M: 0.8 },
|
|
10267
|
+
{ providerId: "cerebras", label: "Cerebras", inputPer1M: 0.1, outputPer1M: 0.1 },
|
|
10268
|
+
{ providerId: "sambanova", label: "SambaNova", inputPer1M: 0.1, outputPer1M: 0.4 },
|
|
10269
|
+
{ providerId: "nvidia", label: "NVIDIA NIM", inputPer1M: 0.3, outputPer1M: 1.2 },
|
|
10270
|
+
{ providerId: "hyperbolic", label: "Hyperbolic", inputPer1M: 0.1, outputPer1M: 0.3 },
|
|
10271
|
+
// Local providers — free (no token cost)
|
|
10272
|
+
{ providerId: "ollama", label: "Ollama (local)", inputPer1M: 0, outputPer1M: 0 },
|
|
10273
|
+
{ providerId: "lmstudio", label: "LM Studio (local)", inputPer1M: 0, outputPer1M: 0 },
|
|
10274
|
+
{ providerId: "vllm", label: "vLLM (local)", inputPer1M: 0, outputPer1M: 0 }
|
|
10275
|
+
];
|
|
10276
|
+
CostTracker = class {
|
|
10277
|
+
pricing;
|
|
10278
|
+
tasks = [];
|
|
10279
|
+
sessionStartedAt;
|
|
10280
|
+
// Running totals
|
|
10281
|
+
_totalInputTokens = 0;
|
|
10282
|
+
_totalOutputTokens = 0;
|
|
10283
|
+
_totalEstimatedCost = 0;
|
|
10284
|
+
// Current task accumulator
|
|
10285
|
+
_currentTask = null;
|
|
10286
|
+
_currentInputTokens = 0;
|
|
10287
|
+
_currentOutputTokens = 0;
|
|
10288
|
+
_currentStartedAt = "";
|
|
10289
|
+
_currentStartMs = 0;
|
|
10290
|
+
constructor(providerId, customPricing) {
|
|
10291
|
+
this.sessionStartedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
10292
|
+
this.pricing = customPricing ?? DEFAULT_PRICING.find((p) => p.providerId === providerId) ?? { providerId: providerId ?? "unknown", label: "Unknown", inputPer1M: 0, outputPer1M: 0 };
|
|
10293
|
+
}
|
|
10294
|
+
/** Get the current provider pricing */
|
|
10295
|
+
get provider() {
|
|
10296
|
+
return this.pricing;
|
|
10297
|
+
}
|
|
10298
|
+
/** Update provider (e.g., when user switches endpoint) */
|
|
10299
|
+
setProvider(providerId, customPricing) {
|
|
10300
|
+
this.pricing = customPricing ?? DEFAULT_PRICING.find((p) => p.providerId === providerId) ?? { providerId, label: "Unknown", inputPer1M: 0, outputPer1M: 0 };
|
|
10301
|
+
}
|
|
10302
|
+
/** Start tracking a new task */
|
|
10303
|
+
startTask(taskDescription) {
|
|
10304
|
+
if (this._currentTask) {
|
|
10305
|
+
this.endTask();
|
|
10306
|
+
}
|
|
10307
|
+
this._currentTask = taskDescription;
|
|
10308
|
+
this._currentInputTokens = 0;
|
|
10309
|
+
this._currentOutputTokens = 0;
|
|
10310
|
+
this._currentStartedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
10311
|
+
this._currentStartMs = Date.now();
|
|
10312
|
+
}
|
|
10313
|
+
/** Record token usage from an API response */
|
|
10314
|
+
trackTokens(inputTokens, outputTokens) {
|
|
10315
|
+
this._currentInputTokens += inputTokens;
|
|
10316
|
+
this._currentOutputTokens += outputTokens;
|
|
10317
|
+
this._totalInputTokens += inputTokens;
|
|
10318
|
+
this._totalOutputTokens += outputTokens;
|
|
10319
|
+
const cost = this.calculateCost(inputTokens, outputTokens);
|
|
10320
|
+
this._totalEstimatedCost += cost;
|
|
10321
|
+
}
|
|
10322
|
+
/** End current task and record it */
|
|
10323
|
+
endTask() {
|
|
10324
|
+
if (!this._currentTask)
|
|
10325
|
+
return null;
|
|
10326
|
+
const cost = this.calculateCost(this._currentInputTokens, this._currentOutputTokens);
|
|
10327
|
+
const record = {
|
|
10328
|
+
task: this._currentTask,
|
|
10329
|
+
inputTokens: this._currentInputTokens,
|
|
10330
|
+
outputTokens: this._currentOutputTokens,
|
|
10331
|
+
estimatedCost: cost,
|
|
10332
|
+
durationMs: Date.now() - this._currentStartMs,
|
|
10333
|
+
startedAt: this._currentStartedAt
|
|
10334
|
+
};
|
|
10335
|
+
this.tasks.push(record);
|
|
10336
|
+
this._currentTask = null;
|
|
10337
|
+
return record;
|
|
10338
|
+
}
|
|
10339
|
+
/** Calculate cost for a given token usage */
|
|
10340
|
+
calculateCost(inputTokens, outputTokens) {
|
|
10341
|
+
return inputTokens / 1e6 * this.pricing.inputPer1M + outputTokens / 1e6 * this.pricing.outputPer1M;
|
|
10342
|
+
}
|
|
10343
|
+
/** Get current running cost estimate */
|
|
10344
|
+
get currentCost() {
|
|
10345
|
+
return this._totalEstimatedCost;
|
|
10346
|
+
}
|
|
10347
|
+
/** Get total input tokens */
|
|
10348
|
+
get totalInputTokens() {
|
|
10349
|
+
return this._totalInputTokens;
|
|
10350
|
+
}
|
|
10351
|
+
/** Get total output tokens */
|
|
10352
|
+
get totalOutputTokens() {
|
|
10353
|
+
return this._totalOutputTokens;
|
|
10354
|
+
}
|
|
10355
|
+
/** Whether this provider has non-zero pricing */
|
|
10356
|
+
get hasPricing() {
|
|
10357
|
+
return this.pricing.inputPer1M > 0 || this.pricing.outputPer1M > 0;
|
|
10358
|
+
}
|
|
10359
|
+
/** Format cost as a readable string */
|
|
10360
|
+
formatCost(cost) {
|
|
10361
|
+
const c3 = cost ?? this._totalEstimatedCost;
|
|
10362
|
+
if (c3 < 0.01)
|
|
10363
|
+
return `$${c3.toFixed(4)}`;
|
|
10364
|
+
if (c3 < 1)
|
|
10365
|
+
return `$${c3.toFixed(3)}`;
|
|
10366
|
+
return `$${c3.toFixed(2)}`;
|
|
10367
|
+
}
|
|
10368
|
+
/** Get full session summary */
|
|
10369
|
+
getSummary() {
|
|
10370
|
+
const pendingRecord = this._currentTask ? {
|
|
10371
|
+
task: this._currentTask,
|
|
10372
|
+
inputTokens: this._currentInputTokens,
|
|
10373
|
+
outputTokens: this._currentOutputTokens,
|
|
10374
|
+
estimatedCost: this.calculateCost(this._currentInputTokens, this._currentOutputTokens),
|
|
10375
|
+
durationMs: Date.now() - this._currentStartMs,
|
|
10376
|
+
startedAt: this._currentStartedAt
|
|
10377
|
+
} : null;
|
|
10378
|
+
const allTasks = pendingRecord ? [...this.tasks, pendingRecord] : [...this.tasks];
|
|
10379
|
+
return {
|
|
10380
|
+
totalInputTokens: this._totalInputTokens,
|
|
10381
|
+
totalOutputTokens: this._totalOutputTokens,
|
|
10382
|
+
totalEstimatedCost: this._totalEstimatedCost,
|
|
10383
|
+
taskCount: allTasks.length,
|
|
10384
|
+
tasks: allTasks,
|
|
10385
|
+
provider: this.pricing.label,
|
|
10386
|
+
sessionStartedAt: this.sessionStartedAt,
|
|
10387
|
+
sessionDurationMs: Date.now() - new Date(this.sessionStartedAt).getTime()
|
|
10388
|
+
};
|
|
10389
|
+
}
|
|
10390
|
+
/** Reset all tracking (e.g., new session) */
|
|
10391
|
+
reset() {
|
|
10392
|
+
this.tasks = [];
|
|
10393
|
+
this._totalInputTokens = 0;
|
|
10394
|
+
this._totalOutputTokens = 0;
|
|
10395
|
+
this._totalEstimatedCost = 0;
|
|
10396
|
+
this._currentTask = null;
|
|
10397
|
+
this.sessionStartedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
10398
|
+
}
|
|
10399
|
+
};
|
|
10400
|
+
}
|
|
10401
|
+
});
|
|
10402
|
+
|
|
10403
|
+
// packages/orchestrator/dist/workEvaluator.js
|
|
10404
|
+
function detectTaskType(taskDescription) {
|
|
10405
|
+
let bestType = "general";
|
|
10406
|
+
let bestScore = 0;
|
|
10407
|
+
for (const { type, patterns } of TASK_TYPE_PATTERNS) {
|
|
10408
|
+
let score = 0;
|
|
10409
|
+
for (const p of patterns) {
|
|
10410
|
+
if (p.test(taskDescription))
|
|
10411
|
+
score++;
|
|
10412
|
+
}
|
|
10413
|
+
if (score > bestScore) {
|
|
10414
|
+
bestScore = score;
|
|
10415
|
+
bestType = type;
|
|
10416
|
+
}
|
|
10417
|
+
}
|
|
10418
|
+
return bestType;
|
|
10419
|
+
}
|
|
10420
|
+
function getRubric(taskType) {
|
|
10421
|
+
return RUBRICS[taskType];
|
|
10422
|
+
}
|
|
10423
|
+
function buildEvaluationPrompt(task, summary, rubric) {
|
|
10424
|
+
const dimensionList = rubric.dimensions.map((d, i) => `${i + 1}. **${d.name}** (${Math.round(d.weight * 100)}%): ${d.criteria}`).join("\n");
|
|
10425
|
+
return `You are a quality evaluator. Score the following completed work on these dimensions.
|
|
10426
|
+
|
|
10427
|
+
## Task
|
|
10428
|
+
${task}
|
|
10429
|
+
|
|
10430
|
+
## Completed Work Summary
|
|
10431
|
+
${summary}
|
|
10432
|
+
|
|
10433
|
+
## Scoring Dimensions (${rubric.label} task)
|
|
10434
|
+
${dimensionList}
|
|
10435
|
+
|
|
10436
|
+
## Instructions
|
|
10437
|
+
For each dimension, provide:
|
|
10438
|
+
1. A score from 0-10 (0 = completely missing, 5 = adequate, 10 = exceptional)
|
|
10439
|
+
2. A brief explanation (1-2 sentences)
|
|
10440
|
+
|
|
10441
|
+
Then provide an overall summary of the work quality.
|
|
10442
|
+
|
|
10443
|
+
Respond in EXACTLY this JSON format:
|
|
10444
|
+
{
|
|
10445
|
+
"dimensions": [
|
|
10446
|
+
{"name": "${rubric.dimensions[0].name}", "score": <0-10>, "feedback": "<explanation>"},
|
|
10447
|
+
{"name": "${rubric.dimensions[1].name}", "score": <0-10>, "feedback": "<explanation>"},
|
|
10448
|
+
{"name": "${rubric.dimensions[2].name}", "score": <0-10>, "feedback": "<explanation>"},
|
|
10449
|
+
{"name": "${rubric.dimensions[3].name}", "score": <0-10>, "feedback": "<explanation>"}
|
|
10450
|
+
],
|
|
10451
|
+
"summary": "<2-3 sentence overall assessment>"
|
|
10452
|
+
}
|
|
10453
|
+
|
|
10454
|
+
Respond with ONLY the JSON object, no other text.`;
|
|
10455
|
+
}
|
|
10456
|
+
var RUBRICS, TASK_TYPE_PATTERNS, WorkEvaluator;
|
|
10457
|
+
var init_workEvaluator = __esm({
|
|
10458
|
+
"packages/orchestrator/dist/workEvaluator.js"() {
|
|
10459
|
+
"use strict";
|
|
10460
|
+
RUBRICS = {
|
|
10461
|
+
code: {
|
|
10462
|
+
type: "code",
|
|
10463
|
+
label: "Code",
|
|
10464
|
+
dimensions: [
|
|
10465
|
+
{ name: "Completeness", weight: 0.4, criteria: "All requested features implemented. Tests written if applicable. No missing edge cases." },
|
|
10466
|
+
{ name: "Correctness", weight: 0.3, criteria: "Code compiles/runs without errors. Tests pass. Logic is sound. No bugs or regressions." },
|
|
10467
|
+
{ name: "Quality", weight: 0.2, criteria: "Clean, readable code. Follows existing conventions. Appropriate naming. No unnecessary complexity." },
|
|
10468
|
+
{ name: "Domain", weight: 0.1, criteria: "Follows language/framework best practices. Proper error handling. Security considerations." }
|
|
10469
|
+
]
|
|
10470
|
+
},
|
|
10471
|
+
document: {
|
|
10472
|
+
type: "document",
|
|
10473
|
+
label: "Document",
|
|
10474
|
+
dimensions: [
|
|
10475
|
+
{ name: "Completeness", weight: 0.4, criteria: "All required sections present. Covers the full scope. No gaps in coverage." },
|
|
10476
|
+
{ name: "Correctness", weight: 0.3, criteria: "Factually accurate. No fabrications. Sources cited where applicable." },
|
|
10477
|
+
{ name: "Quality", weight: 0.2, criteria: "Well-structured. Clear writing. Professional formatting. Good flow." },
|
|
10478
|
+
{ name: "Domain", weight: 0.1, criteria: "Follows document type conventions. Appropriate tone and terminology." }
|
|
10479
|
+
]
|
|
10480
|
+
},
|
|
10481
|
+
analysis: {
|
|
10482
|
+
type: "analysis",
|
|
10483
|
+
label: "Analysis",
|
|
10484
|
+
dimensions: [
|
|
10485
|
+
{ name: "Completeness", weight: 0.4, criteria: "All data considered. Methodology explained. Conclusions cover key findings." },
|
|
10486
|
+
{ name: "Correctness", weight: 0.3, criteria: "Calculations accurate. Logic sound. No errors in reasoning or data interpretation." },
|
|
10487
|
+
{ name: "Quality", weight: 0.2, criteria: "Clear presentation. Data visualized where helpful. Executive summary included." },
|
|
10488
|
+
{ name: "Domain", weight: 0.1, criteria: "Follows analytical best practices. Appropriate statistical methods. Caveats noted." }
|
|
10489
|
+
]
|
|
10490
|
+
},
|
|
10491
|
+
plan: {
|
|
10492
|
+
type: "plan",
|
|
10493
|
+
label: "Plan",
|
|
10494
|
+
dimensions: [
|
|
10495
|
+
{ name: "Completeness", weight: 0.4, criteria: "All phases covered. Timeline realistic. Resources identified. Risks addressed." },
|
|
10496
|
+
{ name: "Correctness", weight: 0.3, criteria: "Dependencies accurate. Estimates reasonable. Constraints respected." },
|
|
10497
|
+
{ name: "Quality", weight: 0.2, criteria: "Actionable steps. Clear ownership. Measurable milestones. Well-organized." },
|
|
10498
|
+
{ name: "Domain", weight: 0.1, criteria: "Follows project management best practices. Appropriate methodology for scope." }
|
|
10499
|
+
]
|
|
10500
|
+
},
|
|
10501
|
+
general: {
|
|
10502
|
+
type: "general",
|
|
10503
|
+
label: "General",
|
|
10504
|
+
dimensions: [
|
|
10505
|
+
{ name: "Completeness", weight: 0.4, criteria: "All aspects of the request addressed. Nothing missing or incomplete." },
|
|
10506
|
+
{ name: "Correctness", weight: 0.3, criteria: "Accurate and factual. No errors or inconsistencies." },
|
|
10507
|
+
{ name: "Quality", weight: 0.2, criteria: "Well-structured. Clear communication. Professional output." },
|
|
10508
|
+
{ name: "Domain", weight: 0.1, criteria: "Appropriate for the context. Follows relevant conventions." }
|
|
10509
|
+
]
|
|
10510
|
+
}
|
|
10511
|
+
};
|
|
10512
|
+
TASK_TYPE_PATTERNS = [
|
|
10513
|
+
{
|
|
10514
|
+
type: "code",
|
|
10515
|
+
patterns: [
|
|
10516
|
+
/\b(fix|implement|refactor|debug|test|code|function|class|module|api|bug|feature|PR|commit|build|compile|lint)\b/i,
|
|
10517
|
+
/\.(ts|js|py|rs|go|java|cpp|rb|php|swift)\b/i
|
|
10518
|
+
]
|
|
10519
|
+
},
|
|
10520
|
+
{
|
|
10521
|
+
type: "document",
|
|
10522
|
+
patterns: [
|
|
10523
|
+
/\b(write|draft|document|report|article|blog|readme|guide|manual|specification|proposal|email|letter)\b/i,
|
|
10524
|
+
/\.(md|doc|docx|pdf|txt)\b/i
|
|
10525
|
+
]
|
|
10526
|
+
},
|
|
10527
|
+
{
|
|
10528
|
+
type: "analysis",
|
|
10529
|
+
patterns: [
|
|
10530
|
+
/\b(analyze|research|evaluate|compare|assess|review|audit|benchmark|metric|data|statistic|trend)\b/i
|
|
10531
|
+
]
|
|
10532
|
+
},
|
|
10533
|
+
{
|
|
10534
|
+
type: "plan",
|
|
10535
|
+
patterns: [
|
|
10536
|
+
/\b(plan|schedule|roadmap|strategy|design|architect|timeline|milestone|sprint|backlog|estimate)\b/i
|
|
10537
|
+
]
|
|
10538
|
+
}
|
|
10539
|
+
];
|
|
10540
|
+
WorkEvaluator = class {
|
|
10541
|
+
backend;
|
|
10542
|
+
constructor(backend) {
|
|
10543
|
+
this.backend = backend ?? null;
|
|
10544
|
+
}
|
|
10545
|
+
/** Set or update the evaluation backend */
|
|
10546
|
+
setBackend(backend) {
|
|
10547
|
+
this.backend = backend;
|
|
10548
|
+
}
|
|
10549
|
+
/** Evaluate completed work */
|
|
10550
|
+
async evaluate(task, summary, taskType) {
|
|
10551
|
+
if (!this.backend) {
|
|
10552
|
+
return {
|
|
10553
|
+
overallScore: 0,
|
|
10554
|
+
dimensions: [],
|
|
10555
|
+
feedback: "No evaluation backend configured.",
|
|
10556
|
+
taskType: taskType ?? "general",
|
|
10557
|
+
success: false,
|
|
10558
|
+
error: "No evaluation backend configured"
|
|
10559
|
+
};
|
|
10560
|
+
}
|
|
10561
|
+
const detectedType = taskType ?? detectTaskType(task);
|
|
10562
|
+
const rubric = getRubric(detectedType);
|
|
10563
|
+
const prompt = buildEvaluationPrompt(task, summary, rubric);
|
|
10564
|
+
try {
|
|
10565
|
+
const response = await this.backend.evaluate(prompt);
|
|
10566
|
+
return this.parseResponse(response, rubric, detectedType);
|
|
10567
|
+
} catch (err) {
|
|
10568
|
+
return {
|
|
10569
|
+
overallScore: 0,
|
|
10570
|
+
dimensions: [],
|
|
10571
|
+
feedback: `Evaluation failed: ${err instanceof Error ? err.message : String(err)}`,
|
|
10572
|
+
taskType: detectedType,
|
|
10573
|
+
success: false,
|
|
10574
|
+
error: err instanceof Error ? err.message : String(err)
|
|
10575
|
+
};
|
|
10576
|
+
}
|
|
10577
|
+
}
|
|
10578
|
+
/** Parse the LLM's JSON response into an EvaluationResult */
|
|
10579
|
+
parseResponse(response, rubric, taskType) {
|
|
10580
|
+
try {
|
|
10581
|
+
let jsonStr = response.trim();
|
|
10582
|
+
const jsonMatch = jsonStr.match(/```(?:json)?\s*([\s\S]*?)```/);
|
|
10583
|
+
if (jsonMatch) {
|
|
10584
|
+
jsonStr = jsonMatch[1].trim();
|
|
10585
|
+
}
|
|
10586
|
+
if (!jsonStr.startsWith("{")) {
|
|
10587
|
+
const braceMatch = jsonStr.match(/\{[\s\S]*\}/);
|
|
10588
|
+
if (braceMatch)
|
|
10589
|
+
jsonStr = braceMatch[0];
|
|
10590
|
+
}
|
|
10591
|
+
const parsed = JSON.parse(jsonStr);
|
|
10592
|
+
if (!parsed.dimensions || !Array.isArray(parsed.dimensions)) {
|
|
10593
|
+
throw new Error("Missing dimensions array in response");
|
|
10594
|
+
}
|
|
10595
|
+
const dimensions = rubric.dimensions.map((rd, i) => {
|
|
10596
|
+
const pd = parsed.dimensions[i];
|
|
10597
|
+
const score = Math.max(0, Math.min(10, pd?.score ?? 0));
|
|
10598
|
+
return {
|
|
10599
|
+
name: rd.name,
|
|
10600
|
+
weight: rd.weight,
|
|
10601
|
+
score,
|
|
10602
|
+
feedback: pd?.feedback ?? ""
|
|
10603
|
+
};
|
|
10604
|
+
});
|
|
10605
|
+
const overallScore = dimensions.reduce((sum, d) => sum + d.score / 10 * d.weight, 0);
|
|
10606
|
+
return {
|
|
10607
|
+
overallScore,
|
|
10608
|
+
dimensions,
|
|
10609
|
+
feedback: parsed.summary ?? "",
|
|
10610
|
+
taskType,
|
|
10611
|
+
success: true
|
|
10612
|
+
};
|
|
10613
|
+
} catch (err) {
|
|
10614
|
+
return {
|
|
10615
|
+
overallScore: 0,
|
|
10616
|
+
dimensions: [],
|
|
10617
|
+
feedback: `Failed to parse evaluation response: ${err instanceof Error ? err.message : String(err)}`,
|
|
10618
|
+
taskType,
|
|
10619
|
+
success: false,
|
|
10620
|
+
error: `Parse error: ${err instanceof Error ? err.message : String(err)}`
|
|
10621
|
+
};
|
|
10622
|
+
}
|
|
10623
|
+
}
|
|
10624
|
+
};
|
|
10625
|
+
}
|
|
10626
|
+
});
|
|
10627
|
+
|
|
10628
|
+
// packages/orchestrator/dist/sessionMetrics.js
|
|
10629
|
+
var SessionMetrics;
|
|
10630
|
+
var init_sessionMetrics = __esm({
|
|
10631
|
+
"packages/orchestrator/dist/sessionMetrics.js"() {
|
|
10632
|
+
"use strict";
|
|
10633
|
+
SessionMetrics = class {
|
|
10634
|
+
sessionStart;
|
|
10635
|
+
turns = 0;
|
|
10636
|
+
toolCalls = 0;
|
|
10637
|
+
toolCallsByName = {};
|
|
10638
|
+
inputTokens = 0;
|
|
10639
|
+
outputTokens = 0;
|
|
10640
|
+
filesModified = /* @__PURE__ */ new Set();
|
|
10641
|
+
tasks = [];
|
|
10642
|
+
currentTask = null;
|
|
10643
|
+
constructor() {
|
|
10644
|
+
this.sessionStart = Date.now();
|
|
10645
|
+
}
|
|
10646
|
+
/** Record a new turn (assistant response). */
|
|
10647
|
+
recordTurn() {
|
|
10648
|
+
this.turns++;
|
|
10649
|
+
}
|
|
10650
|
+
/** Record a tool call. */
|
|
10651
|
+
recordToolCall(toolName) {
|
|
10652
|
+
this.toolCalls++;
|
|
10653
|
+
this.toolCallsByName[toolName] = (this.toolCallsByName[toolName] ?? 0) + 1;
|
|
10654
|
+
if (this.currentTask) {
|
|
10655
|
+
this.currentTask.toolCalls++;
|
|
10656
|
+
}
|
|
10657
|
+
}
|
|
10658
|
+
/** Record token usage. */
|
|
10659
|
+
recordTokenUsage(inputTokens, outputTokens) {
|
|
10660
|
+
this.inputTokens += inputTokens;
|
|
10661
|
+
this.outputTokens += outputTokens;
|
|
10662
|
+
}
|
|
10663
|
+
/** Record a file modification. */
|
|
10664
|
+
recordFileModified(filePath) {
|
|
10665
|
+
this.filesModified.add(filePath);
|
|
10666
|
+
}
|
|
10667
|
+
/** Start tracking a new task. */
|
|
10668
|
+
startTask(description) {
|
|
10669
|
+
this.currentTask = {
|
|
10670
|
+
description,
|
|
10671
|
+
startTime: Date.now(),
|
|
10672
|
+
toolCalls: 0
|
|
10673
|
+
};
|
|
10674
|
+
}
|
|
10675
|
+
/** End the current task with optional evaluation score. */
|
|
10676
|
+
endTask(evaluationScore) {
|
|
10677
|
+
if (this.currentTask) {
|
|
10678
|
+
this.currentTask.endTime = Date.now();
|
|
10679
|
+
this.currentTask.durationMs = this.currentTask.endTime - this.currentTask.startTime;
|
|
10680
|
+
if (evaluationScore !== void 0) {
|
|
10681
|
+
this.currentTask.evaluationScore = evaluationScore;
|
|
10682
|
+
}
|
|
10683
|
+
this.tasks.push(this.currentTask);
|
|
10684
|
+
this.currentTask = null;
|
|
10685
|
+
}
|
|
10686
|
+
}
|
|
10687
|
+
/** Get current session summary. */
|
|
10688
|
+
getSummary() {
|
|
10689
|
+
const now = Date.now();
|
|
10690
|
+
const evalScores = this.tasks.filter((t) => t.evaluationScore !== void 0).map((t) => t.evaluationScore);
|
|
10691
|
+
return {
|
|
10692
|
+
sessionStartTime: this.sessionStart,
|
|
10693
|
+
sessionDurationMs: now - this.sessionStart,
|
|
10694
|
+
totalTurns: this.turns,
|
|
10695
|
+
totalToolCalls: this.toolCalls,
|
|
10696
|
+
toolCallsByName: { ...this.toolCallsByName },
|
|
10697
|
+
totalInputTokens: this.inputTokens,
|
|
10698
|
+
totalOutputTokens: this.outputTokens,
|
|
10699
|
+
filesModified: [...this.filesModified],
|
|
10700
|
+
tasksCompleted: this.tasks.length,
|
|
10701
|
+
tasks: [...this.tasks],
|
|
10702
|
+
averageEvalScore: evalScores.length > 0 ? evalScores.reduce((a, b) => a + b, 0) / evalScores.length : void 0
|
|
10703
|
+
};
|
|
10704
|
+
}
|
|
10705
|
+
/** Get the most-used tools (sorted by count). */
|
|
10706
|
+
getTopTools(limit = 5) {
|
|
10707
|
+
return Object.entries(this.toolCallsByName).sort((a, b) => b[1] - a[1]).slice(0, limit).map(([name, count]) => ({ name, count }));
|
|
10708
|
+
}
|
|
10709
|
+
/** Format duration in human-readable form. */
|
|
10710
|
+
static formatDuration(ms) {
|
|
10711
|
+
if (ms < 1e3)
|
|
10712
|
+
return `${ms}ms`;
|
|
10713
|
+
const seconds = Math.floor(ms / 1e3);
|
|
10714
|
+
if (seconds < 60)
|
|
10715
|
+
return `${seconds}s`;
|
|
10716
|
+
const minutes = Math.floor(seconds / 60);
|
|
10717
|
+
const remainingSecs = seconds % 60;
|
|
10718
|
+
if (minutes < 60)
|
|
10719
|
+
return `${minutes}m ${remainingSecs}s`;
|
|
10720
|
+
const hours = Math.floor(minutes / 60);
|
|
10721
|
+
const remainingMins = minutes % 60;
|
|
10722
|
+
return `${hours}h ${remainingMins}m`;
|
|
10723
|
+
}
|
|
10724
|
+
};
|
|
10725
|
+
}
|
|
10726
|
+
});
|
|
10727
|
+
|
|
10728
|
+
// packages/orchestrator/dist/taskLearning.js
|
|
10729
|
+
var init_taskLearning = __esm({
|
|
10730
|
+
"packages/orchestrator/dist/taskLearning.js"() {
|
|
10731
|
+
"use strict";
|
|
10732
|
+
}
|
|
10733
|
+
});
|
|
10734
|
+
|
|
9335
10735
|
// packages/orchestrator/dist/index.js
|
|
9336
10736
|
var init_dist5 = __esm({
|
|
9337
10737
|
"packages/orchestrator/dist/index.js"() {
|
|
@@ -9347,13 +10747,17 @@ var init_dist5 = __esm({
|
|
|
9347
10747
|
init_mergeRunner();
|
|
9348
10748
|
init_retryController();
|
|
9349
10749
|
init_agenticRunner();
|
|
10750
|
+
init_costTracker();
|
|
10751
|
+
init_workEvaluator();
|
|
10752
|
+
init_sessionMetrics();
|
|
10753
|
+
init_taskLearning();
|
|
9350
10754
|
}
|
|
9351
10755
|
});
|
|
9352
10756
|
|
|
9353
10757
|
// packages/cli/dist/tui/listen.js
|
|
9354
|
-
import { spawn as
|
|
10758
|
+
import { spawn as spawn6, execSync as execSync9 } from "node:child_process";
|
|
9355
10759
|
import { existsSync as existsSync11, mkdirSync as mkdirSync5, writeFileSync as writeFileSync5 } from "node:fs";
|
|
9356
|
-
import { join as
|
|
10760
|
+
import { join as join17 } from "node:path";
|
|
9357
10761
|
import { homedir as homedir6 } from "node:os";
|
|
9358
10762
|
import { EventEmitter } from "node:events";
|
|
9359
10763
|
function isAudioPath(path) {
|
|
@@ -9444,16 +10848,16 @@ function ensureTranscribeCliBackground() {
|
|
|
9444
10848
|
timeout: 5e3,
|
|
9445
10849
|
stdio: ["pipe", "pipe", "pipe"]
|
|
9446
10850
|
}).trim();
|
|
9447
|
-
if (existsSync11(
|
|
10851
|
+
if (existsSync11(join17(globalRoot, "transcribe-cli", "dist", "index.js"))) {
|
|
9448
10852
|
return true;
|
|
9449
10853
|
}
|
|
9450
10854
|
} catch {
|
|
9451
10855
|
}
|
|
9452
10856
|
try {
|
|
9453
10857
|
const { exec } = await import("node:child_process");
|
|
9454
|
-
return new Promise((
|
|
10858
|
+
return new Promise((resolve18) => {
|
|
9455
10859
|
exec("npm i -g transcribe-cli", { timeout: 18e4 }, (err) => {
|
|
9456
|
-
|
|
10860
|
+
resolve18(!err);
|
|
9457
10861
|
});
|
|
9458
10862
|
});
|
|
9459
10863
|
} catch {
|
|
@@ -9568,24 +10972,24 @@ var init_listen = __esm({
|
|
|
9568
10972
|
timeout: 5e3,
|
|
9569
10973
|
stdio: ["pipe", "pipe", "pipe"]
|
|
9570
10974
|
}).trim();
|
|
9571
|
-
const tcPath =
|
|
9572
|
-
if (existsSync11(
|
|
10975
|
+
const tcPath = join17(globalRoot, "transcribe-cli");
|
|
10976
|
+
if (existsSync11(join17(tcPath, "dist", "index.js"))) {
|
|
9573
10977
|
const { createRequire: createRequire4 } = await import("node:module");
|
|
9574
10978
|
const req = createRequire4(import.meta.url);
|
|
9575
|
-
return req(
|
|
10979
|
+
return req(join17(tcPath, "dist", "index.js"));
|
|
9576
10980
|
}
|
|
9577
10981
|
} catch {
|
|
9578
10982
|
}
|
|
9579
|
-
const nvmBase =
|
|
10983
|
+
const nvmBase = join17(homedir6(), ".nvm", "versions", "node");
|
|
9580
10984
|
if (existsSync11(nvmBase)) {
|
|
9581
10985
|
try {
|
|
9582
10986
|
const { readdirSync: readdirSync9 } = await import("node:fs");
|
|
9583
10987
|
for (const ver of readdirSync9(nvmBase)) {
|
|
9584
|
-
const tcPath =
|
|
9585
|
-
if (existsSync11(
|
|
10988
|
+
const tcPath = join17(nvmBase, ver, "lib", "node_modules", "transcribe-cli");
|
|
10989
|
+
if (existsSync11(join17(tcPath, "dist", "index.js"))) {
|
|
9586
10990
|
const { createRequire: createRequire4 } = await import("node:module");
|
|
9587
10991
|
const req = createRequire4(import.meta.url);
|
|
9588
|
-
return req(
|
|
10992
|
+
return req(join17(tcPath, "dist", "index.js"));
|
|
9589
10993
|
}
|
|
9590
10994
|
}
|
|
9591
10995
|
} catch {
|
|
@@ -9646,18 +11050,18 @@ var init_listen = __esm({
|
|
|
9646
11050
|
this.liveTranscriber.on("error", (err) => {
|
|
9647
11051
|
this.emit("error", err);
|
|
9648
11052
|
});
|
|
9649
|
-
await new Promise((
|
|
11053
|
+
await new Promise((resolve18, reject) => {
|
|
9650
11054
|
const timeout = setTimeout(() => reject(new Error("Model load timeout (60s)")), 6e4);
|
|
9651
11055
|
this.liveTranscriber.on("ready", () => {
|
|
9652
11056
|
clearTimeout(timeout);
|
|
9653
|
-
|
|
11057
|
+
resolve18();
|
|
9654
11058
|
});
|
|
9655
11059
|
this.liveTranscriber.on("error", (err) => {
|
|
9656
11060
|
clearTimeout(timeout);
|
|
9657
11061
|
reject(err);
|
|
9658
11062
|
});
|
|
9659
11063
|
});
|
|
9660
|
-
this.micProcess =
|
|
11064
|
+
this.micProcess = spawn6(micCmd.cmd, micCmd.args, {
|
|
9661
11065
|
stdio: ["pipe", "pipe", "pipe"],
|
|
9662
11066
|
env: { ...process.env }
|
|
9663
11067
|
});
|
|
@@ -9768,9 +11172,9 @@ var init_listen = __esm({
|
|
|
9768
11172
|
});
|
|
9769
11173
|
if (outputDir) {
|
|
9770
11174
|
const { basename: basename8 } = await import("node:path");
|
|
9771
|
-
const transcriptDir =
|
|
11175
|
+
const transcriptDir = join17(outputDir, ".oa", "transcripts");
|
|
9772
11176
|
mkdirSync5(transcriptDir, { recursive: true });
|
|
9773
|
-
const outFile =
|
|
11177
|
+
const outFile = join17(transcriptDir, `${basename8(filePath)}.txt`);
|
|
9774
11178
|
writeFileSync5(outFile, result.text, "utf-8");
|
|
9775
11179
|
}
|
|
9776
11180
|
return {
|
|
@@ -10377,6 +11781,10 @@ function renderSlashHelp() {
|
|
|
10377
11781
|
["/listen confirm", "Require Enter to submit transcription"],
|
|
10378
11782
|
["/listen auto", "Auto-submit after 3s silence (blinking \u25CF indicator)"],
|
|
10379
11783
|
["/listen stop", "Stop listening"],
|
|
11784
|
+
["/cost", "Show session token cost breakdown"],
|
|
11785
|
+
["/evaluate", "Evaluate last completed task (LLM quality scoring)"],
|
|
11786
|
+
["/task-type", "Set task type (code, document, analysis, plan, general, auto)"],
|
|
11787
|
+
["/stats", "Show session dashboard (metrics, tool usage, task history)"],
|
|
10380
11788
|
["/bruteforce", "Toggle brute-force mode (auto re-engage on turn limit)"],
|
|
10381
11789
|
["/tools", "List agent-created custom tools"],
|
|
10382
11790
|
["/skills", "List available AIWG skills"],
|
|
@@ -10755,22 +12163,215 @@ var init_render = __esm({
|
|
|
10755
12163
|
}
|
|
10756
12164
|
});
|
|
10757
12165
|
|
|
12166
|
+
// packages/prompts/dist/loader.js
|
|
12167
|
+
var init_loader = __esm({
|
|
12168
|
+
"packages/prompts/dist/loader.js"() {
|
|
12169
|
+
"use strict";
|
|
12170
|
+
}
|
|
12171
|
+
});
|
|
12172
|
+
|
|
12173
|
+
// packages/prompts/dist/render.js
|
|
12174
|
+
var init_render2 = __esm({
|
|
12175
|
+
"packages/prompts/dist/render.js"() {
|
|
12176
|
+
"use strict";
|
|
12177
|
+
}
|
|
12178
|
+
});
|
|
12179
|
+
|
|
12180
|
+
// packages/prompts/dist/task-templates.js
|
|
12181
|
+
function getTaskTemplate(type) {
|
|
12182
|
+
return TEMPLATES[type];
|
|
12183
|
+
}
|
|
12184
|
+
function getTaskTypes() {
|
|
12185
|
+
return Object.keys(TEMPLATES);
|
|
12186
|
+
}
|
|
12187
|
+
function buildTaskContext(type) {
|
|
12188
|
+
const template = TEMPLATES[type];
|
|
12189
|
+
return `${template.systemPromptAddition}
|
|
12190
|
+
|
|
12191
|
+
### Output Guidance
|
|
12192
|
+
${template.outputGuidance}`;
|
|
12193
|
+
}
|
|
12194
|
+
var TEMPLATES;
|
|
12195
|
+
var init_task_templates = __esm({
|
|
12196
|
+
"packages/prompts/dist/task-templates.js"() {
|
|
12197
|
+
"use strict";
|
|
12198
|
+
TEMPLATES = {
|
|
12199
|
+
code: {
|
|
12200
|
+
type: "code",
|
|
12201
|
+
label: "Software Development",
|
|
12202
|
+
description: "Writing, debugging, refactoring, or reviewing code.",
|
|
12203
|
+
systemPromptAddition: `
|
|
12204
|
+
## Task Context: Software Development
|
|
12205
|
+
|
|
12206
|
+
You are working on a software development task. Follow these principles:
|
|
12207
|
+
|
|
12208
|
+
- **Read before writing**: Always read the existing code and understand the context before making changes.
|
|
12209
|
+
- **Test-driven approach**: Run existing tests first, make changes, then verify tests still pass.
|
|
12210
|
+
- **Minimal changes**: Make the smallest change that solves the problem. Avoid refactoring unrelated code.
|
|
12211
|
+
- **Convention adherence**: Match the existing code style, naming conventions, and patterns in the project.
|
|
12212
|
+
- **Error handling**: Ensure proper error handling and edge case coverage.
|
|
12213
|
+
- **File organization**: Follow the existing project structure when adding new files.
|
|
12214
|
+
|
|
12215
|
+
When the task is complete, verify by running tests and/or type-checking where available.`,
|
|
12216
|
+
recommendedTools: [
|
|
12217
|
+
"file_read",
|
|
12218
|
+
"file_write",
|
|
12219
|
+
"file_edit",
|
|
12220
|
+
"shell",
|
|
12221
|
+
"grep_search",
|
|
12222
|
+
"glob_find",
|
|
12223
|
+
"git_info",
|
|
12224
|
+
"codebase_map"
|
|
12225
|
+
],
|
|
12226
|
+
outputGuidance: "Deliver working code with tests passing. Summarize what was changed and why."
|
|
12227
|
+
},
|
|
12228
|
+
document: {
|
|
12229
|
+
type: "document",
|
|
12230
|
+
label: "Document Drafting",
|
|
12231
|
+
description: "Creating reports, specifications, guides, proposals, or other professional documents.",
|
|
12232
|
+
systemPromptAddition: `
|
|
12233
|
+
## Task Context: Document Drafting
|
|
12234
|
+
|
|
12235
|
+
You are working on a professional document. Follow these principles:
|
|
12236
|
+
|
|
12237
|
+
- **Audience awareness**: Tailor language, depth, and terminology to the intended audience.
|
|
12238
|
+
- **Structure first**: Create a clear outline before filling in content. Use headings, sections, and lists.
|
|
12239
|
+
- **Completeness**: Cover all aspects the user requested. Flag any areas where you need clarification.
|
|
12240
|
+
- **Clarity**: Use clear, concise language. Avoid jargon unless appropriate for the audience.
|
|
12241
|
+
- **Formatting**: Use appropriate markdown formatting \u2014 tables for data, code blocks for technical content, lists for enumerations.
|
|
12242
|
+
- **Citations**: When referencing external information, note sources or indicate where citations are needed.
|
|
12243
|
+
|
|
12244
|
+
Use the create_structured_file tool for spreadsheets, CSV, or formatted output. Use file_write for documents.`,
|
|
12245
|
+
recommendedTools: [
|
|
12246
|
+
"file_read",
|
|
12247
|
+
"file_write",
|
|
12248
|
+
"web_search",
|
|
12249
|
+
"web_fetch",
|
|
12250
|
+
"create_structured_file",
|
|
12251
|
+
"memory_read"
|
|
12252
|
+
],
|
|
12253
|
+
outputGuidance: "Deliver a complete, well-structured document. Specify the output format (Markdown, PDF, etc.)."
|
|
12254
|
+
},
|
|
12255
|
+
analysis: {
|
|
12256
|
+
type: "analysis",
|
|
12257
|
+
label: "Analysis & Research",
|
|
12258
|
+
description: "Analyzing data, evaluating options, conducting research, or producing insights.",
|
|
12259
|
+
systemPromptAddition: `
|
|
12260
|
+
## Task Context: Analysis & Research
|
|
12261
|
+
|
|
12262
|
+
You are working on an analytical task. Follow these principles:
|
|
12263
|
+
|
|
12264
|
+
- **Evidence-based**: Ground conclusions in data, code, or verifiable sources. Avoid speculation.
|
|
12265
|
+
- **Methodology**: State your analytical approach clearly. When comparing options, define criteria upfront.
|
|
12266
|
+
- **Quantify**: Use numbers, metrics, and measurements wherever possible. Avoid vague qualifiers.
|
|
12267
|
+
- **Visualization**: Present data in tables or structured formats for clarity.
|
|
12268
|
+
- **Limitations**: Acknowledge limitations in your analysis \u2014 data gaps, assumptions, scope boundaries.
|
|
12269
|
+
- **Actionable conclusions**: End with clear recommendations or next steps.
|
|
12270
|
+
|
|
12271
|
+
Use web_search for external research. Use grep_search and codebase_map for codebase analysis.
|
|
12272
|
+
Use create_structured_file to output data as CSV, JSON, or markdown tables.`,
|
|
12273
|
+
recommendedTools: [
|
|
12274
|
+
"file_read",
|
|
12275
|
+
"grep_search",
|
|
12276
|
+
"glob_find",
|
|
12277
|
+
"web_search",
|
|
12278
|
+
"web_fetch",
|
|
12279
|
+
"codebase_map",
|
|
12280
|
+
"create_structured_file",
|
|
12281
|
+
"shell"
|
|
12282
|
+
],
|
|
12283
|
+
outputGuidance: "Deliver a structured analysis with findings, data tables, and actionable recommendations."
|
|
12284
|
+
},
|
|
12285
|
+
plan: {
|
|
12286
|
+
type: "plan",
|
|
12287
|
+
label: "Planning & Design",
|
|
12288
|
+
description: "Creating project plans, system designs, architecture proposals, or roadmaps.",
|
|
12289
|
+
systemPromptAddition: `
|
|
12290
|
+
## Task Context: Planning & Design
|
|
12291
|
+
|
|
12292
|
+
You are working on a planning or design task. Follow these principles:
|
|
12293
|
+
|
|
12294
|
+
- **Scope clarity**: Define what is in-scope and out-of-scope explicitly.
|
|
12295
|
+
- **Phased approach**: Break work into phases or milestones with clear dependencies.
|
|
12296
|
+
- **Risk identification**: Identify key risks, assumptions, and dependencies for each phase.
|
|
12297
|
+
- **Resource awareness**: Consider team size, skill requirements, and tool/infrastructure needs.
|
|
12298
|
+
- **Alternatives**: When making design decisions, briefly note alternatives considered and why the chosen approach is preferred.
|
|
12299
|
+
- **Actionable items**: Every section should include concrete next steps or action items.
|
|
12300
|
+
- **Traceability**: Link plan items to requirements or goals where applicable.
|
|
12301
|
+
|
|
12302
|
+
Use codebase_map and grep_search to understand existing architecture.
|
|
12303
|
+
Use create_structured_file for timeline/schedule output.`,
|
|
12304
|
+
recommendedTools: [
|
|
12305
|
+
"file_read",
|
|
12306
|
+
"grep_search",
|
|
12307
|
+
"glob_find",
|
|
12308
|
+
"codebase_map",
|
|
12309
|
+
"web_search",
|
|
12310
|
+
"create_structured_file",
|
|
12311
|
+
"file_write",
|
|
12312
|
+
"git_info"
|
|
12313
|
+
],
|
|
12314
|
+
outputGuidance: "Deliver a structured plan with phases, milestones, risks, and action items."
|
|
12315
|
+
},
|
|
12316
|
+
general: {
|
|
12317
|
+
type: "general",
|
|
12318
|
+
label: "General Task",
|
|
12319
|
+
description: "Tasks that don't clearly fit another category.",
|
|
12320
|
+
systemPromptAddition: `
|
|
12321
|
+
## Task Context: General
|
|
12322
|
+
|
|
12323
|
+
Approach this task thoughtfully:
|
|
12324
|
+
|
|
12325
|
+
- **Clarify intent**: If the task is ambiguous, use available tools to gather context before proceeding.
|
|
12326
|
+
- **Appropriate tools**: Select the right tools for the job \u2014 file tools for file work, search for research, shell for commands.
|
|
12327
|
+
- **Quality output**: Regardless of task type, produce clear, complete, and well-organized output.
|
|
12328
|
+
- **Verify results**: After completing work, verify the results are correct and complete.`,
|
|
12329
|
+
recommendedTools: [
|
|
12330
|
+
"file_read",
|
|
12331
|
+
"file_write",
|
|
12332
|
+
"shell",
|
|
12333
|
+
"grep_search",
|
|
12334
|
+
"web_search",
|
|
12335
|
+
"memory_read"
|
|
12336
|
+
],
|
|
12337
|
+
outputGuidance: "Deliver complete results with a clear summary of what was done."
|
|
12338
|
+
}
|
|
12339
|
+
};
|
|
12340
|
+
}
|
|
12341
|
+
});
|
|
12342
|
+
|
|
12343
|
+
// packages/prompts/dist/index.js
|
|
12344
|
+
import { join as join18, dirname as dirname4 } from "node:path";
|
|
12345
|
+
import { fileURLToPath } from "node:url";
|
|
12346
|
+
var _dir, _packageRoot;
|
|
12347
|
+
var init_dist6 = __esm({
|
|
12348
|
+
"packages/prompts/dist/index.js"() {
|
|
12349
|
+
"use strict";
|
|
12350
|
+
init_loader();
|
|
12351
|
+
init_render2();
|
|
12352
|
+
init_task_templates();
|
|
12353
|
+
init_render2();
|
|
12354
|
+
_dir = dirname4(fileURLToPath(import.meta.url));
|
|
12355
|
+
_packageRoot = join18(_dir, "..");
|
|
12356
|
+
}
|
|
12357
|
+
});
|
|
12358
|
+
|
|
10758
12359
|
// packages/cli/dist/tui/oa-directory.js
|
|
10759
12360
|
import { existsSync as existsSync12, mkdirSync as mkdirSync6, readFileSync as readFileSync10, writeFileSync as writeFileSync6, readdirSync as readdirSync6, statSync as statSync5, unlinkSync as unlinkSync2 } from "node:fs";
|
|
10760
|
-
import { join as
|
|
12361
|
+
import { join as join19, relative as relative2, basename as basename4, extname as extname7 } from "node:path";
|
|
10761
12362
|
import { homedir as homedir7 } from "node:os";
|
|
10762
12363
|
function initOaDirectory(repoRoot) {
|
|
10763
|
-
const oaPath =
|
|
12364
|
+
const oaPath = join19(repoRoot, OA_DIR);
|
|
10764
12365
|
for (const sub of SUBDIRS) {
|
|
10765
|
-
mkdirSync6(
|
|
12366
|
+
mkdirSync6(join19(oaPath, sub), { recursive: true });
|
|
10766
12367
|
}
|
|
10767
12368
|
return oaPath;
|
|
10768
12369
|
}
|
|
10769
12370
|
function hasOaDirectory(repoRoot) {
|
|
10770
|
-
return existsSync12(
|
|
12371
|
+
return existsSync12(join19(repoRoot, OA_DIR, "index"));
|
|
10771
12372
|
}
|
|
10772
12373
|
function loadProjectSettings(repoRoot) {
|
|
10773
|
-
const settingsPath =
|
|
12374
|
+
const settingsPath = join19(repoRoot, OA_DIR, "settings.json");
|
|
10774
12375
|
try {
|
|
10775
12376
|
if (existsSync12(settingsPath)) {
|
|
10776
12377
|
return JSON.parse(readFileSync10(settingsPath, "utf-8"));
|
|
@@ -10780,14 +12381,14 @@ function loadProjectSettings(repoRoot) {
|
|
|
10780
12381
|
return {};
|
|
10781
12382
|
}
|
|
10782
12383
|
function saveProjectSettings(repoRoot, settings) {
|
|
10783
|
-
const oaPath =
|
|
12384
|
+
const oaPath = join19(repoRoot, OA_DIR);
|
|
10784
12385
|
mkdirSync6(oaPath, { recursive: true });
|
|
10785
12386
|
const existing = loadProjectSettings(repoRoot);
|
|
10786
12387
|
const merged = { ...existing, ...settings };
|
|
10787
|
-
writeFileSync6(
|
|
12388
|
+
writeFileSync6(join19(oaPath, "settings.json"), JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
10788
12389
|
}
|
|
10789
12390
|
function loadGlobalSettings() {
|
|
10790
|
-
const settingsPath =
|
|
12391
|
+
const settingsPath = join19(homedir7(), ".open-agents", "settings.json");
|
|
10791
12392
|
try {
|
|
10792
12393
|
if (existsSync12(settingsPath)) {
|
|
10793
12394
|
return JSON.parse(readFileSync10(settingsPath, "utf-8"));
|
|
@@ -10797,11 +12398,11 @@ function loadGlobalSettings() {
|
|
|
10797
12398
|
return {};
|
|
10798
12399
|
}
|
|
10799
12400
|
function saveGlobalSettings(settings) {
|
|
10800
|
-
const dir =
|
|
12401
|
+
const dir = join19(homedir7(), ".open-agents");
|
|
10801
12402
|
mkdirSync6(dir, { recursive: true });
|
|
10802
12403
|
const existing = loadGlobalSettings();
|
|
10803
12404
|
const merged = { ...existing, ...settings };
|
|
10804
|
-
writeFileSync6(
|
|
12405
|
+
writeFileSync6(join19(dir, "settings.json"), JSON.stringify(merged, null, 2) + "\n", "utf-8");
|
|
10805
12406
|
}
|
|
10806
12407
|
function resolveSettings(repoRoot) {
|
|
10807
12408
|
const global = loadGlobalSettings();
|
|
@@ -10816,7 +12417,7 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
|
|
|
10816
12417
|
while (dir && !visited.has(dir)) {
|
|
10817
12418
|
visited.add(dir);
|
|
10818
12419
|
for (const name of CONTEXT_FILES) {
|
|
10819
|
-
const filePath =
|
|
12420
|
+
const filePath = join19(dir, name);
|
|
10820
12421
|
const normalizedName = name.toLowerCase();
|
|
10821
12422
|
if (existsSync12(filePath) && !seen.has(filePath)) {
|
|
10822
12423
|
seen.add(filePath);
|
|
@@ -10835,7 +12436,7 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
|
|
|
10835
12436
|
}
|
|
10836
12437
|
}
|
|
10837
12438
|
}
|
|
10838
|
-
const projectMap =
|
|
12439
|
+
const projectMap = join19(dir, OA_DIR, "context", "project-map.md");
|
|
10839
12440
|
if (existsSync12(projectMap) && !seen.has(projectMap)) {
|
|
10840
12441
|
seen.add(projectMap);
|
|
10841
12442
|
try {
|
|
@@ -10851,7 +12452,7 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
|
|
|
10851
12452
|
} catch {
|
|
10852
12453
|
}
|
|
10853
12454
|
}
|
|
10854
|
-
const parent =
|
|
12455
|
+
const parent = join19(dir, "..");
|
|
10855
12456
|
if (parent === dir)
|
|
10856
12457
|
break;
|
|
10857
12458
|
dir = parent;
|
|
@@ -10869,7 +12470,7 @@ function discoverContextFiles(repoRoot, maxContentLen = 8e3) {
|
|
|
10869
12470
|
return found;
|
|
10870
12471
|
}
|
|
10871
12472
|
function readIndexMeta(repoRoot) {
|
|
10872
|
-
const metaPath =
|
|
12473
|
+
const metaPath = join19(repoRoot, OA_DIR, "index", "meta.json");
|
|
10873
12474
|
try {
|
|
10874
12475
|
return JSON.parse(readFileSync10(metaPath, "utf-8"));
|
|
10875
12476
|
} catch {
|
|
@@ -10922,28 +12523,28 @@ ${tree}\`\`\`
|
|
|
10922
12523
|
sections.push("");
|
|
10923
12524
|
}
|
|
10924
12525
|
const content = sections.join("\n");
|
|
10925
|
-
const contextDir =
|
|
12526
|
+
const contextDir = join19(repoRoot, OA_DIR, "context");
|
|
10926
12527
|
mkdirSync6(contextDir, { recursive: true });
|
|
10927
|
-
writeFileSync6(
|
|
12528
|
+
writeFileSync6(join19(contextDir, "project-map.md"), content, "utf-8");
|
|
10928
12529
|
return content;
|
|
10929
12530
|
}
|
|
10930
12531
|
function saveSession(repoRoot, session) {
|
|
10931
|
-
const historyDir =
|
|
12532
|
+
const historyDir = join19(repoRoot, OA_DIR, "history");
|
|
10932
12533
|
mkdirSync6(historyDir, { recursive: true });
|
|
10933
|
-
writeFileSync6(
|
|
12534
|
+
writeFileSync6(join19(historyDir, `${session.id}.json`), JSON.stringify(session, null, 2), "utf-8");
|
|
10934
12535
|
}
|
|
10935
12536
|
function loadRecentSessions(repoRoot, limit = 5) {
|
|
10936
|
-
const historyDir =
|
|
12537
|
+
const historyDir = join19(repoRoot, OA_DIR, "history");
|
|
10937
12538
|
if (!existsSync12(historyDir))
|
|
10938
12539
|
return [];
|
|
10939
12540
|
try {
|
|
10940
12541
|
const files = readdirSync6(historyDir).filter((f) => f.endsWith(".json")).map((f) => {
|
|
10941
|
-
const
|
|
10942
|
-
return { file: f, mtime:
|
|
12542
|
+
const stat5 = statSync5(join19(historyDir, f));
|
|
12543
|
+
return { file: f, mtime: stat5.mtimeMs };
|
|
10943
12544
|
}).sort((a, b) => b.mtime - a.mtime).slice(0, limit);
|
|
10944
12545
|
return files.map((f) => {
|
|
10945
12546
|
try {
|
|
10946
|
-
return JSON.parse(readFileSync10(
|
|
12547
|
+
return JSON.parse(readFileSync10(join19(historyDir, f.file), "utf-8"));
|
|
10947
12548
|
} catch {
|
|
10948
12549
|
return null;
|
|
10949
12550
|
}
|
|
@@ -10953,12 +12554,12 @@ function loadRecentSessions(repoRoot, limit = 5) {
|
|
|
10953
12554
|
}
|
|
10954
12555
|
}
|
|
10955
12556
|
function savePendingTask(repoRoot, task) {
|
|
10956
|
-
const historyDir =
|
|
12557
|
+
const historyDir = join19(repoRoot, OA_DIR, "history");
|
|
10957
12558
|
mkdirSync6(historyDir, { recursive: true });
|
|
10958
|
-
writeFileSync6(
|
|
12559
|
+
writeFileSync6(join19(historyDir, PENDING_TASK_FILE), JSON.stringify(task, null, 2) + "\n", "utf-8");
|
|
10959
12560
|
}
|
|
10960
12561
|
function loadPendingTask(repoRoot) {
|
|
10961
|
-
const filePath =
|
|
12562
|
+
const filePath = join19(repoRoot, OA_DIR, "history", PENDING_TASK_FILE);
|
|
10962
12563
|
try {
|
|
10963
12564
|
if (!existsSync12(filePath))
|
|
10964
12565
|
return null;
|
|
@@ -10990,7 +12591,7 @@ function detectManifests(repoRoot) {
|
|
|
10990
12591
|
{ file: "docker-compose.yaml", type: "Docker Compose" }
|
|
10991
12592
|
];
|
|
10992
12593
|
for (const check of checks) {
|
|
10993
|
-
const filePath =
|
|
12594
|
+
const filePath = join19(repoRoot, check.file);
|
|
10994
12595
|
if (existsSync12(filePath)) {
|
|
10995
12596
|
let name;
|
|
10996
12597
|
if (check.nameField) {
|
|
@@ -11024,7 +12625,7 @@ function findKeyFiles(repoRoot) {
|
|
|
11024
12625
|
{ pattern: "CLAUDE.md", description: "Claude Code context" }
|
|
11025
12626
|
];
|
|
11026
12627
|
for (const check of checks) {
|
|
11027
|
-
if (existsSync12(
|
|
12628
|
+
if (existsSync12(join19(repoRoot, check.pattern))) {
|
|
11028
12629
|
keyFiles.push({ path: check.pattern, description: check.description });
|
|
11029
12630
|
}
|
|
11030
12631
|
}
|
|
@@ -11050,12 +12651,12 @@ function buildDirTree(root, maxDepth, prefix = "", depth = 0) {
|
|
|
11050
12651
|
if (entry.isDirectory()) {
|
|
11051
12652
|
let fileCount = 0;
|
|
11052
12653
|
try {
|
|
11053
|
-
fileCount = readdirSync6(
|
|
12654
|
+
fileCount = readdirSync6(join19(root, entry.name)).filter((f) => !f.startsWith(".")).length;
|
|
11054
12655
|
} catch {
|
|
11055
12656
|
}
|
|
11056
12657
|
result += `${prefix}${connector}${entry.name}/ (${fileCount})
|
|
11057
12658
|
`;
|
|
11058
|
-
result += buildDirTree(
|
|
12659
|
+
result += buildDirTree(join19(root, entry.name), maxDepth, childPrefix, depth + 1);
|
|
11059
12660
|
} else if (depth < maxDepth) {
|
|
11060
12661
|
result += `${prefix}${connector}${entry.name}
|
|
11061
12662
|
`;
|
|
@@ -11108,7 +12709,7 @@ var init_oa_directory = __esm({
|
|
|
11108
12709
|
import * as readline from "node:readline";
|
|
11109
12710
|
import { execSync as execSync10 } from "node:child_process";
|
|
11110
12711
|
import { existsSync as existsSync13, writeFileSync as writeFileSync7, mkdirSync as mkdirSync7 } from "node:fs";
|
|
11111
|
-
import { join as
|
|
12712
|
+
import { join as join20 } from "node:path";
|
|
11112
12713
|
import { homedir as homedir8 } from "node:os";
|
|
11113
12714
|
function detectSystemSpecs() {
|
|
11114
12715
|
let totalRamGB = 0;
|
|
@@ -11192,8 +12793,8 @@ function modelSupportsToolCalling(modelName) {
|
|
|
11192
12793
|
return false;
|
|
11193
12794
|
}
|
|
11194
12795
|
function ask(rl, question) {
|
|
11195
|
-
return new Promise((
|
|
11196
|
-
rl.question(question, (answer) =>
|
|
12796
|
+
return new Promise((resolve18) => {
|
|
12797
|
+
rl.question(question, (answer) => resolve18(answer.trim()));
|
|
11197
12798
|
});
|
|
11198
12799
|
}
|
|
11199
12800
|
function pullModelWithAutoUpdate(tag) {
|
|
@@ -11542,9 +13143,9 @@ async function doSetup(config, rl) {
|
|
|
11542
13143
|
`PARAMETER num_predict 16384`,
|
|
11543
13144
|
`PARAMETER stop "<|endoftext|>"`
|
|
11544
13145
|
].join("\n");
|
|
11545
|
-
const modelDir2 =
|
|
13146
|
+
const modelDir2 = join20(homedir8(), ".open-agents", "models");
|
|
11546
13147
|
mkdirSync7(modelDir2, { recursive: true });
|
|
11547
|
-
const modelfilePath =
|
|
13148
|
+
const modelfilePath = join20(modelDir2, `Modelfile.${customName}`);
|
|
11548
13149
|
writeFileSync7(modelfilePath, modelfileContent + "\n", "utf8");
|
|
11549
13150
|
process.stdout.write(` ${c2.dim("Creating model...")} `);
|
|
11550
13151
|
execSync10(`ollama create ${customName} -f ${modelfilePath}`, {
|
|
@@ -11590,7 +13191,7 @@ async function isModelAvailable(config) {
|
|
|
11590
13191
|
}
|
|
11591
13192
|
function isFirstRun() {
|
|
11592
13193
|
try {
|
|
11593
|
-
return !existsSync13(
|
|
13194
|
+
return !existsSync13(join20(homedir8(), ".open-agents", "config.json"));
|
|
11594
13195
|
} catch {
|
|
11595
13196
|
return true;
|
|
11596
13197
|
}
|
|
@@ -11628,9 +13229,9 @@ function createExpandedVariant(baseModel, specs, sizeGB) {
|
|
|
11628
13229
|
`PARAMETER num_predict 16384`,
|
|
11629
13230
|
`PARAMETER stop "<|endoftext|>"`
|
|
11630
13231
|
].join("\n");
|
|
11631
|
-
const modelDir2 =
|
|
13232
|
+
const modelDir2 = join20(homedir8(), ".open-agents", "models");
|
|
11632
13233
|
mkdirSync7(modelDir2, { recursive: true });
|
|
11633
|
-
const modelfilePath =
|
|
13234
|
+
const modelfilePath = join20(modelDir2, `Modelfile.${customName}`);
|
|
11634
13235
|
writeFileSync7(modelfilePath, modelfileContent + "\n", "utf8");
|
|
11635
13236
|
execSync10(`ollama create ${customName} -f ${modelfilePath}`, {
|
|
11636
13237
|
stdio: "pipe",
|
|
@@ -11759,6 +13360,174 @@ async function handleSlashCommand(input, ctx) {
|
|
|
11759
13360
|
dryRun: String(ctx.config.dryRun)
|
|
11760
13361
|
});
|
|
11761
13362
|
return "handled";
|
|
13363
|
+
case "cost":
|
|
13364
|
+
case "costs":
|
|
13365
|
+
if (ctx.costTracker) {
|
|
13366
|
+
const summary = ctx.costTracker.getSummary();
|
|
13367
|
+
const lines = [];
|
|
13368
|
+
lines.push(c2.bold(` Session Cost Summary (${summary.provider})`));
|
|
13369
|
+
lines.push("");
|
|
13370
|
+
lines.push(` Input tokens: ${c2.bold(summary.totalInputTokens.toLocaleString())}`);
|
|
13371
|
+
lines.push(` Output tokens: ${c2.bold(summary.totalOutputTokens.toLocaleString())}`);
|
|
13372
|
+
if (ctx.costTracker.hasPricing) {
|
|
13373
|
+
lines.push(` Estimated cost: ${c2.bold(c2.yellow(ctx.costTracker.formatCost()))}`);
|
|
13374
|
+
lines.push(` Pricing: $${ctx.costTracker.provider.inputPer1M}/1M in, $${ctx.costTracker.provider.outputPer1M}/1M out`);
|
|
13375
|
+
} else {
|
|
13376
|
+
lines.push(` Cost: ${c2.dim("free (local provider)")}`);
|
|
13377
|
+
}
|
|
13378
|
+
if (summary.taskCount > 0) {
|
|
13379
|
+
lines.push("");
|
|
13380
|
+
lines.push(` Tasks: ${summary.taskCount}`);
|
|
13381
|
+
for (const t of summary.tasks.slice(-5)) {
|
|
13382
|
+
const costStr = ctx.costTracker.hasPricing ? ` ${ctx.costTracker.formatCost(t.estimatedCost)}` : "";
|
|
13383
|
+
const dur = (t.durationMs / 1e3).toFixed(1);
|
|
13384
|
+
lines.push(` ${c2.dim("\u2022")} ${t.task.slice(0, 50)}${t.task.length > 50 ? "..." : ""} \u2014 ${dur}s${costStr}`);
|
|
13385
|
+
}
|
|
13386
|
+
if (summary.taskCount > 5) {
|
|
13387
|
+
lines.push(` ${c2.dim(`... and ${summary.taskCount - 5} more`)}`);
|
|
13388
|
+
}
|
|
13389
|
+
}
|
|
13390
|
+
lines.push("");
|
|
13391
|
+
console.log(lines.join("\n"));
|
|
13392
|
+
} else {
|
|
13393
|
+
renderInfo("Cost tracking not available.");
|
|
13394
|
+
}
|
|
13395
|
+
return "handled";
|
|
13396
|
+
case "evaluate":
|
|
13397
|
+
case "eval":
|
|
13398
|
+
if (ctx.workEvaluator && ctx.lastTask && ctx.lastSummary) {
|
|
13399
|
+
renderInfo("Evaluating last completed task...");
|
|
13400
|
+
try {
|
|
13401
|
+
const evalResult = await ctx.workEvaluator.evaluate(ctx.lastTask, ctx.lastSummary);
|
|
13402
|
+
if (evalResult.success) {
|
|
13403
|
+
const lines = [];
|
|
13404
|
+
const pct = Math.round(evalResult.overallScore * 100);
|
|
13405
|
+
const scoreColor = pct >= 80 ? c2.green : pct >= 60 ? c2.yellow : c2.red;
|
|
13406
|
+
lines.push(`
|
|
13407
|
+
${c2.bold("Task Evaluation")} (${evalResult.taskType})`);
|
|
13408
|
+
lines.push(` Overall: ${scoreColor(c2.bold(`${pct}%`))}`);
|
|
13409
|
+
lines.push("");
|
|
13410
|
+
for (const d of evalResult.dimensions) {
|
|
13411
|
+
const bar = "\u2588".repeat(d.score) + "\u2591".repeat(10 - d.score);
|
|
13412
|
+
const dPct = Math.round(d.score / 10 * 100);
|
|
13413
|
+
const dColor = dPct >= 80 ? c2.green : dPct >= 60 ? c2.yellow : c2.red;
|
|
13414
|
+
lines.push(` ${d.name.padEnd(14)} ${dColor(bar)} ${dColor(`${d.score}/10`)} ${c2.dim(`(${Math.round(d.weight * 100)}%)`)}`);
|
|
13415
|
+
if (d.feedback)
|
|
13416
|
+
lines.push(` ${c2.dim(" " + d.feedback)}`);
|
|
13417
|
+
}
|
|
13418
|
+
if (evalResult.feedback) {
|
|
13419
|
+
lines.push("");
|
|
13420
|
+
lines.push(` ${c2.dim(evalResult.feedback)}`);
|
|
13421
|
+
}
|
|
13422
|
+
lines.push("");
|
|
13423
|
+
console.log(lines.join("\n"));
|
|
13424
|
+
} else {
|
|
13425
|
+
renderError(`Evaluation failed: ${evalResult.error}`);
|
|
13426
|
+
}
|
|
13427
|
+
} catch (err) {
|
|
13428
|
+
renderError(`Evaluation error: ${err instanceof Error ? err.message : String(err)}`);
|
|
13429
|
+
}
|
|
13430
|
+
} else if (!ctx.lastTask) {
|
|
13431
|
+
renderWarning("No completed task to evaluate. Complete a task first.");
|
|
13432
|
+
} else {
|
|
13433
|
+
renderWarning("Evaluation backend not configured.");
|
|
13434
|
+
}
|
|
13435
|
+
return "handled";
|
|
13436
|
+
case "task-type":
|
|
13437
|
+
case "tasktype":
|
|
13438
|
+
case "tt": {
|
|
13439
|
+
const validTypes = getTaskTypes();
|
|
13440
|
+
if (arg === "auto" || arg === "clear" || arg === "reset") {
|
|
13441
|
+
ctx.setTaskType?.(void 0);
|
|
13442
|
+
renderInfo("Task type set to auto-detect.");
|
|
13443
|
+
} else if (arg && validTypes.includes(arg)) {
|
|
13444
|
+
const type = arg;
|
|
13445
|
+
const template = getTaskTemplate(type);
|
|
13446
|
+
ctx.setTaskType?.(type);
|
|
13447
|
+
renderInfo(`Task type: ${c2.bold(template.label)} (${type})`);
|
|
13448
|
+
console.log(` ${c2.dim(template.description)}`);
|
|
13449
|
+
console.log(` ${c2.dim("Recommended tools:")} ${template.recommendedTools.slice(0, 5).join(", ")}`);
|
|
13450
|
+
console.log("");
|
|
13451
|
+
} else {
|
|
13452
|
+
const lines = [];
|
|
13453
|
+
lines.push(`
|
|
13454
|
+
${c2.bold("Available Task Types")}
|
|
13455
|
+
`);
|
|
13456
|
+
for (const t of validTypes) {
|
|
13457
|
+
const tmpl = getTaskTemplate(t);
|
|
13458
|
+
const active = ctx.taskType === t ? c2.green(" \u2190 active") : "";
|
|
13459
|
+
lines.push(` ${c2.bold(t.padEnd(10))} ${tmpl.label}${active}`);
|
|
13460
|
+
lines.push(` ${c2.dim(" " + tmpl.description)}`);
|
|
13461
|
+
}
|
|
13462
|
+
if (!ctx.taskType) {
|
|
13463
|
+
lines.push(`
|
|
13464
|
+
${c2.dim("Current: auto-detect")}`);
|
|
13465
|
+
}
|
|
13466
|
+
lines.push(`
|
|
13467
|
+
${c2.dim("Usage: /task-type <type> or /task-type auto")}`);
|
|
13468
|
+
lines.push("");
|
|
13469
|
+
console.log(lines.join("\n"));
|
|
13470
|
+
}
|
|
13471
|
+
return "handled";
|
|
13472
|
+
}
|
|
13473
|
+
case "stats":
|
|
13474
|
+
case "metrics":
|
|
13475
|
+
case "dashboard": {
|
|
13476
|
+
if (!ctx.sessionMetrics) {
|
|
13477
|
+
renderInfo("Session metrics not available.");
|
|
13478
|
+
return "handled";
|
|
13479
|
+
}
|
|
13480
|
+
const summary = ctx.sessionMetrics.getSummary();
|
|
13481
|
+
const dur = SessionMetrics.formatDuration(summary.sessionDurationMs);
|
|
13482
|
+
const lines = [];
|
|
13483
|
+
lines.push(`
|
|
13484
|
+
${c2.bold("Session Dashboard")}
|
|
13485
|
+
`);
|
|
13486
|
+
lines.push(` Duration: ${c2.bold(dur)}`);
|
|
13487
|
+
lines.push(` Tasks completed: ${c2.bold(String(summary.tasksCompleted))}`);
|
|
13488
|
+
lines.push(` Turns: ${c2.bold(String(summary.totalTurns))}`);
|
|
13489
|
+
lines.push(` Tool calls: ${c2.bold(String(summary.totalToolCalls))}`);
|
|
13490
|
+
lines.push(` Input tokens: ${c2.bold(summary.totalInputTokens.toLocaleString())}`);
|
|
13491
|
+
lines.push(` Output tokens: ${c2.bold(summary.totalOutputTokens.toLocaleString())}`);
|
|
13492
|
+
if (ctx.costTracker?.hasPricing) {
|
|
13493
|
+
lines.push(` Estimated cost: ${c2.bold(c2.yellow(ctx.costTracker.formatCost()))}`);
|
|
13494
|
+
}
|
|
13495
|
+
const topTools = ctx.sessionMetrics.getTopTools(5);
|
|
13496
|
+
if (topTools.length > 0) {
|
|
13497
|
+
lines.push(`
|
|
13498
|
+
${c2.bold("Top Tools")}`);
|
|
13499
|
+
for (const t of topTools) {
|
|
13500
|
+
const bar = "\u2588".repeat(Math.min(t.count, 30));
|
|
13501
|
+
lines.push(` ${t.name.padEnd(20)} ${c2.dim(bar)} ${t.count}`);
|
|
13502
|
+
}
|
|
13503
|
+
}
|
|
13504
|
+
if (summary.filesModified.length > 0) {
|
|
13505
|
+
lines.push(`
|
|
13506
|
+
${c2.bold("Files Modified")} (${summary.filesModified.length})`);
|
|
13507
|
+
for (const f of summary.filesModified.slice(0, 10)) {
|
|
13508
|
+
lines.push(` ${c2.dim("\u2022")} ${f}`);
|
|
13509
|
+
}
|
|
13510
|
+
if (summary.filesModified.length > 10) {
|
|
13511
|
+
lines.push(` ${c2.dim(`... and ${summary.filesModified.length - 10} more`)}`);
|
|
13512
|
+
}
|
|
13513
|
+
}
|
|
13514
|
+
if (summary.tasks.length > 0) {
|
|
13515
|
+
lines.push(`
|
|
13516
|
+
${c2.bold("Task History")}`);
|
|
13517
|
+
for (const task of summary.tasks.slice(-5)) {
|
|
13518
|
+
const taskDur = task.durationMs ? SessionMetrics.formatDuration(task.durationMs) : "?";
|
|
13519
|
+
const score = task.evaluationScore !== void 0 ? ` ${c2.dim(`(${Math.round(task.evaluationScore * 100)}%)`)}` : "";
|
|
13520
|
+
lines.push(` ${c2.dim("\u2022")} ${task.description.slice(0, 50)}${task.description.length > 50 ? "..." : ""} \u2014 ${taskDur}${score}`);
|
|
13521
|
+
}
|
|
13522
|
+
}
|
|
13523
|
+
if (summary.averageEvalScore !== void 0) {
|
|
13524
|
+
lines.push(`
|
|
13525
|
+
Avg eval score: ${c2.bold(`${Math.round(summary.averageEvalScore * 100)}%`)}`);
|
|
13526
|
+
}
|
|
13527
|
+
lines.push("");
|
|
13528
|
+
console.log(lines.join("\n"));
|
|
13529
|
+
return "handled";
|
|
13530
|
+
}
|
|
11762
13531
|
case "model":
|
|
11763
13532
|
if (arg) {
|
|
11764
13533
|
await switchModel(arg, ctx, hasLocal);
|
|
@@ -12098,15 +13867,15 @@ async function handleUpdate(subcommand, ctx) {
|
|
|
12098
13867
|
let currentVersion = "0.0.0";
|
|
12099
13868
|
try {
|
|
12100
13869
|
const { createRequire: createRequire4 } = await import("node:module");
|
|
12101
|
-
const { fileURLToPath:
|
|
12102
|
-
const { dirname:
|
|
13870
|
+
const { fileURLToPath: fileURLToPath4 } = await import("node:url");
|
|
13871
|
+
const { dirname: dirname7, join: join30 } = await import("node:path");
|
|
12103
13872
|
const { existsSync: existsSync19 } = await import("node:fs");
|
|
12104
13873
|
const req = createRequire4(import.meta.url);
|
|
12105
|
-
const thisDir =
|
|
13874
|
+
const thisDir = dirname7(fileURLToPath4(import.meta.url));
|
|
12106
13875
|
const candidates = [
|
|
12107
|
-
|
|
12108
|
-
|
|
12109
|
-
|
|
13876
|
+
join30(thisDir, "..", "package.json"),
|
|
13877
|
+
join30(thisDir, "..", "..", "package.json"),
|
|
13878
|
+
join30(thisDir, "..", "..", "..", "package.json")
|
|
12110
13879
|
];
|
|
12111
13880
|
for (const pkgPath of candidates) {
|
|
12112
13881
|
if (existsSync19(pkgPath)) {
|
|
@@ -12204,6 +13973,8 @@ var init_commands = __esm({
|
|
|
12204
13973
|
init_render();
|
|
12205
13974
|
init_dist2();
|
|
12206
13975
|
init_config();
|
|
13976
|
+
init_dist5();
|
|
13977
|
+
init_dist6();
|
|
12207
13978
|
init_updater();
|
|
12208
13979
|
init_oa_directory();
|
|
12209
13980
|
init_setup();
|
|
@@ -12213,7 +13984,7 @@ var init_commands = __esm({
|
|
|
12213
13984
|
|
|
12214
13985
|
// packages/cli/dist/tui/project-context.js
|
|
12215
13986
|
import { existsSync as existsSync14, readFileSync as readFileSync11, readdirSync as readdirSync7 } from "node:fs";
|
|
12216
|
-
import { join as
|
|
13987
|
+
import { join as join21, basename as basename5 } from "node:path";
|
|
12217
13988
|
import { execSync as execSync11 } from "node:child_process";
|
|
12218
13989
|
import { homedir as homedir9, platform, release } from "node:os";
|
|
12219
13990
|
function loadProjectFiles(repoRoot) {
|
|
@@ -12233,7 +14004,7 @@ function loadProjectMap(repoRoot) {
|
|
|
12233
14004
|
if (!hasOaDirectory(repoRoot)) {
|
|
12234
14005
|
initOaDirectory(repoRoot);
|
|
12235
14006
|
}
|
|
12236
|
-
const mapPath =
|
|
14007
|
+
const mapPath = join21(repoRoot, OA_DIR, "context", "project-map.md");
|
|
12237
14008
|
if (existsSync14(mapPath)) {
|
|
12238
14009
|
try {
|
|
12239
14010
|
const content = readFileSync11(mapPath, "utf-8");
|
|
@@ -12277,17 +14048,17 @@ ${log}`);
|
|
|
12277
14048
|
}
|
|
12278
14049
|
function loadMemoryContext(repoRoot) {
|
|
12279
14050
|
const sections = [];
|
|
12280
|
-
const oaMemDir =
|
|
14051
|
+
const oaMemDir = join21(repoRoot, OA_DIR, "memory");
|
|
12281
14052
|
const oaEntries = loadMemoryDir(oaMemDir, "project");
|
|
12282
14053
|
if (oaEntries)
|
|
12283
14054
|
sections.push(oaEntries);
|
|
12284
|
-
const legacyMemDir =
|
|
14055
|
+
const legacyMemDir = join21(repoRoot, ".open-agents", "memory");
|
|
12285
14056
|
if (legacyMemDir !== oaMemDir && existsSync14(legacyMemDir)) {
|
|
12286
14057
|
const legacyEntries = loadMemoryDir(legacyMemDir, "project/legacy");
|
|
12287
14058
|
if (legacyEntries)
|
|
12288
14059
|
sections.push(legacyEntries);
|
|
12289
14060
|
}
|
|
12290
|
-
const globalMemDir =
|
|
14061
|
+
const globalMemDir = join21(homedir9(), ".open-agents", "memory");
|
|
12291
14062
|
const globalEntries = loadMemoryDir(globalMemDir, "global");
|
|
12292
14063
|
if (globalEntries)
|
|
12293
14064
|
sections.push(globalEntries);
|
|
@@ -12301,7 +14072,7 @@ function loadMemoryDir(memDir, scope) {
|
|
|
12301
14072
|
const files = readdirSync7(memDir).filter((f) => f.endsWith(".json"));
|
|
12302
14073
|
for (const file of files.slice(0, 10)) {
|
|
12303
14074
|
try {
|
|
12304
|
-
const raw = readFileSync11(
|
|
14075
|
+
const raw = readFileSync11(join21(memDir, file), "utf-8");
|
|
12305
14076
|
const entries = JSON.parse(raw);
|
|
12306
14077
|
const topic = basename5(file, ".json");
|
|
12307
14078
|
const keys = Object.keys(entries);
|
|
@@ -13014,7 +14785,7 @@ var init_toolPatternStore = __esm({
|
|
|
13014
14785
|
});
|
|
13015
14786
|
|
|
13016
14787
|
// packages/memory/dist/index.js
|
|
13017
|
-
var
|
|
14788
|
+
var init_dist7 = __esm({
|
|
13018
14789
|
"packages/memory/dist/index.js"() {
|
|
13019
14790
|
"use strict";
|
|
13020
14791
|
init_db();
|
|
@@ -13313,24 +15084,24 @@ var init_carousel = __esm({
|
|
|
13313
15084
|
|
|
13314
15085
|
// packages/cli/dist/tui/voice.js
|
|
13315
15086
|
import { existsSync as existsSync15, mkdirSync as mkdirSync8, writeFileSync as writeFileSync8, readFileSync as readFileSync12, unlinkSync as unlinkSync3 } from "node:fs";
|
|
13316
|
-
import { join as
|
|
13317
|
-
import { homedir as homedir10, tmpdir as
|
|
15087
|
+
import { join as join22 } from "node:path";
|
|
15088
|
+
import { homedir as homedir10, tmpdir as tmpdir3, platform as platform2 } from "node:os";
|
|
13318
15089
|
import { execSync as execSync12, spawn as nodeSpawn } from "node:child_process";
|
|
13319
15090
|
import { createRequire } from "node:module";
|
|
13320
15091
|
function voiceDir() {
|
|
13321
|
-
return
|
|
15092
|
+
return join22(homedir10(), ".open-agents", "voice");
|
|
13322
15093
|
}
|
|
13323
15094
|
function modelsDir() {
|
|
13324
|
-
return
|
|
15095
|
+
return join22(voiceDir(), "models");
|
|
13325
15096
|
}
|
|
13326
15097
|
function modelDir(id) {
|
|
13327
|
-
return
|
|
15098
|
+
return join22(modelsDir(), id);
|
|
13328
15099
|
}
|
|
13329
15100
|
function modelOnnxPath(id) {
|
|
13330
|
-
return
|
|
15101
|
+
return join22(modelDir(id), "model.onnx");
|
|
13331
15102
|
}
|
|
13332
15103
|
function modelConfigPath(id) {
|
|
13333
|
-
return
|
|
15104
|
+
return join22(modelDir(id), "config.json");
|
|
13334
15105
|
}
|
|
13335
15106
|
function describeToolCall(toolName, args) {
|
|
13336
15107
|
const path = args["path"];
|
|
@@ -13603,7 +15374,7 @@ var init_voice = __esm({
|
|
|
13603
15374
|
const audioData = result["output"].data;
|
|
13604
15375
|
if (audioData.length === 0)
|
|
13605
15376
|
return;
|
|
13606
|
-
const wavPath =
|
|
15377
|
+
const wavPath = join22(tmpdir3(), `oa-voice-${Date.now()}.wav`);
|
|
13607
15378
|
this.writeWav(audioData, this.config.audio.sample_rate, wavPath);
|
|
13608
15379
|
await this.playWav(wavPath);
|
|
13609
15380
|
try {
|
|
@@ -13692,7 +15463,7 @@ var init_voice = __esm({
|
|
|
13692
15463
|
const cmd = this.getPlayCommand(path);
|
|
13693
15464
|
if (!cmd)
|
|
13694
15465
|
return;
|
|
13695
|
-
return new Promise((
|
|
15466
|
+
return new Promise((resolve18) => {
|
|
13696
15467
|
const child = nodeSpawn(cmd[0], cmd.slice(1), {
|
|
13697
15468
|
stdio: "ignore",
|
|
13698
15469
|
detached: false
|
|
@@ -13701,12 +15472,12 @@ var init_voice = __esm({
|
|
|
13701
15472
|
child.on("close", () => {
|
|
13702
15473
|
if (this.currentPlayback === child)
|
|
13703
15474
|
this.currentPlayback = null;
|
|
13704
|
-
|
|
15475
|
+
resolve18();
|
|
13705
15476
|
});
|
|
13706
15477
|
child.on("error", () => {
|
|
13707
15478
|
if (this.currentPlayback === child)
|
|
13708
15479
|
this.currentPlayback = null;
|
|
13709
|
-
|
|
15480
|
+
resolve18();
|
|
13710
15481
|
});
|
|
13711
15482
|
setTimeout(() => {
|
|
13712
15483
|
if (this.currentPlayback === child) {
|
|
@@ -13716,7 +15487,7 @@ var init_voice = __esm({
|
|
|
13716
15487
|
}
|
|
13717
15488
|
this.currentPlayback = null;
|
|
13718
15489
|
}
|
|
13719
|
-
|
|
15490
|
+
resolve18();
|
|
13720
15491
|
}, 15e3);
|
|
13721
15492
|
});
|
|
13722
15493
|
}
|
|
@@ -13756,7 +15527,7 @@ var init_voice = __esm({
|
|
|
13756
15527
|
if (this.ort)
|
|
13757
15528
|
return;
|
|
13758
15529
|
mkdirSync8(voiceDir(), { recursive: true });
|
|
13759
|
-
const pkgPath =
|
|
15530
|
+
const pkgPath = join22(voiceDir(), "package.json");
|
|
13760
15531
|
const expectedDeps = {
|
|
13761
15532
|
"onnxruntime-node": "^1.21.0",
|
|
13762
15533
|
"phonemizer": "^1.2.1"
|
|
@@ -13778,7 +15549,7 @@ var init_voice = __esm({
|
|
|
13778
15549
|
dependencies: expectedDeps
|
|
13779
15550
|
}, null, 2));
|
|
13780
15551
|
}
|
|
13781
|
-
const voiceRequire = createRequire(
|
|
15552
|
+
const voiceRequire = createRequire(join22(voiceDir(), "index.js"));
|
|
13782
15553
|
try {
|
|
13783
15554
|
this.ort = voiceRequire("onnxruntime-node");
|
|
13784
15555
|
} catch {
|
|
@@ -14375,10 +16146,10 @@ var init_stream_renderer = __esm({
|
|
|
14375
16146
|
|
|
14376
16147
|
// packages/cli/dist/tui/edit-history.js
|
|
14377
16148
|
import { appendFileSync, mkdirSync as mkdirSync9 } from "node:fs";
|
|
14378
|
-
import { join as
|
|
16149
|
+
import { join as join23 } from "node:path";
|
|
14379
16150
|
function createEditHistoryLogger(repoRoot, sessionId) {
|
|
14380
|
-
const historyDir =
|
|
14381
|
-
const logPath =
|
|
16151
|
+
const historyDir = join23(repoRoot, ".oa", "history");
|
|
16152
|
+
const logPath = join23(historyDir, "edits.jsonl");
|
|
14382
16153
|
try {
|
|
14383
16154
|
mkdirSync9(historyDir, { recursive: true });
|
|
14384
16155
|
} catch {
|
|
@@ -14490,7 +16261,7 @@ var init_edit_history = __esm({
|
|
|
14490
16261
|
|
|
14491
16262
|
// packages/cli/dist/tui/dream-engine.js
|
|
14492
16263
|
import { mkdirSync as mkdirSync10, writeFileSync as writeFileSync9, readFileSync as readFileSync13, existsSync as existsSync16, cpSync, rmSync, readdirSync as readdirSync8 } from "node:fs";
|
|
14493
|
-
import { join as
|
|
16264
|
+
import { join as join24, basename as basename6 } from "node:path";
|
|
14494
16265
|
import { execSync as execSync13 } from "node:child_process";
|
|
14495
16266
|
function adaptTool(tool) {
|
|
14496
16267
|
return {
|
|
@@ -14665,12 +16436,12 @@ var init_dream_engine = __esm({
|
|
|
14665
16436
|
const content = String(args["content"] ?? "");
|
|
14666
16437
|
if (!rawPath)
|
|
14667
16438
|
return { success: false, output: "", error: "path is required", durationMs: Date.now() - start };
|
|
14668
|
-
const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ?
|
|
16439
|
+
const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join24(this.dreamsDir, basename6(rawPath)) : join24(this.dreamsDir, rawPath);
|
|
14669
16440
|
if (!targetPath.startsWith(this.dreamsDir)) {
|
|
14670
16441
|
return { success: false, output: "", error: "Dream mode: writes are confined to .oa/dreams/", durationMs: Date.now() - start };
|
|
14671
16442
|
}
|
|
14672
16443
|
try {
|
|
14673
|
-
const dir =
|
|
16444
|
+
const dir = join24(targetPath, "..");
|
|
14674
16445
|
mkdirSync10(dir, { recursive: true });
|
|
14675
16446
|
writeFileSync9(targetPath, content, "utf-8");
|
|
14676
16447
|
return { success: true, output: `Wrote ${content.length} bytes to ${rawPath}`, durationMs: Date.now() - start };
|
|
@@ -14700,7 +16471,7 @@ var init_dream_engine = __esm({
|
|
|
14700
16471
|
const rawPath = String(args["path"] ?? "");
|
|
14701
16472
|
const oldStr = String(args["old_string"] ?? "");
|
|
14702
16473
|
const newStr = String(args["new_string"] ?? "");
|
|
14703
|
-
const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ?
|
|
16474
|
+
const targetPath = rawPath.startsWith("/") || rawPath.startsWith(".oa/dreams") ? join24(this.dreamsDir, basename6(rawPath)) : join24(this.dreamsDir, rawPath);
|
|
14704
16475
|
if (!targetPath.startsWith(this.dreamsDir)) {
|
|
14705
16476
|
return { success: false, output: "", error: "Dream mode: edits are confined to .oa/dreams/", durationMs: Date.now() - start };
|
|
14706
16477
|
}
|
|
@@ -14767,7 +16538,7 @@ var init_dream_engine = __esm({
|
|
|
14767
16538
|
constructor(config, repoRoot) {
|
|
14768
16539
|
this.config = config;
|
|
14769
16540
|
this.repoRoot = repoRoot;
|
|
14770
|
-
this.dreamsDir =
|
|
16541
|
+
this.dreamsDir = join24(repoRoot, ".oa", "dreams");
|
|
14771
16542
|
this.state = {
|
|
14772
16543
|
mode: "default",
|
|
14773
16544
|
active: false,
|
|
@@ -14839,7 +16610,7 @@ ${result.summary}`;
|
|
|
14839
16610
|
if (mode !== "default" || cycle === totalCycles) {
|
|
14840
16611
|
renderDreamContraction(cycle);
|
|
14841
16612
|
const cycleSummary = this.buildCycleSummary(cycle, previousFindings);
|
|
14842
|
-
const summaryPath =
|
|
16613
|
+
const summaryPath = join24(this.dreamsDir, `cycle-${cycle}-summary.md`);
|
|
14843
16614
|
writeFileSync9(summaryPath, cycleSummary, "utf-8");
|
|
14844
16615
|
}
|
|
14845
16616
|
if (mode === "lucid" && !this.abortController.signal.aborted) {
|
|
@@ -14960,7 +16731,7 @@ Dreams directory: ${this.dreamsDir}`);
|
|
|
14960
16731
|
}
|
|
14961
16732
|
/** Save workspace backup for lucid mode */
|
|
14962
16733
|
saveVersionCheckpoint(cycle) {
|
|
14963
|
-
const checkpointDir =
|
|
16734
|
+
const checkpointDir = join24(this.dreamsDir, "checkpoints", `cycle-${cycle}`);
|
|
14964
16735
|
try {
|
|
14965
16736
|
mkdirSync10(checkpointDir, { recursive: true });
|
|
14966
16737
|
try {
|
|
@@ -14979,10 +16750,10 @@ Dreams directory: ${this.dreamsDir}`);
|
|
|
14979
16750
|
encoding: "utf-8",
|
|
14980
16751
|
timeout: 5e3
|
|
14981
16752
|
}).trim();
|
|
14982
|
-
writeFileSync9(
|
|
14983
|
-
writeFileSync9(
|
|
14984
|
-
writeFileSync9(
|
|
14985
|
-
writeFileSync9(
|
|
16753
|
+
writeFileSync9(join24(checkpointDir, "git-status.txt"), gitStatus, "utf-8");
|
|
16754
|
+
writeFileSync9(join24(checkpointDir, "git-diff.patch"), gitDiff, "utf-8");
|
|
16755
|
+
writeFileSync9(join24(checkpointDir, "git-hash.txt"), gitHash, "utf-8");
|
|
16756
|
+
writeFileSync9(join24(checkpointDir, "checkpoint.json"), JSON.stringify({
|
|
14986
16757
|
cycle,
|
|
14987
16758
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
14988
16759
|
gitHash,
|
|
@@ -14990,7 +16761,7 @@ Dreams directory: ${this.dreamsDir}`);
|
|
|
14990
16761
|
}, null, 2), "utf-8");
|
|
14991
16762
|
renderInfo(`Checkpoint saved: cycle ${cycle} (${gitHash.slice(0, 8)})`);
|
|
14992
16763
|
} catch {
|
|
14993
|
-
writeFileSync9(
|
|
16764
|
+
writeFileSync9(join24(checkpointDir, "checkpoint.json"), JSON.stringify({ cycle, timestamp: (/* @__PURE__ */ new Date()).toISOString(), mode: this.state.mode }, null, 2), "utf-8");
|
|
14994
16765
|
renderInfo(`Checkpoint saved: cycle ${cycle} (no git)`);
|
|
14995
16766
|
}
|
|
14996
16767
|
} catch (err) {
|
|
@@ -15048,14 +16819,14 @@ ${files.map((f) => `- [\`${f}\`](./${f})`).join("\n")}
|
|
|
15048
16819
|
---
|
|
15049
16820
|
*Auto-generated by open-agents dream engine*
|
|
15050
16821
|
`;
|
|
15051
|
-
writeFileSync9(
|
|
16822
|
+
writeFileSync9(join24(this.dreamsDir, "PROPOSAL-INDEX.md"), index, "utf-8");
|
|
15052
16823
|
} catch {
|
|
15053
16824
|
}
|
|
15054
16825
|
}
|
|
15055
16826
|
/** Save dream state for resume/inspection */
|
|
15056
16827
|
saveDreamState() {
|
|
15057
16828
|
try {
|
|
15058
|
-
writeFileSync9(
|
|
16829
|
+
writeFileSync9(join24(this.dreamsDir, "dream-state.json"), JSON.stringify(this.state, null, 2) + "\n", "utf-8");
|
|
15059
16830
|
} catch {
|
|
15060
16831
|
}
|
|
15061
16832
|
}
|
|
@@ -15291,13 +17062,18 @@ var init_status_bar = __esm({
|
|
|
15291
17062
|
const ctxPct = ctxTotal > 0 ? Math.max(0, Math.min(100, Math.round((1 - ctxUsed / ctxTotal) * 100))) : 100;
|
|
15292
17063
|
const ctxColor = ctxPct > 50 ? c2.green : ctxPct > 20 ? c2.yellow : c2.red;
|
|
15293
17064
|
const ctxLabel = pastel2(153, "Ctx: ") + c2.bold(`${ctxUsed.toLocaleString()}/${ctxTotal.toLocaleString()}`) + ` ${ctxColor(`${ctxPct}%`)}`;
|
|
17065
|
+
let costLabel = "";
|
|
17066
|
+
if (m.hasPricing && m.estimatedCost !== void 0) {
|
|
17067
|
+
const costStr = m.estimatedCost < 0.01 ? `$${m.estimatedCost.toFixed(4)}` : m.estimatedCost < 1 ? `$${m.estimatedCost.toFixed(3)}` : `$${m.estimatedCost.toFixed(2)}`;
|
|
17068
|
+
costLabel = pipe + pastel2(222, "Cost: ") + c2.bold(costStr);
|
|
17069
|
+
}
|
|
15294
17070
|
let recordingLabel = "";
|
|
15295
17071
|
if (this._recording) {
|
|
15296
17072
|
const dot = this._recBlink ? pastel2(210, "\u25CF") : " ";
|
|
15297
17073
|
const countdown = this._countdown > 0 ? c2.dim(` ${this._countdown}s`) : "";
|
|
15298
17074
|
recordingLabel = pipe + dot + pastel2(210, " REC") + countdown;
|
|
15299
17075
|
}
|
|
15300
|
-
return ` ${tokInLabel}${pipe}${tokOutLabel}${pipe}${ctxLabel}${recordingLabel}`;
|
|
17076
|
+
return ` ${tokInLabel}${pipe}${tokOutLabel}${pipe}${ctxLabel}${costLabel}${recordingLabel}`;
|
|
15301
17077
|
}
|
|
15302
17078
|
// -------------------------------------------------------------------------
|
|
15303
17079
|
// Private
|
|
@@ -15424,19 +17200,19 @@ var init_status_bar = __esm({
|
|
|
15424
17200
|
import * as readline2 from "node:readline";
|
|
15425
17201
|
import { Writable } from "node:stream";
|
|
15426
17202
|
import { cwd } from "node:process";
|
|
15427
|
-
import { resolve as
|
|
17203
|
+
import { resolve as resolve15, join as join25, dirname as dirname5, extname as extname8 } from "node:path";
|
|
15428
17204
|
import { createRequire as createRequire2 } from "node:module";
|
|
15429
|
-
import { fileURLToPath } from "node:url";
|
|
17205
|
+
import { fileURLToPath as fileURLToPath2 } from "node:url";
|
|
15430
17206
|
import { readFileSync as readFileSync14 } from "node:fs";
|
|
15431
17207
|
import { existsSync as existsSync17 } from "node:fs";
|
|
15432
17208
|
function getVersion() {
|
|
15433
17209
|
try {
|
|
15434
17210
|
const require2 = createRequire2(import.meta.url);
|
|
15435
|
-
const thisDir =
|
|
17211
|
+
const thisDir = dirname5(fileURLToPath2(import.meta.url));
|
|
15436
17212
|
const candidates = [
|
|
15437
|
-
|
|
15438
|
-
|
|
15439
|
-
|
|
17213
|
+
join25(thisDir, "..", "package.json"),
|
|
17214
|
+
join25(thisDir, "..", "..", "package.json"),
|
|
17215
|
+
join25(thisDir, "..", "..", "..", "package.json")
|
|
15440
17216
|
];
|
|
15441
17217
|
for (const pkgPath of candidates) {
|
|
15442
17218
|
if (existsSync17(pkgPath)) {
|
|
@@ -15519,7 +17295,13 @@ function buildTools(repoRoot, config) {
|
|
|
15519
17295
|
new SkillExecuteTool(repoRoot),
|
|
15520
17296
|
// Transcription tools (transcribe-cli / faster-whisper)
|
|
15521
17297
|
new TranscribeFileTool(repoRoot),
|
|
15522
|
-
new TranscribeUrlTool(repoRoot)
|
|
17298
|
+
new TranscribeUrlTool(repoRoot),
|
|
17299
|
+
// Structured file generation (CSV, JSON, Markdown, Excel-compatible)
|
|
17300
|
+
new StructuredFileTool(repoRoot),
|
|
17301
|
+
// Code sandbox (isolated code execution)
|
|
17302
|
+
new CodeSandboxTool(repoRoot),
|
|
17303
|
+
// Structured file reading (CSV, JSON, Markdown, binary detection)
|
|
17304
|
+
new StructuredReadTool(repoRoot)
|
|
15523
17305
|
];
|
|
15524
17306
|
return [
|
|
15525
17307
|
...executionTools.map(adaptTool2),
|
|
@@ -15599,9 +17381,12 @@ Use task_status("${taskId}") or task_output("${taskId}") to check progress.`
|
|
|
15599
17381
|
}
|
|
15600
17382
|
};
|
|
15601
17383
|
}
|
|
15602
|
-
function startTask(task, config, repoRoot, voice, stream, taskStores, bruteForce, statusBar, sudoCallback) {
|
|
17384
|
+
function startTask(task, config, repoRoot, voice, stream, taskStores, bruteForce, statusBar, sudoCallback, costTracker, onComplete, taskType) {
|
|
15603
17385
|
const projectCtx = buildProjectContext(repoRoot, taskStores?.contextStores);
|
|
15604
|
-
|
|
17386
|
+
let dynamicContext = formatContextForPrompt(projectCtx);
|
|
17387
|
+
if (taskType) {
|
|
17388
|
+
dynamicContext += "\n\n" + buildTaskContext(taskType);
|
|
17389
|
+
}
|
|
15605
17390
|
const backend = new OllamaAgenticBackend(config.backendUrl, config.model, config.apiKey);
|
|
15606
17391
|
const runner = new AgenticRunner(backend, {
|
|
15607
17392
|
maxTurns: 60,
|
|
@@ -15705,7 +17490,14 @@ function startTask(task, config, repoRoot, voice, stream, taskStores, bruteForce
|
|
|
15705
17490
|
break;
|
|
15706
17491
|
case "token_usage":
|
|
15707
17492
|
if (statusBar && event.tokenUsage) {
|
|
15708
|
-
|
|
17493
|
+
if (costTracker && event.tokenUsage.promptTokens > 0) {
|
|
17494
|
+
costTracker.trackTokens(event.tokenUsage.promptTokens, event.tokenUsage.completionTokens);
|
|
17495
|
+
}
|
|
17496
|
+
statusBar.updateMetrics({
|
|
17497
|
+
...event.tokenUsage,
|
|
17498
|
+
estimatedCost: costTracker?.currentCost,
|
|
17499
|
+
hasPricing: costTracker?.hasPricing
|
|
17500
|
+
});
|
|
15709
17501
|
}
|
|
15710
17502
|
break;
|
|
15711
17503
|
case "sudo_request":
|
|
@@ -15724,6 +17516,8 @@ function startTask(task, config, repoRoot, voice, stream, taskStores, bruteForce
|
|
|
15724
17516
|
contentWrite(() => {
|
|
15725
17517
|
if (result.completed) {
|
|
15726
17518
|
renderTaskComplete(result.summary, result.turns, result.toolCalls, result.durationMs, tokens);
|
|
17519
|
+
if (onComplete)
|
|
17520
|
+
onComplete(result.summary);
|
|
15727
17521
|
if (voice?.enabled && result.summary) {
|
|
15728
17522
|
const ttsText = result.summary.length > 300 ? result.summary.slice(0, 300) + "..." : result.summary;
|
|
15729
17523
|
voice.speak(`Task complete. ${ttsText}`);
|
|
@@ -15781,7 +17575,7 @@ function startTask(task, config, repoRoot, voice, stream, taskStores, bruteForce
|
|
|
15781
17575
|
} };
|
|
15782
17576
|
}
|
|
15783
17577
|
async function startInteractive(config, repoPath) {
|
|
15784
|
-
const repoRoot =
|
|
17578
|
+
const repoRoot = resolve15(repoPath ?? cwd());
|
|
15785
17579
|
const isResumed = !!process.env.__OA_RESUMED;
|
|
15786
17580
|
if (isResumed) {
|
|
15787
17581
|
delete process.env.__OA_RESUMED;
|
|
@@ -15850,8 +17644,8 @@ async function startInteractive(config, repoPath) {
|
|
|
15850
17644
|
if (!isResumed) {
|
|
15851
17645
|
try {
|
|
15852
17646
|
const baseUrl = normalizeBaseUrl(config.backendUrl);
|
|
15853
|
-
const
|
|
15854
|
-
const healthUrl = `${baseUrl}${
|
|
17647
|
+
const provider2 = detectProvider(config.backendUrl);
|
|
17648
|
+
const healthUrl = `${baseUrl}${provider2.modelsPath}`;
|
|
15855
17649
|
const headers = {};
|
|
15856
17650
|
if (config.apiKey) {
|
|
15857
17651
|
headers["Authorization"] = `Bearer ${config.apiKey}`;
|
|
@@ -15860,9 +17654,9 @@ async function startInteractive(config, repoPath) {
|
|
|
15860
17654
|
if (!resp.ok)
|
|
15861
17655
|
throw new Error(`HTTP ${resp.status}`);
|
|
15862
17656
|
} catch {
|
|
15863
|
-
const
|
|
15864
|
-
renderWarning(`Cannot reach ${
|
|
15865
|
-
if (
|
|
17657
|
+
const provider2 = detectProvider(config.backendUrl);
|
|
17658
|
+
renderWarning(`Cannot reach ${provider2.label} at ${config.backendUrl}`);
|
|
17659
|
+
if (provider2.id === "ollama") {
|
|
15866
17660
|
renderInfo("Start Ollama with: ollama serve");
|
|
15867
17661
|
}
|
|
15868
17662
|
renderInfo("Use /endpoint to configure a different backend. Starting anyway...");
|
|
@@ -15893,6 +17687,10 @@ async function startInteractive(config, repoPath) {
|
|
|
15893
17687
|
end: () => statusBar.endContentWrite()
|
|
15894
17688
|
});
|
|
15895
17689
|
}
|
|
17690
|
+
const provider = detectProvider(config.backendUrl);
|
|
17691
|
+
const costTracker = new CostTracker(provider.id);
|
|
17692
|
+
const sessionMetrics = new SessionMetrics();
|
|
17693
|
+
const workEvaluator = new WorkEvaluator();
|
|
15896
17694
|
ensureTranscribeCliBackground();
|
|
15897
17695
|
const voiceEngine = new VoiceEngine();
|
|
15898
17696
|
const streamRenderer = new StreamRenderer();
|
|
@@ -15910,6 +17708,8 @@ async function startInteractive(config, repoPath) {
|
|
|
15910
17708
|
let messageQueue = [];
|
|
15911
17709
|
let carouselRetired = isResumed;
|
|
15912
17710
|
let lastSubmittedPrompt = "";
|
|
17711
|
+
let lastCompletedSummary = "";
|
|
17712
|
+
let currentTaskType;
|
|
15913
17713
|
let sessionFilesTouched = [];
|
|
15914
17714
|
let sessionToolCallCount = 0;
|
|
15915
17715
|
let sessionSudoPassword = null;
|
|
@@ -15977,11 +17777,43 @@ async function startInteractive(config, repoPath) {
|
|
|
15977
17777
|
const sudoPromptStr = ` ${c2.bold(c2.yellow("\u{1F511} Password:"))} `;
|
|
15978
17778
|
process.stdout.write(sudoPromptStr);
|
|
15979
17779
|
}
|
|
17780
|
+
const evalBackend = {
|
|
17781
|
+
async evaluate(prompt) {
|
|
17782
|
+
const backend = new OllamaAgenticBackend(currentConfig.backendUrl, currentConfig.model, currentConfig.apiKey);
|
|
17783
|
+
const result = await backend.chatCompletion({
|
|
17784
|
+
messages: [
|
|
17785
|
+
{ role: "system", content: "You are a quality evaluator. Respond with JSON only." },
|
|
17786
|
+
{ role: "user", content: prompt }
|
|
17787
|
+
],
|
|
17788
|
+
tools: [],
|
|
17789
|
+
temperature: 0,
|
|
17790
|
+
maxTokens: 2048,
|
|
17791
|
+
timeoutMs: currentConfig.timeoutMs
|
|
17792
|
+
});
|
|
17793
|
+
return result.choices[0]?.message?.content ?? "";
|
|
17794
|
+
}
|
|
17795
|
+
};
|
|
17796
|
+
workEvaluator.setBackend(evalBackend);
|
|
15980
17797
|
const commandCtx = {
|
|
15981
17798
|
get config() {
|
|
15982
17799
|
return currentConfig;
|
|
15983
17800
|
},
|
|
15984
17801
|
repoRoot,
|
|
17802
|
+
costTracker,
|
|
17803
|
+
workEvaluator,
|
|
17804
|
+
get lastTask() {
|
|
17805
|
+
return lastSubmittedPrompt;
|
|
17806
|
+
},
|
|
17807
|
+
get lastSummary() {
|
|
17808
|
+
return lastCompletedSummary;
|
|
17809
|
+
},
|
|
17810
|
+
get taskType() {
|
|
17811
|
+
return currentTaskType;
|
|
17812
|
+
},
|
|
17813
|
+
setTaskType(type) {
|
|
17814
|
+
currentTaskType = type;
|
|
17815
|
+
},
|
|
17816
|
+
sessionMetrics,
|
|
15985
17817
|
setModel(model) {
|
|
15986
17818
|
currentConfig = { ...currentConfig, model };
|
|
15987
17819
|
},
|
|
@@ -15995,6 +17827,8 @@ async function startInteractive(config, repoPath) {
|
|
|
15995
17827
|
backendType,
|
|
15996
17828
|
...apiKey !== void 0 ? { apiKey } : {}
|
|
15997
17829
|
};
|
|
17830
|
+
const newProvider = detectProvider(url);
|
|
17831
|
+
costTracker.setProvider(newProvider.id);
|
|
15998
17832
|
},
|
|
15999
17833
|
clearScreen() {
|
|
16000
17834
|
process.stdout.write("\x1B[2J\x1B[H");
|
|
@@ -16270,7 +18104,9 @@ Execute this skill now. Follow the behavioral guidance above.`;
|
|
|
16270
18104
|
taskMemoryStore: taskMemoryStore ?? void 0,
|
|
16271
18105
|
failureStore: failureStore ?? void 0,
|
|
16272
18106
|
toolPatternStore: toolPatternStore ?? void 0
|
|
16273
|
-
}, bruteForceEnabled, statusBar, handleSudoRequest)
|
|
18107
|
+
}, bruteForceEnabled, statusBar, handleSudoRequest, costTracker, (summary) => {
|
|
18108
|
+
lastCompletedSummary = summary;
|
|
18109
|
+
}, currentTaskType);
|
|
16274
18110
|
activeTask = task;
|
|
16275
18111
|
showPrompt();
|
|
16276
18112
|
await task.promise;
|
|
@@ -16284,15 +18120,15 @@ Execute this skill now. Follow the behavioral guidance above.`;
|
|
|
16284
18120
|
}
|
|
16285
18121
|
}
|
|
16286
18122
|
const cleanPath = input.replace(/^['"]|['"]$/g, "").trim();
|
|
16287
|
-
const isImage = isImagePath(cleanPath) && existsSync17(
|
|
16288
|
-
const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync17(
|
|
18123
|
+
const isImage = isImagePath(cleanPath) && existsSync17(resolve15(repoRoot, cleanPath));
|
|
18124
|
+
const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync17(resolve15(repoRoot, cleanPath));
|
|
16289
18125
|
if (activeTask) {
|
|
16290
18126
|
if (isImage) {
|
|
16291
18127
|
try {
|
|
16292
|
-
const imgPath =
|
|
18128
|
+
const imgPath = resolve15(repoRoot, cleanPath);
|
|
16293
18129
|
const imgBuffer = readFileSync14(imgPath);
|
|
16294
18130
|
const base64 = imgBuffer.toString("base64");
|
|
16295
|
-
const ext =
|
|
18131
|
+
const ext = extname8(cleanPath).toLowerCase();
|
|
16296
18132
|
const mime = ext === ".png" ? "image/png" : ext === ".gif" ? "image/gif" : ext === ".webp" ? "image/webp" : "image/jpeg";
|
|
16297
18133
|
activeTask.runner.injectImage(base64, mime, `User shared image: ${cleanPath}`);
|
|
16298
18134
|
writeContent(() => renderUserInterrupt(`[Image: ${cleanPath}]`));
|
|
@@ -16303,7 +18139,7 @@ Execute this skill now. Follow the behavioral guidance above.`;
|
|
|
16303
18139
|
} else if (isMedia) {
|
|
16304
18140
|
writeContent(() => renderInfo(`Transcribing: ${cleanPath}...`));
|
|
16305
18141
|
const engine = getListenEngine();
|
|
16306
|
-
const result = await engine.transcribeFile(
|
|
18142
|
+
const result = await engine.transcribeFile(resolve15(repoRoot, cleanPath), repoRoot);
|
|
16307
18143
|
if (result) {
|
|
16308
18144
|
const transcript = `[Transcription of ${cleanPath}]
|
|
16309
18145
|
${result.text}`;
|
|
@@ -16336,7 +18172,7 @@ ${result.text}`;
|
|
|
16336
18172
|
if (isMedia && fullInput === input) {
|
|
16337
18173
|
writeContent(() => renderInfo(`Transcribing: ${cleanPath}...`));
|
|
16338
18174
|
const engine = getListenEngine();
|
|
16339
|
-
const result = await engine.transcribeFile(
|
|
18175
|
+
const result = await engine.transcribeFile(resolve15(repoRoot, cleanPath), repoRoot);
|
|
16340
18176
|
if (result) {
|
|
16341
18177
|
fullInput = `The user has provided an audio/video file: ${cleanPath}.
|
|
16342
18178
|
|
|
@@ -16368,7 +18204,9 @@ Summarize or analyze this transcription as appropriate.`;
|
|
|
16368
18204
|
taskMemoryStore: taskMemoryStore ?? void 0,
|
|
16369
18205
|
failureStore: failureStore ?? void 0,
|
|
16370
18206
|
toolPatternStore: toolPatternStore ?? void 0
|
|
16371
|
-
}, bruteForceEnabled, statusBar, handleSudoRequest)
|
|
18207
|
+
}, bruteForceEnabled, statusBar, handleSudoRequest, costTracker, (summary) => {
|
|
18208
|
+
lastCompletedSummary = summary;
|
|
18209
|
+
}, currentTaskType);
|
|
16372
18210
|
activeTask = task;
|
|
16373
18211
|
showPrompt();
|
|
16374
18212
|
await task.promise;
|
|
@@ -16452,7 +18290,7 @@ ${c2.dim("(Use /quit to exit)")}
|
|
|
16452
18290
|
});
|
|
16453
18291
|
}
|
|
16454
18292
|
async function runWithTUI(task, config, repoPath) {
|
|
16455
|
-
const repoRoot =
|
|
18293
|
+
const repoRoot = resolve15(repoPath ?? cwd());
|
|
16456
18294
|
const needsSetup = isFirstRun() || !await isModelAvailable(config);
|
|
16457
18295
|
if (needsSetup && config.backendType === "ollama") {
|
|
16458
18296
|
const setupModel = await runSetupWizard(config);
|
|
@@ -16510,7 +18348,7 @@ var init_interactive = __esm({
|
|
|
16510
18348
|
init_commands();
|
|
16511
18349
|
init_setup();
|
|
16512
18350
|
init_project_context();
|
|
16513
|
-
|
|
18351
|
+
init_dist7();
|
|
16514
18352
|
init_oa_directory();
|
|
16515
18353
|
init_render();
|
|
16516
18354
|
init_carousel();
|
|
@@ -16519,6 +18357,7 @@ var init_interactive = __esm({
|
|
|
16519
18357
|
init_edit_history();
|
|
16520
18358
|
init_dream_engine();
|
|
16521
18359
|
init_status_bar();
|
|
18360
|
+
init_dist6();
|
|
16522
18361
|
taskManager = new BackgroundTaskManager();
|
|
16523
18362
|
}
|
|
16524
18363
|
});
|
|
@@ -16552,9 +18391,9 @@ var init_run = __esm({
|
|
|
16552
18391
|
// packages/indexer/dist/codebase-indexer.js
|
|
16553
18392
|
import { glob } from "glob";
|
|
16554
18393
|
import ignore from "ignore";
|
|
16555
|
-
import { readFile as
|
|
18394
|
+
import { readFile as readFile10, stat as stat4 } from "node:fs/promises";
|
|
16556
18395
|
import { createHash } from "node:crypto";
|
|
16557
|
-
import { join as
|
|
18396
|
+
import { join as join26, relative as relative3, extname as extname9, basename as basename7 } from "node:path";
|
|
16558
18397
|
var DEFAULT_EXCLUDE, LANGUAGE_MAP, CodebaseIndexer;
|
|
16559
18398
|
var init_codebase_indexer = __esm({
|
|
16560
18399
|
"packages/indexer/dist/codebase-indexer.js"() {
|
|
@@ -16598,7 +18437,7 @@ var init_codebase_indexer = __esm({
|
|
|
16598
18437
|
const ig = ignore.default();
|
|
16599
18438
|
if (this.config.respectGitignore) {
|
|
16600
18439
|
try {
|
|
16601
|
-
const gitignoreContent = await
|
|
18440
|
+
const gitignoreContent = await readFile10(join26(this.config.rootDir, ".gitignore"), "utf-8");
|
|
16602
18441
|
ig.add(gitignoreContent);
|
|
16603
18442
|
} catch {
|
|
16604
18443
|
}
|
|
@@ -16613,14 +18452,14 @@ var init_codebase_indexer = __esm({
|
|
|
16613
18452
|
for (const relativePath of files) {
|
|
16614
18453
|
if (ig.ignores(relativePath))
|
|
16615
18454
|
continue;
|
|
16616
|
-
const fullPath =
|
|
18455
|
+
const fullPath = join26(this.config.rootDir, relativePath);
|
|
16617
18456
|
try {
|
|
16618
|
-
const fileStat = await
|
|
18457
|
+
const fileStat = await stat4(fullPath);
|
|
16619
18458
|
if (fileStat.size > this.config.maxFileSize)
|
|
16620
18459
|
continue;
|
|
16621
|
-
const content = await
|
|
18460
|
+
const content = await readFile10(fullPath);
|
|
16622
18461
|
const hash = createHash("sha256").update(content).digest("hex");
|
|
16623
|
-
const ext =
|
|
18462
|
+
const ext = extname9(relativePath);
|
|
16624
18463
|
indexed.push({
|
|
16625
18464
|
path: fullPath,
|
|
16626
18465
|
relativePath,
|
|
@@ -16659,7 +18498,7 @@ var init_codebase_indexer = __esm({
|
|
|
16659
18498
|
if (!child) {
|
|
16660
18499
|
child = {
|
|
16661
18500
|
name: part,
|
|
16662
|
-
path:
|
|
18501
|
+
path: join26(current.path, part),
|
|
16663
18502
|
type: "directory",
|
|
16664
18503
|
children: []
|
|
16665
18504
|
};
|
|
@@ -16716,7 +18555,7 @@ var init_embeddings = __esm({
|
|
|
16716
18555
|
});
|
|
16717
18556
|
|
|
16718
18557
|
// packages/indexer/dist/index.js
|
|
16719
|
-
var
|
|
18558
|
+
var init_dist8 = __esm({
|
|
16720
18559
|
"packages/indexer/dist/index.js"() {
|
|
16721
18560
|
"use strict";
|
|
16722
18561
|
init_codebase_indexer();
|
|
@@ -16733,19 +18572,19 @@ var index_repo_exports = {};
|
|
|
16733
18572
|
__export(index_repo_exports, {
|
|
16734
18573
|
indexRepoCommand: () => indexRepoCommand
|
|
16735
18574
|
});
|
|
16736
|
-
import { resolve as
|
|
18575
|
+
import { resolve as resolve16 } from "node:path";
|
|
16737
18576
|
import { existsSync as existsSync18, statSync as statSync6 } from "node:fs";
|
|
16738
18577
|
import { cwd as cwd2 } from "node:process";
|
|
16739
18578
|
async function indexRepoCommand(opts, _config) {
|
|
16740
|
-
const repoRoot =
|
|
18579
|
+
const repoRoot = resolve16(opts.repoPath ?? cwd2());
|
|
16741
18580
|
printHeader("Index Repository");
|
|
16742
18581
|
printInfo(`Indexing: ${repoRoot}`);
|
|
16743
18582
|
if (!existsSync18(repoRoot)) {
|
|
16744
18583
|
printError(`Path does not exist: ${repoRoot}`);
|
|
16745
18584
|
process.exit(1);
|
|
16746
18585
|
}
|
|
16747
|
-
const
|
|
16748
|
-
if (!
|
|
18586
|
+
const stat5 = statSync6(repoRoot);
|
|
18587
|
+
if (!stat5.isDirectory()) {
|
|
16749
18588
|
printError(`Path is not a directory: ${repoRoot}`);
|
|
16750
18589
|
process.exit(1);
|
|
16751
18590
|
}
|
|
@@ -16823,7 +18662,7 @@ async function indexRepoCommand(opts, _config) {
|
|
|
16823
18662
|
var init_index_repo = __esm({
|
|
16824
18663
|
"packages/cli/dist/commands/index-repo.js"() {
|
|
16825
18664
|
"use strict";
|
|
16826
|
-
|
|
18665
|
+
init_dist8();
|
|
16827
18666
|
init_spinner();
|
|
16828
18667
|
init_output();
|
|
16829
18668
|
}
|
|
@@ -16986,7 +18825,7 @@ var config_exports = {};
|
|
|
16986
18825
|
__export(config_exports, {
|
|
16987
18826
|
configCommand: () => configCommand
|
|
16988
18827
|
});
|
|
16989
|
-
import { join as
|
|
18828
|
+
import { join as join27, resolve as resolve17 } from "node:path";
|
|
16990
18829
|
import { homedir as homedir11 } from "node:os";
|
|
16991
18830
|
import { cwd as cwd3 } from "node:process";
|
|
16992
18831
|
function coerceForSettings(key, value) {
|
|
@@ -17007,7 +18846,7 @@ async function configCommand(opts, config) {
|
|
|
17007
18846
|
return handleShow(opts, config);
|
|
17008
18847
|
}
|
|
17009
18848
|
function handleShow(opts, config) {
|
|
17010
|
-
const repoRoot =
|
|
18849
|
+
const repoRoot = resolve17(opts.repoPath ?? cwd3());
|
|
17011
18850
|
printHeader("Configuration");
|
|
17012
18851
|
printSection("Active Settings (merged)");
|
|
17013
18852
|
printKeyValue("backendUrl", config.backendUrl, 2);
|
|
@@ -17039,7 +18878,7 @@ function handleShow(opts, config) {
|
|
|
17039
18878
|
}
|
|
17040
18879
|
}
|
|
17041
18880
|
printSection("Config File");
|
|
17042
|
-
printInfo(`~/.open-agents/config.json (${
|
|
18881
|
+
printInfo(`~/.open-agents/config.json (${join27(homedir11(), ".open-agents", "config.json")})`);
|
|
17043
18882
|
printSection("Priority Chain");
|
|
17044
18883
|
printInfo(" 1. CLI flags (--model, --backend-url, etc.)");
|
|
17045
18884
|
printInfo(" 2. Project .oa/settings.json (--local)");
|
|
@@ -17072,13 +18911,13 @@ function handleSet(opts, _config) {
|
|
|
17072
18911
|
process.exit(1);
|
|
17073
18912
|
}
|
|
17074
18913
|
if (opts.local) {
|
|
17075
|
-
const repoRoot =
|
|
18914
|
+
const repoRoot = resolve17(opts.repoPath ?? cwd3());
|
|
17076
18915
|
try {
|
|
17077
18916
|
initOaDirectory(repoRoot);
|
|
17078
18917
|
const coerced = coerceForSettings(key, value);
|
|
17079
18918
|
saveProjectSettings(repoRoot, { [key]: coerced });
|
|
17080
18919
|
printSuccess(`Project override set: ${key} = ${value}`);
|
|
17081
|
-
printInfo(`Saved to ${
|
|
18920
|
+
printInfo(`Saved to ${join27(repoRoot, ".oa", "settings.json")}`);
|
|
17082
18921
|
printInfo("This override applies only when running in this workspace.");
|
|
17083
18922
|
} catch (err) {
|
|
17084
18923
|
printError(`Failed to save: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -17138,7 +18977,7 @@ var serve_exports = {};
|
|
|
17138
18977
|
__export(serve_exports, {
|
|
17139
18978
|
serveCommand: () => serveCommand
|
|
17140
18979
|
});
|
|
17141
|
-
import { spawn as
|
|
18980
|
+
import { spawn as spawn7 } from "node:child_process";
|
|
17142
18981
|
async function serveCommand(opts, config) {
|
|
17143
18982
|
const backendType = config.backendType;
|
|
17144
18983
|
if (backendType === "ollama") {
|
|
@@ -17230,8 +19069,8 @@ async function serveVllm(opts, config) {
|
|
|
17230
19069
|
await runVllmServer(args, opts.verbose ?? false);
|
|
17231
19070
|
}
|
|
17232
19071
|
async function runVllmServer(args, verbose) {
|
|
17233
|
-
return new Promise((
|
|
17234
|
-
const child =
|
|
19072
|
+
return new Promise((resolve18, reject) => {
|
|
19073
|
+
const child = spawn7("python", args, {
|
|
17235
19074
|
stdio: verbose ? "inherit" : ["ignore", "pipe", "pipe"],
|
|
17236
19075
|
env: { ...process.env }
|
|
17237
19076
|
});
|
|
@@ -17265,10 +19104,10 @@ async function runVllmServer(args, verbose) {
|
|
|
17265
19104
|
child.once("exit", (code, signal) => {
|
|
17266
19105
|
if (signal) {
|
|
17267
19106
|
printInfo(`vLLM server stopped by signal ${signal}`);
|
|
17268
|
-
|
|
19107
|
+
resolve18();
|
|
17269
19108
|
} else if (code === 0) {
|
|
17270
19109
|
printSuccess("vLLM server exited cleanly");
|
|
17271
|
-
|
|
19110
|
+
resolve18();
|
|
17272
19111
|
} else {
|
|
17273
19112
|
printError(`vLLM server exited with code ${code}`);
|
|
17274
19113
|
reject(new Error(`vLLM exited with code ${code}`));
|
|
@@ -17295,9 +19134,9 @@ var eval_exports = {};
|
|
|
17295
19134
|
__export(eval_exports, {
|
|
17296
19135
|
evalCommand: () => evalCommand
|
|
17297
19136
|
});
|
|
17298
|
-
import { tmpdir as
|
|
19137
|
+
import { tmpdir as tmpdir4 } from "node:os";
|
|
17299
19138
|
import { mkdirSync as mkdirSync11, writeFileSync as writeFileSync10 } from "node:fs";
|
|
17300
|
-
import { join as
|
|
19139
|
+
import { join as join28 } from "node:path";
|
|
17301
19140
|
async function evalCommand(opts, config) {
|
|
17302
19141
|
const suiteName = opts.suite ?? "basic";
|
|
17303
19142
|
const suite = SUITES[suiteName];
|
|
@@ -17418,9 +19257,9 @@ async function evalCommand(opts, config) {
|
|
|
17418
19257
|
process.exit(failed > 0 ? 1 : 0);
|
|
17419
19258
|
}
|
|
17420
19259
|
function createTempEvalRepo() {
|
|
17421
|
-
const dir =
|
|
19260
|
+
const dir = join28(tmpdir4(), `open-agents-eval-${Date.now()}`);
|
|
17422
19261
|
mkdirSync11(dir, { recursive: true });
|
|
17423
|
-
writeFileSync10(
|
|
19262
|
+
writeFileSync10(join28(dir, "package.json"), JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n", "utf8");
|
|
17424
19263
|
return dir;
|
|
17425
19264
|
}
|
|
17426
19265
|
var BASIC_SUITE, FULL_SUITE, SUITES;
|
|
@@ -17479,8 +19318,8 @@ init_output();
|
|
|
17479
19318
|
init_updater();
|
|
17480
19319
|
import { parseArgs as nodeParseArgs2 } from "node:util";
|
|
17481
19320
|
import { createRequire as createRequire3 } from "node:module";
|
|
17482
|
-
import { fileURLToPath as
|
|
17483
|
-
import { dirname as
|
|
19321
|
+
import { fileURLToPath as fileURLToPath3 } from "node:url";
|
|
19322
|
+
import { dirname as dirname6, join as join29 } from "node:path";
|
|
17484
19323
|
|
|
17485
19324
|
// packages/cli/dist/cli.js
|
|
17486
19325
|
import { createInterface } from "node:readline";
|
|
@@ -17587,7 +19426,7 @@ init_output();
|
|
|
17587
19426
|
function getVersion2() {
|
|
17588
19427
|
try {
|
|
17589
19428
|
const require2 = createRequire3(import.meta.url);
|
|
17590
|
-
const pkgPath =
|
|
19429
|
+
const pkgPath = join29(dirname6(fileURLToPath3(import.meta.url)), "..", "package.json");
|
|
17591
19430
|
const pkg = require2(pkgPath);
|
|
17592
19431
|
return pkg.version;
|
|
17593
19432
|
} catch {
|