fluxflow-cli 1.19.3 → 1.19.5

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/fluxflow.js +197 -38
  2. package/package.json +2 -2
package/dist/fluxflow.js CHANGED
@@ -1176,11 +1176,10 @@ var init_main_tools = __esm({
1176
1176
  Access to internal tools. MUST use the exact syntax on a new line: [tool:functions.ToolName(args)]
1177
1177
  MANDATORY TOOL POLICY:
1178
1178
  - **MAX 3 TOOL CALLS PER TURN. Next Turn, verify results, plan next**
1179
- ${mode === "" ? "- Prefer multiple search & replace on patch tool if same file/path\n" : ""}- Use contextually BEST tool, no brute force, no spamming
1179
+ ${mode === "Flux" ? "- USE multiple search & replace on patch tool if editing same file/path with many edits\n" : ""}- Use contextually BEST tool, no brute force, no spamming
1180
1180
  ${mode === "Flux" ? "- **File Tools >> Code in chat**\n" : ""}
1181
1181
  - COMMUNICATION TOOLS -
1182
- 1. [tool:functions.Ask(question="...", optionA="option::description", ...MAX 4)]. Ambiguity Resolution. Mandatory Triggers: Path Divergence, Security, Risk Mitigation. ask >> finish
1183
- Suggest best options; don't ask for preferences
1182
+ 1. [tool:functions.Ask(question="...", optionA="option::description", ...MAX 4)]. Ambiguity Resolution. Mandatory Triggers: Path Divergence, Security, Risk Mitigation. ask >> finish. Suggest best options; don't ask for preferences
1184
1183
 
1185
1184
  - WEB TOOLS -
1186
1185
  1. [tool:functions.WebSearch(query="...", limit=number)]. Limit 3-10. Proactive use for unknown topics
@@ -1204,7 +1203,7 @@ ${mode === "Flux" ? `- PROJECT TOOLS (path = relative to CWD) -
1204
1203
  - File structure: Real newlines for code formatting`.trim() : `
1205
1204
  - FILE TOOLS ARE NOT AVAILABLE IN FLOW (Tell user,\` /mode flux\` if needed)`.trim()}
1206
1205
 
1207
- - Results: Passed as [TOOL RESULT] (system priority)
1206
+ - Results: Passed as [TOOL RESULT]
1208
1207
  - MAX Tool call stack: STRICTLY 3 per turn`.trim();
1209
1208
  }
1210
1209
  });
@@ -2396,12 +2395,13 @@ var init_thinking_prompts = __esm({
2396
2395
 
2397
2396
  // src/utils/prompts.js
2398
2397
  import fs4 from "fs";
2399
- var getMemoryPrompt, getSystemInstruction, getJanitorInstruction;
2398
+ var cachedProjectContextBlock, getMemoryPrompt, getSystemInstruction, getJanitorInstruction;
2400
2399
  var init_prompts = __esm({
2401
2400
  async "src/utils/prompts.js"() {
2402
2401
  await init_main_tools();
2403
2402
  init_janitor_tools();
2404
2403
  init_thinking_prompts();
2404
+ cachedProjectContextBlock = null;
2405
2405
  getMemoryPrompt = (tempMemories = "", userMemories = "", isMemoryEnabled = true, isContext32k = false) => {
2406
2406
  if (!isMemoryEnabled) return "";
2407
2407
  const tempMemoriesStr = tempMemories?.length > 0 && !isContext32k ? `-- RECENT CONTEXT FROM OTHER CHATS (PRIORITY: DYNAMIC-LOW, FOCUS: Chat Context > Recent) --
@@ -2413,7 +2413,7 @@ ${userMemories}` : "";
2413
2413
  ${parts.join("\n\n")}
2414
2414
  ` : "";
2415
2415
  };
2416
- getSystemInstruction = (profile, thinkingLevel, mode, systemSettings, isMemoryEnabled = true) => {
2416
+ getSystemInstruction = (profile, thinkingLevel, mode, systemSettings, isMemoryEnabled = true, isFirstPrompt = false) => {
2417
2417
  let thinkingConfig = "";
2418
2418
  if (thinkingLevel !== "GEM") {
2419
2419
  let levelKey = thinkingLevel;
@@ -2451,12 +2451,15 @@ ${nicknameStr.length || userInstrStr.length ? "" : "\n"}` : "";
2451
2451
  { name: "design.md", desc: "UI/UX" },
2452
2452
  { name: "architecture.md", desc: "System Structure" }
2453
2453
  ];
2454
- const foundFiles = projectContextFiles.filter((f) => fs4.existsSync(f.name));
2455
- const projectContextBlock = mode === "Flux" && foundFiles.length > 0 ? `
2454
+ if (isFirstPrompt || cachedProjectContextBlock === null) {
2455
+ const foundFiles = projectContextFiles.filter((f) => fs4.existsSync(f.name));
2456
+ cachedProjectContextBlock = mode === "Flux" && foundFiles.length > 0 ? `
2456
2457
  -- PROJECT CONTEXT (Source of Truth) --
2457
2458
  ${foundFiles.map((f) => `- ${f.name}: ${f.desc}`).join("\n")}
2458
2459
  Check these first; These Files > Training Data. Safety rules apply
2459
2460
  ` : "";
2461
+ }
2462
+ const projectContextBlock = cachedProjectContextBlock;
2460
2463
  return `${nameStr}${nicknameStr}${userInstrStr}[SYSTEM]
2461
2464
  Identity: Flux Flow (by Kushal Roy Chowdhury). Conversational, Sassy${mode === "Flux" ? ", Respectful" : ", Friendly, Humorous, Sarcastic"}, CLI Agent
2462
2465
  Mode: ${mode}${thinkingLevel !== "Fast" ? " (Thinking Mode)" : ""}. ${mode === "Flux" ? "Logical, Highly Detailed, Task-Driven. Prioritizes scalable file/folder structures, modular architecture, clean code abstractions, step-by-step execution. Industry standard latest coding practices/libraries, clean code, Double Check Imports, Client-Server Sync" : "Concise"}
@@ -2465,6 +2468,10 @@ Mode: ${mode}${thinkingLevel !== "Fast" ? " (Thinking Mode)" : ""}. ${mode === "
2465
2468
  - **MANDATORY: MUST END WITH [turn: continue] to CONTINUE loop OR [turn: finish] to END loop**
2466
2469
  - Tool Called? No post tool chat until [turn: continue]
2467
2470
  - NEVER USE [turn: continue] [turn:finish] together
2471
+
2472
+ -- MARKERS --
2473
+ - TOOL SYSTEM: [TOOL RESULT] (system priority)
2474
+ - SYSTEM NOTIFICATION: [SYSTEM], [METADATA] in user turn
2468
2475
  ${thinkingLevel !== "GEM" ? `
2469
2476
  -- THINKING RULES --
2470
2477
  ${thinkingConfig}
@@ -2484,7 +2491,6 @@ ${projectContextBlock}
2484
2491
 
2485
2492
  -- FORMATTING --
2486
2493
  - GFM Supported
2487
- - Tables: Max 4 cols
2488
2494
  - NO LaTeX${mode === "Flux" ? "" : ". Kaomojis"}
2489
2495
  [/SYSTEM]`.trim();
2490
2496
  };
@@ -5465,6 +5471,8 @@ ${newMemoryListStr}
5465
5471
  const { profile, thinkingLevel, mode, janitorModel, chatId, systemSettings, sessionStats } = settings;
5466
5472
  const isMemoryEnabled = systemSettings?.memory !== false;
5467
5473
  const originalText = history[history.length - 1].text;
5474
+ const summariesFile = path16.join(SECRET_DIR, "chat-summaries.json");
5475
+ let wasCompressedInStream = false;
5468
5476
  const isFirstPrompt = history.filter((m) => m.role === "user").length === 1;
5469
5477
  const hasTitleSignal = originalText.includes("[TITLE-UPDATE]");
5470
5478
  const needTitle = isFirstPrompt || hasTitleSignal;
@@ -5473,6 +5481,111 @@ ${newMemoryListStr}
5473
5481
  await RevertManager.startTransaction(chatId, agentText);
5474
5482
  try {
5475
5483
  let modifiedHistory = [...history.slice(0, -1)];
5484
+ if (systemSettings?.compression === 0 && (sessionStats?.tokens || 0) > 244e3) {
5485
+ yield { type: "status", content: "Condensing session context..." };
5486
+ const flattenContext = (hist) => {
5487
+ return hist.filter((m) => (m.role === "user" || m.role === "agent" || m.role === "system") && !String(m.id).startsWith("welcome") && !m.isMeta).map((m) => {
5488
+ const role = m.text?.startsWith("[TOOL RESULT]") ? "TOOL" : m.role === "agent" ? "AGENT" : "USER";
5489
+ return `[${role}]: ${m.text}`;
5490
+ }).join("\n\n");
5491
+ };
5492
+ const runCondenser = async (flattenedText2, oldSummary2) => {
5493
+ const systemInstruction = `You are an expert context condenser. Summarize the provided chat history (which may include previous summaries, user instructions, agent outputs, and tool results) into a detailed, coherent, and highly technical summary of 1000 to 1500 words. Focus on preserving the architectural decisions made, current system state, task progress, and critical code details. Under no circumstances exceed MAX 2000 words.`;
5494
+ const prompt = oldSummary2 ? `Here is the previous summary:
5495
+ ${oldSummary2}
5496
+
5497
+ Here is the new conversation history:
5498
+ ${flattenedText2}
5499
+
5500
+ Provide a new consolidated summary of the entire session.` : `Here is the conversation history:
5501
+ ${flattenedText2}
5502
+
5503
+ Provide a consolidated summary of the entire session.`;
5504
+ try {
5505
+ const response = await client.models.generateContent({
5506
+ model: "gemini-3.1-flash-lite",
5507
+ contents: prompt,
5508
+ config: {
5509
+ systemInstruction,
5510
+ maxOutputTokens: 4096,
5511
+ temperature: 0.3,
5512
+ safetySettings: [
5513
+ { category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_NONE },
5514
+ { category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_NONE },
5515
+ { category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, threshold: HarmBlockThreshold.BLOCK_NONE },
5516
+ { category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_NONE }
5517
+ ],
5518
+ thinkingConfig: { includeThoughts: false, thinkingLevel: ThinkingLevel.MEDIUM }
5519
+ }
5520
+ });
5521
+ return response.text || "";
5522
+ } catch (err) {
5523
+ try {
5524
+ const response = await client.models.generateContent({
5525
+ model: "gemini-2.5-flash",
5526
+ contents: prompt,
5527
+ config: {
5528
+ systemInstruction,
5529
+ maxOutputTokens: 4096,
5530
+ temperature: 0.3,
5531
+ safetySettings: [
5532
+ { category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_NONE },
5533
+ { category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_NONE },
5534
+ { category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, threshold: HarmBlockThreshold.BLOCK_NONE },
5535
+ { category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_NONE }
5536
+ ],
5537
+ thinkingConfig: { includeThoughts: false, thinkingBudget: 8192 }
5538
+ }
5539
+ });
5540
+ return response.text || "";
5541
+ } catch (e) {
5542
+ try {
5543
+ const response = await client.models.generateContent({
5544
+ model: "gemini-2.5-flash-lite",
5545
+ contents: prompt,
5546
+ config: {
5547
+ systemInstruction,
5548
+ maxOutputTokens: 4096,
5549
+ temperature: 0.3,
5550
+ safetySettings: [
5551
+ { category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_NONE },
5552
+ { category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_NONE },
5553
+ { category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, threshold: HarmBlockThreshold.BLOCK_NONE },
5554
+ { category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_NONE }
5555
+ ],
5556
+ thinkingConfig: { includeThoughts: false, thinkingBudget: 8192 }
5557
+ }
5558
+ });
5559
+ return response.text || "";
5560
+ } catch (e2) {
5561
+ return "";
5562
+ }
5563
+ }
5564
+ }
5565
+ };
5566
+ const flattenedText = flattenContext(modifiedHistory);
5567
+ const summaries2 = readEncryptedJson(summariesFile, {});
5568
+ let chatData = summaries2[chatId] || { summary: "", historyLength: 0 };
5569
+ if (typeof chatData === "string") {
5570
+ chatData = { summary: chatData, historyLength: 0 };
5571
+ }
5572
+ const currentCleanLen2 = modifiedHistory.filter((m) => (m.role === "user" || m.role === "agent" || m.role === "system") && !String(m.id).startsWith("welcome") && !m.isMeta).length;
5573
+ if (chatData.historyLength && currentCleanLen2 < chatData.historyLength) {
5574
+ chatData.summary = "";
5575
+ chatData.historyLength = 0;
5576
+ summaries2[chatId] = chatData;
5577
+ writeEncryptedJson(summariesFile, summaries2);
5578
+ }
5579
+ const oldSummary = chatData.summary || "";
5580
+ const newSummary = await runCondenser(flattenedText, oldSummary);
5581
+ if (newSummary) {
5582
+ chatData.summary = newSummary;
5583
+ summaries2[chatId] = chatData;
5584
+ writeEncryptedJson(summariesFile, summaries2);
5585
+ modifiedHistory = [];
5586
+ wasCompressedInStream = true;
5587
+ }
5588
+ }
5476
5589
  if (systemSettings?.compression === 0 && (sessionStats?.tokens || 0) > 254e3) {
5477
5590
  modifiedHistory = getTruncatedHistory(modifiedHistory, 6);
5478
5591
  }
@@ -5733,13 +5846,33 @@ ${newMemoryListStr}
5733
5846
  const cwdMismatch = lastCwd ? lastCwd !== process.cwd() : false;
5734
5847
  chatPaths[chatId] = process.cwd();
5735
5848
  writeEncryptedJson(PATHS_FILE, chatPaths);
5849
+ const summaries = readEncryptedJson(summariesFile, {});
5850
+ let chatDataObj = summaries[chatId] || { summary: "", historyLength: 0 };
5851
+ if (typeof chatDataObj === "string") {
5852
+ chatDataObj = { summary: chatDataObj, historyLength: 0 };
5853
+ }
5854
+ const currentCleanLen = history.filter((m) => (m.role === "user" || m.role === "agent" || m.role === "system") && !String(m.id).startsWith("welcome") && !m.isMeta).length;
5855
+ if (chatDataObj.historyLength && currentCleanLen < chatDataObj.historyLength) {
5856
+ chatDataObj.summary = "";
5857
+ chatDataObj.historyLength = 0;
5858
+ summaries[chatId] = chatDataObj;
5859
+ writeEncryptedJson(summariesFile, summaries);
5860
+ }
5861
+ const currentSummary = typeof chatDataObj === "object" ? chatDataObj.summary || "" : chatDataObj || "";
5862
+ const summaryBlock = currentSummary ? `
5863
+
5864
+ --- CONTEXT SUMMARY OF PREVIOUS TURNS (PRIORITY: HIGH) ---
5865
+ ${currentSummary}
5866
+
5867
+ ` : "";
5736
5868
  let dirStructure = process.cwd() + "\n" + getDirTree(process.cwd(), dynamicMaxDepth);
5737
5869
  const firstUserMsg = `[SYSTEM METADATA (PRIORITY: DYNAMIC), Chat Context >> Metadata] Time: ${dateTimeStr} | v${versionFluxflow2}
5738
- CWD: ${process.cwd()}${cwdMismatch ? ` (CWD Mismatch! Previous Path: ${lastCwd})` : ""}
5870
+ CWD: ${process.cwd()}${cwdMismatch ? ` (WARNING: CWD Mismatch! Previous Path: ${lastCwd})` : ""}
5739
5871
  **DIRECTORY STRUCTURE**
5740
5872
  ${dirStructure}
5873
+ ${summaryBlock}
5741
5874
  ${memoryPrompt}
5742
- ${thinkingLevel != "Fast" ? `${modelName.toLowerCase().startsWith("gemma") ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS CRITICAL PRIORITY. DO NOT START A RESPONSE WITHOUT <think> ... </think**\n" : ""}` : ""}[USER] ${agentText.replace(/\s*\[Prompted on:.*?\]/g, "").trim()}`.trim();
5875
+ ${thinkingLevel != "Fast" ? `${modelName.toLowerCase().startsWith("gemma") ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS CRITICAL PRIORITY. DO NOT START A RESPONSE WITHOUT <think> ... </think>**\n" : ""}` : ""}[USER] ${agentText.replace(/\s*\[Prompted on:.*?\]/g, "").trim()}`.trim();
5743
5876
  modifiedHistory.push({ role: "user", text: firstUserMsg });
5744
5877
  let lastUsage = null;
5745
5878
  const MAX_LOOPS = mode === "Flux" ? 70 : 7;
@@ -5770,7 +5903,7 @@ ${thinkingLevel != "Fast" ? `${modelName.toLowerCase().startsWith("gemma") ? "[S
5770
5903
 
5771
5904
  [STEERING HINT]: ${hint}`;
5772
5905
  } else {
5773
- modifiedHistory.push({ role: "user", text: `${thinkingLevel != "Fast" ? `${modelName.toLowerCase().startsWith("gemma") ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS CRITICAL PRIORITY. DO NOT START A RESPONSE WITHOUT <think> ... </think**\n" : ""}` : ""}[STEERING HINT]: ${hint}` });
5906
+ modifiedHistory.push({ role: "user", text: `${thinkingLevel != "Fast" ? `${modelName.toLowerCase().startsWith("gemma") ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS CRITICAL PRIORITY. DO NOT START A RESPONSE WITHOUT <think> ... </think>**\n" : ""}` : ""}[STEERING HINT]: ${hint}` });
5774
5907
  }
5775
5908
  yield { type: "status", content: "Steering Hint Injected." };
5776
5909
  }
@@ -5840,7 +5973,7 @@ ${thinkingLevel != "Fast" ? `${modelName.toLowerCase().startsWith("gemma") ? "[S
5840
5973
  } else if (retryCount > 0) {
5841
5974
  yield { type: "model_update", content: null };
5842
5975
  }
5843
- currentSystemInstruction = getSystemInstruction(profile, !(targetModel || "gemma").toLowerCase().startsWith("gemma") ? "GEM" : thinkingLevel, mode, systemSettings, isMemoryEnabled, MAX_LOOPS, loop + 1);
5976
+ currentSystemInstruction = getSystemInstruction(profile, !(targetModel || "gemma").toLowerCase().startsWith("gemma") ? "GEM" : thinkingLevel, mode, systemSettings, isMemoryEnabled, isFirstPrompt);
5844
5977
  const isGemma = modelName && modelName.toLowerCase().startsWith("gemma");
5845
5978
  const lastUserMsg = contents[contents.length - 1];
5846
5979
  if (isGemma) {
@@ -6500,11 +6633,11 @@ ${boxBottom}` };
6500
6633
  if (TERMINATION_SIGNAL) break;
6501
6634
  const signalSafeText2 = (turnText || "").trim();
6502
6635
  const hasFinish2 = /\[\s*(turn\s*:)?\s*finish\s*\]/i.test(signalSafeText2.toLowerCase());
6503
- const hasContinue = /\[\s*(turn\s*:)?\s*continue\s*\]/i.test(signalSafeText2.toLowerCase());
6636
+ const hasContinue2 = /\[\s*(turn\s*:)?\s*continue\s*\]/i.test(signalSafeText2.toLowerCase());
6504
6637
  const didCallTool = toolResults.length > 0 || lastToolSniffed !== null;
6505
6638
  const pureOutputText = signalSafeText2.replace(/(?:<think>|\[think\])[\s\S]*?(?:<\/think>|\[\/think\])/gi, "").trim();
6506
6639
  const endsNormally = /[.!?}"'`’“”]$|```$/s.test(pureOutputText);
6507
- if (!hasFinish2 && !hasContinue && !didCallTool && signalSafeText2.length > 0 && !endsNormally && !isThinkingLoop && !isStutteringLoop && !isGeneralLoop) {
6640
+ if (!hasFinish2 && !hasContinue2 && !didCallTool && signalSafeText2.length > 0 && !endsNormally && !isThinkingLoop && !isStutteringLoop && !isGeneralLoop) {
6508
6641
  throw new Error("Silent stream cutoff (500): Model stream closed cleanly but cut off mid-sentence without signals.");
6509
6642
  }
6510
6643
  success = true;
@@ -6626,7 +6759,7 @@ Error Log can be found in ${path16.join(LOGS_DIR, "agent", "error.log")}`);
6626
6759
  if (lastUsage) {
6627
6760
  const total = lastUsage.totalTokenCount || 0;
6628
6761
  const cached = lastUsage.cachedContentTokenCount || 0;
6629
- const candidates = lastUsage.candidatesTokenCount || 0;
6762
+ const candidates = (lastUsage.candidatesTokenCount || 0) + (lastUsage.thoughtsTokenCount || 0);
6630
6763
  await addToUsage("tokens", total);
6631
6764
  if (cached > 0) {
6632
6765
  await addToUsage("cachedTokens", cached);
@@ -6644,10 +6777,11 @@ Error Log can be found in ${path16.join(LOGS_DIR, "agent", "error.log")}`);
6644
6777
  }
6645
6778
  const signalSafeText = getSanitizedText(turnText);
6646
6779
  const hasFinish = /\[\s*(turn\s*:)?\s*finish\s*\]/i.test(signalSafeText.toLowerCase());
6780
+ const hasContinue = /\[\s*(turn\s*:)?\s*continue\s*\]/i.test(signalSafeText.toLowerCase());
6647
6781
  const shouldContinue = toolCallPointer > 0;
6648
6782
  yield { type: "status", content: "Working..." };
6649
6783
  const cleanedTurnText = contextSafeReplace(turnText, /\[\s*(turn\s*:)?\s*(continue|finish)\s*\]/gi, "").trim();
6650
- let isActuallyFinished = hasFinish && !shouldContinue;
6784
+ let isActuallyFinished = hasFinish && !shouldContinue || !shouldContinue && !hasContinue;
6651
6785
  if (isActuallyFinished) {
6652
6786
  const fullAgentTextRaw = fullAgentResponseChunks.join("\n");
6653
6787
  const cleanedFullResponse = fullAgentTextRaw.replace(/(?:<think>|\[think\])[\s\S]*?(?:<\/think>|\[\/think\])/g, "").trim();
@@ -6660,21 +6794,37 @@ Error Log can be found in ${path16.join(LOGS_DIR, "agent", "error.log")}`);
6660
6794
  needTitle
6661
6795
  }
6662
6796
  };
6663
- const timestamp = `Responded on ${(/* @__PURE__ */ new Date()).toLocaleString()}`;
6664
- const finalWithTime = `${cleanedFullResponse}
6665
-
6666
- ${timestamp}`;
6667
6797
  if (modifiedHistory.length > 0 && modifiedHistory[modifiedHistory.length - 1].role === "agent") {
6668
- modifiedHistory[modifiedHistory.length - 1].text = finalWithTime;
6798
+ modifiedHistory[modifiedHistory.length - 1].text = cleanedFullResponse;
6669
6799
  } else {
6670
- modifiedHistory.push({ role: "agent", text: finalWithTime });
6800
+ modifiedHistory.push({ role: "agent", text: cleanedFullResponse });
6801
+ }
6802
+ try {
6803
+ const summaries2 = readEncryptedJson(summariesFile, {});
6804
+ let existing = summaries2[chatId] || { summary: "", historyLength: 0 };
6805
+ if (typeof existing === "string") {
6806
+ existing = { summary: existing, historyLength: 0 };
6807
+ }
6808
+ const cleanLen = modifiedHistory.filter((m) => (m.role === "user" || m.role === "agent" || m.role === "system") && !String(m.id).startsWith("welcome") && !m.isMeta).length;
6809
+ if (wasCompressedInStream) {
6810
+ existing.historyLength = (existing.historyLength || 0) + cleanLen;
6811
+ } else {
6812
+ existing.historyLength = cleanLen;
6813
+ }
6814
+ summaries2[chatId] = existing;
6815
+ writeEncryptedJson(summariesFile, summaries2);
6816
+ } catch (e) {
6671
6817
  }
6672
6818
  }
6673
6819
  if (isActuallyFinished) break;
6674
6820
  const nextAgentMsg = cleanedTurnText.trim() || "*Working...*";
6675
6821
  modifiedHistory.push({ role: "agent", text: nextAgentMsg });
6676
6822
  if (toolResults.length > 0 || anyToolExecutedInThisTurn) {
6677
- toolResults.forEach((tr) => modifiedHistory.push(tr));
6823
+ if (toolResults.length > 0) {
6824
+ const combinedText = toolResults.map((tr) => tr.text).join("\n\n");
6825
+ const binaryPart = toolResults.find((tr) => tr.binaryPart)?.binaryPart || null;
6826
+ modifiedHistory.push({ role: "user", text: combinedText, binaryPart });
6827
+ }
6678
6828
  } else {
6679
6829
  if (wasToolCalledInLastLoop) {
6680
6830
  modifiedHistory.push({ role: "user", text: `[SYSTEM] System failed to verify tool execution, Verify tool syntax, proper escaping and try again if failed` });
@@ -8523,12 +8673,30 @@ ${timestamp}` };
8523
8673
  let apiStart = Date.now();
8524
8674
  let isFirstPacket = true;
8525
8675
  try {
8526
- const cleanHistoryForAI = [...messages, userMessage].filter(
8676
+ const rawHistory = [...messages, userMessage].filter(
8527
8677
  (m) => m.role !== "think" && !m.isVisualFeedback && !String(m.id).startsWith("welcome")
8528
- ).map((m) => ({
8529
- ...m,
8530
- text: m.fullText || m.text
8531
- }));
8678
+ );
8679
+ const cleanHistoryForAI = [];
8680
+ rawHistory.forEach((m, idx) => {
8681
+ let text = m.fullText || m.text;
8682
+ if (m.role === "user" && idx < rawHistory.length - 1) {
8683
+ const userIndex = text.lastIndexOf("[USER]");
8684
+ if (userIndex !== -1) {
8685
+ text = text.substring(userIndex + 6).trim();
8686
+ }
8687
+ }
8688
+ if (m.role === "system" && text?.startsWith("[TOOL RESULT]")) {
8689
+ const prev = cleanHistoryForAI[cleanHistoryForAI.length - 1];
8690
+ if (prev && prev.role === "system" && prev.text?.startsWith("[TOOL RESULT]")) {
8691
+ prev.text += "\n\n" + text;
8692
+ return;
8693
+ }
8694
+ }
8695
+ cleanHistoryForAI.push({
8696
+ ...m,
8697
+ text
8698
+ });
8699
+ });
8532
8700
  const stream = getAIStream(
8533
8701
  activeModel,
8534
8702
  cleanHistoryForAI,
@@ -8708,15 +8876,6 @@ Selection: ${val}`,
8708
8876
  if (packet.type === "interactive_turn_finished") {
8709
8877
  setIsProcessing(false);
8710
8878
  hasFiredJanitor = true;
8711
- setMessages((prev) => {
8712
- const aiHistory = packet.data.history;
8713
- return prev.map((msg, idx) => {
8714
- if (aiHistory[idx]) {
8715
- return { ...msg, fullText: aiHistory[idx].text };
8716
- }
8717
- return msg;
8718
- });
8719
- });
8720
8879
  runJanitorTask(
8721
8880
  { profile: profileData, thinkingLevel, mode, janitorModel, chatId, systemSettings, sessionStats },
8722
8881
  packet.data.agentText,
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "1.19.3",
4
- "date": "2026-06-03",
3
+ "version": "1.19.5",
4
+ "date": "2026-06-04",
5
5
  "description": "A high-fidelity agentic terminal assistant for the Flux Era.",
6
6
  "keywords": [
7
7
  "ai",