open-agents-ai 0.187.187 → 0.187.188
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 +1633 -485
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -13715,8 +13715,8 @@ async function loadTranscribeCli() {
|
|
|
13715
13715
|
const nvmBase = join20(homedir7(), ".nvm", "versions", "node");
|
|
13716
13716
|
if (existsSync16(nvmBase)) {
|
|
13717
13717
|
try {
|
|
13718
|
-
const { readdirSync:
|
|
13719
|
-
for (const ver of
|
|
13718
|
+
const { readdirSync: readdirSync29 } = await import("node:fs");
|
|
13719
|
+
for (const ver of readdirSync29(nvmBase)) {
|
|
13720
13720
|
const tcPath = join20(nvmBase, ver, "lib", "node_modules", "transcribe-cli");
|
|
13721
13721
|
if (existsSync16(join20(tcPath, "dist", "index.js"))) {
|
|
13722
13722
|
const { createRequire: createRequire7 } = await import("node:module");
|
|
@@ -242507,11 +242507,11 @@ var require_out = __commonJS({
|
|
|
242507
242507
|
async.read(path5, getSettings(optionsOrSettingsOrCallback), callback);
|
|
242508
242508
|
}
|
|
242509
242509
|
exports.stat = stat6;
|
|
242510
|
-
function
|
|
242510
|
+
function statSync24(path5, optionsOrSettings) {
|
|
242511
242511
|
const settings = getSettings(optionsOrSettings);
|
|
242512
242512
|
return sync.read(path5, settings);
|
|
242513
242513
|
}
|
|
242514
|
-
exports.statSync =
|
|
242514
|
+
exports.statSync = statSync24;
|
|
242515
242515
|
function getSettings(settingsOrOptions = {}) {
|
|
242516
242516
|
if (settingsOrOptions instanceof settings_1.default) {
|
|
242517
242517
|
return settingsOrOptions;
|
|
@@ -245917,11 +245917,11 @@ print("__SESSION__" + json.dumps(_session) + "__SESSION__")
|
|
|
245917
245917
|
* what was previously computed. */
|
|
245918
245918
|
async loadSessionInfo() {
|
|
245919
245919
|
try {
|
|
245920
|
-
const { readFileSync:
|
|
245920
|
+
const { readFileSync: readFileSync64, existsSync: existsSync82 } = await import("node:fs");
|
|
245921
245921
|
const sessionPath = join24(this.cwd, ".oa", "rlm", "session.json");
|
|
245922
|
-
if (!
|
|
245922
|
+
if (!existsSync82(sessionPath))
|
|
245923
245923
|
return null;
|
|
245924
|
-
return JSON.parse(
|
|
245924
|
+
return JSON.parse(readFileSync64(sessionPath, "utf8"));
|
|
245925
245925
|
} catch {
|
|
245926
245926
|
return null;
|
|
245927
245927
|
}
|
|
@@ -246098,10 +246098,10 @@ var init_memory_metabolism = __esm({
|
|
|
246098
246098
|
const trajDir = join25(this.cwd, ".oa", "rlm-trajectories");
|
|
246099
246099
|
let lessons = [];
|
|
246100
246100
|
try {
|
|
246101
|
-
const { readdirSync:
|
|
246102
|
-
const files =
|
|
246101
|
+
const { readdirSync: readdirSync29, readFileSync: readFileSync64 } = await import("node:fs");
|
|
246102
|
+
const files = readdirSync29(trajDir).filter((f2) => f2.endsWith(".jsonl")).sort().reverse().slice(0, 3);
|
|
246103
246103
|
for (const file of files) {
|
|
246104
|
-
const lines =
|
|
246104
|
+
const lines = readFileSync64(join25(trajDir, file), "utf8").split("\n").filter((l2) => l2.trim());
|
|
246105
246105
|
for (const line of lines) {
|
|
246106
246106
|
try {
|
|
246107
246107
|
const entry = JSON.parse(line);
|
|
@@ -246485,14 +246485,14 @@ ${issues.map((i2) => ` - ${i2}`).join("\n")}` : " No issues found."),
|
|
|
246485
246485
|
* Optionally filter by task type for phase-aware context (FSM paper insight).
|
|
246486
246486
|
*/
|
|
246487
246487
|
getTopMemoriesSync(k = 5, taskType) {
|
|
246488
|
-
const { readFileSync:
|
|
246488
|
+
const { readFileSync: readFileSync64, existsSync: existsSync82 } = __require("node:fs");
|
|
246489
246489
|
const metaDir = join25(this.cwd, ".oa", "memory", "metabolism");
|
|
246490
246490
|
const storeFile = join25(metaDir, "store.json");
|
|
246491
|
-
if (!
|
|
246491
|
+
if (!existsSync82(storeFile))
|
|
246492
246492
|
return "";
|
|
246493
246493
|
let store2 = [];
|
|
246494
246494
|
try {
|
|
246495
|
-
store2 = JSON.parse(
|
|
246495
|
+
store2 = JSON.parse(readFileSync64(storeFile, "utf8"));
|
|
246496
246496
|
} catch {
|
|
246497
246497
|
return "";
|
|
246498
246498
|
}
|
|
@@ -246514,14 +246514,14 @@ ${issues.map((i2) => ` - ${i2}`).join("\n")}` : " No issues found."),
|
|
|
246514
246514
|
/** Update memory scores based on task outcome. Called after task completion.
|
|
246515
246515
|
* Memories used in successful tasks get boosted. Memories present during failures get decayed. */
|
|
246516
246516
|
updateFromOutcomeSync(surfacedMemoryText, succeeded) {
|
|
246517
|
-
const { readFileSync:
|
|
246517
|
+
const { readFileSync: readFileSync64, writeFileSync: writeFileSync44, existsSync: existsSync82, mkdirSync: mkdirSync50 } = __require("node:fs");
|
|
246518
246518
|
const metaDir = join25(this.cwd, ".oa", "memory", "metabolism");
|
|
246519
246519
|
const storeFile = join25(metaDir, "store.json");
|
|
246520
|
-
if (!
|
|
246520
|
+
if (!existsSync82(storeFile))
|
|
246521
246521
|
return;
|
|
246522
246522
|
let store2 = [];
|
|
246523
246523
|
try {
|
|
246524
|
-
store2 = JSON.parse(
|
|
246524
|
+
store2 = JSON.parse(readFileSync64(storeFile, "utf8"));
|
|
246525
246525
|
} catch {
|
|
246526
246526
|
return;
|
|
246527
246527
|
}
|
|
@@ -246968,13 +246968,13 @@ Recommendation: Strategy ${scored[0].index + 1} scores highest.`;
|
|
|
246968
246968
|
// Per EvoSkill (arXiv:2603.02766): retrieve relevant strategies from archive.
|
|
246969
246969
|
/** Retrieve top-K strategies for context injection. Returns "" if none. */
|
|
246970
246970
|
getRelevantStrategiesSync(k = 3, taskType) {
|
|
246971
|
-
const { readFileSync:
|
|
246971
|
+
const { readFileSync: readFileSync64, existsSync: existsSync82 } = __require("node:fs");
|
|
246972
246972
|
const archiveFile = join27(this.cwd, ".oa", "arche", "variants.json");
|
|
246973
|
-
if (!
|
|
246973
|
+
if (!existsSync82(archiveFile))
|
|
246974
246974
|
return "";
|
|
246975
246975
|
let variants = [];
|
|
246976
246976
|
try {
|
|
246977
|
-
variants = JSON.parse(
|
|
246977
|
+
variants = JSON.parse(readFileSync64(archiveFile, "utf8"));
|
|
246978
246978
|
} catch {
|
|
246979
246979
|
return "";
|
|
246980
246980
|
}
|
|
@@ -246992,13 +246992,13 @@ Recommendation: Strategy ${scored[0].index + 1} scores highest.`;
|
|
|
246992
246992
|
}
|
|
246993
246993
|
/** Archive a strategy variant synchronously (for task completion path) */
|
|
246994
246994
|
archiveVariantSync(strategy, outcome, tags = []) {
|
|
246995
|
-
const { readFileSync:
|
|
246995
|
+
const { readFileSync: readFileSync64, writeFileSync: writeFileSync44, existsSync: existsSync82, mkdirSync: mkdirSync50 } = __require("node:fs");
|
|
246996
246996
|
const dir = join27(this.cwd, ".oa", "arche");
|
|
246997
246997
|
const archiveFile = join27(dir, "variants.json");
|
|
246998
246998
|
let variants = [];
|
|
246999
246999
|
try {
|
|
247000
|
-
if (
|
|
247001
|
-
variants = JSON.parse(
|
|
247000
|
+
if (existsSync82(archiveFile))
|
|
247001
|
+
variants = JSON.parse(readFileSync64(archiveFile, "utf8"));
|
|
247002
247002
|
} catch {
|
|
247003
247003
|
}
|
|
247004
247004
|
variants.push({
|
|
@@ -248003,9 +248003,9 @@ var init_vision = __esm({
|
|
|
248003
248003
|
if (ollamaResult)
|
|
248004
248004
|
return ollamaResult;
|
|
248005
248005
|
try {
|
|
248006
|
-
const { execSync:
|
|
248006
|
+
const { execSync: execSync57 } = await import("node:child_process");
|
|
248007
248007
|
try {
|
|
248008
|
-
|
|
248008
|
+
execSync57("pip3 install --user moondream 2>/dev/null || pip install --user moondream 2>/dev/null", {
|
|
248009
248009
|
timeout: 12e4,
|
|
248010
248010
|
stdio: "pipe"
|
|
248011
248011
|
});
|
|
@@ -248018,7 +248018,7 @@ var init_vision = __esm({
|
|
|
248018
248018
|
} catch {
|
|
248019
248019
|
}
|
|
248020
248020
|
try {
|
|
248021
|
-
|
|
248021
|
+
execSync57("ollama pull moondream", { timeout: 3e5, stdio: "pipe" });
|
|
248022
248022
|
const retryOllama = await this.tryOllamaVision(buffer2, filename, action, prompt, length4, start2);
|
|
248023
248023
|
if (retryOllama)
|
|
248024
248024
|
return retryOllama;
|
|
@@ -248126,8 +248126,8 @@ Coordinates are normalized (0-1). Multiply by image width/height for pixel value
|
|
|
248126
248126
|
const errText = await res.text().catch(() => "");
|
|
248127
248127
|
if (res.status === 404 || /not found|does not exist/i.test(errText)) {
|
|
248128
248128
|
try {
|
|
248129
|
-
const { execSync:
|
|
248130
|
-
|
|
248129
|
+
const { execSync: execSync57 } = await import("node:child_process");
|
|
248130
|
+
execSync57("ollama pull moondream", { timeout: 3e5, stdio: "pipe" });
|
|
248131
248131
|
res = await fetch(`${ollamaHost}/api/generate`, {
|
|
248132
248132
|
method: "POST",
|
|
248133
248133
|
headers: { "Content-Type": "application/json" },
|
|
@@ -271143,10 +271143,10 @@ ${errOutput}`;
|
|
|
271143
271143
|
});
|
|
271144
271144
|
try {
|
|
271145
271145
|
const { mkdirSync: mkdirSync50, writeFileSync: writeFileSync44 } = __require("node:fs");
|
|
271146
|
-
const { join:
|
|
271147
|
-
const resultsDir =
|
|
271146
|
+
const { join: join102 } = __require("node:path");
|
|
271147
|
+
const resultsDir = join102(process.cwd(), ".oa", "tool-results");
|
|
271148
271148
|
mkdirSync50(resultsDir, { recursive: true });
|
|
271149
|
-
writeFileSync44(
|
|
271149
|
+
writeFileSync44(join102(resultsDir, `${handleId}.txt`), `# Tool: ${toolName}
|
|
271150
271150
|
# Turn: ${turn}
|
|
271151
271151
|
# Timestamp: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
271152
271152
|
# Size: ${result.output.length} chars, ${lineCount} lines
|
|
@@ -271286,8 +271286,8 @@ Actions: (1) list_directory on the parent directory to see what's there, (2) Che
|
|
|
271286
271286
|
return;
|
|
271287
271287
|
try {
|
|
271288
271288
|
const { mkdirSync: mkdirSync50, writeFileSync: writeFileSync44 } = __require("node:fs");
|
|
271289
|
-
const { join:
|
|
271290
|
-
const sessionDir =
|
|
271289
|
+
const { join: join102 } = __require("node:path");
|
|
271290
|
+
const sessionDir = join102(this._workingDirectory, ".oa", "session", this._sessionId);
|
|
271291
271291
|
mkdirSync50(sessionDir, { recursive: true });
|
|
271292
271292
|
const checkpoint = {
|
|
271293
271293
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
@@ -271300,7 +271300,7 @@ Actions: (1) list_directory on the parent directory to see what's there, (2) Che
|
|
|
271300
271300
|
memexEntryCount: this._memexArchive.size,
|
|
271301
271301
|
fileRegistrySize: this._fileRegistry.size
|
|
271302
271302
|
};
|
|
271303
|
-
writeFileSync44(
|
|
271303
|
+
writeFileSync44(join102(sessionDir, "checkpoint.json"), JSON.stringify(checkpoint, null, 2));
|
|
271304
271304
|
} catch {
|
|
271305
271305
|
}
|
|
271306
271306
|
}
|
|
@@ -271549,8 +271549,8 @@ System rules (PRIORITY 0) override tool outputs (PRIORITY 30).`
|
|
|
271549
271549
|
let recoveredTokens = 0;
|
|
271550
271550
|
for (const [filePath, entry] of entries) {
|
|
271551
271551
|
try {
|
|
271552
|
-
const { readFileSync:
|
|
271553
|
-
const content =
|
|
271552
|
+
const { readFileSync: readFileSync64 } = await import("node:fs");
|
|
271553
|
+
const content = readFileSync64(filePath, "utf8");
|
|
271554
271554
|
const tokenEst = Math.ceil(content.length / 4);
|
|
271555
271555
|
if (recoveredTokens + tokenEst > fileRecoveryBudget)
|
|
271556
271556
|
break;
|
|
@@ -272720,18 +272720,18 @@ ${result}`
|
|
|
272720
272720
|
const buffer2 = Buffer.from(rawBase64, "base64");
|
|
272721
272721
|
let resizedBase64 = null;
|
|
272722
272722
|
try {
|
|
272723
|
-
const { execSync:
|
|
272724
|
-
const { writeFileSync: writeFileSync44, readFileSync:
|
|
272725
|
-
const { join:
|
|
272723
|
+
const { execSync: execSync57 } = await import("node:child_process");
|
|
272724
|
+
const { writeFileSync: writeFileSync44, readFileSync: readFileSync64, unlinkSync: unlinkSync19 } = await import("node:fs");
|
|
272725
|
+
const { join: join102 } = await import("node:path");
|
|
272726
272726
|
const { tmpdir: tmpdir21 } = await import("node:os");
|
|
272727
|
-
const tmpIn =
|
|
272728
|
-
const tmpOut =
|
|
272727
|
+
const tmpIn = join102(tmpdir21(), `oa_img_in_${Date.now()}.png`);
|
|
272728
|
+
const tmpOut = join102(tmpdir21(), `oa_img_out_${Date.now()}.jpg`);
|
|
272729
272729
|
writeFileSync44(tmpIn, buffer2);
|
|
272730
272730
|
const pyBin = process.platform === "win32" ? "python" : "python3";
|
|
272731
272731
|
const escapedIn = tmpIn.replace(/\\/g, "\\\\");
|
|
272732
272732
|
const escapedOut = tmpOut.replace(/\\/g, "\\\\");
|
|
272733
|
-
|
|
272734
|
-
const resizedBuf =
|
|
272733
|
+
execSync57(`${pyBin} -c "from PIL import Image; img = Image.open('${escapedIn}'); img.thumbnail((512, 512), Image.LANCZOS); img = img.convert('RGB'); img.save('${escapedOut}', 'JPEG', quality=75)"`, { timeout: 1e4, stdio: "pipe" });
|
|
272734
|
+
const resizedBuf = readFileSync64(tmpOut);
|
|
272735
272735
|
resizedBase64 = `data:image/jpeg;base64,${resizedBuf.toString("base64")}`;
|
|
272736
272736
|
try {
|
|
272737
272737
|
unlinkSync19(tmpIn);
|
|
@@ -272784,8 +272784,8 @@ ${result}`
|
|
|
272784
272784
|
if (!res.ok && model === "moondream" && res.status === 404) {
|
|
272785
272785
|
this.emit({ type: "status", content: `Pulling moondream vision model...`, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
272786
272786
|
try {
|
|
272787
|
-
const { execSync:
|
|
272788
|
-
|
|
272787
|
+
const { execSync: execSync57 } = await import("node:child_process");
|
|
272788
|
+
execSync57("ollama pull moondream", { timeout: 3e5, stdio: "pipe" });
|
|
272789
272789
|
res = await fetch(`${ollamaHost}/api/generate`, {
|
|
272790
272790
|
method: "POST",
|
|
272791
272791
|
headers: { "Content-Type": "application/json" },
|
|
@@ -275963,8 +275963,8 @@ var init_listen = __esm({
|
|
|
275963
275963
|
const nvmBase = join66(homedir20(), ".nvm", "versions", "node");
|
|
275964
275964
|
if (existsSync50(nvmBase)) {
|
|
275965
275965
|
try {
|
|
275966
|
-
const { readdirSync:
|
|
275967
|
-
for (const ver of
|
|
275966
|
+
const { readdirSync: readdirSync29 } = await import("node:fs");
|
|
275967
|
+
for (const ver of readdirSync29(nvmBase)) {
|
|
275968
275968
|
const tcPath = join66(nvmBase, ver, "lib", "node_modules", "transcribe-cli");
|
|
275969
275969
|
if (existsSync50(join66(tcPath, "dist", "index.js"))) {
|
|
275970
275970
|
const { createRequire: createRequire7 } = await import("node:module");
|
|
@@ -285195,25 +285195,25 @@ async function fetchOpenAIModels(baseUrl, apiKey) {
|
|
|
285195
285195
|
async function fetchPeerModels(peerId, authKey) {
|
|
285196
285196
|
try {
|
|
285197
285197
|
const { NexusTool: NexusTool2 } = await Promise.resolve().then(() => (init_dist4(), dist_exports));
|
|
285198
|
-
const { existsSync:
|
|
285199
|
-
const { join:
|
|
285198
|
+
const { existsSync: existsSync82, readFileSync: readFileSync64 } = await import("node:fs");
|
|
285199
|
+
const { join: join102 } = await import("node:path");
|
|
285200
285200
|
const cwd4 = process.cwd();
|
|
285201
285201
|
const nexusTool = new NexusTool2(cwd4);
|
|
285202
285202
|
const nexusDir = nexusTool.getNexusDir();
|
|
285203
285203
|
let isLocalPeer = false;
|
|
285204
285204
|
try {
|
|
285205
|
-
const statusPath =
|
|
285206
|
-
if (
|
|
285207
|
-
const status = JSON.parse(
|
|
285205
|
+
const statusPath = join102(nexusDir, "status.json");
|
|
285206
|
+
if (existsSync82(statusPath)) {
|
|
285207
|
+
const status = JSON.parse(readFileSync64(statusPath, "utf8"));
|
|
285208
285208
|
if (status.peerId === peerId) isLocalPeer = true;
|
|
285209
285209
|
}
|
|
285210
285210
|
} catch {
|
|
285211
285211
|
}
|
|
285212
285212
|
if (isLocalPeer) {
|
|
285213
|
-
const pricingPath =
|
|
285214
|
-
if (
|
|
285213
|
+
const pricingPath = join102(nexusDir, "pricing.json");
|
|
285214
|
+
if (existsSync82(pricingPath)) {
|
|
285215
285215
|
try {
|
|
285216
|
-
const pricing = JSON.parse(
|
|
285216
|
+
const pricing = JSON.parse(readFileSync64(pricingPath, "utf8"));
|
|
285217
285217
|
const localModels = (pricing.models || []).map((m2) => ({
|
|
285218
285218
|
name: m2.model || "unknown",
|
|
285219
285219
|
size: m2.parameterSize || "",
|
|
@@ -285226,10 +285226,10 @@ async function fetchPeerModels(peerId, authKey) {
|
|
|
285226
285226
|
}
|
|
285227
285227
|
}
|
|
285228
285228
|
}
|
|
285229
|
-
const cachePath =
|
|
285230
|
-
if (
|
|
285229
|
+
const cachePath = join102(nexusDir, "peer-models-cache.json");
|
|
285230
|
+
if (existsSync82(cachePath)) {
|
|
285231
285231
|
try {
|
|
285232
|
-
const cache7 = JSON.parse(
|
|
285232
|
+
const cache7 = JSON.parse(readFileSync64(cachePath, "utf8"));
|
|
285233
285233
|
if (cache7.peerId === peerId && cache7.models?.length > 0) {
|
|
285234
285234
|
const age = Date.now() - new Date(cache7.cachedAt).getTime();
|
|
285235
285235
|
if (age < 5 * 60 * 1e3) {
|
|
@@ -285341,10 +285341,10 @@ async function fetchPeerModels(peerId, authKey) {
|
|
|
285341
285341
|
} catch {
|
|
285342
285342
|
}
|
|
285343
285343
|
if (isLocalPeer) {
|
|
285344
|
-
const pricingPath =
|
|
285345
|
-
if (
|
|
285344
|
+
const pricingPath = join102(nexusDir, "pricing.json");
|
|
285345
|
+
if (existsSync82(pricingPath)) {
|
|
285346
285346
|
try {
|
|
285347
|
-
const pricing = JSON.parse(
|
|
285347
|
+
const pricing = JSON.parse(readFileSync64(pricingPath, "utf8"));
|
|
285348
285348
|
return (pricing.models || []).map((m2) => ({
|
|
285349
285349
|
name: m2.model || "unknown",
|
|
285350
285350
|
size: m2.parameterSize || "",
|
|
@@ -294716,8 +294716,8 @@ async function startDaemon() {
|
|
|
294716
294716
|
let oaScript = process.argv[1];
|
|
294717
294717
|
if (!oaScript) {
|
|
294718
294718
|
try {
|
|
294719
|
-
const { execSync:
|
|
294720
|
-
const whichOa =
|
|
294719
|
+
const { execSync: execSync57 } = await import("node:child_process");
|
|
294720
|
+
const whichOa = execSync57("which oa 2>/dev/null || where oa 2>nul", { encoding: "utf8" }).trim();
|
|
294721
294721
|
if (whichOa) oaScript = whichOa;
|
|
294722
294722
|
} catch {
|
|
294723
294723
|
}
|
|
@@ -299447,9 +299447,9 @@ async function handleSlashCommand(input, ctx3) {
|
|
|
299447
299447
|
renderInfo("No wallet configured. Ask the agent to create one via the nexus tool.");
|
|
299448
299448
|
}
|
|
299449
299449
|
} else if (sub === "name") {
|
|
299450
|
-
const { homedir:
|
|
299450
|
+
const { homedir: homedir34 } = __require("node:os");
|
|
299451
299451
|
const { existsSync: ex, readFileSync: rf, writeFileSync: wf, mkdirSync: mkd } = __require("node:fs");
|
|
299452
|
-
const namePath = __require("node:path").join(
|
|
299452
|
+
const namePath = __require("node:path").join(homedir34(), ".open-agents", "agent-name");
|
|
299453
299453
|
if (rest2) {
|
|
299454
299454
|
const customName = rest2.replace(/[^a-zA-Z0-9_\-.\s]/g, "").trim().slice(0, 40);
|
|
299455
299455
|
if (!customName) {
|
|
@@ -301152,8 +301152,8 @@ The session corrections MUST become hard rules in the SKILL.md Rules section.`;
|
|
|
301152
301152
|
let sponsorName = (config.header.message || "").replace(/^\/+/, "").trim();
|
|
301153
301153
|
if (!sponsorName || sponsorName.length < 2) {
|
|
301154
301154
|
try {
|
|
301155
|
-
const { homedir:
|
|
301156
|
-
const namePath = __require("path").join(
|
|
301155
|
+
const { homedir: homedir34 } = __require("os");
|
|
301156
|
+
const namePath = __require("path").join(homedir34(), ".open-agents", "agent-name");
|
|
301157
301157
|
if (existsSync62(namePath)) sponsorName = readFileSync47(namePath, "utf8").trim();
|
|
301158
301158
|
} catch {
|
|
301159
301159
|
}
|
|
@@ -302613,9 +302613,9 @@ async function handleVoiceMenu(ctx3, save2, hasLocal) {
|
|
|
302613
302613
|
}
|
|
302614
302614
|
const { basename: basename19, join: pathJoin } = await import("node:path");
|
|
302615
302615
|
const { copyFileSync: copyFileSync3, mkdirSync: mkdirSync50, existsSync: exists2 } = await import("node:fs");
|
|
302616
|
-
const { homedir:
|
|
302616
|
+
const { homedir: homedir34 } = await import("node:os");
|
|
302617
302617
|
const modelName = basename19(onnxDrop.path, ".onnx").replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
302618
|
-
const destDir = pathJoin(
|
|
302618
|
+
const destDir = pathJoin(homedir34(), ".open-agents", "voice", "models", modelName);
|
|
302619
302619
|
if (!exists2(destDir)) mkdirSync50(destDir, { recursive: true });
|
|
302620
302620
|
copyFileSync3(onnxDrop.path, pathJoin(destDir, "model.onnx"));
|
|
302621
302621
|
copyFileSync3(jsonDrop.path, pathJoin(destDir, "config.json"));
|
|
@@ -303531,8 +303531,8 @@ async function handlePeerEndpoint(peerId, authKey, ctx3, local) {
|
|
|
303531
303531
|
if (models.length > 0) {
|
|
303532
303532
|
try {
|
|
303533
303533
|
const { writeFileSync: writeFileSync44, mkdirSync: mkdirSync50 } = await import("node:fs");
|
|
303534
|
-
const { join:
|
|
303535
|
-
const cachePath =
|
|
303534
|
+
const { join: join102, dirname: dirname29 } = await import("node:path");
|
|
303535
|
+
const cachePath = join102(ctx3.repoRoot || process.cwd(), ".oa", "nexus", "peer-models-cache.json");
|
|
303536
303536
|
mkdirSync50(dirname29(cachePath), { recursive: true });
|
|
303537
303537
|
writeFileSync44(cachePath, JSON.stringify({
|
|
303538
303538
|
peerId,
|
|
@@ -303583,7 +303583,7 @@ async function handlePeerEndpoint(peerId, authKey, ctx3, local) {
|
|
|
303583
303583
|
}
|
|
303584
303584
|
}
|
|
303585
303585
|
async function handleParallel(arg, ctx3) {
|
|
303586
|
-
const { execSync:
|
|
303586
|
+
const { execSync: execSync57 } = await import("node:child_process");
|
|
303587
303587
|
const baseUrl = ctx3.config.backendUrl || "http://localhost:11434";
|
|
303588
303588
|
const isRemote = ctx3.config.backendType === "nexus";
|
|
303589
303589
|
if (isRemote) {
|
|
@@ -303607,7 +303607,7 @@ async function handleParallel(arg, ctx3) {
|
|
|
303607
303607
|
}
|
|
303608
303608
|
let systemdVal = "";
|
|
303609
303609
|
try {
|
|
303610
|
-
const out =
|
|
303610
|
+
const out = execSync57("systemctl show ollama.service -p Environment 2>/dev/null || true", { encoding: "utf8" });
|
|
303611
303611
|
const match = out.match(/OLLAMA_NUM_PARALLEL=(\d+)/);
|
|
303612
303612
|
if (match) systemdVal = match[1];
|
|
303613
303613
|
} catch {
|
|
@@ -303635,7 +303635,7 @@ async function handleParallel(arg, ctx3) {
|
|
|
303635
303635
|
}
|
|
303636
303636
|
const isSystemd = (() => {
|
|
303637
303637
|
try {
|
|
303638
|
-
const out =
|
|
303638
|
+
const out = execSync57("systemctl is-active ollama.service 2>/dev/null", { encoding: "utf8" }).trim();
|
|
303639
303639
|
return out === "active" || out === "inactive";
|
|
303640
303640
|
} catch {
|
|
303641
303641
|
return false;
|
|
@@ -303649,10 +303649,10 @@ async function handleParallel(arg, ctx3) {
|
|
|
303649
303649
|
const overrideContent = `[Service]
|
|
303650
303650
|
Environment="OLLAMA_NUM_PARALLEL=${n2}"
|
|
303651
303651
|
`;
|
|
303652
|
-
|
|
303653
|
-
|
|
303654
|
-
|
|
303655
|
-
|
|
303652
|
+
execSync57(`sudo mkdir -p ${overrideDir}`, { stdio: "pipe" });
|
|
303653
|
+
execSync57(`echo '${overrideContent}' | sudo tee ${overrideFile} > /dev/null`, { stdio: "pipe" });
|
|
303654
|
+
execSync57("sudo systemctl daemon-reload", { stdio: "pipe" });
|
|
303655
|
+
execSync57("sudo systemctl restart ollama.service", { stdio: "pipe" });
|
|
303656
303656
|
let ready = false;
|
|
303657
303657
|
for (let i2 = 0; i2 < 30 && !ready; i2++) {
|
|
303658
303658
|
await new Promise((r2) => setTimeout(r2, 500));
|
|
@@ -303678,7 +303678,7 @@ Environment="OLLAMA_NUM_PARALLEL=${n2}"
|
|
|
303678
303678
|
renderInfo(`Setting OLLAMA_NUM_PARALLEL=${n2}...`);
|
|
303679
303679
|
try {
|
|
303680
303680
|
try {
|
|
303681
|
-
|
|
303681
|
+
execSync57("pkill -f 'ollama serve' 2>/dev/null || true", { stdio: "pipe" });
|
|
303682
303682
|
} catch {
|
|
303683
303683
|
}
|
|
303684
303684
|
await new Promise((r2) => setTimeout(r2, 1e3));
|
|
@@ -304100,17 +304100,17 @@ async function handleUpdate(subcommand, ctx3) {
|
|
|
304100
304100
|
try {
|
|
304101
304101
|
const { createRequire: createRequire7 } = await import("node:module");
|
|
304102
304102
|
const { fileURLToPath: fileURLToPath19 } = await import("node:url");
|
|
304103
|
-
const { dirname: dirname29, join:
|
|
304104
|
-
const { existsSync:
|
|
304103
|
+
const { dirname: dirname29, join: join102 } = await import("node:path");
|
|
304104
|
+
const { existsSync: existsSync82 } = await import("node:fs");
|
|
304105
304105
|
const req2 = createRequire7(import.meta.url);
|
|
304106
304106
|
const thisDir = dirname29(fileURLToPath19(import.meta.url));
|
|
304107
304107
|
const candidates = [
|
|
304108
|
-
|
|
304109
|
-
|
|
304110
|
-
|
|
304108
|
+
join102(thisDir, "..", "package.json"),
|
|
304109
|
+
join102(thisDir, "..", "..", "package.json"),
|
|
304110
|
+
join102(thisDir, "..", "..", "..", "package.json")
|
|
304111
304111
|
];
|
|
304112
304112
|
for (const pkgPath of candidates) {
|
|
304113
|
-
if (
|
|
304113
|
+
if (existsSync82(pkgPath)) {
|
|
304114
304114
|
const pkg = req2(pkgPath);
|
|
304115
304115
|
if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli") {
|
|
304116
304116
|
currentVersion = pkg.version ?? "0.0.0";
|
|
@@ -305100,18 +305100,18 @@ async function showExposeDashboard(gateway, rl, ctx3) {
|
|
|
305100
305100
|
const cmd = `/endpoint ${id} --auth ${gateway.authKey ?? ""}`;
|
|
305101
305101
|
let copied = false;
|
|
305102
305102
|
try {
|
|
305103
|
-
const { execSync:
|
|
305103
|
+
const { execSync: execSync57 } = __require("node:child_process");
|
|
305104
305104
|
const platform6 = process.platform;
|
|
305105
305105
|
if (platform6 === "darwin") {
|
|
305106
|
-
|
|
305106
|
+
execSync57("pbcopy", { input: cmd, timeout: 3e3 });
|
|
305107
305107
|
copied = true;
|
|
305108
305108
|
} else if (platform6 === "win32") {
|
|
305109
|
-
|
|
305109
|
+
execSync57("clip", { input: cmd, timeout: 3e3 });
|
|
305110
305110
|
copied = true;
|
|
305111
305111
|
} else {
|
|
305112
305112
|
for (const tool of ["xclip -selection clipboard", "xsel --clipboard --input", "wl-copy"]) {
|
|
305113
305113
|
try {
|
|
305114
|
-
|
|
305114
|
+
execSync57(tool, { input: cmd, timeout: 3e3, stdio: ["pipe", "pipe", "pipe"] });
|
|
305115
305115
|
copied = true;
|
|
305116
305116
|
break;
|
|
305117
305117
|
} catch {
|
|
@@ -305951,8 +305951,8 @@ function listBannerDesigns(workDir) {
|
|
|
305951
305951
|
const dir = join80(workDir, ".oa", "banners");
|
|
305952
305952
|
if (!existsSync64(dir)) return [];
|
|
305953
305953
|
try {
|
|
305954
|
-
const { readdirSync:
|
|
305955
|
-
return
|
|
305954
|
+
const { readdirSync: readdirSync29 } = __require("node:fs");
|
|
305955
|
+
return readdirSync29(dir).filter((f2) => f2.endsWith(".json")).map((f2) => f2.replace(".json", ""));
|
|
305956
305956
|
} catch {
|
|
305957
305957
|
return [];
|
|
305958
305958
|
}
|
|
@@ -312498,21 +312498,6 @@ var init_audit_log = __esm({
|
|
|
312498
312498
|
});
|
|
312499
312499
|
|
|
312500
312500
|
// packages/cli/src/api/http.ts
|
|
312501
|
-
var http_exports = {};
|
|
312502
|
-
__export(http_exports, {
|
|
312503
|
-
API_VERSION: () => API_VERSION,
|
|
312504
|
-
checkNotModified: () => checkNotModified,
|
|
312505
|
-
computeEtag: () => computeEtag,
|
|
312506
|
-
getEventBus: () => getEventBus,
|
|
312507
|
-
paginated: () => paginated,
|
|
312508
|
-
parseJsonBodyStrict: () => parseJsonBodyStrict,
|
|
312509
|
-
parsePagination: () => parsePagination,
|
|
312510
|
-
problemDetails: () => problemDetails,
|
|
312511
|
-
publishEvent: () => publishEvent,
|
|
312512
|
-
readBodyWithLimit: () => readBodyWithLimit,
|
|
312513
|
-
sendJson: () => sendJson,
|
|
312514
|
-
sendProblem: () => sendProblem
|
|
312515
|
-
});
|
|
312516
312501
|
import { createHash as createHash6 } from "node:crypto";
|
|
312517
312502
|
function problemDetails(opts) {
|
|
312518
312503
|
const p2 = {
|
|
@@ -312673,10 +312658,774 @@ data: ${JSON.stringify(ev)}
|
|
|
312673
312658
|
}
|
|
312674
312659
|
});
|
|
312675
312660
|
|
|
312676
|
-
// packages/cli/src/api/
|
|
312661
|
+
// packages/cli/src/api/aiwg.ts
|
|
312662
|
+
var aiwg_exports = {};
|
|
312663
|
+
__export(aiwg_exports, {
|
|
312664
|
+
budgetForTier: () => budgetForTier,
|
|
312665
|
+
detectModelTier: () => detectModelTier,
|
|
312666
|
+
listAiwgAddons: () => listAiwgAddons,
|
|
312667
|
+
listAiwgFrameworks: () => listAiwgFrameworks,
|
|
312668
|
+
listAiwgItems: () => listAiwgItems,
|
|
312669
|
+
loadAiwgItemContent: () => loadAiwgItemContent,
|
|
312670
|
+
resolveAiwgRoot: () => resolveAiwgRoot,
|
|
312671
|
+
tryRouteAiwg: () => tryRouteAiwg
|
|
312672
|
+
});
|
|
312677
312673
|
import { existsSync as existsSync72, readFileSync as readFileSync56, readdirSync as readdirSync22, statSync as statSync21 } from "node:fs";
|
|
312678
|
-
import { join as join89
|
|
312674
|
+
import { join as join89 } from "node:path";
|
|
312679
312675
|
import { homedir as homedir28 } from "node:os";
|
|
312676
|
+
import { execSync as execSync53 } from "node:child_process";
|
|
312677
|
+
function resolveAiwgRoot() {
|
|
312678
|
+
if (_cachedAiwgRoot !== void 0) return _cachedAiwgRoot;
|
|
312679
|
+
const envRoot = process.env["OA_AIWG_ROOT"];
|
|
312680
|
+
if (envRoot && existsSync72(join89(envRoot, "package.json"))) {
|
|
312681
|
+
_cachedAiwgRoot = envRoot;
|
|
312682
|
+
return envRoot;
|
|
312683
|
+
}
|
|
312684
|
+
const shareDir = join89(homedir28(), ".local", "share", "ai-writing-guide");
|
|
312685
|
+
if (existsSync72(join89(shareDir, "agentic"))) {
|
|
312686
|
+
_cachedAiwgRoot = shareDir;
|
|
312687
|
+
return shareDir;
|
|
312688
|
+
}
|
|
312689
|
+
try {
|
|
312690
|
+
const globalRoot = execSync53("npm root -g", {
|
|
312691
|
+
encoding: "utf-8",
|
|
312692
|
+
timeout: 5e3,
|
|
312693
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
312694
|
+
}).trim();
|
|
312695
|
+
const candidate = join89(globalRoot, "aiwg");
|
|
312696
|
+
if (existsSync72(join89(candidate, "package.json"))) {
|
|
312697
|
+
_cachedAiwgRoot = candidate;
|
|
312698
|
+
return candidate;
|
|
312699
|
+
}
|
|
312700
|
+
} catch {
|
|
312701
|
+
}
|
|
312702
|
+
for (const p2 of [
|
|
312703
|
+
"/usr/local/lib/node_modules/aiwg",
|
|
312704
|
+
"/usr/lib/node_modules/aiwg",
|
|
312705
|
+
"/opt/homebrew/lib/node_modules/aiwg"
|
|
312706
|
+
]) {
|
|
312707
|
+
if (existsSync72(join89(p2, "package.json"))) {
|
|
312708
|
+
_cachedAiwgRoot = p2;
|
|
312709
|
+
return p2;
|
|
312710
|
+
}
|
|
312711
|
+
}
|
|
312712
|
+
const versionDirs = [
|
|
312713
|
+
join89(homedir28(), ".nvm", "versions", "node"),
|
|
312714
|
+
join89(homedir28(), ".local", "share", "fnm", "node-versions")
|
|
312715
|
+
];
|
|
312716
|
+
for (const vdir of versionDirs) {
|
|
312717
|
+
if (!existsSync72(vdir)) continue;
|
|
312718
|
+
try {
|
|
312719
|
+
for (const ver of readdirSync22(vdir)) {
|
|
312720
|
+
for (const prefix of ["lib/node_modules/aiwg", "installation/lib/node_modules/aiwg"]) {
|
|
312721
|
+
const cand = join89(vdir, ver, prefix);
|
|
312722
|
+
if (existsSync72(join89(cand, "package.json"))) {
|
|
312723
|
+
_cachedAiwgRoot = cand;
|
|
312724
|
+
return cand;
|
|
312725
|
+
}
|
|
312726
|
+
}
|
|
312727
|
+
}
|
|
312728
|
+
} catch {
|
|
312729
|
+
}
|
|
312730
|
+
}
|
|
312731
|
+
try {
|
|
312732
|
+
const whichAiwg = execSync53("which aiwg 2>/dev/null || where aiwg 2>nul", {
|
|
312733
|
+
encoding: "utf-8",
|
|
312734
|
+
timeout: 3e3,
|
|
312735
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
312736
|
+
}).trim().split("\n")[0];
|
|
312737
|
+
if (whichAiwg) {
|
|
312738
|
+
let cur = whichAiwg;
|
|
312739
|
+
for (let i2 = 0; i2 < 8; i2++) {
|
|
312740
|
+
cur = join89(cur, "..");
|
|
312741
|
+
const pj = join89(cur, "package.json");
|
|
312742
|
+
if (existsSync72(pj)) {
|
|
312743
|
+
try {
|
|
312744
|
+
const pkg = JSON.parse(readFileSync56(pj, "utf-8"));
|
|
312745
|
+
if (pkg.name === "aiwg") {
|
|
312746
|
+
_cachedAiwgRoot = cur;
|
|
312747
|
+
return cur;
|
|
312748
|
+
}
|
|
312749
|
+
} catch {
|
|
312750
|
+
}
|
|
312751
|
+
}
|
|
312752
|
+
}
|
|
312753
|
+
}
|
|
312754
|
+
} catch {
|
|
312755
|
+
}
|
|
312756
|
+
_cachedAiwgRoot = null;
|
|
312757
|
+
return null;
|
|
312758
|
+
}
|
|
312759
|
+
function listAiwgFrameworks() {
|
|
312760
|
+
if (_cachedFrameworks) return _cachedFrameworks;
|
|
312761
|
+
const root = resolveAiwgRoot();
|
|
312762
|
+
if (!root) {
|
|
312763
|
+
_cachedFrameworks = [];
|
|
312764
|
+
return _cachedFrameworks;
|
|
312765
|
+
}
|
|
312766
|
+
const frameworksDir = join89(root, "agentic", "code", "frameworks");
|
|
312767
|
+
if (!existsSync72(frameworksDir)) {
|
|
312768
|
+
_cachedFrameworks = [];
|
|
312769
|
+
return _cachedFrameworks;
|
|
312770
|
+
}
|
|
312771
|
+
const out = [];
|
|
312772
|
+
for (const name10 of readdirSync22(frameworksDir)) {
|
|
312773
|
+
const p2 = join89(frameworksDir, name10);
|
|
312774
|
+
try {
|
|
312775
|
+
const st = statSync21(p2);
|
|
312776
|
+
if (!st.isDirectory()) continue;
|
|
312777
|
+
const agg = aggregateDir(p2);
|
|
312778
|
+
out.push({
|
|
312779
|
+
name: name10,
|
|
312780
|
+
description: readFirstLineDescription(p2),
|
|
312781
|
+
path: p2,
|
|
312782
|
+
file_count: agg.files,
|
|
312783
|
+
size_bytes: agg.bytes,
|
|
312784
|
+
token_estimate: Math.round(agg.mdChars / 4),
|
|
312785
|
+
skills_count: agg.skills,
|
|
312786
|
+
agents_count: agg.agents,
|
|
312787
|
+
commands_count: agg.commands
|
|
312788
|
+
});
|
|
312789
|
+
} catch {
|
|
312790
|
+
}
|
|
312791
|
+
}
|
|
312792
|
+
_cachedFrameworks = out.sort((a2, b) => a2.name.localeCompare(b.name));
|
|
312793
|
+
return _cachedFrameworks;
|
|
312794
|
+
}
|
|
312795
|
+
function aggregateDir(dir, depth = 0) {
|
|
312796
|
+
const out = { files: 0, bytes: 0, mdChars: 0, skills: 0, agents: 0, commands: 0 };
|
|
312797
|
+
if (depth > 8) return out;
|
|
312798
|
+
try {
|
|
312799
|
+
for (const e2 of readdirSync22(dir, { withFileTypes: true })) {
|
|
312800
|
+
if (e2.name.startsWith(".") || e2.name === "node_modules") continue;
|
|
312801
|
+
const p2 = join89(dir, e2.name);
|
|
312802
|
+
if (e2.isDirectory()) {
|
|
312803
|
+
const sub = aggregateDir(p2, depth + 1);
|
|
312804
|
+
out.files += sub.files;
|
|
312805
|
+
out.bytes += sub.bytes;
|
|
312806
|
+
out.mdChars += sub.mdChars;
|
|
312807
|
+
out.skills += sub.skills;
|
|
312808
|
+
out.agents += sub.agents;
|
|
312809
|
+
out.commands += sub.commands;
|
|
312810
|
+
} else if (e2.isFile()) {
|
|
312811
|
+
try {
|
|
312812
|
+
const st = statSync21(p2);
|
|
312813
|
+
out.files++;
|
|
312814
|
+
out.bytes += st.size;
|
|
312815
|
+
if (e2.name.endsWith(".md")) {
|
|
312816
|
+
out.mdChars += st.size;
|
|
312817
|
+
if (e2.name === "SKILL.md") out.skills++;
|
|
312818
|
+
else if (e2.name === "AGENT.md" || p2.includes("/agents/")) out.agents++;
|
|
312819
|
+
else if (p2.includes("/commands/")) out.commands++;
|
|
312820
|
+
}
|
|
312821
|
+
} catch {
|
|
312822
|
+
}
|
|
312823
|
+
}
|
|
312824
|
+
}
|
|
312825
|
+
} catch {
|
|
312826
|
+
}
|
|
312827
|
+
return out;
|
|
312828
|
+
}
|
|
312829
|
+
function readFirstLineDescription(dir) {
|
|
312830
|
+
for (const candidate of ["README.md", "SKILL.md", "INDEX.md"]) {
|
|
312831
|
+
const p2 = join89(dir, candidate);
|
|
312832
|
+
if (!existsSync72(p2)) continue;
|
|
312833
|
+
try {
|
|
312834
|
+
const txt = readFileSync56(p2, "utf-8");
|
|
312835
|
+
const descMatch = txt.match(/^description:\s*(.+)$/m);
|
|
312836
|
+
if (descMatch) return descMatch[1].trim().slice(0, 200);
|
|
312837
|
+
for (const line of txt.split("\n")) {
|
|
312838
|
+
const t2 = line.trim();
|
|
312839
|
+
if (!t2 || t2.startsWith("#") || t2.startsWith("---") || t2.startsWith("```")) continue;
|
|
312840
|
+
return t2.slice(0, 200);
|
|
312841
|
+
}
|
|
312842
|
+
} catch {
|
|
312843
|
+
}
|
|
312844
|
+
}
|
|
312845
|
+
return "";
|
|
312846
|
+
}
|
|
312847
|
+
function listAiwgItems() {
|
|
312848
|
+
if (_cachedItems) return _cachedItems;
|
|
312849
|
+
const root = resolveAiwgRoot();
|
|
312850
|
+
if (!root) {
|
|
312851
|
+
_cachedItems = [];
|
|
312852
|
+
return _cachedItems;
|
|
312853
|
+
}
|
|
312854
|
+
const out = [];
|
|
312855
|
+
const walkRoots = [
|
|
312856
|
+
join89(root, "agentic", "code", "frameworks"),
|
|
312857
|
+
join89(root, "agentic", "code", "addons"),
|
|
312858
|
+
join89(root, "plugins")
|
|
312859
|
+
];
|
|
312860
|
+
for (const wr of walkRoots) {
|
|
312861
|
+
if (!existsSync72(wr)) continue;
|
|
312862
|
+
walkForItems(wr, out, 0);
|
|
312863
|
+
}
|
|
312864
|
+
_cachedItems = out;
|
|
312865
|
+
return _cachedItems;
|
|
312866
|
+
}
|
|
312867
|
+
function walkForItems(dir, out, depth) {
|
|
312868
|
+
if (depth > 10) return;
|
|
312869
|
+
try {
|
|
312870
|
+
for (const e2 of readdirSync22(dir, { withFileTypes: true })) {
|
|
312871
|
+
if (e2.name.startsWith(".") || e2.name === "node_modules") continue;
|
|
312872
|
+
const p2 = join89(dir, e2.name);
|
|
312873
|
+
if (e2.isDirectory()) {
|
|
312874
|
+
walkForItems(p2, out, depth + 1);
|
|
312875
|
+
} else if (e2.isFile() && e2.name.endsWith(".md")) {
|
|
312876
|
+
const item = parseItem(p2);
|
|
312877
|
+
if (item) out.push(item);
|
|
312878
|
+
}
|
|
312879
|
+
}
|
|
312880
|
+
} catch {
|
|
312881
|
+
}
|
|
312882
|
+
}
|
|
312883
|
+
function parseItem(p2) {
|
|
312884
|
+
try {
|
|
312885
|
+
const raw = readFileSync56(p2, "utf-8");
|
|
312886
|
+
const header = raw.slice(0, 3e3);
|
|
312887
|
+
const nameMatch = header.match(/^name:\s*(.+)$/m);
|
|
312888
|
+
const descMatch = header.match(/^description:\s*(.+)$/m);
|
|
312889
|
+
const triggersRaw = header.match(/^triggers:\s*\[(.+?)\]/m)?.[1] || header.match(/^triggers:\s*\n((?:\s+-\s+.+\n?)+)/m)?.[1];
|
|
312890
|
+
const triggers = [];
|
|
312891
|
+
if (triggersRaw) {
|
|
312892
|
+
const parts = triggersRaw.split(/[,\n]/).map((s2) => s2.replace(/^\s*-?\s*/, "").replace(/^["']|["']$/g, "").trim()).filter(Boolean);
|
|
312893
|
+
triggers.push(...parts);
|
|
312894
|
+
}
|
|
312895
|
+
const name10 = nameMatch?.[1]?.trim() ?? p2.split("/").slice(-2, -1)[0] ?? "(unnamed)";
|
|
312896
|
+
let kind = "skill";
|
|
312897
|
+
if (p2.includes("/agents/") || p2.endsWith("AGENT.md")) kind = "agent";
|
|
312898
|
+
else if (p2.includes("/commands/")) kind = "command";
|
|
312899
|
+
else if (!p2.endsWith("SKILL.md") && !p2.includes("/skills/")) return null;
|
|
312900
|
+
const source = deriveSource(p2);
|
|
312901
|
+
return {
|
|
312902
|
+
name: name10,
|
|
312903
|
+
description: descMatch?.[1]?.trim().slice(0, 300) ?? "",
|
|
312904
|
+
triggers,
|
|
312905
|
+
source,
|
|
312906
|
+
path: p2,
|
|
312907
|
+
kind
|
|
312908
|
+
};
|
|
312909
|
+
} catch {
|
|
312910
|
+
return null;
|
|
312911
|
+
}
|
|
312912
|
+
}
|
|
312913
|
+
function deriveSource(p2) {
|
|
312914
|
+
const segments = p2.split("/");
|
|
312915
|
+
for (const key of ["frameworks", "addons", "plugins"]) {
|
|
312916
|
+
const idx = segments.indexOf(key);
|
|
312917
|
+
if (idx >= 0 && idx + 1 < segments.length) return segments[idx + 1];
|
|
312918
|
+
}
|
|
312919
|
+
return "aiwg";
|
|
312920
|
+
}
|
|
312921
|
+
function loadAiwgItemContent(path5, maxBytes = 2e4) {
|
|
312922
|
+
try {
|
|
312923
|
+
if (!existsSync72(path5)) return null;
|
|
312924
|
+
const raw = readFileSync56(path5, "utf-8");
|
|
312925
|
+
return raw.length > maxBytes ? raw.slice(0, maxBytes) + "\n\n...(truncated for context budget)" : raw;
|
|
312926
|
+
} catch {
|
|
312927
|
+
return null;
|
|
312928
|
+
}
|
|
312929
|
+
}
|
|
312930
|
+
function listAiwgAddons() {
|
|
312931
|
+
if (_cachedAddons) return _cachedAddons;
|
|
312932
|
+
const root = resolveAiwgRoot();
|
|
312933
|
+
if (!root) {
|
|
312934
|
+
_cachedAddons = [];
|
|
312935
|
+
return _cachedAddons;
|
|
312936
|
+
}
|
|
312937
|
+
const addonsDir = join89(root, "agentic", "code", "addons");
|
|
312938
|
+
if (!existsSync72(addonsDir)) {
|
|
312939
|
+
_cachedAddons = [];
|
|
312940
|
+
return _cachedAddons;
|
|
312941
|
+
}
|
|
312942
|
+
const out = [];
|
|
312943
|
+
for (const name10 of readdirSync22(addonsDir)) {
|
|
312944
|
+
const p2 = join89(addonsDir, name10);
|
|
312945
|
+
try {
|
|
312946
|
+
const st = statSync21(p2);
|
|
312947
|
+
if (!st.isDirectory()) continue;
|
|
312948
|
+
const agg = aggregateDir(p2);
|
|
312949
|
+
out.push({
|
|
312950
|
+
name: name10,
|
|
312951
|
+
path: p2,
|
|
312952
|
+
file_count: agg.files,
|
|
312953
|
+
size_bytes: agg.bytes,
|
|
312954
|
+
description: readFirstLineDescription(p2)
|
|
312955
|
+
});
|
|
312956
|
+
} catch {
|
|
312957
|
+
}
|
|
312958
|
+
}
|
|
312959
|
+
_cachedAddons = out.sort((a2, b) => a2.name.localeCompare(b.name));
|
|
312960
|
+
return _cachedAddons;
|
|
312961
|
+
}
|
|
312962
|
+
function detectModelTier(modelName, explicitTier) {
|
|
312963
|
+
if (explicitTier === "small" || explicitTier === "medium" || explicitTier === "large" || explicitTier === "xlarge") {
|
|
312964
|
+
return explicitTier;
|
|
312965
|
+
}
|
|
312966
|
+
if (!modelName) return "medium";
|
|
312967
|
+
const m2 = modelName.toLowerCase();
|
|
312968
|
+
const match = m2.match(/(\d+)\s*[bB]/);
|
|
312969
|
+
if (match) {
|
|
312970
|
+
const b = parseInt(match[1], 10);
|
|
312971
|
+
if (b <= 7) return "small";
|
|
312972
|
+
if (b <= 29) return "medium";
|
|
312973
|
+
if (b <= 70) return "large";
|
|
312974
|
+
return "xlarge";
|
|
312975
|
+
}
|
|
312976
|
+
if (/1\.5b|3b|4b|phi-|tiny/.test(m2)) return "small";
|
|
312977
|
+
if (/7b|8b|9b|13b|mistral-/.test(m2)) return "medium";
|
|
312978
|
+
if (/27b|30b|32b|34b|gemma2|qwen2\.5-32/.test(m2)) return "large";
|
|
312979
|
+
if (/70b|72b|mixtral-8x|100b|122b|123b|opus|405b|deepseek-v|claude/.test(m2)) return "xlarge";
|
|
312980
|
+
return "medium";
|
|
312981
|
+
}
|
|
312982
|
+
function budgetForTier(tier) {
|
|
312983
|
+
switch (tier) {
|
|
312984
|
+
case "small":
|
|
312985
|
+
return { indexTokens: 2e3, metadataTokens: 0, contentTokens: 0, frameworkTokens: 0 };
|
|
312986
|
+
case "medium":
|
|
312987
|
+
return { indexTokens: 4e3, metadataTokens: 8e3, contentTokens: 2e4, frameworkTokens: 0 };
|
|
312988
|
+
case "large":
|
|
312989
|
+
return { indexTokens: 6e3, metadataTokens: 16e3, contentTokens: 5e4, frameworkTokens: 1e5 };
|
|
312990
|
+
case "xlarge":
|
|
312991
|
+
return { indexTokens: 1e4, metadataTokens: 3e4, contentTokens: 1e5, frameworkTokens: 3e5 };
|
|
312992
|
+
}
|
|
312993
|
+
}
|
|
312994
|
+
async function tryRouteAiwg(ctx3) {
|
|
312995
|
+
const { pathname, method } = ctx3;
|
|
312996
|
+
if (pathname === "/v1/aiwg" && method === "GET") return handleAiwgRoot(ctx3);
|
|
312997
|
+
if (pathname === "/v1/aiwg/frameworks" && method === "GET") return handleListFrameworks(ctx3);
|
|
312998
|
+
const fwMatch = pathname.match(/^\/v1\/aiwg\/frameworks\/([^/]+)$/);
|
|
312999
|
+
if (fwMatch && method === "GET") return handleGetFramework(ctx3, decodeURIComponent(fwMatch[1]));
|
|
313000
|
+
const fwContentMatch = pathname.match(/^\/v1\/aiwg\/frameworks\/([^/]+)\/content$/);
|
|
313001
|
+
if (fwContentMatch && method === "GET") return handleGetFrameworkContent(ctx3, decodeURIComponent(fwContentMatch[1]));
|
|
313002
|
+
if (pathname === "/v1/aiwg/skills" && method === "GET") return handleListSkillsAiwg(ctx3);
|
|
313003
|
+
const skMatch = pathname.match(/^\/v1\/aiwg\/skills\/([^/]+)$/);
|
|
313004
|
+
if (skMatch && method === "GET") return handleGetSkillAiwg(ctx3, decodeURIComponent(skMatch[1]));
|
|
313005
|
+
if (pathname === "/v1/aiwg/agents" && method === "GET") return handleListAgentsAiwg(ctx3);
|
|
313006
|
+
const agMatch = pathname.match(/^\/v1\/aiwg\/agents\/([^/]+)$/);
|
|
313007
|
+
if (agMatch && method === "GET") return handleGetAgentAiwg(ctx3, decodeURIComponent(agMatch[1]));
|
|
313008
|
+
if (pathname === "/v1/aiwg/addons" && method === "GET") return handleListAddonsAiwg(ctx3);
|
|
313009
|
+
if (pathname === "/v1/aiwg/use" && method === "POST") return handleAiwgUse(ctx3);
|
|
313010
|
+
if (pathname === "/v1/aiwg/expand" && method === "POST") return handleAiwgExpand(ctx3);
|
|
313011
|
+
return false;
|
|
313012
|
+
}
|
|
313013
|
+
async function handleAiwgRoot(ctx3) {
|
|
313014
|
+
const { req: req2, res } = ctx3;
|
|
313015
|
+
const root = resolveAiwgRoot();
|
|
313016
|
+
const frameworks = listAiwgFrameworks();
|
|
313017
|
+
const items = listAiwgItems();
|
|
313018
|
+
const addons = listAiwgAddons();
|
|
313019
|
+
const totalSize = frameworks.reduce((s2, f2) => s2 + f2.size_bytes, 0) + addons.reduce((s2, a2) => s2 + a2.size_bytes, 0);
|
|
313020
|
+
const payload = {
|
|
313021
|
+
installed: root !== null,
|
|
313022
|
+
root,
|
|
313023
|
+
counts: {
|
|
313024
|
+
frameworks: frameworks.length,
|
|
313025
|
+
addons: addons.length,
|
|
313026
|
+
skills: items.filter((i2) => i2.kind === "skill").length,
|
|
313027
|
+
agents: items.filter((i2) => i2.kind === "agent").length,
|
|
313028
|
+
commands: items.filter((i2) => i2.kind === "command").length
|
|
313029
|
+
},
|
|
313030
|
+
total_size_bytes: totalSize,
|
|
313031
|
+
total_size_mb: Math.round(totalSize / (1024 * 1024) * 10) / 10,
|
|
313032
|
+
cascade_tiers: {
|
|
313033
|
+
"0_index": "Names + triggers + 1-line descriptions. Always safe (~2K tokens).",
|
|
313034
|
+
"1_metadata": "Per-item frontmatter + first section (~1-2K per item).",
|
|
313035
|
+
"2_content": "Per-item full body (~2-10K per item).",
|
|
313036
|
+
"3_framework": "Whole framework bundle (100K+ tokens, large models only)."
|
|
313037
|
+
},
|
|
313038
|
+
endpoints: {
|
|
313039
|
+
frameworks: "/v1/aiwg/frameworks",
|
|
313040
|
+
framework_detail: "/v1/aiwg/frameworks/{name}",
|
|
313041
|
+
framework_content: "/v1/aiwg/frameworks/{name}/content?tier=2|3",
|
|
313042
|
+
skills: "/v1/aiwg/skills",
|
|
313043
|
+
skill_detail: "/v1/aiwg/skills/{name}",
|
|
313044
|
+
agents: "/v1/aiwg/agents",
|
|
313045
|
+
agent_detail: "/v1/aiwg/agents/{name}",
|
|
313046
|
+
addons: "/v1/aiwg/addons",
|
|
313047
|
+
use: "POST /v1/aiwg/use \u2014 `aiwg use all` equivalent with cascade sizing",
|
|
313048
|
+
expand: "POST /v1/aiwg/expand \u2014 sub-agent unpack by trigger or name"
|
|
313049
|
+
},
|
|
313050
|
+
warning_context_hog: "AIWG is ~" + Math.round(totalSize / (1024 * 1024)) + " MB of markdown (~2M tokens raw). NEVER request tier=3 on a small model. The /v1/aiwg/use endpoint auto-sizes by model tier."
|
|
313051
|
+
};
|
|
313052
|
+
const etag = computeEtag(payload);
|
|
313053
|
+
if (checkNotModified(req2, res, etag)) return true;
|
|
313054
|
+
sendJson(res, 200, payload, { etag, cacheControl: "private, max-age=60" });
|
|
313055
|
+
return true;
|
|
313056
|
+
}
|
|
313057
|
+
async function handleListFrameworks(ctx3) {
|
|
313058
|
+
const { req: req2, res, url } = ctx3;
|
|
313059
|
+
const list = listAiwgFrameworks();
|
|
313060
|
+
const page2 = parsePagination(url.searchParams);
|
|
313061
|
+
const env2 = paginated(list, page2);
|
|
313062
|
+
const etag = computeEtag(env2);
|
|
313063
|
+
if (checkNotModified(req2, res, etag)) return true;
|
|
313064
|
+
sendJson(res, 200, env2, { etag, cacheControl: "private, max-age=60" });
|
|
313065
|
+
return true;
|
|
313066
|
+
}
|
|
313067
|
+
async function handleGetFramework(ctx3, name10) {
|
|
313068
|
+
const { req: req2, res, requestId } = ctx3;
|
|
313069
|
+
const fw = listAiwgFrameworks().find((f2) => f2.name === name10);
|
|
313070
|
+
if (!fw) {
|
|
313071
|
+
sendProblem(res, problemDetails({
|
|
313072
|
+
type: "https://openagents.nexus/problems/not-found",
|
|
313073
|
+
status: 404,
|
|
313074
|
+
title: "Framework not found",
|
|
313075
|
+
detail: `No AIWG framework named '${name10}'`,
|
|
313076
|
+
instance: requestId
|
|
313077
|
+
}));
|
|
313078
|
+
return true;
|
|
313079
|
+
}
|
|
313080
|
+
const items = listAiwgItems().filter((i2) => i2.source === name10);
|
|
313081
|
+
const payload = {
|
|
313082
|
+
...fw,
|
|
313083
|
+
items: items.map((i2) => ({ name: i2.name, kind: i2.kind, description: i2.description, triggers: i2.triggers })),
|
|
313084
|
+
context_advice: {
|
|
313085
|
+
small_model: "Use /v1/aiwg/expand with a trigger phrase \u2014 don't load the full framework.",
|
|
313086
|
+
medium_model: `Load at most ${Math.max(1, Math.floor(8e3 / 1500))} individual skills via /v1/aiwg/skills/{name}.`,
|
|
313087
|
+
large_model: `Can safely request /v1/aiwg/frameworks/${name10}/content?tier=2 (full metadata).`
|
|
313088
|
+
}
|
|
313089
|
+
};
|
|
313090
|
+
const etag = computeEtag(payload);
|
|
313091
|
+
if (checkNotModified(req2, res, etag)) return true;
|
|
313092
|
+
sendJson(res, 200, payload, { etag, cacheControl: "private, max-age=60" });
|
|
313093
|
+
return true;
|
|
313094
|
+
}
|
|
313095
|
+
async function handleGetFrameworkContent(ctx3, name10) {
|
|
313096
|
+
const { req: req2, res, url, requestId } = ctx3;
|
|
313097
|
+
const fw = listAiwgFrameworks().find((f2) => f2.name === name10);
|
|
313098
|
+
if (!fw) {
|
|
313099
|
+
sendProblem(res, problemDetails({
|
|
313100
|
+
type: "https://openagents.nexus/problems/not-found",
|
|
313101
|
+
status: 404,
|
|
313102
|
+
title: "Framework not found",
|
|
313103
|
+
instance: requestId
|
|
313104
|
+
}));
|
|
313105
|
+
return true;
|
|
313106
|
+
}
|
|
313107
|
+
const tier = url.searchParams.get("tier") || "2";
|
|
313108
|
+
const modelName = url.searchParams.get("model") || void 0;
|
|
313109
|
+
const modelTier = detectModelTier(modelName, tier === "2" || tier === "3" ? void 0 : tier);
|
|
313110
|
+
const budget = budgetForTier(modelTier);
|
|
313111
|
+
if (tier === "3" && modelTier === "small" && url.searchParams.get("override") !== "iknowwhatimdoing") {
|
|
313112
|
+
sendProblem(res, problemDetails({
|
|
313113
|
+
type: "https://openagents.nexus/problems/context-overflow",
|
|
313114
|
+
status: 413,
|
|
313115
|
+
title: "Framework bundle too large for detected model tier",
|
|
313116
|
+
detail: `Framework '${name10}' is ~${fw.token_estimate} tokens. Small-model budget is ${budget.frameworkTokens} tokens. Use /v1/aiwg/expand with a trigger instead, or add ?override=iknowwhatimdoing to force.`,
|
|
313117
|
+
instance: requestId,
|
|
313118
|
+
extensions: {
|
|
313119
|
+
framework_tokens: fw.token_estimate,
|
|
313120
|
+
budget_tokens: budget.frameworkTokens,
|
|
313121
|
+
detected_tier: modelTier
|
|
313122
|
+
}
|
|
313123
|
+
}));
|
|
313124
|
+
return true;
|
|
313125
|
+
}
|
|
313126
|
+
const items = listAiwgItems().filter((i2) => i2.source === name10);
|
|
313127
|
+
const maxPerItem = tier === "3" ? 8e3 : 3e3;
|
|
313128
|
+
const withContent = items.slice(0, tier === "3" ? 100 : 30).map((i2) => ({
|
|
313129
|
+
name: i2.name,
|
|
313130
|
+
kind: i2.kind,
|
|
313131
|
+
description: i2.description,
|
|
313132
|
+
triggers: i2.triggers,
|
|
313133
|
+
content: tier === "3" ? loadAiwgItemContent(i2.path, maxPerItem) : void 0
|
|
313134
|
+
}));
|
|
313135
|
+
sendJson(res, 200, {
|
|
313136
|
+
framework: fw,
|
|
313137
|
+
tier,
|
|
313138
|
+
model_tier: modelTier,
|
|
313139
|
+
budget,
|
|
313140
|
+
items: withContent,
|
|
313141
|
+
truncation_note: "Each item capped at " + maxPerItem + " bytes. Use /v1/aiwg/expand for a specific item at full fidelity."
|
|
313142
|
+
}, { cacheControl: "private, max-age=60" });
|
|
313143
|
+
return true;
|
|
313144
|
+
}
|
|
313145
|
+
async function handleListSkillsAiwg(ctx3) {
|
|
313146
|
+
const { req: req2, res, url } = ctx3;
|
|
313147
|
+
const list = listAiwgItems().filter((i2) => i2.kind === "skill");
|
|
313148
|
+
const source = url.searchParams.get("source");
|
|
313149
|
+
const filtered = source ? list.filter((i2) => i2.source === source) : list;
|
|
313150
|
+
const page2 = parsePagination(url.searchParams);
|
|
313151
|
+
const env2 = paginated(filtered.map((i2) => ({
|
|
313152
|
+
name: i2.name,
|
|
313153
|
+
description: i2.description,
|
|
313154
|
+
triggers: i2.triggers,
|
|
313155
|
+
source: i2.source,
|
|
313156
|
+
path: i2.path
|
|
313157
|
+
})), page2);
|
|
313158
|
+
const etag = computeEtag(env2);
|
|
313159
|
+
if (checkNotModified(req2, res, etag)) return true;
|
|
313160
|
+
sendJson(res, 200, env2, { etag, cacheControl: "private, max-age=60" });
|
|
313161
|
+
return true;
|
|
313162
|
+
}
|
|
313163
|
+
async function handleGetSkillAiwg(ctx3, name10) {
|
|
313164
|
+
const { req: req2, res, url, requestId } = ctx3;
|
|
313165
|
+
const items = listAiwgItems().filter((i2) => i2.kind === "skill");
|
|
313166
|
+
const skill = items.find((i2) => i2.name === name10);
|
|
313167
|
+
if (!skill) {
|
|
313168
|
+
sendProblem(res, problemDetails({
|
|
313169
|
+
type: "https://openagents.nexus/problems/not-found",
|
|
313170
|
+
status: 404,
|
|
313171
|
+
title: "Skill not found",
|
|
313172
|
+
detail: `No AIWG skill named '${name10}'`,
|
|
313173
|
+
instance: requestId
|
|
313174
|
+
}));
|
|
313175
|
+
return true;
|
|
313176
|
+
}
|
|
313177
|
+
const includeContent = url.searchParams.get("content") !== "false";
|
|
313178
|
+
const payload = {
|
|
313179
|
+
...skill,
|
|
313180
|
+
content: includeContent ? loadAiwgItemContent(skill.path) : void 0
|
|
313181
|
+
};
|
|
313182
|
+
const etag = computeEtag(payload);
|
|
313183
|
+
if (checkNotModified(req2, res, etag)) return true;
|
|
313184
|
+
sendJson(res, 200, payload, { etag, cacheControl: "private, max-age=60" });
|
|
313185
|
+
return true;
|
|
313186
|
+
}
|
|
313187
|
+
async function handleListAgentsAiwg(ctx3) {
|
|
313188
|
+
const { req: req2, res, url } = ctx3;
|
|
313189
|
+
const list = listAiwgItems().filter((i2) => i2.kind === "agent");
|
|
313190
|
+
const source = url.searchParams.get("source");
|
|
313191
|
+
const filtered = source ? list.filter((i2) => i2.source === source) : list;
|
|
313192
|
+
const page2 = parsePagination(url.searchParams);
|
|
313193
|
+
const env2 = paginated(filtered.map((i2) => ({
|
|
313194
|
+
name: i2.name,
|
|
313195
|
+
description: i2.description,
|
|
313196
|
+
triggers: i2.triggers,
|
|
313197
|
+
source: i2.source
|
|
313198
|
+
})), page2);
|
|
313199
|
+
const etag = computeEtag(env2);
|
|
313200
|
+
if (checkNotModified(req2, res, etag)) return true;
|
|
313201
|
+
sendJson(res, 200, env2, { etag, cacheControl: "private, max-age=60" });
|
|
313202
|
+
return true;
|
|
313203
|
+
}
|
|
313204
|
+
async function handleGetAgentAiwg(ctx3, name10) {
|
|
313205
|
+
const { req: req2, res, requestId } = ctx3;
|
|
313206
|
+
const ag = listAiwgItems().filter((i2) => i2.kind === "agent").find((i2) => i2.name === name10);
|
|
313207
|
+
if (!ag) {
|
|
313208
|
+
sendProblem(res, problemDetails({
|
|
313209
|
+
type: "https://openagents.nexus/problems/not-found",
|
|
313210
|
+
status: 404,
|
|
313211
|
+
title: "Agent not found",
|
|
313212
|
+
instance: requestId
|
|
313213
|
+
}));
|
|
313214
|
+
return true;
|
|
313215
|
+
}
|
|
313216
|
+
const payload = { ...ag, content: loadAiwgItemContent(ag.path) };
|
|
313217
|
+
const etag = computeEtag(payload);
|
|
313218
|
+
if (checkNotModified(req2, res, etag)) return true;
|
|
313219
|
+
sendJson(res, 200, payload, { etag, cacheControl: "private, max-age=60" });
|
|
313220
|
+
return true;
|
|
313221
|
+
}
|
|
313222
|
+
async function handleListAddonsAiwg(ctx3) {
|
|
313223
|
+
const { req: req2, res, url } = ctx3;
|
|
313224
|
+
const list = listAiwgAddons();
|
|
313225
|
+
const page2 = parsePagination(url.searchParams);
|
|
313226
|
+
const env2 = paginated(list, page2);
|
|
313227
|
+
const etag = computeEtag(env2);
|
|
313228
|
+
if (checkNotModified(req2, res, etag)) return true;
|
|
313229
|
+
sendJson(res, 200, env2, { etag, cacheControl: "private, max-age=60" });
|
|
313230
|
+
return true;
|
|
313231
|
+
}
|
|
313232
|
+
async function handleAiwgUse(ctx3) {
|
|
313233
|
+
const { req: req2, res, requestId, user } = ctx3;
|
|
313234
|
+
try {
|
|
313235
|
+
const body = await parseJsonBodyStrict(req2).catch(() => ({}));
|
|
313236
|
+
const scope = body?.scope || "all";
|
|
313237
|
+
const modelName = body?.model;
|
|
313238
|
+
const tier = detectModelTier(modelName, body?.tier);
|
|
313239
|
+
const budget = budgetForTier(tier);
|
|
313240
|
+
const frameworks = listAiwgFrameworks();
|
|
313241
|
+
const items = listAiwgItems();
|
|
313242
|
+
const addons = listAiwgAddons();
|
|
313243
|
+
let selectedFrameworks = frameworks;
|
|
313244
|
+
let selectedItems = items;
|
|
313245
|
+
if (scope !== "all") {
|
|
313246
|
+
const scopes = Array.isArray(scope) ? scope : [scope];
|
|
313247
|
+
selectedFrameworks = frameworks.filter((f2) => scopes.includes(f2.name));
|
|
313248
|
+
selectedItems = items.filter((i2) => scopes.includes(i2.source));
|
|
313249
|
+
}
|
|
313250
|
+
const bundle = {
|
|
313251
|
+
scope,
|
|
313252
|
+
requested_model: modelName,
|
|
313253
|
+
detected_tier: tier,
|
|
313254
|
+
budget,
|
|
313255
|
+
frameworks: selectedFrameworks.map((f2) => ({
|
|
313256
|
+
name: f2.name,
|
|
313257
|
+
description: f2.description,
|
|
313258
|
+
file_count: f2.file_count,
|
|
313259
|
+
skills_count: f2.skills_count,
|
|
313260
|
+
agents_count: f2.agents_count,
|
|
313261
|
+
token_estimate: f2.token_estimate
|
|
313262
|
+
})),
|
|
313263
|
+
addons: tier === "small" ? [] : addons.map((a2) => ({ name: a2.name, description: a2.description })),
|
|
313264
|
+
index: buildIndex(selectedItems, tier)
|
|
313265
|
+
};
|
|
313266
|
+
if (tier === "medium" || tier === "large" || tier === "xlarge") {
|
|
313267
|
+
bundle.metadata = buildMetadata(selectedItems, tier);
|
|
313268
|
+
}
|
|
313269
|
+
if (tier === "large" || tier === "xlarge") {
|
|
313270
|
+
bundle.content = buildContent(selectedItems, tier);
|
|
313271
|
+
}
|
|
313272
|
+
const totalTokens = Math.round(JSON.stringify(bundle).length / 4);
|
|
313273
|
+
bundle.bundle_tokens = totalTokens;
|
|
313274
|
+
bundle.budget_ok = totalTokens <= (budget.frameworkTokens || budget.contentTokens || budget.metadataTokens || budget.indexTokens) * 1.5;
|
|
313275
|
+
bundle.cascade_advice = {
|
|
313276
|
+
if_small_model: "You received the Tier 0 index only. When a task requires a specific skill, POST /v1/aiwg/expand with {trigger: '<phrase>'} to fetch one skill at a time.",
|
|
313277
|
+
if_medium_model: "You received Tier 1 metadata. Individual skills are listed with their front-matter. Fetch full content via /v1/aiwg/skills/{name}.",
|
|
313278
|
+
if_large_model: "You received Tier 2 content for top skills. Full framework dumps are available at /v1/aiwg/frameworks/{name}/content?tier=3.",
|
|
313279
|
+
always: "NEVER inline more than budget.frameworkTokens into a model prompt. Use the expand endpoint for targeted loads."
|
|
313280
|
+
};
|
|
313281
|
+
publishEvent("aims.decision_recorded", { kind: "aiwg_activation", scope, tier, tokens: totalTokens }, {
|
|
313282
|
+
subject: user ?? "anonymous",
|
|
313283
|
+
aimsControl: "A.7.3"
|
|
313284
|
+
// data for AI systems (knowledge injection record)
|
|
313285
|
+
});
|
|
313286
|
+
sendJson(res, 200, bundle, { cacheControl: "private, max-age=30" });
|
|
313287
|
+
return true;
|
|
313288
|
+
} catch (err) {
|
|
313289
|
+
sendProblem(res, problemDetails({
|
|
313290
|
+
type: "https://openagents.nexus/problems/internal-error",
|
|
313291
|
+
status: 500,
|
|
313292
|
+
title: "AIWG activation failed",
|
|
313293
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
313294
|
+
instance: requestId
|
|
313295
|
+
}));
|
|
313296
|
+
return true;
|
|
313297
|
+
}
|
|
313298
|
+
}
|
|
313299
|
+
function buildIndex(items, tier) {
|
|
313300
|
+
const maxItems = tier === "small" ? 50 : 500;
|
|
313301
|
+
return items.slice(0, maxItems).map((i2) => ({
|
|
313302
|
+
name: i2.name,
|
|
313303
|
+
kind: i2.kind,
|
|
313304
|
+
source: i2.source,
|
|
313305
|
+
triggers: i2.triggers.slice(0, tier === "small" ? 2 : 5),
|
|
313306
|
+
description: i2.description.slice(0, tier === "small" ? 80 : 200)
|
|
313307
|
+
}));
|
|
313308
|
+
}
|
|
313309
|
+
function buildMetadata(items, tier) {
|
|
313310
|
+
const maxItems = tier === "medium" ? 30 : tier === "large" ? 100 : 300;
|
|
313311
|
+
return items.slice(0, maxItems).map((i2) => {
|
|
313312
|
+
const head = loadAiwgItemContent(i2.path, 1500) || "";
|
|
313313
|
+
return {
|
|
313314
|
+
name: i2.name,
|
|
313315
|
+
kind: i2.kind,
|
|
313316
|
+
source: i2.source,
|
|
313317
|
+
triggers: i2.triggers,
|
|
313318
|
+
description: i2.description,
|
|
313319
|
+
head: head.slice(0, 1500)
|
|
313320
|
+
};
|
|
313321
|
+
});
|
|
313322
|
+
}
|
|
313323
|
+
function buildContent(items, tier) {
|
|
313324
|
+
const perItemCap = tier === "large" ? 4e3 : 1e4;
|
|
313325
|
+
const maxItems = tier === "large" ? 20 : 80;
|
|
313326
|
+
return items.slice(0, maxItems).map((i2) => ({
|
|
313327
|
+
name: i2.name,
|
|
313328
|
+
kind: i2.kind,
|
|
313329
|
+
source: i2.source,
|
|
313330
|
+
content: loadAiwgItemContent(i2.path, perItemCap)
|
|
313331
|
+
}));
|
|
313332
|
+
}
|
|
313333
|
+
async function handleAiwgExpand(ctx3) {
|
|
313334
|
+
const { req: req2, res, requestId, user } = ctx3;
|
|
313335
|
+
try {
|
|
313336
|
+
const body = await parseJsonBodyStrict(req2).catch(() => null);
|
|
313337
|
+
if (!body) {
|
|
313338
|
+
sendProblem(res, problemDetails({
|
|
313339
|
+
type: "https://openagents.nexus/problems/invalid-request",
|
|
313340
|
+
status: 400,
|
|
313341
|
+
title: "Missing body",
|
|
313342
|
+
detail: "POST body must include {trigger?: string, name?: string, limit?: number}",
|
|
313343
|
+
instance: requestId
|
|
313344
|
+
}));
|
|
313345
|
+
return true;
|
|
313346
|
+
}
|
|
313347
|
+
const trigger = typeof body.trigger === "string" ? body.trigger.toLowerCase() : null;
|
|
313348
|
+
const name10 = typeof body.name === "string" ? body.name : null;
|
|
313349
|
+
const limit = typeof body.limit === "number" ? Math.min(body.limit, 10) : 3;
|
|
313350
|
+
if (!trigger && !name10) {
|
|
313351
|
+
sendProblem(res, problemDetails({
|
|
313352
|
+
type: "https://openagents.nexus/problems/invalid-request",
|
|
313353
|
+
status: 400,
|
|
313354
|
+
title: "Missing 'trigger' or 'name'",
|
|
313355
|
+
detail: "Provide either a trigger phrase or an explicit skill/agent name",
|
|
313356
|
+
instance: requestId
|
|
313357
|
+
}));
|
|
313358
|
+
return true;
|
|
313359
|
+
}
|
|
313360
|
+
const items = listAiwgItems();
|
|
313361
|
+
const matches = [];
|
|
313362
|
+
if (name10) {
|
|
313363
|
+
const exact = items.find((i2) => i2.name === name10);
|
|
313364
|
+
if (exact) matches.push(exact);
|
|
313365
|
+
}
|
|
313366
|
+
if (trigger && matches.length < limit) {
|
|
313367
|
+
for (const i2 of items) {
|
|
313368
|
+
if (matches.length >= limit) break;
|
|
313369
|
+
const hay = [i2.name, i2.description, ...i2.triggers].join(" ").toLowerCase();
|
|
313370
|
+
if (hay.includes(trigger)) {
|
|
313371
|
+
if (!matches.some((m2) => m2.path === i2.path)) matches.push(i2);
|
|
313372
|
+
}
|
|
313373
|
+
}
|
|
313374
|
+
}
|
|
313375
|
+
if (matches.length === 0) {
|
|
313376
|
+
sendProblem(res, problemDetails({
|
|
313377
|
+
type: "https://openagents.nexus/problems/not-found",
|
|
313378
|
+
status: 404,
|
|
313379
|
+
title: "No matching AIWG items",
|
|
313380
|
+
detail: `No items matched trigger='${trigger}' name='${name10}'`,
|
|
313381
|
+
instance: requestId
|
|
313382
|
+
}));
|
|
313383
|
+
return true;
|
|
313384
|
+
}
|
|
313385
|
+
const unpacked = matches.map((m2) => ({
|
|
313386
|
+
name: m2.name,
|
|
313387
|
+
kind: m2.kind,
|
|
313388
|
+
source: m2.source,
|
|
313389
|
+
description: m2.description,
|
|
313390
|
+
triggers: m2.triggers,
|
|
313391
|
+
content: loadAiwgItemContent(m2.path, 1e4)
|
|
313392
|
+
}));
|
|
313393
|
+
publishEvent("skill.invoked", { count: unpacked.length, trigger, name: name10 }, {
|
|
313394
|
+
subject: user ?? "anonymous",
|
|
313395
|
+
aimsControl: "A.7.3"
|
|
313396
|
+
});
|
|
313397
|
+
sendJson(res, 200, {
|
|
313398
|
+
query: { trigger, name: name10, limit },
|
|
313399
|
+
matches: unpacked.length,
|
|
313400
|
+
items: unpacked
|
|
313401
|
+
}, { cacheControl: "private, max-age=30" });
|
|
313402
|
+
return true;
|
|
313403
|
+
} catch (err) {
|
|
313404
|
+
sendProblem(res, problemDetails({
|
|
313405
|
+
type: "https://openagents.nexus/problems/internal-error",
|
|
313406
|
+
status: 500,
|
|
313407
|
+
title: "AIWG expand failed",
|
|
313408
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
313409
|
+
instance: requestId
|
|
313410
|
+
}));
|
|
313411
|
+
return true;
|
|
313412
|
+
}
|
|
313413
|
+
}
|
|
313414
|
+
var _cachedAiwgRoot, _cachedFrameworks, _cachedItems, _cachedAddons;
|
|
313415
|
+
var init_aiwg = __esm({
|
|
313416
|
+
"packages/cli/src/api/aiwg.ts"() {
|
|
313417
|
+
"use strict";
|
|
313418
|
+
init_http2();
|
|
313419
|
+
_cachedFrameworks = null;
|
|
313420
|
+
_cachedItems = null;
|
|
313421
|
+
_cachedAddons = null;
|
|
313422
|
+
}
|
|
313423
|
+
});
|
|
313424
|
+
|
|
313425
|
+
// packages/cli/src/api/routes-v1.ts
|
|
313426
|
+
import { existsSync as existsSync73, readFileSync as readFileSync57, readdirSync as readdirSync23, statSync as statSync22 } from "node:fs";
|
|
313427
|
+
import { join as join90, resolve as pathResolve } from "node:path";
|
|
313428
|
+
import { homedir as homedir29 } from "node:os";
|
|
312680
313429
|
async function tryRouteV1(ctx3) {
|
|
312681
313430
|
const { pathname, method } = ctx3;
|
|
312682
313431
|
if (pathname === "/v1/skills" && method === "GET") {
|
|
@@ -312776,6 +313525,10 @@ async function tryRouteV1(ctx3) {
|
|
|
312776
313525
|
if (pathname === "/v1/aims" || pathname.startsWith("/v1/aims/")) {
|
|
312777
313526
|
return tryAimsRoute(ctx3);
|
|
312778
313527
|
}
|
|
313528
|
+
if (pathname === "/v1/aiwg" || pathname.startsWith("/v1/aiwg/")) {
|
|
313529
|
+
const { tryRouteAiwg: tryRouteAiwg2 } = await Promise.resolve().then(() => (init_aiwg(), aiwg_exports));
|
|
313530
|
+
return tryRouteAiwg2(ctx3);
|
|
313531
|
+
}
|
|
312779
313532
|
return false;
|
|
312780
313533
|
}
|
|
312781
313534
|
async function handleListSkills(ctx3) {
|
|
@@ -312877,11 +313630,11 @@ async function handleGetSkill(ctx3, name10) {
|
|
|
312877
313630
|
async function fallbackDiscoverSkills() {
|
|
312878
313631
|
return (_root) => {
|
|
312879
313632
|
const roots = [
|
|
312880
|
-
|
|
313633
|
+
join90(homedir29(), ".local", "share", "ai-writing-guide")
|
|
312881
313634
|
];
|
|
312882
313635
|
const out = [];
|
|
312883
313636
|
for (const root of roots) {
|
|
312884
|
-
if (!
|
|
313637
|
+
if (!existsSync73(root)) continue;
|
|
312885
313638
|
walkForSkills(root, out, 0);
|
|
312886
313639
|
}
|
|
312887
313640
|
return out;
|
|
@@ -312890,14 +313643,14 @@ async function fallbackDiscoverSkills() {
|
|
|
312890
313643
|
function walkForSkills(dir, out, depth) {
|
|
312891
313644
|
if (depth > 6) return;
|
|
312892
313645
|
try {
|
|
312893
|
-
for (const e2 of
|
|
313646
|
+
for (const e2 of readdirSync23(dir, { withFileTypes: true })) {
|
|
312894
313647
|
if (e2.name.startsWith(".") || e2.name === "node_modules") continue;
|
|
312895
|
-
const p2 =
|
|
313648
|
+
const p2 = join90(dir, e2.name);
|
|
312896
313649
|
if (e2.isDirectory()) {
|
|
312897
313650
|
walkForSkills(p2, out, depth + 1);
|
|
312898
313651
|
} else if (e2.isFile() && e2.name === "SKILL.md") {
|
|
312899
313652
|
try {
|
|
312900
|
-
const content =
|
|
313653
|
+
const content = readFileSync57(p2, "utf-8").slice(0, 2e3);
|
|
312901
313654
|
const nameMatch = content.match(/^name:\s*(.+)$/m);
|
|
312902
313655
|
const descMatch = content.match(/^description:\s*(.+)$/m);
|
|
312903
313656
|
out.push({
|
|
@@ -313081,7 +313834,7 @@ async function getMemoryStores() {
|
|
|
313081
313834
|
try {
|
|
313082
313835
|
const memMod = await Promise.resolve().then(() => (init_dist7(), dist_exports3));
|
|
313083
313836
|
const { initDb: initDb2, EpisodeStore: EpisodeStore2, TemporalGraph: TemporalGraph2, FailureStore: FailureStore2 } = memMod;
|
|
313084
|
-
const dbPath =
|
|
313837
|
+
const dbPath = join90(homedir29(), ".open-agents", "memory.db");
|
|
313085
313838
|
const db = initDb2(dbPath);
|
|
313086
313839
|
memoryStoresCache = {
|
|
313087
313840
|
episode: new EpisodeStore2(db),
|
|
@@ -313325,7 +314078,7 @@ async function handleFilesRead(ctx3) {
|
|
|
313325
314078
|
}));
|
|
313326
314079
|
return true;
|
|
313327
314080
|
}
|
|
313328
|
-
if (!
|
|
314081
|
+
if (!existsSync73(resolved)) {
|
|
313329
314082
|
sendProblem(res, problemDetails({
|
|
313330
314083
|
type: P.notFound,
|
|
313331
314084
|
status: 404,
|
|
@@ -313335,7 +314088,7 @@ async function handleFilesRead(ctx3) {
|
|
|
313335
314088
|
}));
|
|
313336
314089
|
return true;
|
|
313337
314090
|
}
|
|
313338
|
-
const st =
|
|
314091
|
+
const st = statSync22(resolved);
|
|
313339
314092
|
if (st.isDirectory()) {
|
|
313340
314093
|
sendProblem(res, problemDetails({
|
|
313341
314094
|
type: P.invalidRequest,
|
|
@@ -313357,7 +314110,7 @@ async function handleFilesRead(ctx3) {
|
|
|
313357
314110
|
}));
|
|
313358
314111
|
return true;
|
|
313359
314112
|
}
|
|
313360
|
-
const content =
|
|
314113
|
+
const content = readFileSync57(resolved, "utf-8");
|
|
313361
314114
|
const offset = typeof body.offset === "number" && body.offset >= 0 ? body.offset : 0;
|
|
313362
314115
|
const limit = typeof body.limit === "number" && body.limit > 0 ? body.limit : content.length;
|
|
313363
314116
|
const slice2 = content.slice(offset, offset + limit);
|
|
@@ -313513,17 +314266,17 @@ async function handleContextSave(ctx3) {
|
|
|
313513
314266
|
const body = await parseJsonBodyStrict(req2).catch(() => null);
|
|
313514
314267
|
const repoRoot = typeof body?.repo === "string" && body.repo || process.cwd();
|
|
313515
314268
|
const entry = {
|
|
313516
|
-
|
|
313517
|
-
|
|
313518
|
-
|
|
313519
|
-
|
|
313520
|
-
|
|
313521
|
-
|
|
313522
|
-
|
|
313523
|
-
|
|
314269
|
+
savedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
314270
|
+
task: typeof body?.task === "string" ? body.task : typeof body?.prompt === "string" ? body.prompt : typeof body?.task_id === "string" ? body.task_id : `manual-${Date.now()}`,
|
|
314271
|
+
summary: typeof body?.summary === "string" ? body.summary : "",
|
|
314272
|
+
filesModified: Array.isArray(body?.files_modified) ? body.files_modified : [],
|
|
314273
|
+
toolCalls: typeof body?.tool_calls === "number" ? body.tool_calls : 0,
|
|
314274
|
+
completed: body?.completed !== false,
|
|
314275
|
+
// default true
|
|
314276
|
+
model: typeof body?.model === "string" ? body.model : ""
|
|
313524
314277
|
};
|
|
313525
314278
|
saveSessionContext(repoRoot, entry);
|
|
313526
|
-
publishEvent("session.created", {
|
|
314279
|
+
publishEvent("session.created", { task: entry.task.slice(0, 80) }, {
|
|
313527
314280
|
subject: user ?? "anonymous",
|
|
313528
314281
|
aimsControl: "A.6.2.6"
|
|
313529
314282
|
});
|
|
@@ -313541,26 +314294,19 @@ async function handleContextSave(ctx3) {
|
|
|
313541
314294
|
}
|
|
313542
314295
|
}
|
|
313543
314296
|
async function handleContextRestore(ctx3) {
|
|
313544
|
-
const { res, url
|
|
314297
|
+
const { res, url } = ctx3;
|
|
314298
|
+
const repoRoot = url.searchParams.get("repo") || process.cwd();
|
|
314299
|
+
let prompt = null;
|
|
313545
314300
|
try {
|
|
313546
|
-
|
|
313547
|
-
|
|
313548
|
-
sendJson(res, 200, {
|
|
313549
|
-
repo: repoRoot,
|
|
313550
|
-
restore_prompt: prompt ?? null,
|
|
313551
|
-
available: !!prompt
|
|
313552
|
-
});
|
|
313553
|
-
return true;
|
|
313554
|
-
} catch (err) {
|
|
313555
|
-
sendProblem(res, problemDetails({
|
|
313556
|
-
type: P.internalError,
|
|
313557
|
-
status: 500,
|
|
313558
|
-
title: "Context restore failed",
|
|
313559
|
-
detail: err instanceof Error ? err.message : String(err),
|
|
313560
|
-
instance: requestId
|
|
313561
|
-
}));
|
|
313562
|
-
return true;
|
|
314301
|
+
prompt = buildContextRestorePrompt(repoRoot);
|
|
314302
|
+
} catch {
|
|
313563
314303
|
}
|
|
314304
|
+
sendJson(res, 200, {
|
|
314305
|
+
repo: repoRoot,
|
|
314306
|
+
restore_prompt: prompt,
|
|
314307
|
+
available: !!prompt
|
|
314308
|
+
});
|
|
314309
|
+
return true;
|
|
313564
314310
|
}
|
|
313565
314311
|
async function handleContextCompact(ctx3) {
|
|
313566
314312
|
const { req: req2, res, requestId, user } = ctx3;
|
|
@@ -313595,14 +314341,14 @@ async function handleNexusStatus(ctx3) {
|
|
|
313595
314341
|
const { res, requestId } = ctx3;
|
|
313596
314342
|
try {
|
|
313597
314343
|
const statePaths = [
|
|
313598
|
-
|
|
313599
|
-
|
|
314344
|
+
join90(process.cwd(), ".oa", "nexus-peer-state.json"),
|
|
314345
|
+
join90(homedir29(), ".open-agents", "nexus-peer-cache.json")
|
|
313600
314346
|
];
|
|
313601
314347
|
const states = [];
|
|
313602
314348
|
for (const p2 of statePaths) {
|
|
313603
|
-
if (!
|
|
314349
|
+
if (!existsSync73(p2)) continue;
|
|
313604
314350
|
try {
|
|
313605
|
-
const raw =
|
|
314351
|
+
const raw = readFileSync57(p2, "utf-8");
|
|
313606
314352
|
states.push({ source: p2, data: JSON.parse(raw) });
|
|
313607
314353
|
} catch (e2) {
|
|
313608
314354
|
states.push({ source: p2, error: String(e2) });
|
|
@@ -313629,8 +314375,8 @@ async function handleNexusStatus(ctx3) {
|
|
|
313629
314375
|
}
|
|
313630
314376
|
function loadAgentName() {
|
|
313631
314377
|
try {
|
|
313632
|
-
const p2 =
|
|
313633
|
-
if (
|
|
314378
|
+
const p2 = join90(homedir29(), ".open-agents", "agent-name");
|
|
314379
|
+
if (existsSync73(p2)) return readFileSync57(p2, "utf-8").trim();
|
|
313634
314380
|
} catch {
|
|
313635
314381
|
}
|
|
313636
314382
|
return null;
|
|
@@ -313639,14 +314385,14 @@ async function handleSponsors(ctx3) {
|
|
|
313639
314385
|
const { req: req2, res, url, requestId } = ctx3;
|
|
313640
314386
|
try {
|
|
313641
314387
|
const candidates = [
|
|
313642
|
-
|
|
313643
|
-
|
|
314388
|
+
join90(homedir29(), ".open-agents", "sponsor-cache.json"),
|
|
314389
|
+
join90(homedir29(), ".open-agents", "sponsors.json")
|
|
313644
314390
|
];
|
|
313645
314391
|
let sponsors = [];
|
|
313646
314392
|
for (const p2 of candidates) {
|
|
313647
|
-
if (!
|
|
314393
|
+
if (!existsSync73(p2)) continue;
|
|
313648
314394
|
try {
|
|
313649
|
-
const raw = JSON.parse(
|
|
314395
|
+
const raw = JSON.parse(readFileSync57(p2, "utf-8"));
|
|
313650
314396
|
if (Array.isArray(raw)) {
|
|
313651
314397
|
sponsors = raw;
|
|
313652
314398
|
break;
|
|
@@ -313715,8 +314461,8 @@ async function handleEvaluate(ctx3) {
|
|
|
313715
314461
|
}));
|
|
313716
314462
|
return true;
|
|
313717
314463
|
}
|
|
313718
|
-
const jobPath =
|
|
313719
|
-
if (!
|
|
314464
|
+
const jobPath = join90(process.cwd(), ".oa", "jobs", `${runId}.json`);
|
|
314465
|
+
if (!existsSync73(jobPath)) {
|
|
313720
314466
|
sendProblem(res, problemDetails({
|
|
313721
314467
|
type: P.notFound,
|
|
313722
314468
|
status: 404,
|
|
@@ -313726,7 +314472,7 @@ async function handleEvaluate(ctx3) {
|
|
|
313726
314472
|
}));
|
|
313727
314473
|
return true;
|
|
313728
314474
|
}
|
|
313729
|
-
const job = JSON.parse(
|
|
314475
|
+
const job = JSON.parse(readFileSync57(jobPath, "utf-8"));
|
|
313730
314476
|
sendJson(res, 200, {
|
|
313731
314477
|
run_id: runId,
|
|
313732
314478
|
task: job.task,
|
|
@@ -313864,17 +314610,17 @@ async function handleListAgentTypes(ctx3) {
|
|
|
313864
314610
|
}
|
|
313865
314611
|
async function handleListEngines(ctx3) {
|
|
313866
314612
|
const { res } = ctx3;
|
|
313867
|
-
const home =
|
|
314613
|
+
const home = homedir29();
|
|
313868
314614
|
sendJson(res, 200, {
|
|
313869
314615
|
engines: [
|
|
313870
|
-
{ name: "dream", state_file:
|
|
313871
|
-
{ name: "bless", state_file:
|
|
313872
|
-
{ name: "call", state_file:
|
|
313873
|
-
{ name: "listen", state_file:
|
|
313874
|
-
{ name: "telegram", state_file:
|
|
313875
|
-
{ name: "expose", state_file:
|
|
313876
|
-
{ name: "nexus", state_file:
|
|
313877
|
-
{ name: "ipfs", state_file:
|
|
314616
|
+
{ name: "dream", state_file: join90(process.cwd(), ".oa", "dreams"), controllable_via: "SSE + slash commands" },
|
|
314617
|
+
{ name: "bless", state_file: join90(process.cwd(), ".oa", "bless-state.json"), controllable_via: "slash commands" },
|
|
314618
|
+
{ name: "call", state_file: join90(process.cwd(), ".oa", "call-state.json"), controllable_via: "slash commands" },
|
|
314619
|
+
{ name: "listen", state_file: join90(process.cwd(), ".oa", "listen-state.json"), controllable_via: "slash commands" },
|
|
314620
|
+
{ name: "telegram", state_file: join90(home, ".open-agents", "telegram-state.json"), controllable_via: "slash commands" },
|
|
314621
|
+
{ name: "expose", state_file: join90(process.cwd(), ".oa", "expose-state.json"), controllable_via: "/expose commands" },
|
|
314622
|
+
{ name: "nexus", state_file: join90(home, ".open-agents", "nexus-peer-cache.json"), controllable_via: "/nexus commands" },
|
|
314623
|
+
{ name: "ipfs", state_file: join90(process.cwd(), ".oa", "ipfs"), controllable_via: "slash commands" }
|
|
313878
314624
|
],
|
|
313879
314625
|
note: "Engine instrumentation lives in the running TUI process. Full status + control requires the daemon\u2194TUI bridge (PT-07). See parity audit WO-PARITY-04."
|
|
313880
314626
|
});
|
|
@@ -313957,21 +314703,43 @@ async function tryAimsRoute(ctx3) {
|
|
|
313957
314703
|
return false;
|
|
313958
314704
|
}
|
|
313959
314705
|
function aimsDir() {
|
|
313960
|
-
return
|
|
314706
|
+
return join90(homedir29(), ".open-agents", "aims");
|
|
313961
314707
|
}
|
|
313962
314708
|
function readAimsFile(name10, fallback) {
|
|
313963
314709
|
try {
|
|
313964
|
-
const p2 =
|
|
313965
|
-
if (
|
|
314710
|
+
const p2 = join90(aimsDir(), name10);
|
|
314711
|
+
if (existsSync73(p2)) return JSON.parse(readFileSync57(p2, "utf-8"));
|
|
313966
314712
|
} catch {
|
|
313967
314713
|
}
|
|
313968
314714
|
return fallback;
|
|
313969
314715
|
}
|
|
313970
314716
|
function writeAimsFile(name10, data) {
|
|
313971
314717
|
const dir = aimsDir();
|
|
313972
|
-
const { mkdirSync: mkdirSync50, writeFileSync: wf } = __require("node:fs");
|
|
314718
|
+
const { mkdirSync: mkdirSync50, writeFileSync: wf, renameSync: rn } = __require("node:fs");
|
|
313973
314719
|
mkdirSync50(dir, { recursive: true });
|
|
313974
|
-
|
|
314720
|
+
const finalPath = join90(dir, name10);
|
|
314721
|
+
const tmpPath = `${finalPath}.tmp.${process.pid}.${Date.now()}`;
|
|
314722
|
+
try {
|
|
314723
|
+
wf(tmpPath, JSON.stringify(data, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
|
|
314724
|
+
rn(tmpPath, finalPath);
|
|
314725
|
+
} catch {
|
|
314726
|
+
wf(finalPath, JSON.stringify(data, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
|
|
314727
|
+
}
|
|
314728
|
+
}
|
|
314729
|
+
async function withAimsLock(name10, fn) {
|
|
314730
|
+
const prev = _aimsLocks.get(name10) ?? Promise.resolve();
|
|
314731
|
+
let release2;
|
|
314732
|
+
const next = new Promise((res) => {
|
|
314733
|
+
release2 = res;
|
|
314734
|
+
});
|
|
314735
|
+
_aimsLocks.set(name10, prev.then(() => next));
|
|
314736
|
+
await prev;
|
|
314737
|
+
try {
|
|
314738
|
+
return await fn();
|
|
314739
|
+
} finally {
|
|
314740
|
+
release2();
|
|
314741
|
+
if (_aimsLocks.get(name10) === prev.then(() => next)) _aimsLocks.delete(name10);
|
|
314742
|
+
}
|
|
313975
314743
|
}
|
|
313976
314744
|
async function handleAimsRoot(ctx3) {
|
|
313977
314745
|
const { res } = ctx3;
|
|
@@ -314155,15 +314923,19 @@ async function handleAimsImpactAssessmentPost(ctx3) {
|
|
|
314155
314923
|
}));
|
|
314156
314924
|
return true;
|
|
314157
314925
|
}
|
|
314158
|
-
const
|
|
314159
|
-
const record = {
|
|
314160
|
-
|
|
314161
|
-
|
|
314162
|
-
|
|
314163
|
-
|
|
314164
|
-
|
|
314165
|
-
|
|
314166
|
-
|
|
314926
|
+
const { randomBytes: rb2 } = await import("node:crypto");
|
|
314927
|
+
const record = await withAimsLock("impact-assessments.json", () => {
|
|
314928
|
+
const existing = readAimsFile("impact-assessments.json", []);
|
|
314929
|
+
const rec = {
|
|
314930
|
+
id: `IA-${Date.now()}-${rb2(4).toString("hex")}`,
|
|
314931
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
314932
|
+
author: user ?? "anonymous",
|
|
314933
|
+
...body
|
|
314934
|
+
};
|
|
314935
|
+
existing.push(rec);
|
|
314936
|
+
writeAimsFile("impact-assessments.json", existing);
|
|
314937
|
+
return rec;
|
|
314938
|
+
});
|
|
314167
314939
|
publishEvent("aims.decision_recorded", { kind: "impact_assessment", id: record.id }, {
|
|
314168
314940
|
subject: user ?? "anonymous",
|
|
314169
314941
|
aimsControl: "A.5"
|
|
@@ -314275,12 +315047,12 @@ async function handleAimsSuppliers(ctx3) {
|
|
|
314275
315047
|
}
|
|
314276
315048
|
];
|
|
314277
315049
|
const sponsorPaths = [
|
|
314278
|
-
|
|
315050
|
+
join90(homedir29(), ".open-agents", "sponsor-cache.json")
|
|
314279
315051
|
];
|
|
314280
315052
|
for (const p2 of sponsorPaths) {
|
|
314281
|
-
if (!
|
|
315053
|
+
if (!existsSync73(p2)) continue;
|
|
314282
315054
|
try {
|
|
314283
|
-
const raw = JSON.parse(
|
|
315055
|
+
const raw = JSON.parse(readFileSync57(p2, "utf-8"));
|
|
314284
315056
|
const list = Array.isArray(raw) ? raw : raw?.sponsors ?? [];
|
|
314285
315057
|
for (const s2 of list) {
|
|
314286
315058
|
suppliers.push({
|
|
@@ -314342,16 +315114,20 @@ async function handleAimsIncidentPost(ctx3) {
|
|
|
314342
315114
|
}));
|
|
314343
315115
|
return true;
|
|
314344
315116
|
}
|
|
314345
|
-
const
|
|
314346
|
-
const record = {
|
|
314347
|
-
|
|
314348
|
-
|
|
314349
|
-
|
|
314350
|
-
|
|
314351
|
-
|
|
314352
|
-
|
|
314353
|
-
|
|
314354
|
-
|
|
315117
|
+
const { randomBytes: randomBytes21 } = await import("node:crypto");
|
|
315118
|
+
const record = await withAimsLock("incidents.json", () => {
|
|
315119
|
+
const existing = readAimsFile("incidents.json", []);
|
|
315120
|
+
const rec = {
|
|
315121
|
+
id: `INC-${Date.now()}-${randomBytes21(4).toString("hex")}`,
|
|
315122
|
+
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
315123
|
+
raised_by: user ?? "anonymous",
|
|
315124
|
+
status: "open",
|
|
315125
|
+
...body
|
|
315126
|
+
};
|
|
315127
|
+
existing.push(rec);
|
|
315128
|
+
writeAimsFile("incidents.json", existing);
|
|
315129
|
+
return rec;
|
|
315130
|
+
});
|
|
314355
315131
|
publishEvent("incident.raised", { id: record.id, severity: body.severity }, {
|
|
314356
315132
|
subject: user ?? "anonymous",
|
|
314357
315133
|
aimsControl: "A.6.2.8"
|
|
@@ -314418,7 +315194,7 @@ async function handleAimsConfigHistory(ctx3) {
|
|
|
314418
315194
|
return true;
|
|
314419
315195
|
}
|
|
314420
315196
|
}
|
|
314421
|
-
var PROBLEM_BASE, P, mcpManagerCache, memoryStoresCache, FILE_READ_MAX_BYTES;
|
|
315197
|
+
var PROBLEM_BASE, P, mcpManagerCache, memoryStoresCache, FILE_READ_MAX_BYTES, _aimsLocks;
|
|
314422
315198
|
var init_routes_v1 = __esm({
|
|
314423
315199
|
"packages/cli/src/api/routes-v1.ts"() {
|
|
314424
315200
|
"use strict";
|
|
@@ -314441,6 +315217,7 @@ var init_routes_v1 = __esm({
|
|
|
314441
315217
|
mcpManagerCache = /* @__PURE__ */ new Map();
|
|
314442
315218
|
memoryStoresCache = null;
|
|
314443
315219
|
FILE_READ_MAX_BYTES = 2 * 1024 * 1024;
|
|
315220
|
+
_aimsLocks = /* @__PURE__ */ new Map();
|
|
314444
315221
|
}
|
|
314445
315222
|
});
|
|
314446
315223
|
|
|
@@ -315757,8 +316534,48 @@ function getOpenApiSpec() {
|
|
|
315757
316534
|
}
|
|
315758
316535
|
},
|
|
315759
316536
|
"/v1/embeddings": { post: { summary: "Generate embeddings", tags: ["Inference"], responses: { 200: { description: "Embedding vectors" }, ...ErrorResponses } } },
|
|
315760
|
-
"/v1/chat": {
|
|
316537
|
+
"/v1/chat": {
|
|
316538
|
+
post: {
|
|
316539
|
+
summary: "Stateful chat session with full agent tool access (OpenAI-compatible response shape)",
|
|
316540
|
+
description: "Drop-in replacement for OpenAI /v1/chat/completions and Ollama /api/chat. By default the request runs the FULL OA agent stack (tools, multi-agent, memory, skills) under the hood and returns an OpenAI chat.completion shape on success. Set tools=false to bypass the agent and forward straight to the configured backend (fast path).",
|
|
316541
|
+
tags: ["Chat"],
|
|
316542
|
+
requestBody: { required: true, content: { "application/json": { schema: { type: "object", required: ["message"], properties: { message: { type: "string" }, model: { type: "string" }, session_id: { type: "string" }, stream: { type: "boolean", default: true }, tools: { type: "boolean", default: true, description: "true (default) = full agent. false = direct backend chat." } } } } } },
|
|
316543
|
+
responses: {
|
|
316544
|
+
200: {
|
|
316545
|
+
description: "OpenAI chat.completion shape \u2014 {id, object, created, model, choices: [{index, message, finish_reason}], usage}. finish_reason is 'stop' on success or 'error' if the agent produced no usable content (the error text is in choices[0].message.content)."
|
|
316546
|
+
},
|
|
316547
|
+
...ErrorResponses
|
|
316548
|
+
}
|
|
316549
|
+
}
|
|
316550
|
+
},
|
|
315761
316551
|
"/v1/chat/sessions": { get: { summary: "List active chat sessions", tags: ["Chat"], responses: { 200: { description: "Session list" } } } },
|
|
316552
|
+
// ───── AIWG cascade ─────
|
|
316553
|
+
"/v1/aiwg": { get: { summary: "AIWG installation root + control map", tags: ["AIWG"], responses: { 200: { description: "AIWG installation summary" } } } },
|
|
316554
|
+
"/v1/aiwg/frameworks": { get: { summary: "List AIWG frameworks (paginated)", tags: ["AIWG"], responses: { 200: { description: "Framework list" } } } },
|
|
316555
|
+
"/v1/aiwg/frameworks/{name}": { get: { summary: "Framework details + items", tags: ["AIWG"], responses: { 200: { description: "Framework details" }, 404: { description: "Not found" } } } },
|
|
316556
|
+
"/v1/aiwg/frameworks/{name}/content": { get: { summary: "Framework content (cascade-tier-aware)", tags: ["AIWG"], responses: { 200: { description: "Tier-appropriate content bundle" }, 413: { description: "Bundle too large for detected model tier" } } } },
|
|
316557
|
+
"/v1/aiwg/skills": { get: { summary: "List AIWG skills (paginated)", tags: ["AIWG"], responses: { 200: { description: "Skill list" } } } },
|
|
316558
|
+
"/v1/aiwg/skills/{name}": { get: { summary: "Skill content", tags: ["AIWG"], responses: { 200: { description: "Skill" }, 404: { description: "Not found" } } } },
|
|
316559
|
+
"/v1/aiwg/agents": { get: { summary: "List AIWG agents", tags: ["AIWG"], responses: { 200: { description: "Agent list" } } } },
|
|
316560
|
+
"/v1/aiwg/agents/{name}": { get: { summary: "Agent definition", tags: ["AIWG"], responses: { 200: { description: "Agent" }, 404: { description: "Not found" } } } },
|
|
316561
|
+
"/v1/aiwg/addons": { get: { summary: "List AIWG addons", tags: ["AIWG"], responses: { 200: { description: "Addon list" } } } },
|
|
316562
|
+
"/v1/aiwg/use": {
|
|
316563
|
+
post: {
|
|
316564
|
+
summary: "AIWG cascade activation bundle (aiwg use all equivalent, model-tier sized)",
|
|
316565
|
+
description: "Returns a tier-appropriate AIWG activation bundle: small models get just the index, medium get metadata, large get content, xlarge get full framework dumps. NEVER overflows context \u2014 the response auto-sizes to the detected model tier.",
|
|
316566
|
+
tags: ["AIWG"],
|
|
316567
|
+
requestBody: { required: true, content: { "application/json": { schema: { type: "object", properties: { scope: { type: "string", default: "all" }, model: { type: "string" }, tier: { type: "string", enum: ["small", "medium", "large", "xlarge"] } } } } } },
|
|
316568
|
+
responses: { 200: { description: "Tier-sized activation bundle" } }
|
|
316569
|
+
}
|
|
316570
|
+
},
|
|
316571
|
+
"/v1/aiwg/expand": {
|
|
316572
|
+
post: {
|
|
316573
|
+
summary: "Sub-agent unpack a specific AIWG skill or agent on demand",
|
|
316574
|
+
tags: ["AIWG"],
|
|
316575
|
+
requestBody: { required: true, content: { "application/json": { schema: { type: "object", properties: { trigger: { type: "string" }, name: { type: "string" }, limit: { type: "integer", default: 3 } } } } } },
|
|
316576
|
+
responses: { 200: { description: "Matching items" }, 400: { description: "Missing trigger or name" }, 404: { description: "No matches" } }
|
|
316577
|
+
}
|
|
316578
|
+
},
|
|
315762
316579
|
"/v1/run": { post: { summary: "Submit agentic task", tags: ["Agentic"], responses: { 202: { description: "Task accepted" }, ...ErrorResponses } } },
|
|
315763
316580
|
"/v1/runs": {
|
|
315764
316581
|
get: {
|
|
@@ -315971,31 +316788,31 @@ var init_auth_oidc = __esm({
|
|
|
315971
316788
|
|
|
315972
316789
|
// packages/cli/src/api/chat-session.ts
|
|
315973
316790
|
import { randomUUID as randomUUID10 } from "node:crypto";
|
|
315974
|
-
import { existsSync as
|
|
315975
|
-
import { join as
|
|
316791
|
+
import { existsSync as existsSync74, readFileSync as readFileSync58, readdirSync as readdirSync24 } from "node:fs";
|
|
316792
|
+
import { join as join91 } from "node:path";
|
|
315976
316793
|
function buildSystemPrompt(cwd4) {
|
|
315977
316794
|
const parts = [];
|
|
315978
316795
|
parts.push(
|
|
315979
316796
|
"You are Open Agent (OA), an AI coding assistant running locally via Ollama. You have access to the user's workspace and can discuss code, files, and projects. Be helpful, concise, and technically precise. When asked about files or code, describe what you know from the conversation context."
|
|
315980
316797
|
);
|
|
315981
316798
|
parts.push(`\\nEnvironment: ${process.platform}, Node ${process.version}, CWD: ${cwd4}`);
|
|
315982
|
-
const diaryPath =
|
|
315983
|
-
if (
|
|
316799
|
+
const diaryPath = join91(cwd4, ".oa", "context", "session-diary.md");
|
|
316800
|
+
if (existsSync74(diaryPath)) {
|
|
315984
316801
|
try {
|
|
315985
|
-
const diary =
|
|
316802
|
+
const diary = readFileSync58(diaryPath, "utf-8").slice(0, 1e3);
|
|
315986
316803
|
parts.push(`\\nPrevious session history:\\n${diary}`);
|
|
315987
316804
|
} catch {
|
|
315988
316805
|
}
|
|
315989
316806
|
}
|
|
315990
|
-
const memDir =
|
|
315991
|
-
if (
|
|
316807
|
+
const memDir = join91(cwd4, ".oa", "memory");
|
|
316808
|
+
if (existsSync74(memDir)) {
|
|
315992
316809
|
try {
|
|
315993
|
-
const files =
|
|
316810
|
+
const files = readdirSync24(memDir).filter((f2) => f2.endsWith(".json")).slice(0, 5);
|
|
315994
316811
|
if (files.length > 0) {
|
|
315995
316812
|
parts.push("\\nPersistent memory topics: " + files.map((f2) => f2.replace(".json", "")).join(", "));
|
|
315996
316813
|
for (const f2 of files.slice(0, 3)) {
|
|
315997
316814
|
try {
|
|
315998
|
-
const data = JSON.parse(
|
|
316815
|
+
const data = JSON.parse(readFileSync58(join91(memDir, f2), "utf-8"));
|
|
315999
316816
|
const entries = Object.entries(data).slice(0, 3);
|
|
316000
316817
|
if (entries.length > 0) {
|
|
316001
316818
|
parts.push(`\\nMemory [${f2.replace(".json", "")}]: ` + entries.map(([k, v]) => `${k}: ${String(v.value ?? v).slice(0, 100)}`).join("; "));
|
|
@@ -316008,10 +316825,10 @@ function buildSystemPrompt(cwd4) {
|
|
|
316008
316825
|
}
|
|
316009
316826
|
}
|
|
316010
316827
|
for (const name10 of ["AGENTS.md", "OA.md", ".open-agents.md"]) {
|
|
316011
|
-
const p2 =
|
|
316012
|
-
if (
|
|
316828
|
+
const p2 = join91(cwd4, name10);
|
|
316829
|
+
if (existsSync74(p2)) {
|
|
316013
316830
|
try {
|
|
316014
|
-
const content =
|
|
316831
|
+
const content = readFileSync58(p2, "utf-8").slice(0, 500);
|
|
316015
316832
|
parts.push(`\\nProject instructions (${name10}):\\n${content}`);
|
|
316016
316833
|
} catch {
|
|
316017
316834
|
}
|
|
@@ -316087,15 +316904,15 @@ var init_chat_session = __esm({
|
|
|
316087
316904
|
});
|
|
316088
316905
|
|
|
316089
316906
|
// packages/cli/src/api/usage-tracker.ts
|
|
316090
|
-
import { mkdirSync as mkdirSync43, readFileSync as
|
|
316091
|
-
import { join as
|
|
316907
|
+
import { mkdirSync as mkdirSync43, readFileSync as readFileSync59, writeFileSync as writeFileSync37, existsSync as existsSync75 } from "node:fs";
|
|
316908
|
+
import { join as join92 } from "node:path";
|
|
316092
316909
|
function initUsageTracker(oaDir) {
|
|
316093
|
-
const dir =
|
|
316910
|
+
const dir = join92(oaDir, "usage");
|
|
316094
316911
|
mkdirSync43(dir, { recursive: true });
|
|
316095
|
-
usageFile =
|
|
316912
|
+
usageFile = join92(dir, "token-usage.json");
|
|
316096
316913
|
try {
|
|
316097
|
-
if (
|
|
316098
|
-
store = JSON.parse(
|
|
316914
|
+
if (existsSync75(usageFile)) {
|
|
316915
|
+
store = JSON.parse(readFileSync59(usageFile, "utf-8"));
|
|
316099
316916
|
}
|
|
316100
316917
|
} catch {
|
|
316101
316918
|
store = { providers: {}, lastSaved: "" };
|
|
@@ -316159,24 +316976,24 @@ var init_usage_tracker = __esm({
|
|
|
316159
316976
|
});
|
|
316160
316977
|
|
|
316161
316978
|
// packages/cli/src/api/profiles.ts
|
|
316162
|
-
import { existsSync as
|
|
316163
|
-
import { join as
|
|
316164
|
-
import { homedir as
|
|
316979
|
+
import { existsSync as existsSync76, readFileSync as readFileSync60, writeFileSync as writeFileSync38, mkdirSync as mkdirSync44, readdirSync as readdirSync25, unlinkSync as unlinkSync18 } from "node:fs";
|
|
316980
|
+
import { join as join93 } from "node:path";
|
|
316981
|
+
import { homedir as homedir30 } from "node:os";
|
|
316165
316982
|
import { createCipheriv as createCipheriv3, createDecipheriv as createDecipheriv3, randomBytes as randomBytes18, scryptSync as scryptSync3 } from "node:crypto";
|
|
316166
316983
|
function globalProfileDir() {
|
|
316167
|
-
return
|
|
316984
|
+
return join93(homedir30(), ".open-agents", "profiles");
|
|
316168
316985
|
}
|
|
316169
316986
|
function projectProfileDir(projectDir) {
|
|
316170
|
-
return
|
|
316987
|
+
return join93(projectDir || process.cwd(), ".oa", "profiles");
|
|
316171
316988
|
}
|
|
316172
316989
|
function listProfiles(projectDir) {
|
|
316173
316990
|
const result = [];
|
|
316174
316991
|
const seen = /* @__PURE__ */ new Set();
|
|
316175
316992
|
const projDir = projectProfileDir(projectDir);
|
|
316176
|
-
if (
|
|
316177
|
-
for (const f2 of
|
|
316993
|
+
if (existsSync76(projDir)) {
|
|
316994
|
+
for (const f2 of readdirSync25(projDir).filter((f3) => f3.endsWith(".json"))) {
|
|
316178
316995
|
try {
|
|
316179
|
-
const raw = JSON.parse(
|
|
316996
|
+
const raw = JSON.parse(readFileSync60(join93(projDir, f2), "utf8"));
|
|
316180
316997
|
const name10 = f2.replace(".json", "");
|
|
316181
316998
|
seen.add(name10);
|
|
316182
316999
|
result.push({
|
|
@@ -316190,12 +317007,12 @@ function listProfiles(projectDir) {
|
|
|
316190
317007
|
}
|
|
316191
317008
|
}
|
|
316192
317009
|
const globDir = globalProfileDir();
|
|
316193
|
-
if (
|
|
316194
|
-
for (const f2 of
|
|
317010
|
+
if (existsSync76(globDir)) {
|
|
317011
|
+
for (const f2 of readdirSync25(globDir).filter((f3) => f3.endsWith(".json"))) {
|
|
316195
317012
|
const name10 = f2.replace(".json", "");
|
|
316196
317013
|
if (seen.has(name10)) continue;
|
|
316197
317014
|
try {
|
|
316198
|
-
const raw = JSON.parse(
|
|
317015
|
+
const raw = JSON.parse(readFileSync60(join93(globDir, f2), "utf8"));
|
|
316199
317016
|
result.push({
|
|
316200
317017
|
name: name10,
|
|
316201
317018
|
description: raw.description || "",
|
|
@@ -316210,11 +317027,11 @@ function listProfiles(projectDir) {
|
|
|
316210
317027
|
}
|
|
316211
317028
|
function loadProfile(name10, password, projectDir) {
|
|
316212
317029
|
const sanitized = name10.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
316213
|
-
const projPath =
|
|
316214
|
-
const globPath =
|
|
316215
|
-
const filePath =
|
|
317030
|
+
const projPath = join93(projectProfileDir(projectDir), `${sanitized}.json`);
|
|
317031
|
+
const globPath = join93(globalProfileDir(), `${sanitized}.json`);
|
|
317032
|
+
const filePath = existsSync76(projPath) ? projPath : existsSync76(globPath) ? globPath : null;
|
|
316216
317033
|
if (!filePath) return null;
|
|
316217
|
-
const raw = JSON.parse(
|
|
317034
|
+
const raw = JSON.parse(readFileSync60(filePath, "utf8"));
|
|
316218
317035
|
if (raw.encrypted === true) {
|
|
316219
317036
|
if (!password) return null;
|
|
316220
317037
|
return decryptProfile(raw, password);
|
|
@@ -316225,7 +317042,7 @@ function saveProfile(profile, password, scope = "global", projectDir) {
|
|
|
316225
317042
|
const dir = scope === "project" ? projectProfileDir(projectDir) : globalProfileDir();
|
|
316226
317043
|
mkdirSync44(dir, { recursive: true });
|
|
316227
317044
|
const sanitized = profile.name.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
316228
|
-
const filePath =
|
|
317045
|
+
const filePath = join93(dir, `${sanitized}.json`);
|
|
316229
317046
|
profile.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
316230
317047
|
if (password) {
|
|
316231
317048
|
const encrypted = encryptProfile(profile, password);
|
|
@@ -316238,8 +317055,8 @@ function saveProfile(profile, password, scope = "global", projectDir) {
|
|
|
316238
317055
|
function deleteProfile(name10, scope = "global", projectDir) {
|
|
316239
317056
|
const sanitized = name10.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
316240
317057
|
const dir = scope === "project" ? projectProfileDir(projectDir) : globalProfileDir();
|
|
316241
|
-
const filePath =
|
|
316242
|
-
if (
|
|
317058
|
+
const filePath = join93(dir, `${sanitized}.json`);
|
|
317059
|
+
if (existsSync76(filePath)) {
|
|
316243
317060
|
unlinkSync18(filePath);
|
|
316244
317061
|
return true;
|
|
316245
317062
|
}
|
|
@@ -316353,28 +317170,28 @@ var init_profiles = __esm({
|
|
|
316353
317170
|
});
|
|
316354
317171
|
|
|
316355
317172
|
// packages/cli/src/docker.ts
|
|
316356
|
-
import { execSync as
|
|
316357
|
-
import { existsSync as
|
|
316358
|
-
import { join as
|
|
316359
|
-
import { homedir as
|
|
317173
|
+
import { execSync as execSync54, spawn as spawn24 } from "node:child_process";
|
|
317174
|
+
import { existsSync as existsSync77, mkdirSync as mkdirSync45, writeFileSync as writeFileSync39 } from "node:fs";
|
|
317175
|
+
import { join as join94, resolve as resolve33, dirname as dirname25 } from "node:path";
|
|
317176
|
+
import { homedir as homedir31 } from "node:os";
|
|
316360
317177
|
import { fileURLToPath as fileURLToPath15 } from "node:url";
|
|
316361
317178
|
function getDockerDir() {
|
|
316362
317179
|
try {
|
|
316363
317180
|
if (typeof __dirname !== "undefined") {
|
|
316364
|
-
return
|
|
317181
|
+
return join94(__dirname, "..", "..", "..", "docker");
|
|
316365
317182
|
}
|
|
316366
317183
|
} catch {
|
|
316367
317184
|
}
|
|
316368
317185
|
try {
|
|
316369
317186
|
const thisDir = dirname25(fileURLToPath15(import.meta.url));
|
|
316370
|
-
return
|
|
317187
|
+
return join94(thisDir, "..", "..", "..", "docker");
|
|
316371
317188
|
} catch {
|
|
316372
317189
|
}
|
|
316373
|
-
return
|
|
317190
|
+
return join94(process.cwd(), "docker");
|
|
316374
317191
|
}
|
|
316375
317192
|
function isDockerAvailable() {
|
|
316376
317193
|
try {
|
|
316377
|
-
|
|
317194
|
+
execSync54("docker info", { stdio: "pipe", timeout: 1e4 });
|
|
316378
317195
|
return true;
|
|
316379
317196
|
} catch {
|
|
316380
317197
|
return false;
|
|
@@ -316382,7 +317199,7 @@ function isDockerAvailable() {
|
|
|
316382
317199
|
}
|
|
316383
317200
|
function isDockerInstalled() {
|
|
316384
317201
|
try {
|
|
316385
|
-
|
|
317202
|
+
execSync54("docker --version", { stdio: "pipe", timeout: 5e3 });
|
|
316386
317203
|
return true;
|
|
316387
317204
|
} catch {
|
|
316388
317205
|
return false;
|
|
@@ -316407,31 +317224,31 @@ async function ensureDocker() {
|
|
|
316407
317224
|
}
|
|
316408
317225
|
try {
|
|
316409
317226
|
console.log("[oa-docker] Docker not found. Installing via get.docker.com...");
|
|
316410
|
-
|
|
317227
|
+
execSync54("curl -fsSL https://get.docker.com | sh", {
|
|
316411
317228
|
stdio: "inherit",
|
|
316412
317229
|
timeout: 3e5
|
|
316413
317230
|
});
|
|
316414
317231
|
const user = process.env["USER"] || process.env["LOGNAME"];
|
|
316415
317232
|
if (user) {
|
|
316416
317233
|
try {
|
|
316417
|
-
|
|
317234
|
+
execSync54(`sudo usermod -aG docker ${user}`, { stdio: "pipe" });
|
|
316418
317235
|
} catch {
|
|
316419
317236
|
}
|
|
316420
317237
|
}
|
|
316421
317238
|
try {
|
|
316422
|
-
|
|
317239
|
+
execSync54("sudo systemctl start docker", { stdio: "pipe", timeout: 15e3 });
|
|
316423
317240
|
} catch {
|
|
316424
317241
|
}
|
|
316425
317242
|
try {
|
|
316426
|
-
|
|
316427
|
-
const runtimes =
|
|
317243
|
+
execSync54("nvidia-smi", { stdio: "pipe", timeout: 5e3 });
|
|
317244
|
+
const runtimes = execSync54("docker info --format '{{json .Runtimes}}'", {
|
|
316428
317245
|
stdio: "pipe",
|
|
316429
317246
|
timeout: 5e3
|
|
316430
317247
|
}).toString();
|
|
316431
317248
|
if (!runtimes.includes("nvidia")) {
|
|
316432
317249
|
console.log("[oa-docker] NVIDIA GPU detected. Installing nvidia-container-toolkit...");
|
|
316433
317250
|
try {
|
|
316434
|
-
|
|
317251
|
+
execSync54(`
|
|
316435
317252
|
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg 2>/dev/null
|
|
316436
317253
|
curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list > /dev/null 2>&1
|
|
316437
317254
|
sudo apt-get update -qq 2>/dev/null && sudo apt-get install -y -qq nvidia-container-toolkit 2>/dev/null || ( sudo dnf install -y nvidia-container-toolkit 2>/dev/null || sudo yum install -y nvidia-container-toolkit 2>/dev/null || true )
|
|
@@ -316461,7 +317278,7 @@ async function ensureDocker() {
|
|
|
316461
317278
|
}
|
|
316462
317279
|
async function ensureNvidiaToolkit() {
|
|
316463
317280
|
try {
|
|
316464
|
-
|
|
317281
|
+
execSync54("nvidia-smi --query-gpu=name --format=csv,noheader", { stdio: "pipe", timeout: 5e3 });
|
|
316465
317282
|
} catch {
|
|
316466
317283
|
return { ok: false, message: "No NVIDIA GPU detected (nvidia-smi not found)" };
|
|
316467
317284
|
}
|
|
@@ -316472,7 +317289,7 @@ async function ensureNvidiaToolkit() {
|
|
|
316472
317289
|
return { ok: false, message: "Auto-install only supported on Linux. Install manually: https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/install-guide.html" };
|
|
316473
317290
|
}
|
|
316474
317291
|
try {
|
|
316475
|
-
|
|
317292
|
+
execSync54(`
|
|
316476
317293
|
curl -fsSL https://nvidia.github.io/libnvidia-container/gpgkey | sudo gpg --dearmor -o /usr/share/keyrings/nvidia-container-toolkit-keyring.gpg 2>/dev/null
|
|
316477
317294
|
curl -s -L https://nvidia.github.io/libnvidia-container/stable/deb/nvidia-container-toolkit.list | sed 's#deb https://#deb [signed-by=/usr/share/keyrings/nvidia-container-toolkit-keyring.gpg] https://#g' | sudo tee /etc/apt/sources.list.d/nvidia-container-toolkit.list > /dev/null 2>&1
|
|
316478
317295
|
sudo apt-get update -qq 2>/dev/null && sudo apt-get install -y -qq nvidia-container-toolkit 2>/dev/null || ( sudo dnf install -y nvidia-container-toolkit 2>/dev/null || sudo yum install -y nvidia-container-toolkit 2>/dev/null || true )
|
|
@@ -316486,7 +317303,7 @@ async function ensureNvidiaToolkit() {
|
|
|
316486
317303
|
}
|
|
316487
317304
|
function isOaImageBuilt() {
|
|
316488
317305
|
try {
|
|
316489
|
-
const out =
|
|
317306
|
+
const out = execSync54(`docker images -q ${OA_IMAGE}:${OA_IMAGE_TAG}`, {
|
|
316490
317307
|
stdio: "pipe",
|
|
316491
317308
|
timeout: 5e3
|
|
316492
317309
|
}).toString().trim();
|
|
@@ -316501,16 +317318,16 @@ async function ensureOaImage(force = false) {
|
|
|
316501
317318
|
}
|
|
316502
317319
|
let buildContext;
|
|
316503
317320
|
const dockerDir = getDockerDir();
|
|
316504
|
-
if (
|
|
317321
|
+
if (existsSync77(join94(dockerDir, "Dockerfile"))) {
|
|
316505
317322
|
buildContext = dockerDir;
|
|
316506
317323
|
} else {
|
|
316507
|
-
buildContext =
|
|
317324
|
+
buildContext = join94(homedir31(), ".oa", "docker-build");
|
|
316508
317325
|
mkdirSync45(buildContext, { recursive: true });
|
|
316509
317326
|
writeDockerfiles(buildContext);
|
|
316510
317327
|
}
|
|
316511
317328
|
try {
|
|
316512
317329
|
console.log(`[oa-docker] Building image ${OA_IMAGE}:${OA_IMAGE_TAG}...`);
|
|
316513
|
-
|
|
317330
|
+
execSync54(`docker build -t ${OA_IMAGE}:${OA_IMAGE_TAG} ${buildContext}`, {
|
|
316514
317331
|
stdio: "inherit",
|
|
316515
317332
|
timeout: 6e5
|
|
316516
317333
|
// 10 min
|
|
@@ -316579,16 +317396,16 @@ chown -R node:node /workspace /home/node/.oa /home/node/.open-agents 2>/dev/null
|
|
|
316579
317396
|
if [ "$1" = "oa" ]; then shift; exec su - node -c "cd /workspace && oa $*"; fi
|
|
316580
317397
|
exec "$@"
|
|
316581
317398
|
`;
|
|
316582
|
-
writeFileSync39(
|
|
316583
|
-
writeFileSync39(
|
|
317399
|
+
writeFileSync39(join94(dir, "Dockerfile"), dockerfile);
|
|
317400
|
+
writeFileSync39(join94(dir, "docker-entrypoint.sh"), entrypoint, { mode: 493 });
|
|
316584
317401
|
}
|
|
316585
317402
|
function hasNvidiaGpu() {
|
|
316586
317403
|
try {
|
|
316587
|
-
|
|
317404
|
+
execSync54("nvidia-smi --query-gpu=name --format=csv,noheader", {
|
|
316588
317405
|
stdio: "pipe",
|
|
316589
317406
|
timeout: 5e3
|
|
316590
317407
|
});
|
|
316591
|
-
const runtimes =
|
|
317408
|
+
const runtimes = execSync54("docker info --format '{{json .Runtimes}}'", {
|
|
316592
317409
|
stdio: "pipe",
|
|
316593
317410
|
timeout: 5e3
|
|
316594
317411
|
}).toString();
|
|
@@ -316657,22 +317474,22 @@ import * as http5 from "node:http";
|
|
|
316657
317474
|
import * as https3 from "node:https";
|
|
316658
317475
|
import { createRequire as createRequire4 } from "node:module";
|
|
316659
317476
|
import { fileURLToPath as fileURLToPath16 } from "node:url";
|
|
316660
|
-
import { dirname as dirname26, join as
|
|
316661
|
-
import { spawn as spawn25, execSync as
|
|
316662
|
-
import { mkdirSync as mkdirSync46,
|
|
317477
|
+
import { dirname as dirname26, join as join95, resolve as resolve34 } from "node:path";
|
|
317478
|
+
import { spawn as spawn25, execSync as execSync55 } from "node:child_process";
|
|
317479
|
+
import { mkdirSync as mkdirSync46, readFileSync as readFileSync61, readdirSync as readdirSync26, existsSync as existsSync78 } from "node:fs";
|
|
316663
317480
|
import { randomBytes as randomBytes19, randomUUID as randomUUID11 } from "node:crypto";
|
|
316664
317481
|
function getVersion3() {
|
|
316665
317482
|
try {
|
|
316666
317483
|
const require3 = createRequire4(import.meta.url);
|
|
316667
317484
|
const thisDir = dirname26(fileURLToPath16(import.meta.url));
|
|
316668
317485
|
const candidates = [
|
|
316669
|
-
|
|
316670
|
-
|
|
316671
|
-
|
|
317486
|
+
join95(thisDir, "..", "package.json"),
|
|
317487
|
+
join95(thisDir, "..", "..", "package.json"),
|
|
317488
|
+
join95(thisDir, "..", "..", "..", "package.json")
|
|
316672
317489
|
];
|
|
316673
317490
|
for (const pkgPath of candidates) {
|
|
316674
317491
|
try {
|
|
316675
|
-
if (!
|
|
317492
|
+
if (!existsSync78(pkgPath)) continue;
|
|
316676
317493
|
const pkg = require3(pkgPath);
|
|
316677
317494
|
if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli" || pkg.name === "@open-agents/monorepo") {
|
|
316678
317495
|
return pkg.version ?? "0.0.0";
|
|
@@ -316892,6 +317709,166 @@ async function parseJsonBody(req2) {
|
|
|
316892
317709
|
return null;
|
|
316893
317710
|
}
|
|
316894
317711
|
}
|
|
317712
|
+
function sanitizeChatContent(raw) {
|
|
317713
|
+
if (typeof raw !== "string") return "";
|
|
317714
|
+
const lines = raw.split("\n");
|
|
317715
|
+
const cleaned = [];
|
|
317716
|
+
for (const rawLine of lines) {
|
|
317717
|
+
const line = rawLine.replace(/\x1B\[[0-9;]*[A-Za-z]/g, "").replace(/\x1B\].*?\x07/g, "").trim();
|
|
317718
|
+
if (!line) continue;
|
|
317719
|
+
if (/^i\s+(Knowledge graph|Episodes captured|Context assembled|Tool deferral|Task consolidation|Re-engaging|Stopping re-engagement|Memory written|Backend)/.test(line)) continue;
|
|
317720
|
+
if (/^E\s+(Backend (error|unavailable)|Stopping)/.test(line)) continue;
|
|
317721
|
+
if (/^⚠\s*(Task incomplete|Task complete)/.test(line)) continue;
|
|
317722
|
+
if (/^▹\s/.test(line)) continue;
|
|
317723
|
+
if (/^open-agents \(/.test(line)) continue;
|
|
317724
|
+
cleaned.push(line);
|
|
317725
|
+
}
|
|
317726
|
+
return cleaned.join("\n").trim();
|
|
317727
|
+
}
|
|
317728
|
+
async function directChatBackend(opts) {
|
|
317729
|
+
const { model, messages: messages2, stream, res, sessionId, ollamaUrl } = opts;
|
|
317730
|
+
const cfg = loadConfig();
|
|
317731
|
+
const isVllm = cfg.backendType === "vllm";
|
|
317732
|
+
const cleanModel = model.replace(/^[a-z]+\//, "");
|
|
317733
|
+
const headers = { "Content-Type": "application/json" };
|
|
317734
|
+
if (cfg.apiKey) headers["Authorization"] = `Bearer ${cfg.apiKey}`;
|
|
317735
|
+
if (isVllm) {
|
|
317736
|
+
const reqBody = JSON.stringify({ model: cleanModel, messages: messages2, stream });
|
|
317737
|
+
if (stream) {
|
|
317738
|
+
res.writeHead(200, {
|
|
317739
|
+
"Content-Type": "text/event-stream",
|
|
317740
|
+
"Cache-Control": "no-cache",
|
|
317741
|
+
"Connection": "keep-alive",
|
|
317742
|
+
"X-Session-ID": sessionId,
|
|
317743
|
+
"X-API-Version": API_VERSION
|
|
317744
|
+
});
|
|
317745
|
+
let acc = "";
|
|
317746
|
+
const url = new URL("/v1/chat/completions", ollamaUrl);
|
|
317747
|
+
const transport = url.protocol === "https:" ? https3 : http5;
|
|
317748
|
+
await new Promise((resolve39, reject) => {
|
|
317749
|
+
const proxyReq = transport.request({
|
|
317750
|
+
hostname: url.hostname,
|
|
317751
|
+
port: url.port || (url.protocol === "https:" ? 443 : 80),
|
|
317752
|
+
path: url.pathname,
|
|
317753
|
+
method: "POST",
|
|
317754
|
+
headers: { ...headers, "Content-Length": Buffer.byteLength(reqBody) }
|
|
317755
|
+
}, (proxyRes) => {
|
|
317756
|
+
proxyRes.on("data", (chunk) => {
|
|
317757
|
+
const text = chunk.toString();
|
|
317758
|
+
res.write(text);
|
|
317759
|
+
for (const ln of text.split("\n")) {
|
|
317760
|
+
if (!ln.startsWith("data: ")) continue;
|
|
317761
|
+
const payload = ln.slice(6).trim();
|
|
317762
|
+
if (!payload || payload === "[DONE]") continue;
|
|
317763
|
+
try {
|
|
317764
|
+
const j = JSON.parse(payload);
|
|
317765
|
+
const delta = j?.choices?.[0]?.delta?.content;
|
|
317766
|
+
if (delta) acc += delta;
|
|
317767
|
+
} catch {
|
|
317768
|
+
}
|
|
317769
|
+
}
|
|
317770
|
+
});
|
|
317771
|
+
proxyRes.on("end", () => {
|
|
317772
|
+
res.end();
|
|
317773
|
+
resolve39();
|
|
317774
|
+
});
|
|
317775
|
+
proxyRes.on("error", reject);
|
|
317776
|
+
});
|
|
317777
|
+
proxyReq.on("error", reject);
|
|
317778
|
+
proxyReq.setTimeout(12e4, () => proxyReq.destroy(new Error("Backend timeout (120s)")));
|
|
317779
|
+
proxyReq.write(reqBody);
|
|
317780
|
+
proxyReq.end();
|
|
317781
|
+
});
|
|
317782
|
+
return acc.trim();
|
|
317783
|
+
} else {
|
|
317784
|
+
const result = await ollamaRequest(ollamaUrl, "/v1/chat/completions", "POST", reqBody);
|
|
317785
|
+
if (result.status >= 400) throw new Error(`Backend HTTP ${result.status}: ${result.body.slice(0, 200)}`);
|
|
317786
|
+
const j = JSON.parse(result.body);
|
|
317787
|
+
const content = j?.choices?.[0]?.message?.content || "";
|
|
317788
|
+
jsonResponse(res, 200, {
|
|
317789
|
+
session_id: sessionId,
|
|
317790
|
+
model: cleanModel,
|
|
317791
|
+
message: { role: "assistant", content }
|
|
317792
|
+
});
|
|
317793
|
+
return content;
|
|
317794
|
+
}
|
|
317795
|
+
} else {
|
|
317796
|
+
const reqBody = JSON.stringify({
|
|
317797
|
+
model: cleanModel,
|
|
317798
|
+
messages: messages2,
|
|
317799
|
+
stream,
|
|
317800
|
+
think: false,
|
|
317801
|
+
options: {}
|
|
317802
|
+
});
|
|
317803
|
+
if (stream) {
|
|
317804
|
+
res.writeHead(200, {
|
|
317805
|
+
"Content-Type": "text/event-stream",
|
|
317806
|
+
"Cache-Control": "no-cache",
|
|
317807
|
+
"Connection": "keep-alive",
|
|
317808
|
+
"X-Session-ID": sessionId,
|
|
317809
|
+
"X-API-Version": API_VERSION
|
|
317810
|
+
});
|
|
317811
|
+
let acc = "";
|
|
317812
|
+
await new Promise((resolve39, reject) => {
|
|
317813
|
+
ollamaStream(
|
|
317814
|
+
ollamaUrl,
|
|
317815
|
+
"/api/chat",
|
|
317816
|
+
"POST",
|
|
317817
|
+
reqBody,
|
|
317818
|
+
(chunk) => {
|
|
317819
|
+
for (const ln of chunk.split("\n")) {
|
|
317820
|
+
if (!ln.trim()) continue;
|
|
317821
|
+
try {
|
|
317822
|
+
const j = JSON.parse(ln);
|
|
317823
|
+
const delta = j?.message?.content || "";
|
|
317824
|
+
if (delta) {
|
|
317825
|
+
acc += delta;
|
|
317826
|
+
res.write("data: " + JSON.stringify({
|
|
317827
|
+
id: `chatcmpl-${sessionId.slice(0, 8)}`,
|
|
317828
|
+
object: "chat.completion.chunk",
|
|
317829
|
+
choices: [{ index: 0, delta: { content: delta }, finish_reason: null }]
|
|
317830
|
+
}) + "\n\n");
|
|
317831
|
+
}
|
|
317832
|
+
if (j.done) {
|
|
317833
|
+
res.write("data: " + JSON.stringify({
|
|
317834
|
+
id: `chatcmpl-${sessionId.slice(0, 8)}`,
|
|
317835
|
+
object: "chat.completion.chunk",
|
|
317836
|
+
choices: [{ index: 0, delta: {}, finish_reason: "stop" }]
|
|
317837
|
+
}) + "\n\n");
|
|
317838
|
+
res.write("data: [DONE]\n\n");
|
|
317839
|
+
}
|
|
317840
|
+
} catch {
|
|
317841
|
+
}
|
|
317842
|
+
}
|
|
317843
|
+
},
|
|
317844
|
+
() => {
|
|
317845
|
+
res.end();
|
|
317846
|
+
resolve39();
|
|
317847
|
+
},
|
|
317848
|
+
(err) => reject(err)
|
|
317849
|
+
);
|
|
317850
|
+
});
|
|
317851
|
+
return acc.trim();
|
|
317852
|
+
} else {
|
|
317853
|
+
const result = await ollamaRequest(ollamaUrl, "/api/chat", "POST", reqBody);
|
|
317854
|
+
if (result.status >= 400) throw new Error(`Backend HTTP ${result.status}: ${result.body.slice(0, 200)}`);
|
|
317855
|
+
const j = JSON.parse(result.body);
|
|
317856
|
+
const content = j?.message?.content || "";
|
|
317857
|
+
if (!content) throw new Error("Backend returned empty message content");
|
|
317858
|
+
jsonResponse(res, 200, {
|
|
317859
|
+
session_id: sessionId,
|
|
317860
|
+
model: cleanModel,
|
|
317861
|
+
message: { role: "assistant", content },
|
|
317862
|
+
usage: {
|
|
317863
|
+
prompt_tokens: j?.prompt_eval_count,
|
|
317864
|
+
completion_tokens: j?.eval_count,
|
|
317865
|
+
total_duration_ns: j?.total_duration
|
|
317866
|
+
}
|
|
317867
|
+
});
|
|
317868
|
+
return content;
|
|
317869
|
+
}
|
|
317870
|
+
}
|
|
317871
|
+
}
|
|
316895
317872
|
function backendAuthHeaders(endpoint) {
|
|
316896
317873
|
const key = endpoint?.authKey ?? loadConfig().apiKey;
|
|
316897
317874
|
if (key) return { Authorization: `Bearer ${key}` };
|
|
@@ -316961,27 +317938,27 @@ function ollamaStream(ollamaUrl, path5, method, body, onData, onEnd, onError) {
|
|
|
316961
317938
|
}
|
|
316962
317939
|
function jobsDir() {
|
|
316963
317940
|
const root = resolve34(process.cwd());
|
|
316964
|
-
const dir =
|
|
317941
|
+
const dir = join95(root, ".oa", "jobs");
|
|
316965
317942
|
mkdirSync46(dir, { recursive: true });
|
|
316966
317943
|
return dir;
|
|
316967
317944
|
}
|
|
316968
317945
|
function loadJob(id) {
|
|
316969
|
-
const file =
|
|
316970
|
-
if (!
|
|
317946
|
+
const file = join95(jobsDir(), `${id}.json`);
|
|
317947
|
+
if (!existsSync78(file)) return null;
|
|
316971
317948
|
try {
|
|
316972
|
-
return JSON.parse(
|
|
317949
|
+
return JSON.parse(readFileSync61(file, "utf-8"));
|
|
316973
317950
|
} catch {
|
|
316974
317951
|
return null;
|
|
316975
317952
|
}
|
|
316976
317953
|
}
|
|
316977
317954
|
function listJobs() {
|
|
316978
317955
|
const dir = jobsDir();
|
|
316979
|
-
if (!
|
|
316980
|
-
const files =
|
|
317956
|
+
if (!existsSync78(dir)) return [];
|
|
317957
|
+
const files = readdirSync26(dir).filter((f2) => f2.endsWith(".json")).sort();
|
|
316981
317958
|
const jobs = [];
|
|
316982
317959
|
for (const file of files) {
|
|
316983
317960
|
try {
|
|
316984
|
-
jobs.push(JSON.parse(
|
|
317961
|
+
jobs.push(JSON.parse(readFileSync61(join95(dir, file), "utf-8")));
|
|
316985
317962
|
} catch {
|
|
316986
317963
|
}
|
|
316987
317964
|
}
|
|
@@ -317012,12 +317989,47 @@ function checkKeyRateLimit(auth) {
|
|
|
317012
317989
|
}
|
|
317013
317990
|
return null;
|
|
317014
317991
|
}
|
|
317992
|
+
function checkConcurrentJobLimit(auth) {
|
|
317993
|
+
if (!auth.user || !auth.maxJobs) return null;
|
|
317994
|
+
const usage = getKeyUsage(auth.user);
|
|
317995
|
+
if (usage.activeJobs >= auth.maxJobs) {
|
|
317996
|
+
return `Concurrent job limit exceeded for ${auth.user}: ${usage.activeJobs}/${auth.maxJobs}`;
|
|
317997
|
+
}
|
|
317998
|
+
return null;
|
|
317999
|
+
}
|
|
318000
|
+
function incrementActiveJobs(user) {
|
|
318001
|
+
if (!user) return;
|
|
318002
|
+
getKeyUsage(user).activeJobs++;
|
|
318003
|
+
}
|
|
318004
|
+
function decrementActiveJobs(user) {
|
|
318005
|
+
if (!user) return;
|
|
318006
|
+
const usage = getKeyUsage(user);
|
|
318007
|
+
if (usage.activeJobs > 0) usage.activeJobs--;
|
|
318008
|
+
}
|
|
317015
318009
|
function recordKeyUsage(user, tokens) {
|
|
317016
318010
|
if (!user) return;
|
|
317017
318011
|
const usage = getKeyUsage(user);
|
|
317018
318012
|
usage.requestTimestamps.push(Date.now());
|
|
317019
318013
|
usage.tokensToday += tokens;
|
|
317020
318014
|
}
|
|
318015
|
+
function atomicJobWrite(dir, id, job) {
|
|
318016
|
+
const fs4 = __require("node:fs");
|
|
318017
|
+
const finalPath = join95(dir, `${id}.json`);
|
|
318018
|
+
const tmpPath = `${finalPath}.tmp.${process.pid}.${Date.now()}`;
|
|
318019
|
+
try {
|
|
318020
|
+
fs4.writeFileSync(tmpPath, JSON.stringify(job, null, 2), "utf-8");
|
|
318021
|
+
fs4.renameSync(tmpPath, finalPath);
|
|
318022
|
+
} catch {
|
|
318023
|
+
try {
|
|
318024
|
+
fs4.writeFileSync(finalPath, JSON.stringify(job, null, 2), "utf-8");
|
|
318025
|
+
} catch {
|
|
318026
|
+
}
|
|
318027
|
+
try {
|
|
318028
|
+
fs4.unlinkSync(tmpPath);
|
|
318029
|
+
} catch {
|
|
318030
|
+
}
|
|
318031
|
+
}
|
|
318032
|
+
}
|
|
317021
318033
|
function resolveAuth(req2) {
|
|
317022
318034
|
const authHeader = req2.headers["authorization"];
|
|
317023
318035
|
const token = authHeader?.startsWith("Bearer ") ? authHeader.slice(7) : null;
|
|
@@ -317447,7 +318459,23 @@ async function handleV1Run(req2, res) {
|
|
|
317447
318459
|
return;
|
|
317448
318460
|
}
|
|
317449
318461
|
}
|
|
317450
|
-
|
|
318462
|
+
{
|
|
318463
|
+
const auth = resolveAuth(req2);
|
|
318464
|
+
const overLimit = checkConcurrentJobLimit(auth);
|
|
318465
|
+
if (overLimit) {
|
|
318466
|
+
res.setHeader("Content-Type", "application/problem+json; charset=utf-8");
|
|
318467
|
+
res.writeHead(429);
|
|
318468
|
+
res.end(JSON.stringify({
|
|
318469
|
+
type: "https://openagents.nexus/problems/rate-limited",
|
|
318470
|
+
title: "Concurrent job limit exceeded",
|
|
318471
|
+
status: 429,
|
|
318472
|
+
detail: overLimit,
|
|
318473
|
+
instance: req2.headers["x-request-id"] ?? void 0
|
|
318474
|
+
}));
|
|
318475
|
+
return;
|
|
318476
|
+
}
|
|
318477
|
+
}
|
|
318478
|
+
const id = `job-${randomBytes19(8).toString("hex")}`;
|
|
317451
318479
|
const dir = jobsDir();
|
|
317452
318480
|
const workingDir = requestBody["working_directory"] || req2.headers["x-working-directory"];
|
|
317453
318481
|
const isolate = requestBody["isolate"] === true;
|
|
@@ -317455,7 +318483,7 @@ async function handleV1Run(req2, res) {
|
|
|
317455
318483
|
if (workingDir) {
|
|
317456
318484
|
cwd4 = resolve34(workingDir);
|
|
317457
318485
|
} else if (isolate) {
|
|
317458
|
-
const wsDir =
|
|
318486
|
+
const wsDir = join95(dir, "..", "workspaces", id);
|
|
317459
318487
|
mkdirSync46(wsDir, { recursive: true });
|
|
317460
318488
|
cwd4 = wsDir;
|
|
317461
318489
|
} else {
|
|
@@ -317492,15 +318520,16 @@ async function handleV1Run(req2, res) {
|
|
|
317492
318520
|
}
|
|
317493
318521
|
job.profile = profileName || null;
|
|
317494
318522
|
const runCfg = loadConfig();
|
|
317495
|
-
const runEnv = {
|
|
317496
|
-
|
|
317497
|
-
|
|
317498
|
-
|
|
317499
|
-
|
|
317500
|
-
|
|
317501
|
-
|
|
317502
|
-
|
|
317503
|
-
|
|
318523
|
+
const runEnv = {};
|
|
318524
|
+
for (const [k, v] of Object.entries(process.env)) {
|
|
318525
|
+
if (k === "OA_DAEMON" || k === "OA_PORT") continue;
|
|
318526
|
+
if (typeof v === "string") runEnv[k] = v;
|
|
318527
|
+
}
|
|
318528
|
+
runEnv["OA_JOB_ID"] = id;
|
|
318529
|
+
runEnv["__OPEN_AGENTS_NO_AUTO_RUN"] = "";
|
|
318530
|
+
runEnv["OA_RUN_USER"] = authUser;
|
|
318531
|
+
runEnv["OA_RUN_SCOPE"] = authScope;
|
|
318532
|
+
runEnv["OLLAMA_HOST"] = runCfg.backendUrl || process.env["OLLAMA_HOST"] || "http://127.0.0.1:11434";
|
|
317504
318533
|
if (runCfg.apiKey) runEnv["OA_API_KEY_INHERIT"] = runCfg.apiKey;
|
|
317505
318534
|
if (activeProfile) {
|
|
317506
318535
|
runEnv["OA_TOOL_PROFILE"] = JSON.stringify(activeProfile);
|
|
@@ -317540,8 +318569,17 @@ async function handleV1Run(req2, res) {
|
|
|
317540
318569
|
job.sandbox = sandbox;
|
|
317541
318570
|
}
|
|
317542
318571
|
job.pid = child.pid ?? 0;
|
|
317543
|
-
|
|
318572
|
+
atomicJobWrite(dir, id, job);
|
|
317544
318573
|
runningProcesses.set(id, child);
|
|
318574
|
+
incrementActiveJobs(authUser);
|
|
318575
|
+
try {
|
|
318576
|
+
const pubEv = publishEvent;
|
|
318577
|
+
pubEv("run.started", { run_id: id, model: modelArg, pid: job.pid }, {
|
|
318578
|
+
subject: authUser,
|
|
318579
|
+
aimsControl: "A.6.2.6"
|
|
318580
|
+
});
|
|
318581
|
+
} catch {
|
|
318582
|
+
}
|
|
317545
318583
|
if (streamMode) {
|
|
317546
318584
|
res.writeHead(200, {
|
|
317547
318585
|
"Content-Type": "text/event-stream",
|
|
@@ -317566,11 +318604,18 @@ async function handleV1Run(req2, res) {
|
|
|
317566
318604
|
child.on("exit", (code8) => {
|
|
317567
318605
|
job.status = code8 === 0 ? "completed" : "failed";
|
|
317568
318606
|
job.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
318607
|
+
atomicJobWrite(dir, id, job);
|
|
318608
|
+
runningProcesses.delete(id);
|
|
318609
|
+
decrementActiveJobs(authUser);
|
|
317569
318610
|
try {
|
|
317570
|
-
|
|
318611
|
+
const pubEv = publishEvent;
|
|
318612
|
+
pubEv(
|
|
318613
|
+
job.status === "completed" ? "run.completed" : "run.failed",
|
|
318614
|
+
{ run_id: id, exit_code: code8 },
|
|
318615
|
+
{ subject: authUser, aimsControl: "A.6.2.6" }
|
|
318616
|
+
);
|
|
317571
318617
|
} catch {
|
|
317572
318618
|
}
|
|
317573
|
-
runningProcesses.delete(id);
|
|
317574
318619
|
res.write(`data: ${JSON.stringify({ type: "run_completed", run_id: id, exit_code: code8 })}
|
|
317575
318620
|
|
|
317576
318621
|
`);
|
|
@@ -317606,11 +318651,18 @@ async function handleV1Run(req2, res) {
|
|
|
317606
318651
|
job.status = code8 === 0 ? "completed" : "failed";
|
|
317607
318652
|
job.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
317608
318653
|
}
|
|
318654
|
+
atomicJobWrite(dir, id, job);
|
|
318655
|
+
runningProcesses.delete(id);
|
|
318656
|
+
decrementActiveJobs(authUser);
|
|
317609
318657
|
try {
|
|
317610
|
-
|
|
318658
|
+
const pubEv = publishEvent;
|
|
318659
|
+
pubEv(
|
|
318660
|
+
job.status === "completed" ? "run.completed" : "run.failed",
|
|
318661
|
+
{ run_id: id, exit_code: code8, summary: job.summary },
|
|
318662
|
+
{ subject: authUser, aimsControl: "A.6.2.6" }
|
|
318663
|
+
);
|
|
317611
318664
|
} catch {
|
|
317612
318665
|
}
|
|
317613
|
-
runningProcesses.delete(id);
|
|
317614
318666
|
});
|
|
317615
318667
|
jsonResponse(res, 202, { run_id: id, status: "running", pid: job.pid });
|
|
317616
318668
|
}
|
|
@@ -317666,7 +318718,7 @@ function handleV1RunsDelete(res, id) {
|
|
|
317666
318718
|
const containerName = `oa-${id}`;
|
|
317667
318719
|
if (job.sandbox === "container") {
|
|
317668
318720
|
try {
|
|
317669
|
-
|
|
318721
|
+
execSync55(`docker stop ${containerName}`, { timeout: 5e3, stdio: "ignore" });
|
|
317670
318722
|
} catch {
|
|
317671
318723
|
}
|
|
317672
318724
|
}
|
|
@@ -317674,11 +318726,14 @@ function handleV1RunsDelete(res, id) {
|
|
|
317674
318726
|
job.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
317675
318727
|
job.error = "Aborted via API";
|
|
317676
318728
|
const dir = jobsDir();
|
|
318729
|
+
atomicJobWrite(dir, id, job);
|
|
318730
|
+
runningProcesses.delete(id);
|
|
318731
|
+
decrementActiveJobs(job.user);
|
|
317677
318732
|
try {
|
|
317678
|
-
|
|
318733
|
+
const pubEv = publishEvent;
|
|
318734
|
+
pubEv("run.aborted", { run_id: id }, { subject: job.user, aimsControl: "A.6.2.6" });
|
|
317679
318735
|
} catch {
|
|
317680
318736
|
}
|
|
317681
|
-
runningProcesses.delete(id);
|
|
317682
318737
|
}
|
|
317683
318738
|
jsonResponse(res, 200, { run_id: id, status: "aborted" });
|
|
317684
318739
|
}
|
|
@@ -317730,15 +318785,11 @@ async function handlePatchConfig(req2, res) {
|
|
|
317730
318785
|
settingsUpdate.updateMode = updates["updateMode"];
|
|
317731
318786
|
}
|
|
317732
318787
|
saveGlobalSettings(settingsUpdate);
|
|
317733
|
-
|
|
317734
|
-
|
|
317735
|
-
|
|
317736
|
-
|
|
317737
|
-
|
|
317738
|
-
// ISO 42001 — configuration change record
|
|
317739
|
-
});
|
|
317740
|
-
} catch {
|
|
317741
|
-
}
|
|
318788
|
+
publishEvent("config.changed", { keys: Object.keys(settingsUpdate) }, {
|
|
318789
|
+
subject: req2._authUser ?? "anonymous",
|
|
318790
|
+
aimsControl: "A.6.2.8"
|
|
318791
|
+
// ISO 42001 — configuration change record
|
|
318792
|
+
});
|
|
317742
318793
|
const updatedConfig = loadConfig();
|
|
317743
318794
|
jsonResponse(res, 200, {
|
|
317744
318795
|
config: redactSecrets(updatedConfig),
|
|
@@ -317919,7 +318970,7 @@ async function handleRequest(req2, res, ollamaUrl, verbose) {
|
|
|
317919
318970
|
if (pathname === "/v1/files" && method === "GET") {
|
|
317920
318971
|
const dir = urlObj.searchParams.get("path") || process.cwd();
|
|
317921
318972
|
try {
|
|
317922
|
-
const entries =
|
|
318973
|
+
const entries = readdirSync26(resolve34(dir), { withFileTypes: true }).filter((e2) => !e2.name.startsWith(".") && e2.name !== "node_modules").slice(0, 100).map((e2) => ({ name: e2.name, type: e2.isDirectory() ? "dir" : "file" }));
|
|
317923
318974
|
jsonResponse(res, 200, { path: resolve34(dir), entries });
|
|
317924
318975
|
} catch (e2) {
|
|
317925
318976
|
jsonResponse(res, 400, { error: e2.message });
|
|
@@ -317996,6 +319047,42 @@ async function handleRequest(req2, res, ollamaUrl, verbose) {
|
|
|
317996
319047
|
const session = getSession(sessionId, model, cwdPath);
|
|
317997
319048
|
addUserMessage(session, chatBody.message);
|
|
317998
319049
|
compactSession(session);
|
|
319050
|
+
const wantsTools = chatBody["tools"] !== false && chatBody["use_tools"] !== false;
|
|
319051
|
+
const streamMode = chatBody.stream !== false;
|
|
319052
|
+
if (!wantsTools) {
|
|
319053
|
+
try {
|
|
319054
|
+
const ans = await directChatBackend({
|
|
319055
|
+
model,
|
|
319056
|
+
messages: session.messages.map((m2) => ({ role: m2.role, content: m2.content })),
|
|
319057
|
+
stream: streamMode,
|
|
319058
|
+
res,
|
|
319059
|
+
sessionId: session.id,
|
|
319060
|
+
ollamaUrl
|
|
319061
|
+
});
|
|
319062
|
+
if (ans !== null) {
|
|
319063
|
+
addAssistantMessage(session, ans);
|
|
319064
|
+
}
|
|
319065
|
+
} catch (err) {
|
|
319066
|
+
if (!res.headersSent) {
|
|
319067
|
+
res.setHeader("Content-Type", "application/problem+json; charset=utf-8");
|
|
319068
|
+
res.writeHead(502);
|
|
319069
|
+
res.end(JSON.stringify({
|
|
319070
|
+
type: "https://openagents.nexus/problems/upstream-failure",
|
|
319071
|
+
title: "Backend chat failed",
|
|
319072
|
+
status: 502,
|
|
319073
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
319074
|
+
instance: requestId,
|
|
319075
|
+
"session_id": session.id
|
|
319076
|
+
}));
|
|
319077
|
+
} else {
|
|
319078
|
+
try {
|
|
319079
|
+
res.end();
|
|
319080
|
+
} catch {
|
|
319081
|
+
}
|
|
319082
|
+
}
|
|
319083
|
+
}
|
|
319084
|
+
return;
|
|
319085
|
+
}
|
|
317999
319086
|
const historyLines = session.messages.filter((m2) => m2.role !== "system").slice(-10).map((m2) => m2.role === "user" ? `User: ${m2.content}` : `Assistant: ${m2.content}`).join("\n");
|
|
318000
319087
|
const taskPrompt = (historyLines ? `Previous conversation:
|
|
318001
319088
|
${historyLines}
|
|
@@ -318004,15 +319091,16 @@ ${historyLines}
|
|
|
318004
319091
|
const oaBin = process.argv[1] || "oa";
|
|
318005
319092
|
const args = [taskPrompt, "--json"];
|
|
318006
319093
|
if (model) args.push("--model", model.replace(/^local\//, ""));
|
|
318007
|
-
const streamMode = chatBody.stream !== false;
|
|
318008
319094
|
const currentCfg = loadConfig();
|
|
318009
|
-
const runEnv = {
|
|
318010
|
-
|
|
318011
|
-
|
|
318012
|
-
|
|
318013
|
-
|
|
318014
|
-
|
|
318015
|
-
|
|
319095
|
+
const runEnv = {};
|
|
319096
|
+
for (const [k, v] of Object.entries(process.env)) {
|
|
319097
|
+
if (k === "OA_DAEMON" || k === "OA_PORT") continue;
|
|
319098
|
+
if (typeof v === "string") runEnv[k] = v;
|
|
319099
|
+
}
|
|
319100
|
+
runEnv["__OPEN_AGENTS_NO_AUTO_RUN"] = "";
|
|
319101
|
+
runEnv["OA_RUN_USER"] = req2._authUser || "anonymous";
|
|
319102
|
+
runEnv["OA_RUN_SCOPE"] = req2._authScope || "admin";
|
|
319103
|
+
runEnv["OLLAMA_HOST"] = currentCfg.backendUrl || process.env["OLLAMA_HOST"] || "http://127.0.0.1:11434";
|
|
318016
319104
|
if (currentCfg.apiKey) runEnv["OA_API_KEY_INHERIT"] = currentCfg.apiKey;
|
|
318017
319105
|
const child = spawn25(process.execPath, [oaBin, ...args], {
|
|
318018
319106
|
cwd: cwdPath,
|
|
@@ -318059,44 +319147,54 @@ ${historyLines}
|
|
|
318059
319147
|
child.on("close", () => {
|
|
318060
319148
|
if (lineBuffer.trim()) finalLines.push(lineBuffer);
|
|
318061
319149
|
const rawFinal = finalLines.join("\n").trim();
|
|
319150
|
+
let backendError;
|
|
318062
319151
|
try {
|
|
318063
319152
|
const result = JSON.parse(rawFinal);
|
|
318064
|
-
|
|
319153
|
+
if (result.error) backendError = String(result.error);
|
|
319154
|
+
let content = sanitizeChatContent(result.assistant_text || "");
|
|
318065
319155
|
if (!content) {
|
|
318066
319156
|
const summary = result.summary || "";
|
|
318067
319157
|
const match = summary.match(/Tokens:\s*[\d,]+\s+([\s\S]*)/);
|
|
318068
|
-
content = match ? match[1]
|
|
319158
|
+
content = sanitizeChatContent(match ? match[1] : summary);
|
|
319159
|
+
}
|
|
319160
|
+
if (!content && result.text) {
|
|
319161
|
+
content = sanitizeChatContent(result.text);
|
|
318069
319162
|
}
|
|
318070
319163
|
fullContent = content;
|
|
318071
319164
|
if (content) {
|
|
318072
319165
|
res.write("data: " + JSON.stringify({
|
|
318073
|
-
id: `chatcmpl-${session.id.slice(0,
|
|
319166
|
+
id: `chatcmpl-${session.id.slice(0, 12)}`,
|
|
318074
319167
|
object: "chat.completion.chunk",
|
|
318075
|
-
|
|
319168
|
+
created: Math.floor(Date.now() / 1e3),
|
|
319169
|
+
model: model.replace(/^[a-z]+\//, ""),
|
|
319170
|
+
choices: [{ index: 0, delta: { content }, finish_reason: "stop" }]
|
|
318076
319171
|
}) + "\n\n");
|
|
319172
|
+
} else {
|
|
319173
|
+
const errMsg = backendError ? `Backend error: ${backendError}` : "Agent produced no response. The model may have failed to load.";
|
|
319174
|
+
res.write("data: " + JSON.stringify({
|
|
319175
|
+
id: `chatcmpl-${session.id.slice(0, 12)}`,
|
|
319176
|
+
object: "chat.completion.chunk",
|
|
319177
|
+
created: Math.floor(Date.now() / 1e3),
|
|
319178
|
+
model: model.replace(/^[a-z]+\//, ""),
|
|
319179
|
+
choices: [{ index: 0, delta: { content: errMsg }, finish_reason: "error" }]
|
|
319180
|
+
}) + "\n\n");
|
|
319181
|
+
fullContent = errMsg;
|
|
318077
319182
|
}
|
|
318078
319183
|
if (!toolCallsStreamed && result.tool_calls?.length) {
|
|
318079
319184
|
for (const tc of result.tool_calls) {
|
|
318080
319185
|
res.write("data: " + JSON.stringify({ type: "tool_call", tool: tc.tool, args: tc.args }) + "\n\n");
|
|
318081
319186
|
}
|
|
318082
319187
|
}
|
|
318083
|
-
|
|
319188
|
+
} catch {
|
|
319189
|
+
const errMsg = "Agent subprocess produced no parseable output.";
|
|
319190
|
+
fullContent = errMsg;
|
|
318084
319191
|
res.write("data: " + JSON.stringify({
|
|
318085
|
-
|
|
318086
|
-
|
|
318087
|
-
|
|
318088
|
-
|
|
318089
|
-
|
|
319192
|
+
id: `chatcmpl-${session.id.slice(0, 12)}`,
|
|
319193
|
+
object: "chat.completion.chunk",
|
|
319194
|
+
created: Math.floor(Date.now() / 1e3),
|
|
319195
|
+
model: model.replace(/^[a-z]+\//, ""),
|
|
319196
|
+
choices: [{ index: 0, delta: { content: errMsg }, finish_reason: "error" }]
|
|
318090
319197
|
}) + "\n\n");
|
|
318091
|
-
} catch {
|
|
318092
|
-
if (rawFinal) {
|
|
318093
|
-
fullContent = rawFinal.slice(0, 500);
|
|
318094
|
-
res.write("data: " + JSON.stringify({
|
|
318095
|
-
id: `chatcmpl-${session.id.slice(0, 8)}`,
|
|
318096
|
-
object: "chat.completion.chunk",
|
|
318097
|
-
choices: [{ index: 0, delta: { content: fullContent }, finish_reason: null }]
|
|
318098
|
-
}) + "\n\n");
|
|
318099
|
-
}
|
|
318100
319198
|
}
|
|
318101
319199
|
addAssistantMessage(session, fullContent);
|
|
318102
319200
|
res.write("data: [DONE]\n\n");
|
|
@@ -318129,23 +319227,73 @@ ${historyLines}
|
|
|
318129
319227
|
if (nonStreamBuf.trim()) nonStreamLines.push(nonStreamBuf);
|
|
318130
319228
|
const rawNonStream = nonStreamLines.join("\n").trim();
|
|
318131
319229
|
let content = "";
|
|
319230
|
+
let backendError;
|
|
319231
|
+
let durationMs = 0;
|
|
319232
|
+
let toolCallCount = 0;
|
|
319233
|
+
let parsed = null;
|
|
318132
319234
|
try {
|
|
318133
|
-
|
|
318134
|
-
|
|
318135
|
-
|
|
319235
|
+
parsed = JSON.parse(rawNonStream);
|
|
319236
|
+
durationMs = parsed.durationMs || 0;
|
|
319237
|
+
toolCallCount = parsed.tool_calls?.length || 0;
|
|
319238
|
+
if (parsed.error) backendError = String(parsed.error);
|
|
319239
|
+
if (parsed.assistant_text) {
|
|
319240
|
+
content = sanitizeChatContent(parsed.assistant_text);
|
|
318136
319241
|
}
|
|
318137
319242
|
if (!content) {
|
|
318138
|
-
const summary =
|
|
319243
|
+
const summary = parsed.summary || "";
|
|
318139
319244
|
const summaryMatch = summary.match(/Tokens:\s*[\d,]+\s+([\s\S]*)/);
|
|
318140
|
-
content = summaryMatch ? summaryMatch[1]
|
|
319245
|
+
content = sanitizeChatContent(summaryMatch ? summaryMatch[1] : summary);
|
|
319246
|
+
}
|
|
319247
|
+
if (!content && parsed.text) {
|
|
319248
|
+
content = sanitizeChatContent(parsed.text);
|
|
318141
319249
|
}
|
|
318142
319250
|
} catch {
|
|
318143
|
-
content = rawNonStream.slice(0, 500);
|
|
319251
|
+
content = sanitizeChatContent(rawNonStream.slice(0, 500));
|
|
319252
|
+
}
|
|
319253
|
+
const created = Math.floor(Date.now() / 1e3);
|
|
319254
|
+
const id = `chatcmpl-${session.id.slice(0, 12)}`;
|
|
319255
|
+
const cleanModel = model.replace(/^[a-z]+\//, "");
|
|
319256
|
+
if (!content) {
|
|
319257
|
+
const errMsg = backendError ? `Backend error: ${backendError}` : "Agent produced no response. The model may have failed to load (try a smaller model or check 'ollama ps' for VRAM contention).";
|
|
319258
|
+
jsonResponse(res, 200, {
|
|
319259
|
+
id,
|
|
319260
|
+
object: "chat.completion",
|
|
319261
|
+
created,
|
|
319262
|
+
model: cleanModel,
|
|
319263
|
+
choices: [{
|
|
319264
|
+
index: 0,
|
|
319265
|
+
message: { role: "assistant", content: errMsg },
|
|
319266
|
+
finish_reason: "error"
|
|
319267
|
+
}],
|
|
319268
|
+
usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },
|
|
319269
|
+
session_id: session.id,
|
|
319270
|
+
tool_calls: toolCallCount,
|
|
319271
|
+
duration_ms: durationMs,
|
|
319272
|
+
error: backendError ?? null
|
|
319273
|
+
});
|
|
319274
|
+
return;
|
|
318144
319275
|
}
|
|
318145
319276
|
addAssistantMessage(session, content.trim());
|
|
319277
|
+
const promptTokens = Math.round(session.messages.map((m2) => m2.content).join("").length / 4);
|
|
319278
|
+
const completionTokens = Math.round(content.length / 4);
|
|
318146
319279
|
jsonResponse(res, 200, {
|
|
319280
|
+
id,
|
|
319281
|
+
object: "chat.completion",
|
|
319282
|
+
created,
|
|
319283
|
+
model: cleanModel,
|
|
319284
|
+
choices: [{
|
|
319285
|
+
index: 0,
|
|
319286
|
+
message: { role: "assistant", content: content.trim() },
|
|
319287
|
+
finish_reason: "stop"
|
|
319288
|
+
}],
|
|
319289
|
+
usage: {
|
|
319290
|
+
prompt_tokens: promptTokens,
|
|
319291
|
+
completion_tokens: completionTokens,
|
|
319292
|
+
total_tokens: promptTokens + completionTokens
|
|
319293
|
+
},
|
|
318147
319294
|
session_id: session.id,
|
|
318148
|
-
|
|
319295
|
+
tool_calls: toolCallCount,
|
|
319296
|
+
duration_ms: durationMs
|
|
318149
319297
|
});
|
|
318150
319298
|
}
|
|
318151
319299
|
return;
|
|
@@ -318401,19 +319549,19 @@ function startApiServer(options2 = {}) {
|
|
|
318401
319549
|
const config = loadConfig();
|
|
318402
319550
|
const ollamaUrl = options2.ollamaUrl ?? config.backendUrl;
|
|
318403
319551
|
const cwd4 = process.cwd();
|
|
318404
|
-
initAuditLog(
|
|
318405
|
-
initUsageTracker(
|
|
319552
|
+
initAuditLog(join95(cwd4, ".oa"));
|
|
319553
|
+
initUsageTracker(join95(cwd4, ".oa"));
|
|
318406
319554
|
const retentionDays = parseInt(process.env["OA_JOB_RETENTION_DAYS"] ?? "30", 10);
|
|
318407
319555
|
if (retentionDays > 0) {
|
|
318408
319556
|
try {
|
|
318409
|
-
const jobsDir3 =
|
|
318410
|
-
if (
|
|
319557
|
+
const jobsDir3 = join95(cwd4, ".oa", "jobs");
|
|
319558
|
+
if (existsSync78(jobsDir3)) {
|
|
318411
319559
|
const cutoff = Date.now() - retentionDays * 864e5;
|
|
318412
|
-
for (const f2 of
|
|
319560
|
+
for (const f2 of readdirSync26(jobsDir3)) {
|
|
318413
319561
|
if (!f2.endsWith(".json")) continue;
|
|
318414
319562
|
try {
|
|
318415
|
-
const jobPath =
|
|
318416
|
-
const job = JSON.parse(
|
|
319563
|
+
const jobPath = join95(jobsDir3, f2);
|
|
319564
|
+
const job = JSON.parse(readFileSync61(jobPath, "utf-8"));
|
|
318417
319565
|
const jobTime = new Date(job.startedAt ?? job.completedAt ?? 0).getTime();
|
|
318418
319566
|
if (jobTime > 0 && jobTime < cutoff && job.status !== "running") {
|
|
318419
319567
|
const { unlinkSync: unlinkSync19 } = __require("node:fs");
|
|
@@ -318433,8 +319581,8 @@ function startApiServer(options2 = {}) {
|
|
|
318433
319581
|
if (useTls) {
|
|
318434
319582
|
try {
|
|
318435
319583
|
tlsOpts = {
|
|
318436
|
-
cert:
|
|
318437
|
-
key:
|
|
319584
|
+
cert: readFileSync61(resolve34(tlsCert)),
|
|
319585
|
+
key: readFileSync61(resolve34(tlsKey))
|
|
318438
319586
|
};
|
|
318439
319587
|
} catch (e2) {
|
|
318440
319588
|
log22(`
|
|
@@ -318634,13 +319782,13 @@ var init_serve = __esm({
|
|
|
318634
319782
|
|
|
318635
319783
|
// packages/cli/src/tui/interactive.ts
|
|
318636
319784
|
import { cwd } from "node:process";
|
|
318637
|
-
import { resolve as resolve35, join as
|
|
319785
|
+
import { resolve as resolve35, join as join96, dirname as dirname27, extname as extname11 } from "node:path";
|
|
318638
319786
|
import { createRequire as createRequire5 } from "node:module";
|
|
318639
319787
|
import { fileURLToPath as fileURLToPath17 } from "node:url";
|
|
318640
|
-
import { readFileSync as
|
|
318641
|
-
import { existsSync as
|
|
318642
|
-
import { execSync as
|
|
318643
|
-
import { homedir as
|
|
319788
|
+
import { readFileSync as readFileSync62, writeFileSync as writeFileSync41, appendFileSync as appendFileSync6, rmSync as rmSync4, readdirSync as readdirSync27, mkdirSync as mkdirSync47 } from "node:fs";
|
|
319789
|
+
import { existsSync as existsSync79 } from "node:fs";
|
|
319790
|
+
import { execSync as execSync56 } from "node:child_process";
|
|
319791
|
+
import { homedir as homedir32 } from "node:os";
|
|
318644
319792
|
function formatTimeAgo(date) {
|
|
318645
319793
|
const seconds = Math.floor((Date.now() - date.getTime()) / 1e3);
|
|
318646
319794
|
if (seconds < 60) return "just now";
|
|
@@ -318656,12 +319804,12 @@ function getVersion4() {
|
|
|
318656
319804
|
const require3 = createRequire5(import.meta.url);
|
|
318657
319805
|
const thisDir = dirname27(fileURLToPath17(import.meta.url));
|
|
318658
319806
|
const candidates = [
|
|
318659
|
-
|
|
318660
|
-
|
|
318661
|
-
|
|
319807
|
+
join96(thisDir, "..", "package.json"),
|
|
319808
|
+
join96(thisDir, "..", "..", "package.json"),
|
|
319809
|
+
join96(thisDir, "..", "..", "..", "package.json")
|
|
318662
319810
|
];
|
|
318663
319811
|
for (const pkgPath of candidates) {
|
|
318664
|
-
if (
|
|
319812
|
+
if (existsSync79(pkgPath)) {
|
|
318665
319813
|
const pkg = require3(pkgPath);
|
|
318666
319814
|
if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli" || pkg.name === "@open-agents/monorepo") {
|
|
318667
319815
|
return pkg.version ?? "0.0.0";
|
|
@@ -319168,14 +320316,14 @@ Meta-critique: quality ${meta.quality}/5, thorough: ${meta.thorough}`;
|
|
|
319168
320316
|
function gatherMemorySnippets(root) {
|
|
319169
320317
|
const snippets = [];
|
|
319170
320318
|
const dirs = [
|
|
319171
|
-
|
|
319172
|
-
|
|
320319
|
+
join96(root, ".oa", "memory"),
|
|
320320
|
+
join96(root, ".open-agents", "memory")
|
|
319173
320321
|
];
|
|
319174
320322
|
for (const dir of dirs) {
|
|
319175
|
-
if (!
|
|
320323
|
+
if (!existsSync79(dir)) continue;
|
|
319176
320324
|
try {
|
|
319177
|
-
for (const f2 of
|
|
319178
|
-
const data = JSON.parse(
|
|
320325
|
+
for (const f2 of readdirSync27(dir).filter((f3) => f3.endsWith(".json"))) {
|
|
320326
|
+
const data = JSON.parse(readFileSync62(join96(dir, f2), "utf-8"));
|
|
319179
320327
|
for (const val of Object.values(data)) {
|
|
319180
320328
|
const v = typeof val === "object" && val !== null && "value" in val ? String(val.value) : String(val);
|
|
319181
320329
|
if (v.length > 10) snippets.push(v);
|
|
@@ -319329,9 +320477,9 @@ ${metabolismMemories}
|
|
|
319329
320477
|
} catch {
|
|
319330
320478
|
}
|
|
319331
320479
|
try {
|
|
319332
|
-
const archeFile =
|
|
319333
|
-
if (
|
|
319334
|
-
const variants = JSON.parse(
|
|
320480
|
+
const archeFile = join96(repoRoot, ".oa", "arche", "variants.json");
|
|
320481
|
+
if (existsSync79(archeFile)) {
|
|
320482
|
+
const variants = JSON.parse(readFileSync62(archeFile, "utf8"));
|
|
319335
320483
|
if (variants.length > 0) {
|
|
319336
320484
|
let filtered = variants;
|
|
319337
320485
|
if (taskType) {
|
|
@@ -319500,9 +320648,9 @@ RULES:
|
|
|
319500
320648
|
const compactionThreshold = modelTier === "small" ? 12e3 : modelTier === "medium" ? 24e3 : 4e4;
|
|
319501
320649
|
let identityInjection = "";
|
|
319502
320650
|
try {
|
|
319503
|
-
const ikStateFile =
|
|
319504
|
-
if (
|
|
319505
|
-
const selfState = JSON.parse(
|
|
320651
|
+
const ikStateFile = join96(repoRoot, ".oa", "identity", "self-state.json");
|
|
320652
|
+
if (existsSync79(ikStateFile)) {
|
|
320653
|
+
const selfState = JSON.parse(readFileSync62(ikStateFile, "utf8"));
|
|
319506
320654
|
const lines = [
|
|
319507
320655
|
`[Identity State v${selfState.version}]`,
|
|
319508
320656
|
`Self: ${selfState.narrative_summary}`,
|
|
@@ -320230,11 +321378,11 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
|
|
|
320230
321378
|
});
|
|
320231
321379
|
}
|
|
320232
321380
|
try {
|
|
320233
|
-
const ikDir =
|
|
320234
|
-
const ikFile =
|
|
321381
|
+
const ikDir = join96(repoRoot, ".oa", "identity");
|
|
321382
|
+
const ikFile = join96(ikDir, "self-state.json");
|
|
320235
321383
|
let ikState;
|
|
320236
|
-
if (
|
|
320237
|
-
ikState = JSON.parse(
|
|
321384
|
+
if (existsSync79(ikFile)) {
|
|
321385
|
+
ikState = JSON.parse(readFileSync62(ikFile, "utf8"));
|
|
320238
321386
|
} else {
|
|
320239
321387
|
mkdirSync47(ikDir, { recursive: true });
|
|
320240
321388
|
const machineId = Date.now().toString(36) + Math.random().toString(36).slice(2, 8);
|
|
@@ -320311,9 +321459,9 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
|
|
|
320311
321459
|
} else {
|
|
320312
321460
|
renderTaskIncomplete(result.turns, result.toolCalls, result.durationMs, tokens);
|
|
320313
321461
|
try {
|
|
320314
|
-
const ikFile =
|
|
320315
|
-
if (
|
|
320316
|
-
const ikState = JSON.parse(
|
|
321462
|
+
const ikFile = join96(repoRoot, ".oa", "identity", "self-state.json");
|
|
321463
|
+
if (existsSync79(ikFile)) {
|
|
321464
|
+
const ikState = JSON.parse(readFileSync62(ikFile, "utf8"));
|
|
320317
321465
|
if (!ikState.stats) ikState.stats = { queries_served: 0 };
|
|
320318
321466
|
ikState.stats.queries_served = (ikState.stats.queries_served || 0) + 1;
|
|
320319
321467
|
ikState.homeostasis.uncertainty = Math.min(1, ikState.homeostasis.uncertainty + 0.03);
|
|
@@ -320439,10 +321587,10 @@ async function startInteractive(config, repoPath) {
|
|
|
320439
321587
|
process.stdin.pause();
|
|
320440
321588
|
}
|
|
320441
321589
|
try {
|
|
320442
|
-
const oaDir =
|
|
320443
|
-
const nexusPidFile =
|
|
320444
|
-
if (
|
|
320445
|
-
const pid = parseInt(
|
|
321590
|
+
const oaDir = join96(repoRoot, ".oa");
|
|
321591
|
+
const nexusPidFile = join96(oaDir, "nexus", "daemon.pid");
|
|
321592
|
+
if (existsSync79(nexusPidFile)) {
|
|
321593
|
+
const pid = parseInt(readFileSync62(nexusPidFile, "utf8").trim(), 10);
|
|
320446
321594
|
if (pid > 0) {
|
|
320447
321595
|
try {
|
|
320448
321596
|
process.kill(pid, 0);
|
|
@@ -320987,7 +322135,7 @@ ${opts.systemPromptAddition}` : `Working directory: ${repoRoot}`;
|
|
|
320987
322135
|
let p2pGateway = null;
|
|
320988
322136
|
let peerMesh = null;
|
|
320989
322137
|
let inferenceRouter = null;
|
|
320990
|
-
const secretVault = new SecretVault(
|
|
322138
|
+
const secretVault = new SecretVault(join96(repoRoot, ".oa", "vault.enc"));
|
|
320991
322139
|
let adminSessionKey = null;
|
|
320992
322140
|
const callSubAgents = /* @__PURE__ */ new Map();
|
|
320993
322141
|
const streamRenderer = new StreamRenderer();
|
|
@@ -321206,13 +322354,13 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
321206
322354
|
const hits = allCompletions.filter((c7) => c7.toLowerCase().startsWith(lower));
|
|
321207
322355
|
return [hits, line];
|
|
321208
322356
|
}
|
|
321209
|
-
const HISTORY_DIR =
|
|
321210
|
-
const HISTORY_FILE =
|
|
322357
|
+
const HISTORY_DIR = join96(homedir32(), ".open-agents");
|
|
322358
|
+
const HISTORY_FILE = join96(HISTORY_DIR, "repl-history");
|
|
321211
322359
|
const MAX_HISTORY_LINES = 500;
|
|
321212
322360
|
let savedHistory = [];
|
|
321213
322361
|
try {
|
|
321214
|
-
if (
|
|
321215
|
-
const raw =
|
|
322362
|
+
if (existsSync79(HISTORY_FILE)) {
|
|
322363
|
+
const raw = readFileSync62(HISTORY_FILE, "utf8").trim();
|
|
321216
322364
|
if (raw) savedHistory = raw.split("\n").reverse();
|
|
321217
322365
|
}
|
|
321218
322366
|
} catch {
|
|
@@ -321340,7 +322488,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
321340
322488
|
mkdirSync47(HISTORY_DIR, { recursive: true });
|
|
321341
322489
|
appendFileSync6(HISTORY_FILE, line + "\n", "utf8");
|
|
321342
322490
|
if (Math.random() < 0.02) {
|
|
321343
|
-
const all2 =
|
|
322491
|
+
const all2 = readFileSync62(HISTORY_FILE, "utf8").trim().split("\n");
|
|
321344
322492
|
if (all2.length > MAX_HISTORY_LINES) {
|
|
321345
322493
|
writeFileSync41(HISTORY_FILE, all2.slice(-MAX_HISTORY_LINES).join("\n") + "\n", "utf8");
|
|
321346
322494
|
}
|
|
@@ -321516,10 +322664,10 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
321516
322664
|
const { unlinkSync: _rmStale } = await import("node:fs");
|
|
321517
322665
|
const { homedir: _hdir } = await import("node:os");
|
|
321518
322666
|
for (const dp of [
|
|
321519
|
-
|
|
321520
|
-
|
|
322667
|
+
join96(repoRoot, ".oa", "nexus", "nexus-daemon.mjs"),
|
|
322668
|
+
join96(_hdir(), ".open-agents", ".oa", "nexus", "nexus-daemon.mjs")
|
|
321521
322669
|
]) {
|
|
321522
|
-
if (
|
|
322670
|
+
if (existsSync79(dp)) try {
|
|
321523
322671
|
_rmStale(dp);
|
|
321524
322672
|
} catch {
|
|
321525
322673
|
}
|
|
@@ -321530,9 +322678,9 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
321530
322678
|
const autoNexus = new NexusTool(repoRoot);
|
|
321531
322679
|
const _registerNexusDaemon = () => {
|
|
321532
322680
|
try {
|
|
321533
|
-
const nexusPidFile =
|
|
321534
|
-
if (
|
|
321535
|
-
const nPid = parseInt(
|
|
322681
|
+
const nexusPidFile = join96(repoRoot, ".oa", "nexus", "daemon.pid");
|
|
322682
|
+
if (existsSync79(nexusPidFile)) {
|
|
322683
|
+
const nPid = parseInt(readFileSync62(nexusPidFile, "utf8").trim(), 10);
|
|
321536
322684
|
if (nPid > 0 && !registry2.daemons.has("Nexus")) {
|
|
321537
322685
|
registry2.register({ name: "Nexus", pid: nPid, startedAt: Date.now(), status: "running" });
|
|
321538
322686
|
statusBar.ensureMonitorTimer();
|
|
@@ -321579,7 +322727,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
321579
322727
|
} catch {
|
|
321580
322728
|
}
|
|
321581
322729
|
try {
|
|
321582
|
-
const oaDir =
|
|
322730
|
+
const oaDir = join96(repoRoot, ".oa");
|
|
321583
322731
|
const reconnected = await ExposeGateway.checkAndReconnect(oaDir, {
|
|
321584
322732
|
onInfo: (msg) => writeContent(() => renderInfo(msg)),
|
|
321585
322733
|
onError: (msg) => writeContent(() => renderWarning(msg))
|
|
@@ -321611,7 +322759,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
321611
322759
|
} catch {
|
|
321612
322760
|
}
|
|
321613
322761
|
try {
|
|
321614
|
-
const oaDir =
|
|
322762
|
+
const oaDir = join96(repoRoot, ".oa");
|
|
321615
322763
|
const reconnectedP2P = await ExposeP2PGateway.checkAndReconnect(oaDir, new NexusTool(repoRoot), {
|
|
321616
322764
|
onInfo: (msg) => writeContent(() => renderInfo(msg)),
|
|
321617
322765
|
onError: (msg) => writeContent(() => renderWarning(msg))
|
|
@@ -321652,10 +322800,10 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
321652
322800
|
}
|
|
321653
322801
|
try {
|
|
321654
322802
|
const { homedir: _hd, hostname: _hn, userInfo: _ui } = await import("node:os");
|
|
321655
|
-
const globalNamePath =
|
|
322803
|
+
const globalNamePath = join96(_hd(), ".open-agents", "agent-name");
|
|
321656
322804
|
let agName = "";
|
|
321657
322805
|
try {
|
|
321658
|
-
if (
|
|
322806
|
+
if (existsSync79(globalNamePath)) agName = readFileSync62(globalNamePath, "utf8").trim();
|
|
321659
322807
|
} catch {
|
|
321660
322808
|
}
|
|
321661
322809
|
if (!agName) {
|
|
@@ -321684,11 +322832,11 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
321684
322832
|
}
|
|
321685
322833
|
if (!ollamaAlive) {
|
|
321686
322834
|
try {
|
|
321687
|
-
const savedSponsorsPath =
|
|
322835
|
+
const savedSponsorsPath = join96(repoRoot, ".oa", "sponsor", "known-sponsors.json");
|
|
321688
322836
|
let savedSponsors = [];
|
|
321689
322837
|
try {
|
|
321690
|
-
if (
|
|
321691
|
-
savedSponsors = JSON.parse(
|
|
322838
|
+
if (existsSync79(savedSponsorsPath)) {
|
|
322839
|
+
savedSponsors = JSON.parse(readFileSync62(savedSponsorsPath, "utf8"));
|
|
321692
322840
|
const oneHourAgo = Date.now() - 36e5;
|
|
321693
322841
|
savedSponsors = savedSponsors.filter((s2) => (s2.lastVerified || 0) > oneHourAgo);
|
|
321694
322842
|
}
|
|
@@ -322655,7 +323803,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
322655
323803
|
kind,
|
|
322656
323804
|
targetUrl,
|
|
322657
323805
|
authKey,
|
|
322658
|
-
stateDir:
|
|
323806
|
+
stateDir: join96(repoRoot, ".oa"),
|
|
322659
323807
|
passthrough: passthrough ?? false,
|
|
322660
323808
|
loadbalance: loadbalance ?? false,
|
|
322661
323809
|
endpointAuth: passthrough ? currentConfig.apiKey : void 0,
|
|
@@ -322701,7 +323849,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
322701
323849
|
await tunnelGateway.stop();
|
|
322702
323850
|
tunnelGateway = null;
|
|
322703
323851
|
}
|
|
322704
|
-
const newTunnel = new ExposeGateway({ kind, targetUrl, authKey, fullAccess, stateDir:
|
|
323852
|
+
const newTunnel = new ExposeGateway({ kind, targetUrl, authKey, fullAccess, stateDir: join96(repoRoot, ".oa") });
|
|
322705
323853
|
newTunnel.on("stats", (stats) => {
|
|
322706
323854
|
statusBar.setExposeStatus({
|
|
322707
323855
|
status: stats.status,
|
|
@@ -322788,9 +323936,9 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
322788
323936
|
});
|
|
322789
323937
|
if (!result.success) throw new Error(result.error || "Connect failed");
|
|
322790
323938
|
try {
|
|
322791
|
-
const nexusPidFile =
|
|
322792
|
-
if (
|
|
322793
|
-
const pid = parseInt(
|
|
323939
|
+
const nexusPidFile = join96(repoRoot, ".oa", "nexus", "daemon.pid");
|
|
323940
|
+
if (existsSync79(nexusPidFile)) {
|
|
323941
|
+
const pid = parseInt(readFileSync62(nexusPidFile, "utf8").trim(), 10);
|
|
322794
323942
|
if (pid > 0) {
|
|
322795
323943
|
registry2.register({
|
|
322796
323944
|
name: "Nexus",
|
|
@@ -322976,15 +324124,15 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
322976
324124
|
writeContent(() => renderInfo(`Killed ${bgKilled} background task(s).`));
|
|
322977
324125
|
}
|
|
322978
324126
|
try {
|
|
322979
|
-
const nexusDir =
|
|
322980
|
-
const pidFile =
|
|
322981
|
-
if (
|
|
322982
|
-
const pid = parseInt(
|
|
324127
|
+
const nexusDir = join96(repoRoot, OA_DIR, "nexus");
|
|
324128
|
+
const pidFile = join96(nexusDir, "daemon.pid");
|
|
324129
|
+
if (existsSync79(pidFile)) {
|
|
324130
|
+
const pid = parseInt(readFileSync62(pidFile, "utf8").trim(), 10);
|
|
322983
324131
|
if (pid > 0) {
|
|
322984
324132
|
try {
|
|
322985
324133
|
if (process.platform === "win32") {
|
|
322986
324134
|
try {
|
|
322987
|
-
|
|
324135
|
+
execSync56(`taskkill /F /PID ${pid}`, { timeout: 5e3, stdio: "ignore" });
|
|
322988
324136
|
} catch {
|
|
322989
324137
|
}
|
|
322990
324138
|
} else {
|
|
@@ -323001,17 +324149,17 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
323001
324149
|
} catch {
|
|
323002
324150
|
}
|
|
323003
324151
|
try {
|
|
323004
|
-
const voiceDir2 =
|
|
324152
|
+
const voiceDir2 = join96(homedir32(), ".open-agents", "voice");
|
|
323005
324153
|
const voicePidFiles = ["luxtts-daemon.pid", "piper-daemon.pid"];
|
|
323006
324154
|
for (const pf of voicePidFiles) {
|
|
323007
|
-
const pidPath =
|
|
323008
|
-
if (
|
|
324155
|
+
const pidPath = join96(voiceDir2, pf);
|
|
324156
|
+
if (existsSync79(pidPath)) {
|
|
323009
324157
|
try {
|
|
323010
|
-
const pid = parseInt(
|
|
324158
|
+
const pid = parseInt(readFileSync62(pidPath, "utf8").trim(), 10);
|
|
323011
324159
|
if (pid > 0) {
|
|
323012
324160
|
if (process.platform === "win32") {
|
|
323013
324161
|
try {
|
|
323014
|
-
|
|
324162
|
+
execSync56(`taskkill /F /PID ${pid}`, { timeout: 5e3, stdio: "ignore" });
|
|
323015
324163
|
} catch {
|
|
323016
324164
|
}
|
|
323017
324165
|
} else {
|
|
@@ -323028,11 +324176,11 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
323028
324176
|
} catch {
|
|
323029
324177
|
}
|
|
323030
324178
|
try {
|
|
323031
|
-
|
|
324179
|
+
execSync56(process.platform === "win32" ? "timeout /t 1 /nobreak >nul" : "sleep 0.5", { timeout: 3e3, stdio: "ignore" });
|
|
323032
324180
|
} catch {
|
|
323033
324181
|
}
|
|
323034
|
-
const oaPath =
|
|
323035
|
-
if (
|
|
324182
|
+
const oaPath = join96(repoRoot, OA_DIR);
|
|
324183
|
+
if (existsSync79(oaPath)) {
|
|
323036
324184
|
let deleted = false;
|
|
323037
324185
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
323038
324186
|
try {
|
|
@@ -323042,14 +324190,14 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
323042
324190
|
} catch (err) {
|
|
323043
324191
|
if (attempt < 2) {
|
|
323044
324192
|
try {
|
|
323045
|
-
|
|
324193
|
+
execSync56(process.platform === "win32" ? "timeout /t 1 /nobreak >nul" : "sleep 0.3", { timeout: 3e3, stdio: "ignore" });
|
|
323046
324194
|
} catch {
|
|
323047
324195
|
}
|
|
323048
324196
|
} else {
|
|
323049
324197
|
writeContent(() => renderWarning(`Could not fully remove ${OA_DIR}/: ${err instanceof Error ? err.message : String(err)}`));
|
|
323050
324198
|
if (process.platform === "win32") {
|
|
323051
324199
|
try {
|
|
323052
|
-
|
|
324200
|
+
execSync56(`rd /s /q "${oaPath}"`, { timeout: 1e4, stdio: "ignore" });
|
|
323053
324201
|
deleted = true;
|
|
323054
324202
|
} catch {
|
|
323055
324203
|
}
|
|
@@ -323115,19 +324263,19 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
323115
324263
|
try {
|
|
323116
324264
|
const { isPersonaPlexRunning: isPersonaPlexRunning2 } = await Promise.resolve().then(() => (init_personaplex(), personaplex_exports));
|
|
323117
324265
|
if (isPersonaPlexRunning2()) {
|
|
323118
|
-
const ppPidFile =
|
|
323119
|
-
const ppPortFile =
|
|
323120
|
-
if (
|
|
323121
|
-
const ppPid = parseInt(
|
|
323122
|
-
const ppPort =
|
|
324266
|
+
const ppPidFile = join96(homedir32(), ".open-agents", "voice", "personaplex", "daemon.pid");
|
|
324267
|
+
const ppPortFile = join96(homedir32(), ".open-agents", "voice", "personaplex", "daemon.port");
|
|
324268
|
+
if (existsSync79(ppPidFile)) {
|
|
324269
|
+
const ppPid = parseInt(readFileSync62(ppPidFile, "utf8").trim(), 10);
|
|
324270
|
+
const ppPort = existsSync79(ppPortFile) ? parseInt(readFileSync62(ppPortFile, "utf8").trim(), 10) : void 0;
|
|
323123
324271
|
if (ppPid > 0 && !registry2.daemons.has("PersonaPlex")) {
|
|
323124
324272
|
registry2.register({ name: "PersonaPlex", pid: ppPid, port: ppPort, startedAt: Date.now(), status: "running" });
|
|
323125
324273
|
}
|
|
323126
324274
|
}
|
|
323127
324275
|
}
|
|
323128
|
-
const nexusPidFile =
|
|
323129
|
-
if (
|
|
323130
|
-
const nPid = parseInt(
|
|
324276
|
+
const nexusPidFile = join96(repoRoot, ".oa", "nexus", "daemon.pid");
|
|
324277
|
+
if (existsSync79(nexusPidFile)) {
|
|
324278
|
+
const nPid = parseInt(readFileSync62(nexusPidFile, "utf8").trim(), 10);
|
|
323131
324279
|
if (nPid > 0 && !registry2.daemons.has("Nexus")) {
|
|
323132
324280
|
try {
|
|
323133
324281
|
process.kill(nPid, 0);
|
|
@@ -323468,9 +324616,9 @@ Execute this skill now. Follow the behavioral guidance above.`;
|
|
|
323468
324616
|
}
|
|
323469
324617
|
}
|
|
323470
324618
|
const cleanPath = input.replace(/^['"]|['"]$/g, "").trim();
|
|
323471
|
-
const isImage = isImagePath(cleanPath) &&
|
|
323472
|
-
const isMedia = !isImage && isTranscribablePath(cleanPath) &&
|
|
323473
|
-
const isMarkdown = !isImage && !isMedia && /\.(md|markdown)$/i.test(cleanPath) &&
|
|
324619
|
+
const isImage = isImagePath(cleanPath) && existsSync79(resolve35(repoRoot, cleanPath));
|
|
324620
|
+
const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync79(resolve35(repoRoot, cleanPath));
|
|
324621
|
+
const isMarkdown = !isImage && !isMedia && /\.(md|markdown)$/i.test(cleanPath) && existsSync79(resolve35(repoRoot, cleanPath));
|
|
323474
324622
|
if (activeTask) {
|
|
323475
324623
|
if (activeTask.runner.isPaused) {
|
|
323476
324624
|
activeTask.runner.resume();
|
|
@@ -323479,7 +324627,7 @@ Execute this skill now. Follow the behavioral guidance above.`;
|
|
|
323479
324627
|
if (isImage) {
|
|
323480
324628
|
try {
|
|
323481
324629
|
const imgPath = resolve35(repoRoot, cleanPath);
|
|
323482
|
-
const imgBuffer =
|
|
324630
|
+
const imgBuffer = readFileSync62(imgPath);
|
|
323483
324631
|
const base642 = imgBuffer.toString("base64");
|
|
323484
324632
|
const ext = extname11(cleanPath).toLowerCase();
|
|
323485
324633
|
const mime = ext === ".png" ? "image/png" : ext === ".gif" ? "image/gif" : ext === ".webp" ? "image/webp" : "image/jpeg";
|
|
@@ -323647,7 +324795,7 @@ ${result.text}`;
|
|
|
323647
324795
|
if (isMarkdown && fullInput === input) {
|
|
323648
324796
|
try {
|
|
323649
324797
|
const mdPath = resolve35(repoRoot, cleanPath);
|
|
323650
|
-
const mdContent =
|
|
324798
|
+
const mdContent = readFileSync62(mdPath, "utf8");
|
|
323651
324799
|
const { parseMcpMarkdown: parseMcpMarkdown2 } = await Promise.resolve().then(() => (init_dist4(), dist_exports));
|
|
323652
324800
|
const result = parseMcpMarkdown2(mdContent);
|
|
323653
324801
|
if (result.servers.length > 0) {
|
|
@@ -323736,7 +324884,7 @@ Summarize or analyze this transcription as appropriate.`;
|
|
|
323736
324884
|
|
|
323737
324885
|
NEW TASK: ${fullInput}`;
|
|
323738
324886
|
restoredSessionContext = null;
|
|
323739
|
-
} else if (
|
|
324887
|
+
} else if (existsSync79(join96(repoRoot, ".oa", "context", "session-diary.md"))) {
|
|
323740
324888
|
taskInput = `[Previous sessions exist \u2014 file_read(".oa/context/session-diary.md") to recall]
|
|
323741
324889
|
|
|
323742
324890
|
${fullInput}`;
|
|
@@ -324070,11 +325218,11 @@ async function runWithTUI(task, config, repoPath, callbacks) {
|
|
|
324070
325218
|
const handle2 = startTask(task, config, repoRoot);
|
|
324071
325219
|
await handle2.promise;
|
|
324072
325220
|
try {
|
|
324073
|
-
const ikDir =
|
|
324074
|
-
const ikFile =
|
|
325221
|
+
const ikDir = join96(repoRoot, ".oa", "identity");
|
|
325222
|
+
const ikFile = join96(ikDir, "self-state.json");
|
|
324075
325223
|
let ikState;
|
|
324076
|
-
if (
|
|
324077
|
-
ikState = JSON.parse(
|
|
325224
|
+
if (existsSync79(ikFile)) {
|
|
325225
|
+
ikState = JSON.parse(readFileSync62(ikFile, "utf8"));
|
|
324078
325226
|
} else {
|
|
324079
325227
|
mkdirSync47(ikDir, { recursive: true });
|
|
324080
325228
|
ikState = {
|
|
@@ -324111,11 +325259,11 @@ async function runWithTUI(task, config, repoPath, callbacks) {
|
|
|
324111
325259
|
);
|
|
324112
325260
|
} catch {
|
|
324113
325261
|
try {
|
|
324114
|
-
const archeDir =
|
|
324115
|
-
const archeFile =
|
|
325262
|
+
const archeDir = join96(repoRoot, ".oa", "arche");
|
|
325263
|
+
const archeFile = join96(archeDir, "variants.json");
|
|
324116
325264
|
let variants = [];
|
|
324117
325265
|
try {
|
|
324118
|
-
if (
|
|
325266
|
+
if (existsSync79(archeFile)) variants = JSON.parse(readFileSync62(archeFile, "utf8"));
|
|
324119
325267
|
} catch {
|
|
324120
325268
|
}
|
|
324121
325269
|
variants.push({
|
|
@@ -324135,9 +325283,9 @@ async function runWithTUI(task, config, repoPath, callbacks) {
|
|
|
324135
325283
|
}
|
|
324136
325284
|
}
|
|
324137
325285
|
try {
|
|
324138
|
-
const metaFile =
|
|
324139
|
-
if (
|
|
324140
|
-
const store2 = JSON.parse(
|
|
325286
|
+
const metaFile = join96(repoRoot, ".oa", "memory", "metabolism", "store.json");
|
|
325287
|
+
if (existsSync79(metaFile)) {
|
|
325288
|
+
const store2 = JSON.parse(readFileSync62(metaFile, "utf8"));
|
|
324141
325289
|
const surfaced = store2.filter((m2) => m2.type !== "quarantine" && m2.scores?.confidence > 0.15).sort((a2, b) => b.scores.utility * b.scores.confidence - a2.scores.utility * a2.scores.confidence).slice(0, 5);
|
|
324142
325290
|
let updated = false;
|
|
324143
325291
|
for (const item of surfaced) {
|
|
@@ -324201,9 +325349,9 @@ Rules:
|
|
|
324201
325349
|
try {
|
|
324202
325350
|
const { initDb: initDb2 } = __require("@open-agents/memory");
|
|
324203
325351
|
const { ProceduralMemoryStore: ProceduralMemoryStore2 } = __require("@open-agents/memory");
|
|
324204
|
-
const dbDir =
|
|
325352
|
+
const dbDir = join96(repoRoot, ".oa", "memory");
|
|
324205
325353
|
mkdirSync47(dbDir, { recursive: true });
|
|
324206
|
-
const db = initDb2(
|
|
325354
|
+
const db = initDb2(join96(dbDir, "structured.db"));
|
|
324207
325355
|
const memStore = new ProceduralMemoryStore2(db);
|
|
324208
325356
|
memStore.createWithEmbedding({
|
|
324209
325357
|
content: content.slice(0, 600),
|
|
@@ -324218,11 +325366,11 @@ Rules:
|
|
|
324218
325366
|
db.close();
|
|
324219
325367
|
} catch {
|
|
324220
325368
|
}
|
|
324221
|
-
const metaDir =
|
|
324222
|
-
const storeFile =
|
|
325369
|
+
const metaDir = join96(repoRoot, ".oa", "memory", "metabolism");
|
|
325370
|
+
const storeFile = join96(metaDir, "store.json");
|
|
324223
325371
|
let store2 = [];
|
|
324224
325372
|
try {
|
|
324225
|
-
if (
|
|
325373
|
+
if (existsSync79(storeFile)) store2 = JSON.parse(readFileSync62(storeFile, "utf8"));
|
|
324226
325374
|
} catch {
|
|
324227
325375
|
}
|
|
324228
325376
|
store2.push({
|
|
@@ -324244,19 +325392,19 @@ Rules:
|
|
|
324244
325392
|
} catch {
|
|
324245
325393
|
}
|
|
324246
325394
|
try {
|
|
324247
|
-
const cohereSettingsFile =
|
|
325395
|
+
const cohereSettingsFile = join96(repoRoot, ".oa", "settings.json");
|
|
324248
325396
|
let cohereActive = false;
|
|
324249
325397
|
try {
|
|
324250
|
-
if (
|
|
324251
|
-
const settings = JSON.parse(
|
|
325398
|
+
if (existsSync79(cohereSettingsFile)) {
|
|
325399
|
+
const settings = JSON.parse(readFileSync62(cohereSettingsFile, "utf8"));
|
|
324252
325400
|
cohereActive = settings.cohere === true;
|
|
324253
325401
|
}
|
|
324254
325402
|
} catch {
|
|
324255
325403
|
}
|
|
324256
325404
|
if (cohereActive) {
|
|
324257
|
-
const metaFile =
|
|
324258
|
-
if (
|
|
324259
|
-
const store2 = JSON.parse(
|
|
325405
|
+
const metaFile = join96(repoRoot, ".oa", "memory", "metabolism", "store.json");
|
|
325406
|
+
if (existsSync79(metaFile)) {
|
|
325407
|
+
const store2 = JSON.parse(readFileSync62(metaFile, "utf8"));
|
|
324260
325408
|
const latest = store2.filter((m2) => m2.sourceTrace === "trajectory-extraction" || m2.sourceTrace === "llm-trajectory-extraction").slice(-1)[0];
|
|
324261
325409
|
if (latest && latest.scores?.confidence >= 0.6) {
|
|
324262
325410
|
try {
|
|
@@ -324281,18 +325429,18 @@ Rules:
|
|
|
324281
325429
|
}
|
|
324282
325430
|
} catch (err) {
|
|
324283
325431
|
try {
|
|
324284
|
-
const ikFile =
|
|
324285
|
-
if (
|
|
324286
|
-
const ikState = JSON.parse(
|
|
325432
|
+
const ikFile = join96(repoRoot, ".oa", "identity", "self-state.json");
|
|
325433
|
+
if (existsSync79(ikFile)) {
|
|
325434
|
+
const ikState = JSON.parse(readFileSync62(ikFile, "utf8"));
|
|
324287
325435
|
ikState.homeostasis.uncertainty = Math.min(1, ikState.homeostasis.uncertainty + 0.1);
|
|
324288
325436
|
ikState.homeostasis.coherence = Math.max(0, ikState.homeostasis.coherence - 0.05);
|
|
324289
325437
|
ikState.session_count = (ikState.session_count || 0) + 1;
|
|
324290
325438
|
ikState.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
324291
325439
|
writeFileSync41(ikFile, JSON.stringify(ikState, null, 2));
|
|
324292
325440
|
}
|
|
324293
|
-
const metaFile =
|
|
324294
|
-
if (
|
|
324295
|
-
const store2 = JSON.parse(
|
|
325441
|
+
const metaFile = join96(repoRoot, ".oa", "memory", "metabolism", "store.json");
|
|
325442
|
+
if (existsSync79(metaFile)) {
|
|
325443
|
+
const store2 = JSON.parse(readFileSync62(metaFile, "utf8"));
|
|
324296
325444
|
const surfaced = store2.filter((m2) => m2.type !== "quarantine" && m2.scores?.confidence > 0.15).sort((a2, b) => b.scores.utility * b.scores.confidence - a2.scores.utility * a2.scores.confidence).slice(0, 5);
|
|
324297
325445
|
for (const item of surfaced) {
|
|
324298
325446
|
item.accessCount = (item.accessCount || 0) + 1;
|
|
@@ -324303,11 +325451,11 @@ Rules:
|
|
|
324303
325451
|
writeFileSync41(metaFile, JSON.stringify(store2, null, 2));
|
|
324304
325452
|
}
|
|
324305
325453
|
try {
|
|
324306
|
-
const archeDir =
|
|
324307
|
-
const archeFile =
|
|
325454
|
+
const archeDir = join96(repoRoot, ".oa", "arche");
|
|
325455
|
+
const archeFile = join96(archeDir, "variants.json");
|
|
324308
325456
|
let variants = [];
|
|
324309
325457
|
try {
|
|
324310
|
-
if (
|
|
325458
|
+
if (existsSync79(archeFile)) variants = JSON.parse(readFileSync62(archeFile, "utf8"));
|
|
324311
325459
|
} catch {
|
|
324312
325460
|
}
|
|
324313
325461
|
variants.push({
|
|
@@ -324405,12 +325553,12 @@ __export(run_exports, {
|
|
|
324405
325553
|
});
|
|
324406
325554
|
import { resolve as resolve36 } from "node:path";
|
|
324407
325555
|
import { spawn as spawn26 } from "node:child_process";
|
|
324408
|
-
import { mkdirSync as mkdirSync48, writeFileSync as writeFileSync42, readFileSync as
|
|
325556
|
+
import { mkdirSync as mkdirSync48, writeFileSync as writeFileSync42, readFileSync as readFileSync63, readdirSync as readdirSync28, existsSync as existsSync80 } from "node:fs";
|
|
324409
325557
|
import { randomBytes as randomBytes20 } from "node:crypto";
|
|
324410
|
-
import { join as
|
|
325558
|
+
import { join as join97 } from "node:path";
|
|
324411
325559
|
function jobsDir2(repoPath) {
|
|
324412
325560
|
const root = resolve36(repoPath ?? process.cwd());
|
|
324413
|
-
const dir =
|
|
325561
|
+
const dir = join97(root, ".oa", "jobs");
|
|
324414
325562
|
mkdirSync48(dir, { recursive: true });
|
|
324415
325563
|
return dir;
|
|
324416
325564
|
}
|
|
@@ -324526,7 +325674,7 @@ async function runBackground(task, config, opts) {
|
|
|
324526
325674
|
}
|
|
324527
325675
|
});
|
|
324528
325676
|
job.pid = child.pid ?? 0;
|
|
324529
|
-
writeFileSync42(
|
|
325677
|
+
writeFileSync42(join97(dir, `${id}.json`), JSON.stringify(job, null, 2));
|
|
324530
325678
|
let output = "";
|
|
324531
325679
|
child.stdout?.on("data", (chunk) => {
|
|
324532
325680
|
output += chunk.toString();
|
|
@@ -324542,7 +325690,7 @@ async function runBackground(task, config, opts) {
|
|
|
324542
325690
|
job.summary = result.summary;
|
|
324543
325691
|
job.durationMs = result.durationMs;
|
|
324544
325692
|
job.error = result.error;
|
|
324545
|
-
writeFileSync42(
|
|
325693
|
+
writeFileSync42(join97(dir, `${id}.json`), JSON.stringify(job, null, 2));
|
|
324546
325694
|
} catch {
|
|
324547
325695
|
}
|
|
324548
325696
|
});
|
|
@@ -324558,13 +325706,13 @@ async function runBackground(task, config, opts) {
|
|
|
324558
325706
|
}
|
|
324559
325707
|
function statusCommand(jobId, repoPath) {
|
|
324560
325708
|
const dir = jobsDir2(repoPath);
|
|
324561
|
-
const file =
|
|
324562
|
-
if (!
|
|
325709
|
+
const file = join97(dir, `${jobId}.json`);
|
|
325710
|
+
if (!existsSync80(file)) {
|
|
324563
325711
|
console.error(`Job not found: ${jobId}`);
|
|
324564
325712
|
console.log(`Available jobs: oa jobs`);
|
|
324565
325713
|
process.exit(1);
|
|
324566
325714
|
}
|
|
324567
|
-
const job = JSON.parse(
|
|
325715
|
+
const job = JSON.parse(readFileSync63(file, "utf-8"));
|
|
324568
325716
|
const runtime = job.completedAt ? `${((new Date(job.completedAt).getTime() - new Date(job.startedAt).getTime()) / 1e3).toFixed(0)}s` : `${((Date.now() - new Date(job.startedAt).getTime()) / 1e3).toFixed(0)}s`;
|
|
324569
325717
|
const icon = job.status === "completed" ? "\u2713" : job.status === "failed" ? "\u2717" : "\u25CF";
|
|
324570
325718
|
console.log(`${icon} ${job.id} [${job.status}] ${runtime}`);
|
|
@@ -324577,7 +325725,7 @@ function statusCommand(jobId, repoPath) {
|
|
|
324577
325725
|
}
|
|
324578
325726
|
function jobsCommand(repoPath) {
|
|
324579
325727
|
const dir = jobsDir2(repoPath);
|
|
324580
|
-
const files =
|
|
325728
|
+
const files = readdirSync28(dir).filter((f2) => f2.endsWith(".json")).sort();
|
|
324581
325729
|
if (files.length === 0) {
|
|
324582
325730
|
console.log("No jobs found.");
|
|
324583
325731
|
return;
|
|
@@ -324585,7 +325733,7 @@ function jobsCommand(repoPath) {
|
|
|
324585
325733
|
console.log("Jobs:");
|
|
324586
325734
|
for (const file of files) {
|
|
324587
325735
|
try {
|
|
324588
|
-
const job = JSON.parse(
|
|
325736
|
+
const job = JSON.parse(readFileSync63(join97(dir, file), "utf-8"));
|
|
324589
325737
|
const icon = job.status === "completed" ? "\u2713" : job.status === "failed" ? "\u2717" : "\u25CF";
|
|
324590
325738
|
const runtime = job.completedAt ? `${((new Date(job.completedAt).getTime() - new Date(job.startedAt).getTime()) / 1e3).toFixed(0)}s` : `${((Date.now() - new Date(job.startedAt).getTime()) / 1e3).toFixed(0)}s`;
|
|
324591
325739
|
const cleanListTask = cleanForStorage(job.task) || job.task;
|
|
@@ -324607,7 +325755,7 @@ import { glob as glob2 } from "glob";
|
|
|
324607
325755
|
import ignore from "ignore";
|
|
324608
325756
|
import { readFile as readFile23, stat as stat5 } from "node:fs/promises";
|
|
324609
325757
|
import { createHash as createHash8 } from "node:crypto";
|
|
324610
|
-
import { join as
|
|
325758
|
+
import { join as join98, relative as relative5, extname as extname12, basename as basename18 } from "node:path";
|
|
324611
325759
|
var DEFAULT_EXCLUDE, LANGUAGE_MAP, CodebaseIndexer;
|
|
324612
325760
|
var init_codebase_indexer = __esm({
|
|
324613
325761
|
"packages/indexer/dist/codebase-indexer.js"() {
|
|
@@ -324651,7 +325799,7 @@ var init_codebase_indexer = __esm({
|
|
|
324651
325799
|
const ig = ignore.default();
|
|
324652
325800
|
if (this.config.respectGitignore) {
|
|
324653
325801
|
try {
|
|
324654
|
-
const gitignoreContent = await readFile23(
|
|
325802
|
+
const gitignoreContent = await readFile23(join98(this.config.rootDir, ".gitignore"), "utf-8");
|
|
324655
325803
|
ig.add(gitignoreContent);
|
|
324656
325804
|
} catch {
|
|
324657
325805
|
}
|
|
@@ -324666,7 +325814,7 @@ var init_codebase_indexer = __esm({
|
|
|
324666
325814
|
for (const relativePath of files) {
|
|
324667
325815
|
if (ig.ignores(relativePath))
|
|
324668
325816
|
continue;
|
|
324669
|
-
const fullPath =
|
|
325817
|
+
const fullPath = join98(this.config.rootDir, relativePath);
|
|
324670
325818
|
try {
|
|
324671
325819
|
const fileStat = await stat5(fullPath);
|
|
324672
325820
|
if (fileStat.size > this.config.maxFileSize)
|
|
@@ -324712,7 +325860,7 @@ var init_codebase_indexer = __esm({
|
|
|
324712
325860
|
if (!child) {
|
|
324713
325861
|
child = {
|
|
324714
325862
|
name: part,
|
|
324715
|
-
path:
|
|
325863
|
+
path: join98(current.path, part),
|
|
324716
325864
|
type: "directory",
|
|
324717
325865
|
children: []
|
|
324718
325866
|
};
|
|
@@ -324820,17 +325968,17 @@ __export(index_repo_exports, {
|
|
|
324820
325968
|
indexRepoCommand: () => indexRepoCommand
|
|
324821
325969
|
});
|
|
324822
325970
|
import { resolve as resolve37 } from "node:path";
|
|
324823
|
-
import { existsSync as
|
|
325971
|
+
import { existsSync as existsSync81, statSync as statSync23 } from "node:fs";
|
|
324824
325972
|
import { cwd as cwd2 } from "node:process";
|
|
324825
325973
|
async function indexRepoCommand(opts, _config3) {
|
|
324826
325974
|
const repoRoot = resolve37(opts.repoPath ?? cwd2());
|
|
324827
325975
|
printHeader("Index Repository");
|
|
324828
325976
|
printInfo(`Indexing: ${repoRoot}`);
|
|
324829
|
-
if (!
|
|
325977
|
+
if (!existsSync81(repoRoot)) {
|
|
324830
325978
|
printError(`Path does not exist: ${repoRoot}`);
|
|
324831
325979
|
process.exit(1);
|
|
324832
325980
|
}
|
|
324833
|
-
const stat6 =
|
|
325981
|
+
const stat6 = statSync23(repoRoot);
|
|
324834
325982
|
if (!stat6.isDirectory()) {
|
|
324835
325983
|
printError(`Path is not a directory: ${repoRoot}`);
|
|
324836
325984
|
process.exit(1);
|
|
@@ -325078,8 +326226,8 @@ var config_exports2 = {};
|
|
|
325078
326226
|
__export(config_exports2, {
|
|
325079
326227
|
configCommand: () => configCommand
|
|
325080
326228
|
});
|
|
325081
|
-
import { join as
|
|
325082
|
-
import { homedir as
|
|
326229
|
+
import { join as join99, resolve as resolve38 } from "node:path";
|
|
326230
|
+
import { homedir as homedir33 } from "node:os";
|
|
325083
326231
|
import { cwd as cwd3 } from "node:process";
|
|
325084
326232
|
function redactIfSensitive(key, value2) {
|
|
325085
326233
|
if (SENSITIVE_KEYS.has(key) && typeof value2 === "string" && value2.length > 0) {
|
|
@@ -325160,7 +326308,7 @@ function handleShow(opts, config) {
|
|
|
325160
326308
|
}
|
|
325161
326309
|
}
|
|
325162
326310
|
printSection("Config File");
|
|
325163
|
-
printInfo(`~/.open-agents/config.json (${
|
|
326311
|
+
printInfo(`~/.open-agents/config.json (${join99(homedir33(), ".open-agents", "config.json")})`);
|
|
325164
326312
|
printSection("Priority Chain");
|
|
325165
326313
|
printInfo(" 1. CLI flags (--model, --backend-url, etc.)");
|
|
325166
326314
|
printInfo(" 2. Project .oa/settings.json (--local)");
|
|
@@ -325199,7 +326347,7 @@ function handleSet(opts, _config3) {
|
|
|
325199
326347
|
const coerced = coerceForSettings(key, value2);
|
|
325200
326348
|
saveProjectSettings(repoRoot, { [key]: coerced });
|
|
325201
326349
|
printSuccess(`Project override set: ${key} = ${redactIfSensitive(key, value2)}`);
|
|
325202
|
-
printInfo(`Saved to ${
|
|
326350
|
+
printInfo(`Saved to ${join99(repoRoot, ".oa", "settings.json")}`);
|
|
325203
326351
|
printInfo("This override applies only when running in this workspace.");
|
|
325204
326352
|
} catch (err) {
|
|
325205
326353
|
printError(`Failed to save: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -325383,7 +326531,7 @@ __export(eval_exports, {
|
|
|
325383
326531
|
});
|
|
325384
326532
|
import { tmpdir as tmpdir20 } from "node:os";
|
|
325385
326533
|
import { mkdirSync as mkdirSync49, writeFileSync as writeFileSync43 } from "node:fs";
|
|
325386
|
-
import { join as
|
|
326534
|
+
import { join as join100 } from "node:path";
|
|
325387
326535
|
async function evalCommand(opts, config) {
|
|
325388
326536
|
const suiteName = opts.suite ?? "basic";
|
|
325389
326537
|
const suite = SUITES[suiteName];
|
|
@@ -325512,10 +326660,10 @@ async function evalCommand(opts, config) {
|
|
|
325512
326660
|
process.exit(failed > 0 ? 1 : 0);
|
|
325513
326661
|
}
|
|
325514
326662
|
function createTempEvalRepo() {
|
|
325515
|
-
const dir =
|
|
326663
|
+
const dir = join100(tmpdir20(), `open-agents-eval-${Date.now()}`);
|
|
325516
326664
|
mkdirSync49(dir, { recursive: true });
|
|
325517
326665
|
writeFileSync43(
|
|
325518
|
-
|
|
326666
|
+
join100(dir, "package.json"),
|
|
325519
326667
|
JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n",
|
|
325520
326668
|
"utf8"
|
|
325521
326669
|
);
|
|
@@ -325578,7 +326726,7 @@ init_updater();
|
|
|
325578
326726
|
import { parseArgs as nodeParseArgs2 } from "node:util";
|
|
325579
326727
|
import { createRequire as createRequire6 } from "node:module";
|
|
325580
326728
|
import { fileURLToPath as fileURLToPath18 } from "node:url";
|
|
325581
|
-
import { dirname as dirname28, join as
|
|
326729
|
+
import { dirname as dirname28, join as join101 } from "node:path";
|
|
325582
326730
|
|
|
325583
326731
|
// packages/cli/src/cli.ts
|
|
325584
326732
|
import { createInterface } from "node:readline";
|
|
@@ -325685,7 +326833,7 @@ init_output();
|
|
|
325685
326833
|
function getVersion5() {
|
|
325686
326834
|
try {
|
|
325687
326835
|
const require3 = createRequire6(import.meta.url);
|
|
325688
|
-
const pkgPath =
|
|
326836
|
+
const pkgPath = join101(dirname28(fileURLToPath18(import.meta.url)), "..", "package.json");
|
|
325689
326837
|
const pkg = require3(pkgPath);
|
|
325690
326838
|
return pkg.version;
|
|
325691
326839
|
} catch {
|
|
@@ -325978,11 +327126,11 @@ function crashLog(label, err) {
|
|
|
325978
327126
|
`;
|
|
325979
327127
|
try {
|
|
325980
327128
|
const { appendFileSync: appendFileSync7, mkdirSync: mkdirSync50 } = __require("node:fs");
|
|
325981
|
-
const { join:
|
|
325982
|
-
const { homedir:
|
|
325983
|
-
const logDir =
|
|
327129
|
+
const { join: join102 } = __require("node:path");
|
|
327130
|
+
const { homedir: homedir34 } = __require("node:os");
|
|
327131
|
+
const logDir = join102(homedir34(), ".open-agents");
|
|
325984
327132
|
mkdirSync50(logDir, { recursive: true });
|
|
325985
|
-
appendFileSync7(
|
|
327133
|
+
appendFileSync7(join102(logDir, "crash.log"), logLine);
|
|
325986
327134
|
} catch {
|
|
325987
327135
|
}
|
|
325988
327136
|
try {
|