fluxflow-cli 1.12.2 → 1.12.4

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/ARCHITECTURE.md CHANGED
@@ -15,7 +15,7 @@ The core intelligence of Flux Flow resides in `src/utils/ai.js`. It does not rel
15
15
 
16
16
  The execution flow of a single user prompt follows this loop:
17
17
 
18
- 1. **Context Assembly**: The user's prompt is combined with the system instructions, temporary session context, persistent user memories, and the current chat history. If the history gets too large (e.g., >128k tokens) and compression is disabled, it is gracefully truncated.
18
+ 1. **Context Assembly**: The user's prompt is combined with the system instructions, temporary session context, persistent user memories, and the current chat history. If the history gets too large (e.g., >254k tokens) and compression is disabled, it is gracefully truncated.
19
19
  2. **Stream Processing**: The main loop initiates a streaming request to the Gemini API (`client.models.generateContentStream`). It yields chunks of text and status updates directly back to the React UI as they arrive.
20
20
  3. **Detection & Tool Execution**: Once the stream completes for a given turn, the entire response is scanned for tool calls using a custom regex and bracket-balancing parser (looking for `tool:functions.tool_name(args...)`).
21
21
  - If tools are found, the loop pauses.
package/dist/fluxflow.js CHANGED
@@ -961,7 +961,7 @@ ${mode === "Flux" ? `- FILE TOOLS (path = relative to CWD) -
961
961
  2. [tool:functions.ReadFolder(path="...")]. Detailed DIR stats
962
962
  3. [tool:functions.WriteFile(path="...", content="...")]. Creates/Overwrites. File Exist? -> update_file > write_file
963
963
  4. [tool:functions.PatchFile(path="...", content_to_replace="exact old content", content_to_add="new content")]. Surgical patching. Unsure content_to_replace? -> view_file >> guessing.
964
- 5. [tool:functions.WritePDF(path="...", content="...", orientation="...")]. MUST HAVE PROPER A4 PAGE BREAKS. HTML/CSS for premium layout (100vh/vw). No manual footers
964
+ 5. [tool:functions.WritePDF(path="...", content="...", orientation="...")]. **USE PROPER PROACTIVE A4 PAGE BREAKS**. HTML/CSS for PREMIUM layout (100vh/vw). No manual footers
965
965
  6. [tool:functions.WriteDoc(path="...", content="...")]. A4 Word doc. Proper margins and page breaks
966
966
  7. [tool:functions.Run(command="...")]. Runs a shell command. Destructive/Irreversible ops -> ask user
967
967
  8. [tool:functions.SearchKeyword(keyword="...")]. Global search. Finds definitions/logic without reading every file
@@ -3549,6 +3549,9 @@ ${originalTextProcessed.length > 1500 ? "... (truncated) ...\n\n" : ""}
3549
3549
  let attempts = 0;
3550
3550
  const MAX_JANITOR_RETRIES = 5;
3551
3551
  while (attempts <= MAX_JANITOR_RETRIES) {
3552
+ if (process.stdout.isTTY) {
3553
+ process.stdout.write(`\x1B]0;Retrying Memory (${attempts + 1})...\x07`);
3554
+ }
3552
3555
  try {
3553
3556
  if (!await checkQuota("background", settings)) {
3554
3557
  return;
@@ -3632,7 +3635,7 @@ ${originalTextProcessed.length > 1500 ? "... (truncated) ...\n\n" : ""}
3632
3635
  if (process.stdout.isTTY) {
3633
3636
  process.stdout.write(`\x1B]0;Memory Error\x07`);
3634
3637
  }
3635
- await new Promise((resolve) => setTimeout(resolve, 3e3));
3638
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
3636
3639
  const janitorErrDir = path14.join(LOGS_DIR, "janitor");
3637
3640
  if (!fs15.existsSync(janitorErrDir)) fs15.mkdirSync(janitorErrDir, { recursive: true });
3638
3641
  fs15.appendFileSync(path14.join(janitorErrDir, "error.log"), `ERROR [Attempt ${attempts}/${MAX_JANITOR_RETRIES + 1}] [${date}]: ${String(janitorErr)}
@@ -3891,6 +3894,7 @@ ${thinkingLevel != "Fast" ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS STRIC
3891
3894
  yield { type: "status", content: "Connecting..." };
3892
3895
  TERMINATION_SIGNAL = false;
3893
3896
  let fullAgentResponseChunks = [];
3897
+ let wasToolCalledInLastLoop = false;
3894
3898
  modifiedHistory.forEach((msg) => {
3895
3899
  if (msg.text && msg.role === "agent") {
3896
3900
  msg.text = msg.text.replace(/<(think|thought)>[\s\S]*?<\/(think|thought)>/gi, "").trim();
@@ -3929,6 +3933,7 @@ ${thinkingLevel != "Fast" ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS STRIC
3929
3933
  let lastToolFinishedAt = 0;
3930
3934
  let toolResults = [];
3931
3935
  let toolCallPointer = 0;
3936
+ let anyToolExecutedInThisTurn = false;
3932
3937
  let isThinkingLoop = false;
3933
3938
  let isStutteringLoop = false;
3934
3939
  let isGeneralLoop = false;
@@ -4041,7 +4046,8 @@ ${thinkingLevel != "Fast" ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS STRIC
4041
4046
  }
4042
4047
  const cleanText = dedupeBuffer.substring(overlapLen);
4043
4048
  if (cleanText) {
4044
- const dedupeClean = cleanText.replace(/^\s*<(think|thought)>[\s\S]*?<\/(think|thought)>\s*/gi, "").replace(/^\s*<(think|thought)>\s*/gi, "");
4049
+ const hasOpenThink = /<(think|thought)>(?:(?!<\/(?:think|thought)>)[\s\S])*$/i.test(accumulatedContext);
4050
+ const dedupeClean = hasOpenThink ? cleanText.replace(/^\s*<(think|thought)>\s*/gi, "") : cleanText.replace(/^\s*<(think|thought)>[\s\S]*?<\/(think|thought)>\s*/gi, "").replace(/^\s*<(think|thought)>\s*/gi, "");
4045
4051
  if (dedupeClean) {
4046
4052
  turnText += dedupeClean;
4047
4053
  yield { type: "text", content: dedupeClean };
@@ -4398,6 +4404,7 @@ ${boxBottom}` };
4398
4404
  }
4399
4405
  const aiContent = `[TOOL RESULT]: ${(result || "").toString().split(/\r?\n/).filter((line) => !line.includes("[UI_CONTEXT]")).join("\n")}`;
4400
4406
  toolResults.push({ role: "user", text: aiContent, binaryPart });
4407
+ anyToolExecutedInThisTurn = true;
4401
4408
  let uiContent = `[TOOL RESULT]: ${result || ""}`;
4402
4409
  if (normToolName === "view_file" || normToolName === "web_scrape") {
4403
4410
  uiContent = `[TOOL RESULT]: ${label} (Context Locked for UI Clarity)`;
@@ -4423,7 +4430,8 @@ ${boxBottom}` };
4423
4430
  }
4424
4431
  const cleanText = dedupeBuffer.substring(overlapLen);
4425
4432
  if (cleanText) {
4426
- const dedupeClean = cleanText.replace(/^\s*<(think|thought)>[\s\S]*?<\/(think|thought)>\s*/gi, "").replace(/^\s*<(think|thought)>\s*/gi, "");
4433
+ const hasOpenThink = /<(think|thought)>(?:(?!<\/(?:think|thought)>)[\s\S])*$/i.test(accumulatedContext);
4434
+ const dedupeClean = hasOpenThink ? cleanText.replace(/^\s*<(think|thought)>\s*/gi, "") : cleanText.replace(/^\s*<(think|thought)>[\s\S]*?<\/(think|thought)>\s*/gi, "").replace(/^\s*<(think|thought)>\s*/gi, "");
4427
4435
  if (dedupeClean) {
4428
4436
  turnText += dedupeClean;
4429
4437
  yield { type: "text", content: dedupeClean };
@@ -4461,7 +4469,8 @@ ${boxBottom}` };
4461
4469
  }
4462
4470
  const cleanText = dedupeBuffer.substring(overlapLen);
4463
4471
  if (cleanText) {
4464
- const dedupeClean = cleanText.replace(/^\s*<(think|thought)>[\s\S]*?<\/(think|thought)>\s*/gi, "").replace(/^\s*<(think|thought)>\s*/gi, "");
4472
+ const hasOpenThink = /<(think|thought)>(?:(?!<\/(?:think|thought)>)[\s\S])*$/i.test(accumulatedContext);
4473
+ const dedupeClean = hasOpenThink ? cleanText.replace(/^\s*<(think|thought)>\s*/gi, "") : cleanText.replace(/^\s*<(think|thought)>[\s\S]*?<\/(think|thought)>\s*/gi, "").replace(/^\s*<(think|thought)>\s*/gi, "");
4465
4474
  if (dedupeClean) {
4466
4475
  turnText += dedupeClean;
4467
4476
  }
@@ -4475,7 +4484,6 @@ ${boxBottom}` };
4475
4484
  const agentErrDir = path14.join(LOGS_DIR, "agent");
4476
4485
  if (!fs15.existsSync(agentErrDir)) fs15.mkdirSync(agentErrDir, { recursive: true });
4477
4486
  fs15.appendFileSync(path14.join(agentErrDir, "error.log"), `ERROR [${date}]: ${errLog}
4478
- DEBUG STATE: turnText='${turnText}', length=${turnText.trim().length}, inStreamRetryCount=${inStreamRetryCount}, retryCount=${retryCount}, isDedupeActive=${isDedupeActive}, dedupeBuffer='${dedupeBuffer}'
4479
4487
 
4480
4488
  ----------------------------------------------------------------------
4481
4489
 
@@ -4582,14 +4590,19 @@ ${timestamp}`;
4582
4590
  if (isActuallyFinished) break;
4583
4591
  const nextAgentMsg = cleanedTurnText.trim() || "*Working...*";
4584
4592
  modifiedHistory.push({ role: "agent", text: nextAgentMsg });
4585
- if (toolResults.length > 0) {
4593
+ if (toolResults.length > 0 || anyToolExecutedInThisTurn) {
4586
4594
  toolResults.forEach((tr) => modifiedHistory.push(tr));
4587
4595
  } else {
4588
- modifiedHistory.push({ role: "user", text: `[SYSTEM] ${isStutteringLoop && !isThinkingLoop ? `STUTTERING DETECTED by Internal System. Re-calibrate your response & proceed.` : `${isThinkingLoop ? " OVER-THINKING" : " LOOP"} DETECTED by Internal System${isThinkingLoop ? " for current EFFORT_LEVEL" : ""}. ${isThinkingLoop ? "If you have planned the task, prioritize the execution/output. " : "If you have finished your task use [turn: finish] else continue."}`}` });
4596
+ if (wasToolCalledInLastLoop) {
4597
+ modifiedHistory.push({ role: "user", text: `[SYSTEM] System executed the tool with no explicit result, continue with your task or use [turn: finish] if completed.` });
4598
+ } else {
4599
+ modifiedHistory.push({ role: "user", text: `[SYSTEM] ${isStutteringLoop && !isThinkingLoop ? `STUTTERING DETECTED by Internal System. Re-calibrate your response & proceed.` : `${isThinkingLoop ? " OVER-THINKING" : " LOOP"} DETECTED by Internal System${isThinkingLoop ? " for current EFFORT_LEVEL" : ""}. ${isThinkingLoop ? "If you have planned the task, prioritize the execution/output. " : "If you have finished your task use [turn: finish] else continue."}`}` });
4600
+ }
4589
4601
  isThinkingLoop = false;
4590
4602
  isStutteringLoop = false;
4591
4603
  isGeneralLoop = false;
4592
4604
  }
4605
+ wasToolCalledInLastLoop = toolCallPointer > 0 || anyToolExecutedInThisTurn;
4593
4606
  }
4594
4607
  yield { type: "status", content: null };
4595
4608
  };
@@ -5611,7 +5624,7 @@ ${hintText}`, color: "magenta" }];
5611
5624
  if (newMode === "Flow") {
5612
5625
  setThinkingLevel("Fast");
5613
5626
  } else if (newMode === "Flux") {
5614
- setThinkingLevel("Medium");
5627
+ setThinkingLevel("High");
5615
5628
  }
5616
5629
  const s2 = emojiSpace(2);
5617
5630
  setMessages((prev) => {
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "fluxflow-cli",
3
- "version": "1.12.2",
4
- "date": "2026-05-21",
3
+ "version": "1.12.4",
4
+ "date": "2026-05-22",
5
5
  "description": "A high-fidelity agentic terminal assistant for the Flux Era.",
6
6
  "keywords": [
7
7
  "ai",