fluxflow-cli 1.20.0 → 1.21.1
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 +470 -134
- 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:
|
|
@@ -1857,6 +1859,8 @@ function SettingsMenu({
|
|
|
1857
1859
|
setEditValue(systemSettings.autoDisallowCommands || "");
|
|
1858
1860
|
} else if (item.value === "apiTier") {
|
|
1859
1861
|
setActiveView("apiTier");
|
|
1862
|
+
} else if (item.value === "aiProvider") {
|
|
1863
|
+
setActiveView("selectProvider");
|
|
1860
1864
|
} else if (item.value === "autoDelete") {
|
|
1861
1865
|
const options = ["1d", "7d", "30d"];
|
|
1862
1866
|
const currentIndex = options.indexOf(systemSettings.autoDeleteHistory || "30d");
|
|
@@ -1948,7 +1952,7 @@ function SettingsMenu({
|
|
|
1948
1952
|
},
|
|
1949
1953
|
isSelected ? "\u276F " : " ",
|
|
1950
1954
|
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 },
|
|
1955
|
+
), !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
1956
|
TextInput,
|
|
1953
1957
|
{
|
|
1954
1958
|
value: editValue,
|
|
@@ -2281,18 +2285,20 @@ var init_paths = __esm({
|
|
|
2281
2285
|
var secrets_exports = {};
|
|
2282
2286
|
__export(secrets_exports, {
|
|
2283
2287
|
getAPIKey: () => getAPIKey,
|
|
2288
|
+
getProviderAPIKey: () => getProviderAPIKey,
|
|
2284
2289
|
getSearchSecrets: () => getSearchSecrets,
|
|
2285
2290
|
getSecret: () => getSecret,
|
|
2286
2291
|
removeAPIKey: () => removeAPIKey,
|
|
2287
2292
|
removeSecret: () => removeSecret,
|
|
2288
2293
|
saveAPIKey: () => saveAPIKey,
|
|
2294
|
+
saveProviderAPIKey: () => saveProviderAPIKey,
|
|
2289
2295
|
saveSearchId: () => saveSearchId,
|
|
2290
2296
|
saveSearchKey: () => saveSearchKey,
|
|
2291
2297
|
saveSecret: () => saveSecret
|
|
2292
2298
|
});
|
|
2293
2299
|
import fs3 from "fs-extra";
|
|
2294
2300
|
import path3 from "path";
|
|
2295
|
-
var SECRET_FILE, getAPIKey, getSecret, saveSecret, getSearchSecrets, saveAPIKey, saveSearchKey, saveSearchId, removeSecret, removeAPIKey;
|
|
2301
|
+
var SECRET_FILE, getAPIKey, getProviderAPIKey, saveProviderAPIKey, getSecret, saveSecret, getSearchSecrets, saveAPIKey, saveSearchKey, saveSearchId, removeSecret, removeAPIKey;
|
|
2296
2302
|
var init_secrets = __esm({
|
|
2297
2303
|
"src/utils/secrets.js"() {
|
|
2298
2304
|
init_crypto();
|
|
@@ -2306,6 +2312,26 @@ var init_secrets = __esm({
|
|
|
2306
2312
|
}
|
|
2307
2313
|
return null;
|
|
2308
2314
|
};
|
|
2315
|
+
getProviderAPIKey = async (provider) => {
|
|
2316
|
+
try {
|
|
2317
|
+
const secrets = readEncryptedJson(SECRET_FILE, {});
|
|
2318
|
+
if (provider === "Google") return secrets.GOOGLE_API_KEY || secrets.API_KEY || null;
|
|
2319
|
+
if (provider === "DeepSeek") return secrets.DEEPSEEK_API_KEY || null;
|
|
2320
|
+
if (provider === "OpenRouter") return secrets.OPENROUTER_API_KEY || null;
|
|
2321
|
+
} catch (e) {
|
|
2322
|
+
}
|
|
2323
|
+
return null;
|
|
2324
|
+
};
|
|
2325
|
+
saveProviderAPIKey = async (provider, key) => {
|
|
2326
|
+
if (provider === "Google") {
|
|
2327
|
+
await saveSecret("GOOGLE_API_KEY", key);
|
|
2328
|
+
await saveSecret("API_KEY", key);
|
|
2329
|
+
} else if (provider === "DeepSeek") {
|
|
2330
|
+
await saveSecret("DEEPSEEK_API_KEY", key);
|
|
2331
|
+
} else if (provider === "OpenRouter") {
|
|
2332
|
+
await saveSecret("OPENROUTER_API_KEY", key);
|
|
2333
|
+
}
|
|
2334
|
+
};
|
|
2309
2335
|
getSecret = async (key) => {
|
|
2310
2336
|
try {
|
|
2311
2337
|
const secrets = readEncryptedJson(SECRET_FILE, {});
|
|
@@ -2465,7 +2491,7 @@ Identity: Flux Flow (by Kushal Roy Chowdhury). Conversational, Sassy${mode === "
|
|
|
2465
2491
|
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
2492
|
|
|
2467
2493
|
-- AGENT LOOP RULES (PRIORITY: HIGH) --
|
|
2468
|
-
- **MANDATORY: MUST END WITH [turn: continue] to CONTINUE loop OR [turn: finish] to END loop**
|
|
2494
|
+
- **MANDATORY: MUST END WITH [turn: continue] to CONTINUE loop OR [turn: finish] to END loop** \u2190 IMPORTANT EVERY RESPONSE
|
|
2469
2495
|
- Tool Called? No post tool chat until [turn: continue]
|
|
2470
2496
|
- NEVER USE [turn: continue] [turn:finish] together
|
|
2471
2497
|
|
|
@@ -2480,7 +2506,7 @@ CRITICAL THINKING POLICY
|
|
|
2480
2506
|
- ALWAYS use <think> ... </think> before responding, even with simple queries/greetings
|
|
2481
2507
|
- ${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
2508
|
` : ""}` : ""}` : ``}
|
|
2483
|
-
${TOOL_PROTOCOL(mode, osDetected, isMultiModal, aiProvider)}
|
|
2509
|
+
${TOOL_PROTOCOL(mode, osDetected, aiProvider.toLowerCase() === "deepseek" ? false : isMultiModal, aiProvider)}
|
|
2484
2510
|
${projectContextBlock}
|
|
2485
2511
|
-- MEMORY RULES --
|
|
2486
2512
|
- Memory: ${isMemoryEnabled ? "Subtly Personalize. Auto Saves" : "OFF. Decline Remembering Memories"}
|
|
@@ -4923,7 +4949,7 @@ var init_tools = __esm({
|
|
|
4923
4949
|
import { GoogleGenAI, ThinkingLevel, HarmBlockThreshold, HarmCategory } from "@google/genai";
|
|
4924
4950
|
import path16 from "path";
|
|
4925
4951
|
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;
|
|
4952
|
+
var client, TERMINATION_SIGNAL, stripAnsi2, fetchWithBackoff, getDeepSeekStream, getOpenRouterStream, signalTermination, TOOL_LABELS2, getToolDetail, runJanitorTask, getActiveToolContext, getContextSafeText, contextSafeReplace, getSanitizedText, detectToolCalls, initAI, generateSimpleContent, consolidatePastMemories, getAIStream;
|
|
4927
4953
|
var init_ai = __esm({
|
|
4928
4954
|
async "src/utils/ai.js"() {
|
|
4929
4955
|
await init_prompts();
|
|
@@ -4954,6 +4980,136 @@ var init_ai = __esm({
|
|
|
4954
4980
|
}
|
|
4955
4981
|
return fetch(url, options);
|
|
4956
4982
|
};
|
|
4983
|
+
getDeepSeekStream = async function* (apiKey, model, contents, systemInstruction, thinkingLevel, mode, isMultiModal) {
|
|
4984
|
+
const messages = [];
|
|
4985
|
+
if (systemInstruction) {
|
|
4986
|
+
messages.push({ role: "system", content: systemInstruction });
|
|
4987
|
+
}
|
|
4988
|
+
for (const content of contents) {
|
|
4989
|
+
const role = content.role === "user" ? "user" : "assistant";
|
|
4990
|
+
const msgContent = [];
|
|
4991
|
+
if (Array.isArray(content.parts)) {
|
|
4992
|
+
for (const part of content.parts) {
|
|
4993
|
+
if (part.text) {
|
|
4994
|
+
msgContent.push({ type: "text", text: part.text });
|
|
4995
|
+
} else if (part.inlineData && isMultiModal) {
|
|
4996
|
+
const mimeType = part.inlineData.mimeType;
|
|
4997
|
+
const data = part.inlineData.data;
|
|
4998
|
+
const isImage = mimeType.startsWith("image/");
|
|
4999
|
+
if (isImage) {
|
|
5000
|
+
msgContent.push({
|
|
5001
|
+
type: "image_url",
|
|
5002
|
+
image_url: {
|
|
5003
|
+
url: `data:${mimeType};base64,${data}`
|
|
5004
|
+
}
|
|
5005
|
+
});
|
|
5006
|
+
}
|
|
5007
|
+
}
|
|
5008
|
+
}
|
|
5009
|
+
} else {
|
|
5010
|
+
const text = content.text || "";
|
|
5011
|
+
if (text) msgContent.push({ type: "text", text });
|
|
5012
|
+
}
|
|
5013
|
+
messages.push({
|
|
5014
|
+
role,
|
|
5015
|
+
content: msgContent.length === 1 && msgContent[0].type === "text" ? msgContent[0].text : msgContent
|
|
5016
|
+
});
|
|
5017
|
+
}
|
|
5018
|
+
const requestPayload = {
|
|
5019
|
+
model,
|
|
5020
|
+
messages,
|
|
5021
|
+
stream: true,
|
|
5022
|
+
stream_options: { include_usage: true },
|
|
5023
|
+
temperature: mode === "Flux" ? 1 : 1.4
|
|
5024
|
+
};
|
|
5025
|
+
if (thinkingLevel !== "Fast") {
|
|
5026
|
+
const reasoningEffortMap = {
|
|
5027
|
+
"Low": "high",
|
|
5028
|
+
"Medium": "high",
|
|
5029
|
+
"High": "high",
|
|
5030
|
+
"xHigh": "max"
|
|
5031
|
+
};
|
|
5032
|
+
requestPayload.reasoning_effort = reasoningEffortMap[thinkingLevel] || "high";
|
|
5033
|
+
requestPayload.extra_body = { thinking: { type: "enabled" } };
|
|
5034
|
+
} else {
|
|
5035
|
+
requestPayload.extra_body = { thinking: { type: "disabled" } };
|
|
5036
|
+
}
|
|
5037
|
+
const response = await fetchWithBackoff("https://api.deepseek.com/chat/completions", {
|
|
5038
|
+
method: "POST",
|
|
5039
|
+
headers: {
|
|
5040
|
+
"Authorization": `Bearer ${apiKey}`,
|
|
5041
|
+
"Content-Type": "application/json"
|
|
5042
|
+
},
|
|
5043
|
+
body: JSON.stringify(requestPayload)
|
|
5044
|
+
});
|
|
5045
|
+
if (!response.ok) {
|
|
5046
|
+
const errData = await response.json().catch(() => ({}));
|
|
5047
|
+
throw new Error(`DeepSeek Error (${response.status}): ${errData.error?.message || response.statusText}`);
|
|
5048
|
+
}
|
|
5049
|
+
const reader = response.body.getReader();
|
|
5050
|
+
const decoder = new TextDecoder();
|
|
5051
|
+
let buffer = "";
|
|
5052
|
+
let pendingParts = [];
|
|
5053
|
+
let latestUsageMetadata = null;
|
|
5054
|
+
let lastFlushTime = Date.now();
|
|
5055
|
+
let hasNewData = false;
|
|
5056
|
+
while (true) {
|
|
5057
|
+
const { done, value } = await reader.read();
|
|
5058
|
+
if (done) {
|
|
5059
|
+
if (hasNewData && (pendingParts.length > 0 || latestUsageMetadata)) {
|
|
5060
|
+
yield {
|
|
5061
|
+
candidates: pendingParts.length > 0 ? [{ content: { parts: pendingParts } }] : [],
|
|
5062
|
+
usageMetadata: latestUsageMetadata
|
|
5063
|
+
};
|
|
5064
|
+
}
|
|
5065
|
+
break;
|
|
5066
|
+
}
|
|
5067
|
+
buffer += decoder.decode(value, { stream: true });
|
|
5068
|
+
const lines = buffer.split("\n");
|
|
5069
|
+
buffer = lines.pop();
|
|
5070
|
+
for (const line of lines) {
|
|
5071
|
+
const cleanLine = line.trim();
|
|
5072
|
+
if (!cleanLine || !cleanLine.startsWith("data: ")) continue;
|
|
5073
|
+
if (cleanLine === "data: [DONE]") break;
|
|
5074
|
+
try {
|
|
5075
|
+
const json = JSON.parse(cleanLine.substring(6));
|
|
5076
|
+
const delta = json.choices?.[0]?.delta;
|
|
5077
|
+
const usage = json.usage;
|
|
5078
|
+
if (usage) {
|
|
5079
|
+
latestUsageMetadata = {
|
|
5080
|
+
totalTokenCount: usage.total_tokens || usage.prompt_tokens + usage.completion_tokens,
|
|
5081
|
+
promptTokenCount: usage.prompt_tokens || 0,
|
|
5082
|
+
candidatesTokenCount: usage.completion_tokens || 0,
|
|
5083
|
+
cachedContentTokenCount: usage.prompt_tokens_details?.cached_tokens || 0,
|
|
5084
|
+
thoughtsTokenCount: usage.completion_tokens_details?.reasoning_tokens || 0
|
|
5085
|
+
};
|
|
5086
|
+
hasNewData = true;
|
|
5087
|
+
}
|
|
5088
|
+
if (delta) {
|
|
5089
|
+
const thought = delta.reasoning_content || null;
|
|
5090
|
+
if (thought) {
|
|
5091
|
+
pendingParts.push({ text: thought, thought: true });
|
|
5092
|
+
hasNewData = true;
|
|
5093
|
+
}
|
|
5094
|
+
if (delta.content) {
|
|
5095
|
+
pendingParts.push({ text: delta.content });
|
|
5096
|
+
hasNewData = true;
|
|
5097
|
+
}
|
|
5098
|
+
}
|
|
5099
|
+
} catch (e) {
|
|
5100
|
+
}
|
|
5101
|
+
}
|
|
5102
|
+
if (Date.now() - lastFlushTime >= 100 && hasNewData) {
|
|
5103
|
+
yield {
|
|
5104
|
+
candidates: pendingParts.length > 0 ? [{ content: { parts: [...pendingParts] } }] : [],
|
|
5105
|
+
usageMetadata: latestUsageMetadata
|
|
5106
|
+
};
|
|
5107
|
+
pendingParts = [];
|
|
5108
|
+
lastFlushTime = Date.now();
|
|
5109
|
+
hasNewData = false;
|
|
5110
|
+
}
|
|
5111
|
+
}
|
|
5112
|
+
};
|
|
4957
5113
|
getOpenRouterStream = async function* (apiKey, model, contents, systemInstruction, thinkingLevel, mode, isMultiModal) {
|
|
4958
5114
|
const messages = [];
|
|
4959
5115
|
if (systemInstruction) {
|
|
@@ -5030,9 +5186,21 @@ var init_ai = __esm({
|
|
|
5030
5186
|
const reader = response.body.getReader();
|
|
5031
5187
|
const decoder = new TextDecoder();
|
|
5032
5188
|
let buffer = "";
|
|
5189
|
+
let pendingParts = [];
|
|
5190
|
+
let latestUsageMetadata = null;
|
|
5191
|
+
let lastFlushTime = Date.now();
|
|
5192
|
+
let hasNewData = false;
|
|
5033
5193
|
while (true) {
|
|
5034
5194
|
const { done, value } = await reader.read();
|
|
5035
|
-
if (done)
|
|
5195
|
+
if (done) {
|
|
5196
|
+
if (hasNewData && (pendingParts.length > 0 || latestUsageMetadata)) {
|
|
5197
|
+
yield {
|
|
5198
|
+
candidates: pendingParts.length > 0 ? [{ content: { parts: pendingParts } }] : [],
|
|
5199
|
+
usageMetadata: latestUsageMetadata
|
|
5200
|
+
};
|
|
5201
|
+
}
|
|
5202
|
+
break;
|
|
5203
|
+
}
|
|
5036
5204
|
buffer += decoder.decode(value, { stream: true });
|
|
5037
5205
|
const lines = buffer.split("\n");
|
|
5038
5206
|
buffer = lines.pop();
|
|
@@ -5044,36 +5212,39 @@ var init_ai = __esm({
|
|
|
5044
5212
|
const json = JSON.parse(cleanLine.substring(6));
|
|
5045
5213
|
const delta = json.choices?.[0]?.delta;
|
|
5046
5214
|
const usage = json.usage;
|
|
5047
|
-
let usageMetadata = null;
|
|
5048
5215
|
if (usage) {
|
|
5049
|
-
|
|
5216
|
+
latestUsageMetadata = {
|
|
5050
5217
|
totalTokenCount: usage.total_tokens || usage.prompt_tokens + usage.completion_tokens,
|
|
5051
5218
|
promptTokenCount: usage.prompt_tokens || 0,
|
|
5052
5219
|
candidatesTokenCount: usage.completion_tokens || 0,
|
|
5053
5220
|
cachedContentTokenCount: usage.prompt_tokens_details?.cached_tokens || 0,
|
|
5054
5221
|
thoughtsTokenCount: usage.completion_tokens_details?.reasoning_tokens || 0
|
|
5055
5222
|
};
|
|
5223
|
+
hasNewData = true;
|
|
5056
5224
|
}
|
|
5057
5225
|
if (delta) {
|
|
5058
5226
|
const thought = delta.reasoning || (delta.reasoning_details ? delta.reasoning_details.map((d) => d.text).join("") : null);
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
};
|
|
5227
|
+
if (thought) {
|
|
5228
|
+
pendingParts.push({ text: thought, thought: true });
|
|
5229
|
+
hasNewData = true;
|
|
5230
|
+
}
|
|
5231
|
+
if (delta.content) {
|
|
5232
|
+
pendingParts.push({ text: delta.content });
|
|
5233
|
+
hasNewData = true;
|
|
5067
5234
|
}
|
|
5068
|
-
} else if (usageMetadata) {
|
|
5069
|
-
yield {
|
|
5070
|
-
candidates: [],
|
|
5071
|
-
usageMetadata
|
|
5072
|
-
};
|
|
5073
5235
|
}
|
|
5074
5236
|
} catch (e) {
|
|
5075
5237
|
}
|
|
5076
5238
|
}
|
|
5239
|
+
if (Date.now() - lastFlushTime >= 100 && hasNewData) {
|
|
5240
|
+
yield {
|
|
5241
|
+
candidates: pendingParts.length > 0 ? [{ content: { parts: [...pendingParts] } }] : [],
|
|
5242
|
+
usageMetadata: latestUsageMetadata
|
|
5243
|
+
};
|
|
5244
|
+
pendingParts = [];
|
|
5245
|
+
lastFlushTime = Date.now();
|
|
5246
|
+
hasNewData = false;
|
|
5247
|
+
}
|
|
5077
5248
|
}
|
|
5078
5249
|
};
|
|
5079
5250
|
signalTermination = () => {
|
|
@@ -5181,6 +5352,20 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
|
|
|
5181
5352
|
const iterator2 = stream[Symbol.asyncIterator]();
|
|
5182
5353
|
const firstResult2 = await iterator2.next();
|
|
5183
5354
|
return { iterator: iterator2, firstResult: firstResult2 };
|
|
5355
|
+
} else if (aiProvider === "DeepSeek") {
|
|
5356
|
+
const stream = getDeepSeekStream(
|
|
5357
|
+
apiKey,
|
|
5358
|
+
"deepseek-chat",
|
|
5359
|
+
janitorContents,
|
|
5360
|
+
janitorPrompt,
|
|
5361
|
+
"Fast",
|
|
5362
|
+
// Janitor always minimal
|
|
5363
|
+
mode,
|
|
5364
|
+
false
|
|
5365
|
+
);
|
|
5366
|
+
const iterator2 = stream[Symbol.asyncIterator]();
|
|
5367
|
+
const firstResult2 = await iterator2.next();
|
|
5368
|
+
return { iterator: iterator2, firstResult: firstResult2 };
|
|
5184
5369
|
} else {
|
|
5185
5370
|
const stream = await client.models.generateContentStream({
|
|
5186
5371
|
model: janitorModel || "gemma-4-26b-a4b-it",
|
|
@@ -5524,8 +5709,41 @@ ${originalTextProcessed.length > USER_CONTEXT_LENGTH ? "... (truncated) ...\n\n"
|
|
|
5524
5709
|
client = new GoogleGenAI({ apiKey });
|
|
5525
5710
|
return client;
|
|
5526
5711
|
};
|
|
5712
|
+
generateSimpleContent = async (settings, model, contents, systemInstruction, thinkingLevel = "Fast") => {
|
|
5713
|
+
const { aiProvider = "Google", apiKey, mode } = settings;
|
|
5714
|
+
let fullText = "";
|
|
5715
|
+
let usageMetadata = null;
|
|
5716
|
+
let stream;
|
|
5717
|
+
if (aiProvider === "OpenRouter") {
|
|
5718
|
+
stream = getOpenRouterStream(apiKey, model, contents, systemInstruction, thinkingLevel, mode, false);
|
|
5719
|
+
} else if (aiProvider === "DeepSeek") {
|
|
5720
|
+
stream = getDeepSeekStream(apiKey, model, contents, systemInstruction, thinkingLevel, mode, false);
|
|
5721
|
+
} else {
|
|
5722
|
+
const genStream = await client.models.generateContentStream({
|
|
5723
|
+
model,
|
|
5724
|
+
contents,
|
|
5725
|
+
config: {
|
|
5726
|
+
systemInstruction,
|
|
5727
|
+
maxOutputTokens: 2048,
|
|
5728
|
+
temperature: 0.3,
|
|
5729
|
+
thinkingConfig: { includeThoughts: false, thinkingLevel: ThinkingLevel.MINIMAL }
|
|
5730
|
+
}
|
|
5731
|
+
});
|
|
5732
|
+
stream = genStream;
|
|
5733
|
+
}
|
|
5734
|
+
for await (const chunk of stream) {
|
|
5735
|
+
if (chunk.candidates?.[0]?.content?.parts) {
|
|
5736
|
+
for (const part of chunk.candidates[0].content.parts) {
|
|
5737
|
+
if (part.text && !part.thought) fullText += part.text;
|
|
5738
|
+
}
|
|
5739
|
+
}
|
|
5740
|
+
if (chunk.usageMetadata) usageMetadata = chunk.usageMetadata;
|
|
5741
|
+
}
|
|
5742
|
+
return { text: fullText, usageMetadata };
|
|
5743
|
+
};
|
|
5527
5744
|
consolidatePastMemories = async (currentChatId, settings) => {
|
|
5528
5745
|
try {
|
|
5746
|
+
const { aiProvider = "Google" } = settings;
|
|
5529
5747
|
const tempStorage = readEncryptedJson(TEMP_MEM_FILE, {});
|
|
5530
5748
|
const totalMemoriesCount = Object.values(tempStorage).flat().length;
|
|
5531
5749
|
if (totalMemoriesCount <= 2) return;
|
|
@@ -5573,23 +5791,13 @@ ${newMemoryListStr}
|
|
|
5573
5791
|
let attempts = 0;
|
|
5574
5792
|
const maxAttempts = 3;
|
|
5575
5793
|
let success = false;
|
|
5794
|
+
let targetModel = "gemini-3.1-flash-lite";
|
|
5795
|
+
if (aiProvider === "OpenRouter") targetModel = "google/gemma-4-26b-a4b-it:free";
|
|
5796
|
+
if (aiProvider === "DeepSeek") targetModel = "deepseek-v4-flash";
|
|
5576
5797
|
while (attempts < maxAttempts && !success) {
|
|
5577
5798
|
attempts++;
|
|
5578
5799
|
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
|
-
});
|
|
5800
|
+
const response = await generateSimpleContent(settings, targetModel, prompt, null, "Fast");
|
|
5593
5801
|
const responseText = response.text || "";
|
|
5594
5802
|
const janitorToolCalls = detectToolCalls(responseText);
|
|
5595
5803
|
if (janitorToolCalls.length === 0) {
|
|
@@ -5601,6 +5809,9 @@ ${newMemoryListStr}
|
|
|
5601
5809
|
await dispatchTool(toolName, janitorToolCall.args, { chatId: currentChatId });
|
|
5602
5810
|
}
|
|
5603
5811
|
}
|
|
5812
|
+
if (response.usageMetadata) {
|
|
5813
|
+
await addToUsage("tokens", response.usageMetadata.totalTokenCount || 0);
|
|
5814
|
+
}
|
|
5604
5815
|
success = true;
|
|
5605
5816
|
} catch (err) {
|
|
5606
5817
|
if (attempts >= maxAttempts) {
|
|
@@ -5653,66 +5864,22 @@ Provide a new consolidated summary of the entire session.` : `Here is the conver
|
|
|
5653
5864
|
${flattenedText2}
|
|
5654
5865
|
|
|
5655
5866
|
Provide a consolidated summary of the entire session.`;
|
|
5867
|
+
let targetModel = "gemini-3.1-flash-lite";
|
|
5868
|
+
if (aiProvider === "OpenRouter") targetModel = "google/gemma-4-26b-a4b-it:free";
|
|
5869
|
+
if (aiProvider === "DeepSeek") targetModel = "deepseek-v4-flash";
|
|
5656
5870
|
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
|
-
});
|
|
5871
|
+
const response = await generateSimpleContent(settings, targetModel, prompt, systemInstruction, "Fast");
|
|
5673
5872
|
return response.text || "";
|
|
5674
5873
|
} 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) {
|
|
5874
|
+
if (aiProvider === "Google") {
|
|
5694
5875
|
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) {
|
|
5876
|
+
const fallback = await generateSimpleContent(settings, "gemini-2.5-flash", prompt, systemInstruction, "Fast");
|
|
5877
|
+
return fallback.text || "";
|
|
5878
|
+
} catch (e) {
|
|
5713
5879
|
return "";
|
|
5714
5880
|
}
|
|
5715
5881
|
}
|
|
5882
|
+
return "";
|
|
5716
5883
|
}
|
|
5717
5884
|
};
|
|
5718
5885
|
const flattenedText = flattenContext(modifiedHistory);
|
|
@@ -6113,11 +6280,14 @@ ${thinkingLevel != "Fast" && aiProvider === "Google" ? `${modelName.toLowerCase(
|
|
|
6113
6280
|
throw new Error("Error: Quota Exausted for Agent");
|
|
6114
6281
|
}
|
|
6115
6282
|
targetModel = modelName;
|
|
6283
|
+
if (aiProvider === "DeepSeek" && thinkingLevel === "Fast") {
|
|
6284
|
+
targetModel = "deepseek-chat";
|
|
6285
|
+
}
|
|
6116
6286
|
if (retryCount === MAX_RETRIES - 1) {
|
|
6117
|
-
targetModel = "gemini-3-flash-preview";
|
|
6287
|
+
targetModel = aiProvider === "DeepSeek" ? "deepseek-v4-flash" : "gemini-3-flash-preview";
|
|
6118
6288
|
yield { type: "model_update", content: "Trying with fallback model" };
|
|
6119
6289
|
} else if (retryCount === MAX_RETRIES) {
|
|
6120
|
-
targetModel = "gemini-3.5-flash";
|
|
6290
|
+
targetModel = aiProvider === "DeepSeek" ? "deepseek-v4-pro" : "gemini-3.5-flash";
|
|
6121
6291
|
yield { type: "model_update", content: "Trying with fallback model" };
|
|
6122
6292
|
} else if (retryCount > 12 && retryCount < MAX_RETRIES - 2 && settings.apiKey !== "custom") {
|
|
6123
6293
|
targetModel = "gemma-4-31b-it";
|
|
@@ -6154,6 +6324,16 @@ ${thinkingLevel != "Fast" && aiProvider === "Google" ? `${modelName.toLowerCase(
|
|
|
6154
6324
|
mode,
|
|
6155
6325
|
isMultiModal
|
|
6156
6326
|
);
|
|
6327
|
+
} else if (aiProvider === "DeepSeek") {
|
|
6328
|
+
stream = getDeepSeekStream(
|
|
6329
|
+
settings.apiKey,
|
|
6330
|
+
targetModel,
|
|
6331
|
+
activeContents,
|
|
6332
|
+
currentSystemInstruction,
|
|
6333
|
+
thinkingLevel,
|
|
6334
|
+
mode,
|
|
6335
|
+
isMultiModal
|
|
6336
|
+
);
|
|
6157
6337
|
} else {
|
|
6158
6338
|
stream = await client.models.generateContentStream({
|
|
6159
6339
|
model: targetModel || "gemma-4-31b-it",
|
|
@@ -6216,6 +6396,8 @@ ${thinkingLevel != "Fast" && aiProvider === "Google" ? `${modelName.toLowerCase(
|
|
|
6216
6396
|
yield { type: "status", content: "Working..." };
|
|
6217
6397
|
dedupeBuffer = "";
|
|
6218
6398
|
isDedupeActive = accumulatedContext.length > 0;
|
|
6399
|
+
let pendingGoogleText = "";
|
|
6400
|
+
let lastGoogleFlushTime = Date.now();
|
|
6219
6401
|
for await (const chunk of stream) {
|
|
6220
6402
|
if (TERMINATION_SIGNAL) {
|
|
6221
6403
|
yield { type: "status", content: "Termination Signal Received." };
|
|
@@ -6268,7 +6450,11 @@ ${thinkingLevel != "Fast" && aiProvider === "Google" ? `${modelName.toLowerCase(
|
|
|
6268
6450
|
const dedupeClean = hasOpenThink ? cleanText.replace(/^\s*(?:<(think|thought)>|\[(think|thought)\])\s*/gi, "") : cleanText.replace(/^\s*(?:<(think|thought)>|\[(think|thought)\])[\s\S]*?(?:<\/(think|thought)>|\[\/(think|thought)\])\s*/gi, "").replace(/^\s*(?:<(think|thought)>|\[(think|thought)\])\s*/gi, "");
|
|
6269
6451
|
if (dedupeClean) {
|
|
6270
6452
|
turnText += dedupeClean;
|
|
6271
|
-
|
|
6453
|
+
if (aiProvider === "Google") {
|
|
6454
|
+
pendingGoogleText += dedupeClean;
|
|
6455
|
+
} else {
|
|
6456
|
+
yield { type: "text", content: dedupeClean };
|
|
6457
|
+
}
|
|
6272
6458
|
}
|
|
6273
6459
|
}
|
|
6274
6460
|
isDedupeActive = false;
|
|
@@ -6277,7 +6463,11 @@ ${thinkingLevel != "Fast" && aiProvider === "Google" ? `${modelName.toLowerCase(
|
|
|
6277
6463
|
continue;
|
|
6278
6464
|
} else {
|
|
6279
6465
|
turnText += chunkText;
|
|
6280
|
-
|
|
6466
|
+
if (aiProvider === "Google") {
|
|
6467
|
+
pendingGoogleText += chunkText;
|
|
6468
|
+
} else {
|
|
6469
|
+
yield { type: "text", content: chunkText };
|
|
6470
|
+
}
|
|
6281
6471
|
}
|
|
6282
6472
|
const signalSafeText3 = getSanitizedText(turnText);
|
|
6283
6473
|
const toolContext = getActiveToolContext(turnText);
|
|
@@ -6758,6 +6948,11 @@ ${boxBottom}` };
|
|
|
6758
6948
|
if (normToolName === "memory" && result.includes("SUCCESS")) yield { type: "memory_updated" };
|
|
6759
6949
|
toolCallPointer++;
|
|
6760
6950
|
}
|
|
6951
|
+
if (aiProvider === "Google" && pendingGoogleText && Date.now() - lastGoogleFlushTime >= 100) {
|
|
6952
|
+
yield { type: "text", content: pendingGoogleText };
|
|
6953
|
+
pendingGoogleText = "";
|
|
6954
|
+
lastGoogleFlushTime = Date.now();
|
|
6955
|
+
}
|
|
6761
6956
|
}
|
|
6762
6957
|
if (chunk.usageMetadata) {
|
|
6763
6958
|
lastUsage = chunk.usageMetadata;
|
|
@@ -6772,7 +6967,11 @@ ${boxBottom}` };
|
|
|
6772
6967
|
dedupeBuffer += "</think>";
|
|
6773
6968
|
} else {
|
|
6774
6969
|
turnText += "</think>";
|
|
6775
|
-
|
|
6970
|
+
if (aiProvider === "Google") {
|
|
6971
|
+
pendingGoogleText += "</think>";
|
|
6972
|
+
} else {
|
|
6973
|
+
yield { type: "text", content: "</think>" };
|
|
6974
|
+
}
|
|
6776
6975
|
}
|
|
6777
6976
|
}
|
|
6778
6977
|
if (isDedupeActive && dedupeBuffer.length > 0) {
|
|
@@ -6790,12 +6989,20 @@ ${boxBottom}` };
|
|
|
6790
6989
|
const dedupeClean = hasOpenThink ? cleanText.replace(/^\s*(?:<(think|thought)>|\[(think|thought)\])\s*/gi, "") : cleanText.replace(/^\s*(?:<(think|thought)>|\[(think|thought)\])[\s\S]*?(?:<\/(think|thought)>|\[\/(think|thought)\])\s*/gi, "").replace(/^\s*(?:<(think|thought)>|\[(think|thought)\])\s*/gi, "");
|
|
6791
6990
|
if (dedupeClean) {
|
|
6792
6991
|
turnText += dedupeClean;
|
|
6793
|
-
|
|
6992
|
+
if (aiProvider === "Google") {
|
|
6993
|
+
pendingGoogleText += dedupeClean;
|
|
6994
|
+
} else {
|
|
6995
|
+
yield { type: "text", content: dedupeClean };
|
|
6996
|
+
}
|
|
6794
6997
|
}
|
|
6795
6998
|
}
|
|
6796
6999
|
isDedupeActive = false;
|
|
6797
7000
|
dedupeBuffer = "";
|
|
6798
7001
|
}
|
|
7002
|
+
if (aiProvider === "Google" && pendingGoogleText) {
|
|
7003
|
+
yield { type: "text", content: pendingGoogleText };
|
|
7004
|
+
pendingGoogleText = "";
|
|
7005
|
+
}
|
|
6799
7006
|
if (TERMINATION_SIGNAL) break;
|
|
6800
7007
|
const signalSafeText2 = (turnText || "").trim();
|
|
6801
7008
|
const hasFinish2 = /\[\s*(turn\s*:)?\s*finish\s*\]/i.test(signalSafeText2.toLowerCase());
|
|
@@ -6947,7 +7154,7 @@ Error Log can be found in ${path16.join(LOGS_DIR, "agent", "error.log")}`);
|
|
|
6947
7154
|
const shouldContinue = toolCallPointer > 0;
|
|
6948
7155
|
yield { type: "status", content: "Working..." };
|
|
6949
7156
|
const cleanedTurnText = contextSafeReplace(turnText, /\[\s*(turn\s*:)?\s*(continue|finish)\s*\]/gi, "").trim();
|
|
6950
|
-
let isActuallyFinished = hasFinish
|
|
7157
|
+
let isActuallyFinished = hasFinish || !shouldContinue;
|
|
6951
7158
|
if (isActuallyFinished) {
|
|
6952
7159
|
const fullAgentTextRaw = fullAgentResponseChunks.join("\n");
|
|
6953
7160
|
const cleanedFullResponse = fullAgentTextRaw.replace(/(?:<think>|\[think\])[\s\S]*?(?:<\/think>|\[\/think\])/g, "").trim();
|
|
@@ -7663,44 +7870,63 @@ function App({ args = [] }) {
|
|
|
7663
7870
|
const [tick, setTick] = useState10(0);
|
|
7664
7871
|
const isFirstRender = useRef3(true);
|
|
7665
7872
|
const isSecondRender = useRef3(true);
|
|
7873
|
+
const isThirdRender = useRef3(true);
|
|
7666
7874
|
useEffect7(() => {
|
|
7875
|
+
if (!apiKey) return;
|
|
7667
7876
|
if (isFirstRender.current) {
|
|
7668
7877
|
isFirstRender.current = false;
|
|
7669
7878
|
setTimeout(() => {
|
|
7670
7879
|
isSecondRender.current = false;
|
|
7880
|
+
setTimeout(() => {
|
|
7881
|
+
isThirdRender.current = false;
|
|
7882
|
+
}, 1e3);
|
|
7671
7883
|
}, 2e3);
|
|
7672
7884
|
return;
|
|
7673
7885
|
}
|
|
7674
7886
|
if (isSecondRender.current) {
|
|
7675
7887
|
return;
|
|
7676
7888
|
}
|
|
7889
|
+
if (isThirdRender.current) {
|
|
7890
|
+
return;
|
|
7891
|
+
}
|
|
7677
7892
|
const s = emojiSpace(2);
|
|
7893
|
+
let defaultModel = "";
|
|
7894
|
+
let modelDisplayName = "";
|
|
7678
7895
|
if (apiTier === "Free") {
|
|
7679
|
-
|
|
7680
|
-
|
|
7681
|
-
|
|
7682
|
-
|
|
7683
|
-
|
|
7684
|
-
|
|
7685
|
-
|
|
7686
|
-
|
|
7687
|
-
|
|
7688
|
-
|
|
7689
|
-
});
|
|
7896
|
+
if (aiProvider === "Google") {
|
|
7897
|
+
defaultModel = "gemma-4-31b-it";
|
|
7898
|
+
modelDisplayName = "Gemma 4 (Free default)";
|
|
7899
|
+
} else if (aiProvider === "DeepSeek") {
|
|
7900
|
+
defaultModel = "deepseek-v4-flash";
|
|
7901
|
+
modelDisplayName = "DeepSeek Flash (Free default)";
|
|
7902
|
+
} else {
|
|
7903
|
+
defaultModel = "google/gemma-4-31b-it:free";
|
|
7904
|
+
modelDisplayName = "Gemma 4 (Free default)";
|
|
7905
|
+
}
|
|
7690
7906
|
} else {
|
|
7691
|
-
|
|
7692
|
-
|
|
7693
|
-
|
|
7694
|
-
|
|
7695
|
-
|
|
7696
|
-
|
|
7697
|
-
|
|
7698
|
-
|
|
7699
|
-
|
|
7700
|
-
|
|
7701
|
-
});
|
|
7907
|
+
if (aiProvider === "Google") {
|
|
7908
|
+
defaultModel = "gemini-3-flash-preview";
|
|
7909
|
+
modelDisplayName = "Gemini 3 Flash";
|
|
7910
|
+
} else if (aiProvider === "DeepSeek") {
|
|
7911
|
+
defaultModel = "deepseek-v4-flash";
|
|
7912
|
+
modelDisplayName = "DeepSeek Flash";
|
|
7913
|
+
} else {
|
|
7914
|
+
defaultModel = "deepseek/deepseek-v4-flash";
|
|
7915
|
+
modelDisplayName = "DeepSeek Flash";
|
|
7916
|
+
}
|
|
7702
7917
|
}
|
|
7703
|
-
|
|
7918
|
+
setActiveModel(defaultModel);
|
|
7919
|
+
saveSettings({ apiTier, activeModel: defaultModel });
|
|
7920
|
+
setMessages((prev) => {
|
|
7921
|
+
setCompletedIndex(prev.length + 1);
|
|
7922
|
+
return [...prev, {
|
|
7923
|
+
id: "tier-switch-" + Date.now(),
|
|
7924
|
+
role: "system",
|
|
7925
|
+
text: `\u26A0\uFE0F${s}**[TIER LIMIT]** Auto-switched to ${modelDisplayName}.`,
|
|
7926
|
+
isMeta: true
|
|
7927
|
+
}];
|
|
7928
|
+
});
|
|
7929
|
+
}, [apiTier, aiProvider, apiKey]);
|
|
7704
7930
|
const terminalEnv = useMemo2(() => {
|
|
7705
7931
|
const isIDE = process.env.TERM_PROGRAM === "vscode" || !!process.env.VSC_TERMINAL_URL || !!process.env.INTELLIJ_TERMINAL_COMMAND_BLOCKS;
|
|
7706
7932
|
return {
|
|
@@ -8026,7 +8252,8 @@ function App({ args = [] }) {
|
|
|
8026
8252
|
setSystemSettings(freshSettings);
|
|
8027
8253
|
setProfileData(saved.profileData);
|
|
8028
8254
|
setImageSettings(saved.imageSettings || { keyType: "Default", quality: "Low-High", apiKey: "" });
|
|
8029
|
-
const
|
|
8255
|
+
const startupProvider = saved.aiProvider || "Google";
|
|
8256
|
+
const key = await getProviderAPIKey(startupProvider);
|
|
8030
8257
|
if (key) {
|
|
8031
8258
|
setApiKey(key);
|
|
8032
8259
|
initAI(key);
|
|
@@ -8105,12 +8332,21 @@ function App({ args = [] }) {
|
|
|
8105
8332
|
}, [mode, thinkingLevel, aiProvider, activeModel, showFullThinking, systemSettings, profileData, imageSettings, isInitializing, parsedArgs, apiTier]);
|
|
8106
8333
|
const handleSetup = async (val) => {
|
|
8107
8334
|
const key = val.trim();
|
|
8108
|
-
|
|
8335
|
+
let minLength = 30;
|
|
8336
|
+
if (aiProvider === "OpenRouter") minLength = 10;
|
|
8337
|
+
if (aiProvider === "DeepSeek") minLength = 20;
|
|
8109
8338
|
if (key.length >= minLength) {
|
|
8110
|
-
await
|
|
8339
|
+
await saveProviderAPIKey(aiProvider, key);
|
|
8111
8340
|
setApiKey(key);
|
|
8112
8341
|
initAI(key);
|
|
8113
|
-
|
|
8342
|
+
let defaultModel = "gemma-4-31b-it";
|
|
8343
|
+
if (aiProvider === "OpenRouter") {
|
|
8344
|
+
defaultModel = "google/gemma-4-31b-it:free";
|
|
8345
|
+
} else if (aiProvider === "DeepSeek") {
|
|
8346
|
+
defaultModel = "deepseek-v4-flash";
|
|
8347
|
+
}
|
|
8348
|
+
setActiveModel(defaultModel);
|
|
8349
|
+
setMessages((prev) => [...prev, { role: "system", text: `\u2705 ${aiProvider} API Key saved successfully! Model set to ${defaultModel}. Initialization complete.`, isMeta: true }]);
|
|
8114
8350
|
} else {
|
|
8115
8351
|
setMessages((prev) => [...prev, { role: "system", text: `\u274C INVALID KEY: ${aiProvider} API keys must be at least ${minLength} characters.`, isMeta: true }]);
|
|
8116
8352
|
setTempKey("");
|
|
@@ -8202,12 +8438,28 @@ function App({ args = [] }) {
|
|
|
8202
8438
|
{
|
|
8203
8439
|
cmd: "/thinking",
|
|
8204
8440
|
desc: "Set AI reasoning depth",
|
|
8205
|
-
subs: [
|
|
8206
|
-
{ cmd: "Fast", desc: "
|
|
8207
|
-
{ cmd: "
|
|
8208
|
-
{ cmd: "
|
|
8209
|
-
|
|
8210
|
-
{ cmd: "
|
|
8441
|
+
subs: aiProvider === "DeepSeek" ? [
|
|
8442
|
+
{ cmd: "Fast", desc: "Fastest" },
|
|
8443
|
+
{ cmd: "Standard", desc: "Standard Reasoning" },
|
|
8444
|
+
{ cmd: "xHigh", desc: "Extended Reasoning" }
|
|
8445
|
+
] : aiProvider === "OpenRouter" ? [
|
|
8446
|
+
{ cmd: "Fast", desc: "Fastest" },
|
|
8447
|
+
{ cmd: "Low", desc: "Quick Reasoning" },
|
|
8448
|
+
{ cmd: "Medium", desc: "Balanced Reasoning" },
|
|
8449
|
+
{ cmd: "High", desc: "Deep Reasoning" },
|
|
8450
|
+
{ cmd: "xHigh", desc: "Extended Reasoning" }
|
|
8451
|
+
] : activeModel && activeModel.toLowerCase().startsWith("gemini-3") ? [
|
|
8452
|
+
{ cmd: "Fast", desc: "Fastest" },
|
|
8453
|
+
{ cmd: "Low", desc: "Quick Reasoning" },
|
|
8454
|
+
{ cmd: "Medium", desc: "Balanced Reasoning" },
|
|
8455
|
+
{ cmd: "High", desc: "Deep Reasoning" }
|
|
8456
|
+
] : [
|
|
8457
|
+
// Google General / Gemma
|
|
8458
|
+
{ cmd: "Fast", desc: "Fastest" },
|
|
8459
|
+
{ cmd: "Low", desc: "Quick Reasoning" },
|
|
8460
|
+
{ cmd: "Medium", desc: "Balanced Reasoning" },
|
|
8461
|
+
{ cmd: "High", desc: "Deep Reasoning" },
|
|
8462
|
+
{ cmd: "xHigh", desc: "Extended Reasoning" }
|
|
8211
8463
|
]
|
|
8212
8464
|
},
|
|
8213
8465
|
{
|
|
@@ -8287,6 +8539,15 @@ function App({ args = [] }) {
|
|
|
8287
8539
|
cmd: "moonshotai/kimi-k2.6",
|
|
8288
8540
|
desc: "Multimodal"
|
|
8289
8541
|
}
|
|
8542
|
+
] : aiProvider === "DeepSeek" ? [
|
|
8543
|
+
{
|
|
8544
|
+
cmd: "deepseek-v4-flash",
|
|
8545
|
+
desc: "Fast & Efficient"
|
|
8546
|
+
},
|
|
8547
|
+
{
|
|
8548
|
+
cmd: "deepseek-v4-pro",
|
|
8549
|
+
desc: "High-Intelligence Reasoning"
|
|
8550
|
+
}
|
|
8290
8551
|
] : apiTier === "Free" ? [
|
|
8291
8552
|
{
|
|
8292
8553
|
cmd: "gemma-4-31b-it",
|
|
@@ -9455,7 +9716,61 @@ Selection: ${val}`,
|
|
|
9455
9716
|
setInputConfig,
|
|
9456
9717
|
saveSettings,
|
|
9457
9718
|
quotas,
|
|
9458
|
-
setMessages
|
|
9719
|
+
setMessages,
|
|
9720
|
+
aiProvider
|
|
9721
|
+
}
|
|
9722
|
+
);
|
|
9723
|
+
case "selectProvider":
|
|
9724
|
+
return /* @__PURE__ */ React13.createElement(
|
|
9725
|
+
CommandMenu,
|
|
9726
|
+
{
|
|
9727
|
+
title: "SELECT AI PROVIDER",
|
|
9728
|
+
items: [
|
|
9729
|
+
{ label: "Google (Free/Paid)", value: "Google" },
|
|
9730
|
+
{ label: "DeepSeek (Paid)", value: "DeepSeek" },
|
|
9731
|
+
{ label: "OpenRouter (Free/Paid) [EXPERIMENTAL]", value: "OpenRouter" },
|
|
9732
|
+
{ label: "Back", value: "settings" }
|
|
9733
|
+
],
|
|
9734
|
+
onSelect: async (item) => {
|
|
9735
|
+
if (item.value === "settings" || item.value === "Back") {
|
|
9736
|
+
setActiveView("settings");
|
|
9737
|
+
return;
|
|
9738
|
+
}
|
|
9739
|
+
const selectedProvider = item.value;
|
|
9740
|
+
const key = await getProviderAPIKey(selectedProvider);
|
|
9741
|
+
if (key) {
|
|
9742
|
+
setAiProvider(selectedProvider);
|
|
9743
|
+
setApiKey(key);
|
|
9744
|
+
initAI(key);
|
|
9745
|
+
let defaultModel = "gemma-4-31b-it";
|
|
9746
|
+
if (selectedProvider === "OpenRouter") {
|
|
9747
|
+
defaultModel = "google/gemma-4-31b-it:free";
|
|
9748
|
+
} else if (selectedProvider === "DeepSeek") {
|
|
9749
|
+
defaultModel = "deepseek-v4-flash";
|
|
9750
|
+
}
|
|
9751
|
+
setActiveModel(defaultModel);
|
|
9752
|
+
saveSettings({ aiProvider: selectedProvider, activeModel: defaultModel, apiTier, quotas });
|
|
9753
|
+
setMessages((prev) => [
|
|
9754
|
+
...prev,
|
|
9755
|
+
{
|
|
9756
|
+
role: "system",
|
|
9757
|
+
text: `\u2705 Switched to ${selectedProvider}! Key loaded from Vault. Model set to ${defaultModel}.`,
|
|
9758
|
+
isMeta: true
|
|
9759
|
+
}
|
|
9760
|
+
]);
|
|
9761
|
+
setActiveView("settings");
|
|
9762
|
+
} else {
|
|
9763
|
+
setInputConfig({
|
|
9764
|
+
label: `Enter ${selectedProvider} API Key:`,
|
|
9765
|
+
key: "providerKey",
|
|
9766
|
+
provider: selectedProvider,
|
|
9767
|
+
value: "",
|
|
9768
|
+
returnView: "settings"
|
|
9769
|
+
});
|
|
9770
|
+
setActiveView("input");
|
|
9771
|
+
}
|
|
9772
|
+
},
|
|
9773
|
+
onClose: () => setActiveView("settings")
|
|
9459
9774
|
}
|
|
9460
9775
|
);
|
|
9461
9776
|
case "apiTier":
|
|
@@ -9497,7 +9812,7 @@ Selection: ${val}`,
|
|
|
9497
9812
|
{
|
|
9498
9813
|
value: inputConfig?.value || "",
|
|
9499
9814
|
onChange: (val) => setInputConfig((prev) => ({ ...prev, value: val })),
|
|
9500
|
-
onSubmit: (val) => {
|
|
9815
|
+
onSubmit: async (val) => {
|
|
9501
9816
|
const { key, subKey, next } = inputConfig;
|
|
9502
9817
|
let newQuotas = { ...quotas };
|
|
9503
9818
|
let newSettings = {};
|
|
@@ -9539,6 +9854,26 @@ Selection: ${val}`,
|
|
|
9539
9854
|
return [...prev, { id: Date.now(), role: "system", text: `\u274C [IMAGE KEY ERROR] API key must start with sk_. Key strategy reset to Default.`, isMeta: true }];
|
|
9540
9855
|
});
|
|
9541
9856
|
}
|
|
9857
|
+
} else if (key === "providerKey") {
|
|
9858
|
+
const keyInput = val.trim();
|
|
9859
|
+
const prov = inputConfig.provider;
|
|
9860
|
+
await saveProviderAPIKey(prov, keyInput);
|
|
9861
|
+
setAiProvider(prov);
|
|
9862
|
+
setApiKey(keyInput);
|
|
9863
|
+
initAI(keyInput);
|
|
9864
|
+
let defaultModel = "gemma-4-31b-it";
|
|
9865
|
+
if (prov === "OpenRouter") {
|
|
9866
|
+
defaultModel = "google/gemma-4-31b-it:free";
|
|
9867
|
+
} else if (prov === "DeepSeek") {
|
|
9868
|
+
defaultModel = "deepseek-v4-flash";
|
|
9869
|
+
}
|
|
9870
|
+
setActiveModel(defaultModel);
|
|
9871
|
+
newSettings.aiProvider = prov;
|
|
9872
|
+
newSettings.activeModel = defaultModel;
|
|
9873
|
+
setMessages((prev) => {
|
|
9874
|
+
setCompletedIndex(prev.length + 1);
|
|
9875
|
+
return [...prev, { id: Date.now(), role: "system", text: `\u2705 ${prov} API Key saved successfully! Model set to ${defaultModel}.`, isMeta: true }];
|
|
9876
|
+
});
|
|
9542
9877
|
}
|
|
9543
9878
|
if (next) {
|
|
9544
9879
|
setInputConfig(next(key === "quotas" ? newQuotas : val));
|
|
@@ -9937,8 +10272,9 @@ Selection: ${val}`,
|
|
|
9937
10272
|
CommandMenu,
|
|
9938
10273
|
{
|
|
9939
10274
|
items: [
|
|
9940
|
-
{ label: "Google (
|
|
9941
|
-
{ label: "
|
|
10275
|
+
{ label: "Google (Free/Paid)", value: "Google" },
|
|
10276
|
+
{ label: "DeepSeek (Paid)", value: "DeepSeek" },
|
|
10277
|
+
{ label: "OpenRouter (Free/Paid) [EXPERIMENTAL]", value: "OpenRouter" }
|
|
9942
10278
|
],
|
|
9943
10279
|
onSelect: (item) => {
|
|
9944
10280
|
setAiProvider(item.value);
|