u-foo 2.3.21 → 2.3.23
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/package.json +1 -1
- package/src/agent/upstreamTransport.js +27 -4
- package/src/chat/agentViewController.js +41 -1
- package/src/chat/commandExecutor.js +4 -17
- package/src/chat/commands.js +1 -1
- package/src/code/agent.js +6 -4
- package/src/code/nativeRunner.js +6 -4
- package/src/code/tui.js +82 -9
- package/src/config.js +66 -2
- package/src/controller/gateRouter.js +18 -9
- package/src/daemon/run.js +6 -3
package/package.json
CHANGED
|
@@ -1,7 +1,12 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
3
|
const { randomUUID } = require("crypto");
|
|
4
|
-
const {
|
|
4
|
+
const {
|
|
5
|
+
loadConfig,
|
|
6
|
+
defaultAgentModelForProvider,
|
|
7
|
+
defaultRouterModelForProvider,
|
|
8
|
+
sameModelProvider,
|
|
9
|
+
} = require("../config");
|
|
5
10
|
const {
|
|
6
11
|
resolveRuntimeConfig,
|
|
7
12
|
resolveCompletionUrl,
|
|
@@ -30,6 +35,16 @@ const CODEX_DEFAULT_BASE_URL = "https://chatgpt.com/backend-api/codex";
|
|
|
30
35
|
const CODEX_DEFAULT_USER_AGENT = "codex-tui/0.118.0 (Mac OS 26.3.1; arm64) iTerm.app/3.6.9 (codex-tui; 0.118.0)";
|
|
31
36
|
const CODEX_DEFAULT_ORIGINATOR = "codex-tui";
|
|
32
37
|
|
|
38
|
+
function resolveConfiguredModelForProvider(config = {}, provider = "") {
|
|
39
|
+
if (config.routerProvider && sameModelProvider(config.routerProvider, provider)) {
|
|
40
|
+
return config.routerModel;
|
|
41
|
+
}
|
|
42
|
+
if (config.agentProvider && sameModelProvider(config.agentProvider, provider)) {
|
|
43
|
+
return config.agentModel;
|
|
44
|
+
}
|
|
45
|
+
return "";
|
|
46
|
+
}
|
|
47
|
+
|
|
33
48
|
function buildOpenAiChatRequest({
|
|
34
49
|
model = "",
|
|
35
50
|
systemPrompt = "",
|
|
@@ -217,7 +232,11 @@ async function resolveUpstreamRuntime({
|
|
|
217
232
|
const baseUrl = useCodexResponses
|
|
218
233
|
? String(env.UFOO_CODEX_BASE_URL || "").trim() || CODEX_DEFAULT_BASE_URL
|
|
219
234
|
: String(env.OPENAI_BASE_URL || "").trim() || "https://api.openai.com/v1";
|
|
220
|
-
const resolvedModel = String(
|
|
235
|
+
const resolvedModel = String(
|
|
236
|
+
model
|
|
237
|
+
|| resolveConfiguredModelForProvider(config, "codex")
|
|
238
|
+
|| defaultRouterModelForProvider("codex")
|
|
239
|
+
).trim();
|
|
221
240
|
return {
|
|
222
241
|
provider: "codex",
|
|
223
242
|
transport: useCodexResponses ? "codex-responses" : "openai-chat",
|
|
@@ -237,7 +256,11 @@ async function resolveUpstreamRuntime({
|
|
|
237
256
|
env,
|
|
238
257
|
});
|
|
239
258
|
const baseUrl = String(env.ANTHROPIC_BASE_URL || "").trim() || "https://api.anthropic.com/v1";
|
|
240
|
-
const resolvedModel = String(
|
|
259
|
+
const resolvedModel = String(
|
|
260
|
+
model
|
|
261
|
+
|| resolveConfiguredModelForProvider(config, "claude")
|
|
262
|
+
|| defaultRouterModelForProvider("claude")
|
|
263
|
+
).trim();
|
|
241
264
|
return {
|
|
242
265
|
provider: "claude",
|
|
243
266
|
transport: "anthropic-messages",
|
|
@@ -252,7 +275,7 @@ async function resolveUpstreamRuntime({
|
|
|
252
275
|
const runtime = resolveRuntimeConfig({
|
|
253
276
|
workspaceRoot: projectRoot,
|
|
254
277
|
provider: normalizedProvider === "ucode" ? "" : normalizedProvider,
|
|
255
|
-
model,
|
|
278
|
+
model: model || resolveConfiguredModelForProvider(config, normalizedProvider) || defaultAgentModelForProvider(config.agentProvider),
|
|
256
279
|
});
|
|
257
280
|
const auth = runtime.apiKey ? { apiKey: String(runtime.apiKey || "").trim() } : { headers: {} };
|
|
258
281
|
return {
|
|
@@ -61,6 +61,7 @@ function createAgentViewController(options = {}) {
|
|
|
61
61
|
let busLogLines = [];
|
|
62
62
|
let busStartupAgentId = "";
|
|
63
63
|
let busStartupLineCount = 0;
|
|
64
|
+
let busAgentReplyActive = false;
|
|
64
65
|
const originalRender = screen.render.bind(screen);
|
|
65
66
|
let renderFrozen = false;
|
|
66
67
|
|
|
@@ -361,6 +362,7 @@ function createAgentViewController(options = {}) {
|
|
|
361
362
|
function resetBusView(agentId) {
|
|
362
363
|
busInputValue = "";
|
|
363
364
|
busInputCursor = 0;
|
|
365
|
+
busAgentReplyActive = false;
|
|
364
366
|
busStartupAgentId = agentId || "";
|
|
365
367
|
const label = getAgentLabel(agentId);
|
|
366
368
|
const startupLines = staticStartupLines(agentId, label, getCols());
|
|
@@ -390,6 +392,42 @@ function createAgentViewController(options = {}) {
|
|
|
390
392
|
if (busLogLines.length > 1000) {
|
|
391
393
|
busLogLines = busLogLines.slice(-1000);
|
|
392
394
|
}
|
|
395
|
+
if (clean.endsWith("\n")) {
|
|
396
|
+
busAgentReplyActive = false;
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
function ensureBusLinePrefix(prefix = "") {
|
|
401
|
+
if (busLogLines.length === 0) {
|
|
402
|
+
busLogLines.push(prefix);
|
|
403
|
+
return;
|
|
404
|
+
}
|
|
405
|
+
if (busLogLines[busLogLines.length - 1] === "") {
|
|
406
|
+
busLogLines[busLogLines.length - 1] = prefix;
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
busLogLines.push(prefix);
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
function appendBusAgentReply(text = "") {
|
|
413
|
+
const clean = stripAnsi(String(text || "")).replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
414
|
+
if (!clean) return;
|
|
415
|
+
for (const char of clean) {
|
|
416
|
+
if (char === "\n") {
|
|
417
|
+
busLogLines.push("");
|
|
418
|
+
continue;
|
|
419
|
+
}
|
|
420
|
+
if (!busAgentReplyActive) {
|
|
421
|
+
ensureBusLinePrefix("• ");
|
|
422
|
+
busAgentReplyActive = true;
|
|
423
|
+
} else if (busLogLines.length === 0 || busLogLines[busLogLines.length - 1] === "") {
|
|
424
|
+
ensureBusLinePrefix(" ");
|
|
425
|
+
}
|
|
426
|
+
busLogLines[busLogLines.length - 1] += char;
|
|
427
|
+
}
|
|
428
|
+
if (busLogLines.length > 1000) {
|
|
429
|
+
busLogLines = busLogLines.slice(-1000);
|
|
430
|
+
}
|
|
393
431
|
}
|
|
394
432
|
|
|
395
433
|
function getBusInputViewport(width) {
|
|
@@ -533,6 +571,7 @@ function createAgentViewController(options = {}) {
|
|
|
533
571
|
busLogLines = [];
|
|
534
572
|
busStartupAgentId = "";
|
|
535
573
|
busStartupLineCount = 0;
|
|
574
|
+
busAgentReplyActive = false;
|
|
536
575
|
|
|
537
576
|
currentView = "main";
|
|
538
577
|
viewingAgent = null;
|
|
@@ -661,6 +700,7 @@ function createAgentViewController(options = {}) {
|
|
|
661
700
|
return;
|
|
662
701
|
}
|
|
663
702
|
appendBusLog(`> ${text}\n`);
|
|
703
|
+
busAgentReplyActive = false;
|
|
664
704
|
busInputValue = "";
|
|
665
705
|
busInputCursor = 0;
|
|
666
706
|
sendBusMessage(viewingAgent, text);
|
|
@@ -767,7 +807,7 @@ function createAgentViewController(options = {}) {
|
|
|
767
807
|
.replace(/\x1b\][^\x07\x1b]*(?:\x07|\x1b\\)/g, "")
|
|
768
808
|
.replace(/\x1b\[(?:[?>=]?[0-9]*c|[?]?6n|5n)/g, "");
|
|
769
809
|
if (agentViewUsesBus) {
|
|
770
|
-
|
|
810
|
+
appendBusAgentReply(cleaned);
|
|
771
811
|
renderBusView();
|
|
772
812
|
return;
|
|
773
813
|
}
|
|
@@ -9,6 +9,9 @@ const {
|
|
|
9
9
|
loadGlobalUcodeConfig,
|
|
10
10
|
saveGlobalUcodeConfig,
|
|
11
11
|
normalizeControllerMode,
|
|
12
|
+
SETTINGS_MODEL_DEFAULTS,
|
|
13
|
+
defaultAgentModelForProvider,
|
|
14
|
+
defaultRouterModelForProvider,
|
|
12
15
|
} = require("../config");
|
|
13
16
|
const { resolveTransport } = require("../code/nativeRunner");
|
|
14
17
|
const { resolveDisplayNickname } = require("../daemon/nicknameScope");
|
|
@@ -43,17 +46,6 @@ function defaultResolveTerminalApp() {
|
|
|
43
46
|
return "";
|
|
44
47
|
}
|
|
45
48
|
|
|
46
|
-
const SETTINGS_MODEL_DEFAULTS = Object.freeze({
|
|
47
|
-
agent: Object.freeze({
|
|
48
|
-
codex: "gpt-5.5",
|
|
49
|
-
claude: "opus-4.7",
|
|
50
|
-
}),
|
|
51
|
-
router: Object.freeze({
|
|
52
|
-
codex: "gpt-5.4-mini",
|
|
53
|
-
claude: "sonnet-4.7",
|
|
54
|
-
}),
|
|
55
|
-
});
|
|
56
|
-
|
|
57
49
|
function normalizeSettingsProvider(value = "", fallback = "codex-cli") {
|
|
58
50
|
const text = String(value || "").trim().toLowerCase();
|
|
59
51
|
if (text === "claude" || text === "claude-cli" || text === "claude-code" || text === "anthropic") {
|
|
@@ -69,13 +61,8 @@ function agentProviderKey(value = "") {
|
|
|
69
61
|
return normalizeSettingsProvider(value) === "claude-cli" ? "claude" : "codex";
|
|
70
62
|
}
|
|
71
63
|
|
|
72
|
-
function defaultAgentModelForProvider(value = "") {
|
|
73
|
-
return SETTINGS_MODEL_DEFAULTS.agent[agentProviderKey(value)] || SETTINGS_MODEL_DEFAULTS.agent.codex;
|
|
74
|
-
}
|
|
75
|
-
|
|
76
64
|
function defaultGateModelForProvider(value = "") {
|
|
77
|
-
|
|
78
|
-
return SETTINGS_MODEL_DEFAULTS.router[key] || SETTINGS_MODEL_DEFAULTS.router.codex;
|
|
65
|
+
return defaultRouterModelForProvider(value);
|
|
79
66
|
}
|
|
80
67
|
|
|
81
68
|
function collectHostLaunchRequestContext(env = process.env) {
|
package/src/chat/commands.js
CHANGED
|
@@ -113,7 +113,7 @@ const COMMAND_TREE = {
|
|
|
113
113
|
loop: { desc: "Set router mode to loop", order: 5 },
|
|
114
114
|
legacy: { desc: "Set router mode to legacy", order: 6 },
|
|
115
115
|
shadow: { desc: "Set router mode to shadow", order: 7 },
|
|
116
|
-
codex: { desc: "Use Codex gate model (gpt-5.
|
|
116
|
+
codex: { desc: "Use Codex gate model (gpt-5.3-codex-spark)", order: 8 },
|
|
117
117
|
claude: { desc: "Use Claude gate model (sonnet-4.7)", order: 9 },
|
|
118
118
|
},
|
|
119
119
|
},
|
package/src/code/agent.js
CHANGED
|
@@ -17,7 +17,7 @@ const {
|
|
|
17
17
|
stripLeakedEscapeTags,
|
|
18
18
|
} = require("./tui");
|
|
19
19
|
const { stripBlessedTags } = require("../chat/text");
|
|
20
|
-
const { loadConfig } = require("../config");
|
|
20
|
+
const { loadConfig, defaultAgentModelForProvider, sameModelProvider } = require("../config");
|
|
21
21
|
const {
|
|
22
22
|
resolveSessionId,
|
|
23
23
|
normalizeSessionId,
|
|
@@ -109,12 +109,14 @@ function resolveUcodeProviderModel({
|
|
|
109
109
|
|| ""
|
|
110
110
|
).trim();
|
|
111
111
|
const resolvedProvider = resolvePlannerProvider(explicitProvider || fallbackProviderFromAgent);
|
|
112
|
+
const configuredModel = sameModelProvider(config.ucodeProvider || config.agentProvider, resolvedProvider)
|
|
113
|
+
? (config.ucodeModel || config.agentModel)
|
|
114
|
+
: "";
|
|
112
115
|
const resolvedModel = String(
|
|
113
116
|
model
|
|
114
117
|
|| process.env.UFOO_UCODE_MODEL
|
|
115
|
-
||
|
|
116
|
-
||
|
|
117
|
-
|| ""
|
|
118
|
+
|| configuredModel
|
|
119
|
+
|| defaultAgentModelForProvider(resolvedProvider)
|
|
118
120
|
).trim();
|
|
119
121
|
return {
|
|
120
122
|
provider: resolvedProvider,
|
package/src/code/nativeRunner.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
const { randomUUID } = require("crypto");
|
|
2
|
-
const { loadConfig } = require("../config");
|
|
2
|
+
const { loadConfig, defaultAgentModelForProvider, sameModelProvider } = require("../config");
|
|
3
3
|
const { runToolCall } = require("./dispatch");
|
|
4
4
|
const { getReadToolDescription } = require("./prompts/toolDescriptions/read");
|
|
5
5
|
const { getWriteToolDescription } = require("./prompts/toolDescriptions/write");
|
|
@@ -219,13 +219,15 @@ function resolveRuntimeConfig({ workspaceRoot = process.cwd(), provider = "", mo
|
|
|
219
219
|
|| configuredProvider
|
|
220
220
|
|| "openai"
|
|
221
221
|
) || "openai";
|
|
222
|
+
const configuredModel = sameModelProvider(config.ucodeProvider || config.agentProvider, selectedProvider)
|
|
223
|
+
? (config.ucodeModel || config.agentModel)
|
|
224
|
+
: "";
|
|
222
225
|
|
|
223
226
|
const selectedModel = String(
|
|
224
227
|
model
|
|
225
228
|
|| process.env.UFOO_UCODE_MODEL
|
|
226
|
-
||
|
|
227
|
-
||
|
|
228
|
-
|| ""
|
|
229
|
+
|| configuredModel
|
|
230
|
+
|| defaultAgentModelForProvider(selectedProvider)
|
|
229
231
|
).trim();
|
|
230
232
|
|
|
231
233
|
const defaultBaseUrl = selectedProvider === "anthropic"
|
package/src/code/tui.js
CHANGED
|
@@ -18,6 +18,77 @@ const STATUS_INDICATORS = {
|
|
|
18
18
|
|
|
19
19
|
const ANSI_PATTERN = /\x1B\[[0-9;?]*[ -/]*[@-~]/g;
|
|
20
20
|
|
|
21
|
+
function charDisplayWidth(char = "") {
|
|
22
|
+
if (!char) return 0;
|
|
23
|
+
const code = char.codePointAt(0) || 0;
|
|
24
|
+
if (code === 0) return 0;
|
|
25
|
+
if (code < 32 || (code >= 0x7f && code < 0xa0)) return 0;
|
|
26
|
+
if ((code >= 0x0300 && code <= 0x036f) ||
|
|
27
|
+
(code >= 0x1ab0 && code <= 0x1aff) ||
|
|
28
|
+
(code >= 0x1dc0 && code <= 0x1dff) ||
|
|
29
|
+
(code >= 0x20d0 && code <= 0x20ff) ||
|
|
30
|
+
(code >= 0xfe20 && code <= 0xfe2f)) {
|
|
31
|
+
return 0;
|
|
32
|
+
}
|
|
33
|
+
if ((code >= 0x1100 && code <= 0x115f) ||
|
|
34
|
+
code === 0x2329 ||
|
|
35
|
+
code === 0x232a ||
|
|
36
|
+
(code >= 0x2e80 && code <= 0xa4cf) ||
|
|
37
|
+
(code >= 0xac00 && code <= 0xd7a3) ||
|
|
38
|
+
(code >= 0xf900 && code <= 0xfaff) ||
|
|
39
|
+
(code >= 0xfe10 && code <= 0xfe19) ||
|
|
40
|
+
(code >= 0xfe30 && code <= 0xfe6f) ||
|
|
41
|
+
(code >= 0xff00 && code <= 0xff60) ||
|
|
42
|
+
(code >= 0xffe0 && code <= 0xffe6) ||
|
|
43
|
+
(code >= 0x1f300 && code <= 0x1faff)) {
|
|
44
|
+
return 2;
|
|
45
|
+
}
|
|
46
|
+
return 1;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
function displayCellWidth(text = "") {
|
|
50
|
+
return Array.from(String(text || "").replace(ANSI_PATTERN, "")).reduce(
|
|
51
|
+
(sum, char) => sum + charDisplayWidth(char),
|
|
52
|
+
0
|
|
53
|
+
);
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function safeRead(getter, fallback = undefined) {
|
|
57
|
+
try {
|
|
58
|
+
return getter();
|
|
59
|
+
} catch {
|
|
60
|
+
return fallback;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function resolveLogContentWidth({ logBox = null, screen = null, fallback = 80 } = {}) {
|
|
65
|
+
const coords = safeRead(() => logBox && typeof logBox._getCoords === "function" ? logBox._getCoords() : null, null);
|
|
66
|
+
if (coords && Number.isFinite(coords.xl) && Number.isFinite(coords.xi)) {
|
|
67
|
+
return Math.max(1, coords.xl - coords.xi);
|
|
68
|
+
}
|
|
69
|
+
const width = safeRead(() => logBox && logBox.width, null);
|
|
70
|
+
if (typeof width === "number") return Math.max(1, width);
|
|
71
|
+
const screenWidth = safeRead(() => screen && screen.width, null);
|
|
72
|
+
if (typeof screenWidth === "number") return Math.max(1, screenWidth);
|
|
73
|
+
const screenCols = safeRead(() => screen && screen.cols, null);
|
|
74
|
+
if (typeof screenCols === "number") return Math.max(1, screenCols);
|
|
75
|
+
return Math.max(1, fallback);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function formatHighlightedUserInput(text = "", {
|
|
79
|
+
width = 80,
|
|
80
|
+
escapeText = (value) => String(value || ""),
|
|
81
|
+
} = {}) {
|
|
82
|
+
const plain = String(text || "").trim();
|
|
83
|
+
if (!plain) return "";
|
|
84
|
+
const targetWidth = Math.max(1, Math.floor(Number(width) || 80) - 1);
|
|
85
|
+
const prefix = " → ";
|
|
86
|
+
const suffix = " ";
|
|
87
|
+
const contentWidth = displayCellWidth(`${prefix}${plain}${suffix}`);
|
|
88
|
+
const pad = " ".repeat(Math.max(0, targetWidth - contentWidth));
|
|
89
|
+
return `{cyan-bg}{white-fg}${prefix}${escapeText(plain)}${suffix}${pad}{/white-fg}{/cyan-bg}`;
|
|
90
|
+
}
|
|
91
|
+
|
|
21
92
|
// Stream buffer for smooth output
|
|
22
93
|
class StreamBuffer {
|
|
23
94
|
constructor(writer, options = {}) {
|
|
@@ -627,8 +698,8 @@ function runUcodeTui({
|
|
|
627
698
|
blessed,
|
|
628
699
|
currentInputHeight: 4,
|
|
629
700
|
version: UCODE_VERSION,
|
|
630
|
-
logBorder:
|
|
631
|
-
logScrollbar:
|
|
701
|
+
logBorder: false,
|
|
702
|
+
logScrollbar: false,
|
|
632
703
|
});
|
|
633
704
|
|
|
634
705
|
if (completionPanel && typeof completionPanel.hide === "function") {
|
|
@@ -1027,13 +1098,12 @@ function runUcodeTui({
|
|
|
1027
1098
|
|
|
1028
1099
|
const logUserInput = (text = "") => {
|
|
1029
1100
|
activeToolMerge = null;
|
|
1030
|
-
const
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
|
|
1034
|
-
|
|
1035
|
-
|
|
1036
|
-
logBox.log(`{cyan-bg}{white-fg}${content}${pad}{/white-fg}{/cyan-bg}`);
|
|
1101
|
+
const line = formatHighlightedUserInput(text, {
|
|
1102
|
+
width: resolveLogContentWidth({ logBox, screen, fallback: (stdout && stdout.columns) || 80 }),
|
|
1103
|
+
escapeText: escapeBlessed,
|
|
1104
|
+
});
|
|
1105
|
+
if (!line) return;
|
|
1106
|
+
logBox.log(line);
|
|
1037
1107
|
logBox.log(""); // Add line break after user input
|
|
1038
1108
|
screen.render();
|
|
1039
1109
|
};
|
|
@@ -1911,6 +1981,9 @@ module.exports = {
|
|
|
1911
1981
|
UCODE_BANNER_LINES,
|
|
1912
1982
|
UCODE_VERSION,
|
|
1913
1983
|
StreamBuffer,
|
|
1984
|
+
displayCellWidth,
|
|
1985
|
+
resolveLogContentWidth,
|
|
1986
|
+
formatHighlightedUserInput,
|
|
1914
1987
|
buildUcodeBannerLines,
|
|
1915
1988
|
buildUcodeBannerBlessedLines,
|
|
1916
1989
|
parseActiveAgentsFromBusStatus,
|
package/src/config.js
CHANGED
|
@@ -4,6 +4,17 @@ const path = require("path");
|
|
|
4
4
|
|
|
5
5
|
const UCODE_FIELDS = ["ucodeProvider", "ucodeModel", "ucodeBaseUrl", "ucodeApiKey", "ucodeAgentDir"];
|
|
6
6
|
|
|
7
|
+
const SETTINGS_MODEL_DEFAULTS = Object.freeze({
|
|
8
|
+
agent: Object.freeze({
|
|
9
|
+
codex: "gpt-5.5",
|
|
10
|
+
claude: "opus-4.7",
|
|
11
|
+
}),
|
|
12
|
+
router: Object.freeze({
|
|
13
|
+
codex: "gpt-5.3-codex-spark",
|
|
14
|
+
claude: "sonnet-4.7",
|
|
15
|
+
}),
|
|
16
|
+
});
|
|
17
|
+
|
|
7
18
|
const DEFAULT_CONFIG = {
|
|
8
19
|
launchMode: "auto",
|
|
9
20
|
agentProvider: "codex-cli",
|
|
@@ -15,6 +26,8 @@ const DEFAULT_CONFIG = {
|
|
|
15
26
|
claudeOauthTokenPath: "",
|
|
16
27
|
claudeOauthRefreshWindowSec: 300,
|
|
17
28
|
agentModel: "",
|
|
29
|
+
routerProvider: "",
|
|
30
|
+
routerModel: "",
|
|
18
31
|
autoResume: false,
|
|
19
32
|
};
|
|
20
33
|
|
|
@@ -41,6 +54,33 @@ function normalizeAgentProvider(value) {
|
|
|
41
54
|
return "codex-cli";
|
|
42
55
|
}
|
|
43
56
|
|
|
57
|
+
function providerKey(value = "") {
|
|
58
|
+
const text = String(value || "").trim().toLowerCase();
|
|
59
|
+
if (text === "claude" || text === "claude-cli" || text === "claude-code" || text === "anthropic") return "claude";
|
|
60
|
+
return "codex";
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function sameModelProvider(left = "", right = "") {
|
|
64
|
+
return providerKey(left) === providerKey(right);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
function defaultAgentModelForProvider(value = "") {
|
|
68
|
+
return SETTINGS_MODEL_DEFAULTS.agent[providerKey(value)] || SETTINGS_MODEL_DEFAULTS.agent.codex;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function defaultRouterProviderForAgentProvider(value = "") {
|
|
72
|
+
return providerKey(value) === "claude" ? "claude" : "codex";
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function defaultRouterModelForProvider(value = "") {
|
|
76
|
+
return SETTINGS_MODEL_DEFAULTS.router[providerKey(value)] || SETTINGS_MODEL_DEFAULTS.router.codex;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function normalizeModel(value, fallback = "") {
|
|
80
|
+
const text = typeof value === "string" ? value.trim() : "";
|
|
81
|
+
return text || fallback;
|
|
82
|
+
}
|
|
83
|
+
|
|
44
84
|
function normalizeControllerMode(value) {
|
|
45
85
|
const raw = String(value || "").trim().toLowerCase();
|
|
46
86
|
if (raw === "shadow") return "shadow";
|
|
@@ -100,11 +140,19 @@ function loadJsonSafe(filePath) {
|
|
|
100
140
|
function loadConfig(projectRoot) {
|
|
101
141
|
try {
|
|
102
142
|
const raw = loadJsonSafe(configPath(projectRoot));
|
|
143
|
+
const agentProvider = normalizeAgentProvider(raw.agentProvider);
|
|
144
|
+
const routerProvider = normalizeModel(
|
|
145
|
+
raw.routerProvider,
|
|
146
|
+
defaultRouterProviderForAgentProvider(agentProvider)
|
|
147
|
+
);
|
|
103
148
|
return {
|
|
104
149
|
...DEFAULT_CONFIG,
|
|
105
150
|
...raw,
|
|
106
151
|
launchMode: normalizeLaunchMode(raw.launchMode),
|
|
107
|
-
agentProvider
|
|
152
|
+
agentProvider,
|
|
153
|
+
agentModel: normalizeModel(raw.agentModel, defaultAgentModelForProvider(agentProvider)),
|
|
154
|
+
routerProvider,
|
|
155
|
+
routerModel: normalizeModel(raw.routerModel, defaultRouterModelForProvider(routerProvider)),
|
|
108
156
|
controllerMode: Object.prototype.hasOwnProperty.call(raw, "controllerMode")
|
|
109
157
|
? normalizeControllerMode(raw.controllerMode)
|
|
110
158
|
: DEFAULT_CONFIG.controllerMode,
|
|
@@ -121,7 +169,15 @@ function loadConfig(projectRoot) {
|
|
|
121
169
|
...loadGlobalUcodeConfig(),
|
|
122
170
|
};
|
|
123
171
|
} catch {
|
|
124
|
-
|
|
172
|
+
const agentProvider = DEFAULT_CONFIG.agentProvider;
|
|
173
|
+
const routerProvider = defaultRouterProviderForAgentProvider(agentProvider);
|
|
174
|
+
return {
|
|
175
|
+
...DEFAULT_CONFIG,
|
|
176
|
+
agentModel: defaultAgentModelForProvider(agentProvider),
|
|
177
|
+
routerProvider,
|
|
178
|
+
routerModel: defaultRouterModelForProvider(routerProvider),
|
|
179
|
+
...DEFAULT_UCODE_CONFIG,
|
|
180
|
+
};
|
|
125
181
|
}
|
|
126
182
|
}
|
|
127
183
|
|
|
@@ -152,6 +208,9 @@ function saveConfig(projectRoot, config) {
|
|
|
152
208
|
}
|
|
153
209
|
merged.launchMode = normalizeLaunchMode(merged.launchMode);
|
|
154
210
|
merged.agentProvider = normalizeAgentProvider(merged.agentProvider);
|
|
211
|
+
merged.agentModel = typeof merged.agentModel === "string" ? merged.agentModel.trim() : "";
|
|
212
|
+
merged.routerProvider = typeof merged.routerProvider === "string" ? merged.routerProvider.trim() : "";
|
|
213
|
+
merged.routerModel = typeof merged.routerModel === "string" ? merged.routerModel.trim() : "";
|
|
155
214
|
merged.controllerMode = normalizeControllerMode(merged.controllerMode);
|
|
156
215
|
merged.codexInternalThreadMode = normalizeCodexInternalThreadMode(merged.codexInternalThreadMode);
|
|
157
216
|
merged.codexAuthPath = normalizeCodexAuthPath(merged.codexAuthPath);
|
|
@@ -190,12 +249,17 @@ function saveGlobalUcodeConfig(updates = {}) {
|
|
|
190
249
|
}
|
|
191
250
|
|
|
192
251
|
module.exports = {
|
|
252
|
+
SETTINGS_MODEL_DEFAULTS,
|
|
193
253
|
loadConfig,
|
|
194
254
|
saveConfig,
|
|
195
255
|
loadGlobalUcodeConfig,
|
|
196
256
|
saveGlobalUcodeConfig,
|
|
197
257
|
normalizeLaunchMode,
|
|
198
258
|
normalizeAgentProvider,
|
|
259
|
+
sameModelProvider,
|
|
260
|
+
defaultAgentModelForProvider,
|
|
261
|
+
defaultRouterProviderForAgentProvider,
|
|
262
|
+
defaultRouterModelForProvider,
|
|
199
263
|
normalizeControllerMode,
|
|
200
264
|
normalizeCodexInternalThreadMode,
|
|
201
265
|
normalizeCodexAuthPath,
|
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
const {
|
|
3
|
+
const {
|
|
4
|
+
loadConfig,
|
|
5
|
+
defaultRouterProviderForAgentProvider,
|
|
6
|
+
defaultRouterModelForProvider,
|
|
7
|
+
sameModelProvider,
|
|
8
|
+
} = require("../config");
|
|
4
9
|
|
|
5
10
|
const DEFAULT_EXECUTION_PATH = "main";
|
|
6
11
|
const DEFAULT_CONFIDENCE_THRESHOLD = 0.6;
|
|
@@ -122,18 +127,22 @@ function resolveGateRouterConfig({
|
|
|
122
127
|
loadConfigImpl = loadConfig,
|
|
123
128
|
} = {}) {
|
|
124
129
|
const config = loadConfigImpl(projectRoot || process.cwd());
|
|
130
|
+
const requestProvider = requestMeta.router_provider || env.UFOO_AGENT_ROUTER_PROVIDER;
|
|
131
|
+
const provider = String(
|
|
132
|
+
requestProvider
|
|
133
|
+
|| config.routerProvider
|
|
134
|
+
|| defaultRouterProviderForAgentProvider(config.agentProvider)
|
|
135
|
+
).trim();
|
|
136
|
+
const configuredRouterModel = !requestProvider || sameModelProvider(config.routerProvider, provider)
|
|
137
|
+
? config.routerModel
|
|
138
|
+
: "";
|
|
125
139
|
return {
|
|
126
|
-
provider
|
|
127
|
-
requestMeta.router_provider
|
|
128
|
-
|| env.UFOO_AGENT_ROUTER_PROVIDER
|
|
129
|
-
|| config.routerProvider
|
|
130
|
-
|| "ucode"
|
|
131
|
-
).trim(),
|
|
140
|
+
provider,
|
|
132
141
|
model: String(
|
|
133
142
|
requestMeta.router_model
|
|
134
143
|
|| env.UFOO_AGENT_ROUTER_MODEL
|
|
135
|
-
||
|
|
136
|
-
||
|
|
144
|
+
|| configuredRouterModel
|
|
145
|
+
|| defaultRouterModelForProvider(provider)
|
|
137
146
|
).trim(),
|
|
138
147
|
timeoutMs: toPositiveNumber(
|
|
139
148
|
requestMeta.router_timeout_ms
|
package/src/daemon/run.js
CHANGED
|
@@ -1,14 +1,17 @@
|
|
|
1
1
|
const path = require("path");
|
|
2
2
|
const { startDaemon, stopDaemon, isRunning } = require("./index");
|
|
3
|
-
const { loadConfig } = require("../config");
|
|
3
|
+
const { loadConfig, defaultAgentModelForProvider } = require("../config");
|
|
4
4
|
|
|
5
5
|
function runDaemonCli(argv) {
|
|
6
6
|
const cmd = argv[1] || "start";
|
|
7
7
|
const projectRoot = process.cwd();
|
|
8
8
|
const config = loadConfig(projectRoot);
|
|
9
|
-
const
|
|
9
|
+
const envProvider = process.env.UFOO_AGENT_PROVIDER;
|
|
10
|
+
const provider = envProvider || config.agentProvider || "codex-cli";
|
|
10
11
|
const model =
|
|
11
|
-
process.env.UFOO_AGENT_MODEL
|
|
12
|
+
process.env.UFOO_AGENT_MODEL
|
|
13
|
+
|| (envProvider && envProvider !== config.agentProvider ? "" : config.agentModel)
|
|
14
|
+
|| defaultAgentModelForProvider(provider);
|
|
12
15
|
const resumeMode = process.env.UFOO_FORCE_RESUME === "1" ? "force" : "auto";
|
|
13
16
|
const launchMode = config.launchMode || "terminal";
|
|
14
17
|
|