micro-models-agent 0.27.0 → 0.28.0
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/main.js +136 -30
- package/package.json +1 -1
package/dist/main.js
CHANGED
|
@@ -2229,7 +2229,9 @@ var init_defaults = __esm(() => {
|
|
|
2229
2229
|
navigationTimeout: 15000
|
|
2230
2230
|
},
|
|
2231
2231
|
ui: {
|
|
2232
|
-
spinner: true
|
|
2232
|
+
spinner: true,
|
|
2233
|
+
toolStyle: "inline",
|
|
2234
|
+
toolComments: true
|
|
2233
2235
|
},
|
|
2234
2236
|
mcpServers: {
|
|
2235
2237
|
context7: {
|
|
@@ -4514,12 +4516,12 @@ class OpenAICompatProvider {
|
|
|
4514
4516
|
};
|
|
4515
4517
|
this.rateLimiter = createRateLimiter(config.rateLimits);
|
|
4516
4518
|
}
|
|
4517
|
-
async* chat(messages, tools) {
|
|
4519
|
+
async* chat(messages, tools, signal) {
|
|
4518
4520
|
if (!this.rateLimiter.canMakeRequest()) {
|
|
4519
4521
|
throw new Error(`Rate limit exceeded: ${this.rateLimiter.getConfig().maxRequestsPerMinute} requests per minute`);
|
|
4520
4522
|
}
|
|
4521
4523
|
this.rateLimiter.recordRequest();
|
|
4522
|
-
const streamResult = this.doStream(messages, tools);
|
|
4524
|
+
const streamResult = this.doStream(messages, tools, signal);
|
|
4523
4525
|
let hasToolCall = false;
|
|
4524
4526
|
let hasText = false;
|
|
4525
4527
|
let reasoningAcc = "";
|
|
@@ -4534,13 +4536,13 @@ class OpenAICompatProvider {
|
|
|
4534
4536
|
yield chunk;
|
|
4535
4537
|
}
|
|
4536
4538
|
if (!hasToolCall && !hasText) {
|
|
4537
|
-
const fallback = await this.doNonStreaming(messages, tools);
|
|
4539
|
+
const fallback = await this.doNonStreaming(messages, tools, signal);
|
|
4538
4540
|
for (const chunk of fallback) {
|
|
4539
4541
|
yield chunk;
|
|
4540
4542
|
}
|
|
4541
4543
|
}
|
|
4542
4544
|
}
|
|
4543
|
-
async* doStream(messages, tools) {
|
|
4545
|
+
async* doStream(messages, tools, signal) {
|
|
4544
4546
|
const body = {
|
|
4545
4547
|
model: this.model,
|
|
4546
4548
|
messages,
|
|
@@ -4567,11 +4569,12 @@ class OpenAICompatProvider {
|
|
|
4567
4569
|
const controller = new AbortController;
|
|
4568
4570
|
const totalTimeoutMs = 120000;
|
|
4569
4571
|
const timeoutId = setTimeout(() => controller.abort(), totalTimeoutMs);
|
|
4572
|
+
const abortSignal = signal ? AbortSignal.any([controller.signal, signal]) : controller.signal;
|
|
4570
4573
|
const response = await this.fetchWithRetry(`${this.config.baseUrl}/chat/completions`, {
|
|
4571
4574
|
method: "POST",
|
|
4572
4575
|
headers,
|
|
4573
4576
|
body: JSON.stringify(body),
|
|
4574
|
-
signal:
|
|
4577
|
+
signal: abortSignal
|
|
4575
4578
|
});
|
|
4576
4579
|
if (!response.ok) {
|
|
4577
4580
|
clearTimeout(timeoutId);
|
|
@@ -4670,7 +4673,7 @@ class OpenAICompatProvider {
|
|
|
4670
4673
|
reader.releaseLock();
|
|
4671
4674
|
}
|
|
4672
4675
|
}
|
|
4673
|
-
async doNonStreaming(messages, tools) {
|
|
4676
|
+
async doNonStreaming(messages, tools, signal) {
|
|
4674
4677
|
const body = {
|
|
4675
4678
|
model: this.model,
|
|
4676
4679
|
messages,
|
|
@@ -4698,7 +4701,8 @@ class OpenAICompatProvider {
|
|
|
4698
4701
|
const response = await this.fetchWithRetry(`${this.config.baseUrl}/chat/completions`, {
|
|
4699
4702
|
method: "POST",
|
|
4700
4703
|
headers,
|
|
4701
|
-
body: JSON.stringify(body)
|
|
4704
|
+
body: JSON.stringify(body),
|
|
4705
|
+
signal
|
|
4702
4706
|
});
|
|
4703
4707
|
if (!response.ok) {
|
|
4704
4708
|
const errorText = await response.text();
|
|
@@ -4792,7 +4796,7 @@ class OpenAICompatProvider {
|
|
|
4792
4796
|
if (attempt < maxRetries) {
|
|
4793
4797
|
const delay = Math.min(baseDelay * Math.pow(2, attempt), maxDelay);
|
|
4794
4798
|
const jitter = Math.random() * baseDelay * 0.1;
|
|
4795
|
-
await this.sleep(delay + jitter);
|
|
4799
|
+
await this.sleep(delay + jitter, init.signal ?? undefined);
|
|
4796
4800
|
}
|
|
4797
4801
|
}
|
|
4798
4802
|
throw lastError ?? new Error(t("error.llm_retries"));
|
|
@@ -4800,8 +4804,23 @@ class OpenAICompatProvider {
|
|
|
4800
4804
|
isRetryable(status) {
|
|
4801
4805
|
return status === 429 || status >= 500;
|
|
4802
4806
|
}
|
|
4803
|
-
sleep(ms) {
|
|
4804
|
-
return new Promise((resolve) =>
|
|
4807
|
+
sleep(ms, signal) {
|
|
4808
|
+
return new Promise((resolve, reject) => {
|
|
4809
|
+
if (signal?.aborted) {
|
|
4810
|
+
reject(new DOMException("Aborted", "AbortError"));
|
|
4811
|
+
return;
|
|
4812
|
+
}
|
|
4813
|
+
let timer;
|
|
4814
|
+
const onAbort = () => {
|
|
4815
|
+
clearTimeout(timer);
|
|
4816
|
+
reject(new DOMException("Aborted", "AbortError"));
|
|
4817
|
+
};
|
|
4818
|
+
timer = setTimeout(() => {
|
|
4819
|
+
signal?.removeEventListener("abort", onAbort);
|
|
4820
|
+
resolve();
|
|
4821
|
+
}, ms);
|
|
4822
|
+
signal?.addEventListener("abort", onAbort, { once: true });
|
|
4823
|
+
});
|
|
4805
4824
|
}
|
|
4806
4825
|
}
|
|
4807
4826
|
var init_openai_compat = __esm(() => {
|
|
@@ -5959,9 +5978,9 @@ function formatLine(line, maxNumWidth) {
|
|
|
5959
5978
|
const num = line.type === "remove" ? line.oldNum : line.newNum;
|
|
5960
5979
|
const numStr = num !== null ? String(num).padStart(maxNumWidth) : " ".repeat(maxNumWidth);
|
|
5961
5980
|
if (line.type === "remove") {
|
|
5962
|
-
return
|
|
5981
|
+
return `${numStr} ${pc.red("-")} ${line.content}`;
|
|
5963
5982
|
} else if (line.type === "add") {
|
|
5964
|
-
return
|
|
5983
|
+
return `${numStr} ${pc.green("+")} ${line.content}`;
|
|
5965
5984
|
} else if (line.content === "...") {
|
|
5966
5985
|
return pc.dim(` ${" ".repeat(maxNumWidth)}...`);
|
|
5967
5986
|
} else {
|
|
@@ -6000,7 +6019,7 @@ function generateNewFileDiff(content) {
|
|
|
6000
6019
|
const diffLines = [];
|
|
6001
6020
|
for (let i = 0;i < lines.length; i++) {
|
|
6002
6021
|
const numStr = String(i + 1).padStart(maxNumWidth);
|
|
6003
|
-
diffLines.push(
|
|
6022
|
+
diffLines.push(`${numStr} ${pc.green("+")} ${lines[i]}`);
|
|
6004
6023
|
}
|
|
6005
6024
|
if (diffLines.length > MAX_DIFF_LINES) {
|
|
6006
6025
|
const truncated = diffLines.slice(0, MAX_DIFF_LINES);
|
|
@@ -6018,7 +6037,7 @@ function generateDeleteDiff(content) {
|
|
|
6018
6037
|
const diffLines = [];
|
|
6019
6038
|
for (let i = 0;i < lines.length; i++) {
|
|
6020
6039
|
const numStr = String(i + 1).padStart(maxNumWidth);
|
|
6021
|
-
diffLines.push(
|
|
6040
|
+
diffLines.push(`${numStr} ${pc.red("-")} ${lines[i]}`);
|
|
6022
6041
|
}
|
|
6023
6042
|
if (diffLines.length > MAX_DIFF_LINES) {
|
|
6024
6043
|
const truncated = diffLines.slice(0, MAX_DIFF_LINES);
|
|
@@ -9547,6 +9566,18 @@ var init_store = __esm(() => {
|
|
|
9547
9566
|
|
|
9548
9567
|
// src/core/agent.ts
|
|
9549
9568
|
import { join as join10 } from "path";
|
|
9569
|
+
function isToolCallJson(text) {
|
|
9570
|
+
const trimmed = text.trim();
|
|
9571
|
+
if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
|
|
9572
|
+
try {
|
|
9573
|
+
JSON.parse(trimmed);
|
|
9574
|
+
return true;
|
|
9575
|
+
} catch {
|
|
9576
|
+
return false;
|
|
9577
|
+
}
|
|
9578
|
+
}
|
|
9579
|
+
return false;
|
|
9580
|
+
}
|
|
9550
9581
|
|
|
9551
9582
|
class Agent {
|
|
9552
9583
|
deps;
|
|
@@ -9734,7 +9765,7 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
9734
9765
|
const textChunks = [];
|
|
9735
9766
|
this.emitPhase(iteration, "thinking", onPhase);
|
|
9736
9767
|
try {
|
|
9737
|
-
for await (const chunk of llmProvider.chat(history, allTools)) {
|
|
9768
|
+
for await (const chunk of llmProvider.chat(history, allTools, this.abortController?.signal)) {
|
|
9738
9769
|
if (this.shutdownRequested)
|
|
9739
9770
|
break;
|
|
9740
9771
|
if (chunk.type === "text" && chunk.content) {
|
|
@@ -9776,6 +9807,10 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
9776
9807
|
}
|
|
9777
9808
|
}
|
|
9778
9809
|
} catch (err) {
|
|
9810
|
+
if (this.shutdownRequested || err?.name === "AbortError") {
|
|
9811
|
+
logger.info("LLM call aborted (interrupt)");
|
|
9812
|
+
break;
|
|
9813
|
+
}
|
|
9779
9814
|
logger.error(`LLM call failed: ${err.message}`);
|
|
9780
9815
|
slog.logError(err.message);
|
|
9781
9816
|
pluginManager.runOnError({ iteration, logger }, err);
|
|
@@ -9788,7 +9823,12 @@ ${t("tool.truncated", { tokens: Math.ceil(removedChars / 2) })}`;
|
|
|
9788
9823
|
} finally {
|
|
9789
9824
|
this.emitPhase(iteration, "done", onPhase);
|
|
9790
9825
|
}
|
|
9791
|
-
if (
|
|
9826
|
+
if (this.shutdownRequested) {
|
|
9827
|
+
break;
|
|
9828
|
+
}
|
|
9829
|
+
const toolComments = this.deps.config.ui?.toolComments ?? true;
|
|
9830
|
+
const showText = textChunks.length > 0 && (!sawToolCall || toolComments && !isToolCallJson(textContent));
|
|
9831
|
+
if (showText) {
|
|
9792
9832
|
for (const chunk of textChunks) {
|
|
9793
9833
|
const textOut = pluginManager.runOnText({ iteration, logger }, chunk);
|
|
9794
9834
|
onChunk?.(textOut);
|
|
@@ -16821,6 +16861,10 @@ function box(lines, opts = {}) {
|
|
|
16821
16861
|
out.push(pc.dim(`└${"─".repeat(width - 2)}┘`));
|
|
16822
16862
|
return out;
|
|
16823
16863
|
}
|
|
16864
|
+
function divider(width) {
|
|
16865
|
+
const w = Math.min(width ?? getTerminalWidth(), 60);
|
|
16866
|
+
return pc.dim("─".repeat(w));
|
|
16867
|
+
}
|
|
16824
16868
|
var init_box = __esm(() => {
|
|
16825
16869
|
init_string_width();
|
|
16826
16870
|
init_colors();
|
|
@@ -26563,6 +26607,28 @@ init_spinner();
|
|
|
26563
26607
|
init_box();
|
|
26564
26608
|
init_table();
|
|
26565
26609
|
init_i18n();
|
|
26610
|
+
var GUTTER = " ";
|
|
26611
|
+
function toolMarker(tool) {
|
|
26612
|
+
switch (tool) {
|
|
26613
|
+
case "write_file":
|
|
26614
|
+
case "edit_file":
|
|
26615
|
+
case "create_dir":
|
|
26616
|
+
case "move_file":
|
|
26617
|
+
case "delete_file":
|
|
26618
|
+
return "←";
|
|
26619
|
+
case "read_file":
|
|
26620
|
+
case "list_dir":
|
|
26621
|
+
case "file_info":
|
|
26622
|
+
return "→";
|
|
26623
|
+
case "glob":
|
|
26624
|
+
case "grep":
|
|
26625
|
+
return "✱";
|
|
26626
|
+
case "bash":
|
|
26627
|
+
return "$";
|
|
26628
|
+
default:
|
|
26629
|
+
return "⚙";
|
|
26630
|
+
}
|
|
26631
|
+
}
|
|
26566
26632
|
function isRichTerminal() {
|
|
26567
26633
|
return Boolean(process.stdout.isTTY) && !process.env.CI;
|
|
26568
26634
|
}
|
|
@@ -26592,12 +26658,14 @@ class Renderer {
|
|
|
26592
26658
|
out;
|
|
26593
26659
|
err;
|
|
26594
26660
|
width;
|
|
26661
|
+
toolStyle;
|
|
26595
26662
|
card = null;
|
|
26596
26663
|
constructor(opts = {}) {
|
|
26597
26664
|
this.rich = opts.rich ?? isRichTerminal();
|
|
26598
26665
|
this.out = opts.out ?? process.stdout;
|
|
26599
26666
|
this.err = opts.err ?? process.stderr;
|
|
26600
26667
|
this.width = opts.width ?? getTerminalWidth();
|
|
26668
|
+
this.toolStyle = opts.toolStyle ?? "inline";
|
|
26601
26669
|
this.spinner = new Spinner({
|
|
26602
26670
|
enabled: this.rich && (opts.spinner ?? true),
|
|
26603
26671
|
stream: this.err,
|
|
@@ -26614,11 +26682,24 @@ class Renderer {
|
|
|
26614
26682
|
meta(chunk) {
|
|
26615
26683
|
this.spinner.stop();
|
|
26616
26684
|
if (this.card) {
|
|
26617
|
-
this.
|
|
26685
|
+
if (this.toolStyle === "inline") {
|
|
26686
|
+
this.writeInlineBody(chunk);
|
|
26687
|
+
} else {
|
|
26688
|
+
this.card.body.push(chunk);
|
|
26689
|
+
}
|
|
26618
26690
|
} else {
|
|
26619
26691
|
this.out.write(chunk);
|
|
26620
26692
|
}
|
|
26621
26693
|
}
|
|
26694
|
+
writeInlineBody(chunk) {
|
|
26695
|
+
for (const line of chunk.split(`
|
|
26696
|
+
`)) {
|
|
26697
|
+
if (line.trim() === "")
|
|
26698
|
+
continue;
|
|
26699
|
+
this.out.write(`${GUTTER}${line}
|
|
26700
|
+
`);
|
|
26701
|
+
}
|
|
26702
|
+
}
|
|
26622
26703
|
reasoning(chunk) {
|
|
26623
26704
|
this.spinner.stop();
|
|
26624
26705
|
this.out.write(pc.dim(chunk));
|
|
@@ -26640,6 +26721,13 @@ ${pc.dim("⚙")} ${friendlyTool(tool)}${summary ? ` ${pc.dim(summary)}` : ""}
|
|
|
26640
26721
|
return;
|
|
26641
26722
|
}
|
|
26642
26723
|
this.card = { tool, args, body: [], start: Date.now() };
|
|
26724
|
+
if (this.toolStyle === "inline") {
|
|
26725
|
+
const marker = toolMarker(tool);
|
|
26726
|
+
this.out.write(`
|
|
26727
|
+
${pc.dim(marker)} ${friendlyTool(tool)}${summary ? ` ${pc.dim(summary)}` : ""}
|
|
26728
|
+
`);
|
|
26729
|
+
return;
|
|
26730
|
+
}
|
|
26643
26731
|
this.spinner.start(`${pc.dim("⚙")} ${friendlyTool(tool)}${summary ? ` ${pc.dim(summary)}` : ""}`);
|
|
26644
26732
|
}
|
|
26645
26733
|
toolEnd(_tool, duration, error, ctxDelta) {
|
|
@@ -26655,6 +26743,20 @@ ${pc.dim("⚙")} ${friendlyTool(tool)}${summary ? ` ${pc.dim(summary)}` : ""}
|
|
|
26655
26743
|
if (!this.card)
|
|
26656
26744
|
return;
|
|
26657
26745
|
const { tool, args, body } = this.card;
|
|
26746
|
+
const marker = error ? pc.red("✗") : pc.green("✓");
|
|
26747
|
+
let footer = `${marker} ${pc.dim(`${duration}ms`)}`;
|
|
26748
|
+
if (ctxDelta !== undefined && ctxDelta !== 0) {
|
|
26749
|
+
const deltaStr = ctxDelta > 0 ? pc.green(`+${ctxDelta}`) : pc.yellow(`${ctxDelta} ↓`);
|
|
26750
|
+
footer += ` ${pc.dim("ctx")} ${deltaStr}`;
|
|
26751
|
+
}
|
|
26752
|
+
if (this.toolStyle === "inline") {
|
|
26753
|
+
this.out.write(`${GUTTER}${footer}
|
|
26754
|
+
`);
|
|
26755
|
+
this.out.write(`${divider(this.width)}
|
|
26756
|
+
`);
|
|
26757
|
+
this.card = null;
|
|
26758
|
+
return;
|
|
26759
|
+
}
|
|
26658
26760
|
const lines = [];
|
|
26659
26761
|
const summary = summarizeArgs2(args);
|
|
26660
26762
|
if (summary)
|
|
@@ -26666,12 +26768,6 @@ ${pc.dim("⚙")} ${friendlyTool(tool)}${summary ? ` ${pc.dim(summary)}` : ""}
|
|
|
26666
26768
|
lines.push(line);
|
|
26667
26769
|
}
|
|
26668
26770
|
}
|
|
26669
|
-
const marker = error ? pc.red("✗") : pc.green("✓");
|
|
26670
|
-
let footer = `${marker} ${pc.dim(`${duration}ms`)}`;
|
|
26671
|
-
if (ctxDelta !== undefined && ctxDelta !== 0) {
|
|
26672
|
-
const deltaStr = ctxDelta > 0 ? pc.green(`+${ctxDelta}`) : pc.yellow(`${ctxDelta} ↓`);
|
|
26673
|
-
footer += ` ${pc.dim("ctx")} ${deltaStr}`;
|
|
26674
|
-
}
|
|
26675
26771
|
lines.push(footer);
|
|
26676
26772
|
const title = `${marker} ${friendlyTool(tool)}`;
|
|
26677
26773
|
for (const line of box(lines, { title, width: this.width })) {
|
|
@@ -26894,18 +26990,20 @@ class Repl {
|
|
|
26894
26990
|
readline2.emitKeypressEvents(process.stdin);
|
|
26895
26991
|
process.stdin.on("keypress", async (str, key) => {
|
|
26896
26992
|
if (key.name === "escape") {
|
|
26993
|
+
const escBytes = key.sequence ? (key.sequence.match(/\x1b/g) || []).length : 1;
|
|
26897
26994
|
const now = Date.now();
|
|
26898
|
-
|
|
26995
|
+
const withinWindow = now - this.lastEscTime < this.doubleEscDelay;
|
|
26996
|
+
this.lastEscTime = now;
|
|
26997
|
+
if (escBytes >= 2 || withinWindow) {
|
|
26998
|
+
this.lastEscTime = 0;
|
|
26899
26999
|
if (this.agentRunning) {
|
|
26900
27000
|
process.stdout.write(pc.yellow(`
|
|
26901
27001
|
${t("repl.interrupt")}
|
|
26902
27002
|
`));
|
|
26903
27003
|
this.agent.shutdown();
|
|
26904
27004
|
}
|
|
26905
|
-
this.lastEscTime = 0;
|
|
26906
|
-
return;
|
|
26907
27005
|
}
|
|
26908
|
-
|
|
27006
|
+
return;
|
|
26909
27007
|
}
|
|
26910
27008
|
if (key.ctrl && key.name === "v" && !this.agentRunning) {
|
|
26911
27009
|
try {
|
|
@@ -26918,6 +27016,10 @@ ${t("repl.interrupt")}
|
|
|
26918
27016
|
console.log(pc.green(`
|
|
26919
27017
|
${t("image.attached", { source: "clipboard", size: `${sizeKb} KB` })}`));
|
|
26920
27018
|
this.rl.prompt();
|
|
27019
|
+
} else {
|
|
27020
|
+
console.log(pc.yellow(`
|
|
27021
|
+
${t("image.clipboard_empty")}`));
|
|
27022
|
+
this.rl.prompt();
|
|
26921
27023
|
}
|
|
26922
27024
|
} catch {}
|
|
26923
27025
|
}
|
|
@@ -26962,7 +27064,8 @@ ${t("image.attached", { source: "clipboard", size: `${sizeKb} KB` })}`));
|
|
|
26962
27064
|
process.stdout.write(`
|
|
26963
27065
|
` + pc.green(t("repl.agent")));
|
|
26964
27066
|
const renderer = new Renderer({
|
|
26965
|
-
spinner: this.config.ui?.spinner ?? true
|
|
27067
|
+
spinner: this.config.ui?.spinner ?? true,
|
|
27068
|
+
toolStyle: this.config.ui?.toolStyle ?? "inline"
|
|
26966
27069
|
});
|
|
26967
27070
|
const result = await this.agent.run(input, (c) => renderer.text(c), (m) => renderer.meta(m), (ev) => {
|
|
26968
27071
|
if (ev.type === "start") {
|
|
@@ -27179,7 +27282,10 @@ async function main() {
|
|
|
27179
27282
|
`);
|
|
27180
27283
|
process.exit(result2.success ? 0 : 1);
|
|
27181
27284
|
}
|
|
27182
|
-
const renderer = new Renderer({
|
|
27285
|
+
const renderer = new Renderer({
|
|
27286
|
+
spinner: config.ui?.spinner ?? true,
|
|
27287
|
+
toolStyle: config.ui?.toolStyle ?? "inline"
|
|
27288
|
+
});
|
|
27183
27289
|
const result = await agent.run(prompt, (chunk) => renderer.text(chunk), (meta) => renderer.meta(meta), (ev) => {
|
|
27184
27290
|
if (ev.type === "start") {
|
|
27185
27291
|
renderer.toolStart(ev.tool, ev.args);
|