open-agents-ai 0.187.460 → 0.187.462
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 +297 -17
- package/dist/launcher.cjs +67 -420
- package/dist/postinstall-daemon.cjs +162 -0
- package/dist/preinstall.cjs +2 -506
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -254253,6 +254253,25 @@ var init_todo_write = __esm({
|
|
|
254253
254253
|
}
|
|
254254
254254
|
const sessionId = getTodoSessionId();
|
|
254255
254255
|
const oldTodos = readTodos(sessionId);
|
|
254256
|
+
const canonicalize = (todos) => JSON.stringify(todos.map((t2) => ({
|
|
254257
|
+
content: t2.content,
|
|
254258
|
+
status: t2.status,
|
|
254259
|
+
parentId: t2.parentId ?? null,
|
|
254260
|
+
blocker: t2.blocker ?? null
|
|
254261
|
+
})));
|
|
254262
|
+
const oldKey = canonicalize(oldTodos);
|
|
254263
|
+
const newKey = canonicalize(incoming);
|
|
254264
|
+
if (oldKey === newKey && oldTodos.length > 0) {
|
|
254265
|
+
return {
|
|
254266
|
+
success: true,
|
|
254267
|
+
output: JSON.stringify({
|
|
254268
|
+
reminder: "[NO-OP] You called todo_write with the same plan you already have. The list is unchanged. Use todo_write ONLY to add new tasks, mark a task in_progress / completed, or record a blocker — not as a way to re-read your plan (use todo_read for that, but the current plan is also surfaced automatically in your context). Proceed with the current in_progress task.",
|
|
254269
|
+
todos: oldTodos,
|
|
254270
|
+
noop: true
|
|
254271
|
+
}),
|
|
254272
|
+
durationMs: performance.now() - start2
|
|
254273
|
+
};
|
|
254274
|
+
}
|
|
254256
254275
|
const result = writeTodos(sessionId, incoming);
|
|
254257
254276
|
const closedCount = result.newTodos.filter((t2) => t2.status === "completed").length;
|
|
254258
254277
|
const oldClosedCount = oldTodos.filter((t2) => t2.status === "completed").length;
|
|
@@ -518395,6 +518414,115 @@ ${body}`;
|
|
|
518395
518414
|
* Returns null when the disable knob is set or the backend is missing the
|
|
518396
518415
|
* chatCompletion method.
|
|
518397
518416
|
*/
|
|
518417
|
+
/**
|
|
518418
|
+
* REG-3: Render the current todo list as a compact transient block so the
|
|
518419
|
+
* agent can read its own plan without calling todo_read or re-emitting
|
|
518420
|
+
* todo_write as a scratchpad. Returns null when there are no todos yet.
|
|
518421
|
+
*/
|
|
518422
|
+
_renderTodoStateBlock(turn) {
|
|
518423
|
+
try {
|
|
518424
|
+
const { readTodos: readTodos2 } = __require("@open-agents/execution");
|
|
518425
|
+
const { getTodoSessionId: getTodoSessionId2 } = __require("@open-agents/execution");
|
|
518426
|
+
const sessionId = getTodoSessionId2();
|
|
518427
|
+
const todos = readTodos2(sessionId);
|
|
518428
|
+
if (!todos || todos.length === 0)
|
|
518429
|
+
return null;
|
|
518430
|
+
const lines = ["[CURRENT TODO PLAN — already in your state, no need to call todo_write to see it]"];
|
|
518431
|
+
const inProg = todos.filter((t2) => t2.status === "in_progress");
|
|
518432
|
+
const pending = todos.filter((t2) => t2.status === "pending");
|
|
518433
|
+
const done = todos.filter((t2) => t2.status === "completed");
|
|
518434
|
+
const blocked = todos.filter((t2) => t2.status === "blocked");
|
|
518435
|
+
if (inProg.length > 0) {
|
|
518436
|
+
lines.push(`▶ in_progress (${inProg.length}):`);
|
|
518437
|
+
for (const t2 of inProg)
|
|
518438
|
+
lines.push(` • ${t2.content}`);
|
|
518439
|
+
}
|
|
518440
|
+
if (pending.length > 0) {
|
|
518441
|
+
lines.push(`◯ pending (${pending.length}):`);
|
|
518442
|
+
for (const t2 of pending.slice(0, 8))
|
|
518443
|
+
lines.push(` • ${t2.content}`);
|
|
518444
|
+
if (pending.length > 8)
|
|
518445
|
+
lines.push(` … +${pending.length - 8} more`);
|
|
518446
|
+
}
|
|
518447
|
+
if (blocked.length > 0) {
|
|
518448
|
+
lines.push(`✕ blocked (${blocked.length}):`);
|
|
518449
|
+
for (const t2 of blocked)
|
|
518450
|
+
lines.push(` • ${t2.content}${t2.blocker ? ` — ${t2.blocker}` : ""}`);
|
|
518451
|
+
}
|
|
518452
|
+
if (done.length > 0) {
|
|
518453
|
+
lines.push(`✓ completed (${done.length}): ${done.map((t2) => t2.content.slice(0, 40)).join(" | ")}`);
|
|
518454
|
+
}
|
|
518455
|
+
lines.push(`(turn ${turn} — call todo_write ONLY to update state, never to re-read this plan)`);
|
|
518456
|
+
return lines.join("\n");
|
|
518457
|
+
} catch {
|
|
518458
|
+
return null;
|
|
518459
|
+
}
|
|
518460
|
+
}
|
|
518461
|
+
/**
|
|
518462
|
+
* REG-2: Render a compact "files known to me" block from `_worldFacts`.
|
|
518463
|
+
* Goal: tell the model what it has already touched this run so it stops
|
|
518464
|
+
* re-running `find src -type f` and `list_directory("...")` to confirm
|
|
518465
|
+
* its own outputs.
|
|
518466
|
+
*
|
|
518467
|
+
* Returns null when there is nothing useful to surface yet.
|
|
518468
|
+
*/
|
|
518469
|
+
_renderFilesystemStateBlock(turn) {
|
|
518470
|
+
const wf = this._worldFacts;
|
|
518471
|
+
if (!wf)
|
|
518472
|
+
return null;
|
|
518473
|
+
const files = [...wf.files.entries()];
|
|
518474
|
+
const lists = [...wf.lastLists.entries()];
|
|
518475
|
+
if (files.length === 0 && lists.length === 0 && !wf.lastTest?.summary)
|
|
518476
|
+
return null;
|
|
518477
|
+
const writes = files.filter(([, v]) => (v.writeCount ?? 0) > 0);
|
|
518478
|
+
const reads = files.filter(([, v]) => (v.writeCount ?? 0) === 0);
|
|
518479
|
+
const groupByDir = (entries) => {
|
|
518480
|
+
const m2 = /* @__PURE__ */ new Map();
|
|
518481
|
+
for (const [p2] of entries) {
|
|
518482
|
+
const slash = p2.lastIndexOf("/");
|
|
518483
|
+
const dir = slash > 0 ? p2.slice(0, slash) : ".";
|
|
518484
|
+
const arr = m2.get(dir) ?? [];
|
|
518485
|
+
arr.push(p2);
|
|
518486
|
+
m2.set(dir, arr);
|
|
518487
|
+
}
|
|
518488
|
+
return m2;
|
|
518489
|
+
};
|
|
518490
|
+
const renderGroup = (m2, cap) => {
|
|
518491
|
+
const lines = [];
|
|
518492
|
+
const sorted = [...m2.entries()].sort((a2, b) => b[1].length - a2[1].length);
|
|
518493
|
+
let total = 0;
|
|
518494
|
+
for (const [dir, paths] of sorted) {
|
|
518495
|
+
if (total >= cap) {
|
|
518496
|
+
lines.push(` ... and ${sorted.slice(lines.length).reduce((s2, [, p2]) => s2 + p2.length, 0)} more files in other dirs`);
|
|
518497
|
+
break;
|
|
518498
|
+
}
|
|
518499
|
+
const show = paths.slice(0, 6);
|
|
518500
|
+
lines.push(` ${dir}/ → ${show.map((p2) => p2.slice(dir.length + 1)).join(", ")}${paths.length > show.length ? ` (+${paths.length - show.length} more)` : ""}`);
|
|
518501
|
+
total += paths.length;
|
|
518502
|
+
}
|
|
518503
|
+
return lines.join("\n");
|
|
518504
|
+
};
|
|
518505
|
+
const sections = [];
|
|
518506
|
+
sections.push("[FILES KNOWN — already touched this run; do not re-discover via find/list_directory unless filesystem may have changed externally]");
|
|
518507
|
+
if (writes.length > 0) {
|
|
518508
|
+
sections.push(`Files YOU WROTE this run (${writes.length}):`);
|
|
518509
|
+
sections.push(renderGroup(groupByDir(writes), 40));
|
|
518510
|
+
}
|
|
518511
|
+
if (reads.length > 0) {
|
|
518512
|
+
sections.push(`Files YOU READ this run (${reads.length}):`);
|
|
518513
|
+
sections.push(renderGroup(groupByDir(reads), 20));
|
|
518514
|
+
}
|
|
518515
|
+
if (lists.length > 0) {
|
|
518516
|
+
const recentLists = lists.sort((a2, b) => b[1].lastSeenTurn - a2[1].lastSeenTurn).slice(0, 8);
|
|
518517
|
+
sections.push(`Directories you've listed (${lists.length}):`);
|
|
518518
|
+
sections.push(recentLists.map(([dir, info]) => ` ${dir} (${info.entriesCount} entries, turn ${info.lastSeenTurn})`).join("\n"));
|
|
518519
|
+
}
|
|
518520
|
+
if (wf.lastTest?.summary) {
|
|
518521
|
+
sections.push(`Last test outcome: ${wf.lastTest.passed ? "PASSED" : "FAILED"} (turn ${wf.lastTest.turn ?? "?"})`);
|
|
518522
|
+
}
|
|
518523
|
+
sections.push(`(turn ${turn} — this block is regenerated every turn from your tool history)`);
|
|
518524
|
+
return sections.join("\n");
|
|
518525
|
+
}
|
|
518398
518526
|
makePhaseSummarizer() {
|
|
518399
518527
|
if (process.env["OA_DISABLE_PHASE_SUMMARIZER"] === "1")
|
|
518400
518528
|
return null;
|
|
@@ -519095,7 +519223,7 @@ TASK: ${task}` : task;
|
|
|
519095
519223
|
const recentToolResults = /* @__PURE__ */ new Map();
|
|
519096
519224
|
const toolCallBudget = /* @__PURE__ */ new Map();
|
|
519097
519225
|
const loopTier = this.options.modelTier ?? "large";
|
|
519098
|
-
const toolBudgets = loopTier === "small" ? { web_search: 6, web_fetch: 4, list_directory:
|
|
519226
|
+
const toolBudgets = loopTier === "small" ? { web_search: 6, web_fetch: 4, list_directory: 12, find_files: 10, grep_search: 12 } : loopTier === "medium" ? { web_search: 10, web_fetch: 8, list_directory: 18, find_files: 14, grep_search: 18 } : { web_search: 20, web_fetch: 15, list_directory: 30, find_files: 20, grep_search: 30 };
|
|
519099
519227
|
for (const [tool, budget] of Object.entries(toolBudgets)) {
|
|
519100
519228
|
toolCallBudget.set(tool, budget);
|
|
519101
519229
|
}
|
|
@@ -519462,6 +519590,22 @@ ${memoryLines.join("\n")}`
|
|
|
519462
519590
|
}
|
|
519463
519591
|
});
|
|
519464
519592
|
}
|
|
519593
|
+
const _injections = [];
|
|
519594
|
+
const fsBlock = this._renderFilesystemStateBlock(turn);
|
|
519595
|
+
if (fsBlock)
|
|
519596
|
+
_injections.push(fsBlock);
|
|
519597
|
+
const todoBlock = this._renderTodoStateBlock(turn);
|
|
519598
|
+
if (todoBlock)
|
|
519599
|
+
_injections.push(todoBlock);
|
|
519600
|
+
if (_injections.length > 0) {
|
|
519601
|
+
const reqMsgs = chatRequest.messages;
|
|
519602
|
+
if (Array.isArray(reqMsgs)) {
|
|
519603
|
+
const insertAt = Math.max(0, reqMsgs.length - 1);
|
|
519604
|
+
for (const blk of _injections) {
|
|
519605
|
+
reqMsgs.splice(insertAt, 0, { role: "system", content: blk });
|
|
519606
|
+
}
|
|
519607
|
+
}
|
|
519608
|
+
}
|
|
519465
519609
|
let response;
|
|
519466
519610
|
try {
|
|
519467
519611
|
response = this.options.streamEnabled && this.hasStreamingSupport() ? await this.streamingRequest(chatRequest, turn) : await this.backend.chatCompletion(chatRequest);
|
|
@@ -519741,14 +519885,56 @@ ${memoryLines.join("\n")}`
|
|
|
519741
519885
|
content: `Phase contraction: ${contracted.join(", ")} → contracted (${summarizer ? "LLM-summarized" : "stub-summarized"}, anchors retained)`,
|
|
519742
519886
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
519743
519887
|
});
|
|
519888
|
+
try {
|
|
519889
|
+
const archDir = __require("node:path").join(process.cwd(), ".oa", "phases");
|
|
519890
|
+
__require("node:fs").mkdirSync(archDir, { recursive: true });
|
|
519891
|
+
for (const phaseName of contracted) {
|
|
519892
|
+
const node = this._contextTree.getSnapshot().phases[phaseName];
|
|
519893
|
+
if (!node)
|
|
519894
|
+
continue;
|
|
519895
|
+
const stamp = `${phaseName}-${Date.now().toString(36)}-turn${turn}`;
|
|
519896
|
+
const archPath = __require("node:path").join(archDir, `${stamp}.jsonl`);
|
|
519897
|
+
const archived = {
|
|
519898
|
+
phase: phaseName,
|
|
519899
|
+
contractedAtTurn: turn,
|
|
519900
|
+
contractedAtIso: (/* @__PURE__ */ new Date()).toISOString(),
|
|
519901
|
+
anchors: node.anchors,
|
|
519902
|
+
summary: node.summary ?? null,
|
|
519903
|
+
messages: node.messages ?? []
|
|
519904
|
+
};
|
|
519905
|
+
__require("node:fs").writeFileSync(archPath, JSON.stringify(archived) + "\n", "utf-8");
|
|
519906
|
+
this._contextTree.archive(phaseName, archPath);
|
|
519907
|
+
}
|
|
519908
|
+
this.emit({
|
|
519909
|
+
type: "status",
|
|
519910
|
+
content: `Phase archive: ${contracted.length} phase(s) written to .oa/phases/`,
|
|
519911
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
519912
|
+
});
|
|
519913
|
+
} catch (archErr) {
|
|
519914
|
+
this.emit({
|
|
519915
|
+
type: "status",
|
|
519916
|
+
content: `Phase archive failed (non-fatal): ${archErr instanceof Error ? archErr.message : String(archErr)}`,
|
|
519917
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
519918
|
+
});
|
|
519919
|
+
}
|
|
519744
519920
|
}
|
|
519745
519921
|
this._phaseMessageStartIdx = messages2.length;
|
|
519746
519922
|
this._taskState.phase = transition.to;
|
|
519747
519923
|
this._taskState.phaseSince = turn;
|
|
519924
|
+
for (const [tool2, budget] of Object.entries(toolBudgets)) {
|
|
519925
|
+
toolCallBudget.set(tool2, budget);
|
|
519926
|
+
}
|
|
519927
|
+
this.emit({
|
|
519928
|
+
type: "status",
|
|
519929
|
+
content: `Tool budgets reset for new phase (${Object.keys(toolBudgets).length} tools)`,
|
|
519930
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
519931
|
+
});
|
|
519748
519932
|
}
|
|
519749
519933
|
}
|
|
519934
|
+
const _argsKeyForBudget = `${tc.name}:${argsKey}`;
|
|
519935
|
+
const _isCachedHit = recentToolResults.has(_argsKeyForBudget);
|
|
519750
519936
|
const budgetRemaining = toolCallBudget.get(tc.name);
|
|
519751
|
-
if (budgetRemaining !== void 0) {
|
|
519937
|
+
if (budgetRemaining !== void 0 && !_isCachedHit) {
|
|
519752
519938
|
if (budgetRemaining <= 0) {
|
|
519753
519939
|
this.emit({
|
|
519754
519940
|
type: "tool_call",
|
|
@@ -519757,7 +519943,7 @@ ${memoryLines.join("\n")}`
|
|
|
519757
519943
|
turn,
|
|
519758
519944
|
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
519759
519945
|
});
|
|
519760
|
-
const budgetMsg = `[BUDGET EXHAUSTED] You have used all ${toolBudgets[tc.name]} allowed ${tc.name} calls for
|
|
519946
|
+
const budgetMsg = `[BUDGET EXHAUSTED] You have used all ${toolBudgets[tc.name]} allowed ${tc.name} calls for the current phase. You ALREADY have enough information from previous calls. DO NOT try to call ${tc.name} again — it will be blocked. If your todo list shows more phases pending: mark the current phase completed via todo_write so a new budget allowance kicks in. If all phases are done: call task_complete with your final summary.`;
|
|
519761
519947
|
this.emit({
|
|
519762
519948
|
type: "tool_result",
|
|
519763
519949
|
toolName: tc.name,
|
|
@@ -519939,10 +520125,33 @@ ${cachedEntry2.result.slice(0, 500)}` : `[BLOCKED — the observer confirmed thi
|
|
|
519939
520125
|
updated.lastOutcomeTurn = turn;
|
|
519940
520126
|
this._argCohorts.set(cohortKey, updated);
|
|
519941
520127
|
try {
|
|
520128
|
+
if (tc.name === "file_write" || tc.name === "file_edit" || tc.name === "edit_block") {
|
|
520129
|
+
const p2 = String(tc.arguments?.["path"] ?? tc.arguments?.["file_path"] ?? tc.arguments?.["file"] ?? "");
|
|
520130
|
+
if (p2 && result.success) {
|
|
520131
|
+
const prev = this._worldFacts.files.get(p2);
|
|
520132
|
+
this._worldFacts.files.set(p2, {
|
|
520133
|
+
exists: true,
|
|
520134
|
+
size: prev?.size,
|
|
520135
|
+
hashSample: prev?.hashSample,
|
|
520136
|
+
lastSeenTurn: turn,
|
|
520137
|
+
lastWriteTurn: turn,
|
|
520138
|
+
writeCount: (prev?.writeCount ?? 0) + 1
|
|
520139
|
+
});
|
|
520140
|
+
}
|
|
520141
|
+
}
|
|
519942
520142
|
if (tc.name === "file_read") {
|
|
519943
520143
|
const p2 = String(tc.arguments?.["path"] ?? tc.arguments?.["file"] ?? "");
|
|
519944
|
-
if (p2)
|
|
519945
|
-
this._worldFacts.files.
|
|
520144
|
+
if (p2) {
|
|
520145
|
+
const prev = this._worldFacts.files.get(p2);
|
|
520146
|
+
this._worldFacts.files.set(p2, {
|
|
520147
|
+
exists: result.success,
|
|
520148
|
+
size: (result.output || "").length,
|
|
520149
|
+
hashSample: (result.output || "").slice(0, 32),
|
|
520150
|
+
lastSeenTurn: turn,
|
|
520151
|
+
lastWriteTurn: prev?.lastWriteTurn,
|
|
520152
|
+
writeCount: prev?.writeCount
|
|
520153
|
+
});
|
|
520154
|
+
}
|
|
519946
520155
|
if (this._fileSummaryStore && result.success && result.output && result.output.length > 100) {
|
|
519947
520156
|
try {
|
|
519948
520157
|
const existing = this._fileSummaryStore.get(p2);
|
|
@@ -542292,6 +542501,23 @@ async function ensureExpandedContext(modelName, backendUrl) {
|
|
|
542292
542501
|
return { model: modelName, created: false, contextLabel: "", numCtx: 0 };
|
|
542293
542502
|
}
|
|
542294
542503
|
if (typeof existing === "string") {
|
|
542504
|
+
const lostTools = await wrapperLacksToolsCapability(backendUrl, existing).catch(() => false);
|
|
542505
|
+
if (lostTools) {
|
|
542506
|
+
try {
|
|
542507
|
+
const rebuilt = await createExpandedVariantNamedAsync(
|
|
542508
|
+
stripVariantTag(existing),
|
|
542509
|
+
modelName,
|
|
542510
|
+
specs,
|
|
542511
|
+
sizeGB,
|
|
542512
|
+
kvInfo?.kvBytesPerToken,
|
|
542513
|
+
kvInfo?.archMax
|
|
542514
|
+
);
|
|
542515
|
+
if (rebuilt) {
|
|
542516
|
+
return { model: rebuilt, created: true, contextLabel: ctx3.label, numCtx: ctx3.numCtx };
|
|
542517
|
+
}
|
|
542518
|
+
} catch {
|
|
542519
|
+
}
|
|
542520
|
+
}
|
|
542295
542521
|
const repair = await repairExpandedVariantIfStale(
|
|
542296
542522
|
existing,
|
|
542297
542523
|
modelName,
|
|
@@ -542310,6 +542536,38 @@ async function ensureExpandedContext(modelName, backendUrl) {
|
|
|
542310
542536
|
}
|
|
542311
542537
|
return { model: modelName, created: false, contextLabel: ctx3.label, numCtx: ctx3.numCtx };
|
|
542312
542538
|
}
|
|
542539
|
+
function guessBaseFromVariant(variantName, models) {
|
|
542540
|
+
const stripped = stripVariantTag(variantName);
|
|
542541
|
+
for (const m2 of models) {
|
|
542542
|
+
if (/^open-agents-/i.test(m2.name)) continue;
|
|
542543
|
+
const candidates = expandedModelCandidates(stripVariantTag(m2.name));
|
|
542544
|
+
if (candidates.includes(stripped)) {
|
|
542545
|
+
return m2.name;
|
|
542546
|
+
}
|
|
542547
|
+
}
|
|
542548
|
+
return null;
|
|
542549
|
+
}
|
|
542550
|
+
async function wrapperLacksToolsCapability(backendUrl, modelName) {
|
|
542551
|
+
try {
|
|
542552
|
+
const normalized = backendUrl.replace(/\/+$/, "");
|
|
542553
|
+
const showRes = await fetch(`${normalized}/api/show`, {
|
|
542554
|
+
method: "POST",
|
|
542555
|
+
headers: { "Content-Type": "application/json" },
|
|
542556
|
+
body: JSON.stringify({ name: modelName }),
|
|
542557
|
+
signal: AbortSignal.timeout(5e3)
|
|
542558
|
+
});
|
|
542559
|
+
if (!showRes.ok) return false;
|
|
542560
|
+
const showData = await showRes.json();
|
|
542561
|
+
const caps = Array.isArray(showData.capabilities) ? showData.capabilities : [];
|
|
542562
|
+
const hasTools = caps.some((c9) => /^tools?$/i.test(c9));
|
|
542563
|
+
if (hasTools) return false;
|
|
542564
|
+
const fromMatch = showData.modelfile?.match(/^FROM\s+(.+)$/m);
|
|
542565
|
+
const fromVal = fromMatch?.[1]?.trim() ?? "";
|
|
542566
|
+
return fromVal.startsWith("/") || /blobs\/sha256[-:]/.test(fromVal);
|
|
542567
|
+
} catch {
|
|
542568
|
+
return false;
|
|
542569
|
+
}
|
|
542570
|
+
}
|
|
542313
542571
|
async function repairAllExpandedVariants(backendUrl) {
|
|
542314
542572
|
const specs = await detectSystemSpecsAsync();
|
|
542315
542573
|
const models = await fetchOllamaModels(backendUrl);
|
|
@@ -542327,25 +542585,47 @@ async function repairAllExpandedVariants(backendUrl) {
|
|
|
542327
542585
|
summary.failed.push({ model: variant.name, reason: "missing-state" });
|
|
542328
542586
|
continue;
|
|
542329
542587
|
}
|
|
542330
|
-
|
|
542588
|
+
let baseModel = state.baseModel && !state.baseModel.startsWith("open-agents-") ? state.baseModel : null;
|
|
542589
|
+
if (!baseModel) {
|
|
542590
|
+
baseModel = guessBaseFromVariant(variant.name, models);
|
|
542591
|
+
}
|
|
542331
542592
|
if (!baseModel) {
|
|
542332
542593
|
summary.failed.push({ model: variant.name, reason: "missing-base-model" });
|
|
542333
542594
|
continue;
|
|
542334
542595
|
}
|
|
542335
|
-
const sizeGB = modelSizeGB(models, baseModel
|
|
542596
|
+
const sizeGB = modelSizeGB(models, baseModel);
|
|
542336
542597
|
const kvInfo = await queryModelKVInfo(backendUrl, baseModel);
|
|
542337
542598
|
const target = calculateExpandedVariantContextWindow(specs, sizeGB, kvInfo?.kvBytesPerToken, kvInfo?.archMax);
|
|
542599
|
+
const lostTools = await wrapperLacksToolsCapability(backendUrl, variant.name);
|
|
542338
542600
|
try {
|
|
542339
|
-
|
|
542340
|
-
|
|
542341
|
-
|
|
542342
|
-
|
|
542343
|
-
|
|
542344
|
-
|
|
542345
|
-
|
|
542346
|
-
|
|
542347
|
-
|
|
542348
|
-
|
|
542601
|
+
let result;
|
|
542602
|
+
if (lostTools) {
|
|
542603
|
+
const created = await createExpandedVariantNamedAsync(
|
|
542604
|
+
stripVariantTag(variant.name),
|
|
542605
|
+
baseModel,
|
|
542606
|
+
specs,
|
|
542607
|
+
sizeGB,
|
|
542608
|
+
kvInfo?.kvBytesPerToken,
|
|
542609
|
+
kvInfo?.archMax
|
|
542610
|
+
);
|
|
542611
|
+
result = {
|
|
542612
|
+
repaired: !!created,
|
|
542613
|
+
currentNumCtx: state.currentNumCtx,
|
|
542614
|
+
baseModel,
|
|
542615
|
+
resolvedModel: created ?? variant.name
|
|
542616
|
+
};
|
|
542617
|
+
} else {
|
|
542618
|
+
result = await repairExpandedVariantIfStale(
|
|
542619
|
+
variant.name,
|
|
542620
|
+
baseModel,
|
|
542621
|
+
backendUrl,
|
|
542622
|
+
specs,
|
|
542623
|
+
sizeGB,
|
|
542624
|
+
target.numCtx,
|
|
542625
|
+
kvInfo?.kvBytesPerToken,
|
|
542626
|
+
kvInfo?.archMax
|
|
542627
|
+
);
|
|
542628
|
+
}
|
|
542349
542629
|
if (result.repaired) {
|
|
542350
542630
|
summary.repaired.push({
|
|
542351
542631
|
model: result.resolvedModel,
|