open-agents-ai 0.103.6 → 0.103.7
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 +184 -15
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -28448,7 +28448,77 @@ function buildDirTree(root, maxDepth, prefix = "", depth = 0) {
|
|
|
28448
28448
|
}
|
|
28449
28449
|
return result;
|
|
28450
28450
|
}
|
|
28451
|
-
|
|
28451
|
+
function loadUsageFile(filePath) {
|
|
28452
|
+
try {
|
|
28453
|
+
if (existsSync28(filePath)) {
|
|
28454
|
+
return JSON.parse(readFileSync20(filePath, "utf-8"));
|
|
28455
|
+
}
|
|
28456
|
+
} catch {
|
|
28457
|
+
}
|
|
28458
|
+
return { records: [] };
|
|
28459
|
+
}
|
|
28460
|
+
function saveUsageFile(filePath, data) {
|
|
28461
|
+
const dir = join38(filePath, "..");
|
|
28462
|
+
mkdirSync9(dir, { recursive: true });
|
|
28463
|
+
writeFileSync9(filePath, JSON.stringify(data, null, 2) + "\n", { encoding: "utf-8", mode: 384 });
|
|
28464
|
+
}
|
|
28465
|
+
function recordUsage(kind, value, opts) {
|
|
28466
|
+
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
28467
|
+
const update = (filePath) => {
|
|
28468
|
+
const data = loadUsageFile(filePath);
|
|
28469
|
+
const existing = data.records.find((r) => r.kind === kind && r.value === value);
|
|
28470
|
+
if (existing) {
|
|
28471
|
+
existing.useCount++;
|
|
28472
|
+
existing.lastUsed = now;
|
|
28473
|
+
if (opts?.meta)
|
|
28474
|
+
existing.meta = { ...existing.meta, ...opts.meta };
|
|
28475
|
+
} else {
|
|
28476
|
+
data.records.push({
|
|
28477
|
+
value,
|
|
28478
|
+
kind,
|
|
28479
|
+
useCount: 1,
|
|
28480
|
+
firstUsed: now,
|
|
28481
|
+
lastUsed: now,
|
|
28482
|
+
meta: opts?.meta
|
|
28483
|
+
});
|
|
28484
|
+
}
|
|
28485
|
+
if (data.records.length > MAX_HISTORY_RECORDS) {
|
|
28486
|
+
data.records.sort((a, b) => new Date(b.lastUsed).getTime() - new Date(a.lastUsed).getTime());
|
|
28487
|
+
data.records = data.records.slice(0, MAX_HISTORY_RECORDS);
|
|
28488
|
+
}
|
|
28489
|
+
saveUsageFile(filePath, data);
|
|
28490
|
+
};
|
|
28491
|
+
update(join38(homedir9(), ".open-agents", USAGE_HISTORY_FILE));
|
|
28492
|
+
if (opts?.repoRoot) {
|
|
28493
|
+
update(join38(opts.repoRoot, OA_DIR, USAGE_HISTORY_FILE));
|
|
28494
|
+
}
|
|
28495
|
+
}
|
|
28496
|
+
function loadUsageHistory(kind, repoRoot) {
|
|
28497
|
+
const globalPath = join38(homedir9(), ".open-agents", USAGE_HISTORY_FILE);
|
|
28498
|
+
const globalData = loadUsageFile(globalPath);
|
|
28499
|
+
const localData = repoRoot ? loadUsageFile(join38(repoRoot, OA_DIR, USAGE_HISTORY_FILE)) : { records: [] };
|
|
28500
|
+
const map = /* @__PURE__ */ new Map();
|
|
28501
|
+
for (const r of globalData.records) {
|
|
28502
|
+
if (r.kind !== kind)
|
|
28503
|
+
continue;
|
|
28504
|
+
map.set(r.value, { ...r, localUses: 0 });
|
|
28505
|
+
}
|
|
28506
|
+
for (const r of localData.records) {
|
|
28507
|
+
if (r.kind !== kind)
|
|
28508
|
+
continue;
|
|
28509
|
+
const existing = map.get(r.value);
|
|
28510
|
+
if (existing) {
|
|
28511
|
+
existing.localUses = r.useCount;
|
|
28512
|
+
if (new Date(r.lastUsed) > new Date(existing.lastUsed)) {
|
|
28513
|
+
existing.lastUsed = r.lastUsed;
|
|
28514
|
+
}
|
|
28515
|
+
} else {
|
|
28516
|
+
map.set(r.value, { ...r, localUses: r.useCount });
|
|
28517
|
+
}
|
|
28518
|
+
}
|
|
28519
|
+
return Array.from(map.values()).sort((a, b) => new Date(b.lastUsed).getTime() - new Date(a.lastUsed).getTime());
|
|
28520
|
+
}
|
|
28521
|
+
var OA_DIR, SUBDIRS, CONTEXT_FILES, PENDING_TASK_FILE, CONTEXT_SAVE_FILE, MAX_CONTEXT_ENTRIES, SKIP_DIRS, USAGE_HISTORY_FILE, MAX_HISTORY_RECORDS;
|
|
28452
28522
|
var init_oa_directory = __esm({
|
|
28453
28523
|
"packages/cli/dist/tui/oa-directory.js"() {
|
|
28454
28524
|
"use strict";
|
|
@@ -28486,6 +28556,8 @@ var init_oa_directory = __esm({
|
|
|
28486
28556
|
".idea",
|
|
28487
28557
|
".vscode"
|
|
28488
28558
|
]);
|
|
28559
|
+
USAGE_HISTORY_FILE = "usage-history.json";
|
|
28560
|
+
MAX_HISTORY_RECORDS = 50;
|
|
28489
28561
|
}
|
|
28490
28562
|
});
|
|
28491
28563
|
|
|
@@ -30024,12 +30096,22 @@ function tuiSelect(opts) {
|
|
|
30024
30096
|
const { items, title, rl } = opts;
|
|
30025
30097
|
const renderRow = opts.renderRow ?? defaultRenderRow;
|
|
30026
30098
|
const activeKey = opts.activeKey ?? null;
|
|
30099
|
+
const skipSet = new Set(opts.skipKeys ?? []);
|
|
30027
30100
|
if (items.length === 0) {
|
|
30028
30101
|
return Promise.resolve({ confirmed: false, key: null, index: -1 });
|
|
30029
30102
|
}
|
|
30103
|
+
const isSkippable = (idx) => skipSet.has(items[idx].key);
|
|
30104
|
+
const findSelectable = (from, dir) => {
|
|
30105
|
+
let idx = from;
|
|
30106
|
+
while (idx >= 0 && idx < items.length && isSkippable(idx)) {
|
|
30107
|
+
idx += dir;
|
|
30108
|
+
}
|
|
30109
|
+
return idx >= 0 && idx < items.length ? idx : from;
|
|
30110
|
+
};
|
|
30030
30111
|
let cursor = activeKey ? items.findIndex((i) => i.key === activeKey) : 0;
|
|
30031
30112
|
if (cursor < 0)
|
|
30032
30113
|
cursor = 0;
|
|
30114
|
+
cursor = findSelectable(cursor, 1);
|
|
30033
30115
|
const termRows = process.stdout.rows ?? 24;
|
|
30034
30116
|
const maxVisible = opts.maxVisible ?? Math.max(5, termRows - 6);
|
|
30035
30117
|
let scrollOffset = Math.max(0, cursor - Math.floor(maxVisible / 2));
|
|
@@ -30037,8 +30119,16 @@ function tuiSelect(opts) {
|
|
|
30037
30119
|
return new Promise((resolve31) => {
|
|
30038
30120
|
const stdin = process.stdin;
|
|
30039
30121
|
const hadRawMode = stdin.isRaw;
|
|
30122
|
+
const savedRlListeners = [];
|
|
30040
30123
|
if (rl) {
|
|
30041
30124
|
rl.pause();
|
|
30125
|
+
for (const event of ["keypress", "data"]) {
|
|
30126
|
+
const listeners = stdin.listeners(event);
|
|
30127
|
+
for (const fn of listeners) {
|
|
30128
|
+
savedRlListeners.push({ event, fn });
|
|
30129
|
+
stdin.removeListener(event, fn);
|
|
30130
|
+
}
|
|
30131
|
+
}
|
|
30042
30132
|
}
|
|
30043
30133
|
if (typeof stdin.setRawMode === "function") {
|
|
30044
30134
|
stdin.setRawMode(true);
|
|
@@ -30076,6 +30166,10 @@ function tuiSelect(opts) {
|
|
|
30076
30166
|
const visibleEnd = Math.min(items.length, scrollOffset + maxVisible);
|
|
30077
30167
|
for (let i = scrollOffset; i < visibleEnd; i++) {
|
|
30078
30168
|
const item = items[i];
|
|
30169
|
+
if (isSkippable(i)) {
|
|
30170
|
+
lines.push(` ${item.label}`);
|
|
30171
|
+
continue;
|
|
30172
|
+
}
|
|
30079
30173
|
const focused = i === cursor;
|
|
30080
30174
|
const isActive = item.key === activeKey;
|
|
30081
30175
|
lines.push(renderRow(item, focused, isActive));
|
|
@@ -30104,6 +30198,9 @@ function tuiSelect(opts) {
|
|
|
30104
30198
|
if (typeof stdin.setRawMode === "function") {
|
|
30105
30199
|
stdin.setRawMode(hadRawMode ?? false);
|
|
30106
30200
|
}
|
|
30201
|
+
for (const { event, fn } of savedRlListeners) {
|
|
30202
|
+
stdin.on(event, fn);
|
|
30203
|
+
}
|
|
30107
30204
|
if (rl) {
|
|
30108
30205
|
rl.resume();
|
|
30109
30206
|
rl.prompt(false);
|
|
@@ -30112,20 +30209,28 @@ function tuiSelect(opts) {
|
|
|
30112
30209
|
function onData(chunk) {
|
|
30113
30210
|
const seq = chunk.toString("utf8");
|
|
30114
30211
|
if (seq === "\x1B[A" || seq === "k") {
|
|
30115
|
-
|
|
30116
|
-
|
|
30212
|
+
const next = cursor - 1;
|
|
30213
|
+
if (next >= 0) {
|
|
30214
|
+
cursor = findSelectable(next, -1);
|
|
30215
|
+
render();
|
|
30216
|
+
}
|
|
30117
30217
|
} else if (seq === "\x1B[B" || seq === "j") {
|
|
30118
|
-
|
|
30119
|
-
|
|
30218
|
+
const next = cursor + 1;
|
|
30219
|
+
if (next < items.length) {
|
|
30220
|
+
cursor = findSelectable(next, 1);
|
|
30221
|
+
render();
|
|
30222
|
+
}
|
|
30120
30223
|
} else if (seq === "\x1B[H" || seq === "g") {
|
|
30121
|
-
cursor = 0;
|
|
30224
|
+
cursor = findSelectable(0, 1);
|
|
30122
30225
|
render();
|
|
30123
30226
|
} else if (seq === "\x1B[F" || seq === "G") {
|
|
30124
|
-
cursor = items.length - 1;
|
|
30227
|
+
cursor = findSelectable(items.length - 1, -1);
|
|
30125
30228
|
render();
|
|
30126
30229
|
} else if (seq === "\r" || seq === "\n") {
|
|
30127
|
-
|
|
30128
|
-
|
|
30230
|
+
if (!isSkippable(cursor)) {
|
|
30231
|
+
cleanup();
|
|
30232
|
+
resolve31({ confirmed: true, key: items[cursor].key, index: cursor });
|
|
30233
|
+
}
|
|
30129
30234
|
} else if (seq === "\x1B" || seq === "\x1B\x1B" || seq === "q") {
|
|
30130
30235
|
cleanup();
|
|
30131
30236
|
resolve31({ confirmed: false, key: null, index: cursor });
|
|
@@ -31274,16 +31379,39 @@ async function showModelPicker(ctx, local = false) {
|
|
|
31274
31379
|
renderWarning("No models found.");
|
|
31275
31380
|
return;
|
|
31276
31381
|
}
|
|
31277
|
-
const items =
|
|
31278
|
-
|
|
31279
|
-
|
|
31280
|
-
|
|
31281
|
-
|
|
31382
|
+
const items = [];
|
|
31383
|
+
const history = loadUsageHistory("model", ctx.repoRoot);
|
|
31384
|
+
const liveModelNames = new Set(models.map((m) => m.name));
|
|
31385
|
+
if (history.length > 0) {
|
|
31386
|
+
items.push({ key: "__header_recent__", label: c2.dim("\u2500\u2500 Recent \u2500\u2500"), detail: "" });
|
|
31387
|
+
for (const h of history.slice(0, 8)) {
|
|
31388
|
+
const uses = h.localUses > 0 ? `${h.useCount} uses (${h.localUses} local)` : `${h.useCount} uses`;
|
|
31389
|
+
const available = liveModelNames.has(h.value) ? "" : c2.yellow(" [offline]");
|
|
31390
|
+
items.push({
|
|
31391
|
+
key: h.value,
|
|
31392
|
+
label: h.value,
|
|
31393
|
+
detail: `${uses}${available}`
|
|
31394
|
+
});
|
|
31395
|
+
}
|
|
31396
|
+
items.push({ key: "__header_available__", label: c2.dim("\u2500\u2500 Available \u2500\u2500"), detail: "" });
|
|
31397
|
+
}
|
|
31398
|
+
const historyKeys = new Set(history.map((h) => h.value));
|
|
31399
|
+
for (const m of models) {
|
|
31400
|
+
if (history.length > 0 && historyKeys.has(m.name))
|
|
31401
|
+
continue;
|
|
31402
|
+
items.push({
|
|
31403
|
+
key: m.name,
|
|
31404
|
+
label: m.name,
|
|
31405
|
+
detail: [m.parameterSize, m.size, m.modified].filter(Boolean).join(" ")
|
|
31406
|
+
});
|
|
31407
|
+
}
|
|
31282
31408
|
const result = await tuiSelect({
|
|
31283
31409
|
items,
|
|
31284
31410
|
activeKey: ctx.config.model,
|
|
31285
31411
|
title: "Select Model",
|
|
31286
|
-
rl: ctx.rl
|
|
31412
|
+
rl: ctx.rl,
|
|
31413
|
+
// Skip header rows
|
|
31414
|
+
skipKeys: ["__header_recent__", "__header_available__"]
|
|
31287
31415
|
});
|
|
31288
31416
|
if (!result.confirmed || !result.key) {
|
|
31289
31417
|
renderInfo("Model selection cancelled.");
|
|
@@ -31296,6 +31424,30 @@ async function showModelPicker(ctx, local = false) {
|
|
|
31296
31424
|
}
|
|
31297
31425
|
async function handleEndpoint(arg, ctx, local = false) {
|
|
31298
31426
|
if (!arg) {
|
|
31427
|
+
const history = loadUsageHistory("endpoint", ctx.repoRoot);
|
|
31428
|
+
if (history.length > 0) {
|
|
31429
|
+
const items = history.map((h) => {
|
|
31430
|
+
const provider2 = h.meta?.provider ?? detectProvider(h.value).label;
|
|
31431
|
+
const uses = h.localUses > 0 ? `${h.useCount} uses (${h.localUses} local)` : `${h.useCount} uses`;
|
|
31432
|
+
return {
|
|
31433
|
+
key: h.value,
|
|
31434
|
+
label: h.value,
|
|
31435
|
+
detail: `${provider2} ${uses}`
|
|
31436
|
+
};
|
|
31437
|
+
});
|
|
31438
|
+
const result = await tuiSelect({
|
|
31439
|
+
items,
|
|
31440
|
+
activeKey: ctx.config.backendUrl,
|
|
31441
|
+
title: "Select Endpoint",
|
|
31442
|
+
rl: ctx.rl
|
|
31443
|
+
});
|
|
31444
|
+
if (result.confirmed && result.key) {
|
|
31445
|
+
await handleEndpoint(result.key, ctx, local);
|
|
31446
|
+
return;
|
|
31447
|
+
}
|
|
31448
|
+
renderInfo("Endpoint selection cancelled.");
|
|
31449
|
+
return;
|
|
31450
|
+
}
|
|
31299
31451
|
const currentProvider = detectProvider(ctx.config.backendUrl);
|
|
31300
31452
|
process.stdout.write(`
|
|
31301
31453
|
${c2.bold("Current endpoint:")}
|
|
@@ -31399,6 +31551,15 @@ async function handleEndpoint(arg, ctx, local = false) {
|
|
|
31399
31551
|
}
|
|
31400
31552
|
ctx.saveSettings(endpointSettings);
|
|
31401
31553
|
}
|
|
31554
|
+
recordUsage("endpoint", normalizedUrl, {
|
|
31555
|
+
repoRoot: local ? ctx.repoRoot : void 0,
|
|
31556
|
+
local,
|
|
31557
|
+
meta: {
|
|
31558
|
+
provider: provider.label,
|
|
31559
|
+
backendType,
|
|
31560
|
+
...apiKey ? { authHint: apiKey.slice(0, 4) + "..." } : {}
|
|
31561
|
+
}
|
|
31562
|
+
});
|
|
31402
31563
|
process.stdout.write(`
|
|
31403
31564
|
${c2.green("\u2714")} Endpoint updated and saved${local ? " (project-local)" : ""}:
|
|
31404
31565
|
`);
|
|
@@ -31715,6 +31876,14 @@ async function switchModel(query, ctx, local = false) {
|
|
|
31715
31876
|
if (local) {
|
|
31716
31877
|
renderInfo("Saved as project-local override.");
|
|
31717
31878
|
}
|
|
31879
|
+
recordUsage("model", finalModel, {
|
|
31880
|
+
repoRoot: local ? ctx.repoRoot : void 0,
|
|
31881
|
+
local,
|
|
31882
|
+
meta: {
|
|
31883
|
+
endpoint: ctx.config.backendUrl,
|
|
31884
|
+
parameterSize: match.parameterSize ?? ""
|
|
31885
|
+
}
|
|
31886
|
+
});
|
|
31718
31887
|
if (ctx.setContextWindowSize) {
|
|
31719
31888
|
const ctxSize = await queryContextSize(ctx.config.backendUrl, finalModel, ctx.config.apiKey);
|
|
31720
31889
|
if (ctxSize) {
|
package/package.json
CHANGED