clixad 0.0.1-beta.23 → 0.0.1-beta.24
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/clixad.mjs +90 -20
- package/package.json +1 -1
package/dist/clixad.mjs
CHANGED
|
@@ -327,6 +327,13 @@ function extraFormatIds(raw) {
|
|
|
327
327
|
function imagePart(image) {
|
|
328
328
|
return { type: "image_url", image_url: { url: `data:${image.mimeType};base64,${image.data}` } };
|
|
329
329
|
}
|
|
330
|
+
function withoutReasoning(messages) {
|
|
331
|
+
return messages.map((message) => {
|
|
332
|
+
if (!message.reasoning_details) return message;
|
|
333
|
+
const { reasoning_details: _dropped, ...rest } = message;
|
|
334
|
+
return rest;
|
|
335
|
+
});
|
|
336
|
+
}
|
|
330
337
|
function messageText(message) {
|
|
331
338
|
const content = message.content;
|
|
332
339
|
if (typeof content === "string") return content;
|
|
@@ -447,6 +454,26 @@ function accumulateToolCall(calls, part, fallbackIndex) {
|
|
|
447
454
|
if (part.function?.arguments) current.function.arguments += part.function.arguments;
|
|
448
455
|
calls.set(index, current);
|
|
449
456
|
}
|
|
457
|
+
function mergeReasoningDetails(acc, delta) {
|
|
458
|
+
if (!Array.isArray(delta)) return;
|
|
459
|
+
for (const piece of delta) {
|
|
460
|
+
if (!piece || typeof piece !== "object") continue;
|
|
461
|
+
const part = piece;
|
|
462
|
+
const existing = typeof part.index === "number" ? acc.find((block) => block.index === part.index) : void 0;
|
|
463
|
+
if (!existing) {
|
|
464
|
+
acc.push({ ...part });
|
|
465
|
+
continue;
|
|
466
|
+
}
|
|
467
|
+
for (const [key, value] of Object.entries(part)) {
|
|
468
|
+
if (value === null || value === void 0) continue;
|
|
469
|
+
if ((key === "text" || key === "summary" || key === "data") && typeof value === "string") {
|
|
470
|
+
existing[key] = `${typeof existing[key] === "string" ? existing[key] : ""}${value}`;
|
|
471
|
+
} else {
|
|
472
|
+
existing[key] = value;
|
|
473
|
+
}
|
|
474
|
+
}
|
|
475
|
+
}
|
|
476
|
+
}
|
|
450
477
|
async function* parseSSE(body) {
|
|
451
478
|
const reader = body.getReader();
|
|
452
479
|
const decoder = new TextDecoder();
|
|
@@ -1150,6 +1177,7 @@ var init_client = __esm({
|
|
|
1150
1177
|
let balance = 0;
|
|
1151
1178
|
let streamError;
|
|
1152
1179
|
const calls = /* @__PURE__ */ new Map();
|
|
1180
|
+
const reasoning = [];
|
|
1153
1181
|
for await (const evt of parseSSE(res.body)) {
|
|
1154
1182
|
if (evt === "[DONE]") break;
|
|
1155
1183
|
let json;
|
|
@@ -1167,6 +1195,7 @@ var init_client = __esm({
|
|
|
1167
1195
|
for (const [index, part] of (choice?.delta?.tool_calls ?? []).entries()) {
|
|
1168
1196
|
accumulateToolCall(calls, part, index);
|
|
1169
1197
|
}
|
|
1198
|
+
mergeReasoningDetails(reasoning, choice?.delta?.reasoning_details);
|
|
1170
1199
|
if (choice?.finish_reason) finishReason = choice.finish_reason;
|
|
1171
1200
|
if (json.error) streamError = json.error.message || "the model stream failed";
|
|
1172
1201
|
if (json.clixad) {
|
|
@@ -1179,6 +1208,7 @@ var init_client = __esm({
|
|
|
1179
1208
|
const message = { role: "assistant", content: content || null };
|
|
1180
1209
|
if (calls.size > 0) {
|
|
1181
1210
|
message.tool_calls = [...calls.entries()].sort(([a], [b]) => a - b).map(([, c2]) => c2);
|
|
1211
|
+
if (reasoning.length) message.reasoning_details = reasoning;
|
|
1182
1212
|
}
|
|
1183
1213
|
return { message, finishReason, creditsCharged, balance, ...free };
|
|
1184
1214
|
}
|
|
@@ -4060,6 +4090,19 @@ ${NO_SEARCH_INSTRUCTION}`,
|
|
|
4060
4090
|
|
|
4061
4091
|
(the sub-agent hit its step limit \u2014 this answer may be incomplete)` : answer;
|
|
4062
4092
|
}
|
|
4093
|
+
function emitUsage(turn) {
|
|
4094
|
+
emit({
|
|
4095
|
+
type: "usage",
|
|
4096
|
+
creditsCharged: turn.creditsCharged,
|
|
4097
|
+
balance: turn.balance,
|
|
4098
|
+
...turn.free ? {
|
|
4099
|
+
free: true,
|
|
4100
|
+
creditsWaived: turn.creditsWaived ?? 0,
|
|
4101
|
+
freeCreditsLeft: turn.freeCreditsLeft ?? 0
|
|
4102
|
+
} : {}
|
|
4103
|
+
});
|
|
4104
|
+
}
|
|
4105
|
+
let retriedEmpty = false;
|
|
4063
4106
|
for (let step = 0; step < maxSteps; step++) {
|
|
4064
4107
|
if (opts.signal?.aborted) return stop("aborted");
|
|
4065
4108
|
let turn;
|
|
@@ -4077,23 +4120,27 @@ ${NO_SEARCH_INSTRUCTION}`,
|
|
|
4077
4120
|
creditsWaived += turn.creditsWaived ?? 0;
|
|
4078
4121
|
if (turn.freeCreditsLeft !== void 0) freeCreditsLeft = turn.freeCreditsLeft;
|
|
4079
4122
|
balance = turn.balance;
|
|
4080
|
-
|
|
4081
|
-
type: "usage",
|
|
4082
|
-
creditsCharged: turn.creditsCharged,
|
|
4083
|
-
balance: turn.balance,
|
|
4084
|
-
...turn.free ? {
|
|
4085
|
-
free: true,
|
|
4086
|
-
creditsWaived: turn.creditsWaived ?? 0,
|
|
4087
|
-
freeCreditsLeft: turn.freeCreditsLeft ?? 0
|
|
4088
|
-
} : {}
|
|
4089
|
-
});
|
|
4090
|
-
messages.push(turn.message);
|
|
4123
|
+
emitUsage(turn);
|
|
4091
4124
|
const content = messageText(turn.message);
|
|
4092
|
-
if (content) lastText = content;
|
|
4093
4125
|
const calls = turn.message.tool_calls ?? [];
|
|
4126
|
+
if (calls.length === 0 && !content.trim() && !retriedEmpty) {
|
|
4127
|
+
retriedEmpty = true;
|
|
4128
|
+
continue;
|
|
4129
|
+
}
|
|
4130
|
+
retriedEmpty = false;
|
|
4131
|
+
messages.push(turn.message);
|
|
4132
|
+
if (content) lastText = content;
|
|
4094
4133
|
if (calls.length === 0) {
|
|
4095
4134
|
emit({ type: "final", content, creditsCharged, balance });
|
|
4096
|
-
return {
|
|
4135
|
+
return {
|
|
4136
|
+
content,
|
|
4137
|
+
messages: withoutReasoning(messages),
|
|
4138
|
+
creditsCharged,
|
|
4139
|
+
balance,
|
|
4140
|
+
creditsWaived,
|
|
4141
|
+
freeCreditsLeft,
|
|
4142
|
+
steps: step + 1
|
|
4143
|
+
};
|
|
4097
4144
|
}
|
|
4098
4145
|
if (content) emit({ type: "message", content });
|
|
4099
4146
|
pendingImages = [];
|
|
@@ -4117,7 +4164,7 @@ ${NO_SEARCH_INSTRUCTION}`,
|
|
|
4117
4164
|
emit({ type: "max_steps" });
|
|
4118
4165
|
return {
|
|
4119
4166
|
content: lastText || "(stopped: reached max steps)",
|
|
4120
|
-
messages,
|
|
4167
|
+
messages: withoutReasoning(messages),
|
|
4121
4168
|
creditsCharged,
|
|
4122
4169
|
balance,
|
|
4123
4170
|
creditsWaived,
|
|
@@ -4127,7 +4174,16 @@ ${NO_SEARCH_INSTRUCTION}`,
|
|
|
4127
4174
|
};
|
|
4128
4175
|
function stop(reason) {
|
|
4129
4176
|
emit({ type: reason });
|
|
4130
|
-
return {
|
|
4177
|
+
return {
|
|
4178
|
+
content: lastText,
|
|
4179
|
+
messages: withoutReasoning(messages),
|
|
4180
|
+
creditsCharged,
|
|
4181
|
+
balance,
|
|
4182
|
+
creditsWaived,
|
|
4183
|
+
freeCreditsLeft,
|
|
4184
|
+
steps: 0,
|
|
4185
|
+
stopped: reason
|
|
4186
|
+
};
|
|
4131
4187
|
}
|
|
4132
4188
|
}
|
|
4133
4189
|
function toolMessage(call, content) {
|
|
@@ -4230,7 +4286,7 @@ var init_agent = __esm({
|
|
|
4230
4286
|
init_mcp();
|
|
4231
4287
|
init_client();
|
|
4232
4288
|
SUBAGENT_MAX_STEPS = 12;
|
|
4233
|
-
SYSTEM_PROMPT = "You are Clixad, a terminal coding agent. You can read, search, write and edit files and run shell commands, all confined to the user's workspace. Find your way around with glob and grep before reading whole files. Prefer edit_file over write_file for existing files. Make minimal correct edits, verify them when a test or build command is available, and stop when the task is complete. Keep your final message short: say what you did and why.\n\nNot every message is a task. If the user asks a question, or asks you to say something, answer in plain text and call no tools at all. Reach for a file or a command only when the request is actually about one, and when a message is ambiguous, prefer the reading of it that changes nothing.\n\nA tool call that was refused did not happen. Never describe it as done, and do not repeat it on a later message unless the user asks for it again.\n\nReach outside the workspace when the answer is outside it: web_search for current documentation, releases and error messages, then web_fetch to read the page. Do not guess at an API you could look up.\n\nStart anything that does not exit on its own \u2014 dev servers, watchers, tailed logs \u2014 with run_command background: true, and read it with read_output. A foreground command is killed after its timeout.\n\nWhen finding something out means opening many files, give it to task instead: the sub-agent reads them in its own context and reports back, which keeps this conversation short. Use todo_write for work with several distinct steps, and keep it current as you go.";
|
|
4289
|
+
SYSTEM_PROMPT = "You are Clixad, a terminal coding agent. You can read, search, write and edit files and run shell commands, all confined to the user's workspace. When someone asks who or what you are, answer that you are Clixad, in their language; do not introduce yourself as the underlying language model or as a product of the company that trained it. If asked which model you run on, say it is the one selected with /model, shown under the input box. Find your way around with glob and grep before reading whole files. Prefer edit_file over write_file for existing files. Make minimal correct edits, verify them when a test or build command is available, and stop when the task is complete. Keep your final message short: say what you did and why.\n\nNot every message is a task. If the user asks a question, or asks you to say something, answer in plain text and call no tools at all. Reach for a file or a command only when the request is actually about one, and when a message is ambiguous, prefer the reading of it that changes nothing.\n\nA tool call that was refused did not happen. Never describe it as done, and do not repeat it on a later message unless the user asks for it again.\n\nReach outside the workspace when the answer is outside it: web_search for current documentation, releases and error messages, then web_fetch to read the page. Do not guess at an API you could look up.\n\nStart anything that does not exit on its own \u2014 dev servers, watchers, tailed logs \u2014 with run_command background: true, and read it with read_output. A foreground command is killed after its timeout.\n\nWhen finding something out means opening many files, give it to task instead: the sub-agent reads them in its own context and reports back, which keeps this conversation short. Use todo_write for work with several distinct steps, and keep it current as you go.";
|
|
4234
4290
|
NO_SEARCH_INSTRUCTION = [
|
|
4235
4291
|
"# Web search is not available on this gateway",
|
|
4236
4292
|
"There is no web_search tool. web_fetch works normally and needs no key, so fetch a URL directly",
|
|
@@ -4620,7 +4676,7 @@ var init_kimi = __esm({
|
|
|
4620
4676
|
"gemini-3.8-flash": 1048576,
|
|
4621
4677
|
"kimi-k2.7-code": 262144,
|
|
4622
4678
|
"claude-haiku-4.5": 2e5,
|
|
4623
|
-
"claude-sonnet-5": 1e6,
|
|
4679
|
+
"claude-sonnet-5.5": 1e6,
|
|
4624
4680
|
"gpt-6-sol": 105e4,
|
|
4625
4681
|
"kimi-k3": 1048576,
|
|
4626
4682
|
"claude-opus-5.5": 1e6,
|
|
@@ -4634,7 +4690,9 @@ var init_kimi = __esm({
|
|
|
4634
4690
|
"gpt-5.2": 105e4,
|
|
4635
4691
|
"claude-opus-5": 1e6,
|
|
4636
4692
|
"gpt-5.5": 105e4,
|
|
4637
|
-
"gpt-5.2-pro": 105e4
|
|
4693
|
+
"gpt-5.2-pro": 105e4,
|
|
4694
|
+
// Retired on 2026-09-29 for Claude Sonnet 5.5, same window.
|
|
4695
|
+
"claude-sonnet-5": 1e6
|
|
4638
4696
|
};
|
|
4639
4697
|
DEFAULT_CONTEXT_TOKENS = 256e3;
|
|
4640
4698
|
INSTALL_HELP = `Kimi CLI is not installed (or not on PATH).
|
|
@@ -5751,7 +5809,7 @@ var init_views = __esm({
|
|
|
5751
5809
|
});
|
|
5752
5810
|
|
|
5753
5811
|
// src/tui/app.tsx
|
|
5754
|
-
import { useCallback, useEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
5812
|
+
import { useCallback, useEffect, useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from "react";
|
|
5755
5813
|
import { Box as Box2, Static, Text as Text2, useApp, useInput, usePaste, useStdout } from "ink";
|
|
5756
5814
|
import { Fragment, jsx as jsx2, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
5757
5815
|
function buyDeclarationLines(pack) {
|
|
@@ -5965,6 +6023,9 @@ function App({
|
|
|
5965
6023
|
);
|
|
5966
6024
|
const tallyRef = useRef(createTally());
|
|
5967
6025
|
const heightCacheRef = useRef(/* @__PURE__ */ new Map());
|
|
6026
|
+
const screenRef = useRef(
|
|
6027
|
+
null
|
|
6028
|
+
);
|
|
5968
6029
|
const push = useCallback((e) => {
|
|
5969
6030
|
const id = idRef.current++;
|
|
5970
6031
|
setEntries((prev) => [...prev, { ...e, id }]);
|
|
@@ -7469,7 +7530,16 @@ ${dropped.map((l) => ` \xB7 ${l}`).join("\n")}`
|
|
|
7469
7530
|
}, 0);
|
|
7470
7531
|
}, [entries, cols]);
|
|
7471
7532
|
const used = chromeHeight + menu.length + pickerHeight + askHeight + planHeight + buyHeight + busyHeight + liveHeight;
|
|
7472
|
-
const
|
|
7533
|
+
const lastScreen = screenRef.current;
|
|
7534
|
+
const freshScreen = !lastScreen || lastScreen.epoch !== staticEpoch || lastScreen.rows !== rows || lastScreen.cols !== cols || printed < lastScreen.printed;
|
|
7535
|
+
const onScreen = Math.max(
|
|
7536
|
+
0,
|
|
7537
|
+
Math.min(freshScreen ? printed : lastScreen.onScreen + (printed - lastScreen.printed), viewport - used)
|
|
7538
|
+
);
|
|
7539
|
+
const spacer = Math.max(0, viewport - onScreen - used);
|
|
7540
|
+
useLayoutEffect(() => {
|
|
7541
|
+
screenRef.current = { epoch: staticEpoch, rows, cols, printed, onScreen };
|
|
7542
|
+
});
|
|
7473
7543
|
const labelW = Math.min(
|
|
7474
7544
|
Math.max(1, Math.floor(cols * 0.5)),
|
|
7475
7545
|
menu.reduce((w, c2) => Math.max(w, visibleLength(c2.label)), 0)
|