fluxflow-cli 1.20.0 → 1.21.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/README.md +4 -1
- package/dist/fluxflow.js +325 -126
- package/package.json +2 -2
package/README.md
CHANGED
|
@@ -27,7 +27,10 @@ npm install -g fluxflow-cli
|
|
|
27
27
|
fluxflow-cli
|
|
28
28
|
```
|
|
29
29
|
|
|
30
|
-
*The agent will prompt you for your
|
|
30
|
+
*The agent will prompt you for your API Key on the first run and store it securely in an encrypted vault.* Choose from multiple supported AI providers:
|
|
31
|
+
- **Google GenAI** (Gemini & Gemma models)
|
|
32
|
+
- **DeepSeek** (Native DeepSeek API)
|
|
33
|
+
- **OpenRouter** (Access to hundreds of models; *Experimental*)
|
|
31
34
|
|
|
32
35
|
---
|
|
33
36
|
|
package/dist/fluxflow.js
CHANGED
|
@@ -1176,7 +1176,7 @@ 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 === "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
|
|
1179
|
+
${mode === "Flux" ? "- USE multiple search & replace on patch tool if editing same file/path with many edits \u2190 **MANDATORY where possible**\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
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
|
|
@@ -1706,7 +1706,8 @@ function SettingsMenu({
|
|
|
1706
1706
|
setInputConfig,
|
|
1707
1707
|
saveSettings: saveSettings2,
|
|
1708
1708
|
quotas,
|
|
1709
|
-
setMessages
|
|
1709
|
+
setMessages,
|
|
1710
|
+
aiProvider
|
|
1710
1711
|
}) {
|
|
1711
1712
|
const [activeColumn, setActiveColumn] = useState3("categories");
|
|
1712
1713
|
const [selectedCategoryIndex, setSelectedCategoryIndex] = useState3(0);
|
|
@@ -1740,6 +1741,7 @@ function SettingsMenu({
|
|
|
1740
1741
|
];
|
|
1741
1742
|
case "other":
|
|
1742
1743
|
return [
|
|
1744
|
+
{ label: "Current Provider", value: "aiProvider", status: aiProvider },
|
|
1743
1745
|
{ label: "API Tier", value: "apiTier", status: apiTier }
|
|
1744
1746
|
];
|
|
1745
1747
|
default:
|
|
@@ -1948,7 +1950,7 @@ function SettingsMenu({
|
|
|
1948
1950
|
},
|
|
1949
1951
|
isSelected ? "\u276F " : " ",
|
|
1950
1952
|
item.label
|
|
1951
|
-
), !isCommandListItem && /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { color: "gray", dimColor: true }, dots), /* @__PURE__ */ React6.createElement(Text6, { color: getStatusColor(item), bold: true },
|
|
1953
|
+
), !isCommandListItem && /* @__PURE__ */ React6.createElement(React6.Fragment, null, /* @__PURE__ */ React6.createElement(Text6, { color: "gray", dimColor: true }, dots), /* @__PURE__ */ React6.createElement(Text6, { color: getStatusColor(item), bold: true }, item.value === "aiProvider" ? item.status : `[ ${item.status} ]`))), isCommandListItem && !isEditingThis && item.status !== "None" && /* @__PURE__ */ React6.createElement(Box6, { paddingX: 4, marginBottom: 1 }, /* @__PURE__ */ React6.createElement(Text6, { color: "gray", dimColor: true }, "\u21B3 ", item.status)), isEditingThis && /* @__PURE__ */ React6.createElement(Box6, { flexDirection: "column", marginLeft: 4, marginBottom: 1 }, /* @__PURE__ */ React6.createElement(Box6, { paddingX: 1, borderStyle: "single", borderColor: "cyan", flexDirection: "row" }, /* @__PURE__ */ React6.createElement(Text6, { color: "cyan", bold: true }, "> ", " "), /* @__PURE__ */ React6.createElement(
|
|
1952
1954
|
TextInput,
|
|
1953
1955
|
{
|
|
1954
1956
|
value: editValue,
|
|
@@ -2465,7 +2467,7 @@ Identity: Flux Flow (by Kushal Roy Chowdhury). Conversational, Sassy${mode === "
|
|
|
2465
2467
|
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"}
|
|
2466
2468
|
|
|
2467
2469
|
-- AGENT LOOP RULES (PRIORITY: HIGH) --
|
|
2468
|
-
- **MANDATORY: MUST END WITH [turn: continue] to CONTINUE loop OR [turn: finish] to END loop**
|
|
2470
|
+
- **MANDATORY: MUST END WITH [turn: continue] to CONTINUE loop OR [turn: finish] to END loop** \u2190 IMPORTANT EVERY RESPONSE
|
|
2469
2471
|
- Tool Called? No post tool chat until [turn: continue]
|
|
2470
2472
|
- NEVER USE [turn: continue] [turn:finish] together
|
|
2471
2473
|
|
|
@@ -2480,7 +2482,7 @@ CRITICAL THINKING POLICY
|
|
|
2480
2482
|
- ALWAYS use <think> ... </think> before responding, even with simple queries/greetings
|
|
2481
2483
|
- ${thinkingLevel === "Low" || thinkingLevel === "Medium" || thinkingLevel === "Fast" ? "C" : "Interrogate approaches adversarially, but c"}ommit once best solution is determined through analysis. Avoid spiraling after reaching decision point
|
|
2482
2484
|
` : ""}` : ""}` : ``}
|
|
2483
|
-
${TOOL_PROTOCOL(mode, osDetected, isMultiModal, aiProvider)}
|
|
2485
|
+
${TOOL_PROTOCOL(mode, osDetected, aiProvider.toLowerCase() === "deepseek" ? false : isMultiModal, aiProvider)}
|
|
2484
2486
|
${projectContextBlock}
|
|
2485
2487
|
-- MEMORY RULES --
|
|
2486
2488
|
- Memory: ${isMemoryEnabled ? "Subtly Personalize. Auto Saves" : "OFF. Decline Remembering Memories"}
|
|
@@ -4923,7 +4925,7 @@ var init_tools = __esm({
|
|
|
4923
4925
|
import { GoogleGenAI, ThinkingLevel, HarmBlockThreshold, HarmCategory } from "@google/genai";
|
|
4924
4926
|
import path16 from "path";
|
|
4925
4927
|
import fs17 from "fs";
|
|
4926
|
-
var client, TERMINATION_SIGNAL, stripAnsi2, fetchWithBackoff, getOpenRouterStream, signalTermination, TOOL_LABELS2, getToolDetail, runJanitorTask, getActiveToolContext, getContextSafeText, contextSafeReplace, getSanitizedText, detectToolCalls, initAI, consolidatePastMemories, getAIStream;
|
|
4928
|
+
var client, TERMINATION_SIGNAL, stripAnsi2, fetchWithBackoff, getDeepSeekStream, getOpenRouterStream, signalTermination, TOOL_LABELS2, getToolDetail, runJanitorTask, getActiveToolContext, getContextSafeText, contextSafeReplace, getSanitizedText, detectToolCalls, initAI, generateSimpleContent, consolidatePastMemories, getAIStream;
|
|
4927
4929
|
var init_ai = __esm({
|
|
4928
4930
|
async "src/utils/ai.js"() {
|
|
4929
4931
|
await init_prompts();
|
|
@@ -4954,6 +4956,136 @@ var init_ai = __esm({
|
|
|
4954
4956
|
}
|
|
4955
4957
|
return fetch(url, options);
|
|
4956
4958
|
};
|
|
4959
|
+
getDeepSeekStream = async function* (apiKey, model, contents, systemInstruction, thinkingLevel, mode, isMultiModal) {
|
|
4960
|
+
const messages = [];
|
|
4961
|
+
if (systemInstruction) {
|
|
4962
|
+
messages.push({ role: "system", content: systemInstruction });
|
|
4963
|
+
}
|
|
4964
|
+
for (const content of contents) {
|
|
4965
|
+
const role = content.role === "user" ? "user" : "assistant";
|
|
4966
|
+
const msgContent = [];
|
|
4967
|
+
if (Array.isArray(content.parts)) {
|
|
4968
|
+
for (const part of content.parts) {
|
|
4969
|
+
if (part.text) {
|
|
4970
|
+
msgContent.push({ type: "text", text: part.text });
|
|
4971
|
+
} else if (part.inlineData && isMultiModal) {
|
|
4972
|
+
const mimeType = part.inlineData.mimeType;
|
|
4973
|
+
const data = part.inlineData.data;
|
|
4974
|
+
const isImage = mimeType.startsWith("image/");
|
|
4975
|
+
if (isImage) {
|
|
4976
|
+
msgContent.push({
|
|
4977
|
+
type: "image_url",
|
|
4978
|
+
image_url: {
|
|
4979
|
+
url: `data:${mimeType};base64,${data}`
|
|
4980
|
+
}
|
|
4981
|
+
});
|
|
4982
|
+
}
|
|
4983
|
+
}
|
|
4984
|
+
}
|
|
4985
|
+
} else {
|
|
4986
|
+
const text = content.text || "";
|
|
4987
|
+
if (text) msgContent.push({ type: "text", text });
|
|
4988
|
+
}
|
|
4989
|
+
messages.push({
|
|
4990
|
+
role,
|
|
4991
|
+
content: msgContent.length === 1 && msgContent[0].type === "text" ? msgContent[0].text : msgContent
|
|
4992
|
+
});
|
|
4993
|
+
}
|
|
4994
|
+
const requestPayload = {
|
|
4995
|
+
model,
|
|
4996
|
+
messages,
|
|
4997
|
+
stream: true,
|
|
4998
|
+
stream_options: { include_usage: true },
|
|
4999
|
+
temperature: mode === "Flux" ? 1 : 1.4
|
|
5000
|
+
};
|
|
5001
|
+
if (thinkingLevel !== "Fast") {
|
|
5002
|
+
const reasoningEffortMap = {
|
|
5003
|
+
"Low": "high",
|
|
5004
|
+
"Medium": "high",
|
|
5005
|
+
"High": "high",
|
|
5006
|
+
"xHigh": "max"
|
|
5007
|
+
};
|
|
5008
|
+
requestPayload.reasoning_effort = reasoningEffortMap[thinkingLevel] || "high";
|
|
5009
|
+
requestPayload.extra_body = { thinking: { type: "enabled" } };
|
|
5010
|
+
} else {
|
|
5011
|
+
requestPayload.extra_body = { thinking: { type: "disabled" } };
|
|
5012
|
+
}
|
|
5013
|
+
const response = await fetchWithBackoff("https://api.deepseek.com/chat/completions", {
|
|
5014
|
+
method: "POST",
|
|
5015
|
+
headers: {
|
|
5016
|
+
"Authorization": `Bearer ${apiKey}`,
|
|
5017
|
+
"Content-Type": "application/json"
|
|
5018
|
+
},
|
|
5019
|
+
body: JSON.stringify(requestPayload)
|
|
5020
|
+
});
|
|
5021
|
+
if (!response.ok) {
|
|
5022
|
+
const errData = await response.json().catch(() => ({}));
|
|
5023
|
+
throw new Error(`DeepSeek Error (${response.status}): ${errData.error?.message || response.statusText}`);
|
|
5024
|
+
}
|
|
5025
|
+
const reader = response.body.getReader();
|
|
5026
|
+
const decoder = new TextDecoder();
|
|
5027
|
+
let buffer = "";
|
|
5028
|
+
let pendingParts = [];
|
|
5029
|
+
let latestUsageMetadata = null;
|
|
5030
|
+
let lastFlushTime = Date.now();
|
|
5031
|
+
let hasNewData = false;
|
|
5032
|
+
while (true) {
|
|
5033
|
+
const { done, value } = await reader.read();
|
|
5034
|
+
if (done) {
|
|
5035
|
+
if (hasNewData && (pendingParts.length > 0 || latestUsageMetadata)) {
|
|
5036
|
+
yield {
|
|
5037
|
+
candidates: pendingParts.length > 0 ? [{ content: { parts: pendingParts } }] : [],
|
|
5038
|
+
usageMetadata: latestUsageMetadata
|
|
5039
|
+
};
|
|
5040
|
+
}
|
|
5041
|
+
break;
|
|
5042
|
+
}
|
|
5043
|
+
buffer += decoder.decode(value, { stream: true });
|
|
5044
|
+
const lines = buffer.split("\n");
|
|
5045
|
+
buffer = lines.pop();
|
|
5046
|
+
for (const line of lines) {
|
|
5047
|
+
const cleanLine = line.trim();
|
|
5048
|
+
if (!cleanLine || !cleanLine.startsWith("data: ")) continue;
|
|
5049
|
+
if (cleanLine === "data: [DONE]") break;
|
|
5050
|
+
try {
|
|
5051
|
+
const json = JSON.parse(cleanLine.substring(6));
|
|
5052
|
+
const delta = json.choices?.[0]?.delta;
|
|
5053
|
+
const usage = json.usage;
|
|
5054
|
+
if (usage) {
|
|
5055
|
+
latestUsageMetadata = {
|
|
5056
|
+
totalTokenCount: usage.total_tokens || usage.prompt_tokens + usage.completion_tokens,
|
|
5057
|
+
promptTokenCount: usage.prompt_tokens || 0,
|
|
5058
|
+
candidatesTokenCount: usage.completion_tokens || 0,
|
|
5059
|
+
cachedContentTokenCount: usage.prompt_tokens_details?.cached_tokens || 0,
|
|
5060
|
+
thoughtsTokenCount: usage.completion_tokens_details?.reasoning_tokens || 0
|
|
5061
|
+
};
|
|
5062
|
+
hasNewData = true;
|
|
5063
|
+
}
|
|
5064
|
+
if (delta) {
|
|
5065
|
+
const thought = delta.reasoning_content || null;
|
|
5066
|
+
if (thought) {
|
|
5067
|
+
pendingParts.push({ text: thought, thought: true });
|
|
5068
|
+
hasNewData = true;
|
|
5069
|
+
}
|
|
5070
|
+
if (delta.content) {
|
|
5071
|
+
pendingParts.push({ text: delta.content });
|
|
5072
|
+
hasNewData = true;
|
|
5073
|
+
}
|
|
5074
|
+
}
|
|
5075
|
+
} catch (e) {
|
|
5076
|
+
}
|
|
5077
|
+
}
|
|
5078
|
+
if (Date.now() - lastFlushTime >= 350 && hasNewData) {
|
|
5079
|
+
yield {
|
|
5080
|
+
candidates: pendingParts.length > 0 ? [{ content: { parts: [...pendingParts] } }] : [],
|
|
5081
|
+
usageMetadata: latestUsageMetadata
|
|
5082
|
+
};
|
|
5083
|
+
pendingParts = [];
|
|
5084
|
+
lastFlushTime = Date.now();
|
|
5085
|
+
hasNewData = false;
|
|
5086
|
+
}
|
|
5087
|
+
}
|
|
5088
|
+
};
|
|
4957
5089
|
getOpenRouterStream = async function* (apiKey, model, contents, systemInstruction, thinkingLevel, mode, isMultiModal) {
|
|
4958
5090
|
const messages = [];
|
|
4959
5091
|
if (systemInstruction) {
|
|
@@ -5030,9 +5162,21 @@ var init_ai = __esm({
|
|
|
5030
5162
|
const reader = response.body.getReader();
|
|
5031
5163
|
const decoder = new TextDecoder();
|
|
5032
5164
|
let buffer = "";
|
|
5165
|
+
let pendingParts = [];
|
|
5166
|
+
let latestUsageMetadata = null;
|
|
5167
|
+
let lastFlushTime = Date.now();
|
|
5168
|
+
let hasNewData = false;
|
|
5033
5169
|
while (true) {
|
|
5034
5170
|
const { done, value } = await reader.read();
|
|
5035
|
-
if (done)
|
|
5171
|
+
if (done) {
|
|
5172
|
+
if (hasNewData && (pendingParts.length > 0 || latestUsageMetadata)) {
|
|
5173
|
+
yield {
|
|
5174
|
+
candidates: pendingParts.length > 0 ? [{ content: { parts: pendingParts } }] : [],
|
|
5175
|
+
usageMetadata: latestUsageMetadata
|
|
5176
|
+
};
|
|
5177
|
+
}
|
|
5178
|
+
break;
|
|
5179
|
+
}
|
|
5036
5180
|
buffer += decoder.decode(value, { stream: true });
|
|
5037
5181
|
const lines = buffer.split("\n");
|
|
5038
5182
|
buffer = lines.pop();
|
|
@@ -5044,36 +5188,39 @@ var init_ai = __esm({
|
|
|
5044
5188
|
const json = JSON.parse(cleanLine.substring(6));
|
|
5045
5189
|
const delta = json.choices?.[0]?.delta;
|
|
5046
5190
|
const usage = json.usage;
|
|
5047
|
-
let usageMetadata = null;
|
|
5048
5191
|
if (usage) {
|
|
5049
|
-
|
|
5192
|
+
latestUsageMetadata = {
|
|
5050
5193
|
totalTokenCount: usage.total_tokens || usage.prompt_tokens + usage.completion_tokens,
|
|
5051
5194
|
promptTokenCount: usage.prompt_tokens || 0,
|
|
5052
5195
|
candidatesTokenCount: usage.completion_tokens || 0,
|
|
5053
5196
|
cachedContentTokenCount: usage.prompt_tokens_details?.cached_tokens || 0,
|
|
5054
5197
|
thoughtsTokenCount: usage.completion_tokens_details?.reasoning_tokens || 0
|
|
5055
5198
|
};
|
|
5199
|
+
hasNewData = true;
|
|
5056
5200
|
}
|
|
5057
5201
|
if (delta) {
|
|
5058
5202
|
const thought = delta.reasoning || (delta.reasoning_details ? delta.reasoning_details.map((d) => d.text).join("") : null);
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
};
|
|
5203
|
+
if (thought) {
|
|
5204
|
+
pendingParts.push({ text: thought, thought: true });
|
|
5205
|
+
hasNewData = true;
|
|
5206
|
+
}
|
|
5207
|
+
if (delta.content) {
|
|
5208
|
+
pendingParts.push({ text: delta.content });
|
|
5209
|
+
hasNewData = true;
|
|
5067
5210
|
}
|
|
5068
|
-
} else if (usageMetadata) {
|
|
5069
|
-
yield {
|
|
5070
|
-
candidates: [],
|
|
5071
|
-
usageMetadata
|
|
5072
|
-
};
|
|
5073
5211
|
}
|
|
5074
5212
|
} catch (e) {
|
|
5075
5213
|
}
|
|
5076
5214
|
}
|
|
5215
|
+
if (Date.now() - lastFlushTime >= 350 && hasNewData) {
|
|
5216
|
+
yield {
|
|
5217
|
+
candidates: pendingParts.length > 0 ? [{ content: { parts: [...pendingParts] } }] : [],
|
|
5218
|
+
usageMetadata: latestUsageMetadata
|
|
5219
|
+
};
|
|
5220
|
+
pendingParts = [];
|
|
5221
|
+
lastFlushTime = Date.now();
|
|
5222
|
+
hasNewData = false;
|
|
5223
|
+
}
|
|
5077
5224
|
}
|
|
5078
5225
|
};
|
|
5079
5226
|
signalTermination = () => {
|
|
@@ -5181,6 +5328,20 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
|
|
|
5181
5328
|
const iterator2 = stream[Symbol.asyncIterator]();
|
|
5182
5329
|
const firstResult2 = await iterator2.next();
|
|
5183
5330
|
return { iterator: iterator2, firstResult: firstResult2 };
|
|
5331
|
+
} else if (aiProvider === "DeepSeek") {
|
|
5332
|
+
const stream = getDeepSeekStream(
|
|
5333
|
+
apiKey,
|
|
5334
|
+
"deepseek-chat",
|
|
5335
|
+
janitorContents,
|
|
5336
|
+
janitorPrompt,
|
|
5337
|
+
"Fast",
|
|
5338
|
+
// Janitor always minimal
|
|
5339
|
+
mode,
|
|
5340
|
+
false
|
|
5341
|
+
);
|
|
5342
|
+
const iterator2 = stream[Symbol.asyncIterator]();
|
|
5343
|
+
const firstResult2 = await iterator2.next();
|
|
5344
|
+
return { iterator: iterator2, firstResult: firstResult2 };
|
|
5184
5345
|
} else {
|
|
5185
5346
|
const stream = await client.models.generateContentStream({
|
|
5186
5347
|
model: janitorModel || "gemma-4-26b-a4b-it",
|
|
@@ -5524,8 +5685,41 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
|
|
|
5524
5685
|
client = new GoogleGenAI({ apiKey });
|
|
5525
5686
|
return client;
|
|
5526
5687
|
};
|
|
5688
|
+
generateSimpleContent = async (settings, model, contents, systemInstruction, thinkingLevel = "Fast") => {
|
|
5689
|
+
const { aiProvider = "Google", apiKey, mode } = settings;
|
|
5690
|
+
let fullText = "";
|
|
5691
|
+
let usageMetadata = null;
|
|
5692
|
+
let stream;
|
|
5693
|
+
if (aiProvider === "OpenRouter") {
|
|
5694
|
+
stream = getOpenRouterStream(apiKey, model, contents, systemInstruction, thinkingLevel, mode, false);
|
|
5695
|
+
} else if (aiProvider === "DeepSeek") {
|
|
5696
|
+
stream = getDeepSeekStream(apiKey, model, contents, systemInstruction, thinkingLevel, mode, false);
|
|
5697
|
+
} else {
|
|
5698
|
+
const genStream = await client.models.generateContentStream({
|
|
5699
|
+
model,
|
|
5700
|
+
contents,
|
|
5701
|
+
config: {
|
|
5702
|
+
systemInstruction,
|
|
5703
|
+
maxOutputTokens: 2048,
|
|
5704
|
+
temperature: 0.3,
|
|
5705
|
+
thinkingConfig: { includeThoughts: false, thinkingLevel: ThinkingLevel.MINIMAL }
|
|
5706
|
+
}
|
|
5707
|
+
});
|
|
5708
|
+
stream = genStream;
|
|
5709
|
+
}
|
|
5710
|
+
for await (const chunk of stream) {
|
|
5711
|
+
if (chunk.candidates?.[0]?.content?.parts) {
|
|
5712
|
+
for (const part of chunk.candidates[0].content.parts) {
|
|
5713
|
+
if (part.text && !part.thought) fullText += part.text;
|
|
5714
|
+
}
|
|
5715
|
+
}
|
|
5716
|
+
if (chunk.usageMetadata) usageMetadata = chunk.usageMetadata;
|
|
5717
|
+
}
|
|
5718
|
+
return { text: fullText, usageMetadata };
|
|
5719
|
+
};
|
|
5527
5720
|
consolidatePastMemories = async (currentChatId, settings) => {
|
|
5528
5721
|
try {
|
|
5722
|
+
const { aiProvider = "Google" } = settings;
|
|
5529
5723
|
const tempStorage = readEncryptedJson(TEMP_MEM_FILE, {});
|
|
5530
5724
|
const totalMemoriesCount = Object.values(tempStorage).flat().length;
|
|
5531
5725
|
if (totalMemoriesCount <= 2) return;
|
|
@@ -5573,23 +5767,13 @@ ${newMemoryListStr}
|
|
|
5573
5767
|
let attempts = 0;
|
|
5574
5768
|
const maxAttempts = 3;
|
|
5575
5769
|
let success = false;
|
|
5770
|
+
let targetModel = "gemini-3.1-flash-lite";
|
|
5771
|
+
if (aiProvider === "OpenRouter") targetModel = "google/gemma-4-26b-a4b-it:free";
|
|
5772
|
+
if (aiProvider === "DeepSeek") targetModel = "deepseek-v4-flash";
|
|
5576
5773
|
while (attempts < maxAttempts && !success) {
|
|
5577
5774
|
attempts++;
|
|
5578
5775
|
try {
|
|
5579
|
-
const response = await
|
|
5580
|
-
model: "gemini-3.1-flash-lite",
|
|
5581
|
-
contents: prompt,
|
|
5582
|
-
config: {
|
|
5583
|
-
temperature: 0.3,
|
|
5584
|
-
safetySettings: [
|
|
5585
|
-
{ category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
5586
|
-
{ category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
5587
|
-
{ category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
5588
|
-
{ category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_NONE }
|
|
5589
|
-
],
|
|
5590
|
-
thinkingConfig: { includeThoughts: false, thinkingLevel: ThinkingLevel.LOW }
|
|
5591
|
-
}
|
|
5592
|
-
});
|
|
5776
|
+
const response = await generateSimpleContent(settings, targetModel, prompt, null, "Fast");
|
|
5593
5777
|
const responseText = response.text || "";
|
|
5594
5778
|
const janitorToolCalls = detectToolCalls(responseText);
|
|
5595
5779
|
if (janitorToolCalls.length === 0) {
|
|
@@ -5601,6 +5785,9 @@ ${newMemoryListStr}
|
|
|
5601
5785
|
await dispatchTool(toolName, janitorToolCall.args, { chatId: currentChatId });
|
|
5602
5786
|
}
|
|
5603
5787
|
}
|
|
5788
|
+
if (response.usageMetadata) {
|
|
5789
|
+
await addToUsage("tokens", response.usageMetadata.totalTokenCount || 0);
|
|
5790
|
+
}
|
|
5604
5791
|
success = true;
|
|
5605
5792
|
} catch (err) {
|
|
5606
5793
|
if (attempts >= maxAttempts) {
|
|
@@ -5653,66 +5840,22 @@ Provide a new consolidated summary of the entire session.` : `Here is the conver
|
|
|
5653
5840
|
${flattenedText2}
|
|
5654
5841
|
|
|
5655
5842
|
Provide a consolidated summary of the entire session.`;
|
|
5843
|
+
let targetModel = "gemini-3.1-flash-lite";
|
|
5844
|
+
if (aiProvider === "OpenRouter") targetModel = "google/gemma-4-26b-a4b-it:free";
|
|
5845
|
+
if (aiProvider === "DeepSeek") targetModel = "deepseek-v4-flash";
|
|
5656
5846
|
try {
|
|
5657
|
-
const response = await
|
|
5658
|
-
model: "gemini-3.1-flash-lite",
|
|
5659
|
-
contents: prompt,
|
|
5660
|
-
config: {
|
|
5661
|
-
systemInstruction,
|
|
5662
|
-
maxOutputTokens: 4096,
|
|
5663
|
-
temperature: 0.3,
|
|
5664
|
-
safetySettings: [
|
|
5665
|
-
{ category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
5666
|
-
{ category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
5667
|
-
{ category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
5668
|
-
{ category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_NONE }
|
|
5669
|
-
],
|
|
5670
|
-
thinkingConfig: { includeThoughts: false, thinkingLevel: ThinkingLevel.MEDIUM }
|
|
5671
|
-
}
|
|
5672
|
-
});
|
|
5847
|
+
const response = await generateSimpleContent(settings, targetModel, prompt, systemInstruction, "Fast");
|
|
5673
5848
|
return response.text || "";
|
|
5674
5849
|
} catch (err) {
|
|
5675
|
-
|
|
5676
|
-
const response = await client.models.generateContent({
|
|
5677
|
-
model: "gemini-2.5-flash",
|
|
5678
|
-
contents: prompt,
|
|
5679
|
-
config: {
|
|
5680
|
-
systemInstruction,
|
|
5681
|
-
maxOutputTokens: 4096,
|
|
5682
|
-
temperature: 0.3,
|
|
5683
|
-
safetySettings: [
|
|
5684
|
-
{ category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
5685
|
-
{ category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
5686
|
-
{ category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
5687
|
-
{ category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_NONE }
|
|
5688
|
-
],
|
|
5689
|
-
thinkingConfig: { includeThoughts: false, thinkingBudget: 8192 }
|
|
5690
|
-
}
|
|
5691
|
-
});
|
|
5692
|
-
return response.text || "";
|
|
5693
|
-
} catch (e) {
|
|
5850
|
+
if (aiProvider === "Google") {
|
|
5694
5851
|
try {
|
|
5695
|
-
const
|
|
5696
|
-
|
|
5697
|
-
|
|
5698
|
-
config: {
|
|
5699
|
-
systemInstruction,
|
|
5700
|
-
maxOutputTokens: 4096,
|
|
5701
|
-
temperature: 0.3,
|
|
5702
|
-
safetySettings: [
|
|
5703
|
-
{ category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
5704
|
-
{ category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
5705
|
-
{ category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
5706
|
-
{ category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_NONE }
|
|
5707
|
-
],
|
|
5708
|
-
thinkingConfig: { includeThoughts: false, thinkingBudget: 8192 }
|
|
5709
|
-
}
|
|
5710
|
-
});
|
|
5711
|
-
return response.text || "";
|
|
5712
|
-
} catch (e2) {
|
|
5852
|
+
const fallback = await generateSimpleContent(settings, "gemini-2.5-flash", prompt, systemInstruction, "Fast");
|
|
5853
|
+
return fallback.text || "";
|
|
5854
|
+
} catch (e) {
|
|
5713
5855
|
return "";
|
|
5714
5856
|
}
|
|
5715
5857
|
}
|
|
5858
|
+
return "";
|
|
5716
5859
|
}
|
|
5717
5860
|
};
|
|
5718
5861
|
const flattenedText = flattenContext(modifiedHistory);
|
|
@@ -6113,11 +6256,14 @@ ${thinkingLevel != "Fast" && aiProvider === "Google" ? `${modelName.toLowerCase(
|
|
|
6113
6256
|
throw new Error("Error: Quota Exausted for Agent");
|
|
6114
6257
|
}
|
|
6115
6258
|
targetModel = modelName;
|
|
6259
|
+
if (aiProvider === "DeepSeek" && thinkingLevel === "Fast") {
|
|
6260
|
+
targetModel = "deepseek-chat";
|
|
6261
|
+
}
|
|
6116
6262
|
if (retryCount === MAX_RETRIES - 1) {
|
|
6117
|
-
targetModel = "gemini-3-flash-preview";
|
|
6263
|
+
targetModel = aiProvider === "DeepSeek" ? "deepseek-v4-flash" : "gemini-3-flash-preview";
|
|
6118
6264
|
yield { type: "model_update", content: "Trying with fallback model" };
|
|
6119
6265
|
} else if (retryCount === MAX_RETRIES) {
|
|
6120
|
-
targetModel = "gemini-3.5-flash";
|
|
6266
|
+
targetModel = aiProvider === "DeepSeek" ? "deepseek-v4-pro" : "gemini-3.5-flash";
|
|
6121
6267
|
yield { type: "model_update", content: "Trying with fallback model" };
|
|
6122
6268
|
} else if (retryCount > 12 && retryCount < MAX_RETRIES - 2 && settings.apiKey !== "custom") {
|
|
6123
6269
|
targetModel = "gemma-4-31b-it";
|
|
@@ -6154,6 +6300,16 @@ ${thinkingLevel != "Fast" && aiProvider === "Google" ? `${modelName.toLowerCase(
|
|
|
6154
6300
|
mode,
|
|
6155
6301
|
isMultiModal
|
|
6156
6302
|
);
|
|
6303
|
+
} else if (aiProvider === "DeepSeek") {
|
|
6304
|
+
stream = getDeepSeekStream(
|
|
6305
|
+
settings.apiKey,
|
|
6306
|
+
targetModel,
|
|
6307
|
+
activeContents,
|
|
6308
|
+
currentSystemInstruction,
|
|
6309
|
+
thinkingLevel,
|
|
6310
|
+
mode,
|
|
6311
|
+
isMultiModal
|
|
6312
|
+
);
|
|
6157
6313
|
} else {
|
|
6158
6314
|
stream = await client.models.generateContentStream({
|
|
6159
6315
|
model: targetModel || "gemma-4-31b-it",
|
|
@@ -6947,7 +7103,7 @@ Error Log can be found in ${path16.join(LOGS_DIR, "agent", "error.log")}`);
|
|
|
6947
7103
|
const shouldContinue = toolCallPointer > 0;
|
|
6948
7104
|
yield { type: "status", content: "Working..." };
|
|
6949
7105
|
const cleanedTurnText = contextSafeReplace(turnText, /\[\s*(turn\s*:)?\s*(continue|finish)\s*\]/gi, "").trim();
|
|
6950
|
-
let isActuallyFinished = hasFinish
|
|
7106
|
+
let isActuallyFinished = hasFinish || !shouldContinue;
|
|
6951
7107
|
if (isActuallyFinished) {
|
|
6952
7108
|
const fullAgentTextRaw = fullAgentResponseChunks.join("\n");
|
|
6953
7109
|
const cleanedFullResponse = fullAgentTextRaw.replace(/(?:<think>|\[think\])[\s\S]*?(?:<\/think>|\[\/think\])/g, "").trim();
|
|
@@ -7663,44 +7819,63 @@ function App({ args = [] }) {
|
|
|
7663
7819
|
const [tick, setTick] = useState10(0);
|
|
7664
7820
|
const isFirstRender = useRef3(true);
|
|
7665
7821
|
const isSecondRender = useRef3(true);
|
|
7822
|
+
const isThirdRender = useRef3(true);
|
|
7666
7823
|
useEffect7(() => {
|
|
7824
|
+
if (!apiKey) return;
|
|
7667
7825
|
if (isFirstRender.current) {
|
|
7668
7826
|
isFirstRender.current = false;
|
|
7669
7827
|
setTimeout(() => {
|
|
7670
7828
|
isSecondRender.current = false;
|
|
7829
|
+
setTimeout(() => {
|
|
7830
|
+
isThirdRender.current = false;
|
|
7831
|
+
}, 1e3);
|
|
7671
7832
|
}, 2e3);
|
|
7672
7833
|
return;
|
|
7673
7834
|
}
|
|
7674
7835
|
if (isSecondRender.current) {
|
|
7675
7836
|
return;
|
|
7676
7837
|
}
|
|
7838
|
+
if (isThirdRender.current) {
|
|
7839
|
+
return;
|
|
7840
|
+
}
|
|
7677
7841
|
const s = emojiSpace(2);
|
|
7842
|
+
let defaultModel = "";
|
|
7843
|
+
let modelDisplayName = "";
|
|
7678
7844
|
if (apiTier === "Free") {
|
|
7679
|
-
|
|
7680
|
-
|
|
7681
|
-
|
|
7682
|
-
|
|
7683
|
-
|
|
7684
|
-
|
|
7685
|
-
|
|
7686
|
-
|
|
7687
|
-
|
|
7688
|
-
|
|
7689
|
-
});
|
|
7845
|
+
if (aiProvider === "Google") {
|
|
7846
|
+
defaultModel = "gemma-4-31b-it";
|
|
7847
|
+
modelDisplayName = "Gemma 4 (Free default)";
|
|
7848
|
+
} else if (aiProvider === "DeepSeek") {
|
|
7849
|
+
defaultModel = "deepseek-v4-flash";
|
|
7850
|
+
modelDisplayName = "DeepSeek Flash (Free default)";
|
|
7851
|
+
} else {
|
|
7852
|
+
defaultModel = "google/gemma-4-31b-it:free";
|
|
7853
|
+
modelDisplayName = "Gemma 4 (Free default)";
|
|
7854
|
+
}
|
|
7690
7855
|
} else {
|
|
7691
|
-
|
|
7692
|
-
|
|
7693
|
-
|
|
7694
|
-
|
|
7695
|
-
|
|
7696
|
-
|
|
7697
|
-
|
|
7698
|
-
|
|
7699
|
-
|
|
7700
|
-
|
|
7701
|
-
});
|
|
7856
|
+
if (aiProvider === "Google") {
|
|
7857
|
+
defaultModel = "gemini-3-flash-preview";
|
|
7858
|
+
modelDisplayName = "Gemini 3 Flash";
|
|
7859
|
+
} else if (aiProvider === "DeepSeek") {
|
|
7860
|
+
defaultModel = "deepseek-v4-flash";
|
|
7861
|
+
modelDisplayName = "DeepSeek Flash";
|
|
7862
|
+
} else {
|
|
7863
|
+
defaultModel = "deepseek/deepseek-v4-flash";
|
|
7864
|
+
modelDisplayName = "DeepSeek Flash";
|
|
7865
|
+
}
|
|
7702
7866
|
}
|
|
7703
|
-
|
|
7867
|
+
setActiveModel(defaultModel);
|
|
7868
|
+
saveSettings({ apiTier, activeModel: defaultModel });
|
|
7869
|
+
setMessages((prev) => {
|
|
7870
|
+
setCompletedIndex(prev.length + 1);
|
|
7871
|
+
return [...prev, {
|
|
7872
|
+
id: "tier-switch-" + Date.now(),
|
|
7873
|
+
role: "system",
|
|
7874
|
+
text: `\u26A0\uFE0F${s}**[TIER LIMIT]** Auto-switched to ${modelDisplayName}.`,
|
|
7875
|
+
isMeta: true
|
|
7876
|
+
}];
|
|
7877
|
+
});
|
|
7878
|
+
}, [apiTier, aiProvider, apiKey]);
|
|
7704
7879
|
const terminalEnv = useMemo2(() => {
|
|
7705
7880
|
const isIDE = process.env.TERM_PROGRAM === "vscode" || !!process.env.VSC_TERMINAL_URL || !!process.env.INTELLIJ_TERMINAL_COMMAND_BLOCKS;
|
|
7706
7881
|
return {
|
|
@@ -8105,12 +8280,21 @@ function App({ args = [] }) {
|
|
|
8105
8280
|
}, [mode, thinkingLevel, aiProvider, activeModel, showFullThinking, systemSettings, profileData, imageSettings, isInitializing, parsedArgs, apiTier]);
|
|
8106
8281
|
const handleSetup = async (val) => {
|
|
8107
8282
|
const key = val.trim();
|
|
8108
|
-
|
|
8283
|
+
let minLength = 30;
|
|
8284
|
+
if (aiProvider === "OpenRouter") minLength = 10;
|
|
8285
|
+
if (aiProvider === "DeepSeek") minLength = 20;
|
|
8109
8286
|
if (key.length >= minLength) {
|
|
8110
8287
|
await saveAPIKey(key);
|
|
8111
8288
|
setApiKey(key);
|
|
8112
8289
|
initAI(key);
|
|
8113
|
-
|
|
8290
|
+
let defaultModel = "gemma-4-31b-it";
|
|
8291
|
+
if (aiProvider === "OpenRouter") {
|
|
8292
|
+
defaultModel = "google/gemma-4-31b-it:free";
|
|
8293
|
+
} else if (aiProvider === "DeepSeek") {
|
|
8294
|
+
defaultModel = "deepseek-v4-flash";
|
|
8295
|
+
}
|
|
8296
|
+
setActiveModel(defaultModel);
|
|
8297
|
+
setMessages((prev) => [...prev, { role: "system", text: `\u2705 ${aiProvider} API Key saved successfully! Model set to ${defaultModel}. Initialization complete.`, isMeta: true }]);
|
|
8114
8298
|
} else {
|
|
8115
8299
|
setMessages((prev) => [...prev, { role: "system", text: `\u274C INVALID KEY: ${aiProvider} API keys must be at least ${minLength} characters.`, isMeta: true }]);
|
|
8116
8300
|
setTempKey("");
|
|
@@ -8202,12 +8386,16 @@ function App({ args = [] }) {
|
|
|
8202
8386
|
{
|
|
8203
8387
|
cmd: "/thinking",
|
|
8204
8388
|
desc: "Set AI reasoning depth",
|
|
8205
|
-
subs: [
|
|
8206
|
-
{ cmd: "Fast", desc: "
|
|
8207
|
-
{ cmd: "
|
|
8208
|
-
{ cmd: "
|
|
8209
|
-
|
|
8210
|
-
{ cmd: "
|
|
8389
|
+
subs: aiProvider === "DeepSeek" ? [
|
|
8390
|
+
{ cmd: "Fast", desc: "Fastest" },
|
|
8391
|
+
{ cmd: "Standard", desc: "Standard Reasoning" },
|
|
8392
|
+
{ cmd: "xHigh", desc: "Extended Reasoning" }
|
|
8393
|
+
] : [
|
|
8394
|
+
{ cmd: "Fast", desc: "Fastest" },
|
|
8395
|
+
{ cmd: "Low", desc: "Quick Reasoning" },
|
|
8396
|
+
{ cmd: "Medium", desc: "Balanced Reasoning" },
|
|
8397
|
+
{ cmd: "High", desc: "Deep Reasoning" },
|
|
8398
|
+
{ cmd: "xHigh", desc: "Extended Reasoning" }
|
|
8211
8399
|
]
|
|
8212
8400
|
},
|
|
8213
8401
|
{
|
|
@@ -8287,6 +8475,15 @@ function App({ args = [] }) {
|
|
|
8287
8475
|
cmd: "moonshotai/kimi-k2.6",
|
|
8288
8476
|
desc: "Multimodal"
|
|
8289
8477
|
}
|
|
8478
|
+
] : aiProvider === "DeepSeek" ? [
|
|
8479
|
+
{
|
|
8480
|
+
cmd: "deepseek-v4-flash",
|
|
8481
|
+
desc: "Fast & Efficient"
|
|
8482
|
+
},
|
|
8483
|
+
{
|
|
8484
|
+
cmd: "deepseek-v4-pro",
|
|
8485
|
+
desc: "High-Intelligence Reasoning"
|
|
8486
|
+
}
|
|
8290
8487
|
] : apiTier === "Free" ? [
|
|
8291
8488
|
{
|
|
8292
8489
|
cmd: "gemma-4-31b-it",
|
|
@@ -9455,7 +9652,8 @@ Selection: ${val}`,
|
|
|
9455
9652
|
setInputConfig,
|
|
9456
9653
|
saveSettings,
|
|
9457
9654
|
quotas,
|
|
9458
|
-
setMessages
|
|
9655
|
+
setMessages,
|
|
9656
|
+
aiProvider
|
|
9459
9657
|
}
|
|
9460
9658
|
);
|
|
9461
9659
|
case "apiTier":
|
|
@@ -9937,8 +10135,9 @@ Selection: ${val}`,
|
|
|
9937
10135
|
CommandMenu,
|
|
9938
10136
|
{
|
|
9939
10137
|
items: [
|
|
9940
|
-
{ label: "Google (
|
|
9941
|
-
{ label: "
|
|
10138
|
+
{ label: "Google (Free/Paid)", value: "Google" },
|
|
10139
|
+
{ label: "DeepSeek (Paid)", value: "DeepSeek" },
|
|
10140
|
+
{ label: "OpenRouter (Free/Paid) [EXPERIMENTAL]", value: "OpenRouter" }
|
|
9942
10141
|
],
|
|
9943
10142
|
onSelect: (item) => {
|
|
9944
10143
|
setAiProvider(item.value);
|