fluxflow-cli 1.19.6 → 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 +665 -198
- 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
|
@@ -1171,12 +1171,12 @@ var init_main_tools = __esm({
|
|
|
1171
1171
|
}
|
|
1172
1172
|
return _isPsAvailable;
|
|
1173
1173
|
};
|
|
1174
|
-
TOOL_PROTOCOL = (mode, osDetected) => `
|
|
1174
|
+
TOOL_PROTOCOL = (mode, osDetected, isMultiModal, aiProvider) => `
|
|
1175
1175
|
-- TOOL DEFINITIONS --
|
|
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
|
|
@@ -1186,7 +1186,7 @@ ${mode === "Flux" ? "- **File Tools >> Code in chat**\n" : ""}
|
|
|
1186
1186
|
2. [tool:functions.WebScrape(url="...")]. Proactive use for specific webpage/docs/api
|
|
1187
1187
|
|
|
1188
1188
|
${mode === "Flux" ? `- PROJECT TOOLS (path = relative to CWD, path separator: '/') -
|
|
1189
|
-
1. [tool:functions.ReadFile(path="...", startLine=number, endLine=number)]. Supports images/docs. User gives image/doc: VIEW FIRST
|
|
1189
|
+
1. [tool:functions.ReadFile(path="...", startLine=number, endLine=number)]. ${aiProvider !== "Google" ? `${isMultiModal ? `Supports images/docs. User gives image/doc: VIEW FIRST` : `No Multimodal support`}` : `Supports images/docs. User gives image/doc: VIEW FIRST`}
|
|
1190
1190
|
2. [tool:functions.ReadFolder(path="...")]. Detailed DIR stats
|
|
1191
1191
|
3. [tool:functions.PatchFile(path="...", replaceContent1="exact string", newContent1="...", ...MAX 8)]. Surgical Patch. **Multiple patch on same file/path? Use replaceContent2, newContent2 etc >>> multiple spams**. Unsure? ReadFile > guessing.
|
|
1192
1192
|
4. [tool:functions.WriteFile(path="...", content="...")]. Creates/Overwrites. File Exist? PatchFile >>> WriteFile. Verify Imports
|
|
@@ -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,
|
|
@@ -2413,7 +2415,7 @@ ${userMemories}` : "";
|
|
|
2413
2415
|
${parts.join("\n\n")}
|
|
2414
2416
|
` : "";
|
|
2415
2417
|
};
|
|
2416
|
-
getSystemInstruction = (profile, thinkingLevel, mode, systemSettings, isMemoryEnabled = true, isFirstPrompt = false) => {
|
|
2418
|
+
getSystemInstruction = (profile, thinkingLevel, mode, systemSettings, isMemoryEnabled = true, isFirstPrompt = false, aiProvider = "Google", isMultiModal = false) => {
|
|
2417
2419
|
let thinkingConfig = "";
|
|
2418
2420
|
if (thinkingLevel !== "GEM") {
|
|
2419
2421
|
let levelKey = thinkingLevel;
|
|
@@ -2465,22 +2467,22 @@ 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
|
|
|
2472
2474
|
-- MARKERS --
|
|
2473
2475
|
- TOOL SYSTEM: [TOOL RESULT] (system priority)
|
|
2474
2476
|
- SYSTEM NOTIFICATION: [SYSTEM], [METADATA] in user turn
|
|
2475
|
-
${thinkingLevel !== "GEM" ? `
|
|
2477
|
+
${aiProvider === "Google" ? `${thinkingLevel !== "GEM" ? `
|
|
2476
2478
|
-- THINKING RULES --
|
|
2477
2479
|
${thinkingConfig}
|
|
2478
2480
|
${thinkingLevel !== "Fast" ? `
|
|
2479
2481
|
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
|
-
` : ""}` : ""}
|
|
2483
|
-
${TOOL_PROTOCOL(mode, osDetected)}
|
|
2484
|
+
` : ""}` : ""}` : ``}
|
|
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"}
|
|
@@ -4415,6 +4417,7 @@ var init_settings = __esm({
|
|
|
4415
4417
|
DEFAULT_SETTINGS = {
|
|
4416
4418
|
mode: "Flux",
|
|
4417
4419
|
thinkingLevel: "Medium",
|
|
4420
|
+
aiProvider: "Google",
|
|
4418
4421
|
activeModel: "gemma-4-31b-it",
|
|
4419
4422
|
showFullThinking: true,
|
|
4420
4423
|
apiTier: "Free",
|
|
@@ -4922,7 +4925,7 @@ var init_tools = __esm({
|
|
|
4922
4925
|
import { GoogleGenAI, ThinkingLevel, HarmBlockThreshold, HarmCategory } from "@google/genai";
|
|
4923
4926
|
import path16 from "path";
|
|
4924
4927
|
import fs17 from "fs";
|
|
4925
|
-
var client, TERMINATION_SIGNAL, stripAnsi2, 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;
|
|
4926
4929
|
var init_ai = __esm({
|
|
4927
4930
|
async "src/utils/ai.js"() {
|
|
4928
4931
|
await init_prompts();
|
|
@@ -4940,6 +4943,286 @@ var init_ai = __esm({
|
|
|
4940
4943
|
if (typeof str !== "string") return str;
|
|
4941
4944
|
return str.replace(/[\u001b\u009b][[()#;?]*(?:[0-9]{1,4}(?:;[0-9]{0,4})*)?[0-9A-ORZcf-nqry=><]/g, "");
|
|
4942
4945
|
};
|
|
4946
|
+
fetchWithBackoff = async (url, options, retries = 5, delay = 1e3) => {
|
|
4947
|
+
for (let i = 0; i < retries; i++) {
|
|
4948
|
+
try {
|
|
4949
|
+
const response = await fetch(url, options);
|
|
4950
|
+
if (response.ok) return response;
|
|
4951
|
+
if (response.status !== 429 && response.status < 500) return response;
|
|
4952
|
+
} catch (e) {
|
|
4953
|
+
if (i === retries - 1) throw e;
|
|
4954
|
+
}
|
|
4955
|
+
await new Promise((resolve) => setTimeout(resolve, delay * Math.pow(2, i)));
|
|
4956
|
+
}
|
|
4957
|
+
return fetch(url, options);
|
|
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
|
+
};
|
|
5089
|
+
getOpenRouterStream = async function* (apiKey, model, contents, systemInstruction, thinkingLevel, mode, isMultiModal) {
|
|
5090
|
+
const messages = [];
|
|
5091
|
+
if (systemInstruction) {
|
|
5092
|
+
messages.push({ role: "system", content: systemInstruction });
|
|
5093
|
+
}
|
|
5094
|
+
for (const content of contents) {
|
|
5095
|
+
const role = content.role === "user" ? "user" : "assistant";
|
|
5096
|
+
const msgContent = [];
|
|
5097
|
+
if (Array.isArray(content.parts)) {
|
|
5098
|
+
for (const part of content.parts) {
|
|
5099
|
+
if (part.text) {
|
|
5100
|
+
msgContent.push({ type: "text", text: part.text });
|
|
5101
|
+
} else if (part.inlineData && isMultiModal) {
|
|
5102
|
+
const mimeType = part.inlineData.mimeType;
|
|
5103
|
+
const data = part.inlineData.data;
|
|
5104
|
+
const isImage = mimeType.startsWith("image/");
|
|
5105
|
+
if (isImage) {
|
|
5106
|
+
msgContent.push({
|
|
5107
|
+
type: "image_url",
|
|
5108
|
+
image_url: {
|
|
5109
|
+
url: `data:${mimeType};base64,${data}`
|
|
5110
|
+
}
|
|
5111
|
+
});
|
|
5112
|
+
} else {
|
|
5113
|
+
msgContent.push({
|
|
5114
|
+
type: "file",
|
|
5115
|
+
file: {
|
|
5116
|
+
filename: part.filename || "file",
|
|
5117
|
+
file_data: `data:${mimeType};base64,${data}`
|
|
5118
|
+
}
|
|
5119
|
+
});
|
|
5120
|
+
}
|
|
5121
|
+
}
|
|
5122
|
+
}
|
|
5123
|
+
} else {
|
|
5124
|
+
const text = content.text || "";
|
|
5125
|
+
if (text) msgContent.push({ type: "text", text });
|
|
5126
|
+
}
|
|
5127
|
+
messages.push({
|
|
5128
|
+
role,
|
|
5129
|
+
content: msgContent.length === 1 && msgContent[0].type === "text" ? msgContent[0].text : msgContent
|
|
5130
|
+
});
|
|
5131
|
+
}
|
|
5132
|
+
const reasoningEffortMap = {
|
|
5133
|
+
"Low": "low",
|
|
5134
|
+
"Medium": "medium",
|
|
5135
|
+
"High": "high",
|
|
5136
|
+
"xHigh": "high"
|
|
5137
|
+
};
|
|
5138
|
+
const requestPayload = {
|
|
5139
|
+
model,
|
|
5140
|
+
messages,
|
|
5141
|
+
stream: true,
|
|
5142
|
+
temperature: mode === "Flux" ? 1 : 1.4
|
|
5143
|
+
};
|
|
5144
|
+
const effort = reasoningEffortMap[thinkingLevel];
|
|
5145
|
+
if (effort && thinkingLevel !== "Fast") {
|
|
5146
|
+
requestPayload.reasoning_effort = effort;
|
|
5147
|
+
}
|
|
5148
|
+
const response = await fetchWithBackoff("https://openrouter.ai/api/v1/chat/completions", {
|
|
5149
|
+
method: "POST",
|
|
5150
|
+
headers: {
|
|
5151
|
+
"Authorization": `Bearer ${apiKey}`,
|
|
5152
|
+
"Content-Type": "application/json",
|
|
5153
|
+
"X-Title": "FluxFlow CLI",
|
|
5154
|
+
"X-Cache": "true"
|
|
5155
|
+
},
|
|
5156
|
+
body: JSON.stringify(requestPayload)
|
|
5157
|
+
});
|
|
5158
|
+
if (!response.ok) {
|
|
5159
|
+
const errData = await response.json().catch(() => ({}));
|
|
5160
|
+
throw new Error(`OpenRouter Error (${response.status}): ${errData.error?.message || response.statusText}`);
|
|
5161
|
+
}
|
|
5162
|
+
const reader = response.body.getReader();
|
|
5163
|
+
const decoder = new TextDecoder();
|
|
5164
|
+
let buffer = "";
|
|
5165
|
+
let pendingParts = [];
|
|
5166
|
+
let latestUsageMetadata = null;
|
|
5167
|
+
let lastFlushTime = Date.now();
|
|
5168
|
+
let hasNewData = false;
|
|
5169
|
+
while (true) {
|
|
5170
|
+
const { done, value } = await reader.read();
|
|
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
|
+
}
|
|
5180
|
+
buffer += decoder.decode(value, { stream: true });
|
|
5181
|
+
const lines = buffer.split("\n");
|
|
5182
|
+
buffer = lines.pop();
|
|
5183
|
+
for (const line of lines) {
|
|
5184
|
+
const cleanLine = line.trim();
|
|
5185
|
+
if (!cleanLine || !cleanLine.startsWith("data: ")) continue;
|
|
5186
|
+
if (cleanLine === "data: [DONE]") break;
|
|
5187
|
+
try {
|
|
5188
|
+
const json = JSON.parse(cleanLine.substring(6));
|
|
5189
|
+
const delta = json.choices?.[0]?.delta;
|
|
5190
|
+
const usage = json.usage;
|
|
5191
|
+
if (usage) {
|
|
5192
|
+
latestUsageMetadata = {
|
|
5193
|
+
totalTokenCount: usage.total_tokens || usage.prompt_tokens + usage.completion_tokens,
|
|
5194
|
+
promptTokenCount: usage.prompt_tokens || 0,
|
|
5195
|
+
candidatesTokenCount: usage.completion_tokens || 0,
|
|
5196
|
+
cachedContentTokenCount: usage.prompt_tokens_details?.cached_tokens || 0,
|
|
5197
|
+
thoughtsTokenCount: usage.completion_tokens_details?.reasoning_tokens || 0
|
|
5198
|
+
};
|
|
5199
|
+
hasNewData = true;
|
|
5200
|
+
}
|
|
5201
|
+
if (delta) {
|
|
5202
|
+
const thought = delta.reasoning || (delta.reasoning_details ? delta.reasoning_details.map((d) => d.text).join("") : null);
|
|
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;
|
|
5210
|
+
}
|
|
5211
|
+
}
|
|
5212
|
+
} catch (e) {
|
|
5213
|
+
}
|
|
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
|
+
}
|
|
5224
|
+
}
|
|
5225
|
+
};
|
|
4943
5226
|
signalTermination = () => {
|
|
4944
5227
|
TERMINATION_SIGNAL = true;
|
|
4945
5228
|
};
|
|
@@ -4974,7 +5257,7 @@ var init_ai = __esm({
|
|
|
4974
5257
|
const USER_CONTEXT_LENGTH = 4 * (1024 * 2);
|
|
4975
5258
|
const AGENT_CONTEXT_LENGTH = 4 * (1024 * 8);
|
|
4976
5259
|
const { onStatus, onMemoryUpdated, onBackgroundIncrement } = callbacks;
|
|
4977
|
-
const { profile, thinkingLevel, mode, janitorModel, chatId, systemSettings, sessionStats } = settings;
|
|
5260
|
+
const { profile, thinkingLevel, mode, janitorModel, chatId, systemSettings, sessionStats, aiProvider = "Google", apiKey } = settings;
|
|
4978
5261
|
const isMemoryEnabled = systemSettings?.memory !== false;
|
|
4979
5262
|
const persistentStorage = readEncryptedJson(MEMORIES_FILE, []);
|
|
4980
5263
|
const janitorUserMemories = persistentStorage.map((m) => `- [${m.id}]: ${m.memory}`).join("\n");
|
|
@@ -5031,25 +5314,55 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
|
|
|
5031
5314
|
(_, reject) => setTimeout(() => reject(new Error("JANITOR_TIMEOUT")), 6e4)
|
|
5032
5315
|
);
|
|
5033
5316
|
const streamPromise = (async () => {
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5046
|
-
|
|
5047
|
-
|
|
5048
|
-
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
5317
|
+
if (aiProvider === "OpenRouter") {
|
|
5318
|
+
const janitorOpenRouterModel = "google/gemma-4-26b-a4b-it:free";
|
|
5319
|
+
const stream = getOpenRouterStream(
|
|
5320
|
+
apiKey,
|
|
5321
|
+
janitorOpenRouterModel,
|
|
5322
|
+
janitorContents,
|
|
5323
|
+
janitorPrompt,
|
|
5324
|
+
"Fast",
|
|
5325
|
+
// Janitor always minimal
|
|
5326
|
+
mode
|
|
5327
|
+
);
|
|
5328
|
+
const iterator2 = stream[Symbol.asyncIterator]();
|
|
5329
|
+
const firstResult2 = await iterator2.next();
|
|
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 };
|
|
5345
|
+
} else {
|
|
5346
|
+
const stream = await client.models.generateContentStream({
|
|
5347
|
+
model: janitorModel || "gemma-4-26b-a4b-it",
|
|
5348
|
+
contents: janitorContents,
|
|
5349
|
+
config: {
|
|
5350
|
+
systemInstruction: janitorPrompt,
|
|
5351
|
+
maxOutputTokens: 512,
|
|
5352
|
+
temperature: 0.3,
|
|
5353
|
+
safetySettings: [
|
|
5354
|
+
{ category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
5355
|
+
{ category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
5356
|
+
{ category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
5357
|
+
{ category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_NONE }
|
|
5358
|
+
],
|
|
5359
|
+
thinkingConfig: { includeThoughts: false, thinkingLevel: ThinkingLevel.MINIMAL }
|
|
5360
|
+
}
|
|
5361
|
+
});
|
|
5362
|
+
const iterator2 = stream[Symbol.asyncIterator]();
|
|
5363
|
+
const firstResult2 = await iterator2.next();
|
|
5364
|
+
return { iterator: iterator2, firstResult: firstResult2 };
|
|
5365
|
+
}
|
|
5053
5366
|
})();
|
|
5054
5367
|
const { iterator, firstResult } = await Promise.race([streamPromise, timeoutPromise]);
|
|
5055
5368
|
let { value: firstChunk, done: firstDone } = firstResult;
|
|
@@ -5372,8 +5685,41 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
|
|
|
5372
5685
|
client = new GoogleGenAI({ apiKey });
|
|
5373
5686
|
return client;
|
|
5374
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
|
+
};
|
|
5375
5720
|
consolidatePastMemories = async (currentChatId, settings) => {
|
|
5376
5721
|
try {
|
|
5722
|
+
const { aiProvider = "Google" } = settings;
|
|
5377
5723
|
const tempStorage = readEncryptedJson(TEMP_MEM_FILE, {});
|
|
5378
5724
|
const totalMemoriesCount = Object.values(tempStorage).flat().length;
|
|
5379
5725
|
if (totalMemoriesCount <= 2) return;
|
|
@@ -5421,23 +5767,13 @@ ${newMemoryListStr}
|
|
|
5421
5767
|
let attempts = 0;
|
|
5422
5768
|
const maxAttempts = 3;
|
|
5423
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";
|
|
5424
5773
|
while (attempts < maxAttempts && !success) {
|
|
5425
5774
|
attempts++;
|
|
5426
5775
|
try {
|
|
5427
|
-
const response = await
|
|
5428
|
-
model: "gemini-3.1-flash-lite",
|
|
5429
|
-
contents: prompt,
|
|
5430
|
-
config: {
|
|
5431
|
-
temperature: 0.3,
|
|
5432
|
-
safetySettings: [
|
|
5433
|
-
{ category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
5434
|
-
{ category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
5435
|
-
{ category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
5436
|
-
{ category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_NONE }
|
|
5437
|
-
],
|
|
5438
|
-
thinkingConfig: { includeThoughts: false, thinkingLevel: ThinkingLevel.LOW }
|
|
5439
|
-
}
|
|
5440
|
-
});
|
|
5776
|
+
const response = await generateSimpleContent(settings, targetModel, prompt, null, "Fast");
|
|
5441
5777
|
const responseText = response.text || "";
|
|
5442
5778
|
const janitorToolCalls = detectToolCalls(responseText);
|
|
5443
5779
|
if (janitorToolCalls.length === 0) {
|
|
@@ -5449,6 +5785,9 @@ ${newMemoryListStr}
|
|
|
5449
5785
|
await dispatchTool(toolName, janitorToolCall.args, { chatId: currentChatId });
|
|
5450
5786
|
}
|
|
5451
5787
|
}
|
|
5788
|
+
if (response.usageMetadata) {
|
|
5789
|
+
await addToUsage("tokens", response.usageMetadata.totalTokenCount || 0);
|
|
5790
|
+
}
|
|
5452
5791
|
success = true;
|
|
5453
5792
|
} catch (err) {
|
|
5454
5793
|
if (attempts >= maxAttempts) {
|
|
@@ -5467,8 +5806,8 @@ ${newMemoryListStr}
|
|
|
5467
5806
|
}
|
|
5468
5807
|
};
|
|
5469
5808
|
getAIStream = async function* (modelName, history, settings, steeringCallback, versionFluxflow2) {
|
|
5470
|
-
|
|
5471
|
-
|
|
5809
|
+
const { profile, thinkingLevel, mode, janitorModel, chatId, systemSettings, sessionStats, aiProvider = "Google", isMultiModal } = settings;
|
|
5810
|
+
if (!client && aiProvider === "Google") throw new Error("AI not initialized");
|
|
5472
5811
|
const isMemoryEnabled = systemSettings?.memory !== false;
|
|
5473
5812
|
const originalText = history[history.length - 1].text;
|
|
5474
5813
|
const summariesFile = path16.join(SECRET_DIR, "chat-summaries.json");
|
|
@@ -5501,66 +5840,22 @@ Provide a new consolidated summary of the entire session.` : `Here is the conver
|
|
|
5501
5840
|
${flattenedText2}
|
|
5502
5841
|
|
|
5503
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";
|
|
5504
5846
|
try {
|
|
5505
|
-
const response = await
|
|
5506
|
-
model: "gemini-3.1-flash-lite",
|
|
5507
|
-
contents: prompt,
|
|
5508
|
-
config: {
|
|
5509
|
-
systemInstruction,
|
|
5510
|
-
maxOutputTokens: 4096,
|
|
5511
|
-
temperature: 0.3,
|
|
5512
|
-
safetySettings: [
|
|
5513
|
-
{ category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
5514
|
-
{ category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
5515
|
-
{ category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
5516
|
-
{ category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_NONE }
|
|
5517
|
-
],
|
|
5518
|
-
thinkingConfig: { includeThoughts: false, thinkingLevel: ThinkingLevel.MEDIUM }
|
|
5519
|
-
}
|
|
5520
|
-
});
|
|
5847
|
+
const response = await generateSimpleContent(settings, targetModel, prompt, systemInstruction, "Fast");
|
|
5521
5848
|
return response.text || "";
|
|
5522
5849
|
} catch (err) {
|
|
5523
|
-
|
|
5524
|
-
const response = await client.models.generateContent({
|
|
5525
|
-
model: "gemini-2.5-flash",
|
|
5526
|
-
contents: prompt,
|
|
5527
|
-
config: {
|
|
5528
|
-
systemInstruction,
|
|
5529
|
-
maxOutputTokens: 4096,
|
|
5530
|
-
temperature: 0.3,
|
|
5531
|
-
safetySettings: [
|
|
5532
|
-
{ category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
5533
|
-
{ category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
5534
|
-
{ category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
5535
|
-
{ category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_NONE }
|
|
5536
|
-
],
|
|
5537
|
-
thinkingConfig: { includeThoughts: false, thinkingBudget: 8192 }
|
|
5538
|
-
}
|
|
5539
|
-
});
|
|
5540
|
-
return response.text || "";
|
|
5541
|
-
} catch (e) {
|
|
5850
|
+
if (aiProvider === "Google") {
|
|
5542
5851
|
try {
|
|
5543
|
-
const
|
|
5544
|
-
|
|
5545
|
-
|
|
5546
|
-
config: {
|
|
5547
|
-
systemInstruction,
|
|
5548
|
-
maxOutputTokens: 4096,
|
|
5549
|
-
temperature: 0.3,
|
|
5550
|
-
safetySettings: [
|
|
5551
|
-
{ category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
5552
|
-
{ category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
5553
|
-
{ category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
5554
|
-
{ category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_NONE }
|
|
5555
|
-
],
|
|
5556
|
-
thinkingConfig: { includeThoughts: false, thinkingBudget: 8192 }
|
|
5557
|
-
}
|
|
5558
|
-
});
|
|
5559
|
-
return response.text || "";
|
|
5560
|
-
} catch (e2) {
|
|
5852
|
+
const fallback = await generateSimpleContent(settings, "gemini-2.5-flash", prompt, systemInstruction, "Fast");
|
|
5853
|
+
return fallback.text || "";
|
|
5854
|
+
} catch (e) {
|
|
5561
5855
|
return "";
|
|
5562
5856
|
}
|
|
5563
5857
|
}
|
|
5858
|
+
return "";
|
|
5564
5859
|
}
|
|
5565
5860
|
};
|
|
5566
5861
|
const flattenedText = flattenContext(modifiedHistory);
|
|
@@ -5872,7 +6167,7 @@ CWD: ${process.cwd()}${cwdMismatch ? ` (WARNING: CWD Mismatch! Previous Path: ${
|
|
|
5872
6167
|
${dirStructure}
|
|
5873
6168
|
${summaryBlock}
|
|
5874
6169
|
${memoryPrompt}
|
|
5875
|
-
${thinkingLevel != "Fast" ? `${modelName.toLowerCase().startsWith("gemma") ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS CRITICAL PRIORITY. DO NOT START A RESPONSE WITHOUT <think> ... </think>**\n" : ""}` : ""}[USER] ${agentText.replace(/\s*\[Prompted on:.*?\]/g, "").trim()}`.trim();
|
|
6170
|
+
${thinkingLevel != "Fast" && aiProvider === "Google" ? `${modelName.toLowerCase().startsWith("gemma") ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS CRITICAL PRIORITY. DO NOT START A RESPONSE WITHOUT <think> ... </think>**\n" : ""}` : ""}[USER] ${agentText.replace(/\s*\[Prompted on:.*?\]/g, "").trim()}`.trim();
|
|
5876
6171
|
modifiedHistory.push({ role: "user", text: firstUserMsg });
|
|
5877
6172
|
let lastUsage = null;
|
|
5878
6173
|
const MAX_LOOPS = mode === "Flux" ? 70 : 7;
|
|
@@ -5903,7 +6198,7 @@ ${thinkingLevel != "Fast" ? `${modelName.toLowerCase().startsWith("gemma") ? "[S
|
|
|
5903
6198
|
|
|
5904
6199
|
[STEERING HINT]: ${hint}`;
|
|
5905
6200
|
} else {
|
|
5906
|
-
modifiedHistory.push({ role: "user", text: `${thinkingLevel != "Fast" ? `${modelName.toLowerCase().startsWith("gemma") ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS CRITICAL PRIORITY. DO NOT START A RESPONSE WITHOUT <think> ... </think>**\n" : ""}` : ""}[STEERING HINT]: ${hint}` });
|
|
6201
|
+
modifiedHistory.push({ role: "user", text: `${thinkingLevel != "Fast" && aiProvider === "Google" ? `${modelName.toLowerCase().startsWith("gemma") ? "[SYSTEM] **STRICTLY FOLLOW THINKING POLICY AS CRITICAL PRIORITY. DO NOT START A RESPONSE WITHOUT <think> ... </think>**\n" : ""}` : ""}[STEERING HINT]: ${hint}` });
|
|
5907
6202
|
}
|
|
5908
6203
|
yield { type: "status", content: "Steering Hint Injected." };
|
|
5909
6204
|
}
|
|
@@ -5961,11 +6256,14 @@ ${thinkingLevel != "Fast" ? `${modelName.toLowerCase().startsWith("gemma") ? "[S
|
|
|
5961
6256
|
throw new Error("Error: Quota Exausted for Agent");
|
|
5962
6257
|
}
|
|
5963
6258
|
targetModel = modelName;
|
|
6259
|
+
if (aiProvider === "DeepSeek" && thinkingLevel === "Fast") {
|
|
6260
|
+
targetModel = "deepseek-chat";
|
|
6261
|
+
}
|
|
5964
6262
|
if (retryCount === MAX_RETRIES - 1) {
|
|
5965
|
-
targetModel = "gemini-3-flash-preview";
|
|
6263
|
+
targetModel = aiProvider === "DeepSeek" ? "deepseek-v4-flash" : "gemini-3-flash-preview";
|
|
5966
6264
|
yield { type: "model_update", content: "Trying with fallback model" };
|
|
5967
6265
|
} else if (retryCount === MAX_RETRIES) {
|
|
5968
|
-
targetModel = "gemini-3.5-flash";
|
|
6266
|
+
targetModel = aiProvider === "DeepSeek" ? "deepseek-v4-pro" : "gemini-3.5-flash";
|
|
5969
6267
|
yield { type: "model_update", content: "Trying with fallback model" };
|
|
5970
6268
|
} else if (retryCount > 12 && retryCount < MAX_RETRIES - 2 && settings.apiKey !== "custom") {
|
|
5971
6269
|
targetModel = "gemma-4-31b-it";
|
|
@@ -5973,12 +6271,12 @@ ${thinkingLevel != "Fast" ? `${modelName.toLowerCase().startsWith("gemma") ? "[S
|
|
|
5973
6271
|
} else if (retryCount > 0) {
|
|
5974
6272
|
yield { type: "model_update", content: null };
|
|
5975
6273
|
}
|
|
5976
|
-
currentSystemInstruction = getSystemInstruction(profile, !(targetModel || "gemma").toLowerCase().startsWith("gemma") ? "GEM" : thinkingLevel, mode, systemSettings, isMemoryEnabled, isFirstPrompt);
|
|
6274
|
+
currentSystemInstruction = getSystemInstruction(profile, !(targetModel || "gemma").toLowerCase().startsWith("gemma") ? "GEM" : thinkingLevel, mode, systemSettings, isMemoryEnabled, isFirstPrompt, aiProvider, isMultiModal);
|
|
5977
6275
|
const isGemma = modelName && modelName.toLowerCase().startsWith("gemma");
|
|
5978
6276
|
const lastUserMsg = contents[contents.length - 1];
|
|
5979
6277
|
if (isGemma) {
|
|
5980
6278
|
const jitInstruction = `
|
|
5981
|
-
[SYSTEM] Tool result received. Analyze output and proceed with your turn${thinkingLevel != "Fast" ? `. **STRICTLY MAINTAIN THINKING POLICY. DO NOT START A RESPONSE WITHOUT <think> ... </think>}**` : ""}`;
|
|
6279
|
+
[SYSTEM] Tool result received. Analyze output and proceed with your turn${thinkingLevel != "Fast" && aiProvider === "Google" ? `. **STRICTLY MAINTAIN THINKING POLICY. DO NOT START A RESPONSE WITHOUT <think> ... </think>}**` : ""}`;
|
|
5982
6280
|
if (lastUserMsg && lastUserMsg.role === "user" && lastUserMsg.parts?.[0]?.text?.startsWith("[TOOL RESULT]")) {
|
|
5983
6281
|
lastUserMsg.parts[0].text += jitInstruction;
|
|
5984
6282
|
}
|
|
@@ -5992,57 +6290,79 @@ ${thinkingLevel != "Fast" ? `${modelName.toLowerCase().startsWith("gemma") ? "[S
|
|
|
5992
6290
|
}
|
|
5993
6291
|
}
|
|
5994
6292
|
let activeContents = contents;
|
|
5995
|
-
|
|
5996
|
-
|
|
5997
|
-
|
|
5998
|
-
|
|
5999
|
-
|
|
6000
|
-
|
|
6001
|
-
|
|
6002
|
-
|
|
6003
|
-
|
|
6004
|
-
|
|
6005
|
-
|
|
6006
|
-
|
|
6007
|
-
|
|
6008
|
-
|
|
6009
|
-
|
|
6010
|
-
|
|
6011
|
-
|
|
6012
|
-
|
|
6013
|
-
|
|
6014
|
-
|
|
6015
|
-
|
|
6016
|
-
|
|
6017
|
-
|
|
6018
|
-
|
|
6019
|
-
|
|
6020
|
-
|
|
6021
|
-
|
|
6022
|
-
|
|
6023
|
-
|
|
6024
|
-
|
|
6025
|
-
|
|
6026
|
-
}
|
|
6027
|
-
|
|
6028
|
-
|
|
6029
|
-
|
|
6030
|
-
|
|
6031
|
-
|
|
6032
|
-
|
|
6033
|
-
|
|
6034
|
-
|
|
6035
|
-
|
|
6036
|
-
|
|
6293
|
+
if (aiProvider === "OpenRouter") {
|
|
6294
|
+
stream = getOpenRouterStream(
|
|
6295
|
+
settings.apiKey,
|
|
6296
|
+
targetModel,
|
|
6297
|
+
activeContents,
|
|
6298
|
+
currentSystemInstruction,
|
|
6299
|
+
thinkingLevel,
|
|
6300
|
+
mode,
|
|
6301
|
+
isMultiModal
|
|
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
|
+
);
|
|
6313
|
+
} else {
|
|
6314
|
+
stream = await client.models.generateContentStream({
|
|
6315
|
+
model: targetModel || "gemma-4-31b-it",
|
|
6316
|
+
contents: activeContents,
|
|
6317
|
+
config: {
|
|
6318
|
+
systemInstruction: currentSystemInstruction,
|
|
6319
|
+
temperature: mode === "Flux" ? 1 : 1.4,
|
|
6320
|
+
maxOutputTokens: 32768,
|
|
6321
|
+
mediaResolution: "MEDIA_RESOLUTION_MEDIUM",
|
|
6322
|
+
safetySettings: [
|
|
6323
|
+
{ category: HarmCategory.HARM_CATEGORY_HARASSMENT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
6324
|
+
{ category: HarmCategory.HARM_CATEGORY_HATE_SPEECH, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
6325
|
+
{ category: HarmCategory.HARM_CATEGORY_SEXUALLY_EXPLICIT, threshold: HarmBlockThreshold.BLOCK_NONE },
|
|
6326
|
+
{ category: HarmCategory.HARM_CATEGORY_DANGEROUS_CONTENT, threshold: HarmBlockThreshold.BLOCK_NONE }
|
|
6327
|
+
],
|
|
6328
|
+
thinkingConfig: (() => {
|
|
6329
|
+
const modelLower = (targetModel || "").toLowerCase();
|
|
6330
|
+
const isGemma4 = modelLower.includes("gemma-4") || modelLower.startsWith("gemma");
|
|
6331
|
+
const isGemini3 = modelLower.includes("gemini-3");
|
|
6332
|
+
if (isGemma4 || isGemini3) {
|
|
6333
|
+
if (isGemma4) {
|
|
6334
|
+
return { includeThoughts: false, thinkingLevel: ThinkingLevel.MINIMAL };
|
|
6335
|
+
}
|
|
6336
|
+
return {
|
|
6337
|
+
includeThoughts: true,
|
|
6338
|
+
thinkingLevel: {
|
|
6339
|
+
"Fast": modelLower.includes("pro") ? ThinkingLevel.LOW : ThinkingLevel.MINIMAL,
|
|
6340
|
+
"Low": ThinkingLevel.LOW,
|
|
6341
|
+
"Medium": ThinkingLevel.MEDIUM,
|
|
6342
|
+
"High": ThinkingLevel.HIGH,
|
|
6343
|
+
"xHigh": ThinkingLevel.HIGH
|
|
6344
|
+
}[thinkingLevel] || ThinkingLevel.MEDIUM
|
|
6345
|
+
};
|
|
6346
|
+
} else {
|
|
6347
|
+
const budget = {
|
|
6348
|
+
"Fast": 0,
|
|
6349
|
+
"Low": 512,
|
|
6350
|
+
"Medium": 2048,
|
|
6351
|
+
"High": 16384,
|
|
6352
|
+
"xHigh": 24576
|
|
6353
|
+
}[thinkingLevel] || 2048;
|
|
6354
|
+
if (budget === 0) {
|
|
6355
|
+
return { includeThoughts: false };
|
|
6356
|
+
}
|
|
6357
|
+
return {
|
|
6358
|
+
includeThoughts: true,
|
|
6359
|
+
thinkingBudget: budget
|
|
6360
|
+
};
|
|
6037
6361
|
}
|
|
6038
|
-
|
|
6039
|
-
|
|
6040
|
-
|
|
6041
|
-
|
|
6042
|
-
}
|
|
6043
|
-
})()
|
|
6044
|
-
}
|
|
6045
|
-
});
|
|
6362
|
+
})()
|
|
6363
|
+
}
|
|
6364
|
+
});
|
|
6365
|
+
}
|
|
6046
6366
|
turnText = "";
|
|
6047
6367
|
lastToolSniffed = null;
|
|
6048
6368
|
lastToolEventTime = null;
|
|
@@ -6595,7 +6915,9 @@ ${boxBottom}` };
|
|
|
6595
6915
|
toolCallPointer++;
|
|
6596
6916
|
}
|
|
6597
6917
|
}
|
|
6598
|
-
|
|
6918
|
+
if (chunk.usageMetadata) {
|
|
6919
|
+
lastUsage = chunk.usageMetadata;
|
|
6920
|
+
}
|
|
6599
6921
|
if (lastUsage) {
|
|
6600
6922
|
yield { type: "liveTokens", content: lastUsage.totalTokenCount };
|
|
6601
6923
|
}
|
|
@@ -6781,7 +7103,7 @@ Error Log can be found in ${path16.join(LOGS_DIR, "agent", "error.log")}`);
|
|
|
6781
7103
|
const shouldContinue = toolCallPointer > 0;
|
|
6782
7104
|
yield { type: "status", content: "Working..." };
|
|
6783
7105
|
const cleanedTurnText = contextSafeReplace(turnText, /\[\s*(turn\s*:)?\s*(continue|finish)\s*\]/gi, "").trim();
|
|
6784
|
-
let isActuallyFinished = hasFinish
|
|
7106
|
+
let isActuallyFinished = hasFinish || !shouldContinue;
|
|
6785
7107
|
if (isActuallyFinished) {
|
|
6786
7108
|
const fullAgentTextRaw = fullAgentResponseChunks.join("\n");
|
|
6787
7109
|
const cleanedFullResponse = fullAgentTextRaw.replace(/(?:<think>|\[think\])[\s\S]*?(?:<\/think>|\[\/think\])/g, "").trim();
|
|
@@ -7460,6 +7782,8 @@ function App({ args = [] }) {
|
|
|
7460
7782
|
};
|
|
7461
7783
|
}, [stdout]);
|
|
7462
7784
|
const [thinkingLevel, setThinkingLevel] = useState10("Medium");
|
|
7785
|
+
const [aiProvider, setAiProvider] = useState10("Google");
|
|
7786
|
+
const [setupStep, setSetupStep] = useState10(0);
|
|
7463
7787
|
const [latestVer, setLatestVer] = useState10(null);
|
|
7464
7788
|
const [showFullThinking, setShowFullThinking] = useState10(false);
|
|
7465
7789
|
const [activeModel, setActiveModel] = useState10("gemma-4-31b-it");
|
|
@@ -7495,44 +7819,63 @@ function App({ args = [] }) {
|
|
|
7495
7819
|
const [tick, setTick] = useState10(0);
|
|
7496
7820
|
const isFirstRender = useRef3(true);
|
|
7497
7821
|
const isSecondRender = useRef3(true);
|
|
7822
|
+
const isThirdRender = useRef3(true);
|
|
7498
7823
|
useEffect7(() => {
|
|
7824
|
+
if (!apiKey) return;
|
|
7499
7825
|
if (isFirstRender.current) {
|
|
7500
7826
|
isFirstRender.current = false;
|
|
7501
7827
|
setTimeout(() => {
|
|
7502
7828
|
isSecondRender.current = false;
|
|
7829
|
+
setTimeout(() => {
|
|
7830
|
+
isThirdRender.current = false;
|
|
7831
|
+
}, 1e3);
|
|
7503
7832
|
}, 2e3);
|
|
7504
7833
|
return;
|
|
7505
7834
|
}
|
|
7506
7835
|
if (isSecondRender.current) {
|
|
7507
7836
|
return;
|
|
7508
7837
|
}
|
|
7838
|
+
if (isThirdRender.current) {
|
|
7839
|
+
return;
|
|
7840
|
+
}
|
|
7509
7841
|
const s = emojiSpace(2);
|
|
7842
|
+
let defaultModel = "";
|
|
7843
|
+
let modelDisplayName = "";
|
|
7510
7844
|
if (apiTier === "Free") {
|
|
7511
|
-
|
|
7512
|
-
|
|
7513
|
-
|
|
7514
|
-
|
|
7515
|
-
|
|
7516
|
-
|
|
7517
|
-
|
|
7518
|
-
|
|
7519
|
-
|
|
7520
|
-
|
|
7521
|
-
});
|
|
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
|
+
}
|
|
7522
7855
|
} else {
|
|
7523
|
-
|
|
7524
|
-
|
|
7525
|
-
|
|
7526
|
-
|
|
7527
|
-
|
|
7528
|
-
|
|
7529
|
-
|
|
7530
|
-
|
|
7531
|
-
|
|
7532
|
-
|
|
7533
|
-
});
|
|
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
|
+
}
|
|
7534
7866
|
}
|
|
7535
|
-
|
|
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]);
|
|
7536
7879
|
const terminalEnv = useMemo2(() => {
|
|
7537
7880
|
const isIDE = process.env.TERM_PROGRAM === "vscode" || !!process.env.VSC_TERMINAL_URL || !!process.env.INTELLIJ_TERMINAL_COMMAND_BLOCKS;
|
|
7538
7881
|
return {
|
|
@@ -7717,6 +8060,11 @@ function App({ args = [] }) {
|
|
|
7717
8060
|
} else if (activeView !== "chat" && activeView !== "settings") {
|
|
7718
8061
|
setActiveView("chat");
|
|
7719
8062
|
} else {
|
|
8063
|
+
if (!apiKey && setupStep === 1) {
|
|
8064
|
+
setSetupStep(0);
|
|
8065
|
+
setTempKey("");
|
|
8066
|
+
return;
|
|
8067
|
+
}
|
|
7720
8068
|
setEscPressCount((prev) => {
|
|
7721
8069
|
const nextCount = prev + 1;
|
|
7722
8070
|
if (nextCount === 1) {
|
|
@@ -7809,6 +8157,7 @@ function App({ args = [] }) {
|
|
|
7809
8157
|
} else {
|
|
7810
8158
|
setThinkingLevel(saved.thinkingLevel);
|
|
7811
8159
|
}
|
|
8160
|
+
setAiProvider(saved.aiProvider || "Google");
|
|
7812
8161
|
persistedModelRef.current = saved.activeModel;
|
|
7813
8162
|
if (parsedArgs.model) {
|
|
7814
8163
|
setActiveModel(parsedArgs.model);
|
|
@@ -7919,6 +8268,7 @@ function App({ args = [] }) {
|
|
|
7919
8268
|
saveSettings({
|
|
7920
8269
|
mode,
|
|
7921
8270
|
thinkingLevel,
|
|
8271
|
+
aiProvider,
|
|
7922
8272
|
activeModel: modelToSave || activeModel,
|
|
7923
8273
|
showFullThinking,
|
|
7924
8274
|
systemSettings,
|
|
@@ -7927,16 +8277,26 @@ function App({ args = [] }) {
|
|
|
7927
8277
|
apiTier
|
|
7928
8278
|
});
|
|
7929
8279
|
}
|
|
7930
|
-
}, [mode, thinkingLevel, activeModel, showFullThinking, systemSettings, profileData, imageSettings, isInitializing, parsedArgs, apiTier]);
|
|
8280
|
+
}, [mode, thinkingLevel, aiProvider, activeModel, showFullThinking, systemSettings, profileData, imageSettings, isInitializing, parsedArgs, apiTier]);
|
|
7931
8281
|
const handleSetup = async (val) => {
|
|
7932
8282
|
const key = val.trim();
|
|
7933
|
-
|
|
8283
|
+
let minLength = 30;
|
|
8284
|
+
if (aiProvider === "OpenRouter") minLength = 10;
|
|
8285
|
+
if (aiProvider === "DeepSeek") minLength = 20;
|
|
8286
|
+
if (key.length >= minLength) {
|
|
7934
8287
|
await saveAPIKey(key);
|
|
7935
8288
|
setApiKey(key);
|
|
7936
8289
|
initAI(key);
|
|
7937
|
-
|
|
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 }]);
|
|
7938
8298
|
} else {
|
|
7939
|
-
setMessages((prev) => [...prev, { role: "system", text: `\u274C INVALID KEY:
|
|
8299
|
+
setMessages((prev) => [...prev, { role: "system", text: `\u274C INVALID KEY: ${aiProvider} API keys must be at least ${minLength} characters.`, isMeta: true }]);
|
|
7940
8300
|
setTempKey("");
|
|
7941
8301
|
}
|
|
7942
8302
|
};
|
|
@@ -8026,18 +8386,105 @@ function App({ args = [] }) {
|
|
|
8026
8386
|
{
|
|
8027
8387
|
cmd: "/thinking",
|
|
8028
8388
|
desc: "Set AI reasoning depth",
|
|
8029
|
-
subs: [
|
|
8030
|
-
{ cmd: "Fast", desc: "
|
|
8031
|
-
{ cmd: "
|
|
8032
|
-
{ cmd: "
|
|
8033
|
-
|
|
8034
|
-
{ 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" }
|
|
8035
8399
|
]
|
|
8036
8400
|
},
|
|
8037
8401
|
{
|
|
8038
8402
|
cmd: "/model",
|
|
8039
8403
|
desc: "Switch Model for Agent",
|
|
8040
|
-
subs: apiTier === "Free" ? [
|
|
8404
|
+
subs: aiProvider === "OpenRouter" ? apiTier === "Free" ? [
|
|
8405
|
+
{
|
|
8406
|
+
cmd: "google/gemma-4-31b-it:free",
|
|
8407
|
+
desc: "Multimodal"
|
|
8408
|
+
},
|
|
8409
|
+
{
|
|
8410
|
+
cmd: "moonshotai/kimi-k2.6:free",
|
|
8411
|
+
desc: "Multimodal"
|
|
8412
|
+
},
|
|
8413
|
+
{
|
|
8414
|
+
cmd: "qwen/qwen3-coder:free",
|
|
8415
|
+
desc: ""
|
|
8416
|
+
},
|
|
8417
|
+
{
|
|
8418
|
+
cmd: "z-ai/glm-4.5-air:free",
|
|
8419
|
+
desc: ""
|
|
8420
|
+
}
|
|
8421
|
+
] : [
|
|
8422
|
+
{
|
|
8423
|
+
cmd: "google/gemini-3.5-flash",
|
|
8424
|
+
desc: "Multimodal"
|
|
8425
|
+
},
|
|
8426
|
+
{
|
|
8427
|
+
cmd: "qwen/qwen3.7-plus",
|
|
8428
|
+
desc: "Multimodal"
|
|
8429
|
+
},
|
|
8430
|
+
{
|
|
8431
|
+
cmd: "minimax/minimax-m3",
|
|
8432
|
+
desc: "Multimodal"
|
|
8433
|
+
},
|
|
8434
|
+
{
|
|
8435
|
+
cmd: "anthropic/claude-sonnet-4.5",
|
|
8436
|
+
desc: "Multimodal"
|
|
8437
|
+
},
|
|
8438
|
+
{
|
|
8439
|
+
cmd: "anthropic/claude-opus-4.6",
|
|
8440
|
+
desc: "Multimodal"
|
|
8441
|
+
},
|
|
8442
|
+
{
|
|
8443
|
+
cmd: "anthropic/claude-opus-4.8",
|
|
8444
|
+
desc: "Multimodal"
|
|
8445
|
+
},
|
|
8446
|
+
{
|
|
8447
|
+
cmd: "deepseek/deepseek-v4-pro",
|
|
8448
|
+
desc: ""
|
|
8449
|
+
},
|
|
8450
|
+
{
|
|
8451
|
+
cmd: "deepseek/deepseek-v4-flash",
|
|
8452
|
+
desc: ""
|
|
8453
|
+
},
|
|
8454
|
+
{
|
|
8455
|
+
cmd: "xiaomi/mimo-v2.5-pro",
|
|
8456
|
+
desc: ""
|
|
8457
|
+
},
|
|
8458
|
+
{
|
|
8459
|
+
cmd: "z-ai/glm-5",
|
|
8460
|
+
desc: ""
|
|
8461
|
+
},
|
|
8462
|
+
{
|
|
8463
|
+
cmd: "openai/gpt-5.2-codex",
|
|
8464
|
+
desc: "Multimodal"
|
|
8465
|
+
},
|
|
8466
|
+
{
|
|
8467
|
+
cmd: "openai/gpt-5.2-pro",
|
|
8468
|
+
desc: "Multimodal"
|
|
8469
|
+
},
|
|
8470
|
+
{
|
|
8471
|
+
cmd: "openai/gpt-5.5-pro",
|
|
8472
|
+
desc: "Multimodal"
|
|
8473
|
+
},
|
|
8474
|
+
{
|
|
8475
|
+
cmd: "moonshotai/kimi-k2.6",
|
|
8476
|
+
desc: "Multimodal"
|
|
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
|
+
}
|
|
8487
|
+
] : apiTier === "Free" ? [
|
|
8041
8488
|
{
|
|
8042
8489
|
cmd: "gemma-4-31b-it",
|
|
8043
8490
|
desc: "Standard Default"
|
|
@@ -8388,7 +8835,7 @@ ${hintText}`, color: "magenta" }];
|
|
|
8388
8835
|
case "/model": {
|
|
8389
8836
|
if (parts[1]) {
|
|
8390
8837
|
const mod = parts.slice(1).join(" ");
|
|
8391
|
-
if (mod === "gemma-4-31b-it" && apiTier !== "Free") {
|
|
8838
|
+
if (mod === "gemma-4-31b-it" && apiTier !== "Free" && aiProvider === "Google") {
|
|
8392
8839
|
setMessages((prev) => {
|
|
8393
8840
|
setCompletedIndex(prev.length + 1);
|
|
8394
8841
|
return [...prev, {
|
|
@@ -8697,6 +9144,9 @@ ${timestamp}` };
|
|
|
8697
9144
|
text
|
|
8698
9145
|
});
|
|
8699
9146
|
});
|
|
9147
|
+
const modelCmd = COMMANDS.find((c) => c.cmd === "/model");
|
|
9148
|
+
const currentModelObj = modelCmd?.subs?.find((s) => s.cmd === activeModel);
|
|
9149
|
+
const isMultiModal = currentModelObj?.desc?.toLowerCase().includes("multimodal");
|
|
8700
9150
|
const stream = getAIStream(
|
|
8701
9151
|
activeModel,
|
|
8702
9152
|
cleanHistoryForAI,
|
|
@@ -8708,6 +9158,9 @@ ${timestamp}` };
|
|
|
8708
9158
|
janitorModel,
|
|
8709
9159
|
sessionStats,
|
|
8710
9160
|
chatId,
|
|
9161
|
+
isMultiModal,
|
|
9162
|
+
aiProvider,
|
|
9163
|
+
apiKey,
|
|
8711
9164
|
cols: terminalSize.columns - 6,
|
|
8712
9165
|
rows: 30,
|
|
8713
9166
|
onExecStart: (cmd) => {
|
|
@@ -8877,7 +9330,7 @@ Selection: ${val}`,
|
|
|
8877
9330
|
setIsProcessing(false);
|
|
8878
9331
|
hasFiredJanitor = true;
|
|
8879
9332
|
runJanitorTask(
|
|
8880
|
-
{ profile: profileData, thinkingLevel, mode, janitorModel, chatId, systemSettings, sessionStats },
|
|
9333
|
+
{ profile: profileData, thinkingLevel, mode, janitorModel, chatId, systemSettings, sessionStats, aiProvider, apiKey },
|
|
8881
9334
|
packet.data.agentText,
|
|
8882
9335
|
packet.data.fullAgentTextRaw,
|
|
8883
9336
|
packet.data.history,
|
|
@@ -9199,7 +9652,8 @@ Selection: ${val}`,
|
|
|
9199
9652
|
setInputConfig,
|
|
9200
9653
|
saveSettings,
|
|
9201
9654
|
quotas,
|
|
9202
|
-
setMessages
|
|
9655
|
+
setMessages,
|
|
9656
|
+
aiProvider
|
|
9203
9657
|
}
|
|
9204
9658
|
);
|
|
9205
9659
|
case "apiTier":
|
|
@@ -9677,7 +10131,20 @@ Selection: ${val}`,
|
|
|
9677
10131
|
showFullThinking,
|
|
9678
10132
|
columns: Math.max(20, (stdout?.columns || 80) - 1)
|
|
9679
10133
|
}
|
|
9680
|
-
), activeCommand && /* @__PURE__ */ React13.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(TerminalBox, { command: activeCommand, output: execOutput, isFocused: isTerminalFocused, isPty: isActiveCommandPty }))), isInitializing ? /* @__PURE__ */ React13.createElement(Box13, { borderStyle: "double", borderColor: "magenta", padding: 1, flexShrink: 0 }, /* @__PURE__ */ React13.createElement(Text13, { color: "magenta" }, "\u{1F30A} Starting Flux Flow...")) : !apiKey ? /* @__PURE__ */ React13.createElement(Box13, { borderStyle: "round", borderColor: "gray", padding: 0, flexDirection: "column", flexShrink: 0, width: "100%" }, /* @__PURE__ */ React13.createElement(Box13, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React13.createElement(Text13, { color: "yellow", bold: true }, "\u{1F511}", emojiSpace(2), "API KEY REQUIRED")), /* @__PURE__ */ React13.createElement(Box13, { paddingX: 1, flexDirection: "column" }, /* @__PURE__ */ React13.createElement(
|
|
10134
|
+
), activeCommand && /* @__PURE__ */ React13.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(TerminalBox, { command: activeCommand, output: execOutput, isFocused: isTerminalFocused, isPty: isActiveCommandPty }))), isInitializing ? /* @__PURE__ */ React13.createElement(Box13, { borderStyle: "double", borderColor: "magenta", padding: 1, flexShrink: 0 }, /* @__PURE__ */ React13.createElement(Text13, { color: "magenta" }, "\u{1F30A} Starting Flux Flow...")) : !apiKey ? /* @__PURE__ */ React13.createElement(Box13, { borderStyle: "round", borderColor: "gray", padding: 0, flexDirection: "column", flexShrink: 0, width: "100%" }, /* @__PURE__ */ React13.createElement(Box13, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React13.createElement(Text13, { color: "yellow", bold: true }, "\u{1F511}", emojiSpace(2), "API KEY REQUIRED")), /* @__PURE__ */ React13.createElement(Box13, { paddingX: 1, flexDirection: "column" }, setupStep === 0 ? /* @__PURE__ */ React13.createElement(React13.Fragment, null, /* @__PURE__ */ React13.createElement(Text13, null, "Select your Preferred Provider:"), /* @__PURE__ */ React13.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(
|
|
10135
|
+
CommandMenu,
|
|
10136
|
+
{
|
|
10137
|
+
items: [
|
|
10138
|
+
{ label: "Google (Free/Paid)", value: "Google" },
|
|
10139
|
+
{ label: "DeepSeek (Paid)", value: "DeepSeek" },
|
|
10140
|
+
{ label: "OpenRouter (Free/Paid) [EXPERIMENTAL]", value: "OpenRouter" }
|
|
10141
|
+
],
|
|
10142
|
+
onSelect: (item) => {
|
|
10143
|
+
setAiProvider(item.value);
|
|
10144
|
+
setSetupStep(1);
|
|
10145
|
+
}
|
|
10146
|
+
}
|
|
10147
|
+
))) : /* @__PURE__ */ React13.createElement(React13.Fragment, null, /* @__PURE__ */ React13.createElement(Text13, null, "Please enter your ", aiProvider, " API Key to initialize the agent (If billing is enabled set Tier to paid in /settings \u2192 other \u2192 API Tier)."), /* @__PURE__ */ React13.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text13, { color: "cyan", bold: true }, "\u{1F4A0} "), /* @__PURE__ */ React13.createElement(
|
|
9681
10148
|
TextInput4,
|
|
9682
10149
|
{
|
|
9683
10150
|
value: tempKey,
|
|
@@ -9685,7 +10152,7 @@ Selection: ${val}`,
|
|
|
9685
10152
|
onSubmit: handleSetup,
|
|
9686
10153
|
mask: "*"
|
|
9687
10154
|
}
|
|
9688
|
-
))), /* @__PURE__ */ React13.createElement(Box13, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text13, { color: "gray", dimColor: true, italic: true }, "(Press Enter to confirm and initialize)"))) : renderActiveView(), confirmExit && /* @__PURE__ */ React13.createElement(Box13, { borderStyle: "round", borderColor: "red", paddingX: 2, marginY: 0, width: "100%" }, /* @__PURE__ */ React13.createElement(Text13, { color: "red", bold: true }, "\u{1F534} EXIT CONFIRMATION: "), /* @__PURE__ */ React13.createElement(Text13, { color: "white" }, "Press "), /* @__PURE__ */ React13.createElement(Text13, { color: "red", bold: true }, "CTRL + C"), /* @__PURE__ */ React13.createElement(Text13, { color: "white" }, " again to exit (", exitCountdown, "s). Press "), /* @__PURE__ */ React13.createElement(Text13, { color: "cyan", bold: true }, "ESC"), /* @__PURE__ */ React13.createElement(Text13, { color: "white" }, " to cancel.")), /* @__PURE__ */ React13.createElement(Box13, { flexShrink: 0, width: "100%" }, /* @__PURE__ */ React13.createElement(
|
|
10155
|
+
)), /* @__PURE__ */ React13.createElement(Box13, { marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text13, { color: "gray", italic: true }, "(Press ESC to go back to provider selection)")))), /* @__PURE__ */ React13.createElement(Box13, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React13.createElement(Text13, { color: "gray", dimColor: true, italic: true }, setupStep === 0 ? "(Use arrows to select and Enter to confirm)" : "(Press Enter to confirm and initialize)"))) : renderActiveView(), confirmExit && /* @__PURE__ */ React13.createElement(Box13, { borderStyle: "round", borderColor: "red", paddingX: 2, marginY: 0, width: "100%" }, /* @__PURE__ */ React13.createElement(Text13, { color: "red", bold: true }, "\u{1F534} EXIT CONFIRMATION: "), /* @__PURE__ */ React13.createElement(Text13, { color: "white" }, "Press "), /* @__PURE__ */ React13.createElement(Text13, { color: "red", bold: true }, "CTRL + C"), /* @__PURE__ */ React13.createElement(Text13, { color: "white" }, " again to exit (", exitCountdown, "s). Press "), /* @__PURE__ */ React13.createElement(Text13, { color: "cyan", bold: true }, "ESC"), /* @__PURE__ */ React13.createElement(Text13, { color: "white" }, " to cancel.")), /* @__PURE__ */ React13.createElement(Box13, { flexShrink: 0, width: "100%" }, /* @__PURE__ */ React13.createElement(
|
|
9689
10156
|
StatusBar_default,
|
|
9690
10157
|
{
|
|
9691
10158
|
mode,
|
|
@@ -9733,7 +10200,7 @@ Selection: ${val}`,
|
|
|
9733
10200
|
paddingX: 1
|
|
9734
10201
|
},
|
|
9735
10202
|
/* @__PURE__ */ React13.createElement(Box13, { width: 3 }, /* @__PURE__ */ React13.createElement(Text13, { color: isActive ? "cyan" : "gray", bold: isActive }, isActive ? " \u276F" : " ")),
|
|
9736
|
-
/* @__PURE__ */ React13.createElement(Box13, { width:
|
|
10203
|
+
/* @__PURE__ */ React13.createElement(Box13, { width: 55 }, /* @__PURE__ */ React13.createElement(
|
|
9737
10204
|
Text13,
|
|
9738
10205
|
{
|
|
9739
10206
|
color: isGemmaDisabled ? "gray" : isActive ? "yellow" : "white",
|