@modeloslab/modelcode 0.1.3 → 0.1.4
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/cli.mjs
CHANGED
|
@@ -56,6 +56,7 @@ import {
|
|
|
56
56
|
searchFacts,
|
|
57
57
|
searchSessions,
|
|
58
58
|
shellInvocation,
|
|
59
|
+
shellName,
|
|
59
60
|
snapshot,
|
|
60
61
|
spawnProc,
|
|
61
62
|
toolSchemas,
|
|
@@ -63,7 +64,7 @@ import {
|
|
|
63
64
|
validateMnemonic,
|
|
64
65
|
walletFromMnemonic,
|
|
65
66
|
which
|
|
66
|
-
} from "./main-
|
|
67
|
+
} from "./main-wr686fnv.mjs";
|
|
67
68
|
import"./main-p2xnn95s.mjs";
|
|
68
69
|
import {
|
|
69
70
|
__require
|
|
@@ -141,7 +142,7 @@ function inside(cwd, p) {
|
|
|
141
142
|
}
|
|
142
143
|
var bash = {
|
|
143
144
|
name: "bash",
|
|
144
|
-
description:
|
|
145
|
+
description: `Run a shell command in the working directory (shell: ${shellName()}); returns combined stdout+stderr. Use for builds, tests, git, file ops.${shellName() === "powershell" || shellName() === "pwsh" ? " NOTE: this is Windows PowerShell — use PowerShell syntax (Get-ChildItem/ls, Get-Content/cat, 2>$null, Select-Object -First N)." : shellName() === "cmd" ? " NOTE: this is Windows cmd.exe — use cmd syntax." : ""}`,
|
|
145
146
|
permission: "ask",
|
|
146
147
|
parameters: {
|
|
147
148
|
type: "object",
|
|
@@ -331,7 +332,9 @@ function registerAgentTool(cfg, onProgress) {
|
|
|
331
332
|
if (!agent)
|
|
332
333
|
return `error: unknown subagent '${args.subagent_type}'. available: ${names.join(", ")}`;
|
|
333
334
|
const { text, feeGrains } = await runSubagent(cfg, agent, String(args.prompt ?? ""), ctx, onProgress);
|
|
334
|
-
|
|
335
|
+
ctx.onCost?.(feeGrains);
|
|
336
|
+
onProgress?.(` ↳ ${agent.name} done · ${(feeGrains / 1e8).toFixed(4)} MDL`);
|
|
337
|
+
return `[${agent.name} · ${(feeGrains / 1e8).toFixed(6)} MDL]
|
|
335
338
|
${text}`;
|
|
336
339
|
}
|
|
337
340
|
};
|
|
@@ -352,7 +355,8 @@ ${text}`;
|
|
|
352
355
|
async run(args, ctx) {
|
|
353
356
|
const members = Array.isArray(args.members) ? args.members.map(String) : [];
|
|
354
357
|
const { transcript, feeGrains } = await runTeam(cfg, members, String(args.prompt ?? ""), ctx, Number(args.rounds) || 2, onProgress);
|
|
355
|
-
|
|
358
|
+
ctx.onCost?.(feeGrains);
|
|
359
|
+
return `[team · ${(feeGrains / 1e8).toFixed(6)} MDL]
|
|
356
360
|
${transcript}`;
|
|
357
361
|
}
|
|
358
362
|
};
|
|
@@ -407,6 +411,16 @@ class Agent {
|
|
|
407
411
|
note(text) {
|
|
408
412
|
this.history.push({ role: "system", content: `User steering note (apply going forward): ${text}` });
|
|
409
413
|
}
|
|
414
|
+
async sideQuestion(question, onDelta) {
|
|
415
|
+
const forked = [
|
|
416
|
+
...this.history,
|
|
417
|
+
{ role: "system", content: "The user has a quick side question. Answer it concisely using the conversation so far. This does NOT change the current task." },
|
|
418
|
+
{ role: "user", content: question }
|
|
419
|
+
];
|
|
420
|
+
const res = await chat(this.cfg, forked, [], onDelta ?? (() => {}), this.modelFor(question));
|
|
421
|
+
this.h.onCost(res.feeGrains);
|
|
422
|
+
return res.content || "(no answer)";
|
|
423
|
+
}
|
|
410
424
|
get messages() {
|
|
411
425
|
return [...this.history];
|
|
412
426
|
}
|
|
@@ -592,7 +606,7 @@ ${tail}`;
|
|
|
592
606
|
} else {
|
|
593
607
|
if (MUTATING_TOOLS.has(tool.name) && typeof args.path === "string")
|
|
594
608
|
snapshot(this.ctx.cwd, args.path);
|
|
595
|
-
const runCtx = { ...this.ctx, onStream: (c) => this.h.onToolStream?.(c) };
|
|
609
|
+
const runCtx = { ...this.ctx, onStream: (c) => this.h.onToolStream?.(c), onCost: (g) => this.h.onCost(g) };
|
|
596
610
|
try {
|
|
597
611
|
result = await tool.run(args, runCtx);
|
|
598
612
|
} catch (e) {
|
|
@@ -1585,8 +1599,17 @@ async function main() {
|
|
|
1585
1599
|
const rl = createInterface({ input: stdin, output: stdout });
|
|
1586
1600
|
await interactiveLogin(rl, cfg);
|
|
1587
1601
|
rl.close();
|
|
1602
|
+
const s = stdin;
|
|
1603
|
+
s.removeAllListeners("data");
|
|
1604
|
+
s.removeAllListeners("keypress");
|
|
1605
|
+
try {
|
|
1606
|
+
if (s.isTTY)
|
|
1607
|
+
s.setRawMode(false);
|
|
1608
|
+
} catch {}
|
|
1609
|
+
s.resume();
|
|
1610
|
+
await new Promise((r) => setImmediate(r));
|
|
1588
1611
|
}
|
|
1589
|
-
const { runTui } = await import("./tui-
|
|
1612
|
+
const { runTui } = await import("./tui-sekv1hga.mjs");
|
|
1590
1613
|
return runTui(cfg, resume);
|
|
1591
1614
|
}
|
|
1592
1615
|
if (cmd === "tui")
|
|
@@ -7966,7 +7966,19 @@ var isWin = process.platform === "win32";
|
|
|
7966
7966
|
function shellInvocation(cmd) {
|
|
7967
7967
|
if (!isWin)
|
|
7968
7968
|
return ["bash", "-lc", cmd];
|
|
7969
|
-
|
|
7969
|
+
if (hasBash())
|
|
7970
|
+
return ["bash", "-c", cmd];
|
|
7971
|
+
const ps = powershellBin();
|
|
7972
|
+
if (ps)
|
|
7973
|
+
return [ps, "-NoProfile", "-NonInteractive", "-Command", cmd];
|
|
7974
|
+
return ["cmd", "/c", cmd];
|
|
7975
|
+
}
|
|
7976
|
+
function shellName() {
|
|
7977
|
+
if (!isWin)
|
|
7978
|
+
return "bash";
|
|
7979
|
+
if (hasBash())
|
|
7980
|
+
return "bash";
|
|
7981
|
+
return powershellBin() ?? "cmd";
|
|
7970
7982
|
}
|
|
7971
7983
|
var _bash = null;
|
|
7972
7984
|
function hasBash() {
|
|
@@ -7979,6 +7991,19 @@ function hasBash() {
|
|
|
7979
7991
|
}
|
|
7980
7992
|
return _bash;
|
|
7981
7993
|
}
|
|
7994
|
+
var _ps;
|
|
7995
|
+
function powershellBin() {
|
|
7996
|
+
if (_ps !== undefined)
|
|
7997
|
+
return _ps;
|
|
7998
|
+
for (const bin of ["pwsh", "powershell"]) {
|
|
7999
|
+
try {
|
|
8000
|
+
if (spawnSync(bin, ["-NoProfile", "-Command", "exit 0"], { stdio: "ignore" }).status === 0) {
|
|
8001
|
+
return _ps = bin;
|
|
8002
|
+
}
|
|
8003
|
+
} catch {}
|
|
8004
|
+
}
|
|
8005
|
+
return _ps = null;
|
|
8006
|
+
}
|
|
7982
8007
|
function packageRoot(startDir) {
|
|
7983
8008
|
let dir = startDir;
|
|
7984
8009
|
for (let i = 0;i < 12; i++) {
|
|
@@ -21025,6 +21050,7 @@ async function chat2(cfg, messages, tools, onDelta, modelOverride, timeoutMs = 1
|
|
|
21025
21050
|
messages,
|
|
21026
21051
|
max_tokens: cfg.maxTokens,
|
|
21027
21052
|
stream: true,
|
|
21053
|
+
stream_options: { include_usage: true },
|
|
21028
21054
|
...tools.length ? { tools, tool_choice: "auto" } : {}
|
|
21029
21055
|
};
|
|
21030
21056
|
const attempt = async (live) => {
|
|
@@ -21032,7 +21058,13 @@ async function chat2(cfg, messages, tools, onDelta, modelOverride, timeoutMs = 1
|
|
|
21032
21058
|
let content = "";
|
|
21033
21059
|
let finishReason = null;
|
|
21034
21060
|
let feeGrains = 0;
|
|
21061
|
+
let promptTokens = 0, completionTokens = 0;
|
|
21035
21062
|
const calls = {};
|
|
21063
|
+
const readFee = (o) => {
|
|
21064
|
+
const x = o;
|
|
21065
|
+
const v = x?.x_modelos?.fee_grains ?? x?.fee_grains ?? x?.cost_grains;
|
|
21066
|
+
return v != null ? Number(v) || 0 : 0;
|
|
21067
|
+
};
|
|
21036
21068
|
for await (const chunk of stream) {
|
|
21037
21069
|
const choice = chunk.choices?.[0];
|
|
21038
21070
|
const delta = choice?.delta;
|
|
@@ -21053,22 +21085,33 @@ async function chat2(cfg, messages, tools, onDelta, modelOverride, timeoutMs = 1
|
|
|
21053
21085
|
}
|
|
21054
21086
|
if (choice?.finish_reason)
|
|
21055
21087
|
finishReason = choice.finish_reason;
|
|
21056
|
-
|
|
21057
|
-
|
|
21058
|
-
|
|
21088
|
+
feeGrains = readFee(chunk) || readFee(chunk.usage) || feeGrains;
|
|
21089
|
+
const usage = chunk.usage;
|
|
21090
|
+
if (usage) {
|
|
21091
|
+
promptTokens = usage.prompt_tokens ?? promptTokens;
|
|
21092
|
+
completionTokens = usage.completion_tokens ?? completionTokens;
|
|
21093
|
+
}
|
|
21059
21094
|
}
|
|
21060
|
-
return { content, toolCalls: Object.values(calls), finishReason, feeGrains };
|
|
21095
|
+
return { content, toolCalls: Object.values(calls), finishReason, feeGrains, promptTokens, completionTokens };
|
|
21061
21096
|
};
|
|
21062
|
-
|
|
21063
|
-
|
|
21064
|
-
} catch (e) {
|
|
21065
|
-
await new Promise((r) => setTimeout(r, 1500));
|
|
21097
|
+
let lastErr;
|
|
21098
|
+
for (let i = 0;i < 3; i++) {
|
|
21066
21099
|
try {
|
|
21067
21100
|
return await attempt(true);
|
|
21068
|
-
} catch {
|
|
21069
|
-
|
|
21101
|
+
} catch (e) {
|
|
21102
|
+
lastErr = e;
|
|
21103
|
+
const status = e.status;
|
|
21104
|
+
if (status && status >= 400 && status < 500)
|
|
21105
|
+
break;
|
|
21106
|
+
if (i < 2)
|
|
21107
|
+
await new Promise((r) => setTimeout(r, 1000 * (i + 1)));
|
|
21070
21108
|
}
|
|
21071
21109
|
}
|
|
21110
|
+
const err = lastErr;
|
|
21111
|
+
const reachable = err?.status !== undefined;
|
|
21112
|
+
if (!reachable)
|
|
21113
|
+
throw new Error(`inference API not reachable (${cfg.baseUrl}) — check your connection. ${err?.message ?? err?.code ?? ""}`.trim());
|
|
21114
|
+
throw new Error(`inference API error${err.status ? ` (HTTP ${err.status})` : ""}: ${err.message ?? "request rejected"}`);
|
|
21072
21115
|
}
|
|
21073
21116
|
|
|
21074
21117
|
// src/router/router.ts
|
|
@@ -21387,21 +21430,39 @@ async function runSubagent(cfg2, agent, task, ctx, onProgress, extraTools = [])
|
|
|
21387
21430
|
const granted = base ? [...base, ...extraTools] : extraTools.length ? [...allTools(), ...extraTools] : null;
|
|
21388
21431
|
const tools = granted ? granted.map((t) => ({ type: "function", function: { name: t.name, description: t.description, parameters: t.parameters } })) : toolSchemas();
|
|
21389
21432
|
const lookup = (name) => granted ? granted.find((t) => t.name === name) : getTool(name);
|
|
21390
|
-
const
|
|
21433
|
+
const env = `Working directory: ${ctx.cwd}
|
|
21434
|
+
Platform: ${process.platform}
|
|
21435
|
+
Today: ${new Date().toISOString().slice(0, 10)}`;
|
|
21436
|
+
const projSlice = loadProjectContext(ctx.cwd).slice(0, 4000);
|
|
21437
|
+
const turnCtx = (buildTurnContext(task, ctx.cwd, {}) || "").slice(0, 4000);
|
|
21438
|
+
const sys = [agent.systemPrompt, env, projSlice, turnCtx].filter(Boolean).join(`
|
|
21439
|
+
|
|
21440
|
+
`);
|
|
21391
21441
|
const history = [
|
|
21392
|
-
{ role: "system", content:
|
|
21393
|
-
...turnCtx ? [{ role: "system", content: turnCtx }] : [],
|
|
21442
|
+
{ role: "system", content: sys },
|
|
21394
21443
|
{ role: "user", content: task }
|
|
21395
21444
|
];
|
|
21396
21445
|
let feeGrains = 0;
|
|
21397
21446
|
const routed = cfg2.autoRoute ? route(task)?.model : undefined;
|
|
21398
21447
|
const subModel = cfg2.subagentModel || routed || agent.model || cfg2.model;
|
|
21448
|
+
onProgress?.(` ↳ ${agent.name} on ${subModel}`);
|
|
21449
|
+
const RESULT_CAP = Number(process.env.MODELCODE_MAX_TOOL_RESULT || "40000");
|
|
21450
|
+
const capResult = (s) => s.length <= RESULT_CAP ? s : `${s.slice(0, Math.floor(RESULT_CAP * 0.7))}
|
|
21451
|
+
|
|
21452
|
+
…[truncated ${s.length - RESULT_CAP} chars]…
|
|
21453
|
+
|
|
21454
|
+
${s.slice(-Math.floor(RESULT_CAP * 0.2))}`;
|
|
21399
21455
|
const finish = (text) => {
|
|
21400
21456
|
fireEvent("subagentStop", ctx.cwd, { AGENT: agent.name, RESULT: text.slice(0, 4000) }).catch(() => {});
|
|
21401
21457
|
return { text, feeGrains };
|
|
21402
21458
|
};
|
|
21403
21459
|
for (let step = 0;step < MAX_STEPS; step++) {
|
|
21404
|
-
|
|
21460
|
+
let res;
|
|
21461
|
+
try {
|
|
21462
|
+
res = await chat2(cfg2, history, tools, () => {}, subModel, 120000);
|
|
21463
|
+
} catch (e) {
|
|
21464
|
+
return finish(`error: ${agent.name} (${subModel}) — ${e.message}`);
|
|
21465
|
+
}
|
|
21405
21466
|
feeGrains += res.feeGrains;
|
|
21406
21467
|
history.push({ role: "assistant", content: res.content || null, ...res.toolCalls.length ? { tool_calls: res.toolCalls } : {} });
|
|
21407
21468
|
if (!res.toolCalls.length)
|
|
@@ -21423,7 +21484,7 @@ async function runSubagent(cfg2, agent, task, ctx, onProgress, extraTools = [])
|
|
|
21423
21484
|
result = `error: ${e.message}`;
|
|
21424
21485
|
}
|
|
21425
21486
|
}
|
|
21426
|
-
history.push({ role: "tool", tool_call_id: call.id, name: call.function.name, content: result });
|
|
21487
|
+
history.push({ role: "tool", tool_call_id: call.id, name: call.function.name, content: capResult(result) });
|
|
21427
21488
|
}
|
|
21428
21489
|
}
|
|
21429
21490
|
return finish("(subagent hit the step limit without finishing)");
|
|
@@ -24254,4 +24315,4 @@ async function decryptWallet(enc, password, network = MAINNET) {
|
|
|
24254
24315
|
}
|
|
24255
24316
|
return w;
|
|
24256
24317
|
}
|
|
24257
|
-
export { exports_external, register, getTool, toolSchemas, renderDiff, shellInvocation, globMatch, runProc, which, spawnProc, globalDir, loadConfig, saveConfig, rememberFact, allFacts, searchFacts, deleteFact, recordTurn, searchSessions, parseFrontmatter, loadSubagents, chat2 as chat, route, loadProjectContext, addEntity, addRelation, query, indexFile, indexCodebaseIncremental, indexCodebase, loadSkills, buildTurnContext, preToolUse, postToolUse, userPromptSubmit, fireEvent, runSubagent, runTeam, isImagePath, imageToDataUrl, estimateTokens, contextStatus, compactionThreshold, findCompactionCut, newTurn, snapshot, undo, depth, MUTATING_TOOLS, isProtectedBuiltin, recordUse, recordPatch, recordCreate, getUsage, allUsage, activityCount, analyzeImpact, impactSummary, lspFor, closeAllLsp, COLUMNS, addCard, moveCard, removeCard, renderBoard, addJob, listJobs, removeJob, startScheduler, MAINNET, generateMnemonic2 as generateMnemonic, validateMnemonic2 as validateMnemonic, walletFromMnemonic, importWalletHex, encryptWallet, decryptWallet, createTransfer };
|
|
24318
|
+
export { exports_external, register, getTool, toolSchemas, renderDiff, shellInvocation, shellName, globMatch, runProc, which, spawnProc, globalDir, loadConfig, saveConfig, rememberFact, allFacts, searchFacts, deleteFact, recordTurn, searchSessions, parseFrontmatter, loadSubagents, chat2 as chat, route, loadProjectContext, addEntity, addRelation, query, indexFile, indexCodebaseIncremental, indexCodebase, loadSkills, buildTurnContext, preToolUse, postToolUse, userPromptSubmit, fireEvent, runSubagent, runTeam, isImagePath, imageToDataUrl, estimateTokens, contextStatus, compactionThreshold, findCompactionCut, newTurn, snapshot, undo, depth, MUTATING_TOOLS, isProtectedBuiltin, recordUse, recordPatch, recordCreate, getUsage, allUsage, activityCount, analyzeImpact, impactSummary, lspFor, closeAllLsp, COLUMNS, addCard, moveCard, removeCard, renderBoard, addJob, listJobs, removeJob, startScheduler, MAINNET, generateMnemonic2 as generateMnemonic, validateMnemonic2 as validateMnemonic, walletFromMnemonic, importWalletHex, encryptWallet, decryptWallet, createTransfer };
|
|
@@ -60,6 +60,7 @@ import {
|
|
|
60
60
|
searchFacts,
|
|
61
61
|
searchSessions,
|
|
62
62
|
shellInvocation,
|
|
63
|
+
shellName,
|
|
63
64
|
snapshot,
|
|
64
65
|
spawnProc,
|
|
65
66
|
startScheduler,
|
|
@@ -67,7 +68,7 @@ import {
|
|
|
67
68
|
undo,
|
|
68
69
|
userPromptSubmit,
|
|
69
70
|
which
|
|
70
|
-
} from "./main-
|
|
71
|
+
} from "./main-wr686fnv.mjs";
|
|
71
72
|
import"./main-p2xnn95s.mjs";
|
|
72
73
|
import {
|
|
73
74
|
__commonJS,
|
|
@@ -21382,7 +21383,8 @@ var COMMAND_GROUPS = [
|
|
|
21382
21383
|
{ cmd: "/summary", desc: "recap the session (also /recap); auto-runs after heavy tasks — /summary disable to turn off" },
|
|
21383
21384
|
{ cmd: "/compact <summary>", desc: "collapse history to a summary (free context)" },
|
|
21384
21385
|
{ cmd: "/fork", desc: "save a snapshot of the current conversation" },
|
|
21385
|
-
{ cmd: "/btw <
|
|
21386
|
+
{ cmd: "/btw <question>", desc: "quick side question — answered without changing the current task" },
|
|
21387
|
+
{ cmd: "/steer <note>", desc: "steer the ongoing task (applied going forward)" },
|
|
21386
21388
|
{ cmd: "@<path>", desc: "mention a file — its contents are attached to your message" },
|
|
21387
21389
|
{ cmd: "/exit", desc: "quit" }
|
|
21388
21390
|
] },
|
|
@@ -21566,6 +21568,54 @@ function randomVerb() {
|
|
|
21566
21568
|
return SPINNER_VERBS[Math.floor(Math.random() * SPINNER_VERBS.length)];
|
|
21567
21569
|
}
|
|
21568
21570
|
|
|
21571
|
+
// src/ui/markdown.ts
|
|
21572
|
+
var B = "\x1B[1m";
|
|
21573
|
+
var _B = "\x1B[22m";
|
|
21574
|
+
var I = "\x1B[3m";
|
|
21575
|
+
var _I = "\x1B[23m";
|
|
21576
|
+
var U = "\x1B[4m";
|
|
21577
|
+
var _U = "\x1B[24m";
|
|
21578
|
+
var DIM = "\x1B[2m";
|
|
21579
|
+
var _DIM = "\x1B[22m";
|
|
21580
|
+
var CY = "\x1B[36m";
|
|
21581
|
+
var _CY = "\x1B[39m";
|
|
21582
|
+
function inline(s) {
|
|
21583
|
+
return s.replace(/`([^`]+)`/g, `${CY}$1${_CY}`).replace(/\*\*([^*]+)\*\*/g, `${B}$1${_B}`).replace(/__([^_]+)__/g, `${B}$1${_B}`).replace(/(^|[^*])\*([^*\n]+)\*/g, `$1${I}$2${_I}`).replace(/(^|[^_])_([^_\n]+)_/g, `$1${I}$2${_I}`);
|
|
21584
|
+
}
|
|
21585
|
+
function formatMarkdown(src) {
|
|
21586
|
+
const out = [];
|
|
21587
|
+
let inFence = false;
|
|
21588
|
+
for (const raw of src.split(`
|
|
21589
|
+
`)) {
|
|
21590
|
+
const line = raw.replace(/\s+$/, "");
|
|
21591
|
+
if (/^\s*```/.test(line)) {
|
|
21592
|
+
inFence = !inFence;
|
|
21593
|
+
continue;
|
|
21594
|
+
}
|
|
21595
|
+
if (inFence) {
|
|
21596
|
+
out.push(`${DIM} ${line}${_DIM}`);
|
|
21597
|
+
continue;
|
|
21598
|
+
}
|
|
21599
|
+
const h = line.match(/^(#{1,6})\s+(.*)$/);
|
|
21600
|
+
if (h) {
|
|
21601
|
+
out.push(h[1].length === 1 ? `${B}${U}${h[2]}${_U}${_B}` : `${B}${inline(h[2])}${_B}`);
|
|
21602
|
+
continue;
|
|
21603
|
+
}
|
|
21604
|
+
if (/^\s*([-*_])\1{2,}\s*$/.test(line)) {
|
|
21605
|
+
out.push(`${DIM}────────${_DIM}`);
|
|
21606
|
+
continue;
|
|
21607
|
+
}
|
|
21608
|
+
const b = line.match(/^(\s*)[-*+]\s+(.*)$/);
|
|
21609
|
+
if (b) {
|
|
21610
|
+
out.push(`${b[1]}${CY}•${_CY} ${inline(b[2])}`);
|
|
21611
|
+
continue;
|
|
21612
|
+
}
|
|
21613
|
+
out.push(inline(line));
|
|
21614
|
+
}
|
|
21615
|
+
return out.join(`
|
|
21616
|
+
`);
|
|
21617
|
+
}
|
|
21618
|
+
|
|
21569
21619
|
// src/ui/themes.ts
|
|
21570
21620
|
var THEMES = {
|
|
21571
21621
|
amber: { accent: "yellow", user: "green", tool: "cyan", dim: "gray", ok: "green", warn: "yellow" },
|
|
@@ -21703,8 +21753,6 @@ function App2({ theme, model, mdlUsd, lines, streaming, sessionMdl, contextPct,
|
|
|
21703
21753
|
onInterrupt();
|
|
21704
21754
|
return;
|
|
21705
21755
|
}
|
|
21706
|
-
if (busy)
|
|
21707
|
-
return;
|
|
21708
21756
|
if (key.upArrow) {
|
|
21709
21757
|
if (history.length) {
|
|
21710
21758
|
const i = histIdx < 0 ? history.length - 1 : Math.max(0, histIdx - 1);
|
|
@@ -21752,6 +21800,7 @@ function App2({ theme, model, mdlUsd, lines, streaming, sessionMdl, contextPct,
|
|
|
21752
21800
|
const renderLine = (l, i) => {
|
|
21753
21801
|
if (l.kind === "user")
|
|
21754
21802
|
return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
|
|
21803
|
+
flexDirection: "column",
|
|
21755
21804
|
marginTop: 1,
|
|
21756
21805
|
children: [
|
|
21757
21806
|
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Chip, {
|
|
@@ -21759,27 +21808,23 @@ function App2({ theme, model, mdlUsd, lines, streaming, sessionMdl, contextPct,
|
|
|
21759
21808
|
color: t.user
|
|
21760
21809
|
}, undefined, false, undefined, this),
|
|
21761
21810
|
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
21762
|
-
children:
|
|
21763
|
-
|
|
21764
|
-
l.text
|
|
21765
|
-
]
|
|
21766
|
-
}, undefined, true, undefined, this)
|
|
21811
|
+
children: l.text
|
|
21812
|
+
}, undefined, false, undefined, this)
|
|
21767
21813
|
]
|
|
21768
21814
|
}, i, true, undefined, this);
|
|
21769
21815
|
if (l.kind === "assistant")
|
|
21770
21816
|
return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
|
|
21817
|
+
flexDirection: "column",
|
|
21771
21818
|
marginTop: 1,
|
|
21772
21819
|
children: [
|
|
21773
|
-
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(
|
|
21774
|
-
|
|
21775
|
-
|
|
21820
|
+
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
21821
|
+
color: t.accent,
|
|
21822
|
+
bold: true,
|
|
21823
|
+
children: "◆ modelcode"
|
|
21776
21824
|
}, undefined, false, undefined, this),
|
|
21777
21825
|
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
21778
|
-
children:
|
|
21779
|
-
|
|
21780
|
-
l.text
|
|
21781
|
-
]
|
|
21782
|
-
}, undefined, true, undefined, this)
|
|
21826
|
+
children: formatMarkdown(l.text)
|
|
21827
|
+
}, undefined, false, undefined, this)
|
|
21783
21828
|
]
|
|
21784
21829
|
}, i, true, undefined, this);
|
|
21785
21830
|
if (l.kind === "tool")
|
|
@@ -21792,6 +21837,7 @@ function App2({ theme, model, mdlUsd, lines, streaming, sessionMdl, contextPct,
|
|
|
21792
21837
|
}, i, true, undefined, this);
|
|
21793
21838
|
if (l.kind === "error")
|
|
21794
21839
|
return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
|
|
21840
|
+
flexDirection: "column",
|
|
21795
21841
|
marginTop: 1,
|
|
21796
21842
|
children: [
|
|
21797
21843
|
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Chip, {
|
|
@@ -21800,11 +21846,8 @@ function App2({ theme, model, mdlUsd, lines, streaming, sessionMdl, contextPct,
|
|
|
21800
21846
|
}, undefined, false, undefined, this),
|
|
21801
21847
|
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
21802
21848
|
color: t.warn,
|
|
21803
|
-
children:
|
|
21804
|
-
|
|
21805
|
-
l.text
|
|
21806
|
-
]
|
|
21807
|
-
}, undefined, true, undefined, this)
|
|
21849
|
+
children: l.text
|
|
21850
|
+
}, undefined, false, undefined, this)
|
|
21808
21851
|
]
|
|
21809
21852
|
}, i, true, undefined, this);
|
|
21810
21853
|
return /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
@@ -21846,18 +21889,17 @@ function App2({ theme, model, mdlUsd, lines, streaming, sessionMdl, contextPct,
|
|
|
21846
21889
|
flexDirection: "column",
|
|
21847
21890
|
children: [
|
|
21848
21891
|
streaming ? /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
|
|
21892
|
+
flexDirection: "column",
|
|
21849
21893
|
marginTop: 1,
|
|
21850
21894
|
children: [
|
|
21851
|
-
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(
|
|
21852
|
-
|
|
21853
|
-
|
|
21895
|
+
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
21896
|
+
color: t.accent,
|
|
21897
|
+
bold: true,
|
|
21898
|
+
children: "◆ modelcode"
|
|
21854
21899
|
}, undefined, false, undefined, this),
|
|
21855
21900
|
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
21856
|
-
children:
|
|
21857
|
-
|
|
21858
|
-
streaming
|
|
21859
|
-
]
|
|
21860
|
-
}, undefined, true, undefined, this)
|
|
21901
|
+
children: formatMarkdown(streaming)
|
|
21902
|
+
}, undefined, false, undefined, this)
|
|
21861
21903
|
]
|
|
21862
21904
|
}, undefined, true, undefined, this) : null,
|
|
21863
21905
|
toolStream ? /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
@@ -21931,26 +21973,27 @@ function App2({ theme, model, mdlUsd, lines, streaming, sessionMdl, contextPct,
|
|
|
21931
21973
|
]
|
|
21932
21974
|
}, undefined, true, undefined, this) : /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
|
|
21933
21975
|
borderStyle: "round",
|
|
21934
|
-
borderColor:
|
|
21976
|
+
borderColor: t.user,
|
|
21935
21977
|
paddingX: 1,
|
|
21936
21978
|
marginTop: 1,
|
|
21937
21979
|
children: [
|
|
21938
21980
|
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
21939
|
-
color:
|
|
21940
|
-
children:
|
|
21941
|
-
|
|
21942
|
-
" "
|
|
21943
|
-
]
|
|
21944
|
-
}, undefined, true, undefined, this),
|
|
21981
|
+
color: t.user,
|
|
21982
|
+
children: "› "
|
|
21983
|
+
}, undefined, false, undefined, this),
|
|
21945
21984
|
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
21946
|
-
children: input
|
|
21985
|
+
children: input
|
|
21947
21986
|
}, undefined, false, undefined, this),
|
|
21948
|
-
|
|
21987
|
+
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
21949
21988
|
color: t.accent,
|
|
21950
21989
|
children: "▋"
|
|
21951
|
-
}, undefined, false, undefined, this)
|
|
21990
|
+
}, undefined, false, undefined, this)
|
|
21952
21991
|
]
|
|
21953
21992
|
}, undefined, true, undefined, this),
|
|
21993
|
+
busy && input ? /* @__PURE__ */ jsx_dev_runtime.jsxDEV(Text, {
|
|
21994
|
+
color: t.dim,
|
|
21995
|
+
children: " ↵ to queue this for after the current turn"
|
|
21996
|
+
}, undefined, false, undefined, this) : null,
|
|
21954
21997
|
/* @__PURE__ */ jsx_dev_runtime.jsxDEV(Box_default, {
|
|
21955
21998
|
justifyContent: "space-between",
|
|
21956
21999
|
paddingX: 1,
|
|
@@ -22051,6 +22094,16 @@ class Agent {
|
|
|
22051
22094
|
note(text) {
|
|
22052
22095
|
this.history.push({ role: "system", content: `User steering note (apply going forward): ${text}` });
|
|
22053
22096
|
}
|
|
22097
|
+
async sideQuestion(question, onDelta) {
|
|
22098
|
+
const forked = [
|
|
22099
|
+
...this.history,
|
|
22100
|
+
{ role: "system", content: "The user has a quick side question. Answer it concisely using the conversation so far. This does NOT change the current task." },
|
|
22101
|
+
{ role: "user", content: question }
|
|
22102
|
+
];
|
|
22103
|
+
const res = await chat(this.cfg, forked, [], onDelta ?? (() => {}), this.modelFor(question));
|
|
22104
|
+
this.h.onCost(res.feeGrains);
|
|
22105
|
+
return res.content || "(no answer)";
|
|
22106
|
+
}
|
|
22054
22107
|
get messages() {
|
|
22055
22108
|
return [...this.history];
|
|
22056
22109
|
}
|
|
@@ -22236,7 +22289,7 @@ ${tail2}`;
|
|
|
22236
22289
|
} else {
|
|
22237
22290
|
if (MUTATING_TOOLS.has(tool.name) && typeof args.path === "string")
|
|
22238
22291
|
snapshot(this.ctx.cwd, args.path);
|
|
22239
|
-
const runCtx = { ...this.ctx, onStream: (c2) => this.h.onToolStream?.(c2) };
|
|
22292
|
+
const runCtx = { ...this.ctx, onStream: (c2) => this.h.onToolStream?.(c2), onCost: (g) => this.h.onCost(g) };
|
|
22240
22293
|
try {
|
|
22241
22294
|
result2 = await tool.run(args, runCtx);
|
|
22242
22295
|
} catch (e) {
|
|
@@ -22888,7 +22941,9 @@ ${typeof m.content === "string" ? m.content : JSON.stringify(m.content)}`).join(
|
|
|
22888
22941
|
`) : "no saved sessions" };
|
|
22889
22942
|
}
|
|
22890
22943
|
case "/btw":
|
|
22891
|
-
return arg ? {
|
|
22944
|
+
return arg ? { sideQuestion: arg } : { output: "usage: /btw <quick question> — answered without changing the current task" };
|
|
22945
|
+
case "/steer":
|
|
22946
|
+
return arg ? { note: arg, output: "noted — will apply going forward" } : { output: "usage: /steer <note> — steer the ongoing task" };
|
|
22892
22947
|
case "/web":
|
|
22893
22948
|
case "/fetch":
|
|
22894
22949
|
case "/browse":
|
|
@@ -22947,7 +23002,7 @@ function inside(cwd2, p) {
|
|
|
22947
23002
|
}
|
|
22948
23003
|
var bash = {
|
|
22949
23004
|
name: "bash",
|
|
22950
|
-
description:
|
|
23005
|
+
description: `Run a shell command in the working directory (shell: ${shellName()}); returns combined stdout+stderr. Use for builds, tests, git, file ops.${shellName() === "powershell" || shellName() === "pwsh" ? " NOTE: this is Windows PowerShell — use PowerShell syntax (Get-ChildItem/ls, Get-Content/cat, 2>$null, Select-Object -First N)." : shellName() === "cmd" ? " NOTE: this is Windows cmd.exe — use cmd syntax." : ""}`,
|
|
22951
23006
|
permission: "ask",
|
|
22952
23007
|
parameters: {
|
|
22953
23008
|
type: "object",
|
|
@@ -23137,7 +23192,9 @@ function registerAgentTool(cfg, onProgress) {
|
|
|
23137
23192
|
if (!agent)
|
|
23138
23193
|
return `error: unknown subagent '${args.subagent_type}'. available: ${names.join(", ")}`;
|
|
23139
23194
|
const { text, feeGrains } = await runSubagent(cfg, agent, String(args.prompt ?? ""), ctx, onProgress);
|
|
23140
|
-
|
|
23195
|
+
ctx.onCost?.(feeGrains);
|
|
23196
|
+
onProgress?.(` ↳ ${agent.name} done · ${(feeGrains / 1e8).toFixed(4)} MDL`);
|
|
23197
|
+
return `[${agent.name} · ${(feeGrains / 1e8).toFixed(6)} MDL]
|
|
23141
23198
|
${text}`;
|
|
23142
23199
|
}
|
|
23143
23200
|
};
|
|
@@ -23158,7 +23215,8 @@ ${text}`;
|
|
|
23158
23215
|
async run(args, ctx) {
|
|
23159
23216
|
const members = Array.isArray(args.members) ? args.members.map(String) : [];
|
|
23160
23217
|
const { transcript, feeGrains } = await runTeam(cfg, members, String(args.prompt ?? ""), ctx, Number(args.rounds) || 2, onProgress);
|
|
23161
|
-
|
|
23218
|
+
ctx.onCost?.(feeGrains);
|
|
23219
|
+
return `[team · ${(feeGrains / 1e8).toFixed(6)} MDL]
|
|
23162
23220
|
${transcript}`;
|
|
23163
23221
|
}
|
|
23164
23222
|
};
|
|
@@ -23780,6 +23838,8 @@ function Root({ cfg, resume, mcpCount }) {
|
|
|
23780
23838
|
const mdlUsd = import_react35.useRef(null);
|
|
23781
23839
|
const streamBuf = import_react35.useRef("");
|
|
23782
23840
|
const tokensRef = import_react35.useRef(0);
|
|
23841
|
+
const busyRef = import_react35.useRef(false);
|
|
23842
|
+
const queueRef = import_react35.useRef([]);
|
|
23783
23843
|
const confirmResolve = import_react35.useRef(null);
|
|
23784
23844
|
const sessionIdRef = import_react35.useRef(newSessionId());
|
|
23785
23845
|
const sessionMdlRef = import_react35.useRef(0);
|
|
@@ -23877,6 +23937,7 @@ function Root({ cfg, resume, mcpCount }) {
|
|
|
23877
23937
|
tokensRef.current = 0;
|
|
23878
23938
|
setTurnTokens(0);
|
|
23879
23939
|
setTurnStart(Date.now());
|
|
23940
|
+
busyRef.current = true;
|
|
23880
23941
|
setBusy(true);
|
|
23881
23942
|
try {
|
|
23882
23943
|
await agent.send(expandFileMentions(prompt, cwd2), imageMentions(prompt, cwd2));
|
|
@@ -23897,18 +23958,20 @@ function Root({ cfg, resume, mcpCount }) {
|
|
|
23897
23958
|
setStreaming("");
|
|
23898
23959
|
setToolStream("");
|
|
23899
23960
|
streamBuf.current = "";
|
|
23961
|
+
busyRef.current = false;
|
|
23900
23962
|
setBusy(false);
|
|
23901
23963
|
setContextPct(agent.contextStatus().pct);
|
|
23902
23964
|
setMode(agent.mode);
|
|
23903
23965
|
refreshWallet();
|
|
23966
|
+
const next = queueRef.current.shift();
|
|
23967
|
+
if (next !== undefined)
|
|
23968
|
+
runInput(next);
|
|
23904
23969
|
}
|
|
23905
23970
|
}, [agent, add2, refreshWallet, cfg, cwd2, flushAssistant]);
|
|
23906
23971
|
const onInterrupt = import_react35.useCallback(() => {
|
|
23907
23972
|
agent.abort();
|
|
23908
23973
|
}, [agent]);
|
|
23909
|
-
const
|
|
23910
|
-
add2({ kind: "user", text: input });
|
|
23911
|
-
setHistory((h) => (h[h.length - 1] === input ? h : [...h, input]).slice(-100));
|
|
23974
|
+
const runInput = import_react35.useCallback(async (input) => {
|
|
23912
23975
|
if (input.startsWith("/")) {
|
|
23913
23976
|
const r = await handleSlash(input, { agent, cfg, cwd: cwd2, sessionMdl: sessionMdlRef.current, mcpCount: mcpCountRef.current });
|
|
23914
23977
|
if (r) {
|
|
@@ -23933,6 +23996,28 @@ function Root({ cfg, resume, mcpCount }) {
|
|
|
23933
23996
|
setMode(agent.mode);
|
|
23934
23997
|
if (r.output)
|
|
23935
23998
|
add2({ kind: "system", text: r.output });
|
|
23999
|
+
if (r.sideQuestion) {
|
|
24000
|
+
busyRef.current = true;
|
|
24001
|
+
setBusy(true);
|
|
24002
|
+
setTurnStart(Date.now());
|
|
24003
|
+
streamBuf.current = "";
|
|
24004
|
+
setStreaming("");
|
|
24005
|
+
try {
|
|
24006
|
+
const ans = await agent.sideQuestion(r.sideQuestion, (t) => {
|
|
24007
|
+
streamBuf.current += t;
|
|
24008
|
+
setStreaming(streamBuf.current);
|
|
24009
|
+
});
|
|
24010
|
+
add2({ kind: "system", text: `btw › ${ans}` });
|
|
24011
|
+
} catch (e) {
|
|
24012
|
+
add2({ kind: "error", text: e.message });
|
|
24013
|
+
} finally {
|
|
24014
|
+
streamBuf.current = "";
|
|
24015
|
+
setStreaming("");
|
|
24016
|
+
busyRef.current = false;
|
|
24017
|
+
setBusy(false);
|
|
24018
|
+
refreshWallet();
|
|
24019
|
+
}
|
|
24020
|
+
}
|
|
23936
24021
|
if (r.agentPrompt)
|
|
23937
24022
|
await runTurn(r.agentPrompt);
|
|
23938
24023
|
return;
|
|
@@ -23940,6 +24025,17 @@ function Root({ cfg, resume, mcpCount }) {
|
|
|
23940
24025
|
}
|
|
23941
24026
|
await runTurn(input);
|
|
23942
24027
|
}, [agent, add2, cfg, cwd2, onExit, runTurn]);
|
|
24028
|
+
const onSubmit = import_react35.useCallback((input) => {
|
|
24029
|
+
setHistory((h) => (h[h.length - 1] === input ? h : [...h, input]).slice(-100));
|
|
24030
|
+
if (busyRef.current) {
|
|
24031
|
+
queueRef.current.push(input);
|
|
24032
|
+
add2({ kind: "user", text: input });
|
|
24033
|
+
add2({ kind: "system", text: "↳ queued (runs after the current turn)" });
|
|
24034
|
+
return;
|
|
24035
|
+
}
|
|
24036
|
+
add2({ kind: "user", text: input });
|
|
24037
|
+
runInput(input);
|
|
24038
|
+
}, [add2, runInput]);
|
|
23943
24039
|
return /* @__PURE__ */ jsx_dev_runtime2.jsxDEV(App2, {
|
|
23944
24040
|
theme: cfg.theme,
|
|
23945
24041
|
model: cfg.model,
|
|
@@ -23962,12 +24058,25 @@ function Root({ cfg, resume, mcpCount }) {
|
|
|
23962
24058
|
onExit
|
|
23963
24059
|
}, undefined, false, undefined, this);
|
|
23964
24060
|
}
|
|
23965
|
-
|
|
23966
|
-
if (
|
|
23967
|
-
|
|
23968
|
-
|
|
23969
|
-
|
|
24061
|
+
function getRenderStdin() {
|
|
24062
|
+
if (process.stdin.isTTY)
|
|
24063
|
+
return;
|
|
24064
|
+
if (process.env.CI)
|
|
24065
|
+
return;
|
|
24066
|
+
if (process.platform === "win32")
|
|
24067
|
+
return;
|
|
24068
|
+
try {
|
|
24069
|
+
const { openSync } = __require("fs");
|
|
24070
|
+
const { ReadStream } = __require("tty");
|
|
24071
|
+
const s = new ReadStream(openSync("/dev/tty", "r"));
|
|
24072
|
+
s.isTTY = true;
|
|
24073
|
+
return s;
|
|
24074
|
+
} catch {
|
|
24075
|
+
return;
|
|
23970
24076
|
}
|
|
24077
|
+
}
|
|
24078
|
+
async function runTui(cfg, resume = "none") {
|
|
24079
|
+
const renderStdin = getRenderStdin();
|
|
23971
24080
|
registerCoreTools();
|
|
23972
24081
|
registerMemoryTools();
|
|
23973
24082
|
registerAgentTool(cfg, (line) => emitProgress(line));
|
|
@@ -23975,7 +24084,12 @@ async function runTui(cfg, resume = "none") {
|
|
|
23975
24084
|
registerMoreTools();
|
|
23976
24085
|
registerBrowserTool();
|
|
23977
24086
|
registerTaskTools();
|
|
23978
|
-
|
|
24087
|
+
let mcpCount = 0;
|
|
24088
|
+
registerMcpTools(process.cwd()).then((n) => {
|
|
24089
|
+
mcpCount = n;
|
|
24090
|
+
if (n)
|
|
24091
|
+
emitProgress(`✓ ${n} MCP tool(s) connected`);
|
|
24092
|
+
}).catch(() => {});
|
|
23979
24093
|
startScheduler(async (prompt, jobCwd) => {
|
|
23980
24094
|
emitProgress(`⏰ running scheduled job…`);
|
|
23981
24095
|
const a = new Agent(cfg, { cwd: jobCwd }, { onAssistantDelta: () => {}, onToolStart: () => {}, onToolResult: () => {}, onCost: () => {}, confirm: async () => true });
|
|
@@ -23984,11 +24098,26 @@ async function runTui(cfg, resume = "none") {
|
|
|
23984
24098
|
});
|
|
23985
24099
|
pullTeamMemory().catch(() => {});
|
|
23986
24100
|
indexCodebaseIncremental(process.cwd()).catch(() => {});
|
|
24101
|
+
const restore = () => {
|
|
24102
|
+
try {
|
|
24103
|
+
if (process.stdin.isTTY)
|
|
24104
|
+
process.stdin.setRawMode(false);
|
|
24105
|
+
} catch {}
|
|
24106
|
+
};
|
|
24107
|
+
process.on("exit", restore);
|
|
24108
|
+
process.on("SIGINT", () => {
|
|
24109
|
+
restore();
|
|
24110
|
+
process.exit(0);
|
|
24111
|
+
});
|
|
24112
|
+
process.on("SIGTERM", () => {
|
|
24113
|
+
restore();
|
|
24114
|
+
process.exit(0);
|
|
24115
|
+
});
|
|
23987
24116
|
render_default(/* @__PURE__ */ jsx_dev_runtime2.jsxDEV(Root, {
|
|
23988
24117
|
cfg,
|
|
23989
24118
|
resume,
|
|
23990
24119
|
mcpCount
|
|
23991
|
-
}, undefined, false, undefined, this));
|
|
24120
|
+
}, undefined, false, undefined, this), { exitOnCtrlC: false, ...renderStdin ? { stdin: renderStdin } : {} });
|
|
23992
24121
|
}
|
|
23993
24122
|
export {
|
|
23994
24123
|
runTui
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@modeloslab/modelcode",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.4",
|
|
4
4
|
"description": "modelOS-native AI coding agent CLI — remembers like Hermes, codes like Claude Code, runs on modelOS (pay-per-use in MDL, no rate limits). Knowledge-graph memory, subagents, MCP, vision, spend caps.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|