kimiflare 0.39.0 → 0.40.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/index.js CHANGED
@@ -2654,9 +2654,6 @@ function collapsePath(input, cwd, maxLen = 40) {
2654
2654
  if (parts.length <= 2) return input;
2655
2655
  return `\u2026/${parts.slice(-2).join(sep)}`;
2656
2656
  }
2657
- function collapsePathsInText(s, cwd, maxLen = 40) {
2658
- return s.replace(/([~/][^\s"',)}\]]+)/g, (match) => collapsePath(match, cwd, maxLen));
2659
- }
2660
2657
  var init_paths = __esm({
2661
2658
  "src/util/paths.ts"() {
2662
2659
  "use strict";
@@ -6719,16 +6716,191 @@ var init_diff_view = __esm({
6719
6716
  }
6720
6717
  });
6721
6718
 
6719
+ // src/ui/narrative.ts
6720
+ function countByCategory(items) {
6721
+ let reads = 0;
6722
+ let writes = 0;
6723
+ let shells = 0;
6724
+ let webs = 0;
6725
+ let memories = 0;
6726
+ let others = 0;
6727
+ for (const t of items) {
6728
+ if (READING_TOOLS.has(t.name)) reads++;
6729
+ else if (WRITING_TOOLS.has(t.name)) writes++;
6730
+ else if (SHELL_TOOLS.has(t.name)) shells++;
6731
+ else if (WEB_TOOLS.has(t.name)) webs++;
6732
+ else if (MEMORY_TOOLS.has(t.name)) memories++;
6733
+ else others++;
6734
+ }
6735
+ return { reads, writes, shells, webs, memories, others };
6736
+ }
6737
+ function pickOne(arr) {
6738
+ return arr[Math.floor(Math.random() * arr.length)];
6739
+ }
6740
+ function generateActivityText(items, _ctx) {
6741
+ if (items.length === 0) return null;
6742
+ const { reads, writes, shells, webs, memories } = countByCategory(items);
6743
+ const total = items.length;
6744
+ if (total === 1) {
6745
+ const t = items[0];
6746
+ if (t.name === "read") {
6747
+ const path = typeof t.args?.path === "string" ? t.args.path : "a file";
6748
+ return pickOne([`Reading ${path}\u2026`, `Opening ${path}\u2026`, `Taking a look at ${path}\u2026`]);
6749
+ }
6750
+ if (t.name === "grep") {
6751
+ const pattern = typeof t.args?.pattern === "string" ? `"${t.args.pattern}"` : "for patterns";
6752
+ return pickOne([`Searching for ${pattern}\u2026`, `Hunting for ${pattern}\u2026`]);
6753
+ }
6754
+ if (t.name === "glob") {
6755
+ const pattern = typeof t.args?.pattern === "string" ? t.args.pattern : "files";
6756
+ return pickOne([`Finding ${pattern}\u2026`, `Gathering ${pattern}\u2026`]);
6757
+ }
6758
+ if (t.name === "write") {
6759
+ const path = typeof t.args?.path === "string" ? t.args.path : "a file";
6760
+ return pickOne([`Creating ${path}\u2026`, `Writing ${path}\u2026`]);
6761
+ }
6762
+ if (t.name === "edit") {
6763
+ const path = typeof t.args?.path === "string" ? t.args.path : "a file";
6764
+ return pickOne([`Patching ${path}\u2026`, `Editing ${path}\u2026`]);
6765
+ }
6766
+ if (t.name === "bash") {
6767
+ return pickOne([`Running a shell command\u2026`, `Executing something in the terminal\u2026`]);
6768
+ }
6769
+ if (t.name === "web_fetch") {
6770
+ return pickOne([`Fetching docs\u2026`, `Checking a reference\u2026`, `Looking something up\u2026`]);
6771
+ }
6772
+ if (t.name === "memory_remember") {
6773
+ return pickOne([`Taking notes for next time\u2026`, `Committing that to memory\u2026`]);
6774
+ }
6775
+ if (t.name === "memory_recall") {
6776
+ return pickOne([`Recalling what we know\u2026`, `Searching past notes\u2026`]);
6777
+ }
6778
+ return null;
6779
+ }
6780
+ if (webs >= 2) {
6781
+ return pickOne([`Digging through documentation\u2026`, `Cross-referencing sources\u2026`, `Reading up on this\u2026`]);
6782
+ }
6783
+ if (reads >= 2 && writes === 0 && shells === 0) {
6784
+ return pickOne([`Surveying the landscape\u2026`, `Getting the lay of the land\u2026`, `Mapping out the files\u2026`]);
6785
+ }
6786
+ if (reads >= 1 && (writes >= 1 || shells >= 1)) {
6787
+ return pickOne([`Reading, then making changes\u2026`, `Exploring and editing\u2026`, `Survey and patch\u2026`]);
6788
+ }
6789
+ if (writes >= 1 && shells >= 1) {
6790
+ return pickOne([`Committing the changes\u2026`, `Writing and verifying\u2026`, `Editing and checking\u2026`]);
6791
+ }
6792
+ if (reads >= 1 && webs >= 1) {
6793
+ return pickOne([`Exploring the codebase and docs\u2026`, `Cross-referencing code with references\u2026`]);
6794
+ }
6795
+ if (memories >= 1) {
6796
+ return pickOne([`Jogging the memory\u2026`, `Checking past notes\u2026`]);
6797
+ }
6798
+ if (shells >= 1) {
6799
+ return pickOne([`Running some commands\u2026`, `Working in the shell\u2026`]);
6800
+ }
6801
+ return null;
6802
+ }
6803
+ function narrativizeInfo(text, ctx) {
6804
+ if (ctx?.tier === "heavy") {
6805
+ return { kind: "activity", text: "Sizing this up\u2026 feels like a deep one.", feature: "triage" };
6806
+ }
6807
+ if (ctx?.tier === "light") {
6808
+ return { kind: "activity", text: "Quick check \u2014 this looks light.", feature: "triage" };
6809
+ }
6810
+ if (ctx?.tier === "medium") {
6811
+ return { kind: "activity", text: "This one feels medium weight.", feature: "triage" };
6812
+ }
6813
+ if (ctx?.codeMode) {
6814
+ return { kind: "activity", text: "The toolbox feels right for this. Switching to code mode\u2026", feature: "code" };
6815
+ }
6816
+ if (text.includes("auto-compacted") || text.includes("compacted")) {
6817
+ return { kind: "activity", text: "Making room by summarizing older turns\u2026", feature: "compact" };
6818
+ }
6819
+ if (text.includes("recalled") && text.includes("memory")) {
6820
+ return { kind: "activity", text: "Remembering what we learned before\u2026", feature: "memory" };
6821
+ }
6822
+ if (text.includes("memory cleanup") || text.includes("memory backfill")) {
6823
+ return null;
6824
+ }
6825
+ if (text.startsWith("LSP ready")) {
6826
+ return { kind: "activity", text: "Waking up the language servers\u2026" };
6827
+ }
6828
+ if (text.startsWith("LSP reload complete")) {
6829
+ return null;
6830
+ }
6831
+ if (text.startsWith("MCP connected")) {
6832
+ return { kind: "activity", text: "Plugging in external tools\u2026" };
6833
+ }
6834
+ if (text.includes("research budget") || text.includes("web request")) {
6835
+ return { kind: "activity", text: "Researching\u2026 gathering what we can from the web.", feature: "explore" };
6836
+ }
6837
+ return null;
6838
+ }
6839
+ function humanizeToolTitle(name, args) {
6840
+ const path = typeof args?.path === "string" ? args.path : void 0;
6841
+ const pattern = typeof args?.pattern === "string" ? args.pattern : void 0;
6842
+ const command = typeof args?.command === "string" ? args.command : void 0;
6843
+ const url = typeof args?.url === "string" ? args.url : void 0;
6844
+ switch (name) {
6845
+ case "read":
6846
+ return path ? `Reading ${path}` : "Reading a file\u2026";
6847
+ case "grep":
6848
+ return pattern ? `Searching for "${pattern}"` : "Searching\u2026";
6849
+ case "glob":
6850
+ return pattern ? `Finding ${pattern}` : "Finding files\u2026";
6851
+ case "write":
6852
+ return path ? `Creating ${path}` : "Creating a file\u2026";
6853
+ case "edit":
6854
+ return path ? `Patching ${path}` : "Patching a file\u2026";
6855
+ case "bash":
6856
+ return command ? `Running: ${command.split(/\s+/).slice(0, 4).join(" ")}${command.split(/\s+/).length > 4 ? "\u2026" : ""}` : "Running shell command\u2026";
6857
+ case "web_fetch":
6858
+ return url ? `Fetching ${url.replace(/^https?:\/\//, "").split("/")[0]}` : "Fetching docs\u2026";
6859
+ case "memory_remember":
6860
+ return "Committing to memory\u2026";
6861
+ case "memory_recall":
6862
+ return "Recalling memories\u2026";
6863
+ case "memory_forget":
6864
+ return "Forgetting a memory\u2026";
6865
+ case "lsp_hover":
6866
+ return "Inspecting symbol\u2026";
6867
+ case "lsp_definition":
6868
+ return "Jumping to definition\u2026";
6869
+ case "lsp_references":
6870
+ return "Finding references\u2026";
6871
+ case "lsp_implementation":
6872
+ return "Finding implementations\u2026";
6873
+ case "lsp_typeDefinition":
6874
+ return "Finding type definition\u2026";
6875
+ case "lsp_documentSymbols":
6876
+ return "Listing symbols\u2026";
6877
+ case "lsp_workspaceSymbol":
6878
+ return "Searching workspace symbols\u2026";
6879
+ case "lsp_rename":
6880
+ return "Renaming symbol\u2026";
6881
+ case "lsp_codeAction":
6882
+ return "Applying quick fix\u2026";
6883
+ default:
6884
+ return name;
6885
+ }
6886
+ }
6887
+ var READING_TOOLS, WRITING_TOOLS, SHELL_TOOLS, WEB_TOOLS, MEMORY_TOOLS;
6888
+ var init_narrative = __esm({
6889
+ "src/ui/narrative.ts"() {
6890
+ "use strict";
6891
+ READING_TOOLS = /* @__PURE__ */ new Set(["read", "glob", "grep", "lsp_hover", "lsp_definition", "lsp_references", "lsp_implementation", "lsp_typeDefinition", "lsp_documentSymbols", "lsp_workspaceSymbol"]);
6892
+ WRITING_TOOLS = /* @__PURE__ */ new Set(["write", "edit", "lsp_rename", "lsp_codeAction"]);
6893
+ SHELL_TOOLS = /* @__PURE__ */ new Set(["bash"]);
6894
+ WEB_TOOLS = /* @__PURE__ */ new Set(["web_fetch"]);
6895
+ MEMORY_TOOLS = /* @__PURE__ */ new Set(["memory_remember", "memory_recall", "memory_forget"]);
6896
+ }
6897
+ });
6898
+
6722
6899
  // src/ui/tool-view.tsx
6723
6900
  import React2 from "react";
6724
6901
  import { Box as Box2, Text as Text2 } from "ink";
6725
6902
  import Spinner from "ink-spinner";
6726
6903
  import { jsx as jsx3, jsxs as jsxs2 } from "react/jsx-runtime";
6727
- function compactArgs(raw) {
6728
- const collapsed = collapsePathsInText(raw, process.cwd());
6729
- const s = collapsed.replace(/\s+/g, " ");
6730
- return s.length <= 80 ? s : s.slice(0, 80) + "\u2026";
6731
- }
6732
6904
  function firstLine(s) {
6733
6905
  const line = s.split("\n").find((l) => l.trim().length > 0) ?? "";
6734
6906
  return line.length <= 120 ? line : line.slice(0, 120) + "\u2026";
@@ -6740,10 +6912,18 @@ var init_tool_view = __esm({
6740
6912
  init_diff_view();
6741
6913
  init_paths();
6742
6914
  init_theme_context();
6915
+ init_narrative();
6743
6916
  ToolView = React2.memo(function ToolView2({ evt, verbose }) {
6744
6917
  const theme = useTheme();
6745
6918
  const statusIcon = evt.status === "running" ? /* @__PURE__ */ jsx3(Text2, { color: theme.info.color, children: /* @__PURE__ */ jsx3(Spinner, { type: "dots" }) }) : evt.status === "error" ? /* @__PURE__ */ jsx3(Text2, { color: theme.palette.error, children: "\u2717" }) : /* @__PURE__ */ jsx3(Text2, { color: theme.palette.success, children: "\u2713" });
6746
- const title = evt.render?.title ?? `${evt.name}(${compactArgs(evt.args)})`;
6919
+ const title = evt.render?.title ?? (() => {
6920
+ try {
6921
+ const args = evt.args ? JSON.parse(evt.args) : {};
6922
+ return humanizeToolTitle(evt.name, args);
6923
+ } catch {
6924
+ return humanizeToolTitle(evt.name);
6925
+ }
6926
+ })();
6747
6927
  const expand = Boolean(evt.expanded || verbose);
6748
6928
  const lines = evt.result ? evt.result.split("\n") : [];
6749
6929
  const showLimit = verbose ? 200 : 20;
@@ -6958,12 +7138,13 @@ var init_chat = __esm({
6958
7138
  init_tool_view();
6959
7139
  init_markdown();
6960
7140
  init_theme_context();
6961
- ChatView = React4.memo(function ChatView2({ events, showReasoning, verbose }) {
7141
+ ChatView = React4.memo(function ChatView2({ events, showReasoning, verbose, suppressTools }) {
6962
7142
  const theme = useTheme();
6963
7143
  const finalized = [];
6964
7144
  const active = [];
6965
7145
  for (let i = 0; i < events.length; i++) {
6966
7146
  const e = events[i];
7147
+ if (suppressTools && e.kind === "tool") continue;
6967
7148
  const isStreaming = e.kind === "assistant" && e.streaming;
6968
7149
  if (isStreaming) {
6969
7150
  active.push(e);
@@ -7035,6 +7216,12 @@ var init_chat = __esm({
7035
7216
  evt.text
7036
7217
  ] });
7037
7218
  }
7219
+ if (evt.kind === "activity") {
7220
+ return /* @__PURE__ */ jsxs4(Text4, { italic: true, color: theme.info.dim ? theme.info.color : theme.palette.secondary, children: [
7221
+ "~ ",
7222
+ evt.text
7223
+ ] });
7224
+ }
7038
7225
  return /* @__PURE__ */ jsxs4(Text4, { color: theme.error, children: [
7039
7226
  "! ",
7040
7227
  evt.text
@@ -12569,23 +12756,18 @@ function PaletteSwatches({ palette }) {
12569
12756
  ];
12570
12757
  return /* @__PURE__ */ jsx20(Box18, { children: colors.map((c, i) => /* @__PURE__ */ jsx20(Text19, { color: c, children: "\u2588" }, i)) });
12571
12758
  }
12572
- function ThemePicker({ themes, onPick, onPreview }) {
12759
+ function ThemePicker({ themes, onPick }) {
12573
12760
  const current = useTheme();
12574
12761
  const items = [
12575
12762
  ...themes.map((t) => ({ label: t.label, value: t.name })),
12576
12763
  { label: "< Back", value: "__back__" }
12577
12764
  ];
12578
12765
  return /* @__PURE__ */ jsxs18(Box18, { flexDirection: "column", borderStyle: "round", borderColor: current.accent, paddingX: 1, children: [
12579
- /* @__PURE__ */ jsx20(Text19, { color: current.accent, bold: true, children: "Pick a theme" }),
12766
+ /* @__PURE__ */ jsx20(Text19, { color: current.accent, bold: true, children: "Pick a theme (restart to apply)" }),
12580
12767
  /* @__PURE__ */ jsx20(Box18, { marginTop: 1, children: /* @__PURE__ */ jsx20(
12581
12768
  SelectInput10,
12582
12769
  {
12583
12770
  items,
12584
- onHighlight: (item) => {
12585
- if (item.value === "__back__") return;
12586
- const t = themes.find((x) => x.name === item.value);
12587
- if (t) onPreview?.(t);
12588
- },
12589
12771
  onSelect: (item) => {
12590
12772
  if (item.value === "__back__") {
12591
12773
  onPick(null);
@@ -13294,7 +13476,6 @@ function App({
13294
13476
  const [latestVersion, setLatestVersion] = useState10(initialUpdateResult?.latestVersion ?? null);
13295
13477
  const [theme, setTheme] = useState10(resolveTheme(initialCfg?.theme));
13296
13478
  const [showThemePicker, setShowThemePicker] = useState10(false);
13297
- const [originalTheme, setOriginalTheme] = useState10(null);
13298
13479
  useEffect6(() => {
13299
13480
  if (!cfg?.cloudMode || !initialCloudToken) return;
13300
13481
  let cancelled = false;
@@ -13325,6 +13506,8 @@ function App({
13325
13506
  const permResolveRef = useRef3(null);
13326
13507
  const limitResolveRef = useRef3(null);
13327
13508
  const pendingToolCallsRef = useRef3(/* @__PURE__ */ new Map());
13509
+ const toolBatchRef = useRef3([]);
13510
+ const toolBatchTimerRef = useRef3(null);
13328
13511
  const sessionIdRef = useRef3(null);
13329
13512
  const modeRef = useRef3(mode);
13330
13513
  const effortRef = useRef3(effort);
@@ -13571,7 +13754,7 @@ function App({
13571
13754
  messagesRef.current.splice(insertIdx, 0, { role: "system", content: text });
13572
13755
  setEvents((e) => [
13573
13756
  ...e,
13574
- { kind: "memory", key: mkKey(), text: `recalled ${results.length} memory${results.length === 1 ? "" : "ies"} about this repo` }
13757
+ { kind: "activity", key: mkKey(), text: "Remembering what we know about this repo\u2026", feature: "memory" }
13575
13758
  ]);
13576
13759
  }
13577
13760
  } catch {
@@ -13790,7 +13973,7 @@ function App({
13790
13973
  }
13791
13974
  setEvents((e) => [
13792
13975
  ...e,
13793
- { kind: "info", key: mkKey(), text: `MCP connected \u2014 ${totalTools} external tool${totalTools === 1 ? "" : "s"} available` }
13976
+ { kind: "activity", key: mkKey(), text: "Plugging in external tools\u2026" }
13794
13977
  ]);
13795
13978
  }
13796
13979
  }, [cfg]);
@@ -13848,7 +14031,7 @@ function App({
13848
14031
  }
13849
14032
  setEvents((e) => [
13850
14033
  ...e,
13851
- { kind: "info", key: mkKey(), text: `LSP ready \u2014 ${totalServers} server${totalServers === 1 ? "" : "s"} active` }
14034
+ { kind: "activity", key: mkKey(), text: "Waking up the language servers\u2026" }
13852
14035
  ]);
13853
14036
  } else {
13854
14037
  setEvents((e) => [
@@ -13997,7 +14180,7 @@ function App({
13997
14180
  return;
13998
14181
  }
13999
14182
  if (key.escape) {
14000
- const modalOpen = perm !== null || limitModal !== null || showHelpMenu || showLspWizard || showCommandList || commandWizard !== null || commandToDelete !== null || resumeSessions !== null;
14183
+ const modalOpen = perm !== null || limitModal !== null || showHelpMenu || showLspWizard || showCommandList || commandWizard !== null || commandToDelete !== null || resumeSessions !== null || showThemePicker;
14001
14184
  if (!modalOpen && busyRef.current && activeControllerRef.current) {
14002
14185
  if (permResolveRef.current) {
14003
14186
  permResolveRef.current("deny");
@@ -14085,6 +14268,16 @@ function App({
14085
14268
  },
14086
14269
  []
14087
14270
  );
14271
+ const flushToolBatch = useCallback2(() => {
14272
+ toolBatchTimerRef.current = null;
14273
+ const batch = toolBatchRef.current;
14274
+ toolBatchRef.current = [];
14275
+ if (batch.length === 0) return;
14276
+ const text = generateActivityText(batch, { mode: modeRef.current });
14277
+ if (text) {
14278
+ setEvents((e) => [...e, { kind: "activity", key: mkKey(), text, feature: "explore" }]);
14279
+ }
14280
+ }, []);
14088
14281
  const updateGatewayMeta = useCallback2((meta) => {
14089
14282
  gatewayMetaRef.current = meta;
14090
14283
  setGatewayMeta(meta);
@@ -14261,11 +14454,16 @@ function App({
14261
14454
  pendingToolCallsRef.current.set(call.id, call.function.name);
14262
14455
  const spec = executorRef.current.list().find((t) => t.name === call.function.name);
14263
14456
  let renderMeta;
14457
+ let argsParsed = {};
14264
14458
  try {
14265
- const args = call.function.arguments ? JSON.parse(call.function.arguments) : {};
14266
- renderMeta = spec?.render?.(args);
14459
+ argsParsed = call.function.arguments ? JSON.parse(call.function.arguments) : {};
14460
+ renderMeta = spec?.render?.(argsParsed);
14267
14461
  } catch {
14268
14462
  }
14463
+ toolBatchRef.current.push({ name: call.function.name, args: argsParsed });
14464
+ if (toolBatchTimerRef.current) clearTimeout(toolBatchTimerRef.current);
14465
+ toolBatchTimerRef.current = setTimeout(flushToolBatch, 120);
14466
+ if (modeRef.current === "plan") return;
14269
14467
  setEvents((e) => [
14270
14468
  ...e,
14271
14469
  {
@@ -14393,26 +14591,28 @@ function App({
14393
14591
  permResolveRef.current = null;
14394
14592
  limitResolveRef.current = null;
14395
14593
  pendingToolCallsRef.current.clear();
14594
+ tasksRef.current = [];
14595
+ setTasks([]);
14596
+ setTasksStartedAt(null);
14597
+ setTasksStartTokens(0);
14598
+ setEvents(
14599
+ (evts) => evts.map((e) => e.kind === "tool" && e.status === "running" ? { ...e, status: "error", result: "(interrupted)" } : e)
14600
+ );
14396
14601
  }
14397
- }, [cfg, busy, updateAssistant, updateTool, updateGatewayMeta]);
14602
+ }, [cfg, busy, updateAssistant, updateTool, updateGatewayMeta, flushToolBatch]);
14398
14603
  const handleThemePick = useCallback2(
14399
14604
  (picked) => {
14400
14605
  setShowThemePicker(false);
14401
- setOriginalTheme(null);
14402
- if (!picked) {
14403
- if (originalTheme) setTheme(originalTheme);
14404
- return;
14405
- }
14406
- setTheme(picked);
14606
+ if (!picked) return;
14407
14607
  setCfg((c) => c ? { ...c, theme: picked.name } : c);
14408
14608
  if (cfg) void saveConfig({ ...cfg, theme: picked.name }).catch(() => {
14409
14609
  });
14410
14610
  setEvents((e) => [
14411
14611
  ...e,
14412
- { kind: "info", key: mkKey(), text: `theme: ${picked.label}` }
14612
+ { kind: "info", key: mkKey(), text: `theme: ${picked.label} \u2014 restart to apply` }
14413
14613
  ]);
14414
14614
  },
14415
- [cfg, originalTheme]
14615
+ [cfg]
14416
14616
  );
14417
14617
  const handleResumePick = useCallback2(
14418
14618
  async (picked) => {
@@ -14725,7 +14925,6 @@ use: /thinking low | medium | high`
14725
14925
  }
14726
14926
  if (c === "/theme") {
14727
14927
  if (!arg) {
14728
- setOriginalTheme(theme);
14729
14928
  setShowThemePicker(true);
14730
14929
  return true;
14731
14930
  }
@@ -14737,13 +14936,12 @@ use: /thinking low | medium | high`
14737
14936
  ]);
14738
14937
  return true;
14739
14938
  }
14740
- setTheme(next);
14741
14939
  setCfg((c2) => c2 ? { ...c2, theme: next.name } : c2);
14742
14940
  if (cfg) void saveConfig({ ...cfg, theme: next.name }).catch(() => {
14743
14941
  });
14744
14942
  setEvents((e) => [
14745
14943
  ...e,
14746
- { kind: "info", key: mkKey(), text: `theme: ${next.label}` }
14944
+ { kind: "info", key: mkKey(), text: `theme: ${next.label} \u2014 restart to apply` }
14747
14945
  ]);
14748
14946
  return true;
14749
14947
  }
@@ -15321,6 +15519,10 @@ ${lines.join("\n")}` }]);
15321
15519
  const turnReasoningEffort = overrideEffort ?? effortForTier[classification.tier] ?? effortRef.current;
15322
15520
  const effectiveCodeMode = classification.tier === "heavy";
15323
15521
  setCodeMode(effectiveCodeMode);
15522
+ const triageActivity = narrativizeInfo("", { tier: classification.tier, codeMode: effectiveCodeMode });
15523
+ if (triageActivity) {
15524
+ setEvents((e) => [...e, { kind: "activity", key: mkKey(), text: triageActivity.text, feature: triageActivity.feature }]);
15525
+ }
15324
15526
  const controller = new AbortController();
15325
15527
  activeControllerRef.current = controller;
15326
15528
  const sharedCallbacks = {
@@ -15348,11 +15550,16 @@ ${lines.join("\n")}` }]);
15348
15550
  pendingToolCallsRef.current.set(call.id, call.function.name);
15349
15551
  const spec = executorRef.current.list().find((t) => t.name === call.function.name);
15350
15552
  let renderMeta;
15553
+ let argsParsed = {};
15351
15554
  try {
15352
- const args = call.function.arguments ? JSON.parse(call.function.arguments) : {};
15353
- renderMeta = spec?.render?.(args);
15555
+ argsParsed = call.function.arguments ? JSON.parse(call.function.arguments) : {};
15556
+ renderMeta = spec?.render?.(argsParsed);
15354
15557
  } catch {
15355
15558
  }
15559
+ toolBatchRef.current.push({ name: call.function.name, args: argsParsed });
15560
+ if (toolBatchTimerRef.current) clearTimeout(toolBatchTimerRef.current);
15561
+ toolBatchTimerRef.current = setTimeout(flushToolBatch, 120);
15562
+ if (modeRef.current === "plan") return;
15356
15563
  setEvents((e) => [
15357
15564
  ...e,
15358
15565
  {
@@ -15487,9 +15694,10 @@ ${lines.join("\n")}` }]);
15487
15694
  setEvents((e) => [
15488
15695
  ...e,
15489
15696
  {
15490
- kind: "info",
15697
+ kind: "activity",
15491
15698
  key: mkKey(),
15492
- text: `auto-compacted: ${result.metrics.estimatedTokensBefore} \u2192 ${result.metrics.estimatedTokensAfter} tokens (${result.metrics.archivedArtifacts} artifacts)`
15699
+ text: "Making room by summarizing older turns\u2026",
15700
+ feature: "compact"
15493
15701
  }
15494
15702
  ]);
15495
15703
  await saveSessionSafe();
@@ -15509,9 +15717,10 @@ ${lines.join("\n")}` }]);
15509
15717
  setEvents((e) => [
15510
15718
  ...e,
15511
15719
  {
15512
- kind: "info",
15720
+ kind: "activity",
15513
15721
  key: mkKey(),
15514
- text: `auto-compacted: ${result.replacedCount} messages summarized`
15722
+ text: "Making room by summarizing older turns\u2026",
15723
+ feature: "compact"
15515
15724
  }
15516
15725
  ]);
15517
15726
  await saveSessionSafe();
@@ -15546,9 +15755,10 @@ ${lines.join("\n")}` }]);
15546
15755
  setEvents((e) => [
15547
15756
  ...e,
15548
15757
  {
15549
- kind: "memory",
15758
+ kind: "activity",
15550
15759
  key: mkKey(),
15551
- text: `recalled ${results.length} memory${results.length === 1 ? "" : "ies"} after compaction`
15760
+ text: "Remembering what we learned before\u2026",
15761
+ feature: "memory"
15552
15762
  }
15553
15763
  ]);
15554
15764
  await saveSessionSafe();
@@ -15599,9 +15809,16 @@ ${lines.join("\n")}` }]);
15599
15809
  permResolveRef.current = null;
15600
15810
  limitResolveRef.current = null;
15601
15811
  pendingToolCallsRef.current.clear();
15812
+ tasksRef.current = [];
15813
+ setTasks([]);
15814
+ setTasksStartedAt(null);
15815
+ setTasksStartTokens(0);
15816
+ setEvents(
15817
+ (evts) => evts.map((e) => e.kind === "tool" && e.status === "running" ? { ...e, status: "error", result: "(interrupted)" } : e)
15818
+ );
15602
15819
  }
15603
15820
  },
15604
- [cfg, handleSlash, updateAssistant, updateTool, saveSessionSafe, updateGatewayMeta]
15821
+ [cfg, handleSlash, updateAssistant, updateTool, saveSessionSafe, updateGatewayMeta, flushToolBatch]
15605
15822
  );
15606
15823
  useEffect6(() => {
15607
15824
  if (!busy && queue.length > 0) {
@@ -15828,11 +16045,11 @@ ${lines.join("\n")}` }]);
15828
16045
  ) }) });
15829
16046
  }
15830
16047
  if (showThemePicker) {
15831
- return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsx23(Box21, { flexDirection: "column", children: /* @__PURE__ */ jsx23(ThemePicker, { themes: themeList(), onPick: handleThemePick, onPreview: (t) => setTheme(t) }) }) });
16048
+ return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsx23(Box21, { flexDirection: "column", children: /* @__PURE__ */ jsx23(ThemePicker, { themes: themeList(), onPick: handleThemePick }) }) });
15832
16049
  }
15833
16050
  const hasConversation = events.some((e) => e.kind === "user" || e.kind === "assistant");
15834
16051
  return /* @__PURE__ */ jsx23(ThemeProvider, { theme, children: /* @__PURE__ */ jsxs21(Box21, { flexDirection: "column", children: [
15835
- !hasConversation && events.length === 0 ? /* @__PURE__ */ jsx23(Welcome, { accountId: cfg.accountId }) : /* @__PURE__ */ jsx23(ChatView, { events, showReasoning, verbose }),
16052
+ !hasConversation && events.length === 0 ? /* @__PURE__ */ jsx23(Welcome, { accountId: cfg.accountId }) : /* @__PURE__ */ jsx23(ChatView, { events, showReasoning, verbose, suppressTools: mode === "plan" }),
15836
16053
  perm ? /* @__PURE__ */ jsx23(
15837
16054
  PermissionModal,
15838
16055
  {
@@ -15995,6 +16212,7 @@ var init_app = __esm({
15995
16212
  init_errors();
15996
16213
  init_chat();
15997
16214
  init_status();
16215
+ init_narrative();
15998
16216
  init_permission();
15999
16217
  init_limit_modal();
16000
16218
  init_resume_picker();
@@ -16037,7 +16255,7 @@ var init_app = __esm({
16037
16255
  init_slash_picker();
16038
16256
  init_fuzzy();
16039
16257
  MAX_GITIGNORE_SIZE = 1 * 1024 * 1024;
16040
- FEEDBACK_WORKER_URL = "https://kimiflare-feedback.sina-b35.workers.dev";
16258
+ FEEDBACK_WORKER_URL = "https://hello.kimiflare.com";
16041
16259
  CONTEXT_LIMIT = 262e3;
16042
16260
  AUTO_COMPACT_SUGGEST_PCT = 0.8;
16043
16261
  MAX_EVENTS = 500;