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.
Files changed (2) hide show
  1. package/dist/clixad.mjs +90 -20
  2. 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
- emit({
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 { content, messages, creditsCharged, balance, creditsWaived, freeCreditsLeft, steps: step + 1 };
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 { content: lastText, messages, creditsCharged, balance, creditsWaived, freeCreditsLeft, steps: 0, stopped: reason };
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 spacer = Math.max(0, viewport - printed - used);
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)
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clixad",
3
- "version": "0.0.1-beta.23",
3
+ "version": "0.0.1-beta.24",
4
4
  "description": "Free AI coding agent in your terminal, funded by rewarded ads.",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",