fluxflow-cli 1.12.3 → 1.12.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.
- package/ARCHITECTURE.md +1 -1
- package/dist/fluxflow.js +32 -14
- 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
|
|
@@ -992,13 +992,20 @@ Your tool syntax is: '[tool:functions.ToolName(args...)]'
|
|
|
992
992
|
[tool:functions.Chat(title='<short creative title of FULL conversation in 3-5 words>')]. Consider full chat context to generate title NOT just latest message.
|
|
993
993
|
[tool:functions.Memory(action='temp', content='<summary of the user prompt & model responses ONLY FROM LATEST PROMPT UNDER 40 WORDS>. [Talked on: <date> <hour>]')]
|
|
994
994
|
|
|
995
|
-
${isMemoryEnabled ? `-- User-specific long-term memory (USE BASED ON CONVERSATION CONTEXT) --
|
|
995
|
+
${isMemoryEnabled ? `-- User-specific long-term/permanent memory (USE BASED ON CONVERSATION CONTEXT, PROACTIVE USAGE) --
|
|
996
996
|
- Add: [tool:functions.Memory(action='user', method='add', content='<string to add>. [Saved on: <date ONLY>]')]
|
|
997
997
|
- Delete: [tool:functions.Memory(action='user', method='delete', content='exact memory id')]
|
|
998
998
|
- Update: [tool:functions.Memory(action='user', method='update', content-new='string to update', content-old='exact memory id')]
|
|
999
999
|
|
|
1000
|
+
Explicit Triggers for permanent memory:
|
|
1001
|
+
- User explicitly asks to 'remember' something.
|
|
1002
|
+
- User mentions something important that should be remembered.
|
|
1003
|
+
- User provides information that could be useful for future reference.
|
|
1004
|
+
- User shares personal information or preferences.
|
|
1005
|
+
- User talks about a specific topic that should be remembered.
|
|
1006
|
+
|
|
1000
1007
|
Usage Rules:
|
|
1001
|
-
- Frequency for 'user' action:
|
|
1008
|
+
- Frequency for 'user' action: Based on explicit triggers.
|
|
1002
1009
|
- IF YOU WANT TO SAVE SOMETHING, BUT SIMILAR MEMORY ALREADY EXISTS, USE THE UPDATE METHOD NOT THE ADD METHOD` : ""}`.trim();
|
|
1003
1010
|
}
|
|
1004
1011
|
});
|
|
@@ -1087,8 +1094,8 @@ ${foundFiles.map((f) => `- ${f.name}: ${f.desc}`).join("\n")}
|
|
|
1087
1094
|
Check these first; these files > training data for project consistency. Safety rules apply` : "";
|
|
1088
1095
|
return `${nameStr}${nicknameStr}${userInstrStr}
|
|
1089
1096
|
[SYSTEM (OVERRIDES EVERYTHING)]
|
|
1090
|
-
Identity: Flux Flow (by Kushal Roy Chowdhury). Sassy, Friendly, CLI Agent. No flirting ${mode === "Flux" ? "" : ""}
|
|
1091
|
-
Mode: ${mode}${thinkingLevel !== "Fast" ? "(Thinking Mode)" : ""}. ${mode === "Flux" ? "Goal-oriented" : "Conversational & UX-focused"}
|
|
1097
|
+
Identity: Flux Flow (by Kushal Roy Chowdhury). Sassy, Friendly, Humorous, CLI Agent. No flirting ${mode === "Flux" ? "" : ""}
|
|
1098
|
+
Mode: ${mode}${thinkingLevel !== "Fast" ? "(Thinking Mode)" : ""}. ${mode === "Flux" ? "Goal-oriented, Logical" : "Conversational & UX-focused"}
|
|
1092
1099
|
CWD: ${cwdStr}.${isSystemDir ? " [PROTECTED: ASK BEFORE MODIFYING]" : ""} OS: ${osDetected}${osDetected === "Windows" && mode === "Flux" ? ". PS via CMD" : ""}
|
|
1093
1100
|
High Priority: [SYSTEM], [STEERING HINT]
|
|
1094
1101
|
|
|
@@ -3510,6 +3517,8 @@ var init_ai = __esm({
|
|
|
3510
3517
|
if (process.stdout.isTTY) {
|
|
3511
3518
|
process.stdout.write(`\x1B]0;Finalizing...\x07`);
|
|
3512
3519
|
}
|
|
3520
|
+
const USER_CONTEXT_LENGTH = 4 * (1024 * 2);
|
|
3521
|
+
const AGENT_CONTEXT_LENGTH = 4 * (1024 * 8);
|
|
3513
3522
|
const { onStatus, onMemoryUpdated, onBackgroundIncrement } = callbacks;
|
|
3514
3523
|
const { profile, thinkingLevel, mode, janitorModel, chatId, systemSettings, sessionStats } = settings;
|
|
3515
3524
|
const isMemoryEnabled = systemSettings?.memory !== false;
|
|
@@ -3517,7 +3526,7 @@ var init_ai = __esm({
|
|
|
3517
3526
|
const janitorUserMemories = persistentStorage.map((m) => `- [${m.id}]: ${m.memory}`).join("\n");
|
|
3518
3527
|
const janitorContents = history.slice(-12).filter((msg) => msg.text && !msg.text.includes("[TOOL RESULT]") && !msg.text.includes("OBSERVATION:")).map((msg) => {
|
|
3519
3528
|
let processedText = msg.text.replace(/\[tool:functions\..*?\]/g, "").replace(/<think>[\s\S]*?<\/think>/g, "").replace(/\[Prompted on:.*?\]/g, "").replace(/\[turn: continue\]/g, "").replace(/\[turn: finish\]/g, "").replace(/\[TOOL RESULTS\]/g, "").replace(/\[tool results\]/g, "").replace(/\r?\n\r?\n/g, "\n").replace(/\n\n/g, "\n").replace(/\\n\\n/g, "").trim();
|
|
3520
|
-
const limit = msg.role === "user" ?
|
|
3529
|
+
const limit = msg.role === "user" ? USER_CONTEXT_LENGTH : AGENT_CONTEXT_LENGTH;
|
|
3521
3530
|
let truncatedText = processedText.substring(0, limit);
|
|
3522
3531
|
if (processedText.length > limit) {
|
|
3523
3532
|
truncatedText += "\n... (truncated) ...";
|
|
@@ -3535,14 +3544,14 @@ var init_ai = __esm({
|
|
|
3535
3544
|
isMemoryEnabled,
|
|
3536
3545
|
true
|
|
3537
3546
|
);
|
|
3538
|
-
let agentRes = `${cleanedFullResponse.replace(/\[tool:functions\..*?\]/g, "").replace(/<think>.*<\/think>/g, "").replace(/\[Prompted on:.*?\]/g, "").replace(/\[turn: continue\]/g, "").replace(/\[turn: finish\]/g, "").replace(/\[TOOL RESULTS\]/g, "").replace(/\[tool results\]/g, "").substring(0,
|
|
3539
|
-
if (agentRes.length >
|
|
3547
|
+
let agentRes = `${cleanedFullResponse.replace(/\[tool:functions\..*?\]/g, "").replace(/<think>.*<\/think>/g, "").replace(/\[Prompted on:.*?\]/g, "").replace(/\[turn: continue\]/g, "").replace(/\[turn: finish\]/g, "").replace(/\[TOOL RESULTS\]/g, "").replace(/\[tool results\]/g, "").substring(0, AGENT_CONTEXT_LENGTH)}`;
|
|
3548
|
+
if (agentRes.length > AGENT_CONTEXT_LENGTH) {
|
|
3540
3549
|
agentRes += "\n... (truncated) ...";
|
|
3541
3550
|
}
|
|
3542
3551
|
let originalTextProcessed = agentText.replace(/\[Prompted on:.*?\]/g, "").trim();
|
|
3543
3552
|
agentRes = agentRes.replace(/\r?\n\r?\n/g, "\n").replace(/\n\n/g, "\n").replace(/\\n\\n/g, "").trim();
|
|
3544
|
-
let userPrompt = `[USER]: ${originalTextProcessed.substring(0,
|
|
3545
|
-
${originalTextProcessed.length >
|
|
3553
|
+
let userPrompt = `[USER]: ${originalTextProcessed.substring(0, USER_CONTEXT_LENGTH)}
|
|
3554
|
+
${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n" : ""}
|
|
3546
3555
|
[AGENT (current turn)]: ${agentRes}`;
|
|
3547
3556
|
janitorContents.push({ role: "user", parts: [{ text: userPrompt }] });
|
|
3548
3557
|
let finalSynthesis = "";
|
|
@@ -3894,6 +3903,7 @@ ${thinkingLevel != "Fast" ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS STRIC
|
|
|
3894
3903
|
yield { type: "status", content: "Connecting..." };
|
|
3895
3904
|
TERMINATION_SIGNAL = false;
|
|
3896
3905
|
let fullAgentResponseChunks = [];
|
|
3906
|
+
let wasToolCalledInLastLoop = false;
|
|
3897
3907
|
modifiedHistory.forEach((msg) => {
|
|
3898
3908
|
if (msg.text && msg.role === "agent") {
|
|
3899
3909
|
msg.text = msg.text.replace(/<(think|thought)>[\s\S]*?<\/(think|thought)>/gi, "").trim();
|
|
@@ -3932,6 +3942,7 @@ ${thinkingLevel != "Fast" ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS STRIC
|
|
|
3932
3942
|
let lastToolFinishedAt = 0;
|
|
3933
3943
|
let toolResults = [];
|
|
3934
3944
|
let toolCallPointer = 0;
|
|
3945
|
+
let anyToolExecutedInThisTurn = false;
|
|
3935
3946
|
let isThinkingLoop = false;
|
|
3936
3947
|
let isStutteringLoop = false;
|
|
3937
3948
|
let isGeneralLoop = false;
|
|
@@ -4402,6 +4413,7 @@ ${boxBottom}` };
|
|
|
4402
4413
|
}
|
|
4403
4414
|
const aiContent = `[TOOL RESULT]: ${(result || "").toString().split(/\r?\n/).filter((line) => !line.includes("[UI_CONTEXT]")).join("\n")}`;
|
|
4404
4415
|
toolResults.push({ role: "user", text: aiContent, binaryPart });
|
|
4416
|
+
anyToolExecutedInThisTurn = true;
|
|
4405
4417
|
let uiContent = `[TOOL RESULT]: ${result || ""}`;
|
|
4406
4418
|
if (normToolName === "view_file" || normToolName === "web_scrape") {
|
|
4407
4419
|
uiContent = `[TOOL RESULT]: ${label} (Context Locked for UI Clarity)`;
|
|
@@ -4587,14 +4599,19 @@ ${timestamp}`;
|
|
|
4587
4599
|
if (isActuallyFinished) break;
|
|
4588
4600
|
const nextAgentMsg = cleanedTurnText.trim() || "*Working...*";
|
|
4589
4601
|
modifiedHistory.push({ role: "agent", text: nextAgentMsg });
|
|
4590
|
-
if (toolResults.length > 0) {
|
|
4602
|
+
if (toolResults.length > 0 || anyToolExecutedInThisTurn) {
|
|
4591
4603
|
toolResults.forEach((tr) => modifiedHistory.push(tr));
|
|
4592
4604
|
} else {
|
|
4593
|
-
|
|
4605
|
+
if (wasToolCalledInLastLoop) {
|
|
4606
|
+
modifiedHistory.push({ role: "user", text: `[SYSTEM] System executed the tool with no explicit result, continue with your task or use [turn: finish] if completed.` });
|
|
4607
|
+
} else {
|
|
4608
|
+
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."}`}` });
|
|
4609
|
+
}
|
|
4594
4610
|
isThinkingLoop = false;
|
|
4595
4611
|
isStutteringLoop = false;
|
|
4596
4612
|
isGeneralLoop = false;
|
|
4597
4613
|
}
|
|
4614
|
+
wasToolCalledInLastLoop = toolCallPointer > 0 || anyToolExecutedInThisTurn;
|
|
4598
4615
|
}
|
|
4599
4616
|
yield { type: "status", content: null };
|
|
4600
4617
|
};
|
|
@@ -4729,7 +4746,8 @@ function MemoryModal({ onClose }) {
|
|
|
4729
4746
|
}
|
|
4730
4747
|
});
|
|
4731
4748
|
const cleanDisplay = (text) => {
|
|
4732
|
-
|
|
4749
|
+
if (!text) return "";
|
|
4750
|
+
return text.replace(/\[Saved on: .*?\]/g, "").replace(/\\+'/g, "'").trim();
|
|
4733
4751
|
};
|
|
4734
4752
|
const s = emojiSpace(2);
|
|
4735
4753
|
return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: 80 }, /* @__PURE__ */ React8.createElement(Box8, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React8.createElement(Text8, { color: "cyan", bold: true }, "\u{1F9E0} AGENT MEMORY: LONG-TERM KNOWLEDGE")), !isMemoryOn && memories.length > 0 ? /* @__PURE__ */ React8.createElement(Box8, { paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React8.createElement(Text8, { italic: true, color: "gray" }, "Memory is currently Off...")) : memories.length === 0 ? /* @__PURE__ */ React8.createElement(Box8, { paddingX: 2, paddingY: 1 }, /* @__PURE__ */ React8.createElement(Text8, { italic: true, color: "gray" }, isMemoryOn ? "Learning..." : "Memory not available...")) : /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column" }, memories.map((mem, idx) => {
|
|
@@ -5616,7 +5634,7 @@ ${hintText}`, color: "magenta" }];
|
|
|
5616
5634
|
if (newMode === "Flow") {
|
|
5617
5635
|
setThinkingLevel("Fast");
|
|
5618
5636
|
} else if (newMode === "Flux") {
|
|
5619
|
-
setThinkingLevel("
|
|
5637
|
+
setThinkingLevel("High");
|
|
5620
5638
|
}
|
|
5621
5639
|
const s2 = emojiSpace(2);
|
|
5622
5640
|
setMessages((prev) => {
|