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 +1 -1
- package/dist/fluxflow.js +22 -9
- package/package.json +2 -2
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., >
|
|
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="...")].
|
|
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,
|
|
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
|
|
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
|
|
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
|
|
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
|
-
|
|
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("
|
|
5627
|
+
setThinkingLevel("High");
|
|
5615
5628
|
}
|
|
5616
5629
|
const s2 = emojiSpace(2);
|
|
5617
5630
|
setMessages((prev) => {
|