fluxflow-cli 1.12.7 → 1.13.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/fluxflow.js +426 -41
- package/package.json +2 -2
package/dist/fluxflow.js
CHANGED
|
@@ -464,6 +464,7 @@ var init_ChatLayout = __esm({
|
|
|
464
464
|
{ cmd: "/clear", desc: "Clear terminal screen" },
|
|
465
465
|
{ cmd: "/resume", desc: "Load previous session" },
|
|
466
466
|
{ cmd: "/save", desc: "Force save current chat" },
|
|
467
|
+
{ cmd: "/export", desc: "Export current chat in a .txt file" },
|
|
467
468
|
{ cmd: "/chats", desc: "List all chat sessions" },
|
|
468
469
|
{ cmd: "/image", desc: "Generate images" },
|
|
469
470
|
{ cmd: "/mode", desc: "Toggle Flux/Flow modes" },
|
|
@@ -820,6 +821,7 @@ __export(paths_exports, {
|
|
|
820
821
|
MEMORIES_FILE: () => MEMORIES_FILE,
|
|
821
822
|
SECRET_DIR: () => SECRET_DIR,
|
|
822
823
|
SETTINGS_FILE: () => SETTINGS_FILE,
|
|
824
|
+
TEMP_MEM_CHAT_FILE: () => TEMP_MEM_CHAT_FILE,
|
|
823
825
|
TEMP_MEM_FILE: () => TEMP_MEM_FILE,
|
|
824
826
|
USAGE_FILE: () => USAGE_FILE
|
|
825
827
|
});
|
|
@@ -827,7 +829,7 @@ import os2 from "os";
|
|
|
827
829
|
import path2 from "path";
|
|
828
830
|
import fs2 from "fs";
|
|
829
831
|
import crypto2 from "crypto";
|
|
830
|
-
var FLUXFLOW_DIR, SETTINGS_FILE, externalDir, DATA_DIR, LOGS_DIR, SECRET_DIR, HISTORY_FILE, USAGE_FILE, MEMORIES_FILE, TEMP_MEM_FILE;
|
|
832
|
+
var FLUXFLOW_DIR, SETTINGS_FILE, externalDir, DATA_DIR, LOGS_DIR, SECRET_DIR, HISTORY_FILE, USAGE_FILE, MEMORIES_FILE, TEMP_MEM_FILE, TEMP_MEM_CHAT_FILE;
|
|
831
833
|
var init_paths = __esm({
|
|
832
834
|
"src/utils/paths.js"() {
|
|
833
835
|
FLUXFLOW_DIR = path2.join(os2.homedir(), ".fluxflow");
|
|
@@ -867,6 +869,7 @@ var init_paths = __esm({
|
|
|
867
869
|
USAGE_FILE = path2.join(FLUXFLOW_DIR, "usage.json");
|
|
868
870
|
MEMORIES_FILE = path2.join(SECRET_DIR, "memories.json");
|
|
869
871
|
TEMP_MEM_FILE = path2.join(SECRET_DIR, "memory-temp.json");
|
|
872
|
+
TEMP_MEM_CHAT_FILE = path2.join(SECRET_DIR, "temp-memory-chat.json");
|
|
870
873
|
}
|
|
871
874
|
});
|
|
872
875
|
|
|
@@ -975,7 +978,7 @@ ${mode === "Flux" ? `- FILE TOOLS (path = relative to CWD) -
|
|
|
975
978
|
- File structure: Real newlines for code formatting`.trim() : `
|
|
976
979
|
- DEV TOOLS ARE NOT AVAILABLE IN FLOW MODE`.trim()}
|
|
977
980
|
|
|
978
|
-
- Results: Passed as [TOOL RESULT]
|
|
981
|
+
- Results: Passed as [TOOL RESULT] (system)
|
|
979
982
|
- Tool calls: End with [turn: continue]. Only use [turn: finish] after verifying goals
|
|
980
983
|
- Multi-call: Stack upto 5`.trim();
|
|
981
984
|
}
|
|
@@ -990,13 +993,17 @@ Your tool syntax is: '[tool:functions.ToolName(args...)]'
|
|
|
990
993
|
|
|
991
994
|
-- CHAT MANAGEMENT TOOLS (MUST CALL THESE 2 TOOLS ALWAYS) --
|
|
992
995
|
[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
|
-
[tool:functions.Memory(action="temp", content="<summary of the user prompt & model responses ONLY FROM LATEST PROMPT UNDER 40 WORDS>. [Talked on: <date> <hour>]")]
|
|
996
|
+
[tool:functions.Memory(action="temp", content="<summary of the user prompt & model responses ONLY FROM LATEST PROMPT UNDER 40 WORDS>. [Talked on: <date> <hour>]")]. Time format: YYYY-MM-DD HH am/pm
|
|
994
997
|
|
|
995
998
|
${isMemoryEnabled ? `-- User-specific long-term/permanent memory (USE BASED ON CONVERSATION CONTEXT, DO NOT RE-SAVE MEMORY WHICH IS ALREADY SAVED) --
|
|
996
|
-
- Add: [tool:functions.Memory(action="user", method="add", content="<string to add>. [Saved on: <date ONLY>]")]
|
|
999
|
+
- Add: [tool:functions.Memory(action="user", method="add", content="<string to add>. [Saved on: <date ONLY>]", score=2)] (Set score=2 ONLY if the user explicitly asked to "remember" or "save" this information, else omit this parameter entirely to default to 0.5)
|
|
997
1000
|
- Delete: [tool:functions.Memory(action="user", method="delete", id="<memory id>")]
|
|
998
1001
|
- Update: [tool:functions.Memory(action="user", method="update", content-new="string to update", id="<memory id>")]
|
|
999
1002
|
|
|
1003
|
+
-- Memory Relevance Decay Tool --
|
|
1004
|
+
- Score Adjustment: [tool:functions.addMemScore(id="<memory id>")]
|
|
1005
|
+
You MUST call this tool when a specific saved memory in the '-- CURRENT SAVED USER MEMORIES --' list was highly relevant, referenced, or helpful in the agent's response or user prompt. You can stack multiple calls.
|
|
1006
|
+
|
|
1000
1007
|
Explicit Triggers for permanent memory:
|
|
1001
1008
|
- User explicitly asks to 'remember' something.
|
|
1002
1009
|
- User mentions something important that should be remembered.
|
|
@@ -1097,7 +1104,7 @@ Check these first; these files > training data for project consistency. Safety r
|
|
|
1097
1104
|
Identity: Flux Flow (by Kushal Roy Chowdhury). Sassy, Friendly, Humorous, CLI Agent. No flirting ${mode === "Flux" ? "" : ""}
|
|
1098
1105
|
Mode: ${mode}${thinkingLevel !== "Fast" ? "(Thinking Mode)" : ""}. ${mode === "Flux" ? "Goal-oriented, Logical" : "Conversational & UX-focused"}
|
|
1099
1106
|
CWD: ${cwdStr}.${isSystemDir ? " [PROTECTED: ASK BEFORE MODIFYING]" : ""} OS: ${osDetected}${osDetected === "Windows" && mode === "Flux" ? ". PS via CMD" : ""}
|
|
1100
|
-
High Priority: [SYSTEM], [STEERING HINT]
|
|
1107
|
+
High Priority: [SYSTEM], [STEERING HINT].
|
|
1101
1108
|
|
|
1102
1109
|
-- THINKING RULES --
|
|
1103
1110
|
${thinkingConfig}
|
|
@@ -1117,6 +1124,7 @@ ${projectContextBlock}
|
|
|
1117
1124
|
-- SECURITY RULES --
|
|
1118
1125
|
- EXTERNAL ACCESS: ${systemSettings.allowExternalAccess ? "ENABLED" : "RESTRICTED CWD only"}
|
|
1119
1126
|
- Sensitive files? Ask before Read
|
|
1127
|
+
[SYSTEM] >>> [USER]
|
|
1120
1128
|
|
|
1121
1129
|
-- FORMATTING --
|
|
1122
1130
|
- Clean, concise responses
|
|
@@ -1226,6 +1234,11 @@ var init_history = __esm({
|
|
|
1226
1234
|
delete temp[id];
|
|
1227
1235
|
writeEncryptedJson(TEMP_MEM_FILE, temp);
|
|
1228
1236
|
}
|
|
1237
|
+
const cache = readEncryptedJson(TEMP_MEM_CHAT_FILE, {});
|
|
1238
|
+
if (cache[id]) {
|
|
1239
|
+
delete cache[id];
|
|
1240
|
+
writeEncryptedJson(TEMP_MEM_CHAT_FILE, cache);
|
|
1241
|
+
}
|
|
1229
1242
|
return history;
|
|
1230
1243
|
});
|
|
1231
1244
|
};
|
|
@@ -2098,16 +2111,21 @@ ${cleanedHtml}${htmlContent.length > 3e4 ? "\n\n[TRUNCATED AT 30K CHARS]" : ""}`
|
|
|
2098
2111
|
});
|
|
2099
2112
|
|
|
2100
2113
|
// src/tools/memory.js
|
|
2101
|
-
var memory;
|
|
2114
|
+
var USER_MEMORY_SIZE, memory;
|
|
2102
2115
|
var init_memory = __esm({
|
|
2103
2116
|
"src/tools/memory.js"() {
|
|
2104
2117
|
init_crypto();
|
|
2105
2118
|
init_paths();
|
|
2119
|
+
USER_MEMORY_SIZE = 4 * (1024 * 2);
|
|
2106
2120
|
memory = async (rawArgs, context = {}) => {
|
|
2107
2121
|
const parseArg = (key) => {
|
|
2108
|
-
const
|
|
2109
|
-
const
|
|
2110
|
-
|
|
2122
|
+
const quotedRegex = new RegExp(`${key}\\s*[:=]\\s*(["'])(.*?)\\1(?=\\s*[,)]|\\s+\\w+\\s*[:=]|$)`, "s");
|
|
2123
|
+
const quotedMatch = rawArgs.match(quotedRegex);
|
|
2124
|
+
if (quotedMatch) return quotedMatch[2].trim();
|
|
2125
|
+
const unquotedRegex = new RegExp(`${key}\\s*[:=]\\s*([^,\\s)]+)`, "s");
|
|
2126
|
+
const unquotedMatch = rawArgs.match(unquotedRegex);
|
|
2127
|
+
if (unquotedMatch) return unquotedMatch[1].trim();
|
|
2128
|
+
return null;
|
|
2111
2129
|
};
|
|
2112
2130
|
const action = parseArg("action");
|
|
2113
2131
|
const method = parseArg("method");
|
|
@@ -2120,33 +2138,37 @@ var init_memory = __esm({
|
|
|
2120
2138
|
if (!content) return "ERROR: Missing 'content' for temp memory.";
|
|
2121
2139
|
const tempStorage = readEncryptedJson(TEMP_MEM_FILE, {});
|
|
2122
2140
|
if (!tempStorage[chatId]) tempStorage[chatId] = [];
|
|
2123
|
-
const MAX_CHARS = 1024 * 4;
|
|
2124
|
-
let currentTotalLength = tempStorage[chatId].reduce((acc, m) => acc + m.length, 0);
|
|
2125
|
-
while (tempStorage[chatId].length > 0 && currentTotalLength + content.length > MAX_CHARS) {
|
|
2126
|
-
const removed = tempStorage[chatId].shift();
|
|
2127
|
-
currentTotalLength -= removed.length;
|
|
2128
|
-
}
|
|
2129
2141
|
tempStorage[chatId].push(content);
|
|
2130
2142
|
writeEncryptedJson(TEMP_MEM_FILE, tempStorage);
|
|
2131
|
-
|
|
2143
|
+
const currentTotalLength = tempStorage[chatId].reduce((acc, m) => acc + m.length, 0);
|
|
2144
|
+
return `SUCCESS: Temporary context saved for session [${chatId}]. (Size: ${currentTotalLength} chars)`;
|
|
2132
2145
|
}
|
|
2133
2146
|
if (action === "user") {
|
|
2134
|
-
const memories = readEncryptedJson(MEMORIES_FILE, [])
|
|
2147
|
+
const memories = readEncryptedJson(MEMORIES_FILE, []).map((m) => {
|
|
2148
|
+
if (m.score === void 0) m.score = 0.5;
|
|
2149
|
+
return m;
|
|
2150
|
+
});
|
|
2135
2151
|
if (method === "add") {
|
|
2136
2152
|
if (!content) return "ERROR: Missing 'content' for memory addition.";
|
|
2137
2153
|
const now = /* @__PURE__ */ new Date();
|
|
2138
2154
|
const dateStr = `${now.getDate()}/${now.getMonth() + 1}/${now.getFullYear()}`;
|
|
2139
2155
|
const formattedContent = content.includes("[Saved on:") ? content : `${content.trim()} [Saved on: ${dateStr}]`;
|
|
2140
|
-
const MAX_CHARS =
|
|
2156
|
+
const MAX_CHARS = USER_MEMORY_SIZE;
|
|
2141
2157
|
let currentTotalLength = memories.reduce((acc, m) => acc + (m.memory?.length || 0), 0);
|
|
2142
2158
|
while (memories.length > 0 && currentTotalLength + formattedContent.length > MAX_CHARS) {
|
|
2143
2159
|
const removed = memories.shift();
|
|
2144
2160
|
currentTotalLength -= removed.memory?.length || 0;
|
|
2145
2161
|
}
|
|
2146
|
-
const
|
|
2162
|
+
const scoreArg = parseArg("score");
|
|
2163
|
+
const initialScore = scoreArg ? parseFloat(scoreArg) : 0.5;
|
|
2164
|
+
const newMemory = {
|
|
2165
|
+
id: `mem-${Date.now().toString(36)}`,
|
|
2166
|
+
memory: formattedContent,
|
|
2167
|
+
score: Math.min(2, isNaN(initialScore) ? 0.5 : initialScore)
|
|
2168
|
+
};
|
|
2147
2169
|
memories.push(newMemory);
|
|
2148
2170
|
writeEncryptedJson(MEMORIES_FILE, memories);
|
|
2149
|
-
return `SUCCESS: Memory added with ID [${newMemory.id}]. (Vault Size: ${currentTotalLength + formattedContent.length} chars)`;
|
|
2171
|
+
return `SUCCESS: Memory added with ID [${newMemory.id}] and score [${newMemory.score}]. (Vault Size: ${currentTotalLength + formattedContent.length} chars)`;
|
|
2150
2172
|
}
|
|
2151
2173
|
if (method === "update") {
|
|
2152
2174
|
const memId = id || contentOld;
|
|
@@ -3035,13 +3057,13 @@ var init_search_keyword = __esm({
|
|
|
3035
3057
|
let command = "";
|
|
3036
3058
|
if (isWindows) {
|
|
3037
3059
|
const excludePattern = excludes.join("|").replace(/\./g, "\\.");
|
|
3038
|
-
command = `powershell -Command "Get-ChildItem -Path . -Recurse -File | Where-Object { $_.FullName -notmatch '${excludePattern}' } | Select-String -Pattern '${keyword}' | Select-Object -First
|
|
3060
|
+
command = `powershell -Command "Get-ChildItem -Path . -Recurse -File | Where-Object { $_.FullName -notmatch '${excludePattern}' } | Select-String -Pattern '${keyword}' | Select-Object -First 150 | ForEach-Object { $rel = Resolve-Path $_.Path -Relative; '{0}:{1}:' -f $rel, $_.LineNumber }"`;
|
|
3039
3061
|
} else {
|
|
3040
3062
|
const excludeDirArgs = excludes.map((d) => `--exclude-dir="${d}"`).join(" ");
|
|
3041
|
-
command = `grep -rnI ${excludeDirArgs} "${keyword}" . | head -n
|
|
3063
|
+
command = `grep -rnI ${excludeDirArgs} "${keyword}" . | head -n 150`;
|
|
3042
3064
|
}
|
|
3043
3065
|
return new Promise((resolve) => {
|
|
3044
|
-
exec(command, { cwd: process.cwd(), maxBuffer:
|
|
3066
|
+
exec(command, { cwd: process.cwd(), maxBuffer: 15 * 1024 * 1024 }, (error, stdout, stderr) => {
|
|
3045
3067
|
if (error && error.code === 1 && !stdout) {
|
|
3046
3068
|
return resolve(`Found 0 matches for keyword: "${keyword}"`);
|
|
3047
3069
|
}
|
|
@@ -3054,8 +3076,8 @@ var init_search_keyword = __esm({
|
|
|
3054
3076
|
const lower = line.toLowerCase();
|
|
3055
3077
|
return !lower.includes("node_modules") && !lower.includes(".git") && !lower.includes("dist") && !lower.includes(".next") && !lower.includes(".gemini");
|
|
3056
3078
|
});
|
|
3057
|
-
if (filteredLines.length === 0) return resolve(`Found 0 matches for keyword: "${keyword}"
|
|
3058
|
-
const matches = filteredLines.slice(0,
|
|
3079
|
+
if (filteredLines.length === 0) return resolve(`Found 0 matches for keyword: "${keyword}"`);
|
|
3080
|
+
const matches = filteredLines.slice(0, 150).map((line) => {
|
|
3059
3081
|
const firstColon = line.indexOf(":");
|
|
3060
3082
|
const secondColon = line.indexOf(":", firstColon + 1);
|
|
3061
3083
|
if (firstColon === -1 || secondColon === -1) return null;
|
|
@@ -3067,8 +3089,8 @@ var init_search_keyword = __esm({
|
|
|
3067
3089
|
|
|
3068
3090
|
`;
|
|
3069
3091
|
output += matches.join("\n");
|
|
3070
|
-
if (filteredLines.length >
|
|
3071
|
-
output += "\n\n... (Truncated to first
|
|
3092
|
+
if (filteredLines.length > 150) {
|
|
3093
|
+
output += "\n\n... (Truncated to first 150 matches)";
|
|
3072
3094
|
}
|
|
3073
3095
|
resolve(output);
|
|
3074
3096
|
});
|
|
@@ -3409,6 +3431,89 @@ var init_generate_image = __esm({
|
|
|
3409
3431
|
}
|
|
3410
3432
|
});
|
|
3411
3433
|
|
|
3434
|
+
// src/tools/saveSummary.js
|
|
3435
|
+
var saveSummary;
|
|
3436
|
+
var init_saveSummary = __esm({
|
|
3437
|
+
"src/tools/saveSummary.js"() {
|
|
3438
|
+
init_crypto();
|
|
3439
|
+
init_paths();
|
|
3440
|
+
saveSummary = async (rawArgs, context = {}) => {
|
|
3441
|
+
const parseArg = (key) => {
|
|
3442
|
+
const regex = new RegExp(`${key}\\s*[:=]\\s*(["'])(.*?)\\1(?=\\s*[,)]|\\s+\\w+\\s*[:=]|$)`, "s");
|
|
3443
|
+
const match = rawArgs.match(regex);
|
|
3444
|
+
return match ? match[2].trim() : null;
|
|
3445
|
+
};
|
|
3446
|
+
const id = parseArg("id");
|
|
3447
|
+
const summary = parseArg("summary");
|
|
3448
|
+
if (!id || !summary) {
|
|
3449
|
+
return "ERROR: Missing 'id' or 'summary' for saveSummary tool.";
|
|
3450
|
+
}
|
|
3451
|
+
try {
|
|
3452
|
+
const tempStorage = readEncryptedJson(TEMP_MEM_FILE, {});
|
|
3453
|
+
const cacheStorage = readEncryptedJson(TEMP_MEM_CHAT_FILE, {});
|
|
3454
|
+
cacheStorage[id] = summary;
|
|
3455
|
+
delete tempStorage[id];
|
|
3456
|
+
writeEncryptedJson(TEMP_MEM_CHAT_FILE, cacheStorage);
|
|
3457
|
+
writeEncryptedJson(TEMP_MEM_FILE, tempStorage);
|
|
3458
|
+
return `SUCCESS: Saved summary and purged raw memories for chat [${id}].`;
|
|
3459
|
+
} catch (err) {
|
|
3460
|
+
return `ERROR: Failed to save summary for chat [${id}]: ${err.message}`;
|
|
3461
|
+
}
|
|
3462
|
+
};
|
|
3463
|
+
}
|
|
3464
|
+
});
|
|
3465
|
+
|
|
3466
|
+
// src/tools/addMemScore.js
|
|
3467
|
+
var addMemScore;
|
|
3468
|
+
var init_addMemScore = __esm({
|
|
3469
|
+
"src/tools/addMemScore.js"() {
|
|
3470
|
+
init_crypto();
|
|
3471
|
+
init_paths();
|
|
3472
|
+
addMemScore = async (rawArgs, context = {}) => {
|
|
3473
|
+
const parseArg = (key) => {
|
|
3474
|
+
const regex = new RegExp(`${key}\\s*[:=]\\s*(["'])(.*?)\\1(?=\\s*[,)]|\\s+\\w+\\s*[:=]|$)`, "s");
|
|
3475
|
+
const match = rawArgs.match(regex);
|
|
3476
|
+
return match ? match[2].trim() : null;
|
|
3477
|
+
};
|
|
3478
|
+
const id = parseArg("id");
|
|
3479
|
+
if (!id) {
|
|
3480
|
+
return "ERROR: Missing 'id' parameter for addMemScore tool.";
|
|
3481
|
+
}
|
|
3482
|
+
try {
|
|
3483
|
+
const memories = readEncryptedJson(MEMORIES_FILE, []);
|
|
3484
|
+
let found = false;
|
|
3485
|
+
const updatedMemories = [];
|
|
3486
|
+
for (const mem of memories) {
|
|
3487
|
+
if (mem.score === void 0) {
|
|
3488
|
+
mem.score = 0.5;
|
|
3489
|
+
}
|
|
3490
|
+
if (mem.id === id) {
|
|
3491
|
+
mem.score = Math.min(2, mem.score + 0.2);
|
|
3492
|
+
found = true;
|
|
3493
|
+
} else {
|
|
3494
|
+
mem.score *= 0.98;
|
|
3495
|
+
if (mem.score < 0.05) mem.score = 0;
|
|
3496
|
+
}
|
|
3497
|
+
mem.score = Math.round(mem.score * 1e5) / 1e5;
|
|
3498
|
+
if (mem.score > 0) {
|
|
3499
|
+
updatedMemories.push(mem);
|
|
3500
|
+
}
|
|
3501
|
+
}
|
|
3502
|
+
writeEncryptedJson(MEMORIES_FILE, updatedMemories);
|
|
3503
|
+
if (!found) {
|
|
3504
|
+
return `WARNING: Memory ID [${id}] not found. Other memories decayed by -0.01.`;
|
|
3505
|
+
}
|
|
3506
|
+
const activeTarget = updatedMemories.find((m) => m.id === id);
|
|
3507
|
+
const finalScoreStr = activeTarget ? activeTarget.score.toFixed(2) : "deleted (score <= 0)";
|
|
3508
|
+
const deletedCount = memories.length - updatedMemories.length;
|
|
3509
|
+
return `SUCCESS: Adjusted memory scores. Target [${id}] is now ${finalScoreStr}.${deletedCount > 0 ? ` Purged ${deletedCount} decayed memories.` : ""}`;
|
|
3510
|
+
} catch (err) {
|
|
3511
|
+
return `ERROR: Failed to adjust memory score for [${id}]: ${err.message}`;
|
|
3512
|
+
}
|
|
3513
|
+
};
|
|
3514
|
+
}
|
|
3515
|
+
});
|
|
3516
|
+
|
|
3412
3517
|
// src/utils/tools.js
|
|
3413
3518
|
var TOOL_MAP, dispatchTool;
|
|
3414
3519
|
var init_tools = __esm({
|
|
@@ -3427,6 +3532,8 @@ var init_tools = __esm({
|
|
|
3427
3532
|
init_write_docx();
|
|
3428
3533
|
init_search_keyword();
|
|
3429
3534
|
init_generate_image();
|
|
3535
|
+
init_saveSummary();
|
|
3536
|
+
init_addMemScore();
|
|
3430
3537
|
TOOL_MAP = {
|
|
3431
3538
|
web_search,
|
|
3432
3539
|
web_scrape,
|
|
@@ -3441,6 +3548,8 @@ var init_tools = __esm({
|
|
|
3441
3548
|
write_docx,
|
|
3442
3549
|
search_keyword,
|
|
3443
3550
|
generate_image,
|
|
3551
|
+
saveSummary,
|
|
3552
|
+
addMemScore,
|
|
3444
3553
|
ask: ask_user,
|
|
3445
3554
|
// PascalCase Normalizations for Token Efficiency
|
|
3446
3555
|
Ask: ask_user,
|
|
@@ -3456,7 +3565,14 @@ var init_tools = __esm({
|
|
|
3456
3565
|
SearchKeyword: search_keyword,
|
|
3457
3566
|
Memory: memory,
|
|
3458
3567
|
Chat: chat,
|
|
3459
|
-
GenerateImage: generate_image
|
|
3568
|
+
GenerateImage: generate_image,
|
|
3569
|
+
saveSumary: saveSummary,
|
|
3570
|
+
SaveSummary: saveSummary,
|
|
3571
|
+
SaveSumary: saveSummary,
|
|
3572
|
+
add_mem_score: addMemScore,
|
|
3573
|
+
AddMemScore: addMemScore,
|
|
3574
|
+
addMemoryScore: addMemScore,
|
|
3575
|
+
AddMemoryScore: addMemScore
|
|
3460
3576
|
};
|
|
3461
3577
|
dispatchTool = async (toolName, args, context = {}) => {
|
|
3462
3578
|
const tool = TOOL_MAP[toolName];
|
|
@@ -3476,7 +3592,7 @@ var init_tools = __esm({
|
|
|
3476
3592
|
import { GoogleGenAI, ThinkingLevel, HarmBlockThreshold, HarmCategory } from "@google/genai";
|
|
3477
3593
|
import path14 from "path";
|
|
3478
3594
|
import fs15 from "fs";
|
|
3479
|
-
var client, TERMINATION_SIGNAL, signalTermination, TOOL_LABELS2, getToolDetail, runJanitorTask, getActiveToolContext, getContextSafeText, contextSafeReplace, getSanitizedText, detectToolCalls, initAI, getAIStream;
|
|
3595
|
+
var client, TERMINATION_SIGNAL, signalTermination, TOOL_LABELS2, getToolDetail, runJanitorTask, getActiveToolContext, getContextSafeText, contextSafeReplace, getSanitizedText, detectToolCalls, initAI, consolidatePastMemories, getAIStream;
|
|
3480
3596
|
var init_ai = __esm({
|
|
3481
3597
|
"src/utils/ai.js"() {
|
|
3482
3598
|
init_prompts();
|
|
@@ -3585,8 +3701,8 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
|
|
|
3585
3701
|
contents: janitorContents,
|
|
3586
3702
|
config: {
|
|
3587
3703
|
systemInstruction: janitorPrompt,
|
|
3588
|
-
maxOutputTokens:
|
|
3589
|
-
temperature: 0.
|
|
3704
|
+
maxOutputTokens: 512,
|
|
3705
|
+
temperature: 0.3,
|
|
3590
3706
|
safetySettings: [
|
|
3591
3707
|
{ category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
3592
3708
|
{ category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
@@ -3630,14 +3746,19 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
|
|
|
3630
3746
|
await incrementUsage("background");
|
|
3631
3747
|
}
|
|
3632
3748
|
const janitorToolCalls = detectToolCalls(finalSynthesis);
|
|
3749
|
+
let scoreToolCalled = false;
|
|
3633
3750
|
for (const janitorToolCall of janitorToolCalls) {
|
|
3751
|
+
const toolName = janitorToolCall.toolName;
|
|
3752
|
+
if (["addMemScore", "add_mem_score", "AddMemScore", "addMemoryScore", "AddMemoryScore"].includes(toolName)) {
|
|
3753
|
+
scoreToolCalled = true;
|
|
3754
|
+
}
|
|
3634
3755
|
const toolContext = { chatId, sessionId: chatId, history };
|
|
3635
|
-
const result = await dispatchTool(
|
|
3756
|
+
const result = await dispatchTool(toolName, janitorToolCall.args, toolContext);
|
|
3636
3757
|
const date = (/* @__PURE__ */ new Date()).toLocaleString();
|
|
3637
3758
|
const janitorLogDir = path14.join(LOGS_DIR, "janitor");
|
|
3638
|
-
fs15.appendFileSync(path14.join(janitorLogDir, "debug.log"), `DEBUG [${date}]: RESULT [${
|
|
3759
|
+
fs15.appendFileSync(path14.join(janitorLogDir, "debug.log"), `DEBUG [${date}]: RESULT [${toolName}]: ${result}
|
|
3639
3760
|
`);
|
|
3640
|
-
if (
|
|
3761
|
+
if (toolName.toLowerCase() === "memory" && !janitorToolCall.args.includes("action='temp'")) {
|
|
3641
3762
|
if (onMemoryUpdated) onMemoryUpdated();
|
|
3642
3763
|
if (process.stdout.isTTY) {
|
|
3643
3764
|
process.stdout.write(`\x1B]0;Memory Updated\x07`);
|
|
@@ -3645,6 +3766,27 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
|
|
|
3645
3766
|
await new Promise((resolve) => setTimeout(resolve, 3e3));
|
|
3646
3767
|
}
|
|
3647
3768
|
}
|
|
3769
|
+
if (!scoreToolCalled) {
|
|
3770
|
+
try {
|
|
3771
|
+
const memories = readEncryptedJson(MEMORIES_FILE, []);
|
|
3772
|
+
if (memories.length > 0) {
|
|
3773
|
+
const updatedMemories = [];
|
|
3774
|
+
for (const mem of memories) {
|
|
3775
|
+
if (mem.score === void 0) {
|
|
3776
|
+
mem.score = 0.5;
|
|
3777
|
+
}
|
|
3778
|
+
mem.score *= 0.9995;
|
|
3779
|
+
if (mem.score < 0.05) mem.score = 0;
|
|
3780
|
+
mem.score = Math.round(mem.score * 1e5) / 1e5;
|
|
3781
|
+
if (mem.score > 0) {
|
|
3782
|
+
updatedMemories.push(mem);
|
|
3783
|
+
}
|
|
3784
|
+
}
|
|
3785
|
+
writeEncryptedJson(MEMORIES_FILE, updatedMemories);
|
|
3786
|
+
}
|
|
3787
|
+
} catch (decayErr) {
|
|
3788
|
+
}
|
|
3789
|
+
}
|
|
3648
3790
|
break;
|
|
3649
3791
|
} catch (janitorErr) {
|
|
3650
3792
|
attempts++;
|
|
@@ -3881,6 +4023,100 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
|
|
|
3881
4023
|
client = new GoogleGenAI({ apiKey });
|
|
3882
4024
|
return client;
|
|
3883
4025
|
};
|
|
4026
|
+
consolidatePastMemories = async (currentChatId, settings) => {
|
|
4027
|
+
try {
|
|
4028
|
+
const tempStorage = readEncryptedJson(TEMP_MEM_FILE, {});
|
|
4029
|
+
const totalMemoriesCount = Object.values(tempStorage).flat().length;
|
|
4030
|
+
if (totalMemoriesCount <= 15) return;
|
|
4031
|
+
const chatsToSummarize = Object.keys(tempStorage).filter((id) => {
|
|
4032
|
+
return id !== currentChatId && Array.isArray(tempStorage[id]) && tempStorage[id].length > 3;
|
|
4033
|
+
});
|
|
4034
|
+
if (chatsToSummarize.length === 0) return;
|
|
4035
|
+
let prompt = `You are a silent background process for the FluxFlow CLI Agent.
|
|
4036
|
+
Your task is to summarize or merge temporary context memories from one or more past conversation sessions.
|
|
4037
|
+
For each Chat ID provided, you must output a tool call to save the consolidated summary.
|
|
4038
|
+
|
|
4039
|
+
The tool call format MUST be:
|
|
4040
|
+
[tool:functions.saveSummary(id="<chat-id>", summary="<updated summary string, max 400 words>")]
|
|
4041
|
+
|
|
4042
|
+
Guidelines:
|
|
4043
|
+
- Create a single, updated, highly cohesive, and concise summary statement (max 400 words) for each Chat ID. It should contain WHAT user talked about, WHAT were the tasks, Temporal info, HOW/WHAT the model responded. DON'T REMOVE ANY KEY AND TURN BY TURN INFO DENSITY.
|
|
4044
|
+
- Focus on key goals, preferences, modified files, and technical decisions.
|
|
4045
|
+
- Under no circumstances write normal conversational text. Output ONLY the tool calls.
|
|
4046
|
+
- You can stack multiple tool calls for multiple chats.
|
|
4047
|
+
|
|
4048
|
+
Chats to process:
|
|
4049
|
+
|
|
4050
|
+
`;
|
|
4051
|
+
const cacheStorage = readEncryptedJson(TEMP_MEM_CHAT_FILE, {});
|
|
4052
|
+
for (const id of chatsToSummarize) {
|
|
4053
|
+
const rawMemories = tempStorage[id];
|
|
4054
|
+
const newMemoryListStr = rawMemories.map((m) => `- ${m}`).join("\n");
|
|
4055
|
+
const oldSummary = cacheStorage[id];
|
|
4056
|
+
prompt += `[Chat ID: ${id}]
|
|
4057
|
+
`;
|
|
4058
|
+
if (oldSummary) {
|
|
4059
|
+
prompt += `- Existing Summary: "${oldSummary}"
|
|
4060
|
+
`;
|
|
4061
|
+
prompt += `-- New Memories to integrate:
|
|
4062
|
+
${newMemoryListStr}
|
|
4063
|
+
|
|
4064
|
+
`;
|
|
4065
|
+
} else {
|
|
4066
|
+
prompt += `-- Individual Memories:
|
|
4067
|
+
${newMemoryListStr}
|
|
4068
|
+
|
|
4069
|
+
`;
|
|
4070
|
+
}
|
|
4071
|
+
}
|
|
4072
|
+
let attempts = 0;
|
|
4073
|
+
const maxAttempts = 3;
|
|
4074
|
+
let success = false;
|
|
4075
|
+
while (attempts < maxAttempts && !success) {
|
|
4076
|
+
attempts++;
|
|
4077
|
+
try {
|
|
4078
|
+
const response = await client.models.generateContent({
|
|
4079
|
+
model: "gemini-3.1-flash-lite",
|
|
4080
|
+
contents: prompt,
|
|
4081
|
+
config: {
|
|
4082
|
+
temperature: 0.3,
|
|
4083
|
+
safetySettings: [
|
|
4084
|
+
{ category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
4085
|
+
{ category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
4086
|
+
{ category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
4087
|
+
{ category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_NONE }
|
|
4088
|
+
],
|
|
4089
|
+
thinkingConfig: { includeThoughts: false, thinkingLevel: ThinkingLevel.LOW }
|
|
4090
|
+
}
|
|
4091
|
+
});
|
|
4092
|
+
const responseText = response.text || "";
|
|
4093
|
+
const janitorToolCalls = detectToolCalls(responseText);
|
|
4094
|
+
if (janitorToolCalls.length === 0) {
|
|
4095
|
+
throw new Error("No tool calls detected in synthesis response");
|
|
4096
|
+
}
|
|
4097
|
+
for (const janitorToolCall of janitorToolCalls) {
|
|
4098
|
+
const toolName = janitorToolCall.toolName;
|
|
4099
|
+
if (["saveSummary", "saveSumary", "SaveSummary", "SaveSumary"].includes(toolName)) {
|
|
4100
|
+
await dispatchTool(toolName, janitorToolCall.args, { chatId: currentChatId });
|
|
4101
|
+
}
|
|
4102
|
+
}
|
|
4103
|
+
success = true;
|
|
4104
|
+
} catch (err) {
|
|
4105
|
+
if (attempts >= maxAttempts) {
|
|
4106
|
+
throw new Error(`Failed after ${maxAttempts} attempts. Last error: ${err.message}`);
|
|
4107
|
+
}
|
|
4108
|
+
}
|
|
4109
|
+
}
|
|
4110
|
+
} catch (err) {
|
|
4111
|
+
const janitorLogDir = path14.join(LOGS_DIR, "janitor");
|
|
4112
|
+
if (!fs15.existsSync(janitorLogDir)) fs15.mkdirSync(janitorLogDir, { recursive: true });
|
|
4113
|
+
fs15.appendFileSync(
|
|
4114
|
+
path14.join(janitorLogDir, "error.log"),
|
|
4115
|
+
`[${(/* @__PURE__ */ new Date()).toLocaleString()}] Past memory batch consolidation error: ${err.message}
|
|
4116
|
+
`
|
|
4117
|
+
);
|
|
4118
|
+
}
|
|
4119
|
+
};
|
|
3884
4120
|
getAIStream = async function* (modelName, history, settings, steeringCallback, versionFluxflow2) {
|
|
3885
4121
|
if (!client) throw new Error("AI not initialized");
|
|
3886
4122
|
const { profile, thinkingLevel, mode, janitorModel, chatId, systemSettings, sessionStats } = settings;
|
|
@@ -3894,8 +4130,15 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
|
|
|
3894
4130
|
if (systemSettings?.compression === 0 && (sessionStats?.tokens || 0) > 254e3) {
|
|
3895
4131
|
modifiedHistory = getTruncatedHistory(modifiedHistory, 6);
|
|
3896
4132
|
}
|
|
4133
|
+
if (isFirstPrompt && isMemoryEnabled) {
|
|
4134
|
+
yield { type: "status", content: "Condensing past chat memories..." };
|
|
4135
|
+
await consolidatePastMemories(chatId, settings);
|
|
4136
|
+
}
|
|
3897
4137
|
const tempStorage = readEncryptedJson(TEMP_MEM_FILE, {});
|
|
3898
|
-
const
|
|
4138
|
+
const cacheStorage = readEncryptedJson(TEMP_MEM_CHAT_FILE, {});
|
|
4139
|
+
const otherRawMemories = Object.entries(tempStorage).filter(([id]) => id !== chatId).flatMap(([_, mems]) => mems);
|
|
4140
|
+
const cachedSummaries = Object.entries(cacheStorage).filter(([id]) => id !== chatId).slice(-20).map(([id, summary]) => `[Chat Summary]: ${summary}`);
|
|
4141
|
+
const otherMemories = [...cachedSummaries, ...otherRawMemories].map((mem) => `- ${mem}`).join("\n");
|
|
3899
4142
|
const persistentStorage = readEncryptedJson(MEMORIES_FILE, []);
|
|
3900
4143
|
const mainUserMemories = persistentStorage.map((m) => `- ${m.memory}`).join("\n");
|
|
3901
4144
|
const isContext32k = (sessionStats?.tokens || 0) >= 32e3;
|
|
@@ -3990,8 +4233,8 @@ ${thinkingLevel != "Fast" ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS STRIC
|
|
|
3990
4233
|
targetModel = "gemini-3-flash-preview";
|
|
3991
4234
|
yield { type: "model_update", content: "Trying with fallback model" };
|
|
3992
4235
|
} else if (retryCount === MAX_RETRIES) {
|
|
3993
|
-
targetModel = "gemini-3.
|
|
3994
|
-
yield { type: "model_update", content: "Trying with fallback model
|
|
4236
|
+
targetModel = "gemini-3.5-flash";
|
|
4237
|
+
yield { type: "model_update", content: "Trying with fallback model" };
|
|
3995
4238
|
} else if (retryCount > 12 && retryCount < MAX_RETRIES - 2 && settings.apiKey !== "custom") {
|
|
3996
4239
|
targetModel = "gemma-4-31b-it";
|
|
3997
4240
|
yield { type: "model_update", content: "Trying with fallback Gemma Model" };
|
|
@@ -4014,6 +4257,7 @@ ${thinkingLevel != "Fast" ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS STRIC
|
|
|
4014
4257
|
lastUserMsg.parts[0].text += `
|
|
4015
4258
|
[SYSTEM] WARNING, Turn Limit Impending: Step ${currentStep}/${MAX_LOOPS}. Wrap up quickly/prompt user to continue & use [turn:finish] quickly.`;
|
|
4016
4259
|
}
|
|
4260
|
+
fs15.writeFileSync("contents.txt", currentSystemInstruction + "\n\n" + firstUserMsg);
|
|
4017
4261
|
stream = await client.models.generateContentStream({
|
|
4018
4262
|
model: targetModel || "gemma-4-31b-it",
|
|
4019
4263
|
contents,
|
|
@@ -4757,8 +5001,19 @@ function MemoryModal({ onClose }) {
|
|
|
4757
5001
|
if (!text) return "";
|
|
4758
5002
|
return text.replace(/\[Saved on: .*?\]/g, "").replace(/\\+'/g, "'").trim();
|
|
4759
5003
|
};
|
|
5004
|
+
const totalCapacity = 4 * 1024 * 2;
|
|
5005
|
+
const currentLength = memories.reduce((acc, m) => acc + (m.memory?.length || 0), 0);
|
|
5006
|
+
const usagePercent = Math.min(100, Math.round(currentLength / totalCapacity * 100));
|
|
5007
|
+
const barWidth = 12;
|
|
5008
|
+
const filledCount = Math.round(usagePercent / 100 * barWidth);
|
|
5009
|
+
const barStr = "\u2588".repeat(filledCount) + "\u2591".repeat(Math.max(0, barWidth - filledCount));
|
|
5010
|
+
const getBarColor = () => {
|
|
5011
|
+
if (usagePercent < 50) return "green";
|
|
5012
|
+
if (usagePercent < 90) return "yellow";
|
|
5013
|
+
return "red";
|
|
5014
|
+
};
|
|
4760
5015
|
const s = emojiSpace(2);
|
|
4761
|
-
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) => {
|
|
5016
|
+
return /* @__PURE__ */ React8.createElement(Box8, { flexDirection: "column", borderStyle: "round", borderColor: "gray", padding: 0, width: 80 }, /* @__PURE__ */ React8.createElement(Box8, { paddingX: 1, marginBottom: 1, justifyContent: "space-between" }, /* @__PURE__ */ React8.createElement(Text8, { color: "cyan", bold: true }, "\u{1F9E0} AGENT MEMORY: LONG-TERM KNOWLEDGE"), /* @__PURE__ */ React8.createElement(Box8, null, /* @__PURE__ */ React8.createElement(Text8, { color: "gray" }, "Vault: "), /* @__PURE__ */ React8.createElement(Text8, { color: getBarColor() }, barStr), /* @__PURE__ */ React8.createElement(Text8, { color: "white", bold: true }, " ", usagePercent, "%"))), !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) => {
|
|
4762
5017
|
const isSelected = idx === selectedIndex;
|
|
4763
5018
|
return /* @__PURE__ */ React8.createElement(
|
|
4764
5019
|
Box8,
|
|
@@ -5454,6 +5709,7 @@ function App({ args = [] }) {
|
|
|
5454
5709
|
{ cmd: "/clear", desc: "Clear terminal screen" },
|
|
5455
5710
|
{ cmd: "/resume", desc: "Load previous session" },
|
|
5456
5711
|
{ cmd: "/save", desc: "Force save current chat" },
|
|
5712
|
+
{ cmd: "/export", desc: "Export current chat in a .txt file" },
|
|
5457
5713
|
{ cmd: "/chats", desc: "List all chat sessions" },
|
|
5458
5714
|
{
|
|
5459
5715
|
cmd: "/image",
|
|
@@ -5515,8 +5771,7 @@ function App({ args = [] }) {
|
|
|
5515
5771
|
{ cmd: "gemma-4-31b-it", desc: apiTier === "Free" ? "Standard Default (Free, Recommended)" : "Standard Default (Free, Recommended) - Use Free API Key to use this model " },
|
|
5516
5772
|
{ cmd: "gemini-3.1-pro-preview", desc: "Most Capable (Paid)" },
|
|
5517
5773
|
{ cmd: "gemini-3-flash-preview", desc: "Fast & Lightweight (Paid, Limited Free quota)" },
|
|
5518
|
-
{ cmd: "gemini-3.5-flash", desc: "New (Paid, Limited Free quota)" }
|
|
5519
|
-
{ cmd: "gemini-3.1-flash-lite", desc: "Ultra Fast (Paid, Decent Free quota)" }
|
|
5774
|
+
{ cmd: "gemini-3.5-flash", desc: "New (Paid, Limited Free quota)" }
|
|
5520
5775
|
]
|
|
5521
5776
|
},
|
|
5522
5777
|
{ cmd: "/settings", desc: "Configure system prefs" },
|
|
@@ -5868,6 +6123,71 @@ ${hintText}`, color: "magenta" }];
|
|
|
5868
6123
|
});
|
|
5869
6124
|
break;
|
|
5870
6125
|
}
|
|
6126
|
+
case "/export": {
|
|
6127
|
+
const exportFile = `export-fluxflow-${chatId}.txt`;
|
|
6128
|
+
const exportPath = path15.join(process.cwd(), exportFile);
|
|
6129
|
+
const exportLines = [];
|
|
6130
|
+
let insideAgentBlock = false;
|
|
6131
|
+
for (let i = 0; i < messages.length; i++) {
|
|
6132
|
+
const msg = messages[i];
|
|
6133
|
+
if (!msg) continue;
|
|
6134
|
+
if (msg.role === "system" || msg.isMeta || msg.isLogo || String(msg.id).startsWith("welcome")) {
|
|
6135
|
+
continue;
|
|
6136
|
+
}
|
|
6137
|
+
if (msg.role === "user") {
|
|
6138
|
+
let cleanUserText = msg.text || "";
|
|
6139
|
+
cleanUserText = cleanUserText.replace(/\s*\[Prompted on:.*?\]/g, "").trim();
|
|
6140
|
+
if (exportLines.length > 0) {
|
|
6141
|
+
exportLines.push("");
|
|
6142
|
+
}
|
|
6143
|
+
exportLines.push("[USER]");
|
|
6144
|
+
exportLines.push(cleanUserText);
|
|
6145
|
+
insideAgentBlock = false;
|
|
6146
|
+
} else if (msg.role === "think") {
|
|
6147
|
+
if (!insideAgentBlock) {
|
|
6148
|
+
exportLines.push("");
|
|
6149
|
+
exportLines.push("[AGENT]");
|
|
6150
|
+
insideAgentBlock = true;
|
|
6151
|
+
}
|
|
6152
|
+
const cleanThinkText = (msg.text || "").replace(/\[turn:\s*continue\]/gi, "").replace(/\[turn:\s*finish\]/gi, "").replace(/\[TOOL RESULTS\]/gi, "").trim();
|
|
6153
|
+
if (cleanThinkText) {
|
|
6154
|
+
exportLines.push("[thoughts]");
|
|
6155
|
+
exportLines.push(cleanThinkText);
|
|
6156
|
+
}
|
|
6157
|
+
} else if (msg.role === "agent") {
|
|
6158
|
+
if (!insideAgentBlock) {
|
|
6159
|
+
exportLines.push("");
|
|
6160
|
+
exportLines.push("[AGENT]");
|
|
6161
|
+
insideAgentBlock = true;
|
|
6162
|
+
}
|
|
6163
|
+
const blocks = parseAgentText(msg.text || "");
|
|
6164
|
+
for (const block of blocks) {
|
|
6165
|
+
if (block.type === "output") {
|
|
6166
|
+
const cleanContent = block.content.replace(/\[turn:\s*continue\]/gi, "").replace(/\[turn:\s*finish\]/gi, "").replace(/\[TOOL RESULTS\]/gi, "").trim();
|
|
6167
|
+
if (cleanContent) {
|
|
6168
|
+
exportLines.push("[output]");
|
|
6169
|
+
exportLines.push(cleanContent);
|
|
6170
|
+
}
|
|
6171
|
+
} else if (block.type === "tool") {
|
|
6172
|
+
exportLines.push("[tool]");
|
|
6173
|
+
exportLines.push(`${block.toolName} ${block.args}`);
|
|
6174
|
+
}
|
|
6175
|
+
}
|
|
6176
|
+
}
|
|
6177
|
+
}
|
|
6178
|
+
const fileContent = exportLines.join("\n");
|
|
6179
|
+
fs17.writeFileSync(exportPath, fileContent, "utf8");
|
|
6180
|
+
setMessages((prev) => {
|
|
6181
|
+
setCompletedIndex(prev.length + 1);
|
|
6182
|
+
return [...prev, {
|
|
6183
|
+
id: Date.now(),
|
|
6184
|
+
role: "system",
|
|
6185
|
+
text: `\u{1F4E4} [EXPORT] Chat exported successfully to "${exportFile}"`,
|
|
6186
|
+
isMeta: true
|
|
6187
|
+
}];
|
|
6188
|
+
});
|
|
6189
|
+
break;
|
|
6190
|
+
}
|
|
5871
6191
|
case "/chats": {
|
|
5872
6192
|
const run = async () => {
|
|
5873
6193
|
const history = await loadHistory();
|
|
@@ -6959,7 +7279,7 @@ Selection: ${val}`,
|
|
|
6959
7279
|
);
|
|
6960
7280
|
})()));
|
|
6961
7281
|
}
|
|
6962
|
-
var SESSION_START_TIME, CHANGELOG_URL, packageJsonPath, packageJson, versionFluxflow, updatedOn, ResolutionModal, FLUX_LOGO;
|
|
7282
|
+
var SESSION_START_TIME, CHANGELOG_URL, packageJsonPath, packageJson, versionFluxflow, updatedOn, ResolutionModal, FLUX_LOGO, parseAgentText;
|
|
6963
7283
|
var init_app = __esm({
|
|
6964
7284
|
"src/app.jsx"() {
|
|
6965
7285
|
init_ChatLayout();
|
|
@@ -7010,6 +7330,71 @@ var init_app = __esm({
|
|
|
7010
7330
|
\u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u2588\u2588\u2554\u255D \u2588\u2588\u2557 \u2588\u2588\u2551 \u2588\u2588\u2588\u2588\u2588\u2588\u2588\u2557\u255A\u2588\u2588\u2588\u2588\u2588\u2588\u2554\u255D\u255A\u2588\u2588\u2588\u2554\u2588\u2588\u2588\u2554\u255D
|
|
7011
7331
|
\u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u2550\u2550\u2550\u255D \u255A\u2550\u2550\u255D\u255A\u2550\u2550\u255D`
|
|
7012
7332
|
);
|
|
7333
|
+
parseAgentText = (text) => {
|
|
7334
|
+
const blocks = [];
|
|
7335
|
+
const toolRegex = /\[\s*tool:functions\.([a-z0-9_]+)\s*\(/gi;
|
|
7336
|
+
let lastIdx = 0;
|
|
7337
|
+
let match;
|
|
7338
|
+
while ((match = toolRegex.exec(text)) !== null) {
|
|
7339
|
+
const toolName = match[1];
|
|
7340
|
+
const startIdx = match.index + match[0].length - 1;
|
|
7341
|
+
let balance = 0;
|
|
7342
|
+
let inString = null;
|
|
7343
|
+
let isEscaped = false;
|
|
7344
|
+
let endIdx = -1;
|
|
7345
|
+
let closingParenIdx = -1;
|
|
7346
|
+
for (let i = startIdx; i < text.length; i++) {
|
|
7347
|
+
const char = text[i];
|
|
7348
|
+
if (!inString && (char === '"' || char === "'" || char === "`")) {
|
|
7349
|
+
inString = char;
|
|
7350
|
+
isEscaped = false;
|
|
7351
|
+
} else if (inString && char === inString && !isEscaped) {
|
|
7352
|
+
inString = null;
|
|
7353
|
+
}
|
|
7354
|
+
if (!inString) {
|
|
7355
|
+
if (char === "(") balance++;
|
|
7356
|
+
else if (char === ")") balance--;
|
|
7357
|
+
if (balance === 0) {
|
|
7358
|
+
closingParenIdx = i;
|
|
7359
|
+
let j = i + 1;
|
|
7360
|
+
while (j < text.length && /\s/.test(text[j])) j++;
|
|
7361
|
+
if (j < text.length && text[j] === "]") {
|
|
7362
|
+
endIdx = j;
|
|
7363
|
+
break;
|
|
7364
|
+
}
|
|
7365
|
+
}
|
|
7366
|
+
}
|
|
7367
|
+
if (char === "\\") {
|
|
7368
|
+
isEscaped = !isEscaped;
|
|
7369
|
+
} else {
|
|
7370
|
+
isEscaped = false;
|
|
7371
|
+
}
|
|
7372
|
+
}
|
|
7373
|
+
if (endIdx !== -1) {
|
|
7374
|
+
const beforeText = text.substring(lastIdx, match.index);
|
|
7375
|
+
if (beforeText.trim()) {
|
|
7376
|
+
blocks.push({ type: "output", content: beforeText });
|
|
7377
|
+
}
|
|
7378
|
+
const finalArgsText = text.substring(startIdx + 1, closingParenIdx);
|
|
7379
|
+
blocks.push({
|
|
7380
|
+
type: "tool",
|
|
7381
|
+
toolName: toolName.trim(),
|
|
7382
|
+
args: finalArgsText.trim()
|
|
7383
|
+
});
|
|
7384
|
+
lastIdx = endIdx + 1;
|
|
7385
|
+
toolRegex.lastIndex = lastIdx;
|
|
7386
|
+
} else {
|
|
7387
|
+
break;
|
|
7388
|
+
}
|
|
7389
|
+
}
|
|
7390
|
+
if (lastIdx < text.length) {
|
|
7391
|
+
const remainingText = text.substring(lastIdx);
|
|
7392
|
+
if (remainingText.trim()) {
|
|
7393
|
+
blocks.push({ type: "output", content: remainingText });
|
|
7394
|
+
}
|
|
7395
|
+
}
|
|
7396
|
+
return blocks;
|
|
7397
|
+
};
|
|
7013
7398
|
}
|
|
7014
7399
|
});
|
|
7015
7400
|
|