fluxflow-cli 3.19.1 → 3.19.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ARCHITECTURE.md +3 -0
- package/README.md +3 -5
- package/TOOLS.md +3 -0
- package/UI_FEATURES.md +4 -1
- package/dist/fluxflow.js +468 -281
- package/model_config.json +43 -3
- package/package.json +1 -1
package/dist/fluxflow.js
CHANGED
|
@@ -2662,22 +2662,41 @@ var init_text = __esm({
|
|
|
2662
2662
|
const indices = /* @__PURE__ */ new Set();
|
|
2663
2663
|
const allowMultiple = args.allowMultiple === true || String(args.allowMultiple).toLowerCase() === "true";
|
|
2664
2664
|
Object.keys(args).forEach((key) => {
|
|
2665
|
-
const m = key.match(/^(searchContent|replaceContent|newContent|content_to_replace|content_to_add)(\d+)?$/);
|
|
2665
|
+
const m = key.match(/^(searchContent|search_content|replaceContent|replace_content|newContent|new_content|content_to_replace|content_to_add|searchBlock|search_block|newBlock|new_block)_?(\d+)?$/i);
|
|
2666
2666
|
if (m) {
|
|
2667
|
-
const index2 = m[2] ? parseInt(m[2]) : 1;
|
|
2667
|
+
const index2 = m[2] ? parseInt(m[2], 10) : 1;
|
|
2668
2668
|
indices.add(index2);
|
|
2669
2669
|
}
|
|
2670
2670
|
});
|
|
2671
2671
|
const sortedIndices = Array.from(indices).sort((a, b) => a - b);
|
|
2672
|
-
|
|
2672
|
+
const searchNames = ["searchContent", "search_content", "replaceContent", "replace_content", "content_to_replace", "searchBlock", "search_block"];
|
|
2673
|
+
const newNames = ["newContent", "new_content", "content_to_add", "newBlock", "new_block"];
|
|
2674
|
+
const getVal = (index2, searchList, newList) => {
|
|
2673
2675
|
let r, n;
|
|
2674
|
-
|
|
2675
|
-
|
|
2676
|
-
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2676
|
+
for (const name of searchList) {
|
|
2677
|
+
const keysToTry = index2 === 1 ? [`${name}1`, name, `${name}_1`] : [`${name}${index2}`, `${name}_${index2}`];
|
|
2678
|
+
for (const k of keysToTry) {
|
|
2679
|
+
if (args[k] !== void 0) {
|
|
2680
|
+
r = args[k];
|
|
2681
|
+
break;
|
|
2682
|
+
}
|
|
2683
|
+
}
|
|
2684
|
+
if (r !== void 0) break;
|
|
2680
2685
|
}
|
|
2686
|
+
for (const name of newList) {
|
|
2687
|
+
const keysToTry = index2 === 1 ? [`${name}1`, name, `${name}_1`] : [`${name}${index2}`, `${name}_${index2}`];
|
|
2688
|
+
for (const k of keysToTry) {
|
|
2689
|
+
if (args[k] !== void 0) {
|
|
2690
|
+
n = args[k];
|
|
2691
|
+
break;
|
|
2692
|
+
}
|
|
2693
|
+
}
|
|
2694
|
+
if (n !== void 0) break;
|
|
2695
|
+
}
|
|
2696
|
+
return { r, n };
|
|
2697
|
+
};
|
|
2698
|
+
for (const i of sortedIndices) {
|
|
2699
|
+
const { r, n } = getVal(i, searchNames, newNames);
|
|
2681
2700
|
if (r !== void 0 && n !== void 0) {
|
|
2682
2701
|
patchPairs.push({ replace: r, new: n });
|
|
2683
2702
|
} else if (r !== void 0 || n !== void 0) {
|
|
@@ -2921,6 +2940,9 @@ var init_text = __esm({
|
|
|
2921
2940
|
if (!patchResults || patchResults.length === 0) return "";
|
|
2922
2941
|
const allLinesOriginal = originalContent.split(/\r?\n/);
|
|
2923
2942
|
const allLinesFinal = finalContent.split(/\r?\n/);
|
|
2943
|
+
const maxLineNum = Math.max(allLinesOriginal.length, allLinesFinal.length, 1);
|
|
2944
|
+
const gutterWidth = Math.max(4, String(maxLineNum).length);
|
|
2945
|
+
const fmtNum = (num) => String(num).padStart(gutterWidth, " ");
|
|
2924
2946
|
let diffText = `[DIFF_START]
|
|
2925
2947
|
`;
|
|
2926
2948
|
const separatorLine = "\u2550".repeat(88);
|
|
@@ -2933,7 +2955,7 @@ var init_text = __esm({
|
|
|
2933
2955
|
const contextStart = Math.max(0, startLineFinal - 4);
|
|
2934
2956
|
currentFinalLineIdx = contextStart;
|
|
2935
2957
|
while (currentFinalLineIdx < startLineFinal - 1) {
|
|
2936
|
-
diffText += `[UI_CONTEXT]
|
|
2958
|
+
diffText += `[UI_CONTEXT] ${fmtNum(currentFinalLineIdx + 1)} |${allLinesFinal[currentFinalLineIdx] || ""}
|
|
2937
2959
|
`;
|
|
2938
2960
|
currentFinalLineIdx++;
|
|
2939
2961
|
}
|
|
@@ -2944,7 +2966,7 @@ var init_text = __esm({
|
|
|
2944
2966
|
if (gap >= threshold) {
|
|
2945
2967
|
let afterLimit = Math.min(allLinesFinal.length, currentFinalLineIdx + 3);
|
|
2946
2968
|
while (currentFinalLineIdx < afterLimit) {
|
|
2947
|
-
diffText += `[UI_CONTEXT]
|
|
2969
|
+
diffText += `[UI_CONTEXT] ${fmtNum(currentFinalLineIdx + 1)} |${allLinesFinal[currentFinalLineIdx] || ""}
|
|
2948
2970
|
`;
|
|
2949
2971
|
currentFinalLineIdx++;
|
|
2950
2972
|
}
|
|
@@ -2953,13 +2975,13 @@ var init_text = __esm({
|
|
|
2953
2975
|
const beforeStart = Math.max(currentFinalLineIdx, startLineFinal - 4);
|
|
2954
2976
|
currentFinalLineIdx = beforeStart;
|
|
2955
2977
|
while (currentFinalLineIdx < startLineFinal - 1) {
|
|
2956
|
-
diffText += `[UI_CONTEXT]
|
|
2978
|
+
diffText += `[UI_CONTEXT] ${fmtNum(currentFinalLineIdx + 1)} |${allLinesFinal[currentFinalLineIdx] || ""}
|
|
2957
2979
|
`;
|
|
2958
2980
|
currentFinalLineIdx++;
|
|
2959
2981
|
}
|
|
2960
2982
|
} else {
|
|
2961
2983
|
while (currentFinalLineIdx < startLineFinal - 1) {
|
|
2962
|
-
diffText += `[UI_CONTEXT]
|
|
2984
|
+
diffText += `[UI_CONTEXT] ${fmtNum(currentFinalLineIdx + 1)} |${allLinesFinal[currentFinalLineIdx] || ""}
|
|
2963
2985
|
`;
|
|
2964
2986
|
currentFinalLineIdx++;
|
|
2965
2987
|
}
|
|
@@ -2981,7 +3003,7 @@ var init_text = __esm({
|
|
|
2981
3003
|
lineText = origIndent + line.trimStart();
|
|
2982
3004
|
}
|
|
2983
3005
|
}
|
|
2984
|
-
diffText += `-${res.originalStartLine + i}|${lineText}
|
|
3006
|
+
diffText += `-${fmtNum(res.originalStartLine + i)} |${lineText}
|
|
2985
3007
|
`;
|
|
2986
3008
|
});
|
|
2987
3009
|
let hunkEndInFinal = currentFinalLineIdx;
|
|
@@ -3004,7 +3026,7 @@ var init_text = __esm({
|
|
|
3004
3026
|
}
|
|
3005
3027
|
}
|
|
3006
3028
|
while (currentFinalLineIdx < hunkEndInFinal) {
|
|
3007
|
-
diffText += `+${currentFinalLineIdx + 1}|${allLinesFinal[currentFinalLineIdx] || ""}
|
|
3029
|
+
diffText += `+${fmtNum(currentFinalLineIdx + 1)} |${allLinesFinal[currentFinalLineIdx] || ""}
|
|
3008
3030
|
`;
|
|
3009
3031
|
currentFinalLineIdx++;
|
|
3010
3032
|
}
|
|
@@ -3013,7 +3035,7 @@ var init_text = __esm({
|
|
|
3013
3035
|
if (lastSuccessfulHunk !== null) {
|
|
3014
3036
|
let limit = Math.min(allLinesFinal.length, currentFinalLineIdx + 3);
|
|
3015
3037
|
while (currentFinalLineIdx < limit) {
|
|
3016
|
-
diffText += `[UI_CONTEXT]
|
|
3038
|
+
diffText += `[UI_CONTEXT] ${fmtNum(currentFinalLineIdx + 1)} |${allLinesFinal[currentFinalLineIdx] || ""}
|
|
3017
3039
|
`;
|
|
3018
3040
|
currentFinalLineIdx++;
|
|
3019
3041
|
}
|
|
@@ -3453,7 +3475,7 @@ var init_text = __esm({
|
|
|
3453
3475
|
cleanSignals = (text, isThinkRole = false) => {
|
|
3454
3476
|
if (!text) return text;
|
|
3455
3477
|
if (isThinkRole) {
|
|
3456
|
-
return text.replace(/^<(think|thought)>/gi, "").replace(/<\/(think|thought)>$/gi, "");
|
|
3478
|
+
return text.replace(/^<(think|thought)>/gi, "").replace(/<\/(think|thought)>$/gi, "").replace(/^\r?\n+/, "").replace(/\r?\n+$/, "");
|
|
3457
3479
|
}
|
|
3458
3480
|
let result = text.replace(REGEX_INITIAL_THINK, "</think>").replace(REGEX_INITIAL_TOOL, (match, _nl, offset, str) => !bypassBacktick && isInsideBacktick(str, offset) ? match : "");
|
|
3459
3481
|
if (result && result.includes("[tool:")) {
|
|
@@ -6977,7 +6999,8 @@ TOOL RULES:
|
|
|
6977
6999
|
${mode === "Flux" ? `- JSON ESCAPE ALL LITERAL ESCAPE SEQUENCES IN TOOL ARGUMENTS
|
|
6978
7000
|
- SAME file, MULTIPLE edits? ONE PatchFile (\u226415 blocks) \u2190 PRIORITY
|
|
6979
7001
|
- Tool denied? Ask for guidance \u2190 MANDATORY
|
|
6980
|
-
- Need text or
|
|
7002
|
+
- Need text or HUGE file? SearchKeyword > Full Read
|
|
7003
|
+
- MUST AVOID UNNECESSARY LARGE-FILE CHUNK READS
|
|
6981
7004
|
` : ""}
|
|
6982
7005
|
- COMMUNICATION WITH USER -
|
|
6983
7006
|
- [tool:functions.Ask(question="...", optionA="title::description", ...MAX4)]. Ambiguity: MUST for path divergence, security risk. Ask, don't finish/guess. Keep titles short
|
|
@@ -6989,7 +7012,7 @@ ${mode === "Flux" ? `- JSON ESCAPE ALL LITERAL ESCAPE SEQUENCES IN TOOL ARGUMENT
|
|
|
6989
7012
|
${mode === "Flux" ? `- WORKSPACE TOOLS (path = relative; FIRST ARGUMENT, path separator: '/') -
|
|
6990
7013
|
- [tool:functions.ReadFile(path="...", startLine="integer", endLine="integer")]. ${aiProvider !== "Google" ? `${isMultiModal ? `Supports images/docs` : ""}` : `Supports images/docs`}
|
|
6991
7014
|
- [tool:functions.ReadFolder(path="...", recurse="integer 1-3 optional, default: 1")]. DIR Contents + File Size. Minimize recursion
|
|
6992
|
-
- [tool:functions.PatchFile(path="...", allowMultiple="bool optional, default: false", searchContent1="string OR ^LINE:start..end$", newContent1="...", ...MAX15)]. TARGET MINIMAL DIFF. "^LINE:start..end$"
|
|
7015
|
+
- [tool:functions.PatchFile(path="...", allowMultiple="bool optional, default: false", searchContent1="string OR ^LINE:start..end$", newContent1="...", ...MAX15)]. TARGET MINIMAL DIFF. Line Ranges "^LINE:start..end$" MUST for multi-line selection or escape sequences. Verify diffs
|
|
6993
7016
|
- [tool:functions.WriteFile(path="...", content="...")]. Creates/Overwrites. File Exist? PatchFile > WriteFile
|
|
6994
7017
|
- [tool:functions.SearchKeyword(keyword="...", path="optional, dir/file/glob/regex", fuzzy="bool optional, default: false", regex="bool optional, default: auto")]. path scopes search. Find definitions, logic, relevant code
|
|
6995
7018
|
- [tool:functions.Run(command="...")]. Runs ${osDetected === "Windows" ? isPsAvailable() ? `POWERSHELL` : `WINDOWS CMD` : `BASH`} command. Destructive/Irreversible ops \u2192 Ask user
|
|
@@ -9863,7 +9886,7 @@ ${projectContextBlock}${isMemoryEnabled ? `
|
|
|
9863
9886
|
-- MEMORY RULES --
|
|
9864
9887
|
- Subtly Personalize with RELEVENT CONTEXTUAL MEMORIES. Auto Saves
|
|
9865
9888
|
` : ""}
|
|
9866
|
-
-- SECURITY
|
|
9889
|
+
-- SECURITY POLICIES --
|
|
9867
9890
|
- Sensitive files? Ask before Read${isSystemDir ? "\n- PROTECTED DIRECTORY" : ""}
|
|
9868
9891
|
|
|
9869
9892
|
-- CHAT FORMATTING --
|
|
@@ -10494,11 +10517,12 @@ var init_history = __esm({
|
|
|
10494
10517
|
// src/utils/usage.js
|
|
10495
10518
|
import fs11 from "fs-extra";
|
|
10496
10519
|
import path9 from "path";
|
|
10497
|
-
var generateSaveId, cachedUsage, writeTimeout, lastWriteTime, isDirty, defaultStats, purgeOldHistory, loadUsageFromFile, flushUsage, queueFlush, initUsage, forceFlushUsage, getDailyUsage, getMonthlyUsage, incrementUsage, runtimeSession, addToUsage, getCustomPeriodUsage, checkQuota, getImageQuotaBuckets, getImageQuotaLimit, checkImageQuota, getImageQuotaStats, recordImageGeneration;
|
|
10520
|
+
var generateSaveId, cachedUsage, writeTimeout, lastWriteTime, isDirty, defaultStats, purgeOldHistory, loadUsageFromFile, flushUsage, queueFlush, initUsage, forceFlushUsage, getDailyUsage, getMonthlyUsage, incrementUsage, runtimeSession, addToUsage, getCustomPeriodUsage, checkQuotaDetailed, checkQuota, getImageQuotaBuckets, getImageQuotaLimit, checkImageQuota, getImageQuotaStats, recordImageGeneration;
|
|
10498
10521
|
var init_usage = __esm({
|
|
10499
10522
|
"src/utils/usage.js"() {
|
|
10500
10523
|
init_paths();
|
|
10501
10524
|
init_crypto();
|
|
10525
|
+
init_settings();
|
|
10502
10526
|
generateSaveId = () => Math.random().toString(36).substring(2) + Date.now().toString(36);
|
|
10503
10527
|
cachedUsage = null;
|
|
10504
10528
|
writeTimeout = null;
|
|
@@ -10935,14 +10959,16 @@ var init_usage = __esm({
|
|
|
10935
10959
|
}
|
|
10936
10960
|
return summed;
|
|
10937
10961
|
};
|
|
10938
|
-
|
|
10939
|
-
const
|
|
10940
|
-
const
|
|
10962
|
+
checkQuotaDetailed = async (key, settings = {}) => {
|
|
10963
|
+
const loadedSettings = await loadSettings().catch(() => ({}));
|
|
10964
|
+
const tier = settings.apiTier || loadedSettings.apiTier || "Free";
|
|
10965
|
+
const quotas = settings.quotas || settings.systemSettings?.quotas || loadedSettings.quotas || {};
|
|
10966
|
+
const providerBudgets = quotas.providerBudgets || {};
|
|
10967
|
+
const useProvider = !!providerBudgets.__useProvider;
|
|
10968
|
+
const currentProvider = settings.aiProvider || loadedSettings.aiProvider || "Google";
|
|
10969
|
+
const isPerProvider = useProvider && !!providerBudgets[currentProvider];
|
|
10941
10970
|
const resolveAgentLimits = () => {
|
|
10942
|
-
|
|
10943
|
-
const useProvider = !!providerBudgets.__useProvider;
|
|
10944
|
-
const currentProvider = settings.aiProvider || "Google";
|
|
10945
|
-
if (useProvider && providerBudgets[currentProvider]) {
|
|
10971
|
+
if (isPerProvider) {
|
|
10946
10972
|
const pb = providerBudgets[currentProvider];
|
|
10947
10973
|
return {
|
|
10948
10974
|
agentLimit: typeof pb.agentLimit === "number" && pb.agentLimit > 0 ? pb.agentLimit : 99999999,
|
|
@@ -10956,55 +10982,74 @@ var init_usage = __esm({
|
|
|
10956
10982
|
monthlyTokenLimit: quotas.monthlyTokenLimit || 99999999999999
|
|
10957
10983
|
};
|
|
10958
10984
|
};
|
|
10959
|
-
if (
|
|
10960
|
-
|
|
10961
|
-
|
|
10962
|
-
|
|
10963
|
-
|
|
10964
|
-
|
|
10965
|
-
|
|
10966
|
-
|
|
10967
|
-
|
|
10968
|
-
|
|
10969
|
-
|
|
10970
|
-
|
|
10985
|
+
if (key === "agent") {
|
|
10986
|
+
const { agentLimit, tokenLimit, monthlyTokenLimit } = resolveAgentLimits();
|
|
10987
|
+
const dailyUsage = await getDailyUsage();
|
|
10988
|
+
let monthlyUsage;
|
|
10989
|
+
if (quotas.resetMode === "Custom") {
|
|
10990
|
+
monthlyUsage = await getCustomPeriodUsage(quotas.resetDay || 1);
|
|
10991
|
+
} else {
|
|
10992
|
+
monthlyUsage = await getMonthlyUsage();
|
|
10993
|
+
}
|
|
10994
|
+
let dailyAgentCount = 0;
|
|
10995
|
+
let dailyTokenCount = 0;
|
|
10996
|
+
let monthlyTokenCount = 0;
|
|
10997
|
+
if (isPerProvider) {
|
|
10998
|
+
dailyAgentCount = dailyUsage.providerRequests?.[currentProvider] || 0;
|
|
10999
|
+
const dailyModels = dailyUsage.models?.[currentProvider] || {};
|
|
11000
|
+
for (const m in dailyModels) {
|
|
11001
|
+
dailyTokenCount += dailyModels[m]?.tokens || 0;
|
|
11002
|
+
}
|
|
11003
|
+
const monthlyModels = monthlyUsage.models?.[currentProvider] || {};
|
|
11004
|
+
for (const m in monthlyModels) {
|
|
11005
|
+
monthlyTokenCount += monthlyModels[m]?.tokens || 0;
|
|
10971
11006
|
}
|
|
10972
|
-
|
|
11007
|
+
} else {
|
|
11008
|
+
dailyAgentCount = dailyUsage.agent || 0;
|
|
11009
|
+
dailyTokenCount = dailyUsage.tokens || 0;
|
|
11010
|
+
monthlyTokenCount = monthlyUsage.tokens || 0;
|
|
10973
11011
|
}
|
|
10974
|
-
if (
|
|
10975
|
-
|
|
10976
|
-
if (dailyUsage.agent + dailyUsage.background >= 999999) return false;
|
|
10977
|
-
return dailyUsage.background < (quotas.backgroundLimit || 999999);
|
|
11012
|
+
if (tier === "Free" && dailyUsage.agent + dailyUsage.background >= 999999) {
|
|
11013
|
+
return { allowed: false, reason: "Free Tier Daily Usage Limit Exceeded" };
|
|
10978
11014
|
}
|
|
10979
|
-
if (
|
|
10980
|
-
|
|
10981
|
-
|
|
11015
|
+
if (dailyAgentCount >= agentLimit) {
|
|
11016
|
+
return {
|
|
11017
|
+
allowed: false,
|
|
11018
|
+
reason: isPerProvider ? `Daily Request Limit Reached for ${currentProvider}` : `Daily Agent Request Limit Reached`
|
|
11019
|
+
};
|
|
10982
11020
|
}
|
|
10983
|
-
|
|
10984
|
-
|
|
10985
|
-
|
|
10986
|
-
|
|
10987
|
-
|
|
10988
|
-
const dailyOk = dailyUsage.agent < agentLimit && (dailyUsage.tokens || 0) < tokenLimit;
|
|
10989
|
-
if (!dailyOk) return false;
|
|
10990
|
-
let monthlyUsage;
|
|
10991
|
-
if (quotas.resetMode === "Custom") {
|
|
10992
|
-
monthlyUsage = await getCustomPeriodUsage(quotas.resetDay || 1);
|
|
10993
|
-
} else {
|
|
10994
|
-
monthlyUsage = await getMonthlyUsage();
|
|
10995
|
-
}
|
|
10996
|
-
return (monthlyUsage.tokens || 0) < monthlyTokenLimit;
|
|
11021
|
+
if (dailyTokenCount >= tokenLimit) {
|
|
11022
|
+
return {
|
|
11023
|
+
allowed: false,
|
|
11024
|
+
reason: isPerProvider ? `Daily Token Budget Exhausted for ${currentProvider}` : `Daily Token Budget Exhausted`
|
|
11025
|
+
};
|
|
10997
11026
|
}
|
|
10998
|
-
if (
|
|
10999
|
-
|
|
11000
|
-
|
|
11027
|
+
if (monthlyTokenCount >= monthlyTokenLimit) {
|
|
11028
|
+
return {
|
|
11029
|
+
allowed: false,
|
|
11030
|
+
reason: isPerProvider ? `Monthly Token Budget Exhausted for ${currentProvider}` : `Monthly Token Budget Exhausted`
|
|
11031
|
+
};
|
|
11001
11032
|
}
|
|
11002
|
-
|
|
11003
|
-
|
|
11004
|
-
|
|
11033
|
+
return { allowed: true };
|
|
11034
|
+
}
|
|
11035
|
+
if (key === "background") {
|
|
11036
|
+
const dailyUsage = await getDailyUsage();
|
|
11037
|
+
if (tier === "Free" && dailyUsage.agent + dailyUsage.background >= 999999) {
|
|
11038
|
+
return { allowed: false, reason: "Free Tier Background Limit Exceeded" };
|
|
11005
11039
|
}
|
|
11040
|
+
const ok = dailyUsage.background < (quotas.backgroundLimit || 999999);
|
|
11041
|
+
return { allowed: ok, reason: ok ? void 0 : "Background Request Limit Exceeded" };
|
|
11006
11042
|
}
|
|
11007
|
-
|
|
11043
|
+
if (key === "search") {
|
|
11044
|
+
const dailyUsage = await getDailyUsage();
|
|
11045
|
+
const ok = dailyUsage.search < (quotas.searchLimit || 100);
|
|
11046
|
+
return { allowed: ok, reason: ok ? void 0 : "Search Quota Exceeded" };
|
|
11047
|
+
}
|
|
11048
|
+
return { allowed: true };
|
|
11049
|
+
};
|
|
11050
|
+
checkQuota = async (key, settings = {}) => {
|
|
11051
|
+
const res = await checkQuotaDetailed(key, settings);
|
|
11052
|
+
return res.allowed;
|
|
11008
11053
|
};
|
|
11009
11054
|
getImageQuotaBuckets = (imageCalls) => {
|
|
11010
11055
|
const hourMs = 60 * 60 * 1e3;
|
|
@@ -11321,7 +11366,7 @@ var init_web_search = __esm({
|
|
|
11321
11366
|
init_paths();
|
|
11322
11367
|
init_puppeteer_helper();
|
|
11323
11368
|
web_search = async (argsString) => {
|
|
11324
|
-
const { query, limit =
|
|
11369
|
+
const { query, limit = 5, aiMode = false } = parseArgs(argsString);
|
|
11325
11370
|
if (!query) return 'ERROR: Missing "query" argument for web_search.';
|
|
11326
11371
|
const maxRetries = 3;
|
|
11327
11372
|
let lastError = null;
|
|
@@ -11894,22 +11939,22 @@ ${lines.map((l, i) => `${i + 1} | ${l}`).join("\n")}
|
|
|
11894
11939
|
return `ERROR: CRITICAL FAILURE: Verification failed. File [${targetPath}] is empty on disk despite success report!`;
|
|
11895
11940
|
}
|
|
11896
11941
|
let snippet = "";
|
|
11897
|
-
if (verifiedLineCount <=
|
|
11942
|
+
if (verifiedLineCount <= 100) {
|
|
11898
11943
|
snippet = verifiedLines.join("\n");
|
|
11899
11944
|
} else {
|
|
11900
|
-
const head = verifiedLines.slice(0,
|
|
11901
|
-
const tail = verifiedLines.slice(-
|
|
11945
|
+
const head = verifiedLines.slice(0, 50).join("\n");
|
|
11946
|
+
const tail = verifiedLines.slice(-50).join("\n");
|
|
11902
11947
|
snippet = `${head}
|
|
11903
11948
|
|
|
11904
|
-
... [${verifiedLineCount -
|
|
11949
|
+
... [${verifiedLineCount - 100} lines truncated] ...
|
|
11905
11950
|
|
|
11906
11951
|
${tail}`;
|
|
11907
11952
|
}
|
|
11908
11953
|
verifiedContent = null;
|
|
11909
11954
|
return `SUCCESS: File [${targetPath}] saved.
|
|
11910
|
-
|
|
11911
11955
|
- Stats: [${verifiedLineCount} lines, ${(verifiedSize / 1024).toFixed(1)} KB]
|
|
11912
11956
|
${ancestry}- Content Preview:
|
|
11957
|
+
|
|
11913
11958
|
${snippet}`;
|
|
11914
11959
|
} catch (err) {
|
|
11915
11960
|
const errorMsg = err instanceof Error ? err.message : String(err);
|
|
@@ -15372,34 +15417,51 @@ var init_ai = __esm({
|
|
|
15372
15417
|
for (const line of lines) {
|
|
15373
15418
|
const cleanLine = line.trim();
|
|
15374
15419
|
if (!cleanLine || !cleanLine.startsWith("data: ")) continue;
|
|
15375
|
-
|
|
15376
|
-
|
|
15377
|
-
|
|
15378
|
-
|
|
15379
|
-
|
|
15380
|
-
|
|
15381
|
-
|
|
15382
|
-
|
|
15383
|
-
|
|
15384
|
-
|
|
15385
|
-
cachedContentTokenCount: usage.prompt_tokens_details?.cached_tokens || 0,
|
|
15386
|
-
thoughtsTokenCount: usage.completion_tokens_details?.reasoning_tokens || 0
|
|
15387
|
-
};
|
|
15388
|
-
hasNewData = true;
|
|
15389
|
-
}
|
|
15390
|
-
if (delta) {
|
|
15391
|
-
const thought = delta.reasoning_content || null;
|
|
15392
|
-
if (thought) {
|
|
15393
|
-
pendingParts.push({ text: thought, thought: true });
|
|
15394
|
-
hasNewData = true;
|
|
15420
|
+
let isDone = false;
|
|
15421
|
+
if (cleanLine === "data: [DONE]") {
|
|
15422
|
+
isDone = true;
|
|
15423
|
+
} else {
|
|
15424
|
+
try {
|
|
15425
|
+
const json = JSON.parse(cleanLine.substring(6));
|
|
15426
|
+
const delta = json.choices?.[0]?.delta;
|
|
15427
|
+
const usage = json.usage;
|
|
15428
|
+
if (json.choices?.[0]?.finish_reason) {
|
|
15429
|
+
isDone = true;
|
|
15395
15430
|
}
|
|
15396
|
-
if (
|
|
15397
|
-
|
|
15431
|
+
if (usage) {
|
|
15432
|
+
latestUsageMetadata = {
|
|
15433
|
+
totalTokenCount: usage.total_tokens || usage.prompt_tokens + usage.completion_tokens,
|
|
15434
|
+
promptTokenCount: usage.prompt_tokens || 0,
|
|
15435
|
+
candidatesTokenCount: usage.completion_tokens || 0,
|
|
15436
|
+
cachedContentTokenCount: usage.prompt_tokens_details?.cached_tokens || 0,
|
|
15437
|
+
thoughtsTokenCount: usage.completion_tokens_details?.reasoning_tokens || 0
|
|
15438
|
+
};
|
|
15398
15439
|
hasNewData = true;
|
|
15399
15440
|
}
|
|
15441
|
+
if (delta) {
|
|
15442
|
+
const thought = delta.reasoning_content || null;
|
|
15443
|
+
if (thought) {
|
|
15444
|
+
pendingParts.push({ text: thought, thought: true });
|
|
15445
|
+
hasNewData = true;
|
|
15446
|
+
}
|
|
15447
|
+
if (delta.content) {
|
|
15448
|
+
pendingParts.push({ text: delta.content });
|
|
15449
|
+
hasNewData = true;
|
|
15450
|
+
}
|
|
15451
|
+
}
|
|
15452
|
+
} catch (e) {
|
|
15400
15453
|
}
|
|
15401
|
-
} catch (e) {
|
|
15402
15454
|
}
|
|
15455
|
+
if ((isDone || Date.now() - lastFlushTime >= 150) && hasNewData) {
|
|
15456
|
+
yield {
|
|
15457
|
+
candidates: pendingParts.length > 0 ? [{ content: { parts: [...pendingParts] } }] : [],
|
|
15458
|
+
usageMetadata: latestUsageMetadata
|
|
15459
|
+
};
|
|
15460
|
+
pendingParts = [];
|
|
15461
|
+
lastFlushTime = Date.now();
|
|
15462
|
+
hasNewData = false;
|
|
15463
|
+
}
|
|
15464
|
+
if (isDone) break;
|
|
15403
15465
|
}
|
|
15404
15466
|
if (Date.now() - lastFlushTime >= 150 && hasNewData) {
|
|
15405
15467
|
yield {
|
|
@@ -15497,33 +15559,50 @@ var init_ai = __esm({
|
|
|
15497
15559
|
for (const line of lines) {
|
|
15498
15560
|
const cleanLine = line.trim();
|
|
15499
15561
|
if (!cleanLine || !cleanLine.startsWith("data: ")) continue;
|
|
15500
|
-
|
|
15501
|
-
|
|
15502
|
-
|
|
15503
|
-
|
|
15504
|
-
|
|
15505
|
-
|
|
15506
|
-
|
|
15507
|
-
|
|
15508
|
-
|
|
15509
|
-
|
|
15510
|
-
cachedContentTokenCount: usage.prompt_tokens_details?.cached_tokens || 0,
|
|
15511
|
-
thoughtsTokenCount: 0
|
|
15512
|
-
};
|
|
15513
|
-
hasNewData = true;
|
|
15514
|
-
}
|
|
15515
|
-
if (delta) {
|
|
15516
|
-
if (delta.thinking) {
|
|
15517
|
-
pendingParts.push({ text: delta.thinking, thought: true });
|
|
15518
|
-
hasNewData = true;
|
|
15562
|
+
let isDone = false;
|
|
15563
|
+
if (cleanLine === "data: [DONE]") {
|
|
15564
|
+
isDone = true;
|
|
15565
|
+
} else {
|
|
15566
|
+
try {
|
|
15567
|
+
const json = JSON.parse(cleanLine.substring(6));
|
|
15568
|
+
const delta = json.choices?.[0]?.delta;
|
|
15569
|
+
const usage = json.usage;
|
|
15570
|
+
if (json.choices?.[0]?.finish_reason) {
|
|
15571
|
+
isDone = true;
|
|
15519
15572
|
}
|
|
15520
|
-
if (
|
|
15521
|
-
|
|
15573
|
+
if (usage) {
|
|
15574
|
+
latestUsageMetadata = {
|
|
15575
|
+
totalTokenCount: usage.total_tokens || (usage.prompt_tokens || 0) + (usage.completion_tokens || 0),
|
|
15576
|
+
promptTokenCount: usage.prompt_tokens || 0,
|
|
15577
|
+
candidatesTokenCount: usage.completion_tokens || 0,
|
|
15578
|
+
cachedContentTokenCount: usage.prompt_tokens_details?.cached_tokens || 0,
|
|
15579
|
+
thoughtsTokenCount: 0
|
|
15580
|
+
};
|
|
15522
15581
|
hasNewData = true;
|
|
15523
15582
|
}
|
|
15583
|
+
if (delta) {
|
|
15584
|
+
if (delta.thinking) {
|
|
15585
|
+
pendingParts.push({ text: delta.thinking, thought: true });
|
|
15586
|
+
hasNewData = true;
|
|
15587
|
+
}
|
|
15588
|
+
if (delta.content) {
|
|
15589
|
+
pendingParts.push({ text: delta.content });
|
|
15590
|
+
hasNewData = true;
|
|
15591
|
+
}
|
|
15592
|
+
}
|
|
15593
|
+
} catch (e) {
|
|
15524
15594
|
}
|
|
15525
|
-
} catch (e) {
|
|
15526
15595
|
}
|
|
15596
|
+
if ((isDone || Date.now() - lastFlushTime >= 150) && hasNewData) {
|
|
15597
|
+
yield {
|
|
15598
|
+
candidates: pendingParts.length > 0 ? [{ content: { parts: [...pendingParts] } }] : [],
|
|
15599
|
+
usageMetadata: latestUsageMetadata
|
|
15600
|
+
};
|
|
15601
|
+
pendingParts = [];
|
|
15602
|
+
lastFlushTime = Date.now();
|
|
15603
|
+
hasNewData = false;
|
|
15604
|
+
}
|
|
15605
|
+
if (isDone) break;
|
|
15527
15606
|
}
|
|
15528
15607
|
if (Date.now() - lastFlushTime >= 150 && hasNewData) {
|
|
15529
15608
|
yield {
|
|
@@ -15689,8 +15768,15 @@ var init_ai = __esm({
|
|
|
15689
15768
|
signal
|
|
15690
15769
|
});
|
|
15691
15770
|
if (!response.ok) {
|
|
15692
|
-
const
|
|
15693
|
-
|
|
15771
|
+
const errText = await response.text().catch(() => "");
|
|
15772
|
+
let errMsg = response.statusText;
|
|
15773
|
+
try {
|
|
15774
|
+
const errData = JSON.parse(errText);
|
|
15775
|
+
errMsg = errData.error?.message || errData.message || JSON.stringify(errData.detail || errData);
|
|
15776
|
+
} catch {
|
|
15777
|
+
if (errText) errMsg = errText;
|
|
15778
|
+
}
|
|
15779
|
+
const error = new Error(`NVIDIA API Error (${response.status}): ${errMsg}`);
|
|
15694
15780
|
error.status = response.status;
|
|
15695
15781
|
throw error;
|
|
15696
15782
|
}
|
|
@@ -15716,9 +15802,14 @@ var init_ai = __esm({
|
|
|
15716
15802
|
buffer += decoder.decode(value, { stream: true });
|
|
15717
15803
|
const lines = buffer.split("\n");
|
|
15718
15804
|
buffer = lines.pop();
|
|
15805
|
+
let isDone = false;
|
|
15719
15806
|
for (const line of lines) {
|
|
15720
15807
|
const trimmed = line.trim();
|
|
15721
|
-
if (!trimmed
|
|
15808
|
+
if (!trimmed) continue;
|
|
15809
|
+
if (trimmed === "data: [DONE]") {
|
|
15810
|
+
isDone = true;
|
|
15811
|
+
break;
|
|
15812
|
+
}
|
|
15722
15813
|
if (trimmed.startsWith("data: ")) {
|
|
15723
15814
|
let json;
|
|
15724
15815
|
try {
|
|
@@ -15729,6 +15820,9 @@ var init_ai = __esm({
|
|
|
15729
15820
|
if (json.error) {
|
|
15730
15821
|
throw new Error(`NVIDIA Stream Error: ${json.error.message || JSON.stringify(json.error)}`);
|
|
15731
15822
|
}
|
|
15823
|
+
if (json.choices?.[0]?.finish_reason) {
|
|
15824
|
+
isDone = true;
|
|
15825
|
+
}
|
|
15732
15826
|
try {
|
|
15733
15827
|
const usage = json.usage;
|
|
15734
15828
|
if (usage) {
|
|
@@ -15755,7 +15849,7 @@ var init_ai = __esm({
|
|
|
15755
15849
|
}
|
|
15756
15850
|
}
|
|
15757
15851
|
}
|
|
15758
|
-
if (Date.now() - lastFlushTime >= 350 && hasNewData) {
|
|
15852
|
+
if ((isDone || Date.now() - lastFlushTime >= 350) && hasNewData) {
|
|
15759
15853
|
yield {
|
|
15760
15854
|
candidates: pendingParts.length > 0 ? [{ content: { parts: [...pendingParts] } }] : [],
|
|
15761
15855
|
usageMetadata: latestUsageMetadata
|
|
@@ -15765,6 +15859,7 @@ var init_ai = __esm({
|
|
|
15765
15859
|
lastFlushTime = Date.now();
|
|
15766
15860
|
hasNewData = false;
|
|
15767
15861
|
}
|
|
15862
|
+
if (isDone) break;
|
|
15768
15863
|
}
|
|
15769
15864
|
break;
|
|
15770
15865
|
} catch (error) {
|
|
@@ -15982,43 +16077,51 @@ var init_ai = __esm({
|
|
|
15982
16077
|
for (const line of lines) {
|
|
15983
16078
|
const cleanLine = line.trim();
|
|
15984
16079
|
if (!cleanLine || !cleanLine.startsWith("data: ")) continue;
|
|
15985
|
-
|
|
15986
|
-
|
|
15987
|
-
|
|
15988
|
-
|
|
15989
|
-
|
|
15990
|
-
|
|
15991
|
-
|
|
15992
|
-
|
|
15993
|
-
|
|
15994
|
-
|
|
15995
|
-
cachedContentTokenCount: usage.prompt_tokens_details?.cached_tokens || usage.prompt_tokens_details?.cache_read_input_tokens || usage.cache_read_input_tokens || 0,
|
|
15996
|
-
thoughtsTokenCount: usage.completion_tokens_details?.reasoning_tokens || 0
|
|
15997
|
-
};
|
|
15998
|
-
hasNewData = true;
|
|
15999
|
-
}
|
|
16000
|
-
if (delta) {
|
|
16001
|
-
const thought = delta.reasoning || (delta.reasoning_details ? delta.reasoning_details.map((d) => d.text).join("") : null);
|
|
16002
|
-
if (thought) {
|
|
16003
|
-
pendingParts.push({ text: thought, thought: true });
|
|
16004
|
-
hasNewData = true;
|
|
16080
|
+
let isDone = false;
|
|
16081
|
+
if (cleanLine === "data: [DONE]") {
|
|
16082
|
+
isDone = true;
|
|
16083
|
+
} else {
|
|
16084
|
+
try {
|
|
16085
|
+
const json = JSON.parse(cleanLine.substring(6));
|
|
16086
|
+
const delta = json.choices?.[0]?.delta;
|
|
16087
|
+
const usage = json.usage;
|
|
16088
|
+
if (json.choices?.[0]?.finish_reason) {
|
|
16089
|
+
isDone = true;
|
|
16005
16090
|
}
|
|
16006
|
-
if (
|
|
16007
|
-
|
|
16091
|
+
if (usage) {
|
|
16092
|
+
latestUsageMetadata = {
|
|
16093
|
+
totalTokenCount: usage.total_tokens || (usage.prompt_tokens || 0) + (usage.completion_tokens || 0),
|
|
16094
|
+
promptTokenCount: usage.prompt_tokens || 0,
|
|
16095
|
+
candidatesTokenCount: usage.completion_tokens || 0,
|
|
16096
|
+
cachedContentTokenCount: usage.prompt_tokens_details?.cached_tokens || usage.prompt_tokens_details?.cache_read_input_tokens || usage.cache_read_input_tokens || 0,
|
|
16097
|
+
thoughtsTokenCount: usage.completion_tokens_details?.reasoning_tokens || 0
|
|
16098
|
+
};
|
|
16008
16099
|
hasNewData = true;
|
|
16009
16100
|
}
|
|
16101
|
+
if (delta) {
|
|
16102
|
+
const thought = delta.reasoning || (delta.reasoning_details ? delta.reasoning_details.map((d) => d.text).join("") : null);
|
|
16103
|
+
if (thought) {
|
|
16104
|
+
pendingParts.push({ text: thought, thought: true });
|
|
16105
|
+
hasNewData = true;
|
|
16106
|
+
}
|
|
16107
|
+
if (delta.content) {
|
|
16108
|
+
pendingParts.push({ text: delta.content });
|
|
16109
|
+
hasNewData = true;
|
|
16110
|
+
}
|
|
16111
|
+
}
|
|
16112
|
+
} catch (e) {
|
|
16010
16113
|
}
|
|
16011
|
-
} catch (e) {
|
|
16012
16114
|
}
|
|
16013
|
-
|
|
16014
|
-
|
|
16015
|
-
|
|
16016
|
-
|
|
16017
|
-
|
|
16018
|
-
|
|
16019
|
-
|
|
16020
|
-
|
|
16021
|
-
|
|
16115
|
+
if ((isDone || Date.now() - lastFlushTime >= 150) && hasNewData) {
|
|
16116
|
+
yield {
|
|
16117
|
+
candidates: pendingParts.length > 0 ? [{ content: { parts: [...pendingParts] } }] : [],
|
|
16118
|
+
usageMetadata: latestUsageMetadata
|
|
16119
|
+
};
|
|
16120
|
+
pendingParts = [];
|
|
16121
|
+
lastFlushTime = Date.now();
|
|
16122
|
+
hasNewData = false;
|
|
16123
|
+
}
|
|
16124
|
+
if (isDone) break;
|
|
16022
16125
|
}
|
|
16023
16126
|
}
|
|
16024
16127
|
};
|
|
@@ -16091,18 +16194,24 @@ var init_ai = __esm({
|
|
|
16091
16194
|
hasNewData = true;
|
|
16092
16195
|
}
|
|
16093
16196
|
if (chunk.done) {
|
|
16094
|
-
|
|
16095
|
-
|
|
16197
|
+
let cachedCount = chunk.prompt_cached_count || 0;
|
|
16198
|
+
if (!cachedCount && chunk.prompt_eval_count) {
|
|
16199
|
+
const evalNs = chunk.prompt_eval_duration || 0;
|
|
16200
|
+
if (evalNs > 0 && evalNs < 75e6) {
|
|
16201
|
+
cachedCount = chunk.prompt_eval_count;
|
|
16202
|
+
}
|
|
16203
|
+
}
|
|
16096
16204
|
latestUsageMetadata = {
|
|
16097
16205
|
totalTokenCount: (chunk.prompt_eval_count || 0) + (chunk.eval_count || 0),
|
|
16098
16206
|
promptTokenCount: chunk.prompt_eval_count || 0,
|
|
16099
16207
|
candidatesTokenCount: chunk.eval_count || 0,
|
|
16100
|
-
cachedContentTokenCount:
|
|
16208
|
+
cachedContentTokenCount: cachedCount,
|
|
16101
16209
|
thoughtsTokenCount: 0
|
|
16210
|
+
// Note: Ollama does not natively return a separate sub-count for thoughts yet
|
|
16102
16211
|
};
|
|
16103
16212
|
hasNewData = true;
|
|
16104
16213
|
}
|
|
16105
|
-
if (Date.now() - lastFlushTime >= 150 && hasNewData) {
|
|
16214
|
+
if (chunk.done || Date.now() - lastFlushTime >= 150 && hasNewData) {
|
|
16106
16215
|
yield {
|
|
16107
16216
|
candidates: pendingParts.length > 0 ? [{ content: { parts: [...pendingParts] } }] : [],
|
|
16108
16217
|
usageMetadata: latestUsageMetadata
|
|
@@ -17750,6 +17859,10 @@ ${wildcardToolingPrompt}${taggedContextStr}[USER PROMPT] ${cleanPromptForModel.t
|
|
|
17750
17859
|
let fullAgentResponseChunks = [];
|
|
17751
17860
|
let wasToolCalledInLastLoop = false;
|
|
17752
17861
|
for (let loop = 0; loop <= MAX_LOOPS; loop++) {
|
|
17862
|
+
const quotaCheck = await checkQuotaDetailed("agent", settings);
|
|
17863
|
+
if (!quotaCheck.allowed) {
|
|
17864
|
+
throw new Error(quotaCheck.reason || `Budget Exhausted for Provider (${aiProvider || "Agent"})`);
|
|
17865
|
+
}
|
|
17753
17866
|
const currentTurnTools = [];
|
|
17754
17867
|
wasToolCalledInLastLoop = false;
|
|
17755
17868
|
if (systemSettings2?.compression === 0 && (sessionStats?.tokens || 0) > contextTruncationCount) {
|
|
@@ -17850,16 +17963,30 @@ ${combinedNudge}`;
|
|
|
17850
17963
|
if (!text || !text.includes("[tool:")) return text;
|
|
17851
17964
|
const THINK_OPEN_PH = "___THINK_OPEN_TAG___";
|
|
17852
17965
|
const THINK_CLOSE_PH = "___THINK_CLOSE_TAG___";
|
|
17853
|
-
text = text.
|
|
17854
|
-
text = text.replace(/<(\w+)(?:[^>]*)>\s*([\s\S]*?\[tool:[^\]]*\][\s\S]*?)\s*<\/\1>/gi, (match2, tagName, innerContent) => {
|
|
17855
|
-
if (innerContent && innerContent.includes("[tool:")) return innerContent.trim();
|
|
17856
|
-
return match2;
|
|
17857
|
-
});
|
|
17966
|
+
text = text.replace("<think>", THINK_OPEN_PH).replace("</think>", THINK_CLOSE_PH);
|
|
17858
17967
|
text = text.replace(/```(?:tool|yaml|function|json)?\s*\n?([\s\S]*?)\n?\```/gi, (match2, inner) => {
|
|
17859
17968
|
if (inner.includes("[tool:")) return inner.trim();
|
|
17860
17969
|
return match2;
|
|
17861
17970
|
});
|
|
17862
|
-
|
|
17971
|
+
let result = "";
|
|
17972
|
+
let i = 0;
|
|
17973
|
+
while (i < text.length) {
|
|
17974
|
+
const toolIdx = text.indexOf("[tool:", i);
|
|
17975
|
+
if (toolIdx === -1) {
|
|
17976
|
+
result += text.substring(i).replace(/<(\w+)(?:[^>]*)>\r?\n?/gi, "").replace(/\r?\n?<\/\w+(?:[^>]*)>/gi, "");
|
|
17977
|
+
break;
|
|
17978
|
+
}
|
|
17979
|
+
const beforeTool = text.substring(i, toolIdx);
|
|
17980
|
+
result += beforeTool.replace(/<(\w+)(?:[^>]*)>\r?\n?/gi, "").replace(/\r?\n?<\/\w+(?:[^>]*)>/gi, "");
|
|
17981
|
+
const endToolIdx = text.indexOf("]", toolIdx);
|
|
17982
|
+
if (endToolIdx === -1) {
|
|
17983
|
+
result += text.substring(toolIdx);
|
|
17984
|
+
break;
|
|
17985
|
+
}
|
|
17986
|
+
result += text.substring(toolIdx, endToolIdx + 1);
|
|
17987
|
+
i = endToolIdx + 1;
|
|
17988
|
+
}
|
|
17989
|
+
text = result;
|
|
17863
17990
|
text = text.replaceAll(THINK_OPEN_PH, "<think>").replaceAll(THINK_CLOSE_PH, "</think>");
|
|
17864
17991
|
return text;
|
|
17865
17992
|
};
|
|
@@ -17933,9 +18060,6 @@ ${combinedNudge}`;
|
|
|
17933
18060
|
}
|
|
17934
18061
|
contents.length = 0;
|
|
17935
18062
|
contents.push(...finalContents);
|
|
17936
|
-
if (!await checkQuota("agent", settings)) {
|
|
17937
|
-
throw new Error("Error: Quota Exausted for Agent");
|
|
17938
|
-
}
|
|
17939
18063
|
targetModel = modelName;
|
|
17940
18064
|
const sysInstructionCacheKey2 = `${chatId}|${aiProvider}|${thinkingLevel}|${targetModel}|${JSON.stringify(profile)}|${!!systemSettings2?.dynamicDirAwareness}|${!!systemSettings2?.subAgents}`;
|
|
17941
18065
|
let isCacheHit = systemInstructionCache.key === sysInstructionCacheKey2 && systemInstructionCache.value;
|
|
@@ -19274,14 +19398,14 @@ ${oldLines.map((l, i) => `${i + 1} | ${l}`).join("\n")}
|
|
|
19274
19398
|
`;
|
|
19275
19399
|
}
|
|
19276
19400
|
let snippet = "";
|
|
19277
|
-
if (verifiedLineCount <=
|
|
19401
|
+
if (verifiedLineCount <= 100) {
|
|
19278
19402
|
snippet = verifiedLines.join("\n");
|
|
19279
19403
|
} else {
|
|
19280
|
-
const head = verifiedLines.slice(0,
|
|
19281
|
-
const tail = verifiedLines.slice(-
|
|
19404
|
+
const head = verifiedLines.slice(0, 50).join("\n");
|
|
19405
|
+
const tail = verifiedLines.slice(-50).join("\n");
|
|
19282
19406
|
snippet = `${head}
|
|
19283
19407
|
|
|
19284
|
-
... [${verifiedLineCount -
|
|
19408
|
+
... [${verifiedLineCount - 100} lines truncated for history stability] ...
|
|
19285
19409
|
|
|
19286
19410
|
${tail}`;
|
|
19287
19411
|
}
|
|
@@ -19304,21 +19428,21 @@ ${oldLines.map((l, i) => `${i + 1} | ${l}`).join("\n")}
|
|
|
19304
19428
|
`;
|
|
19305
19429
|
}
|
|
19306
19430
|
let snippet2 = "";
|
|
19307
|
-
if (verifiedLineCount2 <=
|
|
19431
|
+
if (verifiedLineCount2 <= 100) {
|
|
19308
19432
|
snippet2 = verifiedLines2.join("\n");
|
|
19309
19433
|
} else {
|
|
19310
|
-
const head = verifiedLines2.slice(0,
|
|
19311
|
-
const tail = verifiedLines2.slice(-
|
|
19434
|
+
const head = verifiedLines2.slice(0, 50).join("\n");
|
|
19435
|
+
const tail = verifiedLines2.slice(-50).join("\n");
|
|
19312
19436
|
snippet2 = `${head}
|
|
19313
19437
|
|
|
19314
|
-
... [${verifiedLineCount2 -
|
|
19438
|
+
... [${verifiedLineCount2 - 100} lines truncated] ...
|
|
19315
19439
|
|
|
19316
19440
|
${tail}`;
|
|
19317
19441
|
}
|
|
19318
19442
|
result2 = `SUCCESS: File [${filePath}] saved via IDE Companion (May have user edits).
|
|
19319
|
-
|
|
19320
19443
|
- Stats: [${verifiedLineCount2} lines, ${(verifiedSize2 / 1024).toFixed(1)} KB]
|
|
19321
19444
|
${ancestry2}- Content Preview:
|
|
19445
|
+
|
|
19322
19446
|
${snippet2}`;
|
|
19323
19447
|
}
|
|
19324
19448
|
const action = normToolName === "write_file" ? "Created" : "Edited";
|
|
@@ -19565,7 +19689,7 @@ ${snippet2}`;
|
|
|
19565
19689
|
await incrementUsage("toolFailure");
|
|
19566
19690
|
if (settings.onToolResult) settings.onToolResult("failure", normToolName);
|
|
19567
19691
|
}
|
|
19568
|
-
const aiContent = `[TOOL RESULT]: ${(result || "").toString().replaceAll("[UI_CONTEXT]", "
|
|
19692
|
+
const aiContent = `[TOOL RESULT]: ${(result || "").toString().replaceAll("[UI_CONTEXT]", "")}`;
|
|
19569
19693
|
toolResults.push({ role: "user", text: aiContent, binaryPart });
|
|
19570
19694
|
anyToolExecutedInThisTurn = true;
|
|
19571
19695
|
let uiContent = `[TOOL RESULT]: ${result || ""}`;
|
|
@@ -19881,13 +20005,14 @@ Error Log can be found in ${path26.join(LOGS_DIR, "agent", "error.log")}`);
|
|
|
19881
20005
|
wasToolCalledInLastLoop = toolCallPointer > 0 || anyToolExecutedInThisTurn;
|
|
19882
20006
|
}
|
|
19883
20007
|
} catch (err) {
|
|
19884
|
-
const
|
|
20008
|
+
const rawErrStr = err instanceof Error ? (() => {
|
|
19885
20009
|
try {
|
|
19886
20010
|
return JSON.parse(JSON.parse(err.message).error.message).error.message;
|
|
19887
20011
|
} catch {
|
|
19888
|
-
return String(err);
|
|
20012
|
+
return err.message || String(err);
|
|
19889
20013
|
}
|
|
19890
20014
|
})() : String(err);
|
|
20015
|
+
const errLog = rawErrStr.replace(/^(Error:\s*)+/i, "");
|
|
19891
20016
|
const date = (/* @__PURE__ */ new Date()).toLocaleString();
|
|
19892
20017
|
const agentErrDir = path26.join(LOGS_DIR, "agent");
|
|
19893
20018
|
yield { type: "text", content: `\u274C CRITICAL ERROR: ${errLog.includes("fetch failed") ? "Failed to Connect. Check your Internet Connection or Wait a moment" : errLog}` };
|
|
@@ -19933,6 +20058,7 @@ Error Log can be found in ${path26.join(LOGS_DIR, "agent", "error.log")}`);
|
|
|
19933
20058
|
if (lower === "openrouter") return "OpenRouter";
|
|
19934
20059
|
if (lower === "nvidia") return "NVIDIA";
|
|
19935
20060
|
if (lower === "mistral") return "Mistral";
|
|
20061
|
+
if (lower === "ollama") return "Ollama";
|
|
19936
20062
|
return null;
|
|
19937
20063
|
};
|
|
19938
20064
|
const envSubagentProvider = normalizeProvider(envSubagentProviderRaw);
|
|
@@ -19997,6 +20123,7 @@ TOOL RULES:
|
|
|
19997
20123
|
- JSON ESCAPE ALL LITERAL ESCAPE SEQUENCES IN TOOL ARGUMENTS
|
|
19998
20124
|
- SAME file, MULTIPLE edits? ONE PatchFile (\u226415 blocks) \u2190 PRIORITY
|
|
19999
20125
|
- Need text or huge files? SearchKeyword > Full Read
|
|
20126
|
+
- MUST AVOID UNNECESSARY LARGE-FILE CHUNK READS
|
|
20000
20127
|
- Restricted Shell Access, No Deletion
|
|
20001
20128
|
- ONLY valid tools and syntax defined below are allowed
|
|
20002
20129
|
|
|
@@ -20013,7 +20140,7 @@ ${isAsync ? `- [tool:functions.AskMain(question="...")]. Communicate with PARENT
|
|
|
20013
20140
|
- [tool:functions.SearchKeyword(keyword="...", path="optional, dir/file/glob/regex", fuzzy="bool optional, default: false", regex="bool optional, default: auto")]. path scopes search. Find definitions, logic, relevant code
|
|
20014
20141
|
- [tool:functions.ReadFolder(path="...", recurse="integer 1-3 optional, default: 1")]. DIR Contents + File Size. Minimize recursion
|
|
20015
20142
|
- [tool:functions.ReadFile(path="...", startLine="integer", endLine="integer")]. View files
|
|
20016
|
-
- [tool:functions.PatchFile(path="...", allowMultiple="bool optional, default: false", searchContent1="string OR ^LINE:start..end$", newContent1="...", ...MAX15)]. TARGET MINIMAL DIFF. "^LINE:start..end$"
|
|
20143
|
+
- [tool:functions.PatchFile(path="...", allowMultiple="bool optional, default: false", searchContent1="string OR ^LINE:start..end$", newContent1="...", ...MAX15)]. TARGET MINIMAL DIFF. Line Ranges "^LINE:start..end$" MUST for multi-line selection or escape sequences. Verify diffs
|
|
20017
20144
|
- [tool:functions.WriteFile(path="...", content="...")]. Creates/Overwrites. File Exist? PatchFile > WriteFile. VERIFY IMPORTS
|
|
20018
20145
|
- [tool:functions.Run(command="...")]. Runs ${osDetected === "Windows" ? isPsAvailable() ? `WINDOWS POWERSHELL` : `WINDOWS CMD` : `BASH`} command. Destructive/Irreversible ops \u2192 Ask user`.trim();
|
|
20019
20146
|
const systemInstructionSubAgent = `=== START SYSTEM PROMPT ===
|
|
@@ -21325,9 +21452,13 @@ function App({ args = [] }) {
|
|
|
21325
21452
|
const commitActiveStreamingMessage = () => {
|
|
21326
21453
|
flushTypewriterNow();
|
|
21327
21454
|
if (activeStreamingMsgRef.current) {
|
|
21455
|
+
let msgText = flattenString(activeStreamingMsgRef.current.text);
|
|
21456
|
+
if (activeStreamingMsgRef.current.role === "think") {
|
|
21457
|
+
msgText = msgText.replace(/^\r?\n+/, "").replace(/\r?\n+$/, "");
|
|
21458
|
+
}
|
|
21328
21459
|
const msg = {
|
|
21329
21460
|
...activeStreamingMsgRef.current,
|
|
21330
|
-
text:
|
|
21461
|
+
text: msgText,
|
|
21331
21462
|
isStreaming: false
|
|
21332
21463
|
};
|
|
21333
21464
|
setMessages((prev) => {
|
|
@@ -21439,7 +21570,7 @@ function App({ args = [] }) {
|
|
|
21439
21570
|
}
|
|
21440
21571
|
const envModel = process.env.SUBAGENT_MODEL ? process.env.SUBAGENT_MODEL.trim() : null;
|
|
21441
21572
|
const envProviderRaw = process.env.SUBAGENT_PROVIDER ? process.env.SUBAGENT_PROVIDER.trim() : null;
|
|
21442
|
-
const ALL_PROVIDERS = ["Google", "DeepSeek", "OpenRouter", "NVIDIA", "Mistral"];
|
|
21573
|
+
const ALL_PROVIDERS = ["Google", "DeepSeek", "OpenRouter", "NVIDIA", "Mistral", "Ollama"];
|
|
21443
21574
|
const normalizeProvider = (pStr) => {
|
|
21444
21575
|
if (!pStr) return null;
|
|
21445
21576
|
const lower = pStr.toLowerCase();
|
|
@@ -21448,6 +21579,7 @@ function App({ args = [] }) {
|
|
|
21448
21579
|
if (lower === "openrouter") return "OpenRouter";
|
|
21449
21580
|
if (lower === "nvidia") return "NVIDIA";
|
|
21450
21581
|
if (lower === "mistral") return "Mistral";
|
|
21582
|
+
if (lower === "ollama") return "Ollama";
|
|
21451
21583
|
return null;
|
|
21452
21584
|
};
|
|
21453
21585
|
const envProvider = normalizeProvider(envProviderRaw);
|
|
@@ -21774,6 +21906,8 @@ function App({ args = [] }) {
|
|
|
21774
21906
|
const [providerBudgetCursor, setProviderBudgetCursor] = useState15(0);
|
|
21775
21907
|
const [pbsCursor, setPbsCursor] = useState15(0);
|
|
21776
21908
|
const [pbsSelected, setPbsSelected] = useState15({});
|
|
21909
|
+
const [pbfFormState, setPbfFormState] = useState15({});
|
|
21910
|
+
const [pbfFieldIndex, setPbfFieldIndex] = useState15(0);
|
|
21777
21911
|
const [systemSettings2, setSystemSettings] = useState15({ memory: true, theme: "Dark", compression: 0, autoExec: false, autoDeleteHistory: "7d", autoUpdate: false, updateManager: "npm", customUpdateCommand: "" });
|
|
21778
21912
|
const colors = useMemo2(() => getThemeColors(systemSettings2.theme), [systemSettings2.theme]);
|
|
21779
21913
|
const [profileData, setProfileData] = useState15({ name: null, nickname: null, instructions: null });
|
|
@@ -21897,7 +22031,7 @@ function App({ args = [] }) {
|
|
|
21897
22031
|
return [...prev, {
|
|
21898
22032
|
id: "tier-switch-" + Date.now(),
|
|
21899
22033
|
role: "system",
|
|
21900
|
-
text: `**
|
|
22034
|
+
text: `**Switched to ${modelDisplayName}.`,
|
|
21901
22035
|
isMeta: true
|
|
21902
22036
|
}];
|
|
21903
22037
|
});
|
|
@@ -22272,7 +22406,7 @@ function App({ args = [] }) {
|
|
|
22272
22406
|
return;
|
|
22273
22407
|
}
|
|
22274
22408
|
if (activeView === "providerBudgetSelect") {
|
|
22275
|
-
const PBS_PROVIDERS = ["Google", "DeepSeek", "Mistral", "NVIDIA", "OpenRouter"];
|
|
22409
|
+
const PBS_PROVIDERS = ["Google", "DeepSeek", "Mistral", "NVIDIA", "OpenRouter", "Ollama"];
|
|
22276
22410
|
if (key.upArrow) {
|
|
22277
22411
|
setPbsCursor((c) => (c - 1 + PBS_PROVIDERS.length) % PBS_PROVIDERS.length);
|
|
22278
22412
|
return;
|
|
@@ -22299,6 +22433,41 @@ function App({ args = [] }) {
|
|
|
22299
22433
|
}
|
|
22300
22434
|
return;
|
|
22301
22435
|
}
|
|
22436
|
+
if (activeView === "providerBudgetFlow") {
|
|
22437
|
+
const totalFields = providerBudgetQueue.length * 2 + 1;
|
|
22438
|
+
if (key.upArrow) {
|
|
22439
|
+
setPbfFieldIndex((i) => Math.max(0, i - 1));
|
|
22440
|
+
return;
|
|
22441
|
+
} else if (key.downArrow) {
|
|
22442
|
+
setPbfFieldIndex((i) => Math.min(totalFields - 1, i + 1));
|
|
22443
|
+
return;
|
|
22444
|
+
} else if (key.return) {
|
|
22445
|
+
if (pbfFieldIndex === totalFields - 1) {
|
|
22446
|
+
const rawPB = quotas.providerBudgets || {};
|
|
22447
|
+
const cleaned = { __useProvider: true };
|
|
22448
|
+
for (const prov of providerBudgetQueue) {
|
|
22449
|
+
const formProv = pbfFormState[prov] || {};
|
|
22450
|
+
cleaned[prov] = {
|
|
22451
|
+
agentLimit: 9999999999,
|
|
22452
|
+
tokenLimit: parseInt(formProv.tokenLimit, 10) || 0,
|
|
22453
|
+
monthlyTokenLimit: parseInt(formProv.monthlyTokenLimit, 10) || 0
|
|
22454
|
+
};
|
|
22455
|
+
}
|
|
22456
|
+
const finalCleanedQuotas = { ...quotas, providerBudgets: cleaned };
|
|
22457
|
+
setQuotas(finalCleanedQuotas);
|
|
22458
|
+
saveSettings({ apiTier, quotas: finalCleanedQuotas });
|
|
22459
|
+
const returnMode = budgetReturnView === "settings" ? "resetMode" : "budgetResetMode";
|
|
22460
|
+
setActiveView(returnMode);
|
|
22461
|
+
} else {
|
|
22462
|
+
setPbfFieldIndex((i) => Math.min(totalFields - 1, i + 1));
|
|
22463
|
+
}
|
|
22464
|
+
return;
|
|
22465
|
+
} else if (key.escape) {
|
|
22466
|
+
setActiveView("providerBudgetSelect");
|
|
22467
|
+
return;
|
|
22468
|
+
}
|
|
22469
|
+
return;
|
|
22470
|
+
}
|
|
22302
22471
|
if (key.escape) {
|
|
22303
22472
|
if (showBtwBox) {
|
|
22304
22473
|
setShowBtwBox(false);
|
|
@@ -24469,7 +24638,7 @@ Selection: ${val}`,
|
|
|
24469
24638
|
if (afterText.match(/<\/(think|thought)>/i)) {
|
|
24470
24639
|
const parts = afterText.split(/<\/(think|thought)>/i);
|
|
24471
24640
|
const rawThinkContent = parts[0] || "";
|
|
24472
|
-
const thinkContent = rawThinkContent.replace(/^<(think|thought)
|
|
24641
|
+
const thinkContent = rawThinkContent.replace(/^<(think|thought)[^>]*>\r?\n?/i, "").replace(/\r?\n?$/g, "");
|
|
24473
24642
|
const agentContent = parts.slice(2).join("").replace(/<\/?(think|thought)>/gi, "");
|
|
24474
24643
|
activeStreamingMsgRef.current.text = flattenString(thinkContent);
|
|
24475
24644
|
const startTime = activeStreamingMsgRef.current.startTime || Date.now();
|
|
@@ -24482,7 +24651,7 @@ Selection: ${val}`,
|
|
|
24482
24651
|
appendStreamText(agentContent);
|
|
24483
24652
|
}
|
|
24484
24653
|
} else {
|
|
24485
|
-
let thinkStartText = afterText.replace(/^<(think|thought)
|
|
24654
|
+
let thinkStartText = afterText.replace(/^<(think|thought)[^>]*>\r?\n?/gi, "");
|
|
24486
24655
|
appendStreamText(thinkStartText);
|
|
24487
24656
|
}
|
|
24488
24657
|
continue;
|
|
@@ -24719,7 +24888,7 @@ Selection: ${val}`,
|
|
|
24719
24888
|
}, [suggestionVisibleCount, suggestions.length]);
|
|
24720
24889
|
useEffect12(() => {
|
|
24721
24890
|
if (activeView !== "providerBudgetSelect") return;
|
|
24722
|
-
const PBS_PROVIDERS = ["Google", "DeepSeek", "Mistral", "NVIDIA", "OpenRouter"];
|
|
24891
|
+
const PBS_PROVIDERS = ["Google", "DeepSeek", "Mistral", "NVIDIA", "OpenRouter", "Ollama"];
|
|
24723
24892
|
const existingBudgets = quotas.providerBudgets || {};
|
|
24724
24893
|
const initialSelected = PBS_PROVIDERS.reduce((acc, p) => {
|
|
24725
24894
|
acc[p] = !!(existingBudgets[p] && (existingBudgets[p].agentLimit || existingBudgets[p].tokenLimit));
|
|
@@ -24730,74 +24899,19 @@ Selection: ${val}`,
|
|
|
24730
24899
|
}, [activeView]);
|
|
24731
24900
|
useEffect12(() => {
|
|
24732
24901
|
if (activeView !== "providerBudgetFlow") return;
|
|
24733
|
-
const
|
|
24734
|
-
|
|
24735
|
-
|
|
24736
|
-
const
|
|
24737
|
-
|
|
24738
|
-
|
|
24739
|
-
|
|
24740
|
-
|
|
24741
|
-
|
|
24742
|
-
setQuotas(finalCleanedQuotas);
|
|
24743
|
-
saveSettings({ apiTier, quotas: finalCleanedQuotas });
|
|
24744
|
-
setActiveView(returnMode);
|
|
24745
|
-
return;
|
|
24902
|
+
const initialForm = {};
|
|
24903
|
+
const existingPBs = quotas.providerBudgets || {};
|
|
24904
|
+
for (const prov of providerBudgetQueue) {
|
|
24905
|
+
const pb = existingPBs[prov] || {};
|
|
24906
|
+
initialForm[prov] = {
|
|
24907
|
+
agentLimit: getPrefilledValue(pb.agentLimit),
|
|
24908
|
+
tokenLimit: getPrefilledValue(pb.tokenLimit),
|
|
24909
|
+
monthlyTokenLimit: getPrefilledValue(pb.monthlyTokenLimit)
|
|
24910
|
+
};
|
|
24746
24911
|
}
|
|
24747
|
-
|
|
24748
|
-
|
|
24749
|
-
|
|
24750
|
-
const providerLabel = `[${currentStep}/${totalProviders}] ${currentProvider}`;
|
|
24751
|
-
const advanceToNext = (finalQuotas) => {
|
|
24752
|
-
if (providerBudgetCursor + 1 < providerBudgetQueue.length) {
|
|
24753
|
-
setProviderBudgetCursor((c) => c + 1);
|
|
24754
|
-
setActiveView("providerBudgetFlow");
|
|
24755
|
-
} else {
|
|
24756
|
-
const rawPB = finalQuotas.providerBudgets || {};
|
|
24757
|
-
const cleaned = { __useProvider: true };
|
|
24758
|
-
for (const prov of providerBudgetQueue) {
|
|
24759
|
-
if (rawPB[prov]) cleaned[prov] = rawPB[prov];
|
|
24760
|
-
}
|
|
24761
|
-
const finalCleanedQuotas = { ...finalQuotas, providerBudgets: cleaned };
|
|
24762
|
-
setQuotas(finalCleanedQuotas);
|
|
24763
|
-
const rm = budgetReturnView === "settings" ? "resetMode" : "budgetResetMode";
|
|
24764
|
-
saveSettings({ apiTier, quotas: finalCleanedQuotas });
|
|
24765
|
-
setActiveView(rm);
|
|
24766
|
-
}
|
|
24767
|
-
};
|
|
24768
|
-
setInputConfig({
|
|
24769
|
-
label: `${providerLabel} \u2014 Daily budget (requests/day):`,
|
|
24770
|
-
key: "providerBudgets",
|
|
24771
|
-
providerKey: currentProvider,
|
|
24772
|
-
subKey: "agentLimit",
|
|
24773
|
-
value: getPrefilledValue(existingPB.agentLimit),
|
|
24774
|
-
returnView: "providerBudgetSelect",
|
|
24775
|
-
next: (newQuotas) => {
|
|
24776
|
-
const updatedPB = (newQuotas.providerBudgets || {})[currentProvider] || {};
|
|
24777
|
-
return {
|
|
24778
|
-
label: `${providerLabel} \u2014 Daily budget (tokens/day):`,
|
|
24779
|
-
key: "providerBudgets",
|
|
24780
|
-
providerKey: currentProvider,
|
|
24781
|
-
subKey: "tokenLimit",
|
|
24782
|
-
value: getPrefilledValue(updatedPB.tokenLimit),
|
|
24783
|
-
returnView: "providerBudgetSelect",
|
|
24784
|
-
next: (q2) => {
|
|
24785
|
-
const pb2 = (q2.providerBudgets || {})[currentProvider] || {};
|
|
24786
|
-
return {
|
|
24787
|
-
label: `${providerLabel} \u2014 Monthly budget (tokens/month):`,
|
|
24788
|
-
key: "providerBudgets",
|
|
24789
|
-
providerKey: currentProvider,
|
|
24790
|
-
subKey: "monthlyTokenLimit",
|
|
24791
|
-
value: getPrefilledValue(pb2.monthlyTokenLimit),
|
|
24792
|
-
returnView: "providerBudgetFlow",
|
|
24793
|
-
onDone: advanceToNext
|
|
24794
|
-
};
|
|
24795
|
-
}
|
|
24796
|
-
};
|
|
24797
|
-
}
|
|
24798
|
-
});
|
|
24799
|
-
setActiveView("input");
|
|
24800
|
-
}, [activeView, providerBudgetCursor]);
|
|
24912
|
+
setPbfFormState(initialForm);
|
|
24913
|
+
setPbfFieldIndex(0);
|
|
24914
|
+
}, [activeView, providerBudgetQueue]);
|
|
24801
24915
|
const CustomMenuItem = ({ label, isSelected }) => {
|
|
24802
24916
|
const isCancel = label === "Cancel" || label === "Back" || label.toLowerCase().includes("exit") || label.toLowerCase().includes("back");
|
|
24803
24917
|
return /* @__PURE__ */ React16.createElement(
|
|
@@ -24811,10 +24925,9 @@ Selection: ${val}`,
|
|
|
24811
24925
|
/* @__PURE__ */ React16.createElement(Text16, { color: isSelected ? "white" : "gray", bold: isSelected }, isSelected ? "\u276F " : " ", label)
|
|
24812
24926
|
);
|
|
24813
24927
|
};
|
|
24814
|
-
const renderProgressBar = (label, current, limit) => {
|
|
24928
|
+
const renderProgressBar = (label, current, limit, barWidth = 10, paddingLeft = 2, labelWidth = 9) => {
|
|
24815
24929
|
const actualPercent = limit > 0 ? Math.min(100, current / limit * 100) : 0;
|
|
24816
24930
|
const percent = Math.round(actualPercent);
|
|
24817
|
-
const barWidth = 15;
|
|
24818
24931
|
const filledCount = Math.round(percent / 100 * barWidth);
|
|
24819
24932
|
const barStr = "\u2588".repeat(filledCount) + "\u2591".repeat(Math.max(0, barWidth - filledCount));
|
|
24820
24933
|
let barColor = colors.success || "green";
|
|
@@ -24823,7 +24936,7 @@ Selection: ${val}`,
|
|
|
24823
24936
|
} else if (percent > 80) {
|
|
24824
24937
|
barColor = colors.danger || "red";
|
|
24825
24938
|
}
|
|
24826
|
-
const isTokens = label.toLowerCase().includes("token");
|
|
24939
|
+
const isTokens = label.toLowerCase().includes("token") || label.toLowerCase().includes("daily") || label.toLowerCase().includes("monthly");
|
|
24827
24940
|
const displayLimit = shouldClearValue(limit) ? "\u221E" : isTokens ? formatTokens(limit) : limit;
|
|
24828
24941
|
const displayCurrent = isTokens ? formatTokens(current) : current;
|
|
24829
24942
|
let displayPercent;
|
|
@@ -24834,7 +24947,7 @@ Selection: ${val}`,
|
|
|
24834
24947
|
} else {
|
|
24835
24948
|
displayPercent = `${percent}%`;
|
|
24836
24949
|
}
|
|
24837
|
-
return /* @__PURE__ */ React16.createElement(Box14, { flexDirection: "row", paddingLeft
|
|
24950
|
+
return /* @__PURE__ */ React16.createElement(Box14, { flexDirection: "row", paddingLeft, key: label }, /* @__PURE__ */ React16.createElement(Box14, { width: labelWidth }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, label, ": ")), /* @__PURE__ */ React16.createElement(Text16, { color: barColor }, barStr), /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, " ", displayPercent, " (", displayCurrent, "/", displayLimit, ")"));
|
|
24838
24951
|
};
|
|
24839
24952
|
const renderActiveView = () => {
|
|
24840
24953
|
switch (activeView) {
|
|
@@ -25075,8 +25188,43 @@ Selection: ${val}`,
|
|
|
25075
25188
|
return /* @__PURE__ */ React16.createElement(Box14, { key: prov, backgroundColor: isActive ? colors.highlightBg || "#2a2a2a" : void 0, paddingX: 1, width: "100%", flexDirection: "row" }, /* @__PURE__ */ React16.createElement(Text16, { color: isActive ? colors.text : colors.textMuted, bold: isActive }, isActive ? "\u276F " : " "), /* @__PURE__ */ React16.createElement(Text16, { color: isChecked ? colors.success || "green" : colors.textMuted }, isChecked ? "\u2611" : "\u2610"), /* @__PURE__ */ React16.createElement(Text16, { color: isActive ? colors.text : colors.textMuted, bold: isActive }, " ", prov), isChecked && quotas.providerBudgets?.[prov]?.agentLimit ? /* @__PURE__ */ React16.createElement(Text16, { color: colors.primary || "cyan" }, " (budget set)") : null);
|
|
25076
25189
|
}), /* @__PURE__ */ React16.createElement(Box14, { paddingX: 1, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted, italic: true }, "\u2191\u2193 Navigate \u2022 Space to toggle \u2022 Enter to confirm \u2022 ESC to go back"), !anySelected && /* @__PURE__ */ React16.createElement(Text16, { color: colors.warning || "yellow", italic: true }, " Select at least one provider to continue")));
|
|
25077
25190
|
}
|
|
25078
|
-
case "providerBudgetFlow":
|
|
25079
|
-
|
|
25191
|
+
case "providerBudgetFlow": {
|
|
25192
|
+
const fields = [];
|
|
25193
|
+
for (const prov of providerBudgetQueue) {
|
|
25194
|
+
fields.push({ provider: prov, subKey: "tokenLimit", label: "Daily Tokens (tokens/day)" });
|
|
25195
|
+
fields.push({ provider: prov, subKey: "monthlyTokenLimit", label: "Monthly Tokens (tokens/month)" });
|
|
25196
|
+
}
|
|
25197
|
+
const saveButtonIndex = fields.length;
|
|
25198
|
+
return /* @__PURE__ */ React16.createElement(Box14, { flexDirection: "column", borderStyle: "round", borderColor: colors.borderMuted, padding: 0, width: "100%" }, /* @__PURE__ */ React16.createElement(Box14, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.text, bold: true }, "PROVIDER BUDGET CONFIGURATION")), /* @__PURE__ */ React16.createElement(Box14, { paddingX: 1, paddingBottom: 0, marginBottom: 0 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted, italic: true }, "Set limits for selected providers (leave blank or 0 for no limit)")), providerBudgetQueue.map((prov) => {
|
|
25199
|
+
const provFields = fields.filter((f) => f.provider === prov);
|
|
25200
|
+
return /* @__PURE__ */ React16.createElement(Box14, { key: prov, flexDirection: "column", marginY: 0, paddingX: 1 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.primary || "cyan", bold: true }, `
|
|
25201
|
+
\u2500\u2500 ${prov} \u2500\u2500`), provFields.map((field) => {
|
|
25202
|
+
const fieldIdx = fields.findIndex((f) => f.provider === field.provider && f.subKey === field.subKey);
|
|
25203
|
+
const isFocused = pbfFieldIndex === fieldIdx;
|
|
25204
|
+
const currentVal = pbfFormState[field.provider]?.[field.subKey] ?? "";
|
|
25205
|
+
return /* @__PURE__ */ React16.createElement(Box14, { key: field.subKey, paddingLeft: 2, flexDirection: "row" }, /* @__PURE__ */ React16.createElement(Text16, { color: isFocused ? colors.text : colors.textMuted, bold: isFocused }, isFocused ? "\u276F " : " ", field.label.padEnd(30, " "), ": ", " "), isFocused ? /* @__PURE__ */ React16.createElement(
|
|
25206
|
+
TextInput4,
|
|
25207
|
+
{
|
|
25208
|
+
value: currentVal,
|
|
25209
|
+
onChange: (val) => {
|
|
25210
|
+
setPbfFormState((prev) => ({
|
|
25211
|
+
...prev,
|
|
25212
|
+
[prov]: {
|
|
25213
|
+
...prev[prov] || {},
|
|
25214
|
+
[field.subKey]: val
|
|
25215
|
+
}
|
|
25216
|
+
}));
|
|
25217
|
+
},
|
|
25218
|
+
onSubmit: () => {
|
|
25219
|
+
if (fieldIdx + 1 <= saveButtonIndex) {
|
|
25220
|
+
setPbfFieldIndex(fieldIdx + 1);
|
|
25221
|
+
}
|
|
25222
|
+
}
|
|
25223
|
+
}
|
|
25224
|
+
) : /* @__PURE__ */ React16.createElement(Text16, { color: currentVal ? colors.text : colors.textMuted }, currentVal ? currentVal : "0 (Unlimited)"));
|
|
25225
|
+
}));
|
|
25226
|
+
}), /* @__PURE__ */ React16.createElement(Box14, { paddingX: 2, marginTop: 1 }, pbfFieldIndex === saveButtonIndex ? /* @__PURE__ */ React16.createElement(Box14, { backgroundColor: colors.highlightBg || "#2a2a2a", paddingX: 1 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.success || "green", bold: true }, "\u276F [ Save & Apply Budgets ]")) : /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, " [ Save & Apply Budgets ]")), /* @__PURE__ */ React16.createElement(Box14, { paddingX: 1, marginTop: 1, flexDirection: "column" }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted, italic: true }, "\u2191\u2193 Navigate fields \u2022 Enter next / save \u2022 ESC to go back")));
|
|
25227
|
+
}
|
|
25080
25228
|
case "budgetResetMode":
|
|
25081
25229
|
return /* @__PURE__ */ React16.createElement(
|
|
25082
25230
|
CommandMenu,
|
|
@@ -25128,33 +25276,72 @@ Selection: ${val}`,
|
|
|
25128
25276
|
);
|
|
25129
25277
|
const limitsNotSet = !usingProviderBudgets && (shouldClearValue(reqLimit) || shouldClearValue(tokenLimit) || shouldClearValue(monthlyLimit));
|
|
25130
25278
|
let resetInfo = "";
|
|
25279
|
+
let resetCountdown = "";
|
|
25131
25280
|
if (quotas.resetMode === "Custom") {
|
|
25132
25281
|
const today2 = /* @__PURE__ */ new Date();
|
|
25133
25282
|
const resetDay = quotas.resetDay || 1;
|
|
25283
|
+
let resetYear = today2.getFullYear();
|
|
25134
25284
|
let resetMonth = today2.getMonth();
|
|
25135
25285
|
if (today2.getDate() >= resetDay) {
|
|
25136
25286
|
resetMonth += 1;
|
|
25287
|
+
if (resetMonth > 11) {
|
|
25288
|
+
resetMonth = 0;
|
|
25289
|
+
resetYear += 1;
|
|
25290
|
+
}
|
|
25137
25291
|
}
|
|
25138
|
-
const
|
|
25139
|
-
const monthName =
|
|
25292
|
+
const targetResetDate = new Date(resetYear, resetMonth, resetDay, 0, 0, 0);
|
|
25293
|
+
const monthName = targetResetDate.toLocaleString("default", { month: "short" }).toUpperCase();
|
|
25140
25294
|
resetInfo = `${monthName}-${resetDay}`;
|
|
25295
|
+
const diffMs = Math.max(0, targetResetDate.getTime() - today2.getTime());
|
|
25296
|
+
const totalHours = Math.floor(diffMs / (1e3 * 60 * 60));
|
|
25297
|
+
const daysLeft = Math.floor(totalHours / 24);
|
|
25298
|
+
const hoursLeft = totalHours % 24;
|
|
25299
|
+
resetCountdown = `(${daysLeft} days: ${hoursLeft} hrs left)`;
|
|
25141
25300
|
}
|
|
25142
|
-
return /* @__PURE__ */ React16.createElement(Box14, { flexDirection: "column", borderStyle: "round", borderColor: colors.borderMuted, padding: 1, width: "100%" }, /* @__PURE__ */ React16.createElement(Box14, { marginBottom: 1, justifyContent: "space-between", width: "100%" }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.text, bold: true, underline: true }, "BUDGET LIMIT STATUS"), /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "[ ESC to Close ]")), limitsNotSet ? /* @__PURE__ */ React16.createElement(Box14, { padding: 1, justifyContent: "center", alignItems: "center", width: "100%" }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.text, bold: true }, "LIMITS NOT SET")) : usingProviderBudgets && configuredProviders.length > 0 ? /* @__PURE__ */ React16.createElement(Box14, { flexDirection: "column", gap:
|
|
25143
|
-
const
|
|
25144
|
-
const
|
|
25145
|
-
|
|
25146
|
-
|
|
25147
|
-
|
|
25148
|
-
|
|
25149
|
-
|
|
25150
|
-
|
|
25151
|
-
|
|
25152
|
-
|
|
25153
|
-
|
|
25154
|
-
|
|
25301
|
+
return /* @__PURE__ */ React16.createElement(Box14, { flexDirection: "column", borderStyle: "round", borderColor: colors.borderMuted, padding: 1, paddingBottom: 0, width: "100%" }, /* @__PURE__ */ React16.createElement(Box14, { marginBottom: 1, justifyContent: "space-between", width: "100%" }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.text, bold: true, underline: true }, "BUDGET LIMIT STATUS"), /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "[ ESC to Close ]")), limitsNotSet ? /* @__PURE__ */ React16.createElement(Box14, { padding: 1, justifyContent: "center", alignItems: "center", width: "100%" }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.text, bold: true }, "LIMITS NOT SET")) : usingProviderBudgets && configuredProviders.length > 0 ? /* @__PURE__ */ React16.createElement(Box14, { flexDirection: "column", gap: 0, width: "100%" }, (() => {
|
|
25302
|
+
const cols = stdout?.columns || terminalSize?.columns || 80;
|
|
25303
|
+
const isNarrow = cols < 115;
|
|
25304
|
+
if (isNarrow) {
|
|
25305
|
+
const barW = Math.max(5, Math.min(30, cols - 50));
|
|
25306
|
+
return configuredProviders.map((prov) => {
|
|
25307
|
+
const pb = providerBudgetsMap[prov];
|
|
25308
|
+
let provTokenCurrent = 0;
|
|
25309
|
+
const dailyModels = dailyUsage?.models?.[prov] || {};
|
|
25310
|
+
for (const m in dailyModels) {
|
|
25311
|
+
provTokenCurrent += dailyModels[m]?.tokens || 0;
|
|
25312
|
+
}
|
|
25313
|
+
let provMonthlyCurrent = 0;
|
|
25314
|
+
const monthlySource = quotas.resetMode === "Custom" ? customPeriodUsage : monthlyUsage;
|
|
25315
|
+
const monthlyModels = monthlySource?.models?.[prov] || {};
|
|
25316
|
+
for (const m in monthlyModels) {
|
|
25317
|
+
provMonthlyCurrent += monthlyModels[m]?.tokens || 0;
|
|
25318
|
+
}
|
|
25319
|
+
return /* @__PURE__ */ React16.createElement(Box14, { key: prov, flexDirection: "column", borderStyle: "single", borderColor: colors.borderMuted, paddingX: 1, width: "100%" }, /* @__PURE__ */ React16.createElement(Box14, { marginBottom: 0 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.primary, bold: true }, "\u25C6 ", prov)), renderProgressBar("Daily", provTokenCurrent, pb.tokenLimit || 99999999999999, barW, 2, 9), renderProgressBar("Monthly", provMonthlyCurrent, pb.monthlyTokenLimit || 99999999999999, barW, 2, 9));
|
|
25320
|
+
});
|
|
25155
25321
|
}
|
|
25156
|
-
|
|
25157
|
-
|
|
25322
|
+
const rows = [];
|
|
25323
|
+
for (let i = 0; i < configuredProviders.length; i += 2) {
|
|
25324
|
+
rows.push(configuredProviders.slice(i, i + 2));
|
|
25325
|
+
}
|
|
25326
|
+
return rows.map((row, rIdx) => /* @__PURE__ */ React16.createElement(Box14, { key: rIdx, flexDirection: "row", width: "100%" }, row.map((prov) => {
|
|
25327
|
+
const pb = providerBudgetsMap[prov];
|
|
25328
|
+
let provTokenCurrent = 0;
|
|
25329
|
+
const dailyModels = dailyUsage?.models?.[prov] || {};
|
|
25330
|
+
for (const m in dailyModels) {
|
|
25331
|
+
provTokenCurrent += dailyModels[m]?.tokens || 0;
|
|
25332
|
+
}
|
|
25333
|
+
let provMonthlyCurrent = 0;
|
|
25334
|
+
const monthlySource = quotas.resetMode === "Custom" ? customPeriodUsage : monthlyUsage;
|
|
25335
|
+
const monthlyModels = monthlySource?.models?.[prov] || {};
|
|
25336
|
+
for (const m in monthlyModels) {
|
|
25337
|
+
provMonthlyCurrent += monthlyModels[m]?.tokens || 0;
|
|
25338
|
+
}
|
|
25339
|
+
const isFullWidth = row.length === 1;
|
|
25340
|
+
const targetCardCols = isFullWidth ? cols : Math.floor(cols / 2);
|
|
25341
|
+
const barW = Math.max(5, Math.min(25, targetCardCols - 36));
|
|
25342
|
+
return /* @__PURE__ */ React16.createElement(Box14, { key: prov, flexDirection: "column", borderStyle: "single", borderColor: colors.borderMuted, paddingX: 1, width: isFullWidth ? "100%" : "50%" }, /* @__PURE__ */ React16.createElement(Box14, { marginBottom: 0 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.primary, bold: true }, "\u25C6 ", prov)), renderProgressBar("Daily", provTokenCurrent, pb.tokenLimit || 99999999999999, barW, 2, 9), renderProgressBar("Monthly", provMonthlyCurrent, pb.monthlyTokenLimit || 99999999999999, barW, 2, 9));
|
|
25343
|
+
})));
|
|
25344
|
+
})(), resetInfo ? /* @__PURE__ */ React16.createElement(Box14, { marginLeft: 2, marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "Monthly Reset: "), /* @__PURE__ */ React16.createElement(Text16, { color: colors.accent || "magenta", bold: true }, resetInfo), resetCountdown ? /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, ` ${resetCountdown}`) : null) : /* @__PURE__ */ React16.createElement(Box14, { marginLeft: 2, marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "Monthly Reset: "), /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary || "blue", bold: true }, "Rolling 30-Day Window"))) : /* @__PURE__ */ React16.createElement(Box14, { flexDirection: "column", borderStyle: "single", borderColor: colors.borderMuted, paddingX: 1, width: "100%" }, renderProgressBar("Daily Tokens", tokenCurrent, tokenLimit, "green"), renderProgressBar("Monthly Tokens", monthlyCurrent, monthlyLimit, "yellow"), resetInfo ? /* @__PURE__ */ React16.createElement(Box14, { marginLeft: 4, marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "Monthly Reset: "), /* @__PURE__ */ React16.createElement(Text16, { color: colors.accent || "magenta", bold: true }, resetInfo), resetCountdown ? /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, ` ${resetCountdown}`) : null) : /* @__PURE__ */ React16.createElement(Box14, { marginLeft: 4, marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted }, "Monthly Reset: "), /* @__PURE__ */ React16.createElement(Text16, { color: colors.secondary || "blue", bold: true }, "Rolling 30-Day Window"))));
|
|
25158
25345
|
}
|
|
25159
25346
|
case "input":
|
|
25160
25347
|
return /* @__PURE__ */ React16.createElement(Box14, { flexDirection: "column", borderStyle: "round", borderColor: colors.borderMuted, padding: 0, width: "100%" }, /* @__PURE__ */ React16.createElement(Box14, { paddingX: 1 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.text, bold: true }, "DATA CONFIGURATION")), inputConfig?.note && /* @__PURE__ */ React16.createElement(Box14, { paddingX: 1, marginBottom: 1 }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted, italic: true }, inputConfig.note)), /* @__PURE__ */ React16.createElement(Box14, { paddingX: 1, flexDirection: "row" }, /* @__PURE__ */ React16.createElement(Text16, { color: colors.text, bold: true }, inputConfig?.label, " "), /* @__PURE__ */ React16.createElement(
|
|
@@ -25849,7 +26036,7 @@ Selection: ${val}`,
|
|
|
25849
26036
|
})(), /* @__PURE__ */ React16.createElement(
|
|
25850
26037
|
GlintText_default,
|
|
25851
26038
|
{
|
|
25852
|
-
text:
|
|
26039
|
+
text: activeModel.split("/")[1] || (activeModel.length > 1 ? activeModel : "Use '/model model-id' to select model"),
|
|
25853
26040
|
baseColor: colors.text,
|
|
25854
26041
|
glintColor: colors.textMuted,
|
|
25855
26042
|
glintWidth: 3
|
|
@@ -25938,7 +26125,7 @@ Selection: ${val}`,
|
|
|
25938
26125
|
onSubmit: handleSetup,
|
|
25939
26126
|
mask: "*"
|
|
25940
26127
|
}
|
|
25941
|
-
)))), /* @__PURE__ */ React16.createElement(Box14, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text16, { color: "gray", italic: true }, setupStep === 0 ? "(Use arrows to select and Enter to confirm, ESC to go back)" : "(Press Enter to confirm and initialize, ESC to go back)"))) : renderActiveView(), confirmExit && /* @__PURE__ */ React16.createElement(Box14, { borderStyle: "round", borderColor: colors.borderMuted, paddingX:
|
|
26128
|
+
)))), /* @__PURE__ */ React16.createElement(Box14, { paddingX: 1, marginTop: 1 }, /* @__PURE__ */ React16.createElement(Text16, { color: "gray", italic: true }, setupStep === 0 ? "(Use arrows to select and Enter to confirm, ESC to go back)" : "(Press Enter to confirm and initialize, ESC to go back)"))) : renderActiveView(), confirmExit && /* @__PURE__ */ React16.createElement(Box14, { borderStyle: "round", borderColor: colors.borderMuted, paddingX: 1, marginY: 0, width: "100%" }, /* @__PURE__ */ React16.createElement(Text16, null, /* @__PURE__ */ React16.createElement(Text16, { color: "red", bold: true }, "\u{1F534} EXIT: "), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, "Press "), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text, bold: true }, "CTRL+C"), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, " again to exit (", exitCountdown, "s) \u2022 Press "), /* @__PURE__ */ React16.createElement(Text16, { color: colors.textMuted, bold: true }, "ESC"), /* @__PURE__ */ React16.createElement(Text16, { color: colors.text }, " to cancel"))), suggestions.length > 0 && (() => {
|
|
25942
26129
|
const windowSize = 5;
|
|
25943
26130
|
let startIdx = suggestionOffsetRef.current;
|
|
25944
26131
|
let firstSelectableIndex = 0;
|