u-foo 2.3.21 → 2.3.22

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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "u-foo",
3
- "version": "2.3.21",
3
+ "version": "2.3.22",
4
4
  "description": "Multi-Agent Workspace Protocol. Just add u. claude → uclaude, codex → ucodex.",
5
5
  "license": "SEE LICENSE IN LICENSE",
6
6
  "homepage": "https://ufoo.dev",
@@ -1,7 +1,12 @@
1
1
  "use strict";
2
2
 
3
3
  const { randomUUID } = require("crypto");
4
- const { loadConfig } = require("../config");
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(model || config.routerModel || config.agentModel || "").trim();
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(model || config.routerModel || config.agentModel || "").trim();
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 {
@@ -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
- const key = agentProviderKey(value);
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) {
@@ -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.4-mini)", order: 8 },
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
- || config.ucodeModel
116
- || config.agentModel
117
- || ""
118
+ || configuredModel
119
+ || defaultAgentModelForProvider(resolvedProvider)
118
120
  ).trim();
119
121
  return {
120
122
  provider: resolvedProvider,
@@ -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
- || config.ucodeModel
227
- || config.agentModel
228
- || ""
229
+ || configuredModel
230
+ || defaultAgentModelForProvider(selectedProvider)
229
231
  ).trim();
230
232
 
231
233
  const defaultBaseUrl = selectedProvider === "anthropic"
package/src/code/tui.js CHANGED
@@ -627,8 +627,8 @@ function runUcodeTui({
627
627
  blessed,
628
628
  currentInputHeight: 4,
629
629
  version: UCODE_VERSION,
630
- logBorder: true,
631
- logScrollbar: true,
630
+ logBorder: false,
631
+ logScrollbar: false,
632
632
  });
633
633
 
634
634
  if (completionPanel && typeof completionPanel.hide === "function") {
@@ -1031,7 +1031,7 @@ function runUcodeTui({
1031
1031
  if (!plain) return;
1032
1032
  const content = ` → ${escapeBlessed(plain)} `;
1033
1033
  const visibleLen = plain.length + 4; // " → " + text + " "
1034
- const boxWidth = (logBox.width || 80) - 2; // subtract border/padding
1034
+ const boxWidth = logBox.width || 80;
1035
1035
  const pad = boxWidth > visibleLen ? " ".repeat(boxWidth - visibleLen) : "";
1036
1036
  logBox.log(`{cyan-bg}{white-fg}${content}${pad}{/white-fg}{/cyan-bg}`);
1037
1037
  logBox.log(""); // Add line break after user input
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: normalizeAgentProvider(raw.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
- return { ...DEFAULT_CONFIG, ...DEFAULT_UCODE_CONFIG };
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 { loadConfig } = require("../config");
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: String(
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
- || config.routerModel
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 provider = process.env.UFOO_AGENT_PROVIDER || config.agentProvider || "codex-cli";
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 || config.agentModel || (provider === "claude-cli" ? "opus" : "");
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