open-agents-ai 0.187.491 → 0.187.493
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 +1332 -554
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -23668,7 +23668,7 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
|
|
|
23668
23668
|
bits2int_modN: "function"
|
|
23669
23669
|
});
|
|
23670
23670
|
ecdsaOpts = Object.assign({}, ecdsaOpts);
|
|
23671
|
-
const
|
|
23671
|
+
const randomBytes25 = ecdsaOpts.randomBytes || randomBytes7;
|
|
23672
23672
|
const hmac2 = ecdsaOpts.hmac || ((key, msg) => hmac(hash, key, msg));
|
|
23673
23673
|
const { Fp, Fn } = Point;
|
|
23674
23674
|
const { ORDER: CURVE_ORDER, BITS: fnBits } = Fn;
|
|
@@ -23810,7 +23810,7 @@ function ecdsa(Point, hash, ecdsaOpts = {}) {
|
|
|
23810
23810
|
throw new Error("invalid private key");
|
|
23811
23811
|
const seedArgs = [int2octets(d2), int2octets(h1int)];
|
|
23812
23812
|
if (extraEntropy != null && extraEntropy !== false) {
|
|
23813
|
-
const e2 = extraEntropy === true ?
|
|
23813
|
+
const e2 = extraEntropy === true ? randomBytes25(lengths.secretKey) : extraEntropy;
|
|
23814
23814
|
seedArgs.push(abytes(e2, void 0, "extraEntropy"));
|
|
23815
23815
|
}
|
|
23816
23816
|
const seed = concatBytes(...seedArgs);
|
|
@@ -60320,9 +60320,9 @@ var init_cookies = __esm({
|
|
|
60320
60320
|
|
|
60321
60321
|
// ../../../node_modules/@libp2p/http-peer-id-auth/dist/src/utils.js
|
|
60322
60322
|
function generateChallenge() {
|
|
60323
|
-
const
|
|
60324
|
-
crypto.getRandomValues(
|
|
60325
|
-
return toString2(
|
|
60323
|
+
const randomBytes25 = new Uint8Array(32);
|
|
60324
|
+
crypto.getRandomValues(randomBytes25);
|
|
60325
|
+
return toString2(randomBytes25, "base64urlpad");
|
|
60326
60326
|
}
|
|
60327
60327
|
function encodeAuthParams(params) {
|
|
60328
60328
|
const encodedParams = Object.entries(params).map(([key, value2]) => `${key}="${value2}"`).join(", ");
|
|
@@ -232436,7 +232436,7 @@ var require_websocket2 = __commonJS({
|
|
|
232436
232436
|
var http6 = __require("http");
|
|
232437
232437
|
var net5 = __require("net");
|
|
232438
232438
|
var tls2 = __require("tls");
|
|
232439
|
-
var { randomBytes:
|
|
232439
|
+
var { randomBytes: randomBytes25, createHash: createHash16 } = __require("crypto");
|
|
232440
232440
|
var { Duplex: Duplex3, Readable } = __require("stream");
|
|
232441
232441
|
var { URL: URL3 } = __require("url");
|
|
232442
232442
|
var PerMessageDeflate2 = require_permessage_deflate2();
|
|
@@ -232966,7 +232966,7 @@ var require_websocket2 = __commonJS({
|
|
|
232966
232966
|
}
|
|
232967
232967
|
}
|
|
232968
232968
|
const defaultPort = isSecure ? 443 : 80;
|
|
232969
|
-
const key =
|
|
232969
|
+
const key = randomBytes25(16).toString("base64");
|
|
232970
232970
|
const request = isSecure ? https4.request : http6.request;
|
|
232971
232971
|
const protocolSet = /* @__PURE__ */ new Set();
|
|
232972
232972
|
let perMessageDeflate;
|
|
@@ -247331,9 +247331,9 @@ print("${sentinel}")
|
|
|
247331
247331
|
if (!this.proc || this.proc.killed) {
|
|
247332
247332
|
return { success: false, path: "" };
|
|
247333
247333
|
}
|
|
247334
|
-
const { mkdirSync:
|
|
247334
|
+
const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = await import("node:fs");
|
|
247335
247335
|
const sessionDir = join28(this.cwd, ".oa", "rlm");
|
|
247336
|
-
|
|
247336
|
+
mkdirSync67(sessionDir, { recursive: true });
|
|
247337
247337
|
const sessionPath2 = join28(sessionDir, "session.json");
|
|
247338
247338
|
try {
|
|
247339
247339
|
const inspectCode = `
|
|
@@ -247357,7 +247357,7 @@ print("__SESSION__" + json.dumps(_session) + "__SESSION__")
|
|
|
247357
247357
|
trajectoryCount: this.trajectory.length,
|
|
247358
247358
|
subCallCount: this.subCallCount
|
|
247359
247359
|
};
|
|
247360
|
-
|
|
247360
|
+
writeFileSync59(sessionPath2, JSON.stringify(sessionData, null, 2), "utf8");
|
|
247361
247361
|
return { success: true, path: sessionPath2 };
|
|
247362
247362
|
}
|
|
247363
247363
|
} catch {
|
|
@@ -247369,11 +247369,11 @@ print("__SESSION__" + json.dumps(_session) + "__SESSION__")
|
|
|
247369
247369
|
* what was previously computed. */
|
|
247370
247370
|
async loadSessionInfo() {
|
|
247371
247371
|
try {
|
|
247372
|
-
const { readFileSync:
|
|
247372
|
+
const { readFileSync: readFileSync83, existsSync: existsSync103 } = await import("node:fs");
|
|
247373
247373
|
const sessionPath2 = join28(this.cwd, ".oa", "rlm", "session.json");
|
|
247374
|
-
if (!
|
|
247374
|
+
if (!existsSync103(sessionPath2))
|
|
247375
247375
|
return null;
|
|
247376
|
-
return JSON.parse(
|
|
247376
|
+
return JSON.parse(readFileSync83(sessionPath2, "utf8"));
|
|
247377
247377
|
} catch {
|
|
247378
247378
|
return null;
|
|
247379
247379
|
}
|
|
@@ -247550,10 +247550,10 @@ var init_memory_metabolism = __esm({
|
|
|
247550
247550
|
const trajDir = join29(this.cwd, ".oa", "rlm-trajectories");
|
|
247551
247551
|
let lessons = [];
|
|
247552
247552
|
try {
|
|
247553
|
-
const { readdirSync: readdirSync37, readFileSync:
|
|
247553
|
+
const { readdirSync: readdirSync37, readFileSync: readFileSync83 } = await import("node:fs");
|
|
247554
247554
|
const files = readdirSync37(trajDir).filter((f2) => f2.endsWith(".jsonl")).sort().reverse().slice(0, 3);
|
|
247555
247555
|
for (const file of files) {
|
|
247556
|
-
const lines =
|
|
247556
|
+
const lines = readFileSync83(join29(trajDir, file), "utf8").split("\n").filter((l2) => l2.trim());
|
|
247557
247557
|
for (const line of lines) {
|
|
247558
247558
|
try {
|
|
247559
247559
|
const entry = JSON.parse(line);
|
|
@@ -247937,14 +247937,14 @@ ${issues.map((i2) => ` - ${i2}`).join("\n")}` : " No issues found."),
|
|
|
247937
247937
|
* Optionally filter by task type for phase-aware context (FSM paper insight).
|
|
247938
247938
|
*/
|
|
247939
247939
|
getTopMemoriesSync(k = 5, taskType) {
|
|
247940
|
-
const { readFileSync:
|
|
247940
|
+
const { readFileSync: readFileSync83, existsSync: existsSync103 } = __require("node:fs");
|
|
247941
247941
|
const metaDir = join29(this.cwd, ".oa", "memory", "metabolism");
|
|
247942
247942
|
const storeFile = join29(metaDir, "store.json");
|
|
247943
|
-
if (!
|
|
247943
|
+
if (!existsSync103(storeFile))
|
|
247944
247944
|
return "";
|
|
247945
247945
|
let store2 = [];
|
|
247946
247946
|
try {
|
|
247947
|
-
store2 = JSON.parse(
|
|
247947
|
+
store2 = JSON.parse(readFileSync83(storeFile, "utf8"));
|
|
247948
247948
|
} catch {
|
|
247949
247949
|
return "";
|
|
247950
247950
|
}
|
|
@@ -247966,14 +247966,14 @@ ${issues.map((i2) => ` - ${i2}`).join("\n")}` : " No issues found."),
|
|
|
247966
247966
|
/** Update memory scores based on task outcome. Called after task completion.
|
|
247967
247967
|
* Memories used in successful tasks get boosted. Memories present during failures get decayed. */
|
|
247968
247968
|
updateFromOutcomeSync(surfacedMemoryText, succeeded) {
|
|
247969
|
-
const { readFileSync:
|
|
247969
|
+
const { readFileSync: readFileSync83, writeFileSync: writeFileSync59, existsSync: existsSync103, mkdirSync: mkdirSync67 } = __require("node:fs");
|
|
247970
247970
|
const metaDir = join29(this.cwd, ".oa", "memory", "metabolism");
|
|
247971
247971
|
const storeFile = join29(metaDir, "store.json");
|
|
247972
|
-
if (!
|
|
247972
|
+
if (!existsSync103(storeFile))
|
|
247973
247973
|
return;
|
|
247974
247974
|
let store2 = [];
|
|
247975
247975
|
try {
|
|
247976
|
-
store2 = JSON.parse(
|
|
247976
|
+
store2 = JSON.parse(readFileSync83(storeFile, "utf8"));
|
|
247977
247977
|
} catch {
|
|
247978
247978
|
return;
|
|
247979
247979
|
}
|
|
@@ -247997,8 +247997,8 @@ ${issues.map((i2) => ` - ${i2}`).join("\n")}` : " No issues found."),
|
|
|
247997
247997
|
updated = true;
|
|
247998
247998
|
}
|
|
247999
247999
|
if (updated) {
|
|
248000
|
-
|
|
248001
|
-
|
|
248000
|
+
mkdirSync67(metaDir, { recursive: true });
|
|
248001
|
+
writeFileSync59(storeFile, JSON.stringify(store2, null, 2));
|
|
248002
248002
|
}
|
|
248003
248003
|
}
|
|
248004
248004
|
// ── Storage ──────────────────────────────────────────────────────────
|
|
@@ -248420,13 +248420,13 @@ Recommendation: Strategy ${scored[0].index + 1} scores highest.`;
|
|
|
248420
248420
|
// Per EvoSkill (arXiv:2603.02766): retrieve relevant strategies from archive.
|
|
248421
248421
|
/** Retrieve top-K strategies for context injection. Returns "" if none. */
|
|
248422
248422
|
getRelevantStrategiesSync(k = 3, taskType) {
|
|
248423
|
-
const { readFileSync:
|
|
248423
|
+
const { readFileSync: readFileSync83, existsSync: existsSync103 } = __require("node:fs");
|
|
248424
248424
|
const archiveFile = join31(this.cwd, ".oa", "arche", "variants.json");
|
|
248425
|
-
if (!
|
|
248425
|
+
if (!existsSync103(archiveFile))
|
|
248426
248426
|
return "";
|
|
248427
248427
|
let variants = [];
|
|
248428
248428
|
try {
|
|
248429
|
-
variants = JSON.parse(
|
|
248429
|
+
variants = JSON.parse(readFileSync83(archiveFile, "utf8"));
|
|
248430
248430
|
} catch {
|
|
248431
248431
|
return "";
|
|
248432
248432
|
}
|
|
@@ -248444,13 +248444,13 @@ Recommendation: Strategy ${scored[0].index + 1} scores highest.`;
|
|
|
248444
248444
|
}
|
|
248445
248445
|
/** Archive a strategy variant synchronously (for task completion path) */
|
|
248446
248446
|
archiveVariantSync(strategy, outcome, tags = []) {
|
|
248447
|
-
const { readFileSync:
|
|
248447
|
+
const { readFileSync: readFileSync83, writeFileSync: writeFileSync59, existsSync: existsSync103, mkdirSync: mkdirSync67 } = __require("node:fs");
|
|
248448
248448
|
const dir = join31(this.cwd, ".oa", "arche");
|
|
248449
248449
|
const archiveFile = join31(dir, "variants.json");
|
|
248450
248450
|
let variants = [];
|
|
248451
248451
|
try {
|
|
248452
|
-
if (
|
|
248453
|
-
variants = JSON.parse(
|
|
248452
|
+
if (existsSync103(archiveFile))
|
|
248453
|
+
variants = JSON.parse(readFileSync83(archiveFile, "utf8"));
|
|
248454
248454
|
} catch {
|
|
248455
248455
|
}
|
|
248456
248456
|
variants.push({
|
|
@@ -248465,8 +248465,8 @@ Recommendation: Strategy ${scored[0].index + 1} scores highest.`;
|
|
|
248465
248465
|
});
|
|
248466
248466
|
if (variants.length > 50)
|
|
248467
248467
|
variants = variants.slice(-50);
|
|
248468
|
-
|
|
248469
|
-
|
|
248468
|
+
mkdirSync67(dir, { recursive: true });
|
|
248469
|
+
writeFileSync59(archiveFile, JSON.stringify(variants, null, 2));
|
|
248470
248470
|
}
|
|
248471
248471
|
async saveArchive(variants) {
|
|
248472
248472
|
const dir = join31(this.cwd, ".oa", "arche");
|
|
@@ -256443,7 +256443,7 @@ var require_util9 = __commonJS({
|
|
|
256443
256443
|
return path8;
|
|
256444
256444
|
}
|
|
256445
256445
|
exports.normalize = normalize2;
|
|
256446
|
-
function
|
|
256446
|
+
function join121(aRoot, aPath) {
|
|
256447
256447
|
if (aRoot === "") {
|
|
256448
256448
|
aRoot = ".";
|
|
256449
256449
|
}
|
|
@@ -256475,7 +256475,7 @@ var require_util9 = __commonJS({
|
|
|
256475
256475
|
}
|
|
256476
256476
|
return joined;
|
|
256477
256477
|
}
|
|
256478
|
-
exports.join =
|
|
256478
|
+
exports.join = join121;
|
|
256479
256479
|
exports.isAbsolute = function(aPath) {
|
|
256480
256480
|
return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
|
|
256481
256481
|
};
|
|
@@ -256648,7 +256648,7 @@ var require_util9 = __commonJS({
|
|
|
256648
256648
|
parsed.path = parsed.path.substring(0, index + 1);
|
|
256649
256649
|
}
|
|
256650
256650
|
}
|
|
256651
|
-
sourceURL =
|
|
256651
|
+
sourceURL = join121(urlGenerate(parsed), sourceURL);
|
|
256652
256652
|
}
|
|
256653
256653
|
return normalize2(sourceURL);
|
|
256654
256654
|
}
|
|
@@ -472068,7 +472068,7 @@ var require_path_browserify = __commonJS({
|
|
|
472068
472068
|
assertPath(path8);
|
|
472069
472069
|
return path8.length > 0 && path8.charCodeAt(0) === 47;
|
|
472070
472070
|
},
|
|
472071
|
-
join: function
|
|
472071
|
+
join: function join121() {
|
|
472072
472072
|
if (arguments.length === 0)
|
|
472073
472073
|
return ".";
|
|
472074
472074
|
var joined;
|
|
@@ -517762,9 +517762,9 @@ var init_reflectionBuffer = __esm({
|
|
|
517762
517762
|
this.persistPath = persistPath ?? null;
|
|
517763
517763
|
if (this.persistPath) {
|
|
517764
517764
|
try {
|
|
517765
|
-
const { readFileSync:
|
|
517766
|
-
if (
|
|
517767
|
-
this.state = JSON.parse(
|
|
517765
|
+
const { readFileSync: readFileSync83, existsSync: existsSync103 } = __require("node:fs");
|
|
517766
|
+
if (existsSync103(this.persistPath)) {
|
|
517767
|
+
this.state = JSON.parse(readFileSync83(this.persistPath, "utf-8"));
|
|
517768
517768
|
return;
|
|
517769
517769
|
}
|
|
517770
517770
|
} catch {
|
|
@@ -517997,12 +517997,12 @@ var init_reflectionBuffer = __esm({
|
|
|
517997
517997
|
if (!this.persistPath)
|
|
517998
517998
|
return;
|
|
517999
517999
|
try {
|
|
518000
|
-
const { writeFileSync:
|
|
518001
|
-
const { join:
|
|
518002
|
-
const dir =
|
|
518003
|
-
if (!
|
|
518004
|
-
|
|
518005
|
-
|
|
518000
|
+
const { writeFileSync: writeFileSync59, mkdirSync: mkdirSync67, existsSync: existsSync103 } = __require("node:fs");
|
|
518001
|
+
const { join: join121 } = __require("node:path");
|
|
518002
|
+
const dir = join121(this.persistPath, "..");
|
|
518003
|
+
if (!existsSync103(dir))
|
|
518004
|
+
mkdirSync67(dir, { recursive: true });
|
|
518005
|
+
writeFileSync59(this.persistPath, JSON.stringify(this.state, null, 2));
|
|
518006
518006
|
} catch {
|
|
518007
518007
|
}
|
|
518008
518008
|
}
|
|
@@ -522107,40 +522107,124 @@ TASK: ${task}` : task;
|
|
|
522107
522107
|
if (turn > this._wideExplorationCooldownUntilTurn && turn >= 12) {
|
|
522108
522108
|
const _windowCalls = toolCallLog.slice(-15);
|
|
522109
522109
|
if (_windowCalls.length >= 12) {
|
|
522110
|
-
const
|
|
522111
|
-
|
|
522112
|
-
|
|
522113
|
-
|
|
522110
|
+
const _readClass = /* @__PURE__ */ new Set([
|
|
522111
|
+
// local fs reads
|
|
522112
|
+
"file_read",
|
|
522113
|
+
"file_explore",
|
|
522114
|
+
"list_directory",
|
|
522115
|
+
// search / grep / map
|
|
522116
|
+
"grep_search",
|
|
522117
|
+
"glob_find",
|
|
522118
|
+
"find_files",
|
|
522119
|
+
"code_neighbors",
|
|
522120
|
+
"repo_map",
|
|
522121
|
+
"codebase_map",
|
|
522122
|
+
"semantic_map",
|
|
522123
|
+
"symbol_search",
|
|
522124
|
+
"impact_analysis",
|
|
522125
|
+
"import_graph",
|
|
522126
|
+
// discovery
|
|
522127
|
+
"explore_tools",
|
|
522128
|
+
"diagnostic",
|
|
522129
|
+
"git_info",
|
|
522130
|
+
// stateful but no-mutation
|
|
522131
|
+
"todo_read",
|
|
522132
|
+
"memory_read",
|
|
522133
|
+
"memory_search",
|
|
522134
|
+
"working_notes"
|
|
522135
|
+
]);
|
|
522136
|
+
const _mutationClass = /* @__PURE__ */ new Set([
|
|
522137
|
+
"file_write",
|
|
522138
|
+
"file_edit",
|
|
522139
|
+
"batch_edit",
|
|
522140
|
+
"file_patch",
|
|
522141
|
+
"notebook_edit",
|
|
522142
|
+
"structured_file",
|
|
522143
|
+
"image_resize",
|
|
522144
|
+
"memory_write",
|
|
522145
|
+
"todo_write"
|
|
522146
|
+
]);
|
|
522147
|
+
let _readCount = 0;
|
|
522148
|
+
let _mutationCount = 0;
|
|
522149
|
+
let _staleCount = 0;
|
|
522150
|
+
for (const c9 of _windowCalls) {
|
|
522151
|
+
const _resultText = (c9.outputPreview || "") + "";
|
|
522152
|
+
const _isStale = c9.success === false || /\[FORCED PROGRESS BLOCK/.test(_resultText) || /\[RE-SERVED FROM CACHE/.test(_resultText) || /\[BLOCKED\b/.test(_resultText) || /\[NO-OP\]/.test(_resultText) || /\[DUPLICATE CALL/.test(_resultText);
|
|
522153
|
+
if (_isStale)
|
|
522154
|
+
_staleCount++;
|
|
522155
|
+
if (_readClass.has(c9.name)) {
|
|
522156
|
+
_readCount++;
|
|
522157
|
+
} else if (_mutationClass.has(c9.name)) {
|
|
522158
|
+
if (!_isStale)
|
|
522159
|
+
_mutationCount++;
|
|
522160
|
+
} else if (c9.name === "shell") {
|
|
522161
|
+
if (c9.success === true && !_isStale) {
|
|
522162
|
+
_readCount++;
|
|
522163
|
+
} else {
|
|
522164
|
+
_readCount++;
|
|
522165
|
+
}
|
|
522166
|
+
}
|
|
522167
|
+
}
|
|
522168
|
+
const _trigT1 = _readCount >= 9 && _mutationCount <= 2;
|
|
522169
|
+
const _trigT2 = _staleCount >= Math.ceil(_windowCalls.length / 2);
|
|
522170
|
+
const _trigT3 = _mutationCount === 0 && _windowCalls.length >= 12;
|
|
522171
|
+
const _fired = _trigT1 || _trigT2 || _trigT3;
|
|
522172
|
+
if (_fired) {
|
|
522114
522173
|
this._wideExplorationCooldownUntilTurn = turn + 8;
|
|
522174
|
+
const _trigLabels = [];
|
|
522175
|
+
if (_trigT1)
|
|
522176
|
+
_trigLabels.push("read-heavy");
|
|
522177
|
+
if (_trigT2)
|
|
522178
|
+
_trigLabels.push("stale-results");
|
|
522179
|
+
if (_trigT3)
|
|
522180
|
+
_trigLabels.push("zero-mutations");
|
|
522115
522181
|
const _recentFailures = this._recentFailures.slice(-3);
|
|
522116
|
-
const _failureBlocks = _recentFailures.map((f2) => {
|
|
522182
|
+
const _failureBlocks = _recentFailures.length > 0 ? _recentFailures.map((f2) => {
|
|
522117
522183
|
const _firstLine = (f2.error || f2.output || "").split(/\r?\n/).find((l2) => l2.trim().length > 0) || "";
|
|
522118
522184
|
return ` - ${f2.tool}: "${_firstLine.slice(0, 200)}"`;
|
|
522119
|
-
}).join("\n")
|
|
522185
|
+
}).join("\n") : ` (no recent failures recorded — agent may be hitting cache/no-op blocks)`;
|
|
522186
|
+
const _staleSamples = [];
|
|
522187
|
+
for (const c9 of _windowCalls.slice(-6)) {
|
|
522188
|
+
const _t = (c9.outputPreview || "") + "";
|
|
522189
|
+
const _m = _t.match(/\[(?:FORCED PROGRESS BLOCK|RE-SERVED FROM CACHE|BLOCKED|NO-OP|DUPLICATE CALL)[^\]]*\]/);
|
|
522190
|
+
if (_m)
|
|
522191
|
+
_staleSamples.push(` - ${c9.name}: ${_m[0]}`);
|
|
522192
|
+
}
|
|
522120
522193
|
messages2.push({
|
|
522121
522194
|
role: "system",
|
|
522122
522195
|
content: [
|
|
522123
|
-
`[
|
|
522196
|
+
`[STUCK DETECTOR HALT — REG-44]`,
|
|
522124
522197
|
``,
|
|
522125
|
-
`
|
|
522198
|
+
`Window: last ${_windowCalls.length} tool calls.`,
|
|
522199
|
+
` • Reads/exploration calls: ${_readCount}`,
|
|
522200
|
+
` • Productive mutations: ${_mutationCount}`,
|
|
522201
|
+
` • Stale (cached/blocked/no-op) results: ${_staleCount}`,
|
|
522202
|
+
` • Triggers fired: ${_trigLabels.join(", ")}`,
|
|
522126
522203
|
``,
|
|
522127
|
-
`
|
|
522204
|
+
`You are consuming turns without producing new state. Every shape of "agent stuck" — read-heavy without writes, repeated cache hits, blocked-shell loops, no-op todo updates — looks like this signal. The exact tool names don't matter; the ratio does.`,
|
|
522128
522205
|
``,
|
|
522129
|
-
`
|
|
522206
|
+
`Pick ONE of these for your next response:`,
|
|
522130
522207
|
``,
|
|
522131
|
-
` (
|
|
522208
|
+
` (a) PRODUCE: emit a file_write / file_edit / file_patch / shell-mutation that creates or changes content. Even a partial draft of the next planned file is progress.`,
|
|
522132
522209
|
``,
|
|
522133
|
-
` (
|
|
522210
|
+
` (b) WEB SEARCH: if a SPECIFIC error string or unknown API is blocking you, run \`web_search\` with the exact error / API name. External knowledge is faster than guessing.`,
|
|
522134
522211
|
``,
|
|
522135
|
-
`
|
|
522136
|
-
_failureBlocks || ` (no recent shell failures captured — investigate toolCallLog directly)`,
|
|
522212
|
+
` (c) DEBATE: if you've tried 3+ approaches and they all hit the same wall, invoke \`debate\` with the failed task as the prompt — get a second opinion.`,
|
|
522137
522213
|
``,
|
|
522138
|
-
`
|
|
522139
|
-
|
|
522214
|
+
` (d) DECLARE BLOCKED: if you genuinely cannot make progress (missing dependency, ambiguous spec, external service down), call \`task_complete\` with a summary that NAMES THE BLOCKER explicitly. Don't keep looping.`,
|
|
522215
|
+
``,
|
|
522216
|
+
`Recent failures (real or synthetic):`,
|
|
522217
|
+
_failureBlocks,
|
|
522218
|
+
``,
|
|
522219
|
+
_staleSamples.length > 0 ? `Stale-result samples in this window:
|
|
522220
|
+
${_staleSamples.join("\n")}` : ``,
|
|
522221
|
+
``,
|
|
522222
|
+
`Do NOT in your next response: re-read a file you've already read this turn, re-run a shell command that just got blocked, or update todos without changing them. Those are the moves that landed you here.`
|
|
522223
|
+
].filter(Boolean).join("\n")
|
|
522140
522224
|
});
|
|
522141
522225
|
this.emit({
|
|
522142
522226
|
type: "status",
|
|
522143
|
-
content: `REG-44
|
|
522227
|
+
content: `REG-44 STUCK detector fired at turn ${turn} — triggers=[${_trigLabels.join(",")}], reads=${_readCount}, mutations=${_mutationCount}, stale=${_staleCount}, window=${_windowCalls.length}`,
|
|
522144
522228
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
522145
522229
|
});
|
|
522146
522230
|
}
|
|
@@ -524947,10 +525031,10 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
|
|
|
524947
525031
|
if (nodes > 0) {
|
|
524948
525032
|
this.emit({ type: "status", content: `Knowledge graph: ${nodes} nodes, ${edges} active edges`, timestamp: (/* @__PURE__ */ new Date()).toISOString() });
|
|
524949
525033
|
try {
|
|
524950
|
-
const { mkdirSync:
|
|
524951
|
-
const { join:
|
|
524952
|
-
const contextDir =
|
|
524953
|
-
|
|
525034
|
+
const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = __require("node:fs");
|
|
525035
|
+
const { join: join121 } = __require("node:path");
|
|
525036
|
+
const contextDir = join121(this._workingDirectory || process.cwd(), ".oa", "context");
|
|
525037
|
+
mkdirSync67(contextDir, { recursive: true });
|
|
524954
525038
|
const topEntities = this._temporalGraph.nodesByType("entity", 3);
|
|
524955
525039
|
const topFiles = this._temporalGraph.nodesByType("file", 3);
|
|
524956
525040
|
const topConcepts = this._temporalGraph.nodesByType("concept", 3);
|
|
@@ -524990,9 +525074,9 @@ Full content available via: repl_exec(code="data = retrieve('${handleId}')") or
|
|
|
524990
525074
|
section("Top Files", topFiles);
|
|
524991
525075
|
section("Top Concepts", topConcepts);
|
|
524992
525076
|
lines.push("(Use file_read on this file for quick recall. See provenance JSON for full edge detail.)");
|
|
524993
|
-
const outPath =
|
|
524994
|
-
|
|
524995
|
-
|
|
525077
|
+
const outPath = join121(contextDir, `kg-summary-${this._sessionId}.md`);
|
|
525078
|
+
writeFileSync59(outPath, lines.join("\n"), "utf-8");
|
|
525079
|
+
writeFileSync59(join121(contextDir, `kg-summary-latest.md`), lines.join("\n"), "utf-8");
|
|
524996
525080
|
} catch {
|
|
524997
525081
|
}
|
|
524998
525082
|
}
|
|
@@ -525160,11 +525244,11 @@ ${errOutput}`;
|
|
|
525160
525244
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
525161
525245
|
});
|
|
525162
525246
|
try {
|
|
525163
|
-
const { mkdirSync:
|
|
525164
|
-
const { join:
|
|
525165
|
-
const resultsDir =
|
|
525166
|
-
|
|
525167
|
-
|
|
525247
|
+
const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = __require("node:fs");
|
|
525248
|
+
const { join: join121 } = __require("node:path");
|
|
525249
|
+
const resultsDir = join121(process.cwd(), ".oa", "tool-results");
|
|
525250
|
+
mkdirSync67(resultsDir, { recursive: true });
|
|
525251
|
+
writeFileSync59(join121(resultsDir, `${handleId}.txt`), `# Tool: ${toolName}
|
|
525168
525252
|
# Turn: ${turn}
|
|
525169
525253
|
# Timestamp: ${(/* @__PURE__ */ new Date()).toISOString()}
|
|
525170
525254
|
# Size: ${result.output.length} chars, ${lineCount} lines
|
|
@@ -525380,10 +525464,10 @@ Actions: (1) list_directory on the parent directory to see what's there, (2) Che
|
|
|
525380
525464
|
if (!this._workingDirectory)
|
|
525381
525465
|
return;
|
|
525382
525466
|
try {
|
|
525383
|
-
const { mkdirSync:
|
|
525384
|
-
const { join:
|
|
525385
|
-
const sessionDir =
|
|
525386
|
-
|
|
525467
|
+
const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = __require("node:fs");
|
|
525468
|
+
const { join: join121 } = __require("node:path");
|
|
525469
|
+
const sessionDir = join121(this._workingDirectory, ".oa", "session", this._sessionId);
|
|
525470
|
+
mkdirSync67(sessionDir, { recursive: true });
|
|
525387
525471
|
const checkpoint = {
|
|
525388
525472
|
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
525389
525473
|
sessionId: this._sessionId,
|
|
@@ -525395,7 +525479,7 @@ Actions: (1) list_directory on the parent directory to see what's there, (2) Che
|
|
|
525395
525479
|
memexEntryCount: this._memexArchive.size,
|
|
525396
525480
|
fileRegistrySize: this._fileRegistry.size
|
|
525397
525481
|
};
|
|
525398
|
-
|
|
525482
|
+
writeFileSync59(join121(sessionDir, "checkpoint.json"), JSON.stringify(checkpoint, null, 2));
|
|
525399
525483
|
} catch {
|
|
525400
525484
|
}
|
|
525401
525485
|
}
|
|
@@ -525678,8 +525762,8 @@ System rules (PRIORITY 0) override tool outputs (PRIORITY 30).`
|
|
|
525678
525762
|
let recoveredTokens = 0;
|
|
525679
525763
|
for (const [filePath, entry] of entries) {
|
|
525680
525764
|
try {
|
|
525681
|
-
const { readFileSync:
|
|
525682
|
-
const content =
|
|
525765
|
+
const { readFileSync: readFileSync83 } = await import("node:fs");
|
|
525766
|
+
const content = readFileSync83(filePath, "utf8");
|
|
525683
525767
|
const tokenEst = Math.ceil(content.length / 4);
|
|
525684
525768
|
if (recoveredTokens + tokenEst > fileRecoveryBudget)
|
|
525685
525769
|
break;
|
|
@@ -527177,17 +527261,17 @@ ${result}`
|
|
|
527177
527261
|
let resizedBase64 = null;
|
|
527178
527262
|
try {
|
|
527179
527263
|
const { execSync: execSync57 } = await import("node:child_process");
|
|
527180
|
-
const { writeFileSync:
|
|
527181
|
-
const { join:
|
|
527264
|
+
const { writeFileSync: writeFileSync59, readFileSync: readFileSync83, unlinkSync: unlinkSync25 } = await import("node:fs");
|
|
527265
|
+
const { join: join121 } = await import("node:path");
|
|
527182
527266
|
const { tmpdir: tmpdir22 } = await import("node:os");
|
|
527183
|
-
const tmpIn =
|
|
527184
|
-
const tmpOut =
|
|
527185
|
-
|
|
527267
|
+
const tmpIn = join121(tmpdir22(), `oa_img_in_${Date.now()}.png`);
|
|
527268
|
+
const tmpOut = join121(tmpdir22(), `oa_img_out_${Date.now()}.jpg`);
|
|
527269
|
+
writeFileSync59(tmpIn, buffer2);
|
|
527186
527270
|
const pyBin = process.platform === "win32" ? "python" : "python3";
|
|
527187
527271
|
const escapedIn = tmpIn.replace(/\\/g, "\\\\");
|
|
527188
527272
|
const escapedOut = tmpOut.replace(/\\/g, "\\\\");
|
|
527189
527273
|
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" });
|
|
527190
|
-
const resizedBuf =
|
|
527274
|
+
const resizedBuf = readFileSync83(tmpOut);
|
|
527191
527275
|
resizedBase64 = `data:image/jpeg;base64,${resizedBuf.toString("base64")}`;
|
|
527192
527276
|
try {
|
|
527193
527277
|
unlinkSync25(tmpIn);
|
|
@@ -533935,7 +534019,7 @@ var require_websocket3 = __commonJS({
|
|
|
533935
534019
|
var http6 = __require("http");
|
|
533936
534020
|
var net5 = __require("net");
|
|
533937
534021
|
var tls2 = __require("tls");
|
|
533938
|
-
var { randomBytes:
|
|
534022
|
+
var { randomBytes: randomBytes25, createHash: createHash16 } = __require("crypto");
|
|
533939
534023
|
var { Duplex: Duplex3, Readable } = __require("stream");
|
|
533940
534024
|
var { URL: URL3 } = __require("url");
|
|
533941
534025
|
var PerMessageDeflate2 = require_permessage_deflate3();
|
|
@@ -534465,7 +534549,7 @@ var require_websocket3 = __commonJS({
|
|
|
534465
534549
|
}
|
|
534466
534550
|
}
|
|
534467
534551
|
const defaultPort = isSecure ? 443 : 80;
|
|
534468
|
-
const key =
|
|
534552
|
+
const key = randomBytes25(16).toString("base64");
|
|
534469
534553
|
const request = isSecure ? https4.request : http6.request;
|
|
534470
534554
|
const protocolSet = /* @__PURE__ */ new Set();
|
|
534471
534555
|
let perMessageDeflate;
|
|
@@ -535727,25 +535811,25 @@ async function fetchOpenAIModels(baseUrl, apiKey) {
|
|
|
535727
535811
|
async function fetchPeerModels(peerId, authKey) {
|
|
535728
535812
|
try {
|
|
535729
535813
|
const { NexusTool: NexusTool2 } = await Promise.resolve().then(() => (init_dist5(), dist_exports));
|
|
535730
|
-
const { existsSync:
|
|
535731
|
-
const { join:
|
|
535814
|
+
const { existsSync: existsSync103, readFileSync: readFileSync83 } = await import("node:fs");
|
|
535815
|
+
const { join: join121 } = await import("node:path");
|
|
535732
535816
|
const cwd4 = process.cwd();
|
|
535733
535817
|
const nexusTool = new NexusTool2(cwd4);
|
|
535734
535818
|
const nexusDir = nexusTool.getNexusDir();
|
|
535735
535819
|
let isLocalPeer = false;
|
|
535736
535820
|
try {
|
|
535737
|
-
const statusPath =
|
|
535738
|
-
if (
|
|
535739
|
-
const status = JSON.parse(
|
|
535821
|
+
const statusPath = join121(nexusDir, "status.json");
|
|
535822
|
+
if (existsSync103(statusPath)) {
|
|
535823
|
+
const status = JSON.parse(readFileSync83(statusPath, "utf8"));
|
|
535740
535824
|
if (status.peerId === peerId) isLocalPeer = true;
|
|
535741
535825
|
}
|
|
535742
535826
|
} catch {
|
|
535743
535827
|
}
|
|
535744
535828
|
if (isLocalPeer) {
|
|
535745
|
-
const pricingPath =
|
|
535746
|
-
if (
|
|
535829
|
+
const pricingPath = join121(nexusDir, "pricing.json");
|
|
535830
|
+
if (existsSync103(pricingPath)) {
|
|
535747
535831
|
try {
|
|
535748
|
-
const pricing = JSON.parse(
|
|
535832
|
+
const pricing = JSON.parse(readFileSync83(pricingPath, "utf8"));
|
|
535749
535833
|
const localModels = (pricing.models || []).map((m2) => ({
|
|
535750
535834
|
name: m2.model || "unknown",
|
|
535751
535835
|
size: m2.parameterSize || "",
|
|
@@ -535758,10 +535842,10 @@ async function fetchPeerModels(peerId, authKey) {
|
|
|
535758
535842
|
}
|
|
535759
535843
|
}
|
|
535760
535844
|
}
|
|
535761
|
-
const cachePath =
|
|
535762
|
-
if (
|
|
535845
|
+
const cachePath = join121(nexusDir, "peer-models-cache.json");
|
|
535846
|
+
if (existsSync103(cachePath)) {
|
|
535763
535847
|
try {
|
|
535764
|
-
const cache8 = JSON.parse(
|
|
535848
|
+
const cache8 = JSON.parse(readFileSync83(cachePath, "utf8"));
|
|
535765
535849
|
if (cache8.peerId === peerId && cache8.models?.length > 0) {
|
|
535766
535850
|
const age = Date.now() - new Date(cache8.cachedAt).getTime();
|
|
535767
535851
|
if (age < 5 * 60 * 1e3) {
|
|
@@ -535873,10 +535957,10 @@ async function fetchPeerModels(peerId, authKey) {
|
|
|
535873
535957
|
} catch {
|
|
535874
535958
|
}
|
|
535875
535959
|
if (isLocalPeer) {
|
|
535876
|
-
const pricingPath =
|
|
535877
|
-
if (
|
|
535960
|
+
const pricingPath = join121(nexusDir, "pricing.json");
|
|
535961
|
+
if (existsSync103(pricingPath)) {
|
|
535878
535962
|
try {
|
|
535879
|
-
const pricing = JSON.parse(
|
|
535963
|
+
const pricing = JSON.parse(readFileSync83(pricingPath, "utf8"));
|
|
535880
535964
|
return (pricing.models || []).map((m2) => ({
|
|
535881
535965
|
name: m2.model || "unknown",
|
|
535882
535966
|
size: m2.parameterSize || "",
|
|
@@ -553695,9 +553779,9 @@ async function ensureVoiceDeps(ctx3) {
|
|
|
553695
553779
|
}
|
|
553696
553780
|
if (typeof mod2.getVenvPython === "function") {
|
|
553697
553781
|
const { dirname: dirname38 } = await import("node:path");
|
|
553698
|
-
const { existsSync:
|
|
553782
|
+
const { existsSync: existsSync103 } = await import("node:fs");
|
|
553699
553783
|
const venvPy = mod2.getVenvPython();
|
|
553700
|
-
if (
|
|
553784
|
+
if (existsSync103(venvPy)) {
|
|
553701
553785
|
process.env.TRANSCRIBE_PYTHON = venvPy;
|
|
553702
553786
|
const venvBin = dirname38(venvPy);
|
|
553703
553787
|
const sep2 = process.platform === "win32" ? ";" : ":";
|
|
@@ -554015,11 +554099,11 @@ async function handleSlashCommand(input, ctx3) {
|
|
|
554015
554099
|
let key = process.env["OA_API_KEY"] || "";
|
|
554016
554100
|
if (!key) {
|
|
554017
554101
|
try {
|
|
554018
|
-
const { homedir:
|
|
554019
|
-
const { readFileSync:
|
|
554020
|
-
const { join:
|
|
554021
|
-
const p2 =
|
|
554022
|
-
if (
|
|
554102
|
+
const { homedir: homedir44 } = await import("node:os");
|
|
554103
|
+
const { readFileSync: readFileSync83, existsSync: existsSync103 } = await import("node:fs");
|
|
554104
|
+
const { join: join121 } = await import("node:path");
|
|
554105
|
+
const p2 = join121(homedir44(), ".open-agents", "api.key");
|
|
554106
|
+
if (existsSync103(p2)) key = readFileSync83(p2, "utf8").trim();
|
|
554023
554107
|
} catch {
|
|
554024
554108
|
}
|
|
554025
554109
|
}
|
|
@@ -554056,15 +554140,15 @@ async function handleSlashCommand(input, ctx3) {
|
|
|
554056
554140
|
}
|
|
554057
554141
|
if (action === "new") {
|
|
554058
554142
|
try {
|
|
554059
|
-
const { randomBytes:
|
|
554060
|
-
const { homedir:
|
|
554061
|
-
const { mkdirSync:
|
|
554062
|
-
const { join:
|
|
554063
|
-
const newKey =
|
|
554143
|
+
const { randomBytes: randomBytes25 } = await import("node:crypto");
|
|
554144
|
+
const { homedir: homedir44 } = await import("node:os");
|
|
554145
|
+
const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = await import("node:fs");
|
|
554146
|
+
const { join: join121 } = await import("node:path");
|
|
554147
|
+
const newKey = randomBytes25(16).toString("hex");
|
|
554064
554148
|
process.env["OA_API_KEY"] = newKey;
|
|
554065
|
-
const dir =
|
|
554066
|
-
|
|
554067
|
-
|
|
554149
|
+
const dir = join121(homedir44(), ".open-agents");
|
|
554150
|
+
mkdirSync67(dir, { recursive: true });
|
|
554151
|
+
writeFileSync59(join121(dir, "api.key"), newKey + "\n", "utf8");
|
|
554068
554152
|
renderInfo2(`New API key: ${c3.bold(c3.yellow(newKey))}`);
|
|
554069
554153
|
renderInfo2("Restart the daemon to apply if needed. Use /access any to restart quickly.");
|
|
554070
554154
|
} catch (e2) {
|
|
@@ -554245,18 +554329,18 @@ async function handleSlashCommand(input, ctx3) {
|
|
|
554245
554329
|
}
|
|
554246
554330
|
process.env["OA_ACCESS"] = val2;
|
|
554247
554331
|
if (val2 === "any" && !process.env["OA_API_KEY"]) {
|
|
554248
|
-
const { randomBytes:
|
|
554249
|
-
const apiKey =
|
|
554332
|
+
const { randomBytes: randomBytes25 } = await import("node:crypto");
|
|
554333
|
+
const apiKey = randomBytes25(16).toString("hex");
|
|
554250
554334
|
process.env["OA_API_KEY"] = apiKey;
|
|
554251
554335
|
renderInfo2(`Generated API key: ${c3.bold(c3.yellow(apiKey))}`);
|
|
554252
554336
|
renderInfo2("Use the Web UI ‘key’ button to paste this token, or set Authorization: Bearer <key> in your client.");
|
|
554253
554337
|
try {
|
|
554254
|
-
const { homedir:
|
|
554255
|
-
const { mkdirSync:
|
|
554256
|
-
const { join:
|
|
554257
|
-
const dir =
|
|
554258
|
-
|
|
554259
|
-
|
|
554338
|
+
const { homedir: homedir45 } = await import("node:os");
|
|
554339
|
+
const { mkdirSync: mkdirSync68, writeFileSync: writeFileSync60 } = await import("node:fs");
|
|
554340
|
+
const { join: join122 } = await import("node:path");
|
|
554341
|
+
const dir = join122(homedir45(), ".open-agents");
|
|
554342
|
+
mkdirSync68(dir, { recursive: true });
|
|
554343
|
+
writeFileSync60(join122(dir, "api.key"), apiKey + "\n", "utf8");
|
|
554260
554344
|
} catch {
|
|
554261
554345
|
}
|
|
554262
554346
|
}
|
|
@@ -554267,12 +554351,12 @@ async function handleSlashCommand(input, ctx3) {
|
|
|
554267
554351
|
}
|
|
554268
554352
|
const port2 = parseInt(process.env["OA_PORT"] || "11435", 10);
|
|
554269
554353
|
try {
|
|
554270
|
-
const { homedir:
|
|
554271
|
-
const { mkdirSync:
|
|
554272
|
-
const { join:
|
|
554273
|
-
const dir =
|
|
554274
|
-
|
|
554275
|
-
|
|
554354
|
+
const { homedir: homedir45 } = await import("node:os");
|
|
554355
|
+
const { mkdirSync: mkdirSync68, writeFileSync: writeFileSync60 } = await import("node:fs");
|
|
554356
|
+
const { join: join122 } = await import("node:path");
|
|
554357
|
+
const dir = join122(homedir45(), ".open-agents");
|
|
554358
|
+
mkdirSync68(dir, { recursive: true });
|
|
554359
|
+
writeFileSync60(join122(dir, "access"), `${val2}
|
|
554276
554360
|
`, "utf8");
|
|
554277
554361
|
} catch {
|
|
554278
554362
|
}
|
|
@@ -554347,18 +554431,18 @@ async function handleSlashCommand(input, ctx3) {
|
|
|
554347
554431
|
}
|
|
554348
554432
|
process.env["OA_ACCESS"] = val;
|
|
554349
554433
|
if (val === "any" && !process.env["OA_API_KEY"]) {
|
|
554350
|
-
const { randomBytes:
|
|
554351
|
-
const apiKey =
|
|
554434
|
+
const { randomBytes: randomBytes25 } = await import("node:crypto");
|
|
554435
|
+
const apiKey = randomBytes25(16).toString("hex");
|
|
554352
554436
|
process.env["OA_API_KEY"] = apiKey;
|
|
554353
554437
|
renderInfo2(`Generated API key: ${c3.bold(c3.yellow(apiKey))}`);
|
|
554354
554438
|
renderInfo2("Use the Web UI ‘key’ button to paste this token, or set Authorization: Bearer <key> in your client.");
|
|
554355
554439
|
try {
|
|
554356
|
-
const { homedir:
|
|
554357
|
-
const { mkdirSync:
|
|
554358
|
-
const { join:
|
|
554359
|
-
const dir =
|
|
554360
|
-
|
|
554361
|
-
|
|
554440
|
+
const { homedir: homedir45 } = await import("node:os");
|
|
554441
|
+
const { mkdirSync: mkdirSync68, writeFileSync: writeFileSync60 } = await import("node:fs");
|
|
554442
|
+
const { join: join122 } = await import("node:path");
|
|
554443
|
+
const dir = join122(homedir45(), ".open-agents");
|
|
554444
|
+
mkdirSync68(dir, { recursive: true });
|
|
554445
|
+
writeFileSync60(join122(dir, "api.key"), apiKey + "\n", "utf8");
|
|
554362
554446
|
} catch {
|
|
554363
554447
|
}
|
|
554364
554448
|
}
|
|
@@ -554368,13 +554452,13 @@ async function handleSlashCommand(input, ctx3) {
|
|
|
554368
554452
|
ctx3.saveSettings({ oaAccess: val });
|
|
554369
554453
|
}
|
|
554370
554454
|
const port = parseInt(process.env["OA_PORT"] || "11435", 10);
|
|
554371
|
-
const { homedir:
|
|
554372
|
-
const { mkdirSync:
|
|
554373
|
-
const { join:
|
|
554455
|
+
const { homedir: homedir44 } = await import("node:os");
|
|
554456
|
+
const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = await import("node:fs");
|
|
554457
|
+
const { join: join121 } = await import("node:path");
|
|
554374
554458
|
try {
|
|
554375
|
-
const dir =
|
|
554376
|
-
|
|
554377
|
-
|
|
554459
|
+
const dir = join121(homedir44(), ".open-agents");
|
|
554460
|
+
mkdirSync67(dir, { recursive: true });
|
|
554461
|
+
writeFileSync59(join121(dir, "access"), `${val}
|
|
554378
554462
|
`, "utf8");
|
|
554379
554463
|
} catch (e2) {
|
|
554380
554464
|
renderWarning2(`Could not persist ~/.open-agents/access: ${e2 instanceof Error ? e2.message : String(e2)}`);
|
|
@@ -554727,9 +554811,9 @@ async function handleSlashCommand(input, ctx3) {
|
|
|
554727
554811
|
renderInfo2("No wallet configured. Ask the agent to create one via the nexus tool.");
|
|
554728
554812
|
}
|
|
554729
554813
|
} else if (sub === "name") {
|
|
554730
|
-
const { homedir:
|
|
554814
|
+
const { homedir: homedir44 } = __require("node:os");
|
|
554731
554815
|
const { existsSync: ex, readFileSync: rf, writeFileSync: wf, mkdirSync: mkd } = __require("node:fs");
|
|
554732
|
-
const namePath = __require("node:path").join(
|
|
554816
|
+
const namePath = __require("node:path").join(homedir44(), ".open-agents", "agent-name");
|
|
554733
554817
|
if (rest2) {
|
|
554734
554818
|
const customName = rest2.replace(/[^a-zA-Z0-9_\-.\s]/g, "").trim().slice(0, 40);
|
|
554735
554819
|
if (!customName) {
|
|
@@ -556926,8 +557010,8 @@ sleep 1
|
|
|
556926
557010
|
let sponsorName = (config.header.message || "").replace(/^\/+/, "").trim();
|
|
556927
557011
|
if (!sponsorName || sponsorName.length < 2) {
|
|
556928
557012
|
try {
|
|
556929
|
-
const { homedir:
|
|
556930
|
-
const namePath = __require("path").join(
|
|
557013
|
+
const { homedir: homedir44 } = __require("os");
|
|
557014
|
+
const namePath = __require("path").join(homedir44(), ".open-agents", "agent-name");
|
|
556931
557015
|
if (existsSync77(namePath)) sponsorName = readFileSync61(namePath, "utf8").trim();
|
|
556932
557016
|
} catch {
|
|
556933
557017
|
}
|
|
@@ -558591,11 +558675,11 @@ async function handleVoiceMenu(ctx3, save2, hasLocal) {
|
|
|
558591
558675
|
continue;
|
|
558592
558676
|
}
|
|
558593
558677
|
const { basename: basename20, join: pathJoin } = await import("node:path");
|
|
558594
|
-
const { copyFileSync: copyFileSync3, mkdirSync:
|
|
558595
|
-
const { homedir:
|
|
558678
|
+
const { copyFileSync: copyFileSync3, mkdirSync: mkdirSync67, existsSync: exists2 } = await import("node:fs");
|
|
558679
|
+
const { homedir: homedir44 } = await import("node:os");
|
|
558596
558680
|
const modelName = basename20(onnxDrop.path, ".onnx").replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
558597
|
-
const destDir = pathJoin(
|
|
558598
|
-
if (!exists2(destDir))
|
|
558681
|
+
const destDir = pathJoin(homedir44(), ".open-agents", "voice", "models", modelName);
|
|
558682
|
+
if (!exists2(destDir)) mkdirSync67(destDir, { recursive: true });
|
|
558599
558683
|
copyFileSync3(onnxDrop.path, pathJoin(destDir, "model.onnx"));
|
|
558600
558684
|
copyFileSync3(jsonDrop.path, pathJoin(destDir, "config.json"));
|
|
558601
558685
|
const { registerCustomOnnxModel: registerCustomOnnxModel2 } = await Promise.resolve().then(() => (init_voice(), voice_exports));
|
|
@@ -559345,10 +559429,10 @@ async function handleSponsoredEndpoint(ctx3, local) {
|
|
|
559345
559429
|
sponsors.push(...verified);
|
|
559346
559430
|
if (verified.length > 0) {
|
|
559347
559431
|
try {
|
|
559348
|
-
const { mkdirSync:
|
|
559349
|
-
|
|
559432
|
+
const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = __require("node:fs");
|
|
559433
|
+
mkdirSync67(sponsorDir2, { recursive: true });
|
|
559350
559434
|
const cached = verified.map((s2) => ({ ...s2, lastVerified: Date.now() }));
|
|
559351
|
-
|
|
559435
|
+
writeFileSync59(knownFile, JSON.stringify(cached, null, 2));
|
|
559352
559436
|
} catch {
|
|
559353
559437
|
}
|
|
559354
559438
|
}
|
|
@@ -559521,11 +559605,11 @@ async function handlePeerEndpoint(peerId, authKey, ctx3, local) {
|
|
|
559521
559605
|
const models = await fetchModels(peerUrl, authKey);
|
|
559522
559606
|
if (models.length > 0) {
|
|
559523
559607
|
try {
|
|
559524
|
-
const { writeFileSync:
|
|
559525
|
-
const { join:
|
|
559526
|
-
const cachePath =
|
|
559527
|
-
|
|
559528
|
-
|
|
559608
|
+
const { writeFileSync: writeFileSync59, mkdirSync: mkdirSync67 } = await import("node:fs");
|
|
559609
|
+
const { join: join121, dirname: dirname38 } = await import("node:path");
|
|
559610
|
+
const cachePath = join121(ctx3.repoRoot || process.cwd(), ".oa", "nexus", "peer-models-cache.json");
|
|
559611
|
+
mkdirSync67(dirname38(cachePath), { recursive: true });
|
|
559612
|
+
writeFileSync59(cachePath, JSON.stringify({
|
|
559529
559613
|
peerId,
|
|
559530
559614
|
cachedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
559531
559615
|
models: models.map((m2) => ({ name: m2.name, size: m2.size, parameterSize: m2.parameterSize }))
|
|
@@ -560094,17 +560178,17 @@ async function handleUpdate(subcommand, ctx3) {
|
|
|
560094
560178
|
try {
|
|
560095
560179
|
const { createRequire: createRequire7 } = await import("node:module");
|
|
560096
560180
|
const { fileURLToPath: fileURLToPath20 } = await import("node:url");
|
|
560097
|
-
const { dirname: dirname38, join:
|
|
560098
|
-
const { existsSync:
|
|
560181
|
+
const { dirname: dirname38, join: join121 } = await import("node:path");
|
|
560182
|
+
const { existsSync: existsSync103 } = await import("node:fs");
|
|
560099
560183
|
const req2 = createRequire7(import.meta.url);
|
|
560100
560184
|
const thisDir = dirname38(fileURLToPath20(import.meta.url));
|
|
560101
560185
|
const candidates = [
|
|
560102
|
-
|
|
560103
|
-
|
|
560104
|
-
|
|
560186
|
+
join121(thisDir, "..", "package.json"),
|
|
560187
|
+
join121(thisDir, "..", "..", "package.json"),
|
|
560188
|
+
join121(thisDir, "..", "..", "..", "package.json")
|
|
560105
560189
|
];
|
|
560106
560190
|
for (const pkgPath of candidates) {
|
|
560107
|
-
if (
|
|
560191
|
+
if (existsSync103(pkgPath)) {
|
|
560108
560192
|
const pkg = req2(pkgPath);
|
|
560109
560193
|
if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli") {
|
|
560110
560194
|
currentVersion = pkg.version ?? "0.0.0";
|
|
@@ -561250,15 +561334,15 @@ var init_commands = __esm({
|
|
|
561250
561334
|
process.env["OA_ACCESS"] = val;
|
|
561251
561335
|
if (val === "any" && !process.env["OA_API_KEY"]) {
|
|
561252
561336
|
try {
|
|
561253
|
-
const { randomBytes:
|
|
561254
|
-
const { homedir:
|
|
561255
|
-
const { mkdirSync:
|
|
561256
|
-
const { join:
|
|
561257
|
-
const apiKey =
|
|
561337
|
+
const { randomBytes: randomBytes25 } = await import("node:crypto");
|
|
561338
|
+
const { homedir: homedir44 } = await import("node:os");
|
|
561339
|
+
const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = await import("node:fs");
|
|
561340
|
+
const { join: join121 } = await import("node:path");
|
|
561341
|
+
const apiKey = randomBytes25(16).toString("hex");
|
|
561258
561342
|
process.env["OA_API_KEY"] = apiKey;
|
|
561259
|
-
const dir =
|
|
561260
|
-
|
|
561261
|
-
|
|
561343
|
+
const dir = join121(homedir44(), ".open-agents");
|
|
561344
|
+
mkdirSync67(dir, { recursive: true });
|
|
561345
|
+
writeFileSync59(join121(dir, "api.key"), apiKey + "\n", "utf8");
|
|
561262
561346
|
renderInfo2(`Generated API key: ${c3.bold(c3.yellow(apiKey))}`);
|
|
561263
561347
|
renderInfo2("Use Authorization: Bearer <key> or click 'key' in the Web UI header to paste it.");
|
|
561264
561348
|
} catch (e2) {
|
|
@@ -561272,12 +561356,12 @@ var init_commands = __esm({
|
|
|
561272
561356
|
}
|
|
561273
561357
|
const port = parseInt(process.env["OA_PORT"] || "11435", 10);
|
|
561274
561358
|
try {
|
|
561275
|
-
const { homedir:
|
|
561276
|
-
const { mkdirSync:
|
|
561277
|
-
const { join:
|
|
561278
|
-
const dir =
|
|
561279
|
-
|
|
561280
|
-
|
|
561359
|
+
const { homedir: homedir44 } = await import("node:os");
|
|
561360
|
+
const { mkdirSync: mkdirSync67, writeFileSync: writeFileSync59 } = await import("node:fs");
|
|
561361
|
+
const { join: join121 } = await import("node:path");
|
|
561362
|
+
const dir = join121(homedir44(), ".open-agents");
|
|
561363
|
+
mkdirSync67(dir, { recursive: true });
|
|
561364
|
+
writeFileSync59(join121(dir, "access"), `${val}
|
|
561281
561365
|
`, "utf8");
|
|
561282
561366
|
} catch {
|
|
561283
561367
|
}
|
|
@@ -576712,10 +576796,108 @@ var init_aiwg = __esm({
|
|
|
576712
576796
|
}
|
|
576713
576797
|
});
|
|
576714
576798
|
|
|
576715
|
-
// packages/cli/src/api/
|
|
576716
|
-
|
|
576717
|
-
|
|
576799
|
+
// packages/cli/src/api/runtime-keys.ts
|
|
576800
|
+
var runtime_keys_exports = {};
|
|
576801
|
+
__export(runtime_keys_exports, {
|
|
576802
|
+
listKeysSafe: () => listKeysSafe,
|
|
576803
|
+
lookupKey: () => lookupKey,
|
|
576804
|
+
mintKey: () => mintKey,
|
|
576805
|
+
revokeByPrefix: () => revokeByPrefix
|
|
576806
|
+
});
|
|
576807
|
+
import { existsSync as existsSync94, readFileSync as readFileSync76, writeFileSync as writeFileSync51, mkdirSync as mkdirSync59, chmodSync } from "node:fs";
|
|
576808
|
+
import { join as join110 } from "node:path";
|
|
576718
576809
|
import { homedir as homedir37 } from "node:os";
|
|
576810
|
+
import { randomBytes as randomBytes21 } from "node:crypto";
|
|
576811
|
+
function ensureDir2() {
|
|
576812
|
+
const dir = join110(homedir37(), ".open-agents");
|
|
576813
|
+
if (!existsSync94(dir)) mkdirSync59(dir, { recursive: true });
|
|
576814
|
+
}
|
|
576815
|
+
function loadAll() {
|
|
576816
|
+
if (!existsSync94(KEYS_FILE)) return [];
|
|
576817
|
+
try {
|
|
576818
|
+
const raw = readFileSync76(KEYS_FILE, "utf-8");
|
|
576819
|
+
const parsed = JSON.parse(raw);
|
|
576820
|
+
if (!Array.isArray(parsed)) return [];
|
|
576821
|
+
return parsed;
|
|
576822
|
+
} catch {
|
|
576823
|
+
return [];
|
|
576824
|
+
}
|
|
576825
|
+
}
|
|
576826
|
+
function persistAll(records) {
|
|
576827
|
+
ensureDir2();
|
|
576828
|
+
writeFileSync51(KEYS_FILE, JSON.stringify(records, null, 2), "utf-8");
|
|
576829
|
+
try {
|
|
576830
|
+
chmodSync(KEYS_FILE, 384);
|
|
576831
|
+
} catch {
|
|
576832
|
+
}
|
|
576833
|
+
}
|
|
576834
|
+
function mintKey(args) {
|
|
576835
|
+
const records = loadAll();
|
|
576836
|
+
const key = `oa_${randomBytes21(32).toString("hex")}`;
|
|
576837
|
+
const record = {
|
|
576838
|
+
key,
|
|
576839
|
+
scope: args.scope,
|
|
576840
|
+
owner: args.owner,
|
|
576841
|
+
profile: args.profile ?? null,
|
|
576842
|
+
created: (/* @__PURE__ */ new Date()).toISOString(),
|
|
576843
|
+
revoked: null,
|
|
576844
|
+
rpm: args.rpm,
|
|
576845
|
+
tpd: args.tpd,
|
|
576846
|
+
max_jobs: args.max_jobs
|
|
576847
|
+
};
|
|
576848
|
+
records.push(record);
|
|
576849
|
+
persistAll(records);
|
|
576850
|
+
return record;
|
|
576851
|
+
}
|
|
576852
|
+
function listKeysSafe() {
|
|
576853
|
+
return loadAll().map((r2) => ({
|
|
576854
|
+
...r2,
|
|
576855
|
+
key: void 0,
|
|
576856
|
+
key_prefix: r2.key.slice(0, 8),
|
|
576857
|
+
key_suffix: r2.key.slice(-4)
|
|
576858
|
+
})).map((r2) => {
|
|
576859
|
+
const { key: _drop, ...rest } = r2;
|
|
576860
|
+
void _drop;
|
|
576861
|
+
return rest;
|
|
576862
|
+
});
|
|
576863
|
+
}
|
|
576864
|
+
function revokeByPrefix(prefix) {
|
|
576865
|
+
if (!prefix || prefix.length < 8) return 0;
|
|
576866
|
+
const records = loadAll();
|
|
576867
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
576868
|
+
let n2 = 0;
|
|
576869
|
+
for (const r2 of records) {
|
|
576870
|
+
if (r2.key.startsWith(prefix) && !r2.revoked) {
|
|
576871
|
+
r2.revoked = now;
|
|
576872
|
+
n2++;
|
|
576873
|
+
}
|
|
576874
|
+
}
|
|
576875
|
+
if (n2 > 0) persistAll(records);
|
|
576876
|
+
return n2;
|
|
576877
|
+
}
|
|
576878
|
+
function lookupKey(secret) {
|
|
576879
|
+
if (!secret) return null;
|
|
576880
|
+
const records = loadAll();
|
|
576881
|
+
for (const r2 of records) {
|
|
576882
|
+
if (r2.key === secret) {
|
|
576883
|
+
if (r2.revoked) return null;
|
|
576884
|
+
return r2;
|
|
576885
|
+
}
|
|
576886
|
+
}
|
|
576887
|
+
return null;
|
|
576888
|
+
}
|
|
576889
|
+
var KEYS_FILE;
|
|
576890
|
+
var init_runtime_keys = __esm({
|
|
576891
|
+
"packages/cli/src/api/runtime-keys.ts"() {
|
|
576892
|
+
"use strict";
|
|
576893
|
+
KEYS_FILE = join110(homedir37(), ".open-agents", "keys.json");
|
|
576894
|
+
}
|
|
576895
|
+
});
|
|
576896
|
+
|
|
576897
|
+
// packages/cli/src/api/routes-v1.ts
|
|
576898
|
+
import { existsSync as existsSync95, readFileSync as readFileSync77, readdirSync as readdirSync32, statSync as statSync28 } from "node:fs";
|
|
576899
|
+
import { join as join111, resolve as pathResolve } from "node:path";
|
|
576900
|
+
import { homedir as homedir38 } from "node:os";
|
|
576719
576901
|
async function tryRouteV1(ctx3) {
|
|
576720
576902
|
const { pathname, method } = ctx3;
|
|
576721
576903
|
if (pathname === "/v1/skills" && method === "GET") {
|
|
@@ -576791,6 +576973,12 @@ async function tryRouteV1(ctx3) {
|
|
|
576791
576973
|
if (pathname === "/v1/index" && method === "POST") {
|
|
576792
576974
|
return handleIndex(ctx3);
|
|
576793
576975
|
}
|
|
576976
|
+
if (pathname === "/v1/keys" && method === "GET") return handleListKeys(ctx3);
|
|
576977
|
+
if (pathname === "/v1/keys" && method === "POST") return handleMintKey(ctx3);
|
|
576978
|
+
{
|
|
576979
|
+
const m2 = /^\/v1\/keys\/([^/]+)$/.exec(pathname);
|
|
576980
|
+
if (m2 && method === "DELETE") return handleRevokeKey(ctx3, decodeURIComponent(m2[1]));
|
|
576981
|
+
}
|
|
576794
576982
|
if (pathname === "/v1/tools" && method === "GET") {
|
|
576795
576983
|
return handleListTools(ctx3);
|
|
576796
576984
|
}
|
|
@@ -576937,11 +577125,11 @@ async function handleGetSkill(ctx3, name10) {
|
|
|
576937
577125
|
async function fallbackDiscoverSkills() {
|
|
576938
577126
|
return (_root) => {
|
|
576939
577127
|
const roots = [
|
|
576940
|
-
|
|
577128
|
+
join111(homedir38(), ".local", "share", "ai-writing-guide")
|
|
576941
577129
|
];
|
|
576942
577130
|
const out = [];
|
|
576943
577131
|
for (const root of roots) {
|
|
576944
|
-
if (!
|
|
577132
|
+
if (!existsSync95(root)) continue;
|
|
576945
577133
|
walkForSkills(root, out, 0);
|
|
576946
577134
|
}
|
|
576947
577135
|
return out;
|
|
@@ -576952,12 +577140,12 @@ function walkForSkills(dir, out, depth) {
|
|
|
576952
577140
|
try {
|
|
576953
577141
|
for (const e2 of readdirSync32(dir, { withFileTypes: true })) {
|
|
576954
577142
|
if (e2.name.startsWith(".") || e2.name === "node_modules") continue;
|
|
576955
|
-
const p2 =
|
|
577143
|
+
const p2 = join111(dir, e2.name);
|
|
576956
577144
|
if (e2.isDirectory()) {
|
|
576957
577145
|
walkForSkills(p2, out, depth + 1);
|
|
576958
577146
|
} else if (e2.isFile() && e2.name === "SKILL.md") {
|
|
576959
577147
|
try {
|
|
576960
|
-
const content =
|
|
577148
|
+
const content = readFileSync77(p2, "utf-8").slice(0, 2e3);
|
|
576961
577149
|
const nameMatch = content.match(/^name:\s*(.+)$/m);
|
|
576962
577150
|
const descMatch = content.match(/^description:\s*(.+)$/m);
|
|
576963
577151
|
out.push({
|
|
@@ -577141,7 +577329,7 @@ async function getMemoryStores() {
|
|
|
577141
577329
|
if (memoryInitTried) return null;
|
|
577142
577330
|
memoryInitTried = true;
|
|
577143
577331
|
try {
|
|
577144
|
-
const dbPath =
|
|
577332
|
+
const dbPath = join111(homedir38(), ".open-agents", "memory.db");
|
|
577145
577333
|
const sharedDb = initDb(dbPath);
|
|
577146
577334
|
memoryStoresCache = {
|
|
577147
577335
|
episode: new EpisodeStore(dbPath),
|
|
@@ -577399,7 +577587,7 @@ async function handleFilesRead(ctx3) {
|
|
|
577399
577587
|
}));
|
|
577400
577588
|
return true;
|
|
577401
577589
|
}
|
|
577402
|
-
if (!
|
|
577590
|
+
if (!existsSync95(resolved)) {
|
|
577403
577591
|
sendProblem(res, problemDetails({
|
|
577404
577592
|
type: P.notFound,
|
|
577405
577593
|
status: 404,
|
|
@@ -577431,7 +577619,7 @@ async function handleFilesRead(ctx3) {
|
|
|
577431
577619
|
}));
|
|
577432
577620
|
return true;
|
|
577433
577621
|
}
|
|
577434
|
-
const content =
|
|
577622
|
+
const content = readFileSync77(resolved, "utf-8");
|
|
577435
577623
|
const offset = typeof body.offset === "number" && body.offset >= 0 ? body.offset : 0;
|
|
577436
577624
|
const limit = typeof body.limit === "number" && body.limit > 0 ? body.limit : content.length;
|
|
577437
577625
|
const slice2 = content.slice(offset, offset + limit);
|
|
@@ -577664,14 +577852,14 @@ async function handleNexusStatus(ctx3) {
|
|
|
577664
577852
|
const { res, requestId } = ctx3;
|
|
577665
577853
|
try {
|
|
577666
577854
|
const statePaths = [
|
|
577667
|
-
|
|
577668
|
-
|
|
577855
|
+
join111(process.cwd(), ".oa", "nexus-peer-state.json"),
|
|
577856
|
+
join111(homedir38(), ".open-agents", "nexus-peer-cache.json")
|
|
577669
577857
|
];
|
|
577670
577858
|
const states = [];
|
|
577671
577859
|
for (const p2 of statePaths) {
|
|
577672
|
-
if (!
|
|
577860
|
+
if (!existsSync95(p2)) continue;
|
|
577673
577861
|
try {
|
|
577674
|
-
const raw =
|
|
577862
|
+
const raw = readFileSync77(p2, "utf-8");
|
|
577675
577863
|
states.push({ source: p2, data: JSON.parse(raw) });
|
|
577676
577864
|
} catch (e2) {
|
|
577677
577865
|
states.push({ source: p2, error: String(e2) });
|
|
@@ -577698,8 +577886,8 @@ async function handleNexusStatus(ctx3) {
|
|
|
577698
577886
|
}
|
|
577699
577887
|
function loadAgentName() {
|
|
577700
577888
|
try {
|
|
577701
|
-
const p2 =
|
|
577702
|
-
if (
|
|
577889
|
+
const p2 = join111(homedir38(), ".open-agents", "agent-name");
|
|
577890
|
+
if (existsSync95(p2)) return readFileSync77(p2, "utf-8").trim();
|
|
577703
577891
|
} catch {
|
|
577704
577892
|
}
|
|
577705
577893
|
return null;
|
|
@@ -577708,14 +577896,14 @@ async function handleSponsors(ctx3) {
|
|
|
577708
577896
|
const { req: req2, res, url, requestId } = ctx3;
|
|
577709
577897
|
try {
|
|
577710
577898
|
const candidates = [
|
|
577711
|
-
|
|
577712
|
-
|
|
577899
|
+
join111(homedir38(), ".open-agents", "sponsor-cache.json"),
|
|
577900
|
+
join111(homedir38(), ".open-agents", "sponsors.json")
|
|
577713
577901
|
];
|
|
577714
577902
|
let sponsors = [];
|
|
577715
577903
|
for (const p2 of candidates) {
|
|
577716
|
-
if (!
|
|
577904
|
+
if (!existsSync95(p2)) continue;
|
|
577717
577905
|
try {
|
|
577718
|
-
const raw = JSON.parse(
|
|
577906
|
+
const raw = JSON.parse(readFileSync77(p2, "utf-8"));
|
|
577719
577907
|
if (Array.isArray(raw)) {
|
|
577720
577908
|
sponsors = raw;
|
|
577721
577909
|
break;
|
|
@@ -577784,8 +577972,8 @@ async function handleEvaluate(ctx3) {
|
|
|
577784
577972
|
}));
|
|
577785
577973
|
return true;
|
|
577786
577974
|
}
|
|
577787
|
-
const jobPath =
|
|
577788
|
-
if (!
|
|
577975
|
+
const jobPath = join111(process.cwd(), ".oa", "jobs", `${runId}.json`);
|
|
577976
|
+
if (!existsSync95(jobPath)) {
|
|
577789
577977
|
sendProblem(res, problemDetails({
|
|
577790
577978
|
type: P.notFound,
|
|
577791
577979
|
status: 404,
|
|
@@ -577795,7 +577983,7 @@ async function handleEvaluate(ctx3) {
|
|
|
577795
577983
|
}));
|
|
577796
577984
|
return true;
|
|
577797
577985
|
}
|
|
577798
|
-
const job = JSON.parse(
|
|
577986
|
+
const job = JSON.parse(readFileSync77(jobPath, "utf-8"));
|
|
577799
577987
|
sendJson(res, 200, {
|
|
577800
577988
|
run_id: runId,
|
|
577801
577989
|
task: job.task,
|
|
@@ -577846,6 +578034,130 @@ async function handleIndex(ctx3) {
|
|
|
577846
578034
|
return true;
|
|
577847
578035
|
}
|
|
577848
578036
|
}
|
|
578037
|
+
async function handleListKeys(ctx3) {
|
|
578038
|
+
const { req: req2, res, requestId } = ctx3;
|
|
578039
|
+
const reqAuth = req2;
|
|
578040
|
+
if (reqAuth._authScope !== "admin") {
|
|
578041
|
+
sendProblem(res, problemDetails({
|
|
578042
|
+
type: P.forbidden,
|
|
578043
|
+
status: 403,
|
|
578044
|
+
title: "Admin scope required",
|
|
578045
|
+
detail: "Listing keys requires 'admin' scope.",
|
|
578046
|
+
instance: requestId
|
|
578047
|
+
}));
|
|
578048
|
+
return true;
|
|
578049
|
+
}
|
|
578050
|
+
try {
|
|
578051
|
+
const { listKeysSafe: listKeysSafe2 } = await Promise.resolve().then(() => (init_runtime_keys(), runtime_keys_exports));
|
|
578052
|
+
sendJson(res, 200, { keys: listKeysSafe2() });
|
|
578053
|
+
} catch (err) {
|
|
578054
|
+
sendProblem(res, problemDetails({
|
|
578055
|
+
type: P.internalError,
|
|
578056
|
+
status: 500,
|
|
578057
|
+
title: "List keys failed",
|
|
578058
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
578059
|
+
instance: requestId
|
|
578060
|
+
}));
|
|
578061
|
+
}
|
|
578062
|
+
return true;
|
|
578063
|
+
}
|
|
578064
|
+
async function handleMintKey(ctx3) {
|
|
578065
|
+
const { req: req2, res, requestId } = ctx3;
|
|
578066
|
+
const reqAuth = req2;
|
|
578067
|
+
if (reqAuth._authScope !== "admin") {
|
|
578068
|
+
sendProblem(res, problemDetails({
|
|
578069
|
+
type: P.forbidden,
|
|
578070
|
+
status: 403,
|
|
578071
|
+
title: "Admin scope required",
|
|
578072
|
+
detail: "Minting keys requires 'admin' scope.",
|
|
578073
|
+
instance: requestId
|
|
578074
|
+
}));
|
|
578075
|
+
return true;
|
|
578076
|
+
}
|
|
578077
|
+
try {
|
|
578078
|
+
const body = await parseJsonBodyStrict(req2).catch(() => null);
|
|
578079
|
+
if (!body || typeof body !== "object") {
|
|
578080
|
+
sendProblem(res, problemDetails({
|
|
578081
|
+
type: P.invalidRequest,
|
|
578082
|
+
status: 400,
|
|
578083
|
+
title: "Body must be JSON object",
|
|
578084
|
+
detail: "POST {scope: 'read'|'run'|'admin', owner: string, profile?: string}",
|
|
578085
|
+
instance: requestId
|
|
578086
|
+
}));
|
|
578087
|
+
return true;
|
|
578088
|
+
}
|
|
578089
|
+
const scope = body.scope;
|
|
578090
|
+
if (scope !== "read" && scope !== "run" && scope !== "admin") {
|
|
578091
|
+
sendProblem(res, problemDetails({
|
|
578092
|
+
type: P.invalidRequest,
|
|
578093
|
+
status: 400,
|
|
578094
|
+
title: "Invalid scope",
|
|
578095
|
+
detail: "scope must be one of 'read', 'run', 'admin'.",
|
|
578096
|
+
instance: requestId
|
|
578097
|
+
}));
|
|
578098
|
+
return true;
|
|
578099
|
+
}
|
|
578100
|
+
const owner = typeof body.owner === "string" ? body.owner.slice(0, 200) : "anonymous";
|
|
578101
|
+
const profile = typeof body.profile === "string" ? body.profile.slice(0, 100) : null;
|
|
578102
|
+
const { mintKey: mintKey2 } = await Promise.resolve().then(() => (init_runtime_keys(), runtime_keys_exports));
|
|
578103
|
+
const rec = mintKey2({
|
|
578104
|
+
scope,
|
|
578105
|
+
owner,
|
|
578106
|
+
profile,
|
|
578107
|
+
rpm: typeof body.rpm === "number" ? body.rpm : void 0,
|
|
578108
|
+
tpd: typeof body.tpd === "number" ? body.tpd : void 0,
|
|
578109
|
+
max_jobs: typeof body.max_jobs === "number" ? body.max_jobs : void 0
|
|
578110
|
+
});
|
|
578111
|
+
sendJson(res, 201, { ...rec, _note: "This is the ONLY response that contains the full key. Persist it now." });
|
|
578112
|
+
} catch (err) {
|
|
578113
|
+
sendProblem(res, problemDetails({
|
|
578114
|
+
type: P.internalError,
|
|
578115
|
+
status: 500,
|
|
578116
|
+
title: "Key mint failed",
|
|
578117
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
578118
|
+
instance: requestId
|
|
578119
|
+
}));
|
|
578120
|
+
}
|
|
578121
|
+
return true;
|
|
578122
|
+
}
|
|
578123
|
+
async function handleRevokeKey(ctx3, prefix) {
|
|
578124
|
+
const { req: req2, res, requestId } = ctx3;
|
|
578125
|
+
const reqAuth = req2;
|
|
578126
|
+
if (reqAuth._authScope !== "admin") {
|
|
578127
|
+
sendProblem(res, problemDetails({
|
|
578128
|
+
type: P.forbidden,
|
|
578129
|
+
status: 403,
|
|
578130
|
+
title: "Admin scope required",
|
|
578131
|
+
detail: "Revoking keys requires 'admin' scope.",
|
|
578132
|
+
instance: requestId
|
|
578133
|
+
}));
|
|
578134
|
+
return true;
|
|
578135
|
+
}
|
|
578136
|
+
if (!prefix || prefix.length < 8) {
|
|
578137
|
+
sendProblem(res, problemDetails({
|
|
578138
|
+
type: P.invalidRequest,
|
|
578139
|
+
status: 400,
|
|
578140
|
+
title: "Prefix too short",
|
|
578141
|
+
detail: "Provide at least the first 8 characters of the key to revoke.",
|
|
578142
|
+
instance: requestId
|
|
578143
|
+
}));
|
|
578144
|
+
return true;
|
|
578145
|
+
}
|
|
578146
|
+
try {
|
|
578147
|
+
const { revokeByPrefix: revokeByPrefix2 } = await Promise.resolve().then(() => (init_runtime_keys(), runtime_keys_exports));
|
|
578148
|
+
const n2 = revokeByPrefix2(prefix);
|
|
578149
|
+
sendJson(res, 200, { revoked: n2 });
|
|
578150
|
+
} catch (err) {
|
|
578151
|
+
sendProblem(res, problemDetails({
|
|
578152
|
+
type: P.internalError,
|
|
578153
|
+
status: 500,
|
|
578154
|
+
title: "Key revoke failed",
|
|
578155
|
+
detail: err instanceof Error ? err.message : String(err),
|
|
578156
|
+
instance: requestId
|
|
578157
|
+
}));
|
|
578158
|
+
}
|
|
578159
|
+
return true;
|
|
578160
|
+
}
|
|
577849
578161
|
async function handleListTools(ctx3) {
|
|
577850
578162
|
const { req: req2, res, url, requestId } = ctx3;
|
|
577851
578163
|
try {
|
|
@@ -577889,10 +578201,15 @@ async function handleListTools(ctx3) {
|
|
|
577889
578201
|
const filterCat = url.searchParams.get("category");
|
|
577890
578202
|
const filterScope = url.searchParams.get("scope");
|
|
577891
578203
|
const filterRisk = url.searchParams.get("risk");
|
|
578204
|
+
const filterOffDeviceRaw = url.searchParams.get("off_device");
|
|
577892
578205
|
let filtered = tools;
|
|
577893
578206
|
if (filterCat) filtered = filtered.filter((t2) => t2.security?.categories?.includes(filterCat));
|
|
577894
578207
|
if (filterScope) filtered = filtered.filter((t2) => t2.security?.requires_scope === filterScope);
|
|
577895
578208
|
if (filterRisk) filtered = filtered.filter((t2) => t2.security?.risk === filterRisk);
|
|
578209
|
+
if (filterOffDeviceRaw !== null) {
|
|
578210
|
+
const want = filterOffDeviceRaw === "true";
|
|
578211
|
+
filtered = filtered.filter((t2) => t2.security?.off_device_allowed === want);
|
|
578212
|
+
}
|
|
577896
578213
|
const page2 = parsePagination(url.searchParams);
|
|
577897
578214
|
const envelope = paginated(filtered, page2);
|
|
577898
578215
|
const etag = computeEtag(envelope);
|
|
@@ -577965,6 +578282,13 @@ async function handleGetTool(ctx3, name10) {
|
|
|
577965
578282
|
endpoints: {
|
|
577966
578283
|
call: `/v1/tools/${encodeURIComponent(name10)}/call`,
|
|
577967
578284
|
schema: `/v1/tools/${encodeURIComponent(name10)}`
|
|
578285
|
+
},
|
|
578286
|
+
// Q4: document the canonical body shape for /v1/tools/{name}/call.
|
|
578287
|
+
// The `parameters` field IS the JSON-schema describing what goes
|
|
578288
|
+
// INSIDE the args wrapper — it's not the wrapper itself.
|
|
578289
|
+
call_body_shape: {
|
|
578290
|
+
args: "<object matching the `parameters` JSON schema>",
|
|
578291
|
+
working_dir: "<optional absolute path; defaults to daemon cwd>"
|
|
577968
578292
|
}
|
|
577969
578293
|
};
|
|
577970
578294
|
const etag = computeEtag(body);
|
|
@@ -578147,17 +578471,17 @@ async function handleListAgentTypes(ctx3) {
|
|
|
578147
578471
|
}
|
|
578148
578472
|
async function handleListEngines(ctx3) {
|
|
578149
578473
|
const { res } = ctx3;
|
|
578150
|
-
const home =
|
|
578474
|
+
const home = homedir38();
|
|
578151
578475
|
sendJson(res, 200, {
|
|
578152
578476
|
engines: [
|
|
578153
|
-
{ name: "dream", state_file:
|
|
578154
|
-
{ name: "bless", state_file:
|
|
578155
|
-
{ name: "call", state_file:
|
|
578156
|
-
{ name: "listen", state_file:
|
|
578157
|
-
{ name: "telegram", state_file:
|
|
578158
|
-
{ name: "expose", state_file:
|
|
578159
|
-
{ name: "nexus", state_file:
|
|
578160
|
-
{ name: "ipfs", state_file:
|
|
578477
|
+
{ name: "dream", state_file: join111(process.cwd(), ".oa", "dreams"), controllable_via: "SSE + slash commands" },
|
|
578478
|
+
{ name: "bless", state_file: join111(process.cwd(), ".oa", "bless-state.json"), controllable_via: "slash commands" },
|
|
578479
|
+
{ name: "call", state_file: join111(process.cwd(), ".oa", "call-state.json"), controllable_via: "slash commands" },
|
|
578480
|
+
{ name: "listen", state_file: join111(process.cwd(), ".oa", "listen-state.json"), controllable_via: "slash commands" },
|
|
578481
|
+
{ name: "telegram", state_file: join111(home, ".open-agents", "telegram-state.json"), controllable_via: "slash commands" },
|
|
578482
|
+
{ name: "expose", state_file: join111(process.cwd(), ".oa", "expose-state.json"), controllable_via: "/expose commands" },
|
|
578483
|
+
{ name: "nexus", state_file: join111(home, ".open-agents", "nexus-peer-cache.json"), controllable_via: "/nexus commands" },
|
|
578484
|
+
{ name: "ipfs", state_file: join111(process.cwd(), ".oa", "ipfs"), controllable_via: "slash commands" }
|
|
578161
578485
|
],
|
|
578162
578486
|
note: "Engine instrumentation lives in the running TUI process. Full status + control requires the daemon↔TUI bridge (PT-07). See parity audit WO-PARITY-04."
|
|
578163
578487
|
});
|
|
@@ -578240,21 +578564,21 @@ async function tryAimsRoute(ctx3) {
|
|
|
578240
578564
|
return false;
|
|
578241
578565
|
}
|
|
578242
578566
|
function aimsDir() {
|
|
578243
|
-
return
|
|
578567
|
+
return join111(homedir38(), ".open-agents", "aims");
|
|
578244
578568
|
}
|
|
578245
578569
|
function readAimsFile(name10, fallback) {
|
|
578246
578570
|
try {
|
|
578247
|
-
const p2 =
|
|
578248
|
-
if (
|
|
578571
|
+
const p2 = join111(aimsDir(), name10);
|
|
578572
|
+
if (existsSync95(p2)) return JSON.parse(readFileSync77(p2, "utf-8"));
|
|
578249
578573
|
} catch {
|
|
578250
578574
|
}
|
|
578251
578575
|
return fallback;
|
|
578252
578576
|
}
|
|
578253
578577
|
function writeAimsFile(name10, data) {
|
|
578254
578578
|
const dir = aimsDir();
|
|
578255
|
-
const { mkdirSync:
|
|
578256
|
-
|
|
578257
|
-
const finalPath =
|
|
578579
|
+
const { mkdirSync: mkdirSync67, writeFileSync: wf, renameSync: rn } = __require("node:fs");
|
|
578580
|
+
mkdirSync67(dir, { recursive: true });
|
|
578581
|
+
const finalPath = join111(dir, name10);
|
|
578258
578582
|
const tmpPath = `${finalPath}.tmp.${process.pid}.${Date.now()}`;
|
|
578259
578583
|
try {
|
|
578260
578584
|
wf(tmpPath, JSON.stringify(data, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
|
|
@@ -578584,12 +578908,12 @@ async function handleAimsSuppliers(ctx3) {
|
|
|
578584
578908
|
}
|
|
578585
578909
|
];
|
|
578586
578910
|
const sponsorPaths = [
|
|
578587
|
-
|
|
578911
|
+
join111(homedir38(), ".open-agents", "sponsor-cache.json")
|
|
578588
578912
|
];
|
|
578589
578913
|
for (const p2 of sponsorPaths) {
|
|
578590
|
-
if (!
|
|
578914
|
+
if (!existsSync95(p2)) continue;
|
|
578591
578915
|
try {
|
|
578592
|
-
const raw = JSON.parse(
|
|
578916
|
+
const raw = JSON.parse(readFileSync77(p2, "utf-8"));
|
|
578593
578917
|
const list = Array.isArray(raw) ? raw : raw?.sponsors ?? [];
|
|
578594
578918
|
for (const s2 of list) {
|
|
578595
578919
|
suppliers.push({
|
|
@@ -578651,11 +578975,11 @@ async function handleAimsIncidentPost(ctx3) {
|
|
|
578651
578975
|
}));
|
|
578652
578976
|
return true;
|
|
578653
578977
|
}
|
|
578654
|
-
const { randomBytes:
|
|
578978
|
+
const { randomBytes: randomBytes25 } = await import("node:crypto");
|
|
578655
578979
|
const record = await withAimsLock("incidents.json", () => {
|
|
578656
578980
|
const existing = readAimsFile("incidents.json", []);
|
|
578657
578981
|
const rec = {
|
|
578658
|
-
id: `INC-${Date.now()}-${
|
|
578982
|
+
id: `INC-${Date.now()}-${randomBytes25(4).toString("hex")}`,
|
|
578659
578983
|
ts: (/* @__PURE__ */ new Date()).toISOString(),
|
|
578660
578984
|
raised_by: user ?? "anonymous",
|
|
578661
578985
|
status: "open",
|
|
@@ -585783,10 +586107,24 @@ function getOpenApiSpec() {
|
|
|
585783
586107
|
"/v1/models": { get: { summary: "List aggregated models", tags: ["Inference"], responses: { 200: { description: "OpenAI-format model list" }, ...ErrorResponses } } },
|
|
585784
586108
|
"/v1/chat/completions": {
|
|
585785
586109
|
post: {
|
|
585786
|
-
summary: "OpenAI-compatible chat completion",
|
|
586110
|
+
summary: "OpenAI-compatible chat completion (with optional server-side agent loop)",
|
|
585787
586111
|
tags: ["Inference"],
|
|
585788
|
-
|
|
585789
|
-
|
|
586112
|
+
description: "Standard OpenAI chat-completion proxy by default. Set agent_loop=true to enter a synchronous server-side loop that auto-executes daemon tools (web_search, web_fetch, file_read, ocr, etc.) and re-prompts the model — collapsing N round-trips into 1. include_daemon_tools=['read','run'] auto-merges daemon tools matching those scopes into the offered tools[]. timeout_s overrides OA_BACKEND_TIMEOUT_S (default 120s, max 1h). prompt_template='factual-first' prepends a web_search-first policy. SSE streaming honors tool_calls in delta as standard OpenAI shape: delta.tool_calls=[{id,type:'function',index,function:{name,arguments:<JSON-string>}}]. parallel_tool_calls is forwarded to the backend.",
|
|
586113
|
+
requestBody: { required: true, content: { "application/json": { schema: { type: "object", required: ["model", "messages"], properties: {
|
|
586114
|
+
model: { type: "string" },
|
|
586115
|
+
messages: { type: "array" },
|
|
586116
|
+
stream: { type: "boolean" },
|
|
586117
|
+
temperature: { type: "number" },
|
|
586118
|
+
tools: { type: "array", description: "OpenAI-shape tools array. Forwarded to the backend." },
|
|
586119
|
+
tool_choice: { description: "OpenAI-shape tool_choice. Forwarded to the backend." },
|
|
586120
|
+
parallel_tool_calls: { type: "boolean", description: "Q7 — forwarded to backend; some models (qwen3, llama3) emit multiple tool_calls in one response." },
|
|
586121
|
+
timeout_s: { type: "number", description: "Q1 — per-request timeout in seconds (1-3600). Overrides OA_BACKEND_TIMEOUT_S." },
|
|
586122
|
+
agent_loop: { type: "boolean", description: "Q2 — when true, daemon runs an N-turn agent loop server-side. Daemon tools execute inline; client tool_calls cause the loop to yield." },
|
|
586123
|
+
include_daemon_tools: { type: "array", items: { type: "string", enum: ["read", "run", "admin"] }, description: "Q3 — scopes to merge from daemon tool catalog into tools[]." },
|
|
586124
|
+
max_turns: { type: "integer", description: "Q2 — agent_loop max iterations (default 8, max 64)." },
|
|
586125
|
+
prompt_template: { type: "string", enum: ["factual-first"], description: "Q8 — prepended system policy template. 'factual-first' instructs model to call web_search FIRST for any factual question." }
|
|
586126
|
+
} } } } },
|
|
586127
|
+
responses: { 200: { description: "OpenAI chat.completion shape, SSE if stream=true. agent_loop responses include _agent_loop:{turns,log,done,reason}." }, ...ErrorResponses }
|
|
585790
586128
|
}
|
|
585791
586129
|
},
|
|
585792
586130
|
"/v1/embeddings": { post: { summary: "Generate embeddings", tags: ["Inference"], responses: { 200: { description: "Embedding vectors" }, ...ErrorResponses } } },
|
|
@@ -585998,7 +586336,7 @@ function getOpenApiSpec() {
|
|
|
585998
586336
|
post: {
|
|
585999
586337
|
summary: "Execute a single tool directly (MCP-style, no agent loop)",
|
|
586000
586338
|
tags: ["Tools"],
|
|
586001
|
-
description: "Body: {args: object, working_dir?: string}.
|
|
586339
|
+
description: "Body: {args: object, working_dir?: string}. The `args` key is canonical (Q4) — the JSON-schema in /v1/tools/{name} `parameters` describes what goes INSIDE the args wrapper. Returns ToolResult {success, output, llmContent?, error?, durationMs} plus security metadata. Auth gating: request scope (read/run/admin) must satisfy tool.requires_scope; non-loopback callers need admin scope unless tool.off_device_allowed=true. Anonymous loopback callers default to admin scope; anonymous remote callers default to read scope.",
|
|
586002
586340
|
parameters: [{ name: "name", in: "path", required: true, schema: { type: "string" } }],
|
|
586003
586341
|
responses: {
|
|
586004
586342
|
200: { description: "Tool result envelope" },
|
|
@@ -586008,6 +586346,28 @@ function getOpenApiSpec() {
|
|
|
586008
586346
|
}
|
|
586009
586347
|
}
|
|
586010
586348
|
},
|
|
586349
|
+
"/v1/keys": {
|
|
586350
|
+
get: {
|
|
586351
|
+
summary: "List runtime API keys (admin scope)",
|
|
586352
|
+
tags: ["Tools"],
|
|
586353
|
+
description: "Returns runtime keys with secrets masked (only first 8 + last 4 chars). Q6 — runtime-mintable alternative to OA_API_KEY/OA_API_KEYS env vars.",
|
|
586354
|
+
responses: { 200: { description: "Masked key list" }, 403: { description: "Admin scope required" } }
|
|
586355
|
+
},
|
|
586356
|
+
post: {
|
|
586357
|
+
summary: "Mint a new runtime API key (admin scope)",
|
|
586358
|
+
tags: ["Tools"],
|
|
586359
|
+
description: "Body: {scope: 'read'|'run'|'admin', owner: string, profile?: string, rpm?, tpd?, max_jobs?}. Returns the FULL key — only response that contains the secret. Persisted at ~/.open-agents/keys.json mode 0600.",
|
|
586360
|
+
responses: { 201: { description: "Key minted" }, 400: { description: "Invalid body" }, 403: { description: "Admin scope required" } }
|
|
586361
|
+
}
|
|
586362
|
+
},
|
|
586363
|
+
"/v1/keys/{prefix}": {
|
|
586364
|
+
delete: {
|
|
586365
|
+
summary: "Revoke a runtime key by prefix (admin scope)",
|
|
586366
|
+
tags: ["Tools"],
|
|
586367
|
+
parameters: [{ name: "prefix", in: "path", required: true, schema: { type: "string", minLength: 8 }, description: "First 8+ characters of the key" }],
|
|
586368
|
+
responses: { 200: { description: "Number of keys revoked" }, 400: { description: "Prefix too short" }, 403: { description: "Admin scope required" } }
|
|
586369
|
+
}
|
|
586370
|
+
},
|
|
586011
586371
|
"/v1/hooks": { get: { summary: "List hook types and counts", tags: ["Tools"], responses: { 200: { description: "Hook registry" } } } },
|
|
586012
586372
|
"/v1/agents": { get: { summary: "List agent types", tags: ["Tools"], responses: { 200: { description: "Agent type registry" } } } },
|
|
586013
586373
|
"/v1/engines": { get: { summary: "List long-running engines", tags: ["Engines"], responses: { 200: { description: "Engine status + state files" } } } },
|
|
@@ -586440,15 +586800,15 @@ var init_auth_oidc = __esm({
|
|
|
586440
586800
|
});
|
|
586441
586801
|
|
|
586442
586802
|
// packages/cli/src/api/usage-tracker.ts
|
|
586443
|
-
import { mkdirSync as
|
|
586444
|
-
import { join as
|
|
586803
|
+
import { mkdirSync as mkdirSync60, readFileSync as readFileSync78, writeFileSync as writeFileSync52, existsSync as existsSync96 } from "node:fs";
|
|
586804
|
+
import { join as join112 } from "node:path";
|
|
586445
586805
|
function initUsageTracker(oaDir) {
|
|
586446
|
-
const dir =
|
|
586447
|
-
|
|
586448
|
-
usageFile =
|
|
586806
|
+
const dir = join112(oaDir, "usage");
|
|
586807
|
+
mkdirSync60(dir, { recursive: true });
|
|
586808
|
+
usageFile = join112(dir, "token-usage.json");
|
|
586449
586809
|
try {
|
|
586450
|
-
if (
|
|
586451
|
-
store = JSON.parse(
|
|
586810
|
+
if (existsSync96(usageFile)) {
|
|
586811
|
+
store = JSON.parse(readFileSync78(usageFile, "utf-8"));
|
|
586452
586812
|
}
|
|
586453
586813
|
} catch {
|
|
586454
586814
|
store = { providers: {}, lastSaved: "" };
|
|
@@ -586484,7 +586844,7 @@ function flush2() {
|
|
|
586484
586844
|
if (!initialized2 || !dirty) return;
|
|
586485
586845
|
try {
|
|
586486
586846
|
store.lastSaved = (/* @__PURE__ */ new Date()).toISOString();
|
|
586487
|
-
|
|
586847
|
+
writeFileSync52(usageFile, JSON.stringify(store, null, 2), "utf-8");
|
|
586488
586848
|
dirty = false;
|
|
586489
586849
|
} catch {
|
|
586490
586850
|
}
|
|
@@ -586512,24 +586872,24 @@ var init_usage_tracker = __esm({
|
|
|
586512
586872
|
});
|
|
586513
586873
|
|
|
586514
586874
|
// packages/cli/src/api/profiles.ts
|
|
586515
|
-
import { existsSync as
|
|
586516
|
-
import { join as
|
|
586517
|
-
import { homedir as
|
|
586518
|
-
import { createCipheriv as createCipheriv4, createDecipheriv as createDecipheriv4, randomBytes as
|
|
586875
|
+
import { existsSync as existsSync97, readFileSync as readFileSync79, writeFileSync as writeFileSync53, mkdirSync as mkdirSync61, readdirSync as readdirSync33, unlinkSync as unlinkSync23 } from "node:fs";
|
|
586876
|
+
import { join as join113 } from "node:path";
|
|
586877
|
+
import { homedir as homedir39 } from "node:os";
|
|
586878
|
+
import { createCipheriv as createCipheriv4, createDecipheriv as createDecipheriv4, randomBytes as randomBytes22, scryptSync as scryptSync3 } from "node:crypto";
|
|
586519
586879
|
function globalProfileDir() {
|
|
586520
|
-
return
|
|
586880
|
+
return join113(homedir39(), ".open-agents", "profiles");
|
|
586521
586881
|
}
|
|
586522
586882
|
function projectProfileDir(projectDir2) {
|
|
586523
|
-
return
|
|
586883
|
+
return join113(projectDir2 || process.cwd(), ".oa", "profiles");
|
|
586524
586884
|
}
|
|
586525
586885
|
function listProfiles(projectDir2) {
|
|
586526
586886
|
const result = [];
|
|
586527
586887
|
const seen = /* @__PURE__ */ new Set();
|
|
586528
586888
|
const projDir = projectProfileDir(projectDir2);
|
|
586529
|
-
if (
|
|
586889
|
+
if (existsSync97(projDir)) {
|
|
586530
586890
|
for (const f2 of readdirSync33(projDir).filter((f3) => f3.endsWith(".json"))) {
|
|
586531
586891
|
try {
|
|
586532
|
-
const raw = JSON.parse(
|
|
586892
|
+
const raw = JSON.parse(readFileSync79(join113(projDir, f2), "utf8"));
|
|
586533
586893
|
const name10 = f2.replace(".json", "");
|
|
586534
586894
|
seen.add(name10);
|
|
586535
586895
|
result.push({
|
|
@@ -586543,12 +586903,12 @@ function listProfiles(projectDir2) {
|
|
|
586543
586903
|
}
|
|
586544
586904
|
}
|
|
586545
586905
|
const globDir = globalProfileDir();
|
|
586546
|
-
if (
|
|
586906
|
+
if (existsSync97(globDir)) {
|
|
586547
586907
|
for (const f2 of readdirSync33(globDir).filter((f3) => f3.endsWith(".json"))) {
|
|
586548
586908
|
const name10 = f2.replace(".json", "");
|
|
586549
586909
|
if (seen.has(name10)) continue;
|
|
586550
586910
|
try {
|
|
586551
|
-
const raw = JSON.parse(
|
|
586911
|
+
const raw = JSON.parse(readFileSync79(join113(globDir, f2), "utf8"));
|
|
586552
586912
|
result.push({
|
|
586553
586913
|
name: name10,
|
|
586554
586914
|
description: raw.description || "",
|
|
@@ -586563,11 +586923,11 @@ function listProfiles(projectDir2) {
|
|
|
586563
586923
|
}
|
|
586564
586924
|
function loadProfile(name10, password, projectDir2) {
|
|
586565
586925
|
const sanitized = name10.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
586566
|
-
const projPath =
|
|
586567
|
-
const globPath =
|
|
586568
|
-
const filePath =
|
|
586926
|
+
const projPath = join113(projectProfileDir(projectDir2), `${sanitized}.json`);
|
|
586927
|
+
const globPath = join113(globalProfileDir(), `${sanitized}.json`);
|
|
586928
|
+
const filePath = existsSync97(projPath) ? projPath : existsSync97(globPath) ? globPath : null;
|
|
586569
586929
|
if (!filePath) return null;
|
|
586570
|
-
const raw = JSON.parse(
|
|
586930
|
+
const raw = JSON.parse(readFileSync79(filePath, "utf8"));
|
|
586571
586931
|
if (raw.encrypted === true) {
|
|
586572
586932
|
if (!password) return null;
|
|
586573
586933
|
return decryptProfile(raw, password);
|
|
@@ -586576,32 +586936,32 @@ function loadProfile(name10, password, projectDir2) {
|
|
|
586576
586936
|
}
|
|
586577
586937
|
function saveProfile(profile, password, scope = "global", projectDir2) {
|
|
586578
586938
|
const dir = scope === "project" ? projectProfileDir(projectDir2) : globalProfileDir();
|
|
586579
|
-
|
|
586939
|
+
mkdirSync61(dir, { recursive: true });
|
|
586580
586940
|
const sanitized = profile.name.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
586581
|
-
const filePath =
|
|
586941
|
+
const filePath = join113(dir, `${sanitized}.json`);
|
|
586582
586942
|
profile.modified = (/* @__PURE__ */ new Date()).toISOString();
|
|
586583
586943
|
if (password) {
|
|
586584
586944
|
const encrypted = encryptProfile(profile, password);
|
|
586585
|
-
|
|
586945
|
+
writeFileSync53(filePath, JSON.stringify(encrypted, null, 2), { mode: 384 });
|
|
586586
586946
|
} else {
|
|
586587
586947
|
profile.encrypted = false;
|
|
586588
|
-
|
|
586948
|
+
writeFileSync53(filePath, JSON.stringify(profile, null, 2), { mode: 420 });
|
|
586589
586949
|
}
|
|
586590
586950
|
}
|
|
586591
586951
|
function deleteProfile(name10, scope = "global", projectDir2) {
|
|
586592
586952
|
const sanitized = name10.replace(/[^a-zA-Z0-9_-]/g, "");
|
|
586593
586953
|
const dir = scope === "project" ? projectProfileDir(projectDir2) : globalProfileDir();
|
|
586594
|
-
const filePath =
|
|
586595
|
-
if (
|
|
586954
|
+
const filePath = join113(dir, `${sanitized}.json`);
|
|
586955
|
+
if (existsSync97(filePath)) {
|
|
586596
586956
|
unlinkSync23(filePath);
|
|
586597
586957
|
return true;
|
|
586598
586958
|
}
|
|
586599
586959
|
return false;
|
|
586600
586960
|
}
|
|
586601
586961
|
function encryptProfile(profile, password) {
|
|
586602
|
-
const salt =
|
|
586962
|
+
const salt = randomBytes22(32);
|
|
586603
586963
|
const key = scryptSync3(password, salt, 32);
|
|
586604
|
-
const iv =
|
|
586964
|
+
const iv = randomBytes22(16);
|
|
586605
586965
|
const cipher = createCipheriv4("aes-256-gcm", key, iv);
|
|
586606
586966
|
const plaintext = JSON.stringify(profile);
|
|
586607
586967
|
const encrypted = Buffer.concat([cipher.update(plaintext, "utf8"), cipher.final()]);
|
|
@@ -586707,23 +587067,23 @@ var init_profiles = __esm({
|
|
|
586707
587067
|
|
|
586708
587068
|
// packages/cli/src/docker.ts
|
|
586709
587069
|
import { execSync as execSync54, spawn as spawn24 } from "node:child_process";
|
|
586710
|
-
import { existsSync as
|
|
586711
|
-
import { join as
|
|
586712
|
-
import { homedir as
|
|
587070
|
+
import { existsSync as existsSync98, mkdirSync as mkdirSync62, writeFileSync as writeFileSync54 } from "node:fs";
|
|
587071
|
+
import { join as join114, resolve as resolve37, dirname as dirname34 } from "node:path";
|
|
587072
|
+
import { homedir as homedir40 } from "node:os";
|
|
586713
587073
|
import { fileURLToPath as fileURLToPath16 } from "node:url";
|
|
586714
587074
|
function getDockerDir() {
|
|
586715
587075
|
try {
|
|
586716
587076
|
if (typeof __dirname !== "undefined") {
|
|
586717
|
-
return
|
|
587077
|
+
return join114(__dirname, "..", "..", "..", "docker");
|
|
586718
587078
|
}
|
|
586719
587079
|
} catch {
|
|
586720
587080
|
}
|
|
586721
587081
|
try {
|
|
586722
587082
|
const thisDir = dirname34(fileURLToPath16(import.meta.url));
|
|
586723
|
-
return
|
|
587083
|
+
return join114(thisDir, "..", "..", "..", "docker");
|
|
586724
587084
|
} catch {
|
|
586725
587085
|
}
|
|
586726
|
-
return
|
|
587086
|
+
return join114(process.cwd(), "docker");
|
|
586727
587087
|
}
|
|
586728
587088
|
function isDockerAvailable() {
|
|
586729
587089
|
try {
|
|
@@ -586854,11 +587214,11 @@ async function ensureOaImage(force = false) {
|
|
|
586854
587214
|
}
|
|
586855
587215
|
let buildContext;
|
|
586856
587216
|
const dockerDir = getDockerDir();
|
|
586857
|
-
if (
|
|
587217
|
+
if (existsSync98(join114(dockerDir, "Dockerfile"))) {
|
|
586858
587218
|
buildContext = dockerDir;
|
|
586859
587219
|
} else {
|
|
586860
|
-
buildContext =
|
|
586861
|
-
|
|
587220
|
+
buildContext = join114(homedir40(), ".oa", "docker-build");
|
|
587221
|
+
mkdirSync62(buildContext, { recursive: true });
|
|
586862
587222
|
writeDockerfiles(buildContext);
|
|
586863
587223
|
}
|
|
586864
587224
|
try {
|
|
@@ -586932,8 +587292,8 @@ chown -R node:node /workspace /home/node/.oa /home/node/.open-agents 2>/dev/null
|
|
|
586932
587292
|
if [ "$1" = "oa" ]; then shift; exec su - node -c "cd /workspace && oa $*"; fi
|
|
586933
587293
|
exec "$@"
|
|
586934
587294
|
`;
|
|
586935
|
-
|
|
586936
|
-
|
|
587295
|
+
writeFileSync54(join114(dir, "Dockerfile"), dockerfile);
|
|
587296
|
+
writeFileSync54(join114(dir, "docker-entrypoint.sh"), entrypoint, { mode: 493 });
|
|
586937
587297
|
}
|
|
586938
587298
|
function hasNvidiaGpu() {
|
|
586939
587299
|
try {
|
|
@@ -587186,23 +587546,23 @@ import * as http5 from "node:http";
|
|
|
587186
587546
|
import * as https3 from "node:https";
|
|
587187
587547
|
import { createRequire as createRequire4 } from "node:module";
|
|
587188
587548
|
import { fileURLToPath as fileURLToPath17 } from "node:url";
|
|
587189
|
-
import { dirname as dirname35, join as
|
|
587190
|
-
import { homedir as
|
|
587549
|
+
import { dirname as dirname35, join as join115, resolve as resolve38 } from "node:path";
|
|
587550
|
+
import { homedir as homedir41 } from "node:os";
|
|
587191
587551
|
import { spawn as spawn25, execSync as execSync55 } from "node:child_process";
|
|
587192
|
-
import { mkdirSync as
|
|
587193
|
-
import { randomBytes as
|
|
587552
|
+
import { mkdirSync as mkdirSync63, writeFileSync as writeFileSync55, readFileSync as readFileSync80, readdirSync as readdirSync34, existsSync as existsSync99, watch as fsWatch3, renameSync as renameSync8, unlinkSync as unlinkSync24 } from "node:fs";
|
|
587553
|
+
import { randomBytes as randomBytes23, randomUUID as randomUUID14 } from "node:crypto";
|
|
587194
587554
|
import { createHash as createHash15 } from "node:crypto";
|
|
587195
587555
|
function getVersion3() {
|
|
587196
587556
|
try {
|
|
587197
587557
|
const thisDir = dirname35(fileURLToPath17(import.meta.url));
|
|
587198
587558
|
const candidates = [
|
|
587199
|
-
|
|
587200
|
-
|
|
587201
|
-
|
|
587559
|
+
join115(thisDir, "..", "package.json"),
|
|
587560
|
+
join115(thisDir, "..", "..", "package.json"),
|
|
587561
|
+
join115(thisDir, "..", "..", "..", "package.json")
|
|
587202
587562
|
];
|
|
587203
587563
|
for (const pkgPath of candidates) {
|
|
587204
587564
|
try {
|
|
587205
|
-
if (!
|
|
587565
|
+
if (!existsSync99(pkgPath)) continue;
|
|
587206
587566
|
const pkg = require3(pkgPath);
|
|
587207
587567
|
if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli" || pkg.name === "@open-agents/monorepo") {
|
|
587208
587568
|
return pkg.version ?? "0.0.0";
|
|
@@ -587349,6 +587709,19 @@ function resolveModelEndpoint(modelId) {
|
|
|
587349
587709
|
}
|
|
587350
587710
|
return null;
|
|
587351
587711
|
}
|
|
587712
|
+
function getBackendTimeoutMs(perRequestSeconds) {
|
|
587713
|
+
if (typeof perRequestSeconds === "number" && perRequestSeconds > 0) {
|
|
587714
|
+
return Math.min(Math.floor(perRequestSeconds * 1e3), BACKEND_TIMEOUT_MAX_MS);
|
|
587715
|
+
}
|
|
587716
|
+
const envS = process.env["OA_BACKEND_TIMEOUT_S"];
|
|
587717
|
+
if (envS) {
|
|
587718
|
+
const n2 = parseFloat(envS);
|
|
587719
|
+
if (Number.isFinite(n2) && n2 > 0) {
|
|
587720
|
+
return Math.min(Math.floor(n2 * 1e3), BACKEND_TIMEOUT_MAX_MS);
|
|
587721
|
+
}
|
|
587722
|
+
}
|
|
587723
|
+
return BACKEND_TIMEOUT_DEFAULT_MS;
|
|
587724
|
+
}
|
|
587352
587725
|
function recordMetric(method, path8, status) {
|
|
587353
587726
|
const key = `${method}|${path8}|${status}`;
|
|
587354
587727
|
const existing = metrics.requests.get(key);
|
|
@@ -587391,9 +587764,9 @@ function isOriginAllowed(origin) {
|
|
|
587391
587764
|
if (!origin) return true;
|
|
587392
587765
|
let accessMode = (process.env["OA_ACCESS"] || "").toLowerCase().trim();
|
|
587393
587766
|
try {
|
|
587394
|
-
const accessFile =
|
|
587395
|
-
if (
|
|
587396
|
-
const persisted =
|
|
587767
|
+
const accessFile = join115(homedir41(), ".open-agents", "access");
|
|
587768
|
+
if (existsSync99(accessFile)) {
|
|
587769
|
+
const persisted = readFileSync80(accessFile, "utf8").trim().toLowerCase();
|
|
587397
587770
|
if (persisted === "any" || persisted === "lan" || persisted === "loopback") {
|
|
587398
587771
|
accessMode = persisted;
|
|
587399
587772
|
}
|
|
@@ -587453,7 +587826,7 @@ async function retrieveMemoryContext(userMessage, sessionId, maxEpisodes = 5) {
|
|
|
587453
587826
|
if (!memMod || !memMod.EpisodeStore) {
|
|
587454
587827
|
return { contextBlock: "", retrieved: [] };
|
|
587455
587828
|
}
|
|
587456
|
-
const dbPath =
|
|
587829
|
+
const dbPath = join115(homedir41(), ".open-agents", "memory.db");
|
|
587457
587830
|
const store2 = new memMod.EpisodeStore(dbPath);
|
|
587458
587831
|
const recent = store2.search({ limit: 30, sessionId: void 0 }) ?? [];
|
|
587459
587832
|
const qLower = userMessage.toLowerCase();
|
|
@@ -587496,7 +587869,7 @@ async function writeMemoryEpisodes(sessionId, userMessage, assistantContent, too
|
|
|
587496
587869
|
try {
|
|
587497
587870
|
const memMod = await Promise.resolve().then(() => (init_dist7(), dist_exports2)).catch(() => null);
|
|
587498
587871
|
if (!memMod || !memMod.EpisodeStore) return 0;
|
|
587499
|
-
const dbPath =
|
|
587872
|
+
const dbPath = join115(homedir41(), ".open-agents", "memory.db");
|
|
587500
587873
|
const store2 = new memMod.EpisodeStore(dbPath);
|
|
587501
587874
|
let written = 0;
|
|
587502
587875
|
try {
|
|
@@ -587598,7 +587971,8 @@ async function directChatBackend(opts) {
|
|
|
587598
587971
|
proxyRes.on("error", reject);
|
|
587599
587972
|
});
|
|
587600
587973
|
proxyReq.on("error", reject);
|
|
587601
|
-
|
|
587974
|
+
const _dctTo = getBackendTimeoutMs(extraFields?.["timeout_s"]);
|
|
587975
|
+
proxyReq.setTimeout(_dctTo, () => proxyReq.destroy(new Error(`Backend timeout (${Math.round(_dctTo / 1e3)}s)`)));
|
|
587602
587976
|
proxyReq.write(reqBody);
|
|
587603
587977
|
proxyReq.end();
|
|
587604
587978
|
});
|
|
@@ -587751,7 +588125,7 @@ function backendAuthHeaders(endpoint) {
|
|
|
587751
588125
|
if (key) return { Authorization: `Bearer ${key}` };
|
|
587752
588126
|
return {};
|
|
587753
588127
|
}
|
|
587754
|
-
function ollamaRequest(ollamaUrl, path8, method, body) {
|
|
588128
|
+
function ollamaRequest(ollamaUrl, path8, method, body, timeoutMs) {
|
|
587755
588129
|
return new Promise((resolve43, reject) => {
|
|
587756
588130
|
const url = new URL(path8, ollamaUrl);
|
|
587757
588131
|
const isHttps = url.protocol === "https:";
|
|
@@ -587778,15 +588152,16 @@ function ollamaRequest(ollamaUrl, path8, method, body) {
|
|
|
587778
588152
|
});
|
|
587779
588153
|
});
|
|
587780
588154
|
});
|
|
587781
|
-
|
|
587782
|
-
|
|
588155
|
+
const _to = getBackendTimeoutMs(timeoutMs ? timeoutMs / 1e3 : void 0);
|
|
588156
|
+
proxyReq.setTimeout(_to, () => {
|
|
588157
|
+
proxyReq.destroy(new Error(`Backend request timeout (${Math.round(_to / 1e3)}s)`));
|
|
587783
588158
|
});
|
|
587784
588159
|
proxyReq.on("error", reject);
|
|
587785
588160
|
if (body) proxyReq.write(body);
|
|
587786
588161
|
proxyReq.end();
|
|
587787
588162
|
});
|
|
587788
588163
|
}
|
|
587789
|
-
function ollamaStream(ollamaUrl, path8, method, body, onData, onEnd, onError) {
|
|
588164
|
+
function ollamaStream(ollamaUrl, path8, method, body, onData, onEnd, onError, timeoutMs) {
|
|
587790
588165
|
const url = new URL(path8, ollamaUrl);
|
|
587791
588166
|
const isHttps = url.protocol === "https:";
|
|
587792
588167
|
const options2 = {
|
|
@@ -587806,8 +588181,9 @@ function ollamaStream(ollamaUrl, path8, method, body, onData, onEnd, onError) {
|
|
|
587806
588181
|
proxyRes.on("data", onData);
|
|
587807
588182
|
proxyRes.on("end", onEnd);
|
|
587808
588183
|
});
|
|
587809
|
-
|
|
587810
|
-
|
|
588184
|
+
const _streamTo = getBackendTimeoutMs(timeoutMs ? timeoutMs / 1e3 : void 0);
|
|
588185
|
+
proxyReq.setTimeout(_streamTo, () => {
|
|
588186
|
+
proxyReq.destroy(new Error(`Backend stream timeout (${Math.round(_streamTo / 1e3)}s)`));
|
|
587811
588187
|
});
|
|
587812
588188
|
proxyReq.on("error", onError);
|
|
587813
588189
|
if (body) proxyReq.write(body);
|
|
@@ -587815,32 +588191,76 @@ function ollamaStream(ollamaUrl, path8, method, body, onData, onEnd, onError) {
|
|
|
587815
588191
|
}
|
|
587816
588192
|
function jobsDir() {
|
|
587817
588193
|
const root = resolve38(process.cwd());
|
|
587818
|
-
const dir =
|
|
587819
|
-
|
|
588194
|
+
const dir = join115(root, ".oa", "jobs");
|
|
588195
|
+
mkdirSync63(dir, { recursive: true });
|
|
587820
588196
|
return dir;
|
|
587821
588197
|
}
|
|
587822
588198
|
function loadJob(id) {
|
|
587823
|
-
const file =
|
|
587824
|
-
if (!
|
|
588199
|
+
const file = join115(jobsDir(), `${id}.json`);
|
|
588200
|
+
if (!existsSync99(file)) return null;
|
|
587825
588201
|
try {
|
|
587826
|
-
return JSON.parse(
|
|
588202
|
+
return JSON.parse(readFileSync80(file, "utf-8"));
|
|
587827
588203
|
} catch {
|
|
587828
588204
|
return null;
|
|
587829
588205
|
}
|
|
587830
588206
|
}
|
|
587831
588207
|
function listJobs() {
|
|
587832
588208
|
const dir = jobsDir();
|
|
587833
|
-
if (!
|
|
588209
|
+
if (!existsSync99(dir)) return [];
|
|
587834
588210
|
const files = readdirSync34(dir).filter((f2) => f2.endsWith(".json")).sort();
|
|
587835
588211
|
const jobs = [];
|
|
587836
588212
|
for (const file of files) {
|
|
587837
588213
|
try {
|
|
587838
|
-
jobs.push(JSON.parse(
|
|
588214
|
+
jobs.push(JSON.parse(readFileSync80(join115(dir, file), "utf-8")));
|
|
587839
588215
|
} catch {
|
|
587840
588216
|
}
|
|
587841
588217
|
}
|
|
587842
588218
|
return jobs;
|
|
587843
588219
|
}
|
|
588220
|
+
function pruneOldJobs() {
|
|
588221
|
+
const retentionH = parseFloat(process.env["OA_RUN_RETENTION_H"] || "24");
|
|
588222
|
+
const cutoffMs = Date.now() - (Number.isFinite(retentionH) && retentionH > 0 ? retentionH : 24) * 36e5;
|
|
588223
|
+
const dir = jobsDir();
|
|
588224
|
+
if (!existsSync99(dir)) return { pruned: 0, kept: 0 };
|
|
588225
|
+
let pruned = 0;
|
|
588226
|
+
let kept = 0;
|
|
588227
|
+
for (const file of readdirSync34(dir)) {
|
|
588228
|
+
if (!file.endsWith(".json")) continue;
|
|
588229
|
+
const path8 = join115(dir, file);
|
|
588230
|
+
try {
|
|
588231
|
+
const job = JSON.parse(readFileSync80(path8, "utf-8"));
|
|
588232
|
+
if (job.status === "running") {
|
|
588233
|
+
kept++;
|
|
588234
|
+
continue;
|
|
588235
|
+
}
|
|
588236
|
+
const ageRef = job.completedAt || job.startedAt;
|
|
588237
|
+
const ts = ageRef ? Date.parse(ageRef) : NaN;
|
|
588238
|
+
if (Number.isFinite(ts) && ts < cutoffMs) {
|
|
588239
|
+
try {
|
|
588240
|
+
unlinkSync24(path8);
|
|
588241
|
+
} catch {
|
|
588242
|
+
}
|
|
588243
|
+
const outFile = path8.replace(/\.json$/, ".output");
|
|
588244
|
+
if (existsSync99(outFile)) {
|
|
588245
|
+
try {
|
|
588246
|
+
unlinkSync24(outFile);
|
|
588247
|
+
} catch {
|
|
588248
|
+
}
|
|
588249
|
+
}
|
|
588250
|
+
pruned++;
|
|
588251
|
+
} else {
|
|
588252
|
+
kept++;
|
|
588253
|
+
}
|
|
588254
|
+
} catch {
|
|
588255
|
+
try {
|
|
588256
|
+
unlinkSync24(path8);
|
|
588257
|
+
pruned++;
|
|
588258
|
+
} catch {
|
|
588259
|
+
}
|
|
588260
|
+
}
|
|
588261
|
+
}
|
|
588262
|
+
return { pruned, kept };
|
|
588263
|
+
}
|
|
587844
588264
|
function getKeyUsage(user) {
|
|
587845
588265
|
if (!perKeyUsage.has(user)) {
|
|
587846
588266
|
perKeyUsage.set(user, { requestTimestamps: [], tokensToday: 0, tokenDate: (/* @__PURE__ */ new Date()).toISOString().slice(0, 10), activeJobs: 0 });
|
|
@@ -587909,14 +588329,14 @@ function autoSeedTodosFromPrompt(prompt) {
|
|
|
587909
588329
|
return [];
|
|
587910
588330
|
}
|
|
587911
588331
|
function atomicJobWrite(dir, id, job) {
|
|
587912
|
-
const finalPath =
|
|
588332
|
+
const finalPath = join115(dir, `${id}.json`);
|
|
587913
588333
|
const tmpPath = `${finalPath}.tmp.${process.pid}.${Date.now()}`;
|
|
587914
588334
|
try {
|
|
587915
|
-
|
|
588335
|
+
writeFileSync55(tmpPath, JSON.stringify(job, null, 2), "utf-8");
|
|
587916
588336
|
renameSync8(tmpPath, finalPath);
|
|
587917
588337
|
} catch {
|
|
587918
588338
|
try {
|
|
587919
|
-
|
|
588339
|
+
writeFileSync55(finalPath, JSON.stringify(job, null, 2), "utf-8");
|
|
587920
588340
|
} catch {
|
|
587921
588341
|
}
|
|
587922
588342
|
try {
|
|
@@ -587948,8 +588368,27 @@ function resolveAuth(req2) {
|
|
|
587948
588368
|
return { authenticated: false, scope: "read" };
|
|
587949
588369
|
}
|
|
587950
588370
|
const singleKey = process.env["OA_API_KEY"];
|
|
588371
|
+
if (singleKey) {
|
|
588372
|
+
if (token === singleKey) return { authenticated: true, scope: "admin" };
|
|
588373
|
+
}
|
|
588374
|
+
if (token) {
|
|
588375
|
+
try {
|
|
588376
|
+
const { lookupKey: _lk } = require3("./runtime-keys.js");
|
|
588377
|
+
const rec = _lk(token);
|
|
588378
|
+
if (rec) {
|
|
588379
|
+
return {
|
|
588380
|
+
authenticated: true,
|
|
588381
|
+
scope: rec.scope,
|
|
588382
|
+
user: rec.owner,
|
|
588383
|
+
rpm: rec.rpm,
|
|
588384
|
+
tpd: rec.tpd,
|
|
588385
|
+
maxJobs: rec.max_jobs
|
|
588386
|
+
};
|
|
588387
|
+
}
|
|
588388
|
+
} catch {
|
|
588389
|
+
}
|
|
588390
|
+
}
|
|
587951
588391
|
if (!singleKey) return { authenticated: true, scope: "admin" };
|
|
587952
|
-
if (token === singleKey) return { authenticated: true, scope: "admin" };
|
|
587953
588392
|
return { authenticated: false, scope: "read" };
|
|
587954
588393
|
}
|
|
587955
588394
|
function checkAuth(req2, res, requiredScope = "read") {
|
|
@@ -588070,7 +588509,41 @@ function handleHelp(req2, res) {
|
|
|
588070
588509
|
},
|
|
588071
588510
|
off_device_policy: "Tools with off_device_allowed=false are loopback-only; remote callers need admin scope to bypass.",
|
|
588072
588511
|
anonymous_default: "Loopback callers default to admin scope. Remote callers default to read scope until authenticated.",
|
|
588073
|
-
override: "Operators can override per-tool classification via OA_TOOL_OVERRIDES env var (JSON map of name → partial security info)."
|
|
588512
|
+
override: "Operators can override per-tool classification via OA_TOOL_OVERRIDES env var (JSON map of name → partial security info).",
|
|
588513
|
+
filters: "GET /v1/tools supports ?category=, ?scope=, ?risk=, ?off_device=true|false (Q9). E.g. /v1/tools?scope=read&off_device=true returns the safe-to-expose set."
|
|
588514
|
+
},
|
|
588515
|
+
runtime_keys: {
|
|
588516
|
+
"GET /v1/keys": "List runtime keys (admin scope). Secrets masked.",
|
|
588517
|
+
"POST /v1/keys": "Mint a runtime key (admin scope). Body: {scope, owner, profile?, rpm?, tpd?, max_jobs?}. Returns full secret ONCE.",
|
|
588518
|
+
"DELETE /v1/keys/{prefix}": "Revoke a key by its first 8+ chars (admin scope). Soft-delete; record retained for audit.",
|
|
588519
|
+
env_alternative: 'OA_API_KEY (single, admin) or OA_API_KEYS="key:scope:owner:rpm:tpd:max_jobs,...". Runtime keys are checked AFTER env keys.',
|
|
588520
|
+
per_key_profile: "Bind a key to a tool profile (allow/deny lists from /v1/profiles) for capability scoping beyond coarse read/run/admin.",
|
|
588521
|
+
storage: "~/.open-agents/keys.json (mode 600). Soft-deleted keys are kept for audit."
|
|
588522
|
+
},
|
|
588523
|
+
agent_loop_inference: {
|
|
588524
|
+
enable: "POST /v1/chat/completions with body {agent_loop: true} runs an N-turn server-side loop. Daemon executes any tool_calls matching daemon-resident tools and re-prompts; client-side tool_calls cause the loop to yield back so caller can execute them.",
|
|
588525
|
+
merge_daemon_tools: "Body field include_daemon_tools: ['read'] (or ['read','run']) merges the daemon's matching tools into the offered tools[] array automatically — no need to hand-list web_search/web_fetch/file_read/etc.",
|
|
588526
|
+
max_turns: "Body field max_turns (default 8, max 64).",
|
|
588527
|
+
timeout: "Body field timeout_s caps the whole loop (default 30 min, max 1 hour). Per-backend-call timeout is separate (see OA_BACKEND_TIMEOUT_S).",
|
|
588528
|
+
prompt_template: "Body field prompt_template: 'factual-first' prepends a system message instructing the model to call web_search FIRST for any factual question.",
|
|
588529
|
+
response_envelope: "Standard OpenAI chat.completion shape PLUS a _agent_loop: {turns, log:[], done, reason} field. Reason is one of: model_returned_content, client_tools_pending, max_turns_exhausted."
|
|
588530
|
+
},
|
|
588531
|
+
backend_timeout: {
|
|
588532
|
+
env: "OA_BACKEND_TIMEOUT_S — default 120 seconds, max 3600 (1 hour).",
|
|
588533
|
+
per_request: "Body field timeout_s on /v1/chat/completions, /v1/run, agent_loop. Caps to 1h.",
|
|
588534
|
+
rationale: "Q1 (Cody/SA) — was hardcoded 120s, broke cold-start tool-calling thinks on large models."
|
|
588535
|
+
},
|
|
588536
|
+
run_lifecycle: {
|
|
588537
|
+
gc: "Q10 — completed/failed runs older than OA_RUN_RETENTION_H hours (default 24) are pruned at startup and on a 1h interval. Set OA_RUN_RETENTION_H=0 to disable. Running runs are never pruned.",
|
|
588538
|
+
manual_delete: "DELETE /v1/runs/{id} — explicit cleanup."
|
|
588539
|
+
},
|
|
588540
|
+
sse_chunk_shape: {
|
|
588541
|
+
chat_completions: "Standard OpenAI delta shape. tool_calls in delta: [{id:'call_<hex>', type:'function', index:N, function:{name:'...', arguments:'<JSON-string>'}}]. Final chunk: {choices:[{finish_reason:'stop', delta:{}}]} then 'data: [DONE]'.",
|
|
588542
|
+
events_bus: "GET /v1/events streams the daemon-event bus (different shape): event:'tool.called', data:{run_id, tool, args, ts}. NOT the same as chat completions SSE."
|
|
588543
|
+
},
|
|
588544
|
+
parallel_tool_calls: {
|
|
588545
|
+
passthrough: "Request body field parallel_tool_calls: true is forwarded to the backend (Ollama/vLLM). Models supporting it (qwen3, llama3) emit multiple tool_calls in one response — daemon forwards them in delta.tool_calls[].",
|
|
588546
|
+
agent_loop: "When agent_loop=true with multiple daemon-tool tool_calls, all execute sequentially (still server-side; saves N round-trips vs the client doing each one)."
|
|
588074
588547
|
},
|
|
588075
588548
|
mcp: {
|
|
588076
588549
|
"GET /v1/mcps": "List connected MCP (Model Context Protocol) servers",
|
|
@@ -588309,6 +588782,277 @@ async function handleApiTags(res) {
|
|
|
588309
588782
|
});
|
|
588310
588783
|
}
|
|
588311
588784
|
}
|
|
588785
|
+
async function runAgentLoopChatCompletions(opts) {
|
|
588786
|
+
const { req: req2, res, ollamaUrl, requestBody, perReqTimeoutS } = opts;
|
|
588787
|
+
const startMs = Date.now();
|
|
588788
|
+
const reqTimeoutMs = getBackendTimeoutMs(perReqTimeoutS);
|
|
588789
|
+
const totalDeadline = startMs + (perReqTimeoutS && perReqTimeoutS > 0 ? Math.min(perReqTimeoutS * 1e3, BACKEND_TIMEOUT_MAX_MS) : 30 * 60 * 1e3);
|
|
588790
|
+
const model = requestBody["model"] || "unknown";
|
|
588791
|
+
const route = resolveModelEndpoint(model);
|
|
588792
|
+
const targetUrl = route?.endpoint.url ?? ollamaUrl;
|
|
588793
|
+
const targetType = route?.endpoint.type ?? loadConfig().backendType ?? "ollama";
|
|
588794
|
+
const originalModel = route?.originalId ?? model;
|
|
588795
|
+
const maxTurns = typeof requestBody["max_turns"] === "number" ? Math.max(1, Math.min(64, requestBody["max_turns"])) : 8;
|
|
588796
|
+
const remoteIp = (req2.socket?.remoteAddress || "").replace(/^::ffff:/, "");
|
|
588797
|
+
const origin = /^(127\.\d+\.\d+\.\d+|::1|localhost)$/.test(remoteIp) ? "loopback" : "remote";
|
|
588798
|
+
const reqAuth = req2;
|
|
588799
|
+
const scope = reqAuth._authScope ?? (origin === "loopback" ? "admin" : "read");
|
|
588800
|
+
const execMod = await Promise.resolve().then(() => (init_dist5(), dist_exports)).catch(() => null);
|
|
588801
|
+
if (!execMod) {
|
|
588802
|
+
jsonResponse(res, 500, { error: "Execution module unavailable" });
|
|
588803
|
+
return;
|
|
588804
|
+
}
|
|
588805
|
+
const classify = execMod.classifyTool;
|
|
588806
|
+
const canInvoke = execMod.canInvokeTool;
|
|
588807
|
+
const daemonTools = /* @__PURE__ */ new Map();
|
|
588808
|
+
for (const [classKey, value2] of Object.entries(execMod)) {
|
|
588809
|
+
if (typeof value2 !== "function") continue;
|
|
588810
|
+
const proto = value2.prototype;
|
|
588811
|
+
if (!proto || typeof proto.execute !== "function") continue;
|
|
588812
|
+
let probe = null;
|
|
588813
|
+
try {
|
|
588814
|
+
probe = new value2();
|
|
588815
|
+
} catch {
|
|
588816
|
+
try {
|
|
588817
|
+
probe = new value2(process.cwd());
|
|
588818
|
+
} catch {
|
|
588819
|
+
probe = null;
|
|
588820
|
+
}
|
|
588821
|
+
}
|
|
588822
|
+
if (probe?.name && typeof probe.name === "string") {
|
|
588823
|
+
daemonTools.set(probe.name, { ToolClass: value2, classKey });
|
|
588824
|
+
}
|
|
588825
|
+
}
|
|
588826
|
+
const includeDaemonTools = Array.isArray(requestBody["include_daemon_tools"]) ? requestBody["include_daemon_tools"].filter((s2) => typeof s2 === "string") : [];
|
|
588827
|
+
const advertisedDaemonNames = /* @__PURE__ */ new Set();
|
|
588828
|
+
if (includeDaemonTools.length > 0) {
|
|
588829
|
+
for (const [toolName, { ToolClass: _T }] of daemonTools.entries()) {
|
|
588830
|
+
void _T;
|
|
588831
|
+
const sec = classify(toolName);
|
|
588832
|
+
if (!sec) continue;
|
|
588833
|
+
if (!includeDaemonTools.includes(sec.requires_scope)) continue;
|
|
588834
|
+
if (canInvoke({ toolName, origin, scope }) !== null) continue;
|
|
588835
|
+
advertisedDaemonNames.add(toolName);
|
|
588836
|
+
}
|
|
588837
|
+
}
|
|
588838
|
+
const callerTools = Array.isArray(requestBody["tools"]) ? requestBody["tools"].filter((t2) => t2?.type === "function" && typeof t2?.function?.name === "string") : [];
|
|
588839
|
+
const callerToolNames = new Set(callerTools.map((t2) => t2.function.name));
|
|
588840
|
+
const daemonToolEntries = [];
|
|
588841
|
+
for (const name10 of advertisedDaemonNames) {
|
|
588842
|
+
if (callerToolNames.has(name10)) continue;
|
|
588843
|
+
const meta = daemonTools.get(name10);
|
|
588844
|
+
if (!meta) continue;
|
|
588845
|
+
let inst = null;
|
|
588846
|
+
try {
|
|
588847
|
+
inst = new meta.ToolClass();
|
|
588848
|
+
} catch {
|
|
588849
|
+
try {
|
|
588850
|
+
inst = new meta.ToolClass(process.cwd());
|
|
588851
|
+
} catch {
|
|
588852
|
+
inst = null;
|
|
588853
|
+
}
|
|
588854
|
+
}
|
|
588855
|
+
if (!inst) continue;
|
|
588856
|
+
daemonToolEntries.push({
|
|
588857
|
+
type: "function",
|
|
588858
|
+
function: {
|
|
588859
|
+
name: name10,
|
|
588860
|
+
description: typeof inst.description === "string" ? inst.description : "",
|
|
588861
|
+
parameters: inst.parameters ?? { type: "object", properties: {} }
|
|
588862
|
+
}
|
|
588863
|
+
});
|
|
588864
|
+
}
|
|
588865
|
+
const mergedTools = [...callerTools, ...daemonToolEntries];
|
|
588866
|
+
const messages2 = Array.isArray(requestBody["messages"]) ? requestBody["messages"].slice() : [];
|
|
588867
|
+
const promptTemplate = typeof requestBody["prompt_template"] === "string" ? requestBody["prompt_template"] : null;
|
|
588868
|
+
if (promptTemplate === "factual-first" && advertisedDaemonNames.has("web_search")) {
|
|
588869
|
+
const SYSTEM_FACTUAL_FIRST = [
|
|
588870
|
+
"[POLICY: factual-first]",
|
|
588871
|
+
"For any user question that asks for a fact, statistic, current event,",
|
|
588872
|
+
"person/place/product detail, or anything you might be tempted to answer",
|
|
588873
|
+
"from training data alone — your FIRST tool_call MUST be `web_search`",
|
|
588874
|
+
"with a query derived from the user's question. Do NOT answer from",
|
|
588875
|
+
"training data. After web_search returns, optionally call `web_fetch`",
|
|
588876
|
+
"on the most relevant URL, then synthesize a grounded answer citing",
|
|
588877
|
+
"the source. Decline to answer factual questions if web_search is",
|
|
588878
|
+
"unavailable."
|
|
588879
|
+
].join(" ");
|
|
588880
|
+
const firstSystemIdx = messages2.findIndex((m2) => m2.role === "system");
|
|
588881
|
+
if (firstSystemIdx >= 0 && typeof messages2[firstSystemIdx].content === "string") {
|
|
588882
|
+
messages2[firstSystemIdx] = {
|
|
588883
|
+
...messages2[firstSystemIdx],
|
|
588884
|
+
content: `${SYSTEM_FACTUAL_FIRST}
|
|
588885
|
+
|
|
588886
|
+
${messages2[firstSystemIdx].content}`
|
|
588887
|
+
};
|
|
588888
|
+
} else {
|
|
588889
|
+
messages2.unshift({ role: "system", content: SYSTEM_FACTUAL_FIRST });
|
|
588890
|
+
}
|
|
588891
|
+
}
|
|
588892
|
+
const chatId = `chatcmpl-${randomBytes23(12).toString("hex")}`;
|
|
588893
|
+
const turnsLog = [];
|
|
588894
|
+
for (let turn = 1; turn <= maxTurns; turn++) {
|
|
588895
|
+
if (Date.now() > totalDeadline) {
|
|
588896
|
+
jsonResponse(res, 504, {
|
|
588897
|
+
error: "agent_loop timed out",
|
|
588898
|
+
turn,
|
|
588899
|
+
elapsed_ms: Date.now() - startMs,
|
|
588900
|
+
timeout_s: perReqTimeoutS ?? null
|
|
588901
|
+
});
|
|
588902
|
+
return;
|
|
588903
|
+
}
|
|
588904
|
+
const turnBody = {
|
|
588905
|
+
...requestBody,
|
|
588906
|
+
model: originalModel,
|
|
588907
|
+
messages: messages2,
|
|
588908
|
+
tools: mergedTools.length > 0 ? mergedTools : void 0,
|
|
588909
|
+
stream: false,
|
|
588910
|
+
// Strip our own loop-control fields so they don't confuse the backend
|
|
588911
|
+
agent_loop: void 0,
|
|
588912
|
+
include_daemon_tools: void 0,
|
|
588913
|
+
max_turns: void 0,
|
|
588914
|
+
timeout_s: void 0
|
|
588915
|
+
};
|
|
588916
|
+
for (const k of Object.keys(turnBody)) if (turnBody[k] === void 0) delete turnBody[k];
|
|
588917
|
+
let parsed;
|
|
588918
|
+
try {
|
|
588919
|
+
const path8 = targetType === "vllm" || targetType === "openai" ? "/v1/chat/completions" : "/v1/chat/completions";
|
|
588920
|
+
const result = await ollamaRequest(targetUrl, path8, "POST", JSON.stringify(turnBody), reqTimeoutMs);
|
|
588921
|
+
if (result.status !== 200) {
|
|
588922
|
+
jsonResponse(res, result.status, {
|
|
588923
|
+
error: "Backend request failed during agent_loop",
|
|
588924
|
+
turn,
|
|
588925
|
+
details: result.body.slice(0, 500)
|
|
588926
|
+
});
|
|
588927
|
+
return;
|
|
588928
|
+
}
|
|
588929
|
+
parsed = JSON.parse(result.body);
|
|
588930
|
+
} catch (err) {
|
|
588931
|
+
jsonResponse(res, 502, {
|
|
588932
|
+
error: "Backend proxy error during agent_loop",
|
|
588933
|
+
message: err instanceof Error ? err.message : String(err),
|
|
588934
|
+
turn
|
|
588935
|
+
});
|
|
588936
|
+
return;
|
|
588937
|
+
}
|
|
588938
|
+
const choice = parsed?.choices?.[0];
|
|
588939
|
+
const message2 = choice?.message || { role: "assistant", content: "" };
|
|
588940
|
+
const toolCalls = Array.isArray(message2.tool_calls) ? message2.tool_calls : [];
|
|
588941
|
+
if (toolCalls.length === 0) {
|
|
588942
|
+
jsonResponse(res, 200, {
|
|
588943
|
+
...parsed,
|
|
588944
|
+
id: chatId,
|
|
588945
|
+
_agent_loop: { turns: turn, log: turnsLog, done: true, reason: "model_returned_content" }
|
|
588946
|
+
});
|
|
588947
|
+
return;
|
|
588948
|
+
}
|
|
588949
|
+
const daemonCalls = [];
|
|
588950
|
+
const clientCalls = [];
|
|
588951
|
+
for (const tc of toolCalls) {
|
|
588952
|
+
const name10 = tc?.function?.name ?? tc?.name ?? "";
|
|
588953
|
+
if (advertisedDaemonNames.has(name10)) daemonCalls.push(tc);
|
|
588954
|
+
else clientCalls.push(tc);
|
|
588955
|
+
}
|
|
588956
|
+
if (clientCalls.length > 0) {
|
|
588957
|
+
turnsLog.push({ turn, tool_calls: toolCalls.length, daemon_executed: 0, client_yielded: clientCalls.length });
|
|
588958
|
+
jsonResponse(res, 200, {
|
|
588959
|
+
...parsed,
|
|
588960
|
+
id: chatId,
|
|
588961
|
+
_agent_loop: {
|
|
588962
|
+
turns: turn,
|
|
588963
|
+
log: turnsLog,
|
|
588964
|
+
done: false,
|
|
588965
|
+
reason: "client_tools_pending",
|
|
588966
|
+
pending_tool_calls: clientCalls.length
|
|
588967
|
+
}
|
|
588968
|
+
});
|
|
588969
|
+
return;
|
|
588970
|
+
}
|
|
588971
|
+
messages2.push(message2);
|
|
588972
|
+
let executed = 0;
|
|
588973
|
+
for (const tc of daemonCalls) {
|
|
588974
|
+
const name10 = tc?.function?.name ?? tc?.name ?? "";
|
|
588975
|
+
const argsRaw = tc?.function?.arguments ?? tc?.arguments ?? "{}";
|
|
588976
|
+
let args = {};
|
|
588977
|
+
try {
|
|
588978
|
+
args = typeof argsRaw === "string" ? JSON.parse(argsRaw) : argsRaw || {};
|
|
588979
|
+
} catch {
|
|
588980
|
+
args = {};
|
|
588981
|
+
}
|
|
588982
|
+
const denial = canInvoke({ toolName: name10, origin, scope });
|
|
588983
|
+
if (denial) {
|
|
588984
|
+
messages2.push({
|
|
588985
|
+
role: "tool",
|
|
588986
|
+
tool_call_id: tc.id,
|
|
588987
|
+
name: name10,
|
|
588988
|
+
content: JSON.stringify({ error: denial.reason, status: denial.status })
|
|
588989
|
+
});
|
|
588990
|
+
continue;
|
|
588991
|
+
}
|
|
588992
|
+
const meta = daemonTools.get(name10);
|
|
588993
|
+
if (!meta) {
|
|
588994
|
+
messages2.push({
|
|
588995
|
+
role: "tool",
|
|
588996
|
+
tool_call_id: tc.id,
|
|
588997
|
+
name: name10,
|
|
588998
|
+
content: JSON.stringify({ error: `Daemon tool '${name10}' not found` })
|
|
588999
|
+
});
|
|
589000
|
+
continue;
|
|
589001
|
+
}
|
|
589002
|
+
let tool = null;
|
|
589003
|
+
try {
|
|
589004
|
+
tool = new meta.ToolClass(process.cwd());
|
|
589005
|
+
} catch {
|
|
589006
|
+
try {
|
|
589007
|
+
tool = new meta.ToolClass();
|
|
589008
|
+
} catch {
|
|
589009
|
+
tool = null;
|
|
589010
|
+
}
|
|
589011
|
+
}
|
|
589012
|
+
if (!tool) {
|
|
589013
|
+
messages2.push({
|
|
589014
|
+
role: "tool",
|
|
589015
|
+
tool_call_id: tc.id,
|
|
589016
|
+
name: name10,
|
|
589017
|
+
content: JSON.stringify({ error: `Could not instantiate ${meta.classKey}` })
|
|
589018
|
+
});
|
|
589019
|
+
continue;
|
|
589020
|
+
}
|
|
589021
|
+
let toolResult;
|
|
589022
|
+
try {
|
|
589023
|
+
toolResult = await tool.execute(args);
|
|
589024
|
+
} catch (e2) {
|
|
589025
|
+
toolResult = { success: false, output: "", error: e2 instanceof Error ? e2.message : String(e2), durationMs: 0 };
|
|
589026
|
+
}
|
|
589027
|
+
messages2.push({
|
|
589028
|
+
role: "tool",
|
|
589029
|
+
tool_call_id: tc.id,
|
|
589030
|
+
name: name10,
|
|
589031
|
+
content: JSON.stringify(toolResult)
|
|
589032
|
+
});
|
|
589033
|
+
executed++;
|
|
589034
|
+
}
|
|
589035
|
+
turnsLog.push({ turn, tool_calls: toolCalls.length, daemon_executed: executed, client_yielded: 0 });
|
|
589036
|
+
}
|
|
589037
|
+
jsonResponse(res, 200, {
|
|
589038
|
+
id: chatId,
|
|
589039
|
+
object: "chat.completion",
|
|
589040
|
+
created: Math.floor(Date.now() / 1e3),
|
|
589041
|
+
model,
|
|
589042
|
+
choices: [{
|
|
589043
|
+
index: 0,
|
|
589044
|
+
message: { role: "assistant", content: "[agent_loop reached max_turns without producing a final answer]" },
|
|
589045
|
+
finish_reason: "length"
|
|
589046
|
+
}],
|
|
589047
|
+
_agent_loop: {
|
|
589048
|
+
turns: maxTurns,
|
|
589049
|
+
log: turnsLog,
|
|
589050
|
+
done: false,
|
|
589051
|
+
reason: "max_turns_exhausted",
|
|
589052
|
+
max_turns: maxTurns
|
|
589053
|
+
}
|
|
589054
|
+
});
|
|
589055
|
+
}
|
|
588312
589056
|
async function handleV1ChatCompletions(req2, res, ollamaUrl) {
|
|
588313
589057
|
const body = await parseJsonBody(req2);
|
|
588314
589058
|
if (!body || typeof body !== "object") {
|
|
@@ -588318,6 +589062,18 @@ async function handleV1ChatCompletions(req2, res, ollamaUrl) {
|
|
|
588318
589062
|
const requestBody = body;
|
|
588319
589063
|
const stream = requestBody["stream"] === true;
|
|
588320
589064
|
const model = requestBody["model"] || "unknown";
|
|
589065
|
+
const perReqTimeoutS = typeof requestBody["timeout_s"] === "number" ? requestBody["timeout_s"] : void 0;
|
|
589066
|
+
if (requestBody["agent_loop"] === true) {
|
|
589067
|
+
await runAgentLoopChatCompletions({
|
|
589068
|
+
req: req2,
|
|
589069
|
+
res,
|
|
589070
|
+
ollamaUrl,
|
|
589071
|
+
requestBody,
|
|
589072
|
+
perReqTimeoutS
|
|
589073
|
+
});
|
|
589074
|
+
return;
|
|
589075
|
+
}
|
|
589076
|
+
const reqTimeoutMs = getBackendTimeoutMs(perReqTimeoutS);
|
|
588321
589077
|
const route = resolveModelEndpoint(model);
|
|
588322
589078
|
const targetUrl = route?.endpoint.url ?? ollamaUrl;
|
|
588323
589079
|
const targetType = route?.endpoint.type ?? loadConfig().backendType ?? "ollama";
|
|
@@ -588357,11 +589113,12 @@ async function handleV1ChatCompletions(req2, res, ollamaUrl) {
|
|
|
588357
589113
|
} catch {
|
|
588358
589114
|
}
|
|
588359
589115
|
res.end();
|
|
588360
|
-
}
|
|
589116
|
+
},
|
|
589117
|
+
reqTimeoutMs
|
|
588361
589118
|
);
|
|
588362
589119
|
} else {
|
|
588363
589120
|
try {
|
|
588364
|
-
const result = await ollamaRequest(targetUrl, "/v1/chat/completions", "POST", payload);
|
|
589121
|
+
const result = await ollamaRequest(targetUrl, "/v1/chat/completions", "POST", payload, reqTimeoutMs);
|
|
588365
589122
|
if (result.status !== 200) {
|
|
588366
589123
|
jsonResponse(res, result.status, { error: "Backend request failed", details: result.body });
|
|
588367
589124
|
return;
|
|
@@ -588397,7 +589154,7 @@ async function handleV1ChatCompletions(req2, res, ollamaUrl) {
|
|
|
588397
589154
|
"Cache-Control": "no-cache",
|
|
588398
589155
|
"Connection": "keep-alive"
|
|
588399
589156
|
});
|
|
588400
|
-
const chatId = `chatcmpl-${
|
|
589157
|
+
const chatId = `chatcmpl-${randomBytes23(12).toString("hex")}`;
|
|
588401
589158
|
let buffer2 = "";
|
|
588402
589159
|
ollamaStream(
|
|
588403
589160
|
targetUrl,
|
|
@@ -588439,7 +589196,7 @@ async function handleV1ChatCompletions(req2, res, ollamaUrl) {
|
|
|
588439
589196
|
if (ollamaChunk.message.content) delta.content = ollamaChunk.message.content;
|
|
588440
589197
|
if (ollamaChunk.message.tool_calls) {
|
|
588441
589198
|
delta.tool_calls = ollamaChunk.message.tool_calls.map((tc, idx) => ({
|
|
588442
|
-
id: tc.id || `call_${
|
|
589199
|
+
id: tc.id || `call_${randomBytes23(8).toString("hex")}`,
|
|
588443
589200
|
type: "function",
|
|
588444
589201
|
function: {
|
|
588445
589202
|
name: tc?.function?.name ?? tc?.name ?? "",
|
|
@@ -588501,11 +589258,12 @@ async function handleV1ChatCompletions(req2, res, ollamaUrl) {
|
|
|
588501
589258
|
} catch {
|
|
588502
589259
|
}
|
|
588503
589260
|
res.end();
|
|
588504
|
-
}
|
|
589261
|
+
},
|
|
589262
|
+
reqTimeoutMs
|
|
588505
589263
|
);
|
|
588506
589264
|
} else {
|
|
588507
589265
|
try {
|
|
588508
|
-
const result = await ollamaRequest(targetUrl, "/api/chat", "POST", ollamaPayload);
|
|
589266
|
+
const result = await ollamaRequest(targetUrl, "/api/chat", "POST", ollamaPayload, reqTimeoutMs);
|
|
588509
589267
|
if (result.status !== 200) {
|
|
588510
589268
|
jsonResponse(res, result.status, {
|
|
588511
589269
|
error: "Ollama request failed",
|
|
@@ -588517,14 +589275,14 @@ async function handleV1ChatCompletions(req2, res, ollamaUrl) {
|
|
|
588517
589275
|
if (ollamaResp.eval_count) metrics.totalTokensOut += ollamaResp.eval_count;
|
|
588518
589276
|
if (ollamaResp.prompt_eval_count) metrics.totalTokensIn += ollamaResp.prompt_eval_count;
|
|
588519
589277
|
trackTokens("local", ollamaResp.prompt_eval_count ?? 0, ollamaResp.eval_count ?? 0);
|
|
588520
|
-
const chatId = `chatcmpl-${
|
|
589278
|
+
const chatId = `chatcmpl-${randomBytes23(12).toString("hex")}`;
|
|
588521
589279
|
const responseMessage = {
|
|
588522
589280
|
role: ollamaResp.message?.role ?? "assistant",
|
|
588523
589281
|
content: ollamaResp.message?.content ?? ""
|
|
588524
589282
|
};
|
|
588525
589283
|
if (ollamaResp.message?.tool_calls && ollamaResp.message.tool_calls.length > 0) {
|
|
588526
589284
|
responseMessage.tool_calls = ollamaResp.message.tool_calls.map((tc, idx) => ({
|
|
588527
|
-
id: tc.id || `call_${
|
|
589285
|
+
id: tc.id || `call_${randomBytes23(8).toString("hex")}`,
|
|
588528
589286
|
type: "function",
|
|
588529
589287
|
function: {
|
|
588530
589288
|
name: tc?.function?.name ?? tc?.name ?? "",
|
|
@@ -588997,27 +589755,27 @@ ${task}` : task;
|
|
|
588997
589755
|
});
|
|
588998
589756
|
}
|
|
588999
589757
|
function updateStateFile() {
|
|
589000
|
-
return
|
|
589758
|
+
return join115(homedir41(), ".open-agents", "update-state.json");
|
|
589001
589759
|
}
|
|
589002
589760
|
function updateLogPath() {
|
|
589003
|
-
return
|
|
589761
|
+
return join115(homedir41(), ".open-agents", "update.log");
|
|
589004
589762
|
}
|
|
589005
589763
|
function readUpdateState() {
|
|
589006
589764
|
try {
|
|
589007
589765
|
const p2 = updateStateFile();
|
|
589008
|
-
if (!
|
|
589009
|
-
return JSON.parse(
|
|
589766
|
+
if (!existsSync99(p2)) return null;
|
|
589767
|
+
return JSON.parse(readFileSync80(p2, "utf-8"));
|
|
589010
589768
|
} catch {
|
|
589011
589769
|
return null;
|
|
589012
589770
|
}
|
|
589013
589771
|
}
|
|
589014
589772
|
function writeUpdateState(state) {
|
|
589015
589773
|
try {
|
|
589016
|
-
const dir =
|
|
589017
|
-
|
|
589774
|
+
const dir = join115(homedir41(), ".open-agents");
|
|
589775
|
+
mkdirSync63(dir, { recursive: true });
|
|
589018
589776
|
const finalPath = updateStateFile();
|
|
589019
589777
|
const tmpPath = `${finalPath}.tmp.${process.pid}`;
|
|
589020
|
-
|
|
589778
|
+
writeFileSync55(tmpPath, JSON.stringify(state, null, 2), "utf-8");
|
|
589021
589779
|
renameSync8(tmpPath, finalPath);
|
|
589022
589780
|
} catch {
|
|
589023
589781
|
}
|
|
@@ -589061,15 +589819,15 @@ async function handleV1Update(req2, res, requestId) {
|
|
|
589061
589819
|
const { execSync: es } = require3("node:child_process");
|
|
589062
589820
|
const isWin2 = process.platform === "win32";
|
|
589063
589821
|
let npmBin = "";
|
|
589064
|
-
for (const candidate of isWin2 ? [
|
|
589065
|
-
if (
|
|
589822
|
+
for (const candidate of isWin2 ? [join115(nodeDir, "npm.cmd"), join115(nodeDir, "npm")] : [join115(nodeDir, "npm"), "/usr/local/bin/npm", "/usr/bin/npm"]) {
|
|
589823
|
+
if (existsSync99(candidate)) {
|
|
589066
589824
|
npmBin = candidate;
|
|
589067
589825
|
break;
|
|
589068
589826
|
}
|
|
589069
589827
|
}
|
|
589070
589828
|
if (!npmBin) npmBin = isWin2 ? "npm.cmd" : "npm";
|
|
589071
589829
|
const pkgSpec = `open-agents-ai@${targetVersion}`;
|
|
589072
|
-
const dir =
|
|
589830
|
+
const dir = join115(homedir41(), ".open-agents");
|
|
589073
589831
|
fs7.mkdirSync(dir, { recursive: true });
|
|
589074
589832
|
const logFd = fs7.openSync(logPath3, "w");
|
|
589075
589833
|
const npmPrefix = dirname35(nodeDir);
|
|
@@ -589079,13 +589837,13 @@ async function handleV1Update(req2, res, requestId) {
|
|
|
589079
589837
|
globalBinDir = es(`${npmBin} bin -g`, { encoding: "utf8", timeout: 5e3, stdio: "pipe" }).trim();
|
|
589080
589838
|
} else {
|
|
589081
589839
|
const npmCliCandidates = [
|
|
589082
|
-
|
|
589083
|
-
|
|
589840
|
+
join115(nodeDir, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js"),
|
|
589841
|
+
join115(npmBin, "..", "..", "lib", "node_modules", "npm", "bin", "npm-cli.js")
|
|
589084
589842
|
];
|
|
589085
589843
|
let npmCli = "";
|
|
589086
589844
|
for (const c9 of npmCliCandidates) {
|
|
589087
589845
|
try {
|
|
589088
|
-
if (
|
|
589846
|
+
if (existsSync99(c9)) {
|
|
589089
589847
|
npmCli = c9;
|
|
589090
589848
|
break;
|
|
589091
589849
|
}
|
|
@@ -589117,13 +589875,13 @@ async function handleV1Update(req2, res, requestId) {
|
|
|
589117
589875
|
});
|
|
589118
589876
|
} else {
|
|
589119
589877
|
const npmCliCandidates = [
|
|
589120
|
-
|
|
589121
|
-
|
|
589878
|
+
join115(nodeDir, "..", "lib", "node_modules", "npm", "bin", "npm-cli.js"),
|
|
589879
|
+
join115(npmBin, "..", "..", "lib", "node_modules", "npm", "bin", "npm-cli.js")
|
|
589122
589880
|
];
|
|
589123
589881
|
let npmCli = "";
|
|
589124
589882
|
for (const c9 of npmCliCandidates) {
|
|
589125
589883
|
try {
|
|
589126
|
-
if (
|
|
589884
|
+
if (existsSync99(c9)) {
|
|
589127
589885
|
npmCli = c9;
|
|
589128
589886
|
break;
|
|
589129
589887
|
}
|
|
@@ -589220,8 +589978,8 @@ function handleV1UpdateStatus(res) {
|
|
|
589220
589978
|
let logTail = "";
|
|
589221
589979
|
let exitCode = null;
|
|
589222
589980
|
try {
|
|
589223
|
-
if (
|
|
589224
|
-
const raw =
|
|
589981
|
+
if (existsSync99(logPath3)) {
|
|
589982
|
+
const raw = readFileSync80(logPath3, "utf-8");
|
|
589225
589983
|
const m2 = raw.match(/__EXIT_CODE=(\d+)/);
|
|
589226
589984
|
if (m2) exitCode = parseInt(m2[1], 10);
|
|
589227
589985
|
logTail = raw.slice(-2e3);
|
|
@@ -589309,7 +590067,7 @@ async function handleV1Run(req2, res) {
|
|
|
589309
590067
|
return;
|
|
589310
590068
|
}
|
|
589311
590069
|
}
|
|
589312
|
-
const id = `job-${
|
|
590070
|
+
const id = `job-${randomBytes23(8).toString("hex")}`;
|
|
589313
590071
|
const dir = jobsDir();
|
|
589314
590072
|
const workingDir = requestBody["working_directory"] || req2.headers["x-working-directory"];
|
|
589315
590073
|
const isolate = requestBody["isolate"] === true;
|
|
@@ -589317,8 +590075,8 @@ async function handleV1Run(req2, res) {
|
|
|
589317
590075
|
if (workingDir) {
|
|
589318
590076
|
cwd4 = resolve38(workingDir);
|
|
589319
590077
|
} else if (isolate) {
|
|
589320
|
-
const wsDir =
|
|
589321
|
-
|
|
590078
|
+
const wsDir = join115(dir, "..", "workspaces", id);
|
|
590079
|
+
mkdirSync63(wsDir, { recursive: true });
|
|
589322
590080
|
cwd4 = wsDir;
|
|
589323
590081
|
} else {
|
|
589324
590082
|
cwd4 = resolve38(process.cwd());
|
|
@@ -589460,7 +590218,7 @@ async function handleV1Run(req2, res) {
|
|
|
589460
590218
|
let output = "";
|
|
589461
590219
|
let tailBytes = 0;
|
|
589462
590220
|
const TAIL_BUDGET = 1048576;
|
|
589463
|
-
const outputWriter = new DiskTaskOutput(
|
|
590221
|
+
const outputWriter = new DiskTaskOutput(join115(dir, `${id}.output`));
|
|
589464
590222
|
job.outputFile = outputWriter.path;
|
|
589465
590223
|
atomicJobWrite(dir, id, job);
|
|
589466
590224
|
child.stdout?.on("data", (chunk) => {
|
|
@@ -590353,10 +591111,10 @@ async function handleRequest(req2, res, ollamaUrl, verbose) {
|
|
|
590353
591111
|
return;
|
|
590354
591112
|
}
|
|
590355
591113
|
const { tmpdir: tmpdir22 } = await import("node:os");
|
|
590356
|
-
const { writeFileSync:
|
|
591114
|
+
const { writeFileSync: writeFileSync59, unlinkSync: unlinkSync25 } = await import("node:fs");
|
|
590357
591115
|
const { join: pjoin } = await import("node:path");
|
|
590358
591116
|
const tmpPath = pjoin(tmpdir22(), `oa-clone-upload-${Date.now()}-${safeName}`);
|
|
590359
|
-
|
|
591117
|
+
writeFileSync59(tmpPath, buf);
|
|
590360
591118
|
try {
|
|
590361
591119
|
const ve = getVoiceEngine();
|
|
590362
591120
|
const msg = await ve.setCloneVoice(tmpPath);
|
|
@@ -590906,7 +591664,7 @@ data: ${JSON.stringify(data)}
|
|
|
590906
591664
|
}
|
|
590907
591665
|
for (const f2 of seenFiles) {
|
|
590908
591666
|
try {
|
|
590909
|
-
|
|
591667
|
+
writeFileSync55(f2, JSON.stringify({ tasks: [] }, null, 2));
|
|
590910
591668
|
deleted++;
|
|
590911
591669
|
} catch {
|
|
590912
591670
|
}
|
|
@@ -591968,7 +592726,7 @@ ${steering}`;
|
|
|
591968
592726
|
function getScheduleRoots() {
|
|
591969
592727
|
const rootsEnv = process.env["OA_SCHEDULE_ROOTS"] || "";
|
|
591970
592728
|
const roots = rootsEnv.split(rootsEnv.includes(";") ? ";" : ":").filter(Boolean);
|
|
591971
|
-
const defaults3 = [process.cwd(),
|
|
592729
|
+
const defaults3 = [process.cwd(), join115(homedir41(), "Documents")];
|
|
591972
592730
|
const set = /* @__PURE__ */ new Set([...defaults3, ...roots]);
|
|
591973
592731
|
return [...set];
|
|
591974
592732
|
}
|
|
@@ -591980,10 +592738,10 @@ function listScheduledTasks() {
|
|
|
591980
592738
|
for (const root of roots) {
|
|
591981
592739
|
try {
|
|
591982
592740
|
walk(root, 0, (dir) => {
|
|
591983
|
-
if (dir.endsWith(`${
|
|
591984
|
-
const file =
|
|
592741
|
+
if (dir.endsWith(`${join115(".oa", "scheduled")}`) || dir.includes(`${join115(".oa", "scheduled")}`)) {
|
|
592742
|
+
const file = join115(dir, "tasks.json");
|
|
591985
592743
|
try {
|
|
591986
|
-
const raw =
|
|
592744
|
+
const raw = readFileSync80(file, "utf-8");
|
|
591987
592745
|
const json = JSON.parse(raw);
|
|
591988
592746
|
const tasks = Array.isArray(json?.tasks) ? json.tasks : Array.isArray(json) ? json : [];
|
|
591989
592747
|
tasks.forEach((t2, i2) => {
|
|
@@ -592048,7 +592806,7 @@ function walk(dir, depth, onDir, maxDepth) {
|
|
|
592048
592806
|
if (e2.name === "node_modules" || e2.name.startsWith(".")) {
|
|
592049
592807
|
if (e2.name !== ".oa") continue;
|
|
592050
592808
|
}
|
|
592051
|
-
const child =
|
|
592809
|
+
const child = join115(dir, e2.name);
|
|
592052
592810
|
walk(child, depth + 1, onDir, maxDepth);
|
|
592053
592811
|
}
|
|
592054
592812
|
}
|
|
@@ -592057,18 +592815,18 @@ function setScheduledEnabled(id, enabled2) {
|
|
|
592057
592815
|
const target = tasks.find((t2) => t2.id === id);
|
|
592058
592816
|
if (!target) return false;
|
|
592059
592817
|
try {
|
|
592060
|
-
const raw =
|
|
592818
|
+
const raw = readFileSync80(target.file, "utf-8");
|
|
592061
592819
|
const json = JSON.parse(raw);
|
|
592062
592820
|
const arr = Array.isArray(json?.tasks) ? json.tasks : Array.isArray(json) ? json : [];
|
|
592063
592821
|
if (!arr[target.index]) return false;
|
|
592064
592822
|
arr[target.index].enabled = enabled2;
|
|
592065
592823
|
if (Array.isArray(json?.tasks)) {
|
|
592066
592824
|
json.tasks = arr;
|
|
592067
|
-
|
|
592825
|
+
writeFileSync55(target.file, JSON.stringify(json, null, 2));
|
|
592068
592826
|
} else if (Array.isArray(json)) {
|
|
592069
|
-
|
|
592827
|
+
writeFileSync55(target.file, JSON.stringify(arr, null, 2));
|
|
592070
592828
|
} else {
|
|
592071
|
-
|
|
592829
|
+
writeFileSync55(target.file, JSON.stringify({ tasks: arr }, null, 2));
|
|
592072
592830
|
}
|
|
592073
592831
|
if (!enabled2) {
|
|
592074
592832
|
try {
|
|
@@ -592090,7 +592848,7 @@ function deleteScheduledById(id) {
|
|
|
592090
592848
|
const target = tasks.find((t2) => t2.id === id);
|
|
592091
592849
|
if (!target) return false;
|
|
592092
592850
|
try {
|
|
592093
|
-
const raw =
|
|
592851
|
+
const raw = readFileSync80(target.file, "utf-8");
|
|
592094
592852
|
const json = JSON.parse(raw);
|
|
592095
592853
|
const arr = Array.isArray(json?.tasks) ? json.tasks : Array.isArray(json) ? json : [];
|
|
592096
592854
|
if (!arr[target.index]) return false;
|
|
@@ -592098,11 +592856,11 @@ function deleteScheduledById(id) {
|
|
|
592098
592856
|
arr.splice(target.index, 1);
|
|
592099
592857
|
if (Array.isArray(json?.tasks)) {
|
|
592100
592858
|
json.tasks = arr;
|
|
592101
|
-
|
|
592859
|
+
writeFileSync55(target.file, JSON.stringify(json, null, 2));
|
|
592102
592860
|
} else if (Array.isArray(json)) {
|
|
592103
|
-
|
|
592861
|
+
writeFileSync55(target.file, JSON.stringify(arr, null, 2));
|
|
592104
592862
|
} else {
|
|
592105
|
-
|
|
592863
|
+
writeFileSync55(target.file, JSON.stringify({ tasks: arr }, null, 2));
|
|
592106
592864
|
}
|
|
592107
592865
|
const candidates = [];
|
|
592108
592866
|
if (id) candidates.push(id);
|
|
@@ -592355,11 +593113,11 @@ function reconcileScheduledTasks(apply) {
|
|
|
592355
593113
|
const errors = [];
|
|
592356
593114
|
for (const f2 of found) {
|
|
592357
593115
|
const wdir = f2.workingDir || process.cwd();
|
|
592358
|
-
const file =
|
|
593116
|
+
const file = join115(wdir, ".oa", "scheduled", "tasks.json");
|
|
592359
593117
|
try {
|
|
592360
593118
|
let json = { tasks: [] };
|
|
592361
593119
|
try {
|
|
592362
|
-
const raw =
|
|
593120
|
+
const raw = readFileSync80(file, "utf-8");
|
|
592363
593121
|
json = JSON.parse(raw);
|
|
592364
593122
|
} catch {
|
|
592365
593123
|
}
|
|
@@ -592370,9 +593128,9 @@ function reconcileScheduledTasks(apply) {
|
|
|
592370
593128
|
const entry = { task: f2.task || `legacy ${f2.id}`, schedule: f2.cron, enabled: true };
|
|
592371
593129
|
arr.push(entry);
|
|
592372
593130
|
const toWrite = Array.isArray(json?.tasks) ? { ...json, tasks: arr } : Array.isArray(json) ? arr : { tasks: arr };
|
|
592373
|
-
|
|
592374
|
-
|
|
592375
|
-
|
|
593131
|
+
mkdirSync63(join115(wdir, ".oa", "scheduled"), { recursive: true });
|
|
593132
|
+
mkdirSync63(join115(wdir, ".oa", "scheduled", "logs"), { recursive: true });
|
|
593133
|
+
writeFileSync55(file, JSON.stringify(toWrite, null, 2));
|
|
592376
593134
|
adopted.push({ file, index: arr.length - 1 });
|
|
592377
593135
|
}
|
|
592378
593136
|
} else {
|
|
@@ -592416,32 +593174,32 @@ function writeCrontabLines(lines) {
|
|
|
592416
593174
|
}
|
|
592417
593175
|
function canonicalCronLine(rec) {
|
|
592418
593176
|
const oaBin = findOaBinary4();
|
|
592419
|
-
const logDir =
|
|
592420
|
-
const logFile =
|
|
592421
|
-
const storeFile =
|
|
593177
|
+
const logDir = join115(rec.workingDir, ".oa", "scheduled", "logs");
|
|
593178
|
+
const logFile = join115(logDir, `${rec.id}.log`);
|
|
593179
|
+
const storeFile = join115(rec.workingDir, ".oa", "scheduled", "tasks.json");
|
|
592422
593180
|
const taskEsc = rec.task.replace(/'/g, "'\\''");
|
|
592423
|
-
const lockDir =
|
|
592424
|
-
const lockPath =
|
|
593181
|
+
const lockDir = join115(rec.workingDir, ".oa", "run");
|
|
593182
|
+
const lockPath = join115(lockDir, `${rec.id}.lock`);
|
|
592425
593183
|
const wrapper = [
|
|
592426
593184
|
`cd ${JSON.stringify(rec.workingDir)}`,
|
|
592427
593185
|
`mkdir -p ${JSON.stringify(logDir)}`,
|
|
592428
593186
|
`mkdir -p ${JSON.stringify(lockDir)}`,
|
|
592429
593187
|
`if mkdir ${JSON.stringify(lockPath)} 2>/dev/null; then`,
|
|
592430
|
-
` echo $$ > ${JSON.stringify(
|
|
593188
|
+
` echo $$ > ${JSON.stringify(join115(lockPath, "pid"))}`,
|
|
592431
593189
|
` trap 'rm -rf ${lockPath}' EXIT`,
|
|
592432
593190
|
`else`,
|
|
592433
|
-
` if [ -f ${JSON.stringify(
|
|
592434
|
-
` oldpid=$(cat ${JSON.stringify(
|
|
593191
|
+
` if [ -f ${JSON.stringify(join115(lockPath, "pid"))} ]; then`,
|
|
593192
|
+
` oldpid=$(cat ${JSON.stringify(join115(lockPath, "pid"))} 2>/dev/null || echo)`,
|
|
592435
593193
|
` if [ -n "$oldpid" ] && kill -0 "$oldpid" 2>/dev/null; then`,
|
|
592436
593194
|
` echo "[oa-scheduler] ${rec.id} already running as PID $oldpid; skipping" >> ${JSON.stringify(logFile)}`,
|
|
592437
593195
|
` exit 0`,
|
|
592438
593196
|
` else`,
|
|
592439
593197
|
` rm -rf ${JSON.stringify(lockPath)} 2>/dev/null || true`,
|
|
592440
|
-
` mkdir -p ${JSON.stringify(lockPath)} && echo $$ > ${JSON.stringify(
|
|
593198
|
+
` mkdir -p ${JSON.stringify(lockPath)} && echo $$ > ${JSON.stringify(join115(lockPath, "pid"))} && trap 'rm -rf ${lockPath}' EXIT`,
|
|
592441
593199
|
` fi`,
|
|
592442
593200
|
` else`,
|
|
592443
593201
|
` rm -rf ${JSON.stringify(lockPath)} 2>/dev/null || true`,
|
|
592444
|
-
` mkdir -p ${JSON.stringify(lockPath)} && echo $$ > ${JSON.stringify(
|
|
593202
|
+
` mkdir -p ${JSON.stringify(lockPath)} && echo $$ > ${JSON.stringify(join115(lockPath, "pid"))} && trap 'rm -rf ${lockPath}' EXIT`,
|
|
592445
593203
|
` fi`,
|
|
592446
593204
|
`fi`,
|
|
592447
593205
|
`${oaBin} '${taskEsc}' >> ${JSON.stringify(logFile)} 2>&1; _oa_exit=$?`,
|
|
@@ -592473,9 +593231,9 @@ function fixupOrMigrateScheduled(mode, dryRun) {
|
|
|
592473
593231
|
try {
|
|
592474
593232
|
if (!f2.workingDir || !f2.task) continue;
|
|
592475
593233
|
const unitBase = `oa-${f2.id}`;
|
|
592476
|
-
const unitDir =
|
|
592477
|
-
const svc =
|
|
592478
|
-
const tim =
|
|
593234
|
+
const unitDir = join115(homedir41(), ".config", "systemd", "user");
|
|
593235
|
+
const svc = join115(unitDir, `${unitBase}.service`);
|
|
593236
|
+
const tim = join115(unitDir, `${unitBase}.timer`);
|
|
592479
593237
|
const oaBin = findOaBinary4();
|
|
592480
593238
|
const rec = { id: f2.id, cron: f2.cron, workingDir: f2.workingDir, task: f2.task };
|
|
592481
593239
|
const cmd = canonicalCronLine(rec).split(" ").slice(5).join(" ");
|
|
@@ -592505,9 +593263,9 @@ Persistent=true
|
|
|
592505
593263
|
WantedBy=timers.target
|
|
592506
593264
|
`;
|
|
592507
593265
|
if (!dryRun) {
|
|
592508
|
-
|
|
592509
|
-
|
|
592510
|
-
|
|
593266
|
+
mkdirSync63(unitDir, { recursive: true });
|
|
593267
|
+
writeFileSync55(svc, svcText);
|
|
593268
|
+
writeFileSync55(tim, timText);
|
|
592511
593269
|
try {
|
|
592512
593270
|
const { execSync: es } = require3("node:child_process");
|
|
592513
593271
|
es("systemctl --user daemon-reload", { stdio: "pipe" });
|
|
@@ -592601,8 +593359,8 @@ function startApiServer(options2 = {}) {
|
|
|
592601
593359
|
const config = loadConfig();
|
|
592602
593360
|
const ollamaUrl = options2.ollamaUrl ?? config.backendUrl;
|
|
592603
593361
|
const cwd4 = process.cwd();
|
|
592604
|
-
initAuditLog(
|
|
592605
|
-
initUsageTracker(
|
|
593362
|
+
initAuditLog(join115(cwd4, ".oa"));
|
|
593363
|
+
initUsageTracker(join115(cwd4, ".oa"));
|
|
592606
593364
|
try {
|
|
592607
593365
|
const taskMgr = getSharedTaskManager();
|
|
592608
593366
|
taskMgr.setEventPublisher((type, data, opts) => {
|
|
@@ -592644,7 +593402,7 @@ function startApiServer(options2 = {}) {
|
|
|
592644
593402
|
try {
|
|
592645
593403
|
const dir = todoDir();
|
|
592646
593404
|
try {
|
|
592647
|
-
|
|
593405
|
+
mkdirSync63(dir, { recursive: true });
|
|
592648
593406
|
} catch {
|
|
592649
593407
|
}
|
|
592650
593408
|
const cache8 = /* @__PURE__ */ new Map();
|
|
@@ -592653,7 +593411,7 @@ function startApiServer(options2 = {}) {
|
|
|
592653
593411
|
if (!f2.endsWith(".json") || f2.includes(".tmp.")) continue;
|
|
592654
593412
|
const sid = f2.replace(/\.json$/, "");
|
|
592655
593413
|
try {
|
|
592656
|
-
const items = JSON.parse(
|
|
593414
|
+
const items = JSON.parse(readFileSync80(join115(dir, f2), "utf-8"));
|
|
592657
593415
|
if (Array.isArray(items)) {
|
|
592658
593416
|
cache8.set(sid, new Map(items.map((t2) => [t2.id, t2])));
|
|
592659
593417
|
}
|
|
@@ -592665,10 +593423,10 @@ function startApiServer(options2 = {}) {
|
|
|
592665
593423
|
const watcher = fsWatch3(dir, (_evt, fname) => {
|
|
592666
593424
|
if (!fname || !fname.endsWith(".json") || fname.includes(".tmp.")) return;
|
|
592667
593425
|
const sid = fname.replace(/\.json$/, "");
|
|
592668
|
-
const fp =
|
|
593426
|
+
const fp = join115(dir, fname);
|
|
592669
593427
|
let next = [];
|
|
592670
593428
|
try {
|
|
592671
|
-
if (!
|
|
593429
|
+
if (!existsSync99(fp)) {
|
|
592672
593430
|
const old = cache8.get(sid);
|
|
592673
593431
|
if (old) {
|
|
592674
593432
|
for (const t2 of old.values()) {
|
|
@@ -592681,7 +593439,7 @@ function startApiServer(options2 = {}) {
|
|
|
592681
593439
|
}
|
|
592682
593440
|
return;
|
|
592683
593441
|
}
|
|
592684
|
-
next = JSON.parse(
|
|
593442
|
+
next = JSON.parse(readFileSync80(fp, "utf-8"));
|
|
592685
593443
|
if (!Array.isArray(next)) return;
|
|
592686
593444
|
} catch {
|
|
592687
593445
|
return;
|
|
@@ -592720,14 +593478,14 @@ function startApiServer(options2 = {}) {
|
|
|
592720
593478
|
const retentionDays = parseInt(process.env["OA_JOB_RETENTION_DAYS"] ?? "30", 10);
|
|
592721
593479
|
if (retentionDays > 0) {
|
|
592722
593480
|
try {
|
|
592723
|
-
const jobsDir3 =
|
|
592724
|
-
if (
|
|
593481
|
+
const jobsDir3 = join115(cwd4, ".oa", "jobs");
|
|
593482
|
+
if (existsSync99(jobsDir3)) {
|
|
592725
593483
|
const cutoff = Date.now() - retentionDays * 864e5;
|
|
592726
593484
|
for (const f2 of readdirSync34(jobsDir3)) {
|
|
592727
593485
|
if (!f2.endsWith(".json")) continue;
|
|
592728
593486
|
try {
|
|
592729
|
-
const jobPath =
|
|
592730
|
-
const job = JSON.parse(
|
|
593487
|
+
const jobPath = join115(jobsDir3, f2);
|
|
593488
|
+
const job = JSON.parse(readFileSync80(jobPath, "utf-8"));
|
|
592731
593489
|
const jobTime = new Date(job.startedAt ?? job.completedAt ?? 0).getTime();
|
|
592732
593490
|
if (jobTime > 0 && jobTime < cutoff && job.status !== "running") {
|
|
592733
593491
|
const { unlinkSync: unlinkSync25 } = require3("node:fs");
|
|
@@ -592747,8 +593505,8 @@ function startApiServer(options2 = {}) {
|
|
|
592747
593505
|
if (useTls) {
|
|
592748
593506
|
try {
|
|
592749
593507
|
tlsOpts = {
|
|
592750
|
-
cert:
|
|
592751
|
-
key:
|
|
593508
|
+
cert: readFileSync80(resolve38(tlsCert)),
|
|
593509
|
+
key: readFileSync80(resolve38(tlsKey))
|
|
592752
593510
|
};
|
|
592753
593511
|
} catch (e2) {
|
|
592754
593512
|
log22(`
|
|
@@ -592759,9 +593517,9 @@ function startApiServer(options2 = {}) {
|
|
|
592759
593517
|
}
|
|
592760
593518
|
let runtimeAccessMode = resolveAccessMode(process.env["OA_ACCESS"], host);
|
|
592761
593519
|
try {
|
|
592762
|
-
const accessFile =
|
|
592763
|
-
if (
|
|
592764
|
-
const persisted =
|
|
593520
|
+
const accessFile = join115(homedir41(), ".open-agents", "access");
|
|
593521
|
+
if (existsSync99(accessFile)) {
|
|
593522
|
+
const persisted = readFileSync80(accessFile, "utf8").trim();
|
|
592765
593523
|
const resolved = resolveAccessMode(persisted, host);
|
|
592766
593524
|
if (resolved) runtimeAccessMode = resolved;
|
|
592767
593525
|
}
|
|
@@ -592814,9 +593572,9 @@ function startApiServer(options2 = {}) {
|
|
|
592814
593572
|
const previous = runtimeAccessMode;
|
|
592815
593573
|
runtimeAccessMode = requested;
|
|
592816
593574
|
try {
|
|
592817
|
-
const dir =
|
|
592818
|
-
|
|
592819
|
-
|
|
593575
|
+
const dir = join115(homedir41(), ".open-agents");
|
|
593576
|
+
mkdirSync63(dir, { recursive: true });
|
|
593577
|
+
writeFileSync55(join115(dir, "access"), `${runtimeAccessMode}
|
|
592820
593578
|
`, "utf8");
|
|
592821
593579
|
} catch {
|
|
592822
593580
|
}
|
|
@@ -593029,9 +593787,9 @@ function startApiServer(options2 = {}) {
|
|
|
593029
593787
|
try {
|
|
593030
593788
|
const { startEmbeddingWorkers: startEmbeddingWorkers2 } = await Promise.resolve().then(() => (init_embedding_workers(), embedding_workers_exports));
|
|
593031
593789
|
const { ensureEmbedDeps: ensureEmbedDeps2, runEmbedImage: runEmbedImage2, runEmbedAudio: runEmbedAudio2 } = await Promise.resolve().then(() => (init_py_embed(), py_embed_exports));
|
|
593032
|
-
const dbBase =
|
|
593033
|
-
const epStore = new mem.EpisodeStore(
|
|
593034
|
-
const kg = new mem.TemporalGraph(
|
|
593790
|
+
const dbBase = join115(cwd4, ".oa");
|
|
593791
|
+
const epStore = new mem.EpisodeStore(join115(dbBase, "memory.db"));
|
|
593792
|
+
const kg = new mem.TemporalGraph(join115(dbBase, "kg.db"));
|
|
593035
593793
|
try {
|
|
593036
593794
|
ensureEmbedDeps2();
|
|
593037
593795
|
} catch {
|
|
@@ -593108,6 +593866,24 @@ function startApiServer(options2 = {}) {
|
|
|
593108
593866
|
`);
|
|
593109
593867
|
log22(` Primary: ${config.backendUrl} (${config.backendType || "ollama"})
|
|
593110
593868
|
`);
|
|
593869
|
+
const _retCheck = process.env["OA_RUN_RETENTION_H"];
|
|
593870
|
+
const _retOff = _retCheck === "0";
|
|
593871
|
+
if (!_retOff) {
|
|
593872
|
+
try {
|
|
593873
|
+
const initial = pruneOldJobs();
|
|
593874
|
+
if (initial.pruned > 0) {
|
|
593875
|
+
log22(` Run GC: pruned ${initial.pruned} old job records (kept ${initial.kept}).
|
|
593876
|
+
`);
|
|
593877
|
+
}
|
|
593878
|
+
} catch {
|
|
593879
|
+
}
|
|
593880
|
+
setInterval(() => {
|
|
593881
|
+
try {
|
|
593882
|
+
pruneOldJobs();
|
|
593883
|
+
} catch {
|
|
593884
|
+
}
|
|
593885
|
+
}, 36e5).unref();
|
|
593886
|
+
}
|
|
593111
593887
|
if (process.env["OA_API_KEYS"]) {
|
|
593112
593888
|
const keyCount = process.env["OA_API_KEYS"].split(",").length;
|
|
593113
593889
|
log22(` Auth: ${keyCount} scoped key(s) (read/run/admin)
|
|
@@ -593228,10 +594004,10 @@ async function handleMemoryIngest(req2, res, ollamaUrl) {
|
|
|
593228
594004
|
const labels = Array.isArray(b.labels) ? b.labels : [];
|
|
593229
594005
|
const mediaPath = typeof b.media_path === "string" ? b.media_path : void 0;
|
|
593230
594006
|
const cwd4 = process.cwd();
|
|
593231
|
-
const dbBase =
|
|
594007
|
+
const dbBase = join115(cwd4, ".oa");
|
|
593232
594008
|
const { EpisodeStore: EpisodeStore3, TemporalGraph: TemporalGraph3 } = await Promise.resolve().then(() => (init_dist7(), dist_exports2));
|
|
593233
|
-
const epStore = new EpisodeStore3(
|
|
593234
|
-
const kg = new TemporalGraph3(
|
|
594009
|
+
const epStore = new EpisodeStore3(join115(dbBase, "memory.db"));
|
|
594010
|
+
const kg = new TemporalGraph3(join115(dbBase, "kg.db"));
|
|
593235
594011
|
const meta = {};
|
|
593236
594012
|
if (mediaPath) meta.media_path = mediaPath;
|
|
593237
594013
|
const epId = epStore.insert({ modality, content: content || (mediaPath || ""), metadata: meta, toolName: "memory_ingest" });
|
|
@@ -593298,7 +594074,7 @@ async function handleEntitiesList(req2, res) {
|
|
|
593298
594074
|
const type = url.searchParams.get("type") || "person";
|
|
593299
594075
|
const limit = Math.max(1, Math.min(1e3, parseInt(url.searchParams.get("limit") || "100", 10)));
|
|
593300
594076
|
const { TemporalGraph: TemporalGraph3 } = await Promise.resolve().then(() => (init_dist7(), dist_exports2));
|
|
593301
|
-
const kg = new TemporalGraph3(
|
|
594077
|
+
const kg = new TemporalGraph3(join115(process.cwd(), ".oa", "kg.db"));
|
|
593302
594078
|
const nodes = kg.nodesByType(type, limit).map((n2) => ({ id: n2.id, text: n2.text, mentionCount: n2.mentionCount, firstSeen: n2.firstSeen, lastSeen: n2.lastSeen }));
|
|
593303
594079
|
jsonResponse(res, 200, { object: "list", data: nodes });
|
|
593304
594080
|
} catch (err) {
|
|
@@ -593320,7 +594096,7 @@ async function handleMemorySearch2(req2, res) {
|
|
|
593320
594096
|
const wLex = typeof b.lexical_weight === "number" ? b.lexical_weight : 1;
|
|
593321
594097
|
const wEmb = typeof b.embedding_weight === "number" ? b.embedding_weight : 1;
|
|
593322
594098
|
const { EpisodeStore: EpisodeStore3 } = await Promise.resolve().then(() => (init_dist7(), dist_exports2));
|
|
593323
|
-
const epStore = new EpisodeStore3(
|
|
594099
|
+
const epStore = new EpisodeStore3(join115(process.cwd(), ".oa", "memory.db"));
|
|
593324
594100
|
const results = epStore.search({ query, modality, limit }, { queryEmbedding: qEmb, lexicalWeight: wLex, embeddingWeight: wEmb });
|
|
593325
594101
|
jsonResponse(res, 200, { object: "list", data: results.map((e2) => ({ id: e2.id, modality: e2.modality, content: e2.content, timestamp: e2.timestamp })) });
|
|
593326
594102
|
} catch (err) {
|
|
@@ -593387,7 +594163,7 @@ function setTimerEnabled(name10, enabled2) {
|
|
|
593387
594163
|
return false;
|
|
593388
594164
|
}
|
|
593389
594165
|
}
|
|
593390
|
-
var require3, endpointRegistry, modelRouteMap, endpointUsage, metrics, startedAt, runningProcesses, perKeyUsage, CRON_MARKER2;
|
|
594166
|
+
var require3, endpointRegistry, modelRouteMap, endpointUsage, BACKEND_TIMEOUT_DEFAULT_MS, BACKEND_TIMEOUT_MAX_MS, metrics, startedAt, runningProcesses, perKeyUsage, CRON_MARKER2;
|
|
593391
594167
|
var init_serve = __esm({
|
|
593392
594168
|
"packages/cli/src/api/serve.ts"() {
|
|
593393
594169
|
"use strict";
|
|
@@ -593419,6 +594195,8 @@ var init_serve = __esm({
|
|
|
593419
594195
|
endpointRegistry = [];
|
|
593420
594196
|
modelRouteMap = /* @__PURE__ */ new Map();
|
|
593421
594197
|
endpointUsage = /* @__PURE__ */ new Map();
|
|
594198
|
+
BACKEND_TIMEOUT_DEFAULT_MS = 12e4;
|
|
594199
|
+
BACKEND_TIMEOUT_MAX_MS = 36e5;
|
|
593422
594200
|
metrics = {
|
|
593423
594201
|
requests: /* @__PURE__ */ new Map(),
|
|
593424
594202
|
totalTokensIn: 0,
|
|
@@ -593434,13 +594212,13 @@ var init_serve = __esm({
|
|
|
593434
594212
|
|
|
593435
594213
|
// packages/cli/src/tui/interactive.ts
|
|
593436
594214
|
import { cwd } from "node:process";
|
|
593437
|
-
import { resolve as resolve39, join as
|
|
594215
|
+
import { resolve as resolve39, join as join116, dirname as dirname36, extname as extname12 } from "node:path";
|
|
593438
594216
|
import { createRequire as createRequire5 } from "node:module";
|
|
593439
594217
|
import { fileURLToPath as fileURLToPath18 } from "node:url";
|
|
593440
|
-
import { readFileSync as
|
|
593441
|
-
import { existsSync as
|
|
594218
|
+
import { readFileSync as readFileSync81, writeFileSync as writeFileSync56, appendFileSync as appendFileSync8, rmSync as rmSync5, readdirSync as readdirSync35, mkdirSync as mkdirSync64 } from "node:fs";
|
|
594219
|
+
import { existsSync as existsSync100 } from "node:fs";
|
|
593442
594220
|
import { execSync as execSync56 } from "node:child_process";
|
|
593443
|
-
import { homedir as
|
|
594221
|
+
import { homedir as homedir42 } from "node:os";
|
|
593444
594222
|
function formatTimeAgo2(date) {
|
|
593445
594223
|
const seconds = Math.floor((Date.now() - date.getTime()) / 1e3);
|
|
593446
594224
|
if (seconds < 60) return "just now";
|
|
@@ -593456,12 +594234,12 @@ function getVersion4() {
|
|
|
593456
594234
|
const require4 = createRequire5(import.meta.url);
|
|
593457
594235
|
const thisDir = dirname36(fileURLToPath18(import.meta.url));
|
|
593458
594236
|
const candidates = [
|
|
593459
|
-
|
|
593460
|
-
|
|
593461
|
-
|
|
594237
|
+
join116(thisDir, "..", "package.json"),
|
|
594238
|
+
join116(thisDir, "..", "..", "package.json"),
|
|
594239
|
+
join116(thisDir, "..", "..", "..", "package.json")
|
|
593462
594240
|
];
|
|
593463
594241
|
for (const pkgPath of candidates) {
|
|
593464
|
-
if (
|
|
594242
|
+
if (existsSync100(pkgPath)) {
|
|
593465
594243
|
const pkg = require4(pkgPath);
|
|
593466
594244
|
if (pkg.name === "open-agents-ai" || pkg.name === "@open-agents/cli" || pkg.name === "@open-agents/monorepo") {
|
|
593467
594245
|
return pkg.version ?? "0.0.0";
|
|
@@ -594224,14 +595002,14 @@ Meta-critique: quality ${meta.quality}/5, thorough: ${meta.thorough}`;
|
|
|
594224
595002
|
function gatherMemorySnippets(root) {
|
|
594225
595003
|
const snippets = [];
|
|
594226
595004
|
const dirs = [
|
|
594227
|
-
|
|
594228
|
-
|
|
595005
|
+
join116(root, ".oa", "memory"),
|
|
595006
|
+
join116(root, ".open-agents", "memory")
|
|
594229
595007
|
];
|
|
594230
595008
|
for (const dir of dirs) {
|
|
594231
|
-
if (!
|
|
595009
|
+
if (!existsSync100(dir)) continue;
|
|
594232
595010
|
try {
|
|
594233
595011
|
for (const f2 of readdirSync35(dir).filter((f3) => f3.endsWith(".json"))) {
|
|
594234
|
-
const data = JSON.parse(
|
|
595012
|
+
const data = JSON.parse(readFileSync81(join116(dir, f2), "utf-8"));
|
|
594235
595013
|
for (const val of Object.values(data)) {
|
|
594236
595014
|
const v = typeof val === "object" && val !== null && "value" in val ? String(val.value) : String(val);
|
|
594237
595015
|
if (v.length > 10) snippets.push(v);
|
|
@@ -594385,9 +595163,9 @@ ${metabolismMemories}
|
|
|
594385
595163
|
} catch {
|
|
594386
595164
|
}
|
|
594387
595165
|
try {
|
|
594388
|
-
const archeFile =
|
|
594389
|
-
if (
|
|
594390
|
-
const variants = JSON.parse(
|
|
595166
|
+
const archeFile = join116(repoRoot, ".oa", "arche", "variants.json");
|
|
595167
|
+
if (existsSync100(archeFile)) {
|
|
595168
|
+
const variants = JSON.parse(readFileSync81(archeFile, "utf8"));
|
|
594391
595169
|
if (variants.length > 0) {
|
|
594392
595170
|
let filtered = variants;
|
|
594393
595171
|
if (taskType) {
|
|
@@ -594559,9 +595337,9 @@ RULES:
|
|
|
594559
595337
|
const compactionThreshold = Number.isFinite(envOverride) && envOverride > 0 ? envOverride : modelTier === "small" ? 12e3 : modelTier === "medium" ? 24e3 : 4e4;
|
|
594560
595338
|
let identityInjection = "";
|
|
594561
595339
|
try {
|
|
594562
|
-
const ikStateFile =
|
|
594563
|
-
if (
|
|
594564
|
-
const selfState = JSON.parse(
|
|
595340
|
+
const ikStateFile = join116(repoRoot, ".oa", "identity", "self-state.json");
|
|
595341
|
+
if (existsSync100(ikStateFile)) {
|
|
595342
|
+
const selfState = JSON.parse(readFileSync81(ikStateFile, "utf8"));
|
|
594565
595343
|
const lines = [
|
|
594566
595344
|
`[Identity State v${selfState.version}]`,
|
|
594567
595345
|
`Self: ${selfState.narrative_summary}`,
|
|
@@ -595422,13 +596200,13 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
|
|
|
595422
596200
|
});
|
|
595423
596201
|
}
|
|
595424
596202
|
try {
|
|
595425
|
-
const ikDir =
|
|
595426
|
-
const ikFile =
|
|
596203
|
+
const ikDir = join116(repoRoot, ".oa", "identity");
|
|
596204
|
+
const ikFile = join116(ikDir, "self-state.json");
|
|
595427
596205
|
let ikState;
|
|
595428
|
-
if (
|
|
595429
|
-
ikState = JSON.parse(
|
|
596206
|
+
if (existsSync100(ikFile)) {
|
|
596207
|
+
ikState = JSON.parse(readFileSync81(ikFile, "utf8"));
|
|
595430
596208
|
} else {
|
|
595431
|
-
|
|
596209
|
+
mkdirSync64(ikDir, { recursive: true });
|
|
595432
596210
|
const machineId = Date.now().toString(36) + Math.random().toString(36).slice(2, 8);
|
|
595433
596211
|
ikState = {
|
|
595434
596212
|
self_id: `oa-${machineId}`,
|
|
@@ -595484,7 +596262,7 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
|
|
|
595484
596262
|
}
|
|
595485
596263
|
ikState.session_count = (ikState.session_count || 0) + 1;
|
|
595486
596264
|
ikState.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
595487
|
-
|
|
596265
|
+
writeFileSync56(ikFile, JSON.stringify(ikState, null, 2));
|
|
595488
596266
|
} catch (ikErr) {
|
|
595489
596267
|
try {
|
|
595490
596268
|
console.error("[IK-OBSERVE]", ikErr);
|
|
@@ -595503,9 +596281,9 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
|
|
|
595503
596281
|
} else {
|
|
595504
596282
|
renderTaskIncomplete(result.turns, result.toolCalls, result.durationMs, tokens);
|
|
595505
596283
|
try {
|
|
595506
|
-
const ikFile =
|
|
595507
|
-
if (
|
|
595508
|
-
const ikState = JSON.parse(
|
|
596284
|
+
const ikFile = join116(repoRoot, ".oa", "identity", "self-state.json");
|
|
596285
|
+
if (existsSync100(ikFile)) {
|
|
596286
|
+
const ikState = JSON.parse(readFileSync81(ikFile, "utf8"));
|
|
595509
596287
|
if (!ikState.stats) ikState.stats = { queries_served: 0 };
|
|
595510
596288
|
ikState.stats.queries_served = (ikState.stats.queries_served || 0) + 1;
|
|
595511
596289
|
ikState.homeostasis.uncertainty = Math.min(1, ikState.homeostasis.uncertainty + 0.03);
|
|
@@ -595516,7 +596294,7 @@ When done, either call task_complete with your answer, or use FINAL_VAR(variable
|
|
|
595516
596294
|
if (ikState.version_history.length > 200) ikState.version_history = ikState.version_history.slice(-200);
|
|
595517
596295
|
ikState.session_count = (ikState.session_count || 0) + 1;
|
|
595518
596296
|
ikState.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
595519
|
-
|
|
596297
|
+
writeFileSync56(ikFile, JSON.stringify(ikState, null, 2));
|
|
595520
596298
|
}
|
|
595521
596299
|
} catch {
|
|
595522
596300
|
}
|
|
@@ -595761,10 +596539,10 @@ async function startInteractive(config, repoPath) {
|
|
|
595761
596539
|
process.stdin.pause();
|
|
595762
596540
|
}
|
|
595763
596541
|
try {
|
|
595764
|
-
const oaDir =
|
|
595765
|
-
const nexusPidFile =
|
|
595766
|
-
if (
|
|
595767
|
-
const pid = parseInt(
|
|
596542
|
+
const oaDir = join116(repoRoot, ".oa");
|
|
596543
|
+
const nexusPidFile = join116(oaDir, "nexus", "daemon.pid");
|
|
596544
|
+
if (existsSync100(nexusPidFile)) {
|
|
596545
|
+
const pid = parseInt(readFileSync81(nexusPidFile, "utf8").trim(), 10);
|
|
595768
596546
|
if (pid > 0) {
|
|
595769
596547
|
try {
|
|
595770
596548
|
process.kill(pid, 0);
|
|
@@ -596424,7 +597202,7 @@ ${result.summary}`
|
|
|
596424
597202
|
let p2pGateway = null;
|
|
596425
597203
|
let peerMesh = null;
|
|
596426
597204
|
let inferenceRouter = null;
|
|
596427
|
-
const secretVault = new SecretVault(
|
|
597205
|
+
const secretVault = new SecretVault(join116(repoRoot, ".oa", "vault.enc"));
|
|
596428
597206
|
let adminSessionKey = null;
|
|
596429
597207
|
const callSubAgents = /* @__PURE__ */ new Map();
|
|
596430
597208
|
const streamRenderer = new StreamRenderer();
|
|
@@ -596655,13 +597433,13 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
596655
597433
|
const hits = allCompletions.filter((c9) => c9.toLowerCase().startsWith(lower));
|
|
596656
597434
|
return [hits, line];
|
|
596657
597435
|
}
|
|
596658
|
-
const HISTORY_DIR =
|
|
596659
|
-
const HISTORY_FILE =
|
|
597436
|
+
const HISTORY_DIR = join116(homedir42(), ".open-agents");
|
|
597437
|
+
const HISTORY_FILE = join116(HISTORY_DIR, "repl-history");
|
|
596660
597438
|
const MAX_HISTORY_LINES = 500;
|
|
596661
597439
|
let savedHistory = [];
|
|
596662
597440
|
try {
|
|
596663
|
-
if (
|
|
596664
|
-
const raw =
|
|
597441
|
+
if (existsSync100(HISTORY_FILE)) {
|
|
597442
|
+
const raw = readFileSync81(HISTORY_FILE, "utf8").trim();
|
|
596665
597443
|
if (raw) savedHistory = raw.split("\n").reverse();
|
|
596666
597444
|
}
|
|
596667
597445
|
} catch {
|
|
@@ -596808,12 +597586,12 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
596808
597586
|
function persistHistoryLine(line) {
|
|
596809
597587
|
if (!line.trim()) return;
|
|
596810
597588
|
try {
|
|
596811
|
-
|
|
597589
|
+
mkdirSync64(HISTORY_DIR, { recursive: true });
|
|
596812
597590
|
appendFileSync8(HISTORY_FILE, line + "\n", "utf8");
|
|
596813
597591
|
if (Math.random() < 0.02) {
|
|
596814
|
-
const all2 =
|
|
597592
|
+
const all2 = readFileSync81(HISTORY_FILE, "utf8").trim().split("\n");
|
|
596815
597593
|
if (all2.length > MAX_HISTORY_LINES) {
|
|
596816
|
-
|
|
597594
|
+
writeFileSync56(HISTORY_FILE, all2.slice(-MAX_HISTORY_LINES).join("\n") + "\n", "utf8");
|
|
596817
597595
|
}
|
|
596818
597596
|
}
|
|
596819
597597
|
} catch {
|
|
@@ -596998,10 +597776,10 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
596998
597776
|
const { unlinkSync: _rmStale } = await import("node:fs");
|
|
596999
597777
|
const { homedir: _hdir } = await import("node:os");
|
|
597000
597778
|
for (const dp of [
|
|
597001
|
-
|
|
597002
|
-
|
|
597779
|
+
join116(repoRoot, ".oa", "nexus", "nexus-daemon.mjs"),
|
|
597780
|
+
join116(_hdir(), ".open-agents", ".oa", "nexus", "nexus-daemon.mjs")
|
|
597003
597781
|
]) {
|
|
597004
|
-
if (
|
|
597782
|
+
if (existsSync100(dp)) try {
|
|
597005
597783
|
_rmStale(dp);
|
|
597006
597784
|
} catch {
|
|
597007
597785
|
}
|
|
@@ -597012,9 +597790,9 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
597012
597790
|
const autoNexus = new NexusTool(repoRoot);
|
|
597013
597791
|
const _registerNexusDaemon = () => {
|
|
597014
597792
|
try {
|
|
597015
|
-
const nexusPidFile =
|
|
597016
|
-
if (
|
|
597017
|
-
const nPid = parseInt(
|
|
597793
|
+
const nexusPidFile = join116(repoRoot, ".oa", "nexus", "daemon.pid");
|
|
597794
|
+
if (existsSync100(nexusPidFile)) {
|
|
597795
|
+
const nPid = parseInt(readFileSync81(nexusPidFile, "utf8").trim(), 10);
|
|
597018
597796
|
if (nPid > 0 && !registry2.daemons.has("Nexus")) {
|
|
597019
597797
|
registry2.register({ name: "Nexus", pid: nPid, startedAt: Date.now(), status: "running" });
|
|
597020
597798
|
statusBar.ensureMonitorTimer();
|
|
@@ -597071,7 +597849,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
597071
597849
|
} catch {
|
|
597072
597850
|
}
|
|
597073
597851
|
try {
|
|
597074
|
-
const oaDir =
|
|
597852
|
+
const oaDir = join116(repoRoot, ".oa");
|
|
597075
597853
|
const reconnected = await ExposeGateway.checkAndReconnect(oaDir, {
|
|
597076
597854
|
onInfo: (msg) => writeContent(() => renderInfo2(msg)),
|
|
597077
597855
|
onError: (msg) => writeContent(() => renderWarning2(msg))
|
|
@@ -597103,7 +597881,7 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
597103
597881
|
} catch {
|
|
597104
597882
|
}
|
|
597105
597883
|
try {
|
|
597106
|
-
const oaDir =
|
|
597884
|
+
const oaDir = join116(repoRoot, ".oa");
|
|
597107
597885
|
const reconnectedP2P = await ExposeP2PGateway.checkAndReconnect(oaDir, new NexusTool(repoRoot), {
|
|
597108
597886
|
onInfo: (msg) => writeContent(() => renderInfo2(msg)),
|
|
597109
597887
|
onError: (msg) => writeContent(() => renderWarning2(msg))
|
|
@@ -597144,10 +597922,10 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
597144
597922
|
}
|
|
597145
597923
|
try {
|
|
597146
597924
|
const { homedir: _hd, hostname: _hn, userInfo: _ui } = await import("node:os");
|
|
597147
|
-
const globalNamePath =
|
|
597925
|
+
const globalNamePath = join116(_hd(), ".open-agents", "agent-name");
|
|
597148
597926
|
let agName = "";
|
|
597149
597927
|
try {
|
|
597150
|
-
if (
|
|
597928
|
+
if (existsSync100(globalNamePath)) agName = readFileSync81(globalNamePath, "utf8").trim();
|
|
597151
597929
|
} catch {
|
|
597152
597930
|
}
|
|
597153
597931
|
if (!agName) {
|
|
@@ -597176,11 +597954,11 @@ Rationale: ${proposal.rationale}${provenanceNote}`;
|
|
|
597176
597954
|
}
|
|
597177
597955
|
if (!ollamaAlive) {
|
|
597178
597956
|
try {
|
|
597179
|
-
const savedSponsorsPath =
|
|
597957
|
+
const savedSponsorsPath = join116(repoRoot, ".oa", "sponsor", "known-sponsors.json");
|
|
597180
597958
|
let savedSponsors = [];
|
|
597181
597959
|
try {
|
|
597182
|
-
if (
|
|
597183
|
-
savedSponsors = JSON.parse(
|
|
597960
|
+
if (existsSync100(savedSponsorsPath)) {
|
|
597961
|
+
savedSponsors = JSON.parse(readFileSync81(savedSponsorsPath, "utf8"));
|
|
597184
597962
|
const oneHourAgo = Date.now() - 36e5;
|
|
597185
597963
|
savedSponsors = savedSponsors.filter((s2) => (s2.lastVerified || 0) > oneHourAgo);
|
|
597186
597964
|
}
|
|
@@ -598272,10 +599050,10 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
598272
599050
|
if (name10 === "voice_list_files") {
|
|
598273
599051
|
const baseDir = String(args?.dir ?? ".");
|
|
598274
599052
|
const { readdirSync: readdirSync37, statSync: statSync30 } = __require("node:fs");
|
|
598275
|
-
const { join:
|
|
598276
|
-
const base3 = baseDir.startsWith("/") ? baseDir : resolve43(
|
|
599053
|
+
const { join: join121, resolve: resolve43 } = __require("node:path");
|
|
599054
|
+
const base3 = baseDir.startsWith("/") ? baseDir : resolve43(join121(repoRoot, baseDir));
|
|
598277
599055
|
const items = readdirSync37(base3).slice(0, 200).map((f2) => {
|
|
598278
|
-
const s2 = statSync30(
|
|
599056
|
+
const s2 = statSync30(join121(base3, f2));
|
|
598279
599057
|
return { name: f2, dir: s2.isDirectory(), size: s2.size };
|
|
598280
599058
|
});
|
|
598281
599059
|
return JSON.stringify({ dir: base3, items }, null, 2);
|
|
@@ -598363,7 +599141,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
598363
599141
|
kind,
|
|
598364
599142
|
targetUrl,
|
|
598365
599143
|
authKey,
|
|
598366
|
-
stateDir:
|
|
599144
|
+
stateDir: join116(repoRoot, ".oa"),
|
|
598367
599145
|
passthrough: passthrough ?? false,
|
|
598368
599146
|
loadbalance: loadbalance ?? false,
|
|
598369
599147
|
endpointAuth: passthrough ? currentConfig.apiKey : void 0,
|
|
@@ -598409,7 +599187,7 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
598409
599187
|
await tunnelGateway.stop();
|
|
598410
599188
|
tunnelGateway = null;
|
|
598411
599189
|
}
|
|
598412
|
-
const newTunnel = new ExposeGateway({ kind, targetUrl, authKey, fullAccess, stateDir:
|
|
599190
|
+
const newTunnel = new ExposeGateway({ kind, targetUrl, authKey, fullAccess, stateDir: join116(repoRoot, ".oa") });
|
|
598413
599191
|
newTunnel.on("stats", (stats) => {
|
|
598414
599192
|
statusBar.setExposeStatus({
|
|
598415
599193
|
status: stats.status,
|
|
@@ -598496,9 +599274,9 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
598496
599274
|
});
|
|
598497
599275
|
if (!result.success) throw new Error(result.error || "Connect failed");
|
|
598498
599276
|
try {
|
|
598499
|
-
const nexusPidFile =
|
|
598500
|
-
if (
|
|
598501
|
-
const pid = parseInt(
|
|
599277
|
+
const nexusPidFile = join116(repoRoot, ".oa", "nexus", "daemon.pid");
|
|
599278
|
+
if (existsSync100(nexusPidFile)) {
|
|
599279
|
+
const pid = parseInt(readFileSync81(nexusPidFile, "utf8").trim(), 10);
|
|
598502
599280
|
if (pid > 0) {
|
|
598503
599281
|
registry2.register({
|
|
598504
599282
|
name: "Nexus",
|
|
@@ -598686,10 +599464,10 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
598686
599464
|
writeContent(() => renderInfo2(`Killed ${bgKilled} background task(s).`));
|
|
598687
599465
|
}
|
|
598688
599466
|
try {
|
|
598689
|
-
const nexusDir =
|
|
598690
|
-
const pidFile =
|
|
598691
|
-
if (
|
|
598692
|
-
const pid = parseInt(
|
|
599467
|
+
const nexusDir = join116(repoRoot, OA_DIR, "nexus");
|
|
599468
|
+
const pidFile = join116(nexusDir, "daemon.pid");
|
|
599469
|
+
if (existsSync100(pidFile)) {
|
|
599470
|
+
const pid = parseInt(readFileSync81(pidFile, "utf8").trim(), 10);
|
|
598693
599471
|
if (pid > 0) {
|
|
598694
599472
|
try {
|
|
598695
599473
|
if (process.platform === "win32") {
|
|
@@ -598711,13 +599489,13 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
598711
599489
|
} catch {
|
|
598712
599490
|
}
|
|
598713
599491
|
try {
|
|
598714
|
-
const voiceDir2 =
|
|
599492
|
+
const voiceDir2 = join116(homedir42(), ".open-agents", "voice");
|
|
598715
599493
|
const voicePidFiles = ["luxtts-daemon.pid", "piper-daemon.pid"];
|
|
598716
599494
|
for (const pf of voicePidFiles) {
|
|
598717
|
-
const pidPath =
|
|
598718
|
-
if (
|
|
599495
|
+
const pidPath = join116(voiceDir2, pf);
|
|
599496
|
+
if (existsSync100(pidPath)) {
|
|
598719
599497
|
try {
|
|
598720
|
-
const pid = parseInt(
|
|
599498
|
+
const pid = parseInt(readFileSync81(pidPath, "utf8").trim(), 10);
|
|
598721
599499
|
if (pid > 0) {
|
|
598722
599500
|
if (process.platform === "win32") {
|
|
598723
599501
|
try {
|
|
@@ -598741,8 +599519,8 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
598741
599519
|
execSync56(process.platform === "win32" ? "timeout /t 1 /nobreak >nul" : "sleep 0.5", { timeout: 3e3, stdio: "ignore" });
|
|
598742
599520
|
} catch {
|
|
598743
599521
|
}
|
|
598744
|
-
const oaPath =
|
|
598745
|
-
if (
|
|
599522
|
+
const oaPath = join116(repoRoot, OA_DIR);
|
|
599523
|
+
if (existsSync100(oaPath)) {
|
|
598746
599524
|
let deleted = false;
|
|
598747
599525
|
for (let attempt = 0; attempt < 3; attempt++) {
|
|
598748
599526
|
try {
|
|
@@ -598826,19 +599604,19 @@ Respond concisely and safely. Remember: you are talking to the general public.`;
|
|
|
598826
599604
|
try {
|
|
598827
599605
|
const { isPersonaPlexRunning: isPersonaPlexRunning2 } = await Promise.resolve().then(() => (init_personaplex(), personaplex_exports));
|
|
598828
599606
|
if (isPersonaPlexRunning2()) {
|
|
598829
|
-
const ppPidFile =
|
|
598830
|
-
const ppPortFile =
|
|
598831
|
-
if (
|
|
598832
|
-
const ppPid = parseInt(
|
|
598833
|
-
const ppPort =
|
|
599607
|
+
const ppPidFile = join116(homedir42(), ".open-agents", "voice", "personaplex", "daemon.pid");
|
|
599608
|
+
const ppPortFile = join116(homedir42(), ".open-agents", "voice", "personaplex", "daemon.port");
|
|
599609
|
+
if (existsSync100(ppPidFile)) {
|
|
599610
|
+
const ppPid = parseInt(readFileSync81(ppPidFile, "utf8").trim(), 10);
|
|
599611
|
+
const ppPort = existsSync100(ppPortFile) ? parseInt(readFileSync81(ppPortFile, "utf8").trim(), 10) : void 0;
|
|
598834
599612
|
if (ppPid > 0 && !registry2.daemons.has("PersonaPlex")) {
|
|
598835
599613
|
registry2.register({ name: "PersonaPlex", pid: ppPid, port: ppPort, startedAt: Date.now(), status: "running" });
|
|
598836
599614
|
}
|
|
598837
599615
|
}
|
|
598838
599616
|
}
|
|
598839
|
-
const nexusPidFile =
|
|
598840
|
-
if (
|
|
598841
|
-
const nPid = parseInt(
|
|
599617
|
+
const nexusPidFile = join116(repoRoot, ".oa", "nexus", "daemon.pid");
|
|
599618
|
+
if (existsSync100(nexusPidFile)) {
|
|
599619
|
+
const nPid = parseInt(readFileSync81(nexusPidFile, "utf8").trim(), 10);
|
|
598842
599620
|
if (nPid > 0 && !registry2.daemons.has("Nexus")) {
|
|
598843
599621
|
try {
|
|
598844
599622
|
process.kill(nPid, 0);
|
|
@@ -599205,9 +599983,9 @@ Execute this skill now. Follow the behavioral guidance above.`;
|
|
|
599205
599983
|
}
|
|
599206
599984
|
}
|
|
599207
599985
|
const cleanPath = input.replace(/^['"]|['"]$/g, "").trim();
|
|
599208
|
-
const isImage = isImagePath(cleanPath) &&
|
|
599209
|
-
const isMedia = !isImage && isTranscribablePath(cleanPath) &&
|
|
599210
|
-
const isMarkdown = !isImage && !isMedia && /\.(md|markdown)$/i.test(cleanPath) &&
|
|
599986
|
+
const isImage = isImagePath(cleanPath) && existsSync100(resolve39(repoRoot, cleanPath));
|
|
599987
|
+
const isMedia = !isImage && isTranscribablePath(cleanPath) && existsSync100(resolve39(repoRoot, cleanPath));
|
|
599988
|
+
const isMarkdown = !isImage && !isMedia && /\.(md|markdown)$/i.test(cleanPath) && existsSync100(resolve39(repoRoot, cleanPath));
|
|
599211
599989
|
if (activeTask) {
|
|
599212
599990
|
if (activeTask.runner.isPaused) {
|
|
599213
599991
|
activeTask.runner.resume();
|
|
@@ -599216,7 +599994,7 @@ Execute this skill now. Follow the behavioral guidance above.`;
|
|
|
599216
599994
|
if (isImage) {
|
|
599217
599995
|
try {
|
|
599218
599996
|
const imgPath = resolve39(repoRoot, cleanPath);
|
|
599219
|
-
const imgBuffer =
|
|
599997
|
+
const imgBuffer = readFileSync81(imgPath);
|
|
599220
599998
|
const base642 = imgBuffer.toString("base64");
|
|
599221
599999
|
const ext = extname12(cleanPath).toLowerCase();
|
|
599222
600000
|
const mime = ext === ".png" ? "image/png" : ext === ".gif" ? "image/gif" : ext === ".webp" ? "image/webp" : "image/jpeg";
|
|
@@ -599372,7 +600150,7 @@ ${result.text}`;
|
|
|
599372
600150
|
if (isMarkdown && fullInput === input) {
|
|
599373
600151
|
try {
|
|
599374
600152
|
const mdPath = resolve39(repoRoot, cleanPath);
|
|
599375
|
-
const mdContent =
|
|
600153
|
+
const mdContent = readFileSync81(mdPath, "utf8");
|
|
599376
600154
|
const { parseMcpMarkdown: parseMcpMarkdown2 } = await Promise.resolve().then(() => (init_dist5(), dist_exports));
|
|
599377
600155
|
const result = parseMcpMarkdown2(mdContent);
|
|
599378
600156
|
if (result.servers.length > 0) {
|
|
@@ -599794,13 +600572,13 @@ async function runWithTUI(task, config, repoPath, callbacks) {
|
|
|
599794
600572
|
const handle2 = startTask(task, config, repoRoot);
|
|
599795
600573
|
await handle2.promise;
|
|
599796
600574
|
try {
|
|
599797
|
-
const ikDir =
|
|
599798
|
-
const ikFile =
|
|
600575
|
+
const ikDir = join116(repoRoot, ".oa", "identity");
|
|
600576
|
+
const ikFile = join116(ikDir, "self-state.json");
|
|
599799
600577
|
let ikState;
|
|
599800
|
-
if (
|
|
599801
|
-
ikState = JSON.parse(
|
|
600578
|
+
if (existsSync100(ikFile)) {
|
|
600579
|
+
ikState = JSON.parse(readFileSync81(ikFile, "utf8"));
|
|
599802
600580
|
} else {
|
|
599803
|
-
|
|
600581
|
+
mkdirSync64(ikDir, { recursive: true });
|
|
599804
600582
|
ikState = {
|
|
599805
600583
|
self_id: `oa-${Date.now().toString(36)}`,
|
|
599806
600584
|
version: 1,
|
|
@@ -599822,7 +600600,7 @@ async function runWithTUI(task, config, repoPath, callbacks) {
|
|
|
599822
600600
|
ikState.homeostasis.coherence = Math.min(1, ikState.homeostasis.coherence + 0.05);
|
|
599823
600601
|
ikState.session_count = (ikState.session_count || 0) + 1;
|
|
599824
600602
|
ikState.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
599825
|
-
|
|
600603
|
+
writeFileSync56(ikFile, JSON.stringify(ikState, null, 2));
|
|
599826
600604
|
} catch (ikErr) {
|
|
599827
600605
|
}
|
|
599828
600606
|
try {
|
|
@@ -599835,11 +600613,11 @@ async function runWithTUI(task, config, repoPath, callbacks) {
|
|
|
599835
600613
|
);
|
|
599836
600614
|
} catch {
|
|
599837
600615
|
try {
|
|
599838
|
-
const archeDir =
|
|
599839
|
-
const archeFile =
|
|
600616
|
+
const archeDir = join116(repoRoot, ".oa", "arche");
|
|
600617
|
+
const archeFile = join116(archeDir, "variants.json");
|
|
599840
600618
|
let variants = [];
|
|
599841
600619
|
try {
|
|
599842
|
-
if (
|
|
600620
|
+
if (existsSync100(archeFile)) variants = JSON.parse(readFileSync81(archeFile, "utf8"));
|
|
599843
600621
|
} catch {
|
|
599844
600622
|
}
|
|
599845
600623
|
variants.push({
|
|
@@ -599853,15 +600631,15 @@ async function runWithTUI(task, config, repoPath, callbacks) {
|
|
|
599853
600631
|
tags: ["general"]
|
|
599854
600632
|
});
|
|
599855
600633
|
if (variants.length > 50) variants = variants.slice(-50);
|
|
599856
|
-
|
|
599857
|
-
|
|
600634
|
+
mkdirSync64(archeDir, { recursive: true });
|
|
600635
|
+
writeFileSync56(archeFile, JSON.stringify(variants, null, 2));
|
|
599858
600636
|
} catch {
|
|
599859
600637
|
}
|
|
599860
600638
|
}
|
|
599861
600639
|
try {
|
|
599862
|
-
const metaFile =
|
|
599863
|
-
if (
|
|
599864
|
-
const store2 = JSON.parse(
|
|
600640
|
+
const metaFile = join116(repoRoot, ".oa", "memory", "metabolism", "store.json");
|
|
600641
|
+
if (existsSync100(metaFile)) {
|
|
600642
|
+
const store2 = JSON.parse(readFileSync81(metaFile, "utf8"));
|
|
599865
600643
|
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);
|
|
599866
600644
|
let updated = false;
|
|
599867
600645
|
for (const item of surfaced) {
|
|
@@ -599872,7 +600650,7 @@ async function runWithTUI(task, config, repoPath, callbacks) {
|
|
|
599872
600650
|
updated = true;
|
|
599873
600651
|
}
|
|
599874
600652
|
if (updated) {
|
|
599875
|
-
|
|
600653
|
+
writeFileSync56(metaFile, JSON.stringify(store2, null, 2));
|
|
599876
600654
|
}
|
|
599877
600655
|
}
|
|
599878
600656
|
} catch {
|
|
@@ -599925,9 +600703,9 @@ Rules:
|
|
|
599925
600703
|
try {
|
|
599926
600704
|
const { initDb: initDb2 } = __require("@open-agents/memory");
|
|
599927
600705
|
const { ProceduralMemoryStore: ProceduralMemoryStore2 } = __require("@open-agents/memory");
|
|
599928
|
-
const dbDir =
|
|
599929
|
-
|
|
599930
|
-
const db = initDb2(
|
|
600706
|
+
const dbDir = join116(repoRoot, ".oa", "memory");
|
|
600707
|
+
mkdirSync64(dbDir, { recursive: true });
|
|
600708
|
+
const db = initDb2(join116(dbDir, "structured.db"));
|
|
599931
600709
|
const memStore = new ProceduralMemoryStore2(db);
|
|
599932
600710
|
memStore.createWithEmbedding({
|
|
599933
600711
|
content: content.slice(0, 600),
|
|
@@ -599942,11 +600720,11 @@ Rules:
|
|
|
599942
600720
|
db.close();
|
|
599943
600721
|
} catch {
|
|
599944
600722
|
}
|
|
599945
|
-
const metaDir =
|
|
599946
|
-
const storeFile =
|
|
600723
|
+
const metaDir = join116(repoRoot, ".oa", "memory", "metabolism");
|
|
600724
|
+
const storeFile = join116(metaDir, "store.json");
|
|
599947
600725
|
let store2 = [];
|
|
599948
600726
|
try {
|
|
599949
|
-
if (
|
|
600727
|
+
if (existsSync100(storeFile)) store2 = JSON.parse(readFileSync81(storeFile, "utf8"));
|
|
599950
600728
|
} catch {
|
|
599951
600729
|
}
|
|
599952
600730
|
store2.push({
|
|
@@ -599961,26 +600739,26 @@ Rules:
|
|
|
599961
600739
|
accessCount: 0
|
|
599962
600740
|
});
|
|
599963
600741
|
if (store2.length > 100) store2 = store2.slice(-100);
|
|
599964
|
-
|
|
599965
|
-
|
|
600742
|
+
mkdirSync64(metaDir, { recursive: true });
|
|
600743
|
+
writeFileSync56(storeFile, JSON.stringify(store2, null, 2));
|
|
599966
600744
|
}
|
|
599967
600745
|
}
|
|
599968
600746
|
} catch {
|
|
599969
600747
|
}
|
|
599970
600748
|
try {
|
|
599971
|
-
const cohereSettingsFile =
|
|
600749
|
+
const cohereSettingsFile = join116(repoRoot, ".oa", "settings.json");
|
|
599972
600750
|
let cohereActive = false;
|
|
599973
600751
|
try {
|
|
599974
|
-
if (
|
|
599975
|
-
const settings = JSON.parse(
|
|
600752
|
+
if (existsSync100(cohereSettingsFile)) {
|
|
600753
|
+
const settings = JSON.parse(readFileSync81(cohereSettingsFile, "utf8"));
|
|
599976
600754
|
cohereActive = settings.cohere === true;
|
|
599977
600755
|
}
|
|
599978
600756
|
} catch {
|
|
599979
600757
|
}
|
|
599980
600758
|
if (cohereActive) {
|
|
599981
|
-
const metaFile =
|
|
599982
|
-
if (
|
|
599983
|
-
const store2 = JSON.parse(
|
|
600759
|
+
const metaFile = join116(repoRoot, ".oa", "memory", "metabolism", "store.json");
|
|
600760
|
+
if (existsSync100(metaFile)) {
|
|
600761
|
+
const store2 = JSON.parse(readFileSync81(metaFile, "utf8"));
|
|
599984
600762
|
const latest = store2.filter((m2) => m2.sourceTrace === "trajectory-extraction" || m2.sourceTrace === "llm-trajectory-extraction").slice(-1)[0];
|
|
599985
600763
|
if (latest && latest.scores?.confidence >= 0.6) {
|
|
599986
600764
|
try {
|
|
@@ -600005,18 +600783,18 @@ Rules:
|
|
|
600005
600783
|
}
|
|
600006
600784
|
} catch (err) {
|
|
600007
600785
|
try {
|
|
600008
|
-
const ikFile =
|
|
600009
|
-
if (
|
|
600010
|
-
const ikState = JSON.parse(
|
|
600786
|
+
const ikFile = join116(repoRoot, ".oa", "identity", "self-state.json");
|
|
600787
|
+
if (existsSync100(ikFile)) {
|
|
600788
|
+
const ikState = JSON.parse(readFileSync81(ikFile, "utf8"));
|
|
600011
600789
|
ikState.homeostasis.uncertainty = Math.min(1, ikState.homeostasis.uncertainty + 0.1);
|
|
600012
600790
|
ikState.homeostasis.coherence = Math.max(0, ikState.homeostasis.coherence - 0.05);
|
|
600013
600791
|
ikState.session_count = (ikState.session_count || 0) + 1;
|
|
600014
600792
|
ikState.updated_at = (/* @__PURE__ */ new Date()).toISOString();
|
|
600015
|
-
|
|
600793
|
+
writeFileSync56(ikFile, JSON.stringify(ikState, null, 2));
|
|
600016
600794
|
}
|
|
600017
|
-
const metaFile =
|
|
600018
|
-
if (
|
|
600019
|
-
const store2 = JSON.parse(
|
|
600795
|
+
const metaFile = join116(repoRoot, ".oa", "memory", "metabolism", "store.json");
|
|
600796
|
+
if (existsSync100(metaFile)) {
|
|
600797
|
+
const store2 = JSON.parse(readFileSync81(metaFile, "utf8"));
|
|
600020
600798
|
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);
|
|
600021
600799
|
for (const item of surfaced) {
|
|
600022
600800
|
item.accessCount = (item.accessCount || 0) + 1;
|
|
@@ -600024,14 +600802,14 @@ Rules:
|
|
|
600024
600802
|
item.scores.utility = Math.max(0, (item.scores.utility || 0.5) - 0.05);
|
|
600025
600803
|
item.scores.confidence = Math.max(0, (item.scores.confidence || 0.5) - 0.02);
|
|
600026
600804
|
}
|
|
600027
|
-
|
|
600805
|
+
writeFileSync56(metaFile, JSON.stringify(store2, null, 2));
|
|
600028
600806
|
}
|
|
600029
600807
|
try {
|
|
600030
|
-
const archeDir =
|
|
600031
|
-
const archeFile =
|
|
600808
|
+
const archeDir = join116(repoRoot, ".oa", "arche");
|
|
600809
|
+
const archeFile = join116(archeDir, "variants.json");
|
|
600032
600810
|
let variants = [];
|
|
600033
600811
|
try {
|
|
600034
|
-
if (
|
|
600812
|
+
if (existsSync100(archeFile)) variants = JSON.parse(readFileSync81(archeFile, "utf8"));
|
|
600035
600813
|
} catch {
|
|
600036
600814
|
}
|
|
600037
600815
|
variants.push({
|
|
@@ -600045,8 +600823,8 @@ Rules:
|
|
|
600045
600823
|
tags: ["general"]
|
|
600046
600824
|
});
|
|
600047
600825
|
if (variants.length > 50) variants = variants.slice(-50);
|
|
600048
|
-
|
|
600049
|
-
|
|
600826
|
+
mkdirSync64(archeDir, { recursive: true });
|
|
600827
|
+
writeFileSync56(archeFile, JSON.stringify(variants, null, 2));
|
|
600050
600828
|
} catch {
|
|
600051
600829
|
}
|
|
600052
600830
|
} catch {
|
|
@@ -600135,13 +600913,13 @@ __export(run_exports, {
|
|
|
600135
600913
|
});
|
|
600136
600914
|
import { resolve as resolve40 } from "node:path";
|
|
600137
600915
|
import { spawn as spawn26 } from "node:child_process";
|
|
600138
|
-
import { mkdirSync as
|
|
600139
|
-
import { randomBytes as
|
|
600140
|
-
import { join as
|
|
600916
|
+
import { mkdirSync as mkdirSync65, writeFileSync as writeFileSync57, readFileSync as readFileSync82, readdirSync as readdirSync36, existsSync as existsSync101 } from "node:fs";
|
|
600917
|
+
import { randomBytes as randomBytes24 } from "node:crypto";
|
|
600918
|
+
import { join as join117 } from "node:path";
|
|
600141
600919
|
function jobsDir2(repoPath) {
|
|
600142
600920
|
const root = resolve40(repoPath ?? process.cwd());
|
|
600143
|
-
const dir =
|
|
600144
|
-
|
|
600921
|
+
const dir = join117(root, ".oa", "jobs");
|
|
600922
|
+
mkdirSync65(dir, { recursive: true });
|
|
600145
600923
|
return dir;
|
|
600146
600924
|
}
|
|
600147
600925
|
async function runCommand(opts, config) {
|
|
@@ -600231,7 +601009,7 @@ function extractSummary(captured) {
|
|
|
600231
601009
|
return lines.slice(-3).join(" ").slice(0, 200);
|
|
600232
601010
|
}
|
|
600233
601011
|
async function runBackground(task, config, opts) {
|
|
600234
|
-
const id = `job-${
|
|
601012
|
+
const id = `job-${randomBytes24(3).toString("hex")}`;
|
|
600235
601013
|
const dir = jobsDir2(opts.repoPath);
|
|
600236
601014
|
const repoRoot = resolve40(opts.repoPath ?? process.cwd());
|
|
600237
601015
|
const job = {
|
|
@@ -600260,7 +601038,7 @@ async function runBackground(task, config, opts) {
|
|
|
600260
601038
|
}
|
|
600261
601039
|
});
|
|
600262
601040
|
job.pid = child.pid ?? 0;
|
|
600263
|
-
|
|
601041
|
+
writeFileSync57(join117(dir, `${id}.json`), JSON.stringify(job, null, 2));
|
|
600264
601042
|
let output = "";
|
|
600265
601043
|
child.stdout?.on("data", (chunk) => {
|
|
600266
601044
|
output += chunk.toString();
|
|
@@ -600276,7 +601054,7 @@ async function runBackground(task, config, opts) {
|
|
|
600276
601054
|
job.summary = result.summary;
|
|
600277
601055
|
job.durationMs = result.durationMs;
|
|
600278
601056
|
job.error = result.error;
|
|
600279
|
-
|
|
601057
|
+
writeFileSync57(join117(dir, `${id}.json`), JSON.stringify(job, null, 2));
|
|
600280
601058
|
} catch {
|
|
600281
601059
|
}
|
|
600282
601060
|
});
|
|
@@ -600292,13 +601070,13 @@ async function runBackground(task, config, opts) {
|
|
|
600292
601070
|
}
|
|
600293
601071
|
function statusCommand(jobId, repoPath) {
|
|
600294
601072
|
const dir = jobsDir2(repoPath);
|
|
600295
|
-
const file =
|
|
600296
|
-
if (!
|
|
601073
|
+
const file = join117(dir, `${jobId}.json`);
|
|
601074
|
+
if (!existsSync101(file)) {
|
|
600297
601075
|
console.error(`Job not found: ${jobId}`);
|
|
600298
601076
|
console.log(`Available jobs: oa jobs`);
|
|
600299
601077
|
process.exit(1);
|
|
600300
601078
|
}
|
|
600301
|
-
const job = JSON.parse(
|
|
601079
|
+
const job = JSON.parse(readFileSync82(file, "utf-8"));
|
|
600302
601080
|
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`;
|
|
600303
601081
|
const icon = job.status === "completed" ? "✓" : job.status === "failed" ? "✗" : "●";
|
|
600304
601082
|
console.log(`${icon} ${job.id} [${job.status}] ${runtime}`);
|
|
@@ -600319,7 +601097,7 @@ function jobsCommand(repoPath) {
|
|
|
600319
601097
|
console.log("Jobs:");
|
|
600320
601098
|
for (const file of files) {
|
|
600321
601099
|
try {
|
|
600322
|
-
const job = JSON.parse(
|
|
601100
|
+
const job = JSON.parse(readFileSync82(join117(dir, file), "utf-8"));
|
|
600323
601101
|
const icon = job.status === "completed" ? "✓" : job.status === "failed" ? "✗" : "●";
|
|
600324
601102
|
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`;
|
|
600325
601103
|
const cleanListTask = cleanForStorage(job.task) || job.task;
|
|
@@ -600343,13 +601121,13 @@ __export(index_repo_exports, {
|
|
|
600343
601121
|
indexRepoCommand: () => indexRepoCommand
|
|
600344
601122
|
});
|
|
600345
601123
|
import { resolve as resolve41 } from "node:path";
|
|
600346
|
-
import { existsSync as
|
|
601124
|
+
import { existsSync as existsSync102, statSync as statSync29 } from "node:fs";
|
|
600347
601125
|
import { cwd as cwd2 } from "node:process";
|
|
600348
601126
|
async function indexRepoCommand(opts, _config3) {
|
|
600349
601127
|
const repoRoot = resolve41(opts.repoPath ?? cwd2());
|
|
600350
601128
|
printHeader("Index Repository");
|
|
600351
601129
|
printInfo(`Indexing: ${repoRoot}`);
|
|
600352
|
-
if (!
|
|
601130
|
+
if (!existsSync102(repoRoot)) {
|
|
600353
601131
|
printError(`Path does not exist: ${repoRoot}`);
|
|
600354
601132
|
process.exit(1);
|
|
600355
601133
|
}
|
|
@@ -600601,8 +601379,8 @@ var config_exports2 = {};
|
|
|
600601
601379
|
__export(config_exports2, {
|
|
600602
601380
|
configCommand: () => configCommand
|
|
600603
601381
|
});
|
|
600604
|
-
import { join as
|
|
600605
|
-
import { homedir as
|
|
601382
|
+
import { join as join118, resolve as resolve42 } from "node:path";
|
|
601383
|
+
import { homedir as homedir43 } from "node:os";
|
|
600606
601384
|
import { cwd as cwd3 } from "node:process";
|
|
600607
601385
|
function redactIfSensitive(key, value2) {
|
|
600608
601386
|
if (SENSITIVE_KEYS.has(key) && typeof value2 === "string" && value2.length > 0) {
|
|
@@ -600683,7 +601461,7 @@ function handleShow(opts, config) {
|
|
|
600683
601461
|
}
|
|
600684
601462
|
}
|
|
600685
601463
|
printSection("Config File");
|
|
600686
|
-
printInfo(`~/.open-agents/config.json (${
|
|
601464
|
+
printInfo(`~/.open-agents/config.json (${join118(homedir43(), ".open-agents", "config.json")})`);
|
|
600687
601465
|
printSection("Priority Chain");
|
|
600688
601466
|
printInfo(" 1. CLI flags (--model, --backend-url, etc.)");
|
|
600689
601467
|
printInfo(" 2. Project .oa/settings.json (--local)");
|
|
@@ -600722,7 +601500,7 @@ function handleSet(opts, _config3) {
|
|
|
600722
601500
|
const coerced = coerceForSettings(key, value2);
|
|
600723
601501
|
saveProjectSettings(repoRoot, { [key]: coerced });
|
|
600724
601502
|
printSuccess(`Project override set: ${key} = ${redactIfSensitive(key, value2)}`);
|
|
600725
|
-
printInfo(`Saved to ${
|
|
601503
|
+
printInfo(`Saved to ${join118(repoRoot, ".oa", "settings.json")}`);
|
|
600726
601504
|
printInfo("This override applies only when running in this workspace.");
|
|
600727
601505
|
} catch (err) {
|
|
600728
601506
|
printError(`Failed to save: ${err instanceof Error ? err.message : String(err)}`);
|
|
@@ -600906,8 +601684,8 @@ __export(eval_exports, {
|
|
|
600906
601684
|
evalCommand: () => evalCommand
|
|
600907
601685
|
});
|
|
600908
601686
|
import { tmpdir as tmpdir21 } from "node:os";
|
|
600909
|
-
import { mkdirSync as
|
|
600910
|
-
import { join as
|
|
601687
|
+
import { mkdirSync as mkdirSync66, writeFileSync as writeFileSync58 } from "node:fs";
|
|
601688
|
+
import { join as join119 } from "node:path";
|
|
600911
601689
|
async function evalCommand(opts, config) {
|
|
600912
601690
|
const suiteName = opts.suite ?? "basic";
|
|
600913
601691
|
const suite = SUITES[suiteName];
|
|
@@ -601036,10 +601814,10 @@ async function evalCommand(opts, config) {
|
|
|
601036
601814
|
process.exit(failed > 0 ? 1 : 0);
|
|
601037
601815
|
}
|
|
601038
601816
|
function createTempEvalRepo() {
|
|
601039
|
-
const dir =
|
|
601040
|
-
|
|
601041
|
-
|
|
601042
|
-
|
|
601817
|
+
const dir = join119(tmpdir21(), `open-agents-eval-${Date.now()}`);
|
|
601818
|
+
mkdirSync66(dir, { recursive: true });
|
|
601819
|
+
writeFileSync58(
|
|
601820
|
+
join119(dir, "package.json"),
|
|
601043
601821
|
JSON.stringify({ name: "eval-repo", version: "0.0.0" }, null, 2) + "\n",
|
|
601044
601822
|
"utf8"
|
|
601045
601823
|
);
|
|
@@ -601103,7 +601881,7 @@ init_typed_node_events();
|
|
|
601103
601881
|
import { parseArgs as nodeParseArgs2 } from "node:util";
|
|
601104
601882
|
import { createRequire as createRequire6 } from "node:module";
|
|
601105
601883
|
import { fileURLToPath as fileURLToPath19 } from "node:url";
|
|
601106
|
-
import { dirname as dirname37, join as
|
|
601884
|
+
import { dirname as dirname37, join as join120 } from "node:path";
|
|
601107
601885
|
|
|
601108
601886
|
// packages/cli/src/cli.ts
|
|
601109
601887
|
init_typed_node_events();
|
|
@@ -601243,7 +602021,7 @@ init_output();
|
|
|
601243
602021
|
function getVersion5() {
|
|
601244
602022
|
try {
|
|
601245
602023
|
const require4 = createRequire6(import.meta.url);
|
|
601246
|
-
const pkgPath =
|
|
602024
|
+
const pkgPath = join120(dirname37(fileURLToPath19(import.meta.url)), "..", "package.json");
|
|
601247
602025
|
const pkg = require4(pkgPath);
|
|
601248
602026
|
return pkg.version;
|
|
601249
602027
|
} catch {
|
|
@@ -601557,12 +602335,12 @@ function crashLog(label, err) {
|
|
|
601557
602335
|
const logLine = `[${timestamp}] ${label}: ${msg}
|
|
601558
602336
|
`;
|
|
601559
602337
|
try {
|
|
601560
|
-
const { appendFileSync: appendFileSync9, mkdirSync:
|
|
601561
|
-
const { join:
|
|
601562
|
-
const { homedir:
|
|
601563
|
-
const logDir =
|
|
601564
|
-
|
|
601565
|
-
appendFileSync9(
|
|
602338
|
+
const { appendFileSync: appendFileSync9, mkdirSync: mkdirSync67 } = __require("node:fs");
|
|
602339
|
+
const { join: join121 } = __require("node:path");
|
|
602340
|
+
const { homedir: homedir44 } = __require("node:os");
|
|
602341
|
+
const logDir = join121(homedir44(), ".open-agents");
|
|
602342
|
+
mkdirSync67(logDir, { recursive: true });
|
|
602343
|
+
appendFileSync9(join121(logDir, "crash.log"), logLine);
|
|
601566
602344
|
} catch {
|
|
601567
602345
|
}
|
|
601568
602346
|
try {
|