open-agents-ai 0.187.187 → 0.187.189
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 +1637 -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,169 @@ 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+/.test(line)) continue;
|
|
317720
|
+
if (/^E\s+/.test(line)) continue;
|
|
317721
|
+
if (/^⚠\s*(Task incomplete|Task complete)/.test(line)) continue;
|
|
317722
|
+
if (/^▹\s/.test(line)) continue;
|
|
317723
|
+
if (/^User:\s/.test(line)) continue;
|
|
317724
|
+
if (/^Assistant:\s/.test(line)) continue;
|
|
317725
|
+
if (/^Previous conversation:/.test(line)) continue;
|
|
317726
|
+
if (/^open-agents \(/.test(line)) continue;
|
|
317727
|
+
cleaned.push(line);
|
|
317728
|
+
}
|
|
317729
|
+
return cleaned.join("\n").trim();
|
|
317730
|
+
}
|
|
317731
|
+
async function directChatBackend(opts) {
|
|
317732
|
+
const { model, messages: messages2, stream, res, sessionId, ollamaUrl } = opts;
|
|
317733
|
+
const cfg = loadConfig();
|
|
317734
|
+
const isVllm = cfg.backendType === "vllm";
|
|
317735
|
+
const cleanModel = model.replace(/^[a-z]+\//, "");
|
|
317736
|
+
const headers = { "Content-Type": "application/json" };
|
|
317737
|
+
if (cfg.apiKey) headers["Authorization"] = `Bearer ${cfg.apiKey}`;
|
|
317738
|
+
if (isVllm) {
|
|
317739
|
+
const reqBody = JSON.stringify({ model: cleanModel, messages: messages2, stream });
|
|
317740
|
+
if (stream) {
|
|
317741
|
+
res.writeHead(200, {
|
|
317742
|
+
"Content-Type": "text/event-stream",
|
|
317743
|
+
"Cache-Control": "no-cache",
|
|
317744
|
+
"Connection": "keep-alive",
|
|
317745
|
+
"X-Session-ID": sessionId,
|
|
317746
|
+
"X-API-Version": API_VERSION
|
|
317747
|
+
});
|
|
317748
|
+
let acc = "";
|
|
317749
|
+
const url = new URL("/v1/chat/completions", ollamaUrl);
|
|
317750
|
+
const transport = url.protocol === "https:" ? https3 : http5;
|
|
317751
|
+
await new Promise((resolve39, reject) => {
|
|
317752
|
+
const proxyReq = transport.request({
|
|
317753
|
+
hostname: url.hostname,
|
|
317754
|
+
port: url.port || (url.protocol === "https:" ? 443 : 80),
|
|
317755
|
+
path: url.pathname,
|
|
317756
|
+
method: "POST",
|
|
317757
|
+
headers: { ...headers, "Content-Length": Buffer.byteLength(reqBody) }
|
|
317758
|
+
}, (proxyRes) => {
|
|
317759
|
+
proxyRes.on("data", (chunk) => {
|
|
317760
|
+
const text = chunk.toString();
|
|
317761
|
+
res.write(text);
|
|
317762
|
+
for (const ln of text.split("\n")) {
|
|
317763
|
+
if (!ln.startsWith("data: ")) continue;
|
|
317764
|
+
const payload = ln.slice(6).trim();
|
|
317765
|
+
if (!payload || payload === "[DONE]") continue;
|
|
317766
|
+
try {
|
|
317767
|
+
const j = JSON.parse(payload);
|
|
317768
|
+
const delta = j?.choices?.[0]?.delta?.content;
|
|
317769
|
+
if (delta) acc += delta;
|
|
317770
|
+
} catch {
|
|
317771
|
+
}
|
|
317772
|
+
}
|
|
317773
|
+
});
|
|
317774
|
+
proxyRes.on("end", () => {
|
|
317775
|
+
res.end();
|
|
317776
|
+
resolve39();
|
|
317777
|
+
});
|
|
317778
|
+
proxyRes.on("error", reject);
|
|
317779
|
+
});
|
|
317780
|
+
proxyReq.on("error", reject);
|
|
317781
|
+
proxyReq.setTimeout(12e4, () => proxyReq.destroy(new Error("Backend timeout (120s)")));
|
|
317782
|
+
proxyReq.write(reqBody);
|
|
317783
|
+
proxyReq.end();
|
|
317784
|
+
});
|
|
317785
|
+
return acc.trim();
|
|
317786
|
+
} else {
|
|
317787
|
+
const result = await ollamaRequest(ollamaUrl, "/v1/chat/completions", "POST", reqBody);
|
|
317788
|
+
if (result.status >= 400) throw new Error(`Backend HTTP ${result.status}: ${result.body.slice(0, 200)}`);
|
|
317789
|
+
const j = JSON.parse(result.body);
|
|
317790
|
+
const content = j?.choices?.[0]?.message?.content || "";
|
|
317791
|
+
jsonResponse(res, 200, {
|
|
317792
|
+
session_id: sessionId,
|
|
317793
|
+
model: cleanModel,
|
|
317794
|
+
message: { role: "assistant", content }
|
|
317795
|
+
});
|
|
317796
|
+
return content;
|
|
317797
|
+
}
|
|
317798
|
+
} else {
|
|
317799
|
+
const reqBody = JSON.stringify({
|
|
317800
|
+
model: cleanModel,
|
|
317801
|
+
messages: messages2,
|
|
317802
|
+
stream,
|
|
317803
|
+
think: false,
|
|
317804
|
+
options: {}
|
|
317805
|
+
});
|
|
317806
|
+
if (stream) {
|
|
317807
|
+
res.writeHead(200, {
|
|
317808
|
+
"Content-Type": "text/event-stream",
|
|
317809
|
+
"Cache-Control": "no-cache",
|
|
317810
|
+
"Connection": "keep-alive",
|
|
317811
|
+
"X-Session-ID": sessionId,
|
|
317812
|
+
"X-API-Version": API_VERSION
|
|
317813
|
+
});
|
|
317814
|
+
let acc = "";
|
|
317815
|
+
await new Promise((resolve39, reject) => {
|
|
317816
|
+
ollamaStream(
|
|
317817
|
+
ollamaUrl,
|
|
317818
|
+
"/api/chat",
|
|
317819
|
+
"POST",
|
|
317820
|
+
reqBody,
|
|
317821
|
+
(chunk) => {
|
|
317822
|
+
for (const ln of chunk.split("\n")) {
|
|
317823
|
+
if (!ln.trim()) continue;
|
|
317824
|
+
try {
|
|
317825
|
+
const j = JSON.parse(ln);
|
|
317826
|
+
const delta = j?.message?.content || "";
|
|
317827
|
+
if (delta) {
|
|
317828
|
+
acc += delta;
|
|
317829
|
+
res.write("data: " + JSON.stringify({
|
|
317830
|
+
id: `chatcmpl-${sessionId.slice(0, 8)}`,
|
|
317831
|
+
object: "chat.completion.chunk",
|
|
317832
|
+
choices: [{ index: 0, delta: { content: delta }, finish_reason: null }]
|
|
317833
|
+
}) + "\n\n");
|
|
317834
|
+
}
|
|
317835
|
+
if (j.done) {
|
|
317836
|
+
res.write("data: " + JSON.stringify({
|
|
317837
|
+
id: `chatcmpl-${sessionId.slice(0, 8)}`,
|
|
317838
|
+
object: "chat.completion.chunk",
|
|
317839
|
+
choices: [{ index: 0, delta: {}, finish_reason: "stop" }]
|
|
317840
|
+
}) + "\n\n");
|
|
317841
|
+
res.write("data: [DONE]\n\n");
|
|
317842
|
+
}
|
|
317843
|
+
} catch {
|
|
317844
|
+
}
|
|
317845
|
+
}
|
|
317846
|
+
},
|
|
317847
|
+
() => {
|
|
317848
|
+
res.end();
|
|
317849
|
+
resolve39();
|
|
317850
|
+
},
|
|
317851
|
+
(err) => reject(err)
|
|
317852
|
+
);
|
|
317853
|
+
});
|
|
317854
|
+
return acc.trim();
|
|
317855
|
+
} else {
|
|
317856
|
+
const result = await ollamaRequest(ollamaUrl, "/api/chat", "POST", reqBody);
|
|
317857
|
+
if (result.status >= 400) throw new Error(`Backend HTTP ${result.status}: ${result.body.slice(0, 200)}`);
|
|
317858
|
+
const j = JSON.parse(result.body);
|
|
317859
|
+
const content = j?.message?.content || "";
|
|
317860
|
+
if (!content) throw new Error("Backend returned empty message content");
|
|
317861
|
+
jsonResponse(res, 200, {
|
|
317862
|
+
session_id: sessionId,
|
|
317863
|
+
model: cleanModel,
|
|
317864
|
+
message: { role: "assistant", content },
|
|
317865
|
+
usage: {
|
|
317866
|
+
prompt_tokens: j?.prompt_eval_count,
|
|
317867
|
+
completion_tokens: j?.eval_count,
|
|
317868
|
+
total_duration_ns: j?.total_duration
|
|
317869
|
+
}
|
|
317870
|
+
});
|
|
317871
|
+
return content;
|
|
317872
|
+
}
|
|
317873
|
+
}
|
|
317874
|
+
}
|
|
316895
317875
|
function backendAuthHeaders(endpoint) {
|
|
316896
317876
|
const key = endpoint?.authKey ?? loadConfig().apiKey;
|
|
316897
317877
|
if (key) return { Authorization: `Bearer ${key}` };
|
|
@@ -316961,27 +317941,27 @@ function ollamaStream(ollamaUrl, path5, method, body, onData, onEnd, onError) {
|
|
|
316961
317941
|
}
|
|
316962
317942
|
function jobsDir() {
|
|
316963
317943
|
const root = resolve34(process.cwd());
|
|
316964
|
-
const dir =
|
|
317944
|
+
const dir = join95(root, ".oa", "jobs");
|
|
316965
317945
|
mkdirSync46(dir, { recursive: true });
|
|
316966
317946
|
return dir;
|
|
316967
317947
|
}
|
|
316968
317948
|
function loadJob(id) {
|
|
316969
|
-
const file =
|
|
316970
|
-
if (!
|
|
317949
|
+
const file = join95(jobsDir(), `${id}.json`);
|
|
317950
|
+
if (!existsSync78(file)) return null;
|
|
316971
317951
|
try {
|
|
316972
|
-
return JSON.parse(
|
|
317952
|
+
return JSON.parse(readFileSync61(file, "utf-8"));
|
|
316973
317953
|
} catch {
|
|
316974
317954
|
return null;
|
|
316975
317955
|
}
|
|
316976
317956
|
}
|
|
316977
317957
|
function listJobs() {
|
|
316978
317958
|
const dir = jobsDir();
|
|
316979
|
-
if (!
|
|
316980
|
-
const files =
|
|
317959
|
+
if (!existsSync78(dir)) return [];
|
|
317960
|
+
const files = readdirSync26(dir).filter((f2) => f2.endsWith(".json")).sort();
|
|
316981
317961
|
const jobs = [];
|
|
316982
317962
|
for (const file of files) {
|
|
316983
317963
|
try {
|
|
316984
|
-
jobs.push(JSON.parse(
|
|
317964
|
+
jobs.push(JSON.parse(readFileSync61(join95(dir, file), "utf-8")));
|
|
316985
317965
|
} catch {
|
|
316986
317966
|
}
|
|
316987
317967
|
}
|
|
@@ -317012,12 +317992,47 @@ function checkKeyRateLimit(auth) {
|
|
|
317012
317992
|
}
|
|
317013
317993
|
return null;
|
|
317014
317994
|
}
|
|
317995
|
+
function checkConcurrentJobLimit(auth) {
|
|
317996
|
+
if (!auth.user || !auth.maxJobs) return null;
|
|
317997
|
+
const usage = getKeyUsage(auth.user);
|
|
317998
|
+
if (usage.activeJobs >= auth.maxJobs) {
|
|
317999
|
+
return `Concurrent job limit exceeded for ${auth.user}: ${usage.activeJobs}/${auth.maxJobs}`;
|
|
318000
|
+
}
|
|
318001
|
+
return null;
|
|
318002
|
+
}
|
|
318003
|
+
function incrementActiveJobs(user) {
|
|
318004
|
+
if (!user) return;
|
|
318005
|
+
getKeyUsage(user).activeJobs++;
|
|
318006
|
+
}
|
|
318007
|
+
function decrementActiveJobs(user) {
|
|
318008
|
+
if (!user) return;
|
|
318009
|
+
const usage = getKeyUsage(user);
|
|
318010
|
+
if (usage.activeJobs > 0) usage.activeJobs--;
|
|
318011
|
+
}
|
|
317015
318012
|
function recordKeyUsage(user, tokens) {
|
|
317016
318013
|
if (!user) return;
|
|
317017
318014
|
const usage = getKeyUsage(user);
|
|
317018
318015
|
usage.requestTimestamps.push(Date.now());
|
|
317019
318016
|
usage.tokensToday += tokens;
|
|
317020
318017
|
}
|
|
318018
|
+
function atomicJobWrite(dir, id, job) {
|
|
318019
|
+
const fs4 = __require("node:fs");
|
|
318020
|
+
const finalPath = join95(dir, `${id}.json`);
|
|
318021
|
+
const tmpPath = `${finalPath}.tmp.${process.pid}.${Date.now()}`;
|
|
318022
|
+
try {
|
|
318023
|
+
fs4.writeFileSync(tmpPath, JSON.stringify(job, null, 2), "utf-8");
|
|
318024
|
+
fs4.renameSync(tmpPath, finalPath);
|
|
318025
|
+
} catch {
|
|
318026
|
+
try {
|
|
318027
|
+
fs4.writeFileSync(finalPath, JSON.stringify(job, null, 2), "utf-8");
|
|
318028
|
+
} catch {
|
|
318029
|
+
}
|
|
318030
|
+
try {
|
|
318031
|
+
fs4.unlinkSync(tmpPath);
|
|
318032
|
+
} catch {
|
|
318033
|
+
}
|
|
318034
|
+
}
|
|
318035
|
+
}
|
|
317021
318036
|
function resolveAuth(req2) {
|
|
317022
318037
|
const authHeader = req2.headers["authorization"];
|
|
317023
318038
|
const token = authHeader?.startsWith("Bearer ") ? authHeader.slice(7) : null;
|
|
@@ -317447,7 +318462,23 @@ async function handleV1Run(req2, res) {
|
|
|
317447
318462
|
return;
|
|
317448
318463
|
}
|
|
317449
318464
|
}
|
|
317450
|
-
|
|
318465
|
+
{
|
|
318466
|
+
const auth = resolveAuth(req2);
|
|
318467
|
+
const overLimit = checkConcurrentJobLimit(auth);
|
|
318468
|
+
if (overLimit) {
|
|
318469
|
+
res.setHeader("Content-Type", "application/problem+json; charset=utf-8");
|
|
318470
|
+
res.writeHead(429);
|
|
318471
|
+
res.end(JSON.stringify({
|
|
318472
|
+
type: "https://openagents.nexus/problems/rate-limited",
|
|
318473
|
+
title: "Concurrent job limit exceeded",
|
|
318474
|
+
status: 429,
|
|
318475
|
+
detail: overLimit,
|
|
318476
|
+
instance: req2.headers["x-request-id"] ?? void 0
|
|
318477
|
+
}));
|
|
318478
|
+
return;
|
|
318479
|
+
}
|
|
318480
|
+
}
|
|
318481
|
+
const id = `job-${randomBytes19(8).toString("hex")}`;
|
|
317451
318482
|
const dir = jobsDir();
|
|
317452
318483
|
const workingDir = requestBody["working_directory"] || req2.headers["x-working-directory"];
|
|
317453
318484
|
const isolate = requestBody["isolate"] === true;
|
|
@@ -317455,7 +318486,7 @@ async function handleV1Run(req2, res) {
|
|
|
317455
318486
|
if (workingDir) {
|
|
317456
318487
|
cwd4 = resolve34(workingDir);
|
|
317457
318488
|
} else if (isolate) {
|
|
317458
|
-
const wsDir =
|
|
318489
|
+
const wsDir = join95(dir, "..", "workspaces", id);
|
|
317459
318490
|
mkdirSync46(wsDir, { recursive: true });
|
|
317460
318491
|
cwd4 = wsDir;
|
|
317461
318492
|
} else {
|
|
@@ -317492,15 +318523,16 @@ async function handleV1Run(req2, res) {
|
|
|
317492
318523
|
}
|
|
317493
318524
|
job.profile = profileName || null;
|
|
317494
318525
|
const runCfg = loadConfig();
|
|
317495
|
-
const runEnv = {
|
|
317496
|
-
|
|
317497
|
-
|
|
317498
|
-
|
|
317499
|
-
|
|
317500
|
-
|
|
317501
|
-
|
|
317502
|
-
|
|
317503
|
-
|
|
318526
|
+
const runEnv = {};
|
|
318527
|
+
for (const [k, v] of Object.entries(process.env)) {
|
|
318528
|
+
if (k === "OA_DAEMON" || k === "OA_PORT") continue;
|
|
318529
|
+
if (typeof v === "string") runEnv[k] = v;
|
|
318530
|
+
}
|
|
318531
|
+
runEnv["OA_JOB_ID"] = id;
|
|
318532
|
+
runEnv["__OPEN_AGENTS_NO_AUTO_RUN"] = "";
|
|
318533
|
+
runEnv["OA_RUN_USER"] = authUser;
|
|
318534
|
+
runEnv["OA_RUN_SCOPE"] = authScope;
|
|
318535
|
+
runEnv["OLLAMA_HOST"] = runCfg.backendUrl || process.env["OLLAMA_HOST"] || "http://127.0.0.1:11434";
|
|
317504
318536
|
if (runCfg.apiKey) runEnv["OA_API_KEY_INHERIT"] = runCfg.apiKey;
|
|
317505
318537
|
if (activeProfile) {
|
|
317506
318538
|
runEnv["OA_TOOL_PROFILE"] = JSON.stringify(activeProfile);
|
|
@@ -317540,8 +318572,17 @@ async function handleV1Run(req2, res) {
|
|
|
317540
318572
|
job.sandbox = sandbox;
|
|
317541
318573
|
}
|
|
317542
318574
|
job.pid = child.pid ?? 0;
|
|
317543
|
-
|
|
318575
|
+
atomicJobWrite(dir, id, job);
|
|
317544
318576
|
runningProcesses.set(id, child);
|
|
318577
|
+
incrementActiveJobs(authUser);
|
|
318578
|
+
try {
|
|
318579
|
+
const pubEv = publishEvent;
|
|
318580
|
+
pubEv("run.started", { run_id: id, model: modelArg, pid: job.pid }, {
|
|
318581
|
+
subject: authUser,
|
|
318582
|
+
aimsControl: "A.6.2.6"
|
|
318583
|
+
});
|
|
318584
|
+
} catch {
|
|
318585
|
+
}
|
|
317545
318586
|
if (streamMode) {
|
|
317546
318587
|
res.writeHead(200, {
|
|
317547
318588
|
"Content-Type": "text/event-stream",
|
|
@@ -317566,11 +318607,18 @@ async function handleV1Run(req2, res) {
|
|
|
317566
318607
|
child.on("exit", (code8) => {
|
|
317567
318608
|
job.status = code8 === 0 ? "completed" : "failed";
|
|
317568
318609
|
job.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
318610
|
+
atomicJobWrite(dir, id, job);
|
|
318611
|
+
runningProcesses.delete(id);
|
|
318612
|
+
decrementActiveJobs(authUser);
|
|
317569
318613
|
try {
|
|
317570
|
-
|
|
318614
|
+
const pubEv = publishEvent;
|
|
318615
|
+
pubEv(
|
|
318616
|
+
job.status === "completed" ? "run.completed" : "run.failed",
|
|
318617
|
+
{ run_id: id, exit_code: code8 },
|
|
318618
|
+
{ subject: authUser, aimsControl: "A.6.2.6" }
|
|
318619
|
+
);
|
|
317571
318620
|
} catch {
|
|
317572
318621
|
}
|
|
317573
|
-
runningProcesses.delete(id);
|
|
317574
318622
|
res.write(`data: ${JSON.stringify({ type: "run_completed", run_id: id, exit_code: code8 })}
|
|
317575
318623
|
|
|
317576
318624
|
`);
|
|
@@ -317606,11 +318654,18 @@ async function handleV1Run(req2, res) {
|
|
|
317606
318654
|
job.status = code8 === 0 ? "completed" : "failed";
|
|
317607
318655
|
job.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
317608
318656
|
}
|
|
318657
|
+
atomicJobWrite(dir, id, job);
|
|
318658
|
+
runningProcesses.delete(id);
|
|
318659
|
+
decrementActiveJobs(authUser);
|
|
317609
318660
|
try {
|
|
317610
|
-
|
|
318661
|
+
const pubEv = publishEvent;
|
|
318662
|
+
pubEv(
|
|
318663
|
+
job.status === "completed" ? "run.completed" : "run.failed",
|
|
318664
|
+
{ run_id: id, exit_code: code8, summary: job.summary },
|
|
318665
|
+
{ subject: authUser, aimsControl: "A.6.2.6" }
|
|
318666
|
+
);
|
|
317611
318667
|
} catch {
|
|
317612
318668
|
}
|
|
317613
|
-
runningProcesses.delete(id);
|
|
317614
318669
|
});
|
|
317615
318670
|
jsonResponse(res, 202, { run_id: id, status: "running", pid: job.pid });
|
|
317616
318671
|
}
|
|
@@ -317666,7 +318721,7 @@ function handleV1RunsDelete(res, id) {
|
|
|
317666
318721
|
const containerName = `oa-${id}`;
|
|
317667
318722
|
if (job.sandbox === "container") {
|
|
317668
318723
|
try {
|
|
317669
|
-
|
|
318724
|
+
execSync55(`docker stop ${containerName}`, { timeout: 5e3, stdio: "ignore" });
|
|
317670
318725
|
} catch {
|
|
317671
318726
|
}
|
|
317672
318727
|
}
|
|
@@ -317674,11 +318729,14 @@ function handleV1RunsDelete(res, id) {
|
|
|
317674
318729
|
job.completedAt = (/* @__PURE__ */ new Date()).toISOString();
|
|
317675
318730
|
job.error = "Aborted via API";
|
|
317676
318731
|
const dir = jobsDir();
|
|
318732
|
+
atomicJobWrite(dir, id, job);
|
|
318733
|
+
runningProcesses.delete(id);
|
|
318734
|
+
decrementActiveJobs(job.user);
|
|
317677
318735
|
try {
|
|
317678
|
-
|
|
318736
|
+
const pubEv = publishEvent;
|
|
318737
|
+
pubEv("run.aborted", { run_id: id }, { subject: job.user, aimsControl: "A.6.2.6" });
|
|
317679
318738
|
} catch {
|
|
317680
318739
|
}
|
|
317681
|
-
runningProcesses.delete(id);
|
|
317682
318740
|
}
|
|
317683
318741
|
jsonResponse(res, 200, { run_id: id, status: "aborted" });
|
|
317684
318742
|
}
|
|
@@ -317730,15 +318788,11 @@ async function handlePatchConfig(req2, res) {
|
|
|
317730
318788
|
settingsUpdate.updateMode = updates["updateMode"];
|
|
317731
318789
|
}
|
|
317732
318790
|
saveGlobalSettings(settingsUpdate);
|
|
317733
|
-
|
|
317734
|
-
|
|
317735
|
-
|
|
317736
|
-
|
|
317737
|
-
|
|
317738
|
-
// ISO 42001 — configuration change record
|
|
317739
|
-
});
|
|
317740
|
-
} catch {
|
|
317741
|
-
}
|
|
318791
|
+
publishEvent("config.changed", { keys: Object.keys(settingsUpdate) }, {
|
|
318792
|
+
subject: req2._authUser ?? "anonymous",
|
|
318793
|
+
aimsControl: "A.6.2.8"
|
|
318794
|
+
// ISO 42001 — configuration change record
|
|
318795
|
+
});
|
|
317742
318796
|
const updatedConfig = loadConfig();
|
|
317743
318797
|
jsonResponse(res, 200, {
|
|
317744
318798
|
config: redactSecrets(updatedConfig),
|
|
@@ -317919,7 +318973,7 @@ async function handleRequest(req2, res, ollamaUrl, verbose) {
|
|
|
317919
318973
|
if (pathname === "/v1/files" && method === "GET") {
|
|
317920
318974
|
const dir = urlObj.searchParams.get("path") || process.cwd();
|
|
317921
318975
|
try {
|
|
317922
|
-
const entries =
|
|
318976
|
+
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
318977
|
jsonResponse(res, 200, { path: resolve34(dir), entries });
|
|
317924
318978
|
} catch (e2) {
|
|
317925
318979
|
jsonResponse(res, 400, { error: e2.message });
|
|
@@ -317996,6 +319050,42 @@ async function handleRequest(req2, res, ollamaUrl, verbose) {
|
|
|
317996
319050
|
const session = getSession(sessionId, model, cwdPath);
|
|
317997
319051
|
addUserMessage(session, chatBody.message);
|
|
317998
319052
|
compactSession(session);
|
|
319053
|
+
const wantsTools = chatBody["tools"] !== false && chatBody["use_tools"] !== false;
|
|
319054
|
+
const streamMode = chatBody.stream !== false;
|
|
319055
|
+
if (!wantsTools) {
|
|
319056
|
+
try {
|
|
319057
|
+
const ans = await directChatBackend({
|
|
319058
|
+
model,
|
|
319059
|
+
messages: session.messages.map((m2) => ({ role: m2.role, content: m2.content })),
|
|
319060
|
+
stream: streamMode,
|
|
319061
|
+
res,
|
|
319062
|
+
sessionId: session.id,
|
|
319063
|
+
ollamaUrl
|
|
319064
|
+
});
|
|
319065
|
+
if (ans !== null) {
|
|
319066
|
+
addAssistantMessage(session, ans);
|
|
319067
|
+
}
|
|
319068
|
+
} catch (err) {
|
|
319069
|
+
if (!res.headersSent) {
|
|
319070
|
+
res.setHeader("Content-Type", "application/problem+json; charset=utf-8");
|
|
319071
|
+
res.writeHead(502);
|
|
319072
|
+
res.end(JSON.stringify({
|
|
319073
|
+
type: "https://openagents.nexus/problems/upstream-failure",
|
|
319074
|
+
title: "Backend chat failed",
|
|
319075
|
+
status: 502,
|
|
319076
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
319077
|
+
instance: requestId,
|
|
319078
|
+
"session_id": session.id
|
|
319079
|
+
}));
|
|
319080
|
+
} else {
|
|
319081
|
+
try {
|
|
319082
|
+
res.end();
|
|
319083
|
+
} catch {
|
|
319084
|
+
}
|
|
319085
|
+
}
|
|
319086
|
+
}
|
|
319087
|
+
return;
|
|
319088
|
+
}
|
|
317999
319089
|
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
319090
|
const taskPrompt = (historyLines ? `Previous conversation:
|
|
318001
319091
|
${historyLines}
|
|
@@ -318004,15 +319094,16 @@ ${historyLines}
|
|
|
318004
319094
|
const oaBin = process.argv[1] || "oa";
|
|
318005
319095
|
const args = [taskPrompt, "--json"];
|
|
318006
319096
|
if (model) args.push("--model", model.replace(/^local\//, ""));
|
|
318007
|
-
const streamMode = chatBody.stream !== false;
|
|
318008
319097
|
const currentCfg = loadConfig();
|
|
318009
|
-
const runEnv = {
|
|
318010
|
-
|
|
318011
|
-
|
|
318012
|
-
|
|
318013
|
-
|
|
318014
|
-
|
|
318015
|
-
|
|
319098
|
+
const runEnv = {};
|
|
319099
|
+
for (const [k, v] of Object.entries(process.env)) {
|
|
319100
|
+
if (k === "OA_DAEMON" || k === "OA_PORT") continue;
|
|
319101
|
+
if (typeof v === "string") runEnv[k] = v;
|
|
319102
|
+
}
|
|
319103
|
+
runEnv["__OPEN_AGENTS_NO_AUTO_RUN"] = "";
|
|
319104
|
+
runEnv["OA_RUN_USER"] = req2._authUser || "anonymous";
|
|
319105
|
+
runEnv["OA_RUN_SCOPE"] = req2._authScope || "admin";
|
|
319106
|
+
runEnv["OLLAMA_HOST"] = currentCfg.backendUrl || process.env["OLLAMA_HOST"] || "http://127.0.0.1:11434";
|
|
318016
319107
|
if (currentCfg.apiKey) runEnv["OA_API_KEY_INHERIT"] = currentCfg.apiKey;
|
|
318017
319108
|
const child = spawn25(process.execPath, [oaBin, ...args], {
|
|
318018
319109
|
cwd: cwdPath,
|
|
@@ -318059,44 +319150,54 @@ ${historyLines}
|
|
|
318059
319150
|
child.on("close", () => {
|
|
318060
319151
|
if (lineBuffer.trim()) finalLines.push(lineBuffer);
|
|
318061
319152
|
const rawFinal = finalLines.join("\n").trim();
|
|
319153
|
+
let backendError;
|
|
318062
319154
|
try {
|
|
318063
319155
|
const result = JSON.parse(rawFinal);
|
|
318064
|
-
|
|
319156
|
+
if (result.error) backendError = String(result.error);
|
|
319157
|
+
let content = sanitizeChatContent(result.assistant_text || "");
|
|
318065
319158
|
if (!content) {
|
|
318066
319159
|
const summary = result.summary || "";
|
|
318067
319160
|
const match = summary.match(/Tokens:\s*[\d,]+\s+([\s\S]*)/);
|
|
318068
|
-
content = match ? match[1]
|
|
319161
|
+
content = sanitizeChatContent(match ? match[1] : summary);
|
|
319162
|
+
}
|
|
319163
|
+
if (!content && result.text) {
|
|
319164
|
+
content = sanitizeChatContent(result.text);
|
|
318069
319165
|
}
|
|
318070
319166
|
fullContent = content;
|
|
318071
319167
|
if (content) {
|
|
318072
319168
|
res.write("data: " + JSON.stringify({
|
|
318073
|
-
id: `chatcmpl-${session.id.slice(0,
|
|
319169
|
+
id: `chatcmpl-${session.id.slice(0, 12)}`,
|
|
318074
319170
|
object: "chat.completion.chunk",
|
|
318075
|
-
|
|
319171
|
+
created: Math.floor(Date.now() / 1e3),
|
|
319172
|
+
model: model.replace(/^[a-z]+\//, ""),
|
|
319173
|
+
choices: [{ index: 0, delta: { content }, finish_reason: "stop" }]
|
|
318076
319174
|
}) + "\n\n");
|
|
319175
|
+
} else {
|
|
319176
|
+
const errMsg = backendError ? `Backend error: ${backendError}` : "Agent produced no response. The model may have failed to load.";
|
|
319177
|
+
res.write("data: " + JSON.stringify({
|
|
319178
|
+
id: `chatcmpl-${session.id.slice(0, 12)}`,
|
|
319179
|
+
object: "chat.completion.chunk",
|
|
319180
|
+
created: Math.floor(Date.now() / 1e3),
|
|
319181
|
+
model: model.replace(/^[a-z]+\//, ""),
|
|
319182
|
+
choices: [{ index: 0, delta: { content: errMsg }, finish_reason: "error" }]
|
|
319183
|
+
}) + "\n\n");
|
|
319184
|
+
fullContent = errMsg;
|
|
318077
319185
|
}
|
|
318078
319186
|
if (!toolCallsStreamed && result.tool_calls?.length) {
|
|
318079
319187
|
for (const tc of result.tool_calls) {
|
|
318080
319188
|
res.write("data: " + JSON.stringify({ type: "tool_call", tool: tc.tool, args: tc.args }) + "\n\n");
|
|
318081
319189
|
}
|
|
318082
319190
|
}
|
|
318083
|
-
|
|
319191
|
+
} catch {
|
|
319192
|
+
const errMsg = "Agent subprocess produced no parseable output.";
|
|
319193
|
+
fullContent = errMsg;
|
|
318084
319194
|
res.write("data: " + JSON.stringify({
|
|
318085
|
-
|
|
318086
|
-
|
|
318087
|
-
|
|
318088
|
-
|
|
318089
|
-
|
|
319195
|
+
id: `chatcmpl-${session.id.slice(0, 12)}`,
|
|
319196
|
+
object: "chat.completion.chunk",
|
|
319197
|
+
created: Math.floor(Date.now() / 1e3),
|
|
319198
|
+
model: model.replace(/^[a-z]+\//, ""),
|
|
319199
|
+
choices: [{ index: 0, delta: { content: errMsg }, finish_reason: "error" }]
|
|
318090
319200
|
}) + "\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
319201
|
}
|
|
318101
319202
|
addAssistantMessage(session, fullContent);
|
|
318102
319203
|
res.write("data: [DONE]\n\n");
|
|
@@ -318129,23 +319230,74 @@ ${historyLines}
|
|
|
318129
319230
|
if (nonStreamBuf.trim()) nonStreamLines.push(nonStreamBuf);
|
|
318130
319231
|
const rawNonStream = nonStreamLines.join("\n").trim();
|
|
318131
319232
|
let content = "";
|
|
319233
|
+
let backendError;
|
|
319234
|
+
let durationMs = 0;
|
|
319235
|
+
let toolCallCount = 0;
|
|
319236
|
+
let parsed = null;
|
|
318132
319237
|
try {
|
|
318133
|
-
|
|
318134
|
-
|
|
318135
|
-
|
|
319238
|
+
parsed = JSON.parse(rawNonStream);
|
|
319239
|
+
durationMs = parsed.durationMs || 0;
|
|
319240
|
+
toolCallCount = parsed.tool_calls?.length || 0;
|
|
319241
|
+
if (parsed.error) backendError = String(parsed.error);
|
|
319242
|
+
if (parsed.assistant_text) {
|
|
319243
|
+
content = sanitizeChatContent(parsed.assistant_text);
|
|
318136
319244
|
}
|
|
318137
319245
|
if (!content) {
|
|
318138
|
-
const summary =
|
|
319246
|
+
const summary = parsed.summary || "";
|
|
318139
319247
|
const summaryMatch = summary.match(/Tokens:\s*[\d,]+\s+([\s\S]*)/);
|
|
318140
|
-
content = summaryMatch ? summaryMatch[1]
|
|
319248
|
+
content = sanitizeChatContent(summaryMatch ? summaryMatch[1] : summary);
|
|
319249
|
+
}
|
|
319250
|
+
if (!backendError && parsed.text) {
|
|
319251
|
+
const m2 = String(parsed.text).match(/Backend (?:HTTP \d+|error):\s*[^\n]+/);
|
|
319252
|
+
if (m2) backendError = m2[0];
|
|
318141
319253
|
}
|
|
318142
319254
|
} catch {
|
|
318143
|
-
content =
|
|
319255
|
+
content = "";
|
|
319256
|
+
}
|
|
319257
|
+
const created = Math.floor(Date.now() / 1e3);
|
|
319258
|
+
const id = `chatcmpl-${session.id.slice(0, 12)}`;
|
|
319259
|
+
const cleanModel = model.replace(/^[a-z]+\//, "");
|
|
319260
|
+
if (!content) {
|
|
319261
|
+
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).";
|
|
319262
|
+
jsonResponse(res, 200, {
|
|
319263
|
+
id,
|
|
319264
|
+
object: "chat.completion",
|
|
319265
|
+
created,
|
|
319266
|
+
model: cleanModel,
|
|
319267
|
+
choices: [{
|
|
319268
|
+
index: 0,
|
|
319269
|
+
message: { role: "assistant", content: errMsg },
|
|
319270
|
+
finish_reason: "error"
|
|
319271
|
+
}],
|
|
319272
|
+
usage: { prompt_tokens: 0, completion_tokens: 0, total_tokens: 0 },
|
|
319273
|
+
session_id: session.id,
|
|
319274
|
+
tool_calls: toolCallCount,
|
|
319275
|
+
duration_ms: durationMs,
|
|
319276
|
+
error: backendError ?? null
|
|
319277
|
+
});
|
|
319278
|
+
return;
|
|
318144
319279
|
}
|
|
318145
319280
|
addAssistantMessage(session, content.trim());
|
|
319281
|
+
const promptTokens = Math.round(session.messages.map((m2) => m2.content).join("").length / 4);
|
|
319282
|
+
const completionTokens = Math.round(content.length / 4);
|
|
318146
319283
|
jsonResponse(res, 200, {
|
|
319284
|
+
id,
|
|
319285
|
+
object: "chat.completion",
|
|
319286
|
+
created,
|
|
319287
|
+
model: cleanModel,
|
|
319288
|
+
choices: [{
|
|
319289
|
+
index: 0,
|
|
319290
|
+
message: { role: "assistant", content: content.trim() },
|
|
319291
|
+
finish_reason: "stop"
|
|
319292
|
+
}],
|
|
319293
|
+
usage: {
|
|
319294
|
+
prompt_tokens: promptTokens,
|
|
319295
|
+
completion_tokens: completionTokens,
|
|
319296
|
+
total_tokens: promptTokens + completionTokens
|
|
319297
|
+
},
|
|
318147
319298
|
session_id: session.id,
|
|
318148
|
-
|
|
319299
|
+
tool_calls: toolCallCount,
|
|
319300
|
+
duration_ms: durationMs
|
|
318149
319301
|
});
|
|
318150
319302
|
}
|
|
318151
319303
|
return;
|
|
@@ -318401,19 +319553,19 @@ function startApiServer(options2 = {}) {
|
|
|
318401
319553
|
const config = loadConfig();
|
|
318402
319554
|
const ollamaUrl = options2.ollamaUrl ?? config.backendUrl;
|
|
318403
319555
|
const cwd4 = process.cwd();
|
|
318404
|
-
initAuditLog(
|
|
318405
|
-
initUsageTracker(
|
|
319556
|
+
initAuditLog(join95(cwd4, ".oa"));
|
|
319557
|
+
initUsageTracker(join95(cwd4, ".oa"));
|
|
318406
319558
|
const retentionDays = parseInt(process.env["OA_JOB_RETENTION_DAYS"] ?? "30", 10);
|
|
318407
319559
|
if (retentionDays > 0) {
|
|
318408
319560
|
try {
|
|
318409
|
-
const jobsDir3 =
|
|
318410
|
-
if (
|
|
319561
|
+
const jobsDir3 = join95(cwd4, ".oa", "jobs");
|
|
319562
|
+
if (existsSync78(jobsDir3)) {
|
|
318411
319563
|
const cutoff = Date.now() - retentionDays * 864e5;
|
|
318412
|
-
for (const f2 of
|
|
319564
|
+
for (const f2 of readdirSync26(jobsDir3)) {
|
|
318413
319565
|
if (!f2.endsWith(".json")) continue;
|
|
318414
319566
|
try {
|
|
318415
|
-
const jobPath =
|
|
318416
|
-
const job = JSON.parse(
|
|
319567
|
+
const jobPath = join95(jobsDir3, f2);
|
|
319568
|
+
const job = JSON.parse(readFileSync61(jobPath, "utf-8"));
|
|
318417
319569
|
const jobTime = new Date(job.startedAt ?? job.completedAt ?? 0).getTime();
|
|
318418
319570
|
if (jobTime > 0 && jobTime < cutoff && job.status !== "running") {
|
|
318419
319571
|
const { unlinkSync: unlinkSync19 } = __require("node:fs");
|
|
@@ -318433,8 +319585,8 @@ function startApiServer(options2 = {}) {
|
|
|
318433
319585
|
if (useTls) {
|
|
318434
319586
|
try {
|
|
318435
319587
|
tlsOpts = {
|
|
318436
|
-
cert:
|
|
318437
|
-
key:
|
|
319588
|
+
cert: readFileSync61(resolve34(tlsCert)),
|
|
319589
|
+
key: readFileSync61(resolve34(tlsKey))
|
|
318438
319590
|
};
|
|
318439
319591
|
} catch (e2) {
|
|
318440
319592
|
log22(`
|
|
@@ -318634,13 +319786,13 @@ var init_serve = __esm({
|
|
|
318634
319786
|
|
|
318635
319787
|
// packages/cli/src/tui/interactive.ts
|
|
318636
319788
|
import { cwd } from "node:process";
|
|
318637
|
-
import { resolve as resolve35, join as
|
|
319789
|
+
import { resolve as resolve35, join as join96, dirname as dirname27, extname as extname11 } from "node:path";
|
|
318638
319790
|
import { createRequire as createRequire5 } from "node:module";
|
|
318639
319791
|
import { fileURLToPath as fileURLToPath17 } from "node:url";
|
|
318640
|
-
import { readFileSync as
|
|
318641
|
-
import { existsSync as
|
|
318642
|
-
import { execSync as
|
|
318643
|
-
import { homedir as
|
|
319792
|
+
import { readFileSync as readFileSync62, writeFileSync as writeFileSync41, appendFileSync as appendFileSync6, rmSync as rmSync4, readdirSync as readdirSync27, mkdirSync as mkdirSync47 } from "node:fs";
|
|
319793
|
+
import { existsSync as existsSync79 } from "node:fs";
|
|
319794
|
+
import { execSync as execSync56 } from "node:child_process";
|
|
319795
|
+
import { homedir as homedir32 } from "node:os";
|
|
318644
319796
|
function formatTimeAgo(date) {
|
|
318645
319797
|
const seconds = Math.floor((Date.now() - date.getTime()) / 1e3);
|
|
318646
319798
|
if (seconds < 60) return "just now";
|
|
@@ -318656,12 +319808,12 @@ function getVersion4() {
|
|
|
318656
319808
|
const require3 = createRequire5(import.meta.url);
|
|
318657
319809
|
const thisDir = dirname27(fileURLToPath17(import.meta.url));
|
|
318658
319810
|
const candidates = [
|
|
318659
|
-
|
|
318660
|
-
|
|
318661
|
-
|
|
319811
|
+
join96(thisDir, "..", "package.json"),
|
|
319812
|
+
join96(thisDir, "..", "..", "package.json"),
|
|
319813
|
+
join96(thisDir, "..", "..", "..", "package.json")
|
|
318662
319814
|
];
|
|
318663
319815
|
for (const pkgPath of candidates) {
|
|
318664
|
-
if (
|
|
319816
|
+
if (existsSync79(pkgPath)) {
|
|
318665
319817
|
const pkg = require3(pkgPath);
|
|
318666
319818
|
if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli" || pkg.name === "@open-agents/monorepo") {
|
|
318667
319819
|
return pkg.version ?? "0.0.0";
|
|
@@ -319168,14 +320320,14 @@ Meta-critique: quality ${meta.quality}/5, thorough: ${meta.thorough}`;
|
|
|
319168
320320
|
function gatherMemorySnippets(root) {
|
|
319169
320321
|
const snippets = [];
|
|
319170
320322
|
const dirs = [
|
|
319171
|
-
|
|
319172
|
-
|
|
320323
|
+
join96(root, ".oa", "memory"),
|
|
320324
|
+
join96(root, ".open-agents", "memory")
|
|
319173
320325
|
];
|
|
319174
320326
|
for (const dir of dirs) {
|
|
319175
|
-
if (!
|
|
320327
|
+
if (!existsSync79(dir)) continue;
|
|
319176
320328
|
try {
|
|
319177
|
-
for (const f2 of
|
|
319178
|
-
const data = JSON.parse(
|
|
320329
|
+
for (const f2 of readdirSync27(dir).filter((f3) => f3.endsWith(".json"))) {
|
|
320330
|
+
const data = JSON.parse(readFileSync62(join96(dir, f2), "utf-8"));
|
|
319179
320331
|
for (const val of Object.values(data)) {
|
|
319180
320332
|
const v = typeof val === "object" && val !== null && "value" in val ? String(val.value) : String(val);
|
|
319181
320333
|
if (v.length > 10) snippets.push(v);
|
|
@@ -319329,9 +320481,9 @@ ${metabolismMemories}
|
|
|
319329
320481
|
} catch {
|
|
319330
320482
|
}
|
|
319331
320483
|
try {
|
|
319332
|
-
const archeFile =
|
|
319333
|
-
if (
|
|
319334
|
-
const variants = JSON.parse(
|
|
320484
|
+
const archeFile = join96(repoRoot, ".oa", "arche", "variants.json");
|
|
320485
|
+
if (existsSync79(archeFile)) {
|
|
320486
|
+
const variants = JSON.parse(readFileSync62(archeFile, "utf8"));
|
|
319335
320487
|
if (variants.length > 0) {
|
|
319336
320488
|
let filtered = variants;
|
|
319337
320489
|
if (taskType) {
|
|
@@ -319500,9 +320652,9 @@ RULES:
|
|
|
319500
320652
|
const compactionThreshold = modelTier === "small" ? 12e3 : modelTier === "medium" ? 24e3 : 4e4;
|
|
319501
320653
|
let identityInjection = "";
|
|
319502
320654
|
try {
|
|
319503
|
-
const ikStateFile =
|
|
319504
|
-
if (
|
|
319505
|
-
const selfState = JSON.parse(
|
|
320655
|
+
const ikStateFile = join96(repoRoot, ".oa", "identity", "self-state.json");
|
|
320656
|
+
if (existsSync79(ikStateFile)) {
|
|
320657
|
+
const selfState = JSON.parse(readFileSync62(ikStateFile, "utf8"));
|
|
319506
320658
|
const lines = [
|
|
319507
320659
|
`[Identity State v${selfState.version}]`,
|
|
319508
320660
|
`Self: ${selfState.narrative_summary}`,
|
|
@@ -320230,11 +321382,11 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
|
|
|
320230
321382
|
});
|
|
320231
321383
|
}
|
|
320232
321384
|
try {
|
|
320233
|
-
const ikDir =
|
|
320234
|
-
const ikFile =
|
|
321385
|
+
const ikDir = join96(repoRoot, ".oa", "identity");
|
|
321386
|
+
const ikFile = join96(ikDir, "self-state.json");
|
|
320235
321387
|
let ikState;
|
|
320236
|
-
if (
|
|
320237
|
-
ikState = JSON.parse(
|
|
321388
|
+
if (existsSync79(ikFile)) {
|
|
321389
|
+
ikState = JSON.parse(readFileSync62(ikFile, "utf8"));
|
|
320238
321390
|
} else {
|
|
320239
321391
|
mkdirSync47(ikDir, { recursive: true });
|
|
320240
321392
|
const machineId = Date.now().toString(36) + Math.random().toString(36).slice(2, 8);
|
|
@@ -320311,9 +321463,9 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
|
|
|
320311
321463
|
} else {
|
|
320312
321464
|
renderTaskIncomplete(result.turns, result.toolCalls, result.durationMs, tokens);
|
|
320313
321465
|
try {
|
|
320314
|
-
const ikFile =
|
|
320315
|
-
if (
|
|
320316
|
-
const ikState = JSON.parse(
|
|
321466
|
+
const ikFile = join96(repoRoot, ".oa", "identity", "self-state.json");
|
|
321467
|
+
if (existsSync79(ikFile)) {
|
|
321468
|
+
const ikState = JSON.parse(readFileSync62(ikFile, "utf8"));
|
|
320317
321469
|
if (!ikState.stats) ikState.stats = { queries_served: 0 };
|
|
320318
321470
|
ikState.stats.queries_served = (ikState.stats.queries_served || 0) + 1;
|
|
320319
321471
|
ikState.homeostasis.uncertainty = Math.min(1, ikState.homeostasis.uncertainty + 0.03);
|
|
@@ -320439,10 +321591,10 @@ async function startInteractive(config, repoPath) {
|
|
|
320439
321591
|
process.stdin.pause();
|
|
320440
321592
|
}
|
|
320441
321593
|
try {
|
|
320442
|
-
const oaDir =
|
|
320443
|
-
const nexusPidFile =
|
|
320444
|
-
if (
|
|
320445
|
-
const pid = parseInt(
|
|
321594
|
+
const oaDir = join96(repoRoot, ".oa");
|
|
321595
|
+
const nexusPidFile = join96(oaDir, "nexus", "daemon.pid");
|
|
321596
|
+
if (existsSync79(nexusPidFile)) {
|
|
321597
|
+
const pid = parseInt(readFileSync62(nexusPidFile, "utf8").trim(), 10);
|
|
320446
321598
|
if (pid > 0) {
|
|
320447
321599
|
try {
|
|
320448
321600
|
process.kill(pid, 0);
|
|
@@ -320987,7 +322139,7 @@ ${opts.systemPromptAddition}` : `Working directory: ${repoRoot}`;
|
|
|
320987
322139
|
let p2pGateway = null;
|
|
320988
322140
|
let peerMesh = null;
|
|
320989
322141
|
let inferenceRouter = null;
|
|
320990
|
-
const secretVault = new SecretVault(
|
|
322142
|
+
const secretVault = new SecretVault(join96(repoRoot, ".oa", "vault.enc"));
|
|
320991
322143
|
let adminSessionKey = null;
|
|
320992
322144
|
const callSubAgents = /* @__PURE__ */ new Map();
|
|
320993
322145
|
const streamRenderer = new StreamRenderer();
|
|
@@ -321206,13 +322358,13 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
321206
322358
|
const hits = allCompletions.filter((c7) => c7.toLowerCase().startsWith(lower));
|
|
321207
322359
|
return [hits, line];
|
|
321208
322360
|
}
|
|
321209
|
-
const HISTORY_DIR =
|
|
321210
|
-
const HISTORY_FILE =
|
|
322361
|
+
const HISTORY_DIR = join96(homedir32(), ".open-agents");
|
|
322362
|
+
const HISTORY_FILE = join96(HISTORY_DIR, "repl-history");
|
|
321211
322363
|
const MAX_HISTORY_LINES = 500;
|
|
321212
322364
|
let savedHistory = [];
|
|
321213
322365
|
try {
|
|
321214
|
-
if (
|
|
321215
|
-
const raw =
|
|
322366
|
+
if (existsSync79(HISTORY_FILE)) {
|
|
322367
|
+
const raw = readFileSync62(HISTORY_FILE, "utf8").trim();
|
|
321216
322368
|
if (raw) savedHistory = raw.split("\n").reverse();
|
|
321217
322369
|
}
|
|
321218
322370
|
} catch {
|
|
@@ -321340,7 +322492,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
321340
322492
|
mkdirSync47(HISTORY_DIR, { recursive: true });
|
|
321341
322493
|
appendFileSync6(HISTORY_FILE, line + "\n", "utf8");
|
|
321342
322494
|
if (Math.random() < 0.02) {
|
|
321343
|
-
const all2 =
|
|
322495
|
+
const all2 = readFileSync62(HISTORY_FILE, "utf8").trim().split("\n");
|
|
321344
322496
|
if (all2.length > MAX_HISTORY_LINES) {
|
|
321345
322497
|
writeFileSync41(HISTORY_FILE, all2.slice(-MAX_HISTORY_LINES).join("\n") + "\n", "utf8");
|
|
321346
322498
|
}
|
|
@@ -321516,10 +322668,10 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
321516
322668
|
const { unlinkSync: _rmStale } = await import("node:fs");
|
|
321517
322669
|
const { homedir: _hdir } = await import("node:os");
|
|
321518
322670
|
for (const dp of [
|
|
321519
|
-
|
|
321520
|
-
|
|
322671
|
+
join96(repoRoot, ".oa", "nexus", "nexus-daemon.mjs"),
|
|
322672
|
+
join96(_hdir(), ".open-agents", ".oa", "nexus", "nexus-daemon.mjs")
|
|
321521
322673
|
]) {
|
|
321522
|
-
if (
|
|
322674
|
+
if (existsSync79(dp)) try {
|
|
321523
322675
|
_rmStale(dp);
|
|
321524
322676
|
} catch {
|
|
321525
322677
|
}
|
|
@@ -321530,9 +322682,9 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
321530
322682
|
const autoNexus = new NexusTool(repoRoot);
|
|
321531
322683
|
const _registerNexusDaemon = () => {
|
|
321532
322684
|
try {
|
|
321533
|
-
const nexusPidFile =
|
|
321534
|
-
if (
|
|
321535
|
-
const nPid = parseInt(
|
|
322685
|
+
const nexusPidFile = join96(repoRoot, ".oa", "nexus", "daemon.pid");
|
|
322686
|
+
if (existsSync79(nexusPidFile)) {
|
|
322687
|
+
const nPid = parseInt(readFileSync62(nexusPidFile, "utf8").trim(), 10);
|
|
321536
322688
|
if (nPid > 0 && !registry2.daemons.has("Nexus")) {
|
|
321537
322689
|
registry2.register({ name: "Nexus", pid: nPid, startedAt: Date.now(), status: "running" });
|
|
321538
322690
|
statusBar.ensureMonitorTimer();
|
|
@@ -321579,7 +322731,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
321579
322731
|
} catch {
|
|
321580
322732
|
}
|
|
321581
322733
|
try {
|
|
321582
|
-
const oaDir =
|
|
322734
|
+
const oaDir = join96(repoRoot, ".oa");
|
|
321583
322735
|
const reconnected = await ExposeGateway.checkAndReconnect(oaDir, {
|
|
321584
322736
|
onInfo: (msg) => writeContent(() => renderInfo(msg)),
|
|
321585
322737
|
onError: (msg) => writeContent(() => renderWarning(msg))
|
|
@@ -321611,7 +322763,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
321611
322763
|
} catch {
|
|
321612
322764
|
}
|
|
321613
322765
|
try {
|
|
321614
|
-
const oaDir =
|
|
322766
|
+
const oaDir = join96(repoRoot, ".oa");
|
|
321615
322767
|
const reconnectedP2P = await ExposeP2PGateway.checkAndReconnect(oaDir, new NexusTool(repoRoot), {
|
|
321616
322768
|
onInfo: (msg) => writeContent(() => renderInfo(msg)),
|
|
321617
322769
|
onError: (msg) => writeContent(() => renderWarning(msg))
|
|
@@ -321652,10 +322804,10 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
321652
322804
|
}
|
|
321653
322805
|
try {
|
|
321654
322806
|
const { homedir: _hd, hostname: _hn, userInfo: _ui } = await import("node:os");
|
|
321655
|
-
const globalNamePath =
|
|
322807
|
+
const globalNamePath = join96(_hd(), ".open-agents", "agent-name");
|
|
321656
322808
|
let agName = "";
|
|
321657
322809
|
try {
|
|
321658
|
-
if (
|
|
322810
|
+
if (existsSync79(globalNamePath)) agName = readFileSync62(globalNamePath, "utf8").trim();
|
|
321659
322811
|
} catch {
|
|
321660
322812
|
}
|
|
321661
322813
|
if (!agName) {
|
|
@@ -321684,11 +322836,11 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
321684
322836
|
}
|
|
321685
322837
|
if (!ollamaAlive) {
|
|
321686
322838
|
try {
|
|
321687
|
-
const savedSponsorsPath =
|
|
322839
|
+
const savedSponsorsPath = join96(repoRoot, ".oa", "sponsor", "known-sponsors.json");
|
|
321688
322840
|
let savedSponsors = [];
|
|
321689
322841
|
try {
|
|
321690
|
-
if (
|
|
321691
|
-
savedSponsors = JSON.parse(
|
|
322842
|
+
if (existsSync79(savedSponsorsPath)) {
|
|
322843
|
+
savedSponsors = JSON.parse(readFileSync62(savedSponsorsPath, "utf8"));
|
|
321692
322844
|
const oneHourAgo = Date.now() - 36e5;
|
|
321693
322845
|
savedSponsors = savedSponsors.filter((s2) => (s2.lastVerified || 0) > oneHourAgo);
|
|
321694
322846
|
}
|
|
@@ -322655,7 +323807,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
322655
323807
|
kind,
|
|
322656
323808
|
targetUrl,
|
|
322657
323809
|
authKey,
|
|
322658
|
-
stateDir:
|
|
323810
|
+
stateDir: join96(repoRoot, ".oa"),
|
|
322659
323811
|
passthrough: passthrough ?? false,
|
|
322660
323812
|
loadbalance: loadbalance ?? false,
|
|
322661
323813
|
endpointAuth: passthrough ? currentConfig.apiKey : void 0,
|
|
@@ -322701,7 +323853,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
322701
323853
|
await tunnelGateway.stop();
|
|
322702
323854
|
tunnelGateway = null;
|
|
322703
323855
|
}
|
|
322704
|
-
const newTunnel = new ExposeGateway({ kind, targetUrl, authKey, fullAccess, stateDir:
|
|
323856
|
+
const newTunnel = new ExposeGateway({ kind, targetUrl, authKey, fullAccess, stateDir: join96(repoRoot, ".oa") });
|
|
322705
323857
|
newTunnel.on("stats", (stats) => {
|
|
322706
323858
|
statusBar.setExposeStatus({
|
|
322707
323859
|
status: stats.status,
|
|
@@ -322788,9 +323940,9 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
322788
323940
|
});
|
|
322789
323941
|
if (!result.success) throw new Error(result.error || "Connect failed");
|
|
322790
323942
|
try {
|
|
322791
|
-
const nexusPidFile =
|
|
322792
|
-
if (
|
|
322793
|
-
const pid = parseInt(
|
|
323943
|
+
const nexusPidFile = join96(repoRoot, ".oa", "nexus", "daemon.pid");
|
|
323944
|
+
if (existsSync79(nexusPidFile)) {
|
|
323945
|
+
const pid = parseInt(readFileSync62(nexusPidFile, "utf8").trim(), 10);
|
|
322794
323946
|
if (pid > 0) {
|
|
322795
323947
|
registry2.register({
|
|
322796
323948
|
name: "Nexus",
|
|
@@ -322976,15 +324128,15 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
322976
324128
|
writeContent(() => renderInfo(`Killed ${bgKilled} background task(s).`));
|
|
322977
324129
|
}
|
|
322978
324130
|
try {
|
|
322979
|
-
const nexusDir =
|
|
322980
|
-
const pidFile =
|
|
322981
|
-
if (
|
|
322982
|
-
const pid = parseInt(
|
|
324131
|
+
const nexusDir = join96(repoRoot, OA_DIR, "nexus");
|
|
324132
|
+
const pidFile = join96(nexusDir, "daemon.pid");
|
|
324133
|
+
if (existsSync79(pidFile)) {
|
|
324134
|
+
const pid = parseInt(readFileSync62(pidFile, "utf8").trim(), 10);
|
|
322983
324135
|
if (pid > 0) {
|
|
322984
324136
|
try {
|
|
322985
324137
|
if (process.platform === "win32") {
|
|
322986
324138
|
try {
|
|
322987
|
-
|
|
324139
|
+
execSync56(`taskkill /F /PID ${pid}`, { timeout: 5e3, stdio: "ignore" });
|
|
322988
324140
|
} catch {
|
|
322989
324141
|
}
|
|
322990
324142
|
} else {
|
|
@@ -323001,17 +324153,17 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
323001
324153
|
} catch {
|
|
323002
324154
|
}
|
|
323003
324155
|
try {
|
|
323004
|
-
const voiceDir2 =
|
|
324156
|
+
const voiceDir2 = join96(homedir32(), ".open-agents", "voice");
|
|
323005
324157
|
const voicePidFiles = ["luxtts-daemon.pid", "piper-daemon.pid"];
|
|
323006
324158
|
for (const pf of voicePidFiles) {
|
|
323007
|
-
const pidPath =
|
|
323008
|
-
if (
|
|
324159
|
+
const pidPath = join96(voiceDir2, pf);
|
|
324160
|
+
if (existsSync79(pidPath)) {
|
|
323009
324161
|
try {
|
|
323010
|
-
const pid = parseInt(
|
|
324162
|
+
const pid = parseInt(readFileSync62(pidPath, "utf8").trim(), 10);
|
|
323011
324163
|
if (pid > 0) {
|
|
323012
324164
|
if (process.platform === "win32") {
|
|
323013
324165
|
try {
|
|
323014
|
-
|
|
324166
|
+
execSync56(`taskkill /F /PID ${pid}`, { timeout: 5e3, stdio: "ignore" });
|
|
323015
324167
|
} catch {
|
|
323016
324168
|
}
|
|
323017
324169
|
} else {
|
|
@@ -323028,11 +324180,11 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
323028
324180
|
} catch {
|
|
323029
324181
|
}
|
|
323030
324182
|
try {
|
|
323031
|
-
|
|
324183
|
+
execSync56(process.platform === "win32" ? "timeout /t 1 /nobreak >nul" : "sleep 0.5", { timeout: 3e3, stdio: "ignore" });
|
|
323032
324184
|
} catch {
|
|
323033
324185
|
}
|
|
323034
|
-
const oaPath =
|
|
323035
|
-
if (
|
|
324186
|
+
const oaPath = join96(repoRoot, OA_DIR);
|
|
324187
|
+
if (existsSync79(oaPath)) {
|
|
323036
324188
|
let deleted = false;
|
|
323037
324189
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
323038
324190
|
try {
|
|
@@ -323042,14 +324194,14 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
323042
324194
|
} catch (err) {
|
|
323043
324195
|
if (attempt < 2) {
|
|
323044
324196
|
try {
|
|
323045
|
-
|
|
324197
|
+
execSync56(process.platform === "win32" ? "timeout /t 1 /nobreak >nul" : "sleep 0.3", { timeout: 3e3, stdio: "ignore" });
|
|
323046
324198
|
} catch {
|
|
323047
324199
|
}
|
|
323048
324200
|
} else {
|
|
323049
324201
|
writeContent(() => renderWarning(`Could not fully remove ${OA_DIR}/: ${err instanceof Error ? err.message : String(err)}`));
|
|
323050
324202
|
if (process.platform === "win32") {
|
|
323051
324203
|
try {
|
|
323052
|
-
|
|
324204
|
+
execSync56(`rd /s /q "${oaPath}"`, { timeout: 1e4, stdio: "ignore" });
|
|
323053
324205
|
deleted = true;
|
|
323054
324206
|
} catch {
|
|
323055
324207
|
}
|
|
@@ -323115,19 +324267,19 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
323115
324267
|
try {
|
|
323116
324268
|
const { isPersonaPlexRunning: isPersonaPlexRunning2 } = await Promise.resolve().then(() => (init_personaplex(), personaplex_exports));
|
|
323117
324269
|
if (isPersonaPlexRunning2()) {
|
|
323118
|
-
const ppPidFile =
|
|
323119
|
-
const ppPortFile =
|
|
323120
|
-
if (
|
|
323121
|
-
const ppPid = parseInt(
|
|
323122
|
-
const ppPort =
|
|
324270
|
+
const ppPidFile = join96(homedir32(), ".open-agents", "voice", "personaplex", "daemon.pid");
|
|
324271
|
+
const ppPortFile = join96(homedir32(), ".open-agents", "voice", "personaplex", "daemon.port");
|
|
324272
|
+
if (existsSync79(ppPidFile)) {
|
|
324273
|
+
const ppPid = parseInt(readFileSync62(ppPidFile, "utf8").trim(), 10);
|
|
324274
|
+
const ppPort = existsSync79(ppPortFile) ? parseInt(readFileSync62(ppPortFile, "utf8").trim(), 10) : void 0;
|
|
323123
324275
|
if (ppPid > 0 && !registry2.daemons.has("PersonaPlex")) {
|
|
323124
324276
|
registry2.register({ name: "PersonaPlex", pid: ppPid, port: ppPort, startedAt: Date.now(), status: "running" });
|
|
323125
324277
|
}
|
|
323126
324278
|
}
|
|
323127
324279
|
}
|
|
323128
|
-
const nexusPidFile =
|
|
323129
|
-
if (
|
|
323130
|
-
const nPid = parseInt(
|
|
324280
|
+
const nexusPidFile = join96(repoRoot, ".oa", "nexus", "daemon.pid");
|
|
324281
|
+
if (existsSync79(nexusPidFile)) {
|
|
324282
|
+
const nPid = parseInt(readFileSync62(nexusPidFile, "utf8").trim(), 10);
|
|
323131
324283
|
if (nPid > 0 && !registry2.daemons.has("Nexus")) {
|
|
323132
324284
|
try {
|
|
323133
324285
|
process.kill(nPid, 0);
|
|
@@ -323468,9 +324620,9 @@ Execute this skill now. Follow the behavioral guidance above.`;
|
|
|
323468
324620
|
}
|
|
323469
324621
|
}
|
|
323470
324622
|
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) &&
|
|
324623
|
+
const isImage = isImagePath(cleanPath) && existsSync79(resolve35(repoRoot, cleanPath));
|
|
324624
|
+
const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync79(resolve35(repoRoot, cleanPath));
|
|
324625
|
+
const isMarkdown = !isImage && !isMedia && /\.(md|markdown)$/i.test(cleanPath) && existsSync79(resolve35(repoRoot, cleanPath));
|
|
323474
324626
|
if (activeTask) {
|
|
323475
324627
|
if (activeTask.runner.isPaused) {
|
|
323476
324628
|
activeTask.runner.resume();
|
|
@@ -323479,7 +324631,7 @@ Execute this skill now. Follow the behavioral guidance above.`;
|
|
|
323479
324631
|
if (isImage) {
|
|
323480
324632
|
try {
|
|
323481
324633
|
const imgPath = resolve35(repoRoot, cleanPath);
|
|
323482
|
-
const imgBuffer =
|
|
324634
|
+
const imgBuffer = readFileSync62(imgPath);
|
|
323483
324635
|
const base642 = imgBuffer.toString("base64");
|
|
323484
324636
|
const ext = extname11(cleanPath).toLowerCase();
|
|
323485
324637
|
const mime = ext === ".png" ? "image/png" : ext === ".gif" ? "image/gif" : ext === ".webp" ? "image/webp" : "image/jpeg";
|
|
@@ -323647,7 +324799,7 @@ ${result.text}`;
|
|
|
323647
324799
|
if (isMarkdown && fullInput === input) {
|
|
323648
324800
|
try {
|
|
323649
324801
|
const mdPath = resolve35(repoRoot, cleanPath);
|
|
323650
|
-
const mdContent =
|
|
324802
|
+
const mdContent = readFileSync62(mdPath, "utf8");
|
|
323651
324803
|
const { parseMcpMarkdown: parseMcpMarkdown2 } = await Promise.resolve().then(() => (init_dist4(), dist_exports));
|
|
323652
324804
|
const result = parseMcpMarkdown2(mdContent);
|
|
323653
324805
|
if (result.servers.length > 0) {
|
|
@@ -323736,7 +324888,7 @@ Summarize or analyze this transcription as appropriate.`;
|
|
|
323736
324888
|
|
|
323737
324889
|
NEW TASK: ${fullInput}`;
|
|
323738
324890
|
restoredSessionContext = null;
|
|
323739
|
-
} else if (
|
|
324891
|
+
} else if (existsSync79(join96(repoRoot, ".oa", "context", "session-diary.md"))) {
|
|
323740
324892
|
taskInput = `[Previous sessions exist \u2014 file_read(".oa/context/session-diary.md") to recall]
|
|
323741
324893
|
|
|
323742
324894
|
${fullInput}`;
|
|
@@ -324070,11 +325222,11 @@ async function runWithTUI(task, config, repoPath, callbacks) {
|
|
|
324070
325222
|
const handle2 = startTask(task, config, repoRoot);
|
|
324071
325223
|
await handle2.promise;
|
|
324072
325224
|
try {
|
|
324073
|
-
const ikDir =
|
|
324074
|
-
const ikFile =
|
|
325225
|
+
const ikDir = join96(repoRoot, ".oa", "identity");
|
|
325226
|
+
const ikFile = join96(ikDir, "self-state.json");
|
|
324075
325227
|
let ikState;
|
|
324076
|
-
if (
|
|
324077
|
-
ikState = JSON.parse(
|
|
325228
|
+
if (existsSync79(ikFile)) {
|
|
325229
|
+
ikState = JSON.parse(readFileSync62(ikFile, "utf8"));
|
|
324078
325230
|
} else {
|
|
324079
325231
|
mkdirSync47(ikDir, { recursive: true });
|
|
324080
325232
|
ikState = {
|
|
@@ -324111,11 +325263,11 @@ async function runWithTUI(task, config, repoPath, callbacks) {
|
|
|
324111
325263
|
);
|
|
324112
325264
|
} catch {
|
|
324113
325265
|
try {
|
|
324114
|
-
const archeDir =
|
|
324115
|
-
const archeFile =
|
|
325266
|
+
const archeDir = join96(repoRoot, ".oa", "arche");
|
|
325267
|
+
const archeFile = join96(archeDir, "variants.json");
|
|
324116
325268
|
let variants = [];
|
|
324117
325269
|
try {
|
|
324118
|
-
if (
|
|
325270
|
+
if (existsSync79(archeFile)) variants = JSON.parse(readFileSync62(archeFile, "utf8"));
|
|
324119
325271
|
} catch {
|
|
324120
325272
|
}
|
|
324121
325273
|
variants.push({
|
|
@@ -324135,9 +325287,9 @@ async function runWithTUI(task, config, repoPath, callbacks) {
|
|
|
324135
325287
|
}
|
|
324136
325288
|
}
|
|
324137
325289
|
try {
|
|
324138
|
-
const metaFile =
|
|
324139
|
-
if (
|
|
324140
|
-
const store2 = JSON.parse(
|
|
325290
|
+
const metaFile = join96(repoRoot, ".oa", "memory", "metabolism", "store.json");
|
|
325291
|
+
if (existsSync79(metaFile)) {
|
|
325292
|
+
const store2 = JSON.parse(readFileSync62(metaFile, "utf8"));
|
|
324141
325293
|
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
325294
|
let updated = false;
|
|
324143
325295
|
for (const item of surfaced) {
|
|
@@ -324201,9 +325353,9 @@ Rules:
|
|
|
324201
325353
|
try {
|
|
324202
325354
|
const { initDb: initDb2 } = __require("@open-agents/memory");
|
|
324203
325355
|
const { ProceduralMemoryStore: ProceduralMemoryStore2 } = __require("@open-agents/memory");
|
|
324204
|
-
const dbDir =
|
|
325356
|
+
const dbDir = join96(repoRoot, ".oa", "memory");
|
|
324205
325357
|
mkdirSync47(dbDir, { recursive: true });
|
|
324206
|
-
const db = initDb2(
|
|
325358
|
+
const db = initDb2(join96(dbDir, "structured.db"));
|
|
324207
325359
|
const memStore = new ProceduralMemoryStore2(db);
|
|
324208
325360
|
memStore.createWithEmbedding({
|
|
324209
325361
|
content: content.slice(0, 600),
|
|
@@ -324218,11 +325370,11 @@ Rules:
|
|
|
324218
325370
|
db.close();
|
|
324219
325371
|
} catch {
|
|
324220
325372
|
}
|
|
324221
|
-
const metaDir =
|
|
324222
|
-
const storeFile =
|
|
325373
|
+
const metaDir = join96(repoRoot, ".oa", "memory", "metabolism");
|
|
325374
|
+
const storeFile = join96(metaDir, "store.json");
|
|
324223
325375
|
let store2 = [];
|
|
324224
325376
|
try {
|
|
324225
|
-
if (
|
|
325377
|
+
if (existsSync79(storeFile)) store2 = JSON.parse(readFileSync62(storeFile, "utf8"));
|
|
324226
325378
|
} catch {
|
|
324227
325379
|
}
|
|
324228
325380
|
store2.push({
|
|
@@ -324244,19 +325396,19 @@ Rules:
|
|
|
324244
325396
|
} catch {
|
|
324245
325397
|
}
|
|
324246
325398
|
try {
|
|
324247
|
-
const cohereSettingsFile =
|
|
325399
|
+
const cohereSettingsFile = join96(repoRoot, ".oa", "settings.json");
|
|
324248
325400
|
let cohereActive = false;
|
|
324249
325401
|
try {
|
|
324250
|
-
if (
|
|
324251
|
-
const settings = JSON.parse(
|
|
325402
|
+
if (existsSync79(cohereSettingsFile)) {
|
|
325403
|
+
const settings = JSON.parse(readFileSync62(cohereSettingsFile, "utf8"));
|
|
324252
325404
|
cohereActive = settings.cohere === true;
|
|
324253
325405
|
}
|
|
324254
325406
|
} catch {
|
|
324255
325407
|
}
|
|
324256
325408
|
if (cohereActive) {
|
|
324257
|
-
const metaFile =
|
|
324258
|
-
if (
|
|
324259
|
-
const store2 = JSON.parse(
|
|
325409
|
+
const metaFile = join96(repoRoot, ".oa", "memory", "metabolism", "store.json");
|
|
325410
|
+
if (existsSync79(metaFile)) {
|
|
325411
|
+
const store2 = JSON.parse(readFileSync62(metaFile, "utf8"));
|
|
324260
325412
|
const latest = store2.filter((m2) => m2.sourceTrace === "trajectory-extraction" || m2.sourceTrace === "llm-trajectory-extraction").slice(-1)[0];
|
|
324261
325413
|
if (latest && latest.scores?.confidence >= 0.6) {
|
|
324262
325414
|
try {
|
|
@@ -324281,18 +325433,18 @@ Rules:
|
|
|
324281
325433
|
}
|
|
324282
325434
|
} catch (err) {
|
|
324283
325435
|
try {
|
|
324284
|
-
const ikFile =
|
|
324285
|
-
if (
|
|
324286
|
-
const ikState = JSON.parse(
|
|
325436
|
+
const ikFile = join96(repoRoot, ".oa", "identity", "self-state.json");
|
|
325437
|
+
if (existsSync79(ikFile)) {
|
|
325438
|
+
const ikState = JSON.parse(readFileSync62(ikFile, "utf8"));
|
|
324287
325439
|
ikState.homeostasis.uncertainty = Math.min(1, ikState.homeostasis.uncertainty + 0.1);
|
|
324288
325440
|
ikState.homeostasis.coherence = Math.max(0, ikState.homeostasis.coherence - 0.05);
|
|
324289
325441
|
ikState.session_count = (ikState.session_count || 0) + 1;
|
|
324290
325442
|
ikState.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
324291
325443
|
writeFileSync41(ikFile, JSON.stringify(ikState, null, 2));
|
|
324292
325444
|
}
|
|
324293
|
-
const metaFile =
|
|
324294
|
-
if (
|
|
324295
|
-
const store2 = JSON.parse(
|
|
325445
|
+
const metaFile = join96(repoRoot, ".oa", "memory", "metabolism", "store.json");
|
|
325446
|
+
if (existsSync79(metaFile)) {
|
|
325447
|
+
const store2 = JSON.parse(readFileSync62(metaFile, "utf8"));
|
|
324296
325448
|
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
325449
|
for (const item of surfaced) {
|
|
324298
325450
|
item.accessCount = (item.accessCount || 0) + 1;
|
|
@@ -324303,11 +325455,11 @@ Rules:
|
|
|
324303
325455
|
writeFileSync41(metaFile, JSON.stringify(store2, null, 2));
|
|
324304
325456
|
}
|
|
324305
325457
|
try {
|
|
324306
|
-
const archeDir =
|
|
324307
|
-
const archeFile =
|
|
325458
|
+
const archeDir = join96(repoRoot, ".oa", "arche");
|
|
325459
|
+
const archeFile = join96(archeDir, "variants.json");
|
|
324308
325460
|
let variants = [];
|
|
324309
325461
|
try {
|
|
324310
|
-
if (
|
|
325462
|
+
if (existsSync79(archeFile)) variants = JSON.parse(readFileSync62(archeFile, "utf8"));
|
|
324311
325463
|
} catch {
|
|
324312
325464
|
}
|
|
324313
325465
|
variants.push({
|
|
@@ -324405,12 +325557,12 @@ __export(run_exports, {
|
|
|
324405
325557
|
});
|
|
324406
325558
|
import { resolve as resolve36 } from "node:path";
|
|
324407
325559
|
import { spawn as spawn26 } from "node:child_process";
|
|
324408
|
-
import { mkdirSync as mkdirSync48, writeFileSync as writeFileSync42, readFileSync as
|
|
325560
|
+
import { mkdirSync as mkdirSync48, writeFileSync as writeFileSync42, readFileSync as readFileSync63, readdirSync as readdirSync28, existsSync as existsSync80 } from "node:fs";
|
|
324409
325561
|
import { randomBytes as randomBytes20 } from "node:crypto";
|
|
324410
|
-
import { join as
|
|
325562
|
+
import { join as join97 } from "node:path";
|
|
324411
325563
|
function jobsDir2(repoPath) {
|
|
324412
325564
|
const root = resolve36(repoPath ?? process.cwd());
|
|
324413
|
-
const dir =
|
|
325565
|
+
const dir = join97(root, ".oa", "jobs");
|
|
324414
325566
|
mkdirSync48(dir, { recursive: true });
|
|
324415
325567
|
return dir;
|
|
324416
325568
|
}
|
|
@@ -324526,7 +325678,7 @@ async function runBackground(task, config, opts) {
|
|
|
324526
325678
|
}
|
|
324527
325679
|
});
|
|
324528
325680
|
job.pid = child.pid ?? 0;
|
|
324529
|
-
writeFileSync42(
|
|
325681
|
+
writeFileSync42(join97(dir, `${id}.json`), JSON.stringify(job, null, 2));
|
|
324530
325682
|
let output = "";
|
|
324531
325683
|
child.stdout?.on("data", (chunk) => {
|
|
324532
325684
|
output += chunk.toString();
|
|
@@ -324542,7 +325694,7 @@ async function runBackground(task, config, opts) {
|
|
|
324542
325694
|
job.summary = result.summary;
|
|
324543
325695
|
job.durationMs = result.durationMs;
|
|
324544
325696
|
job.error = result.error;
|
|
324545
|
-
writeFileSync42(
|
|
325697
|
+
writeFileSync42(join97(dir, `${id}.json`), JSON.stringify(job, null, 2));
|
|
324546
325698
|
} catch {
|
|
324547
325699
|
}
|
|
324548
325700
|
});
|
|
@@ -324558,13 +325710,13 @@ async function runBackground(task, config, opts) {
|
|
|
324558
325710
|
}
|
|
324559
325711
|
function statusCommand(jobId, repoPath) {
|
|
324560
325712
|
const dir = jobsDir2(repoPath);
|
|
324561
|
-
const file =
|
|
324562
|
-
if (!
|
|
325713
|
+
const file = join97(dir, `${jobId}.json`);
|
|
325714
|
+
if (!existsSync80(file)) {
|
|
324563
325715
|
console.error(`Job not found: ${jobId}`);
|
|
324564
325716
|
console.log(`Available jobs: oa jobs`);
|
|
324565
325717
|
process.exit(1);
|
|
324566
325718
|
}
|
|
324567
|
-
const job = JSON.parse(
|
|
325719
|
+
const job = JSON.parse(readFileSync63(file, "utf-8"));
|
|
324568
325720
|
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
325721
|
const icon = job.status === "completed" ? "\u2713" : job.status === "failed" ? "\u2717" : "\u25CF";
|
|
324570
325722
|
console.log(`${icon} ${job.id} [${job.status}] ${runtime}`);
|
|
@@ -324577,7 +325729,7 @@ function statusCommand(jobId, repoPath) {
|
|
|
324577
325729
|
}
|
|
324578
325730
|
function jobsCommand(repoPath) {
|
|
324579
325731
|
const dir = jobsDir2(repoPath);
|
|
324580
|
-
const files =
|
|
325732
|
+
const files = readdirSync28(dir).filter((f2) => f2.endsWith(".json")).sort();
|
|
324581
325733
|
if (files.length === 0) {
|
|
324582
325734
|
console.log("No jobs found.");
|
|
324583
325735
|
return;
|
|
@@ -324585,7 +325737,7 @@ function jobsCommand(repoPath) {
|
|
|
324585
325737
|
console.log("Jobs:");
|
|
324586
325738
|
for (const file of files) {
|
|
324587
325739
|
try {
|
|
324588
|
-
const job = JSON.parse(
|
|
325740
|
+
const job = JSON.parse(readFileSync63(join97(dir, file), "utf-8"));
|
|
324589
325741
|
const icon = job.status === "completed" ? "\u2713" : job.status === "failed" ? "\u2717" : "\u25CF";
|
|
324590
325742
|
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
325743
|
const cleanListTask = cleanForStorage(job.task) || job.task;
|
|
@@ -324607,7 +325759,7 @@ import { glob as glob2 } from "glob";
|
|
|
324607
325759
|
import ignore from "ignore";
|
|
324608
325760
|
import { readFile as readFile23, stat as stat5 } from "node:fs/promises";
|
|
324609
325761
|
import { createHash as createHash8 } from "node:crypto";
|
|
324610
|
-
import { join as
|
|
325762
|
+
import { join as join98, relative as relative5, extname as extname12, basename as basename18 } from "node:path";
|
|
324611
325763
|
var DEFAULT_EXCLUDE, LANGUAGE_MAP, CodebaseIndexer;
|
|
324612
325764
|
var init_codebase_indexer = __esm({
|
|
324613
325765
|
"packages/indexer/dist/codebase-indexer.js"() {
|
|
@@ -324651,7 +325803,7 @@ var init_codebase_indexer = __esm({
|
|
|
324651
325803
|
const ig = ignore.default();
|
|
324652
325804
|
if (this.config.respectGitignore) {
|
|
324653
325805
|
try {
|
|
324654
|
-
const gitignoreContent = await readFile23(
|
|
325806
|
+
const gitignoreContent = await readFile23(join98(this.config.rootDir, ".gitignore"), "utf-8");
|
|
324655
325807
|
ig.add(gitignoreContent);
|
|
324656
325808
|
} catch {
|
|
324657
325809
|
}
|
|
@@ -324666,7 +325818,7 @@ var init_codebase_indexer = __esm({
|
|
|
324666
325818
|
for (const relativePath of files) {
|
|
324667
325819
|
if (ig.ignores(relativePath))
|
|
324668
325820
|
continue;
|
|
324669
|
-
const fullPath =
|
|
325821
|
+
const fullPath = join98(this.config.rootDir, relativePath);
|
|
324670
325822
|
try {
|
|
324671
325823
|
const fileStat = await stat5(fullPath);
|
|
324672
325824
|
if (fileStat.size > this.config.maxFileSize)
|
|
@@ -324712,7 +325864,7 @@ var init_codebase_indexer = __esm({
|
|
|
324712
325864
|
if (!child) {
|
|
324713
325865
|
child = {
|
|
324714
325866
|
name: part,
|
|
324715
|
-
path:
|
|
325867
|
+
path: join98(current.path, part),
|
|
324716
325868
|
type: "directory",
|
|
324717
325869
|
children: []
|
|
324718
325870
|
};
|
|
@@ -324820,17 +325972,17 @@ __export(index_repo_exports, {
|
|
|
324820
325972
|
indexRepoCommand: () => indexRepoCommand
|
|
324821
325973
|
});
|
|
324822
325974
|
import { resolve as resolve37 } from "node:path";
|
|
324823
|
-
import { existsSync as
|
|
325975
|
+
import { existsSync as existsSync81, statSync as statSync23 } from "node:fs";
|
|
324824
325976
|
import { cwd as cwd2 } from "node:process";
|
|
324825
325977
|
async function indexRepoCommand(opts, _config3) {
|
|
324826
325978
|
const repoRoot = resolve37(opts.repoPath ?? cwd2());
|
|
324827
325979
|
printHeader("Index Repository");
|
|
324828
325980
|
printInfo(`Indexing: ${repoRoot}`);
|
|
324829
|
-
if (!
|
|
325981
|
+
if (!existsSync81(repoRoot)) {
|
|
324830
325982
|
printError(`Path does not exist: ${repoRoot}`);
|
|
324831
325983
|
process.exit(1);
|
|
324832
325984
|
}
|
|
324833
|
-
const stat6 =
|
|
325985
|
+
const stat6 = statSync23(repoRoot);
|
|
324834
325986
|
if (!stat6.isDirectory()) {
|
|
324835
325987
|
printError(`Path is not a directory: ${repoRoot}`);
|
|
324836
325988
|
process.exit(1);
|
|
@@ -325078,8 +326230,8 @@ var config_exports2 = {};
|
|
|
325078
326230
|
__export(config_exports2, {
|
|
325079
326231
|
configCommand: () => configCommand
|
|
325080
326232
|
});
|
|
325081
|
-
import { join as
|
|
325082
|
-
import { homedir as
|
|
326233
|
+
import { join as join99, resolve as resolve38 } from "node:path";
|
|
326234
|
+
import { homedir as homedir33 } from "node:os";
|
|
325083
326235
|
import { cwd as cwd3 } from "node:process";
|
|
325084
326236
|
function redactIfSensitive(key, value2) {
|
|
325085
326237
|
if (SENSITIVE_KEYS.has(key) && typeof value2 === "string" && value2.length > 0) {
|
|
@@ -325160,7 +326312,7 @@ function handleShow(opts, config) {
|
|
|
325160
326312
|
}
|
|
325161
326313
|
}
|
|
325162
326314
|
printSection("Config File");
|
|
325163
|
-
printInfo(`~/.open-agents/config.json (${
|
|
326315
|
+
printInfo(`~/.open-agents/config.json (${join99(homedir33(), ".open-agents", "config.json")})`);
|
|
325164
326316
|
printSection("Priority Chain");
|
|
325165
326317
|
printInfo(" 1. CLI flags (--model, --backend-url, etc.)");
|
|
325166
326318
|
printInfo(" 2. Project .oa/settings.json (--local)");
|
|
@@ -325199,7 +326351,7 @@ function handleSet(opts, _config3) {
|
|
|
325199
326351
|
const coerced = coerceForSettings(key, value2);
|
|
325200
326352
|
saveProjectSettings(repoRoot, { [key]: coerced });
|
|
325201
326353
|
printSuccess(`Project override set: ${key} = ${redactIfSensitive(key, value2)}`);
|
|
325202
|
-
printInfo(`Saved to ${
|
|
326354
|
+
printInfo(`Saved to ${join99(repoRoot, ".oa", "settings.json")}`);
|
|
325203
326355
|
printInfo("This override applies only when running in this workspace.");
|
|
325204
326356
|
} catch (err) {
|
|
325205
326357
|
printError(`Failed to save: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -325383,7 +326535,7 @@ __export(eval_exports, {
|
|
|
325383
326535
|
});
|
|
325384
326536
|
import { tmpdir as tmpdir20 } from "node:os";
|
|
325385
326537
|
import { mkdirSync as mkdirSync49, writeFileSync as writeFileSync43 } from "node:fs";
|
|
325386
|
-
import { join as
|
|
326538
|
+
import { join as join100 } from "node:path";
|
|
325387
326539
|
async function evalCommand(opts, config) {
|
|
325388
326540
|
const suiteName = opts.suite ?? "basic";
|
|
325389
326541
|
const suite = SUITES[suiteName];
|
|
@@ -325512,10 +326664,10 @@ async function evalCommand(opts, config) {
|
|
|
325512
326664
|
process.exit(failed > 0 ? 1 : 0);
|
|
325513
326665
|
}
|
|
325514
326666
|
function createTempEvalRepo() {
|
|
325515
|
-
const dir =
|
|
326667
|
+
const dir = join100(tmpdir20(), `open-agents-eval-${Date.now()}`);
|
|
325516
326668
|
mkdirSync49(dir, { recursive: true });
|
|
325517
326669
|
writeFileSync43(
|
|
325518
|
-
|
|
326670
|
+
join100(dir, "package.json"),
|
|
325519
326671
|
JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n",
|
|
325520
326672
|
"utf8"
|
|
325521
326673
|
);
|
|
@@ -325578,7 +326730,7 @@ init_updater();
|
|
|
325578
326730
|
import { parseArgs as nodeParseArgs2 } from "node:util";
|
|
325579
326731
|
import { createRequire as createRequire6 } from "node:module";
|
|
325580
326732
|
import { fileURLToPath as fileURLToPath18 } from "node:url";
|
|
325581
|
-
import { dirname as dirname28, join as
|
|
326733
|
+
import { dirname as dirname28, join as join101 } from "node:path";
|
|
325582
326734
|
|
|
325583
326735
|
// packages/cli/src/cli.ts
|
|
325584
326736
|
import { createInterface } from "node:readline";
|
|
@@ -325685,7 +326837,7 @@ init_output();
|
|
|
325685
326837
|
function getVersion5() {
|
|
325686
326838
|
try {
|
|
325687
326839
|
const require3 = createRequire6(import.meta.url);
|
|
325688
|
-
const pkgPath =
|
|
326840
|
+
const pkgPath = join101(dirname28(fileURLToPath18(import.meta.url)), "..", "package.json");
|
|
325689
326841
|
const pkg = require3(pkgPath);
|
|
325690
326842
|
return pkg.version;
|
|
325691
326843
|
} catch {
|
|
@@ -325978,11 +327130,11 @@ function crashLog(label, err) {
|
|
|
325978
327130
|
`;
|
|
325979
327131
|
try {
|
|
325980
327132
|
const { appendFileSync: appendFileSync7, mkdirSync: mkdirSync50 } = __require("node:fs");
|
|
325981
|
-
const { join:
|
|
325982
|
-
const { homedir:
|
|
325983
|
-
const logDir =
|
|
327133
|
+
const { join: join102 } = __require("node:path");
|
|
327134
|
+
const { homedir: homedir34 } = __require("node:os");
|
|
327135
|
+
const logDir = join102(homedir34(), ".open-agents");
|
|
325984
327136
|
mkdirSync50(logDir, { recursive: true });
|
|
325985
|
-
appendFileSync7(
|
|
327137
|
+
appendFileSync7(join102(logDir, "crash.log"), logLine);
|
|
325986
327138
|
} catch {
|
|
325987
327139
|
}
|
|
325988
327140
|
try {
|