u-foo 1.9.8 → 2.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +2 -4
- package/src/agent/claudeEventTranslator.js +267 -0
- package/src/agent/claudeOauthTokenReader.js +52 -0
- package/src/agent/claudeThreadProvider.js +343 -0
- package/src/agent/cliRunner.js +4 -16
- package/src/agent/codexEventTranslator.js +78 -0
- package/src/agent/codexThreadProvider.js +181 -0
- package/src/agent/controllerToolExecutor.js +233 -0
- package/src/agent/credentials/claude.js +324 -0
- package/src/agent/credentials/codex.js +203 -0
- package/src/agent/credentials/index.js +106 -0
- package/src/agent/defaultBootstrap.js +128 -5
- package/src/agent/internalRunner.js +333 -2
- package/src/agent/loopObservability.js +190 -0
- package/src/agent/loopRuntime.js +457 -0
- package/src/agent/ufooAgent.js +178 -120
- package/src/agent/upstreamTransport.js +464 -0
- package/src/bus/utils.js +3 -2
- package/src/chat/dashboardView.js +51 -1
- package/src/chat/index.js +3 -1
- package/src/config.js +53 -17
- package/src/controller/flags.js +160 -0
- package/src/controller/gateRouter.js +201 -0
- package/src/controller/routerFastPath.js +22 -0
- package/src/controller/shadowGuard.js +280 -0
- package/src/daemon/index.js +2 -3
- package/src/daemon/promptLoop.js +33 -224
- package/src/daemon/promptRequest.js +360 -5
- package/src/daemon/status.js +2 -0
- package/src/history/inputTimeline.js +9 -4
- package/src/memory/index.js +24 -0
- package/src/providerapi/redactor.js +87 -0
- package/src/providerapi/shadowDiff.js +174 -0
- package/src/report/store.js +4 -3
- package/src/tools/handlers/ackBus.js +26 -0
- package/src/tools/handlers/common.js +64 -0
- package/src/tools/handlers/dispatchMessage.js +81 -0
- package/src/tools/handlers/listAgents.js +14 -0
- package/src/tools/handlers/readBusSummary.js +34 -0
- package/src/tools/handlers/readOpenDecisions.js +26 -0
- package/src/tools/handlers/readProjectRegistry.js +20 -0
- package/src/tools/handlers/readPromptHistory.js +123 -0
- package/src/tools/handlers/tier2.js +134 -0
- package/src/tools/index.js +55 -0
- package/src/tools/registry.js +69 -0
- package/src/tools/schemaFixtures.js +415 -0
- package/src/tools/tier0/listAgents.js +14 -0
- package/src/tools/tier0/readBusSummary.js +14 -0
- package/src/tools/tier0/readOpenDecisions.js +14 -0
- package/src/tools/tier0/readProjectRegistry.js +14 -0
- package/src/tools/tier0/readPromptHistory.js +14 -0
- package/src/tools/tier1/ackBus.js +14 -0
- package/src/tools/tier1/dispatchMessage.js +14 -0
- package/src/tools/tier1/routeAgent.js +14 -0
- package/src/tools/tier2/closeAgent.js +14 -0
- package/src/tools/tier2/launchAgent.js +14 -0
- package/src/tools/tier2/manageCron.js +14 -0
- package/src/tools/tier2/renameAgent.js +14 -0
- package/src/tools/types.js +75 -0
- package/src/tools/unimplemented.js +13 -0
- package/src/ufoo/paths.js +4 -0
- package/bin/ufoo-assistant-agent.js +0 -5
- package/bin/ufoo-engine.js +0 -25
- package/src/assistant/agent.js +0 -261
- package/src/assistant/bridge.js +0 -178
- package/src/assistant/constants.js +0 -15
- package/src/assistant/engine.js +0 -252
- package/src/assistant/stdio.js +0 -58
- package/src/assistant/ufooEngineCli.js +0 -312
package/src/config.js
CHANGED
|
@@ -7,10 +7,13 @@ const UCODE_FIELDS = ["ucodeProvider", "ucodeModel", "ucodeBaseUrl", "ucodeApiKe
|
|
|
7
7
|
const DEFAULT_CONFIG = {
|
|
8
8
|
launchMode: "auto",
|
|
9
9
|
agentProvider: "codex-cli",
|
|
10
|
+
controllerMode: "legacy",
|
|
11
|
+
codexInternalThreadMode: "legacy",
|
|
12
|
+
codexAuthPath: "",
|
|
13
|
+
claudeOauthProfile: "",
|
|
14
|
+
claudeOauthTokenPath: "",
|
|
15
|
+
claudeOauthRefreshWindowSec: 300,
|
|
10
16
|
agentModel: "",
|
|
11
|
-
assistantEngine: "auto",
|
|
12
|
-
assistantModel: "",
|
|
13
|
-
assistantUfooCmd: "",
|
|
14
17
|
autoResume: false,
|
|
15
18
|
};
|
|
16
19
|
|
|
@@ -33,17 +36,39 @@ function normalizeLaunchMode(value) {
|
|
|
33
36
|
|
|
34
37
|
function normalizeAgentProvider(value) {
|
|
35
38
|
if (value === "claude-cli") return "claude-cli";
|
|
36
|
-
if (value === "ucode" || value === "ufoo" || value === "ufoo-code") return "ucode";
|
|
37
39
|
return "codex-cli";
|
|
38
40
|
}
|
|
39
41
|
|
|
40
|
-
function
|
|
42
|
+
function normalizeControllerMode(value) {
|
|
41
43
|
const raw = String(value || "").trim().toLowerCase();
|
|
42
|
-
if (
|
|
43
|
-
if (raw === "
|
|
44
|
-
if (raw === "
|
|
45
|
-
|
|
46
|
-
|
|
44
|
+
if (raw === "shadow") return "shadow";
|
|
45
|
+
if (raw === "router-api") return "router-api";
|
|
46
|
+
if (raw === "loop") return "loop";
|
|
47
|
+
return "legacy";
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function normalizeCodexInternalThreadMode(value) {
|
|
51
|
+
const raw = String(value || "").trim().toLowerCase();
|
|
52
|
+
if (raw === "sdk") return "sdk";
|
|
53
|
+
return "legacy";
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
function normalizeCodexAuthPath(value) {
|
|
57
|
+
return typeof value === "string" ? value.trim() : "";
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function normalizeClaudeOauthProfile(value) {
|
|
61
|
+
return typeof value === "string" ? value.trim() : "";
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function normalizeClaudeOauthTokenPath(value) {
|
|
65
|
+
return typeof value === "string" ? value.trim() : "";
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function normalizeClaudeOauthRefreshWindowSec(value) {
|
|
69
|
+
const num = Number(value);
|
|
70
|
+
if (!Number.isFinite(num) || num < 0) return 300;
|
|
71
|
+
return Math.floor(num);
|
|
47
72
|
}
|
|
48
73
|
|
|
49
74
|
function globalConfigPath() {
|
|
@@ -70,9 +95,12 @@ function loadConfig(projectRoot) {
|
|
|
70
95
|
...raw,
|
|
71
96
|
launchMode: normalizeLaunchMode(raw.launchMode),
|
|
72
97
|
agentProvider: normalizeAgentProvider(raw.agentProvider),
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
98
|
+
controllerMode: normalizeControllerMode(raw.controllerMode),
|
|
99
|
+
codexInternalThreadMode: normalizeCodexInternalThreadMode(raw.codexInternalThreadMode),
|
|
100
|
+
codexAuthPath: normalizeCodexAuthPath(raw.codexAuthPath),
|
|
101
|
+
claudeOauthProfile: normalizeClaudeOauthProfile(raw.claudeOauthProfile),
|
|
102
|
+
claudeOauthTokenPath: normalizeClaudeOauthTokenPath(raw.claudeOauthTokenPath),
|
|
103
|
+
claudeOauthRefreshWindowSec: normalizeClaudeOauthRefreshWindowSec(raw.claudeOauthRefreshWindowSec),
|
|
76
104
|
autoResume: raw.autoResume !== false,
|
|
77
105
|
// Merge ucode fields from global config so callers still see them
|
|
78
106
|
...loadGlobalUcodeConfig(),
|
|
@@ -109,9 +137,12 @@ function saveConfig(projectRoot, config) {
|
|
|
109
137
|
}
|
|
110
138
|
merged.launchMode = normalizeLaunchMode(merged.launchMode);
|
|
111
139
|
merged.agentProvider = normalizeAgentProvider(merged.agentProvider);
|
|
112
|
-
merged.
|
|
113
|
-
merged.
|
|
114
|
-
merged.
|
|
140
|
+
merged.controllerMode = normalizeControllerMode(merged.controllerMode);
|
|
141
|
+
merged.codexInternalThreadMode = normalizeCodexInternalThreadMode(merged.codexInternalThreadMode);
|
|
142
|
+
merged.codexAuthPath = normalizeCodexAuthPath(merged.codexAuthPath);
|
|
143
|
+
merged.claudeOauthProfile = normalizeClaudeOauthProfile(merged.claudeOauthProfile);
|
|
144
|
+
merged.claudeOauthTokenPath = normalizeClaudeOauthTokenPath(merged.claudeOauthTokenPath);
|
|
145
|
+
merged.claudeOauthRefreshWindowSec = normalizeClaudeOauthRefreshWindowSec(merged.claudeOauthRefreshWindowSec);
|
|
115
146
|
merged.autoResume = merged.autoResume !== false;
|
|
116
147
|
fs.writeFileSync(target, JSON.stringify(merged, null, 2));
|
|
117
148
|
return merged;
|
|
@@ -149,5 +180,10 @@ module.exports = {
|
|
|
149
180
|
saveGlobalUcodeConfig,
|
|
150
181
|
normalizeLaunchMode,
|
|
151
182
|
normalizeAgentProvider,
|
|
152
|
-
|
|
183
|
+
normalizeControllerMode,
|
|
184
|
+
normalizeCodexInternalThreadMode,
|
|
185
|
+
normalizeCodexAuthPath,
|
|
186
|
+
normalizeClaudeOauthProfile,
|
|
187
|
+
normalizeClaudeOauthTokenPath,
|
|
188
|
+
normalizeClaudeOauthRefreshWindowSec,
|
|
153
189
|
};
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
const fs = require("fs");
|
|
2
|
+
const path = require("path");
|
|
3
|
+
const { loadConfig, normalizeControllerMode } = require("../config");
|
|
4
|
+
|
|
5
|
+
const CONTROLLER_MODES = Object.freeze({
|
|
6
|
+
LEGACY: "legacy",
|
|
7
|
+
SHADOW: "shadow",
|
|
8
|
+
ROUTER_API: "router-api",
|
|
9
|
+
LOOP: "loop",
|
|
10
|
+
});
|
|
11
|
+
|
|
12
|
+
const CONTROLLER_MODE_HISTORY_LIMIT = 16;
|
|
13
|
+
|
|
14
|
+
const appliedControllerModes = new Map();
|
|
15
|
+
const appliedControllerModeHistory = new Map();
|
|
16
|
+
|
|
17
|
+
function readProcessControllerMode(env = process.env) {
|
|
18
|
+
return normalizeControllerMode(env.UFOO_CONTROLLER_MODE);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
function resolveControllerMode({
|
|
22
|
+
projectRoot,
|
|
23
|
+
requestedMode = "",
|
|
24
|
+
env = process.env,
|
|
25
|
+
config = null,
|
|
26
|
+
} = {}) {
|
|
27
|
+
const explicit = normalizeControllerMode(requestedMode);
|
|
28
|
+
if (explicit !== CONTROLLER_MODES.LEGACY || String(requestedMode || "").trim().toLowerCase() === CONTROLLER_MODES.LEGACY) {
|
|
29
|
+
return explicit;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const hasExplicitConfig = config && typeof config === "object"
|
|
33
|
+
? Object.prototype.hasOwnProperty.call(config, "controllerMode")
|
|
34
|
+
: Boolean(projectRoot) && fs.existsSync(path.join(projectRoot, ".ufoo", "config.json"));
|
|
35
|
+
const loadedConfig = hasExplicitConfig
|
|
36
|
+
? (config && typeof config === "object" ? config : loadConfig(projectRoot))
|
|
37
|
+
: null;
|
|
38
|
+
if (loadedConfig) {
|
|
39
|
+
const projectMode = normalizeControllerMode(loadedConfig.controllerMode);
|
|
40
|
+
return projectMode;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
return readProcessControllerMode(env);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function getControllerModeStateKey(projectRoot = "") {
|
|
47
|
+
const text = String(projectRoot || "").trim();
|
|
48
|
+
return text || "__default__";
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
function pushModeHistory(key, previousMode, normalizedMode, messageId) {
|
|
52
|
+
if (!previousMode || previousMode === normalizedMode) return;
|
|
53
|
+
const list = appliedControllerModeHistory.get(key) || [];
|
|
54
|
+
list.push({
|
|
55
|
+
from_mode: previousMode,
|
|
56
|
+
to_mode: normalizedMode,
|
|
57
|
+
applied_from_msg_id: String(messageId || "").trim(),
|
|
58
|
+
});
|
|
59
|
+
while (list.length > CONTROLLER_MODE_HISTORY_LIMIT) list.shift();
|
|
60
|
+
appliedControllerModeHistory.set(key, list);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
function applyControllerModeForMessage({
|
|
64
|
+
projectRoot,
|
|
65
|
+
nextMode = CONTROLLER_MODES.LEGACY,
|
|
66
|
+
messageId = "",
|
|
67
|
+
} = {}) {
|
|
68
|
+
const key = getControllerModeStateKey(projectRoot);
|
|
69
|
+
const normalizedMode = normalizeControllerMode(nextMode);
|
|
70
|
+
const previousMode = appliedControllerModes.get(key) || null;
|
|
71
|
+
appliedControllerModes.set(key, normalizedMode);
|
|
72
|
+
|
|
73
|
+
if (!previousMode || previousMode === normalizedMode) {
|
|
74
|
+
return {
|
|
75
|
+
mode: normalizedMode,
|
|
76
|
+
transition: null,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
pushModeHistory(key, previousMode, normalizedMode, messageId);
|
|
81
|
+
|
|
82
|
+
return {
|
|
83
|
+
mode: normalizedMode,
|
|
84
|
+
transition: {
|
|
85
|
+
from_mode: previousMode,
|
|
86
|
+
to_mode: normalizedMode,
|
|
87
|
+
applied_from_msg_id: String(messageId || "").trim(),
|
|
88
|
+
},
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
function rollbackControllerModeForMessage({
|
|
93
|
+
projectRoot,
|
|
94
|
+
messageId = "",
|
|
95
|
+
} = {}) {
|
|
96
|
+
const key = getControllerModeStateKey(projectRoot);
|
|
97
|
+
const list = appliedControllerModeHistory.get(key) || [];
|
|
98
|
+
const lastTransition = list.length > 0 ? list[list.length - 1] : null;
|
|
99
|
+
const currentMode = appliedControllerModes.get(key) || CONTROLLER_MODES.LEGACY;
|
|
100
|
+
|
|
101
|
+
if (!lastTransition) {
|
|
102
|
+
return {
|
|
103
|
+
mode: currentMode,
|
|
104
|
+
transition: null,
|
|
105
|
+
rolled_back: false,
|
|
106
|
+
};
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
list.pop();
|
|
110
|
+
appliedControllerModeHistory.set(key, list);
|
|
111
|
+
|
|
112
|
+
const nextMode = normalizeControllerMode(lastTransition.from_mode);
|
|
113
|
+
appliedControllerModes.set(key, nextMode);
|
|
114
|
+
|
|
115
|
+
if (nextMode === currentMode) {
|
|
116
|
+
return {
|
|
117
|
+
mode: nextMode,
|
|
118
|
+
transition: null,
|
|
119
|
+
rolled_back: true,
|
|
120
|
+
};
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return {
|
|
124
|
+
mode: nextMode,
|
|
125
|
+
rolled_back: true,
|
|
126
|
+
transition: {
|
|
127
|
+
from_mode: currentMode,
|
|
128
|
+
to_mode: nextMode,
|
|
129
|
+
applied_from_msg_id: String(messageId || "").trim(),
|
|
130
|
+
rolled_back: true,
|
|
131
|
+
restored_from_msg_id: String(lastTransition.applied_from_msg_id || "").trim(),
|
|
132
|
+
},
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
function getAppliedControllerMode(projectRoot) {
|
|
137
|
+
const key = getControllerModeStateKey(projectRoot);
|
|
138
|
+
return appliedControllerModes.get(key) || CONTROLLER_MODES.LEGACY;
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
function getControllerModeHistoryForTests(projectRoot) {
|
|
142
|
+
const key = getControllerModeStateKey(projectRoot);
|
|
143
|
+
return (appliedControllerModeHistory.get(key) || []).slice();
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
function resetAppliedControllerModesForTests() {
|
|
147
|
+
appliedControllerModes.clear();
|
|
148
|
+
appliedControllerModeHistory.clear();
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
module.exports = {
|
|
152
|
+
CONTROLLER_MODES,
|
|
153
|
+
applyControllerModeForMessage,
|
|
154
|
+
getAppliedControllerMode,
|
|
155
|
+
getControllerModeHistoryForTests,
|
|
156
|
+
readProcessControllerMode,
|
|
157
|
+
resetAppliedControllerModesForTests,
|
|
158
|
+
resolveControllerMode,
|
|
159
|
+
rollbackControllerModeForMessage,
|
|
160
|
+
};
|
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const { loadConfig } = require("../config");
|
|
4
|
+
|
|
5
|
+
const DEFAULT_EXECUTION_PATH = "legacy";
|
|
6
|
+
const DEFAULT_CONFIDENCE_THRESHOLD = 0.6;
|
|
7
|
+
const DEFAULT_TIMEOUT_MS = 5000;
|
|
8
|
+
|
|
9
|
+
const ROUTING_PATTERNS = [
|
|
10
|
+
/\bwho should\b/i,
|
|
11
|
+
/\bwhich agent\b/i,
|
|
12
|
+
/\broute (?:this|it|that|the request)\b/i,
|
|
13
|
+
/\bcontinue with\b/i,
|
|
14
|
+
/\bhand\s+off\b/i,
|
|
15
|
+
/\bsend (?:this|it|that)\b/i,
|
|
16
|
+
/\bassign (?:this|it|that)\b/i,
|
|
17
|
+
/\bforward (?:this|it|that)\b/i,
|
|
18
|
+
/\bshould (?:i|we) ask\b/i,
|
|
19
|
+
/\bnew (?:codex|claude|ucode)\b/i,
|
|
20
|
+
/交给谁/,
|
|
21
|
+
/继续给/,
|
|
22
|
+
/发送(?:这个|它|这条|这个任务)?给/,
|
|
23
|
+
/让.*(?:接这个任务|接手|处理这个|来处理)/,
|
|
24
|
+
/发给/,
|
|
25
|
+
/转给/,
|
|
26
|
+
/应该找谁/,
|
|
27
|
+
/需要新开.*(?:codex|claude|ucode)/i,
|
|
28
|
+
];
|
|
29
|
+
|
|
30
|
+
const NON_ROUTING_PATTERNS = [
|
|
31
|
+
/\bfix\b/i,
|
|
32
|
+
/\bimplement\b/i,
|
|
33
|
+
/\bwrite\b/i,
|
|
34
|
+
/\bedit\b/i,
|
|
35
|
+
/\brefactor\b/i,
|
|
36
|
+
/\btest\b/i,
|
|
37
|
+
/\binvestigate\b/i,
|
|
38
|
+
/\bdebug\b/i,
|
|
39
|
+
/\bbuild\b/i,
|
|
40
|
+
/\bcreate\b/i,
|
|
41
|
+
/\bsearch\b/i,
|
|
42
|
+
/\bopen\b/i,
|
|
43
|
+
/\bread\b/i,
|
|
44
|
+
/修复/,
|
|
45
|
+
/修正/,
|
|
46
|
+
/实现/,
|
|
47
|
+
/重构/,
|
|
48
|
+
/测试/,
|
|
49
|
+
/排查/,
|
|
50
|
+
/调试/,
|
|
51
|
+
/构建/,
|
|
52
|
+
/搜索/,
|
|
53
|
+
/查看/,
|
|
54
|
+
];
|
|
55
|
+
|
|
56
|
+
function normalizeExecutionPath(value = "") {
|
|
57
|
+
const text = String(value || "").trim().toLowerCase();
|
|
58
|
+
if (text === "router-api") return "router-api";
|
|
59
|
+
if (text === "shadow") return "shadow";
|
|
60
|
+
if (text === "loop") return "loop";
|
|
61
|
+
return DEFAULT_EXECUTION_PATH;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function toPositiveNumber(value, fallback) {
|
|
65
|
+
const parsed = Number(value);
|
|
66
|
+
if (!Number.isFinite(parsed) || parsed <= 0) return fallback;
|
|
67
|
+
return parsed;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function resolveExecutionPath({
|
|
71
|
+
projectRoot,
|
|
72
|
+
requestMeta = {},
|
|
73
|
+
env = process.env,
|
|
74
|
+
loadConfigImpl = loadConfig,
|
|
75
|
+
} = {}) {
|
|
76
|
+
const config = loadConfigImpl(projectRoot || process.cwd());
|
|
77
|
+
return normalizeExecutionPath(
|
|
78
|
+
requestMeta.agent_execution_path
|
|
79
|
+
|| env.UFOO_AGENT_EXECUTION_PATH
|
|
80
|
+
|| config.agentExecutionPath
|
|
81
|
+
|| config.controllerMode
|
|
82
|
+
|| DEFAULT_EXECUTION_PATH
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function classifyPromptIntent(prompt = "") {
|
|
87
|
+
const text = String(prompt || "").trim();
|
|
88
|
+
if (!text) return { kind: "general", reason: "empty_prompt" };
|
|
89
|
+
const hasRoutingSignal = ROUTING_PATTERNS.some((pattern) => pattern.test(text));
|
|
90
|
+
if (!hasRoutingSignal) return { kind: "general", reason: "no_routing_signal" };
|
|
91
|
+
const hasNonRoutingSignal = NON_ROUTING_PATTERNS.some((pattern) => pattern.test(text));
|
|
92
|
+
if (hasNonRoutingSignal) return { kind: "general", reason: "contains_execution_language" };
|
|
93
|
+
return { kind: "routing", reason: "routing_signal" };
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function shouldUseGateRouter({
|
|
97
|
+
projectRoot,
|
|
98
|
+
prompt,
|
|
99
|
+
requestMeta = {},
|
|
100
|
+
env = process.env,
|
|
101
|
+
loadConfigImpl = loadConfig,
|
|
102
|
+
} = {}) {
|
|
103
|
+
const executionPath = resolveExecutionPath({
|
|
104
|
+
projectRoot,
|
|
105
|
+
requestMeta,
|
|
106
|
+
env,
|
|
107
|
+
loadConfigImpl,
|
|
108
|
+
});
|
|
109
|
+
const intent = classifyPromptIntent(prompt);
|
|
110
|
+
return {
|
|
111
|
+
executionPath,
|
|
112
|
+
intent,
|
|
113
|
+
enabled: executionPath === "router-api" || executionPath === "loop",
|
|
114
|
+
};
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
function resolveGateRouterConfig({
|
|
118
|
+
projectRoot,
|
|
119
|
+
requestMeta = {},
|
|
120
|
+
env = process.env,
|
|
121
|
+
loadConfigImpl = loadConfig,
|
|
122
|
+
} = {}) {
|
|
123
|
+
const config = loadConfigImpl(projectRoot || process.cwd());
|
|
124
|
+
return {
|
|
125
|
+
provider: String(
|
|
126
|
+
requestMeta.router_provider
|
|
127
|
+
|| env.UFOO_AGENT_ROUTER_PROVIDER
|
|
128
|
+
|| config.routerProvider
|
|
129
|
+
|| "ucode"
|
|
130
|
+
).trim(),
|
|
131
|
+
model: String(
|
|
132
|
+
requestMeta.router_model
|
|
133
|
+
|| env.UFOO_AGENT_ROUTER_MODEL
|
|
134
|
+
|| config.routerModel
|
|
135
|
+
|| ""
|
|
136
|
+
).trim(),
|
|
137
|
+
timeoutMs: toPositiveNumber(
|
|
138
|
+
requestMeta.router_timeout_ms
|
|
139
|
+
|| env.UFOO_AGENT_ROUTER_TIMEOUT_MS
|
|
140
|
+
|| config.routerTimeoutMs,
|
|
141
|
+
DEFAULT_TIMEOUT_MS
|
|
142
|
+
),
|
|
143
|
+
confidenceThreshold: Math.min(
|
|
144
|
+
1,
|
|
145
|
+
toPositiveNumber(
|
|
146
|
+
requestMeta.router_confidence_threshold
|
|
147
|
+
|| env.UFOO_AGENT_ROUTER_CONFIDENCE_THRESHOLD
|
|
148
|
+
|| config.routerConfidenceThreshold,
|
|
149
|
+
DEFAULT_CONFIDENCE_THRESHOLD
|
|
150
|
+
)
|
|
151
|
+
),
|
|
152
|
+
};
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
function normalizeInjectionMode(value = "") {
|
|
156
|
+
const text = String(value || "").trim().toLowerCase();
|
|
157
|
+
return text === "queued" ? "queued" : "immediate";
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function normalizeGateRouterResult(payload = {}, fallbackMessage = "") {
|
|
161
|
+
if (!payload || typeof payload !== "object") {
|
|
162
|
+
return {
|
|
163
|
+
decision: "upgrade_to_main_router",
|
|
164
|
+
target: "unknown",
|
|
165
|
+
confidence: 0,
|
|
166
|
+
reason: "",
|
|
167
|
+
message: String(fallbackMessage || ""),
|
|
168
|
+
injection_mode: "immediate",
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
const rawConfidence = Number(payload.confidence);
|
|
173
|
+
const normalizedConfidence = Number.isFinite(rawConfidence)
|
|
174
|
+
? Math.max(0, Math.min(1, rawConfidence))
|
|
175
|
+
: 0;
|
|
176
|
+
const rawDecision = String(payload.decision || "").trim().toLowerCase();
|
|
177
|
+
const normalizedDecision = rawDecision === "direct_dispatch"
|
|
178
|
+
|| rawDecision === "upgrade_to_main_router"
|
|
179
|
+
? rawDecision
|
|
180
|
+
: (String(payload.target || "").trim() && String(payload.target || "").trim() !== "unknown"
|
|
181
|
+
? "direct_dispatch"
|
|
182
|
+
: "upgrade_to_main_router");
|
|
183
|
+
|
|
184
|
+
return {
|
|
185
|
+
decision: normalizedDecision,
|
|
186
|
+
target: String(payload.target || "unknown").trim() || "unknown",
|
|
187
|
+
confidence: normalizedConfidence,
|
|
188
|
+
reason: String(payload.reason || "").trim(),
|
|
189
|
+
message: String(payload.message || fallbackMessage || "").trim(),
|
|
190
|
+
injection_mode: normalizeInjectionMode(payload.injection_mode),
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
module.exports = {
|
|
195
|
+
classifyPromptIntent,
|
|
196
|
+
normalizeExecutionPath,
|
|
197
|
+
normalizeGateRouterResult,
|
|
198
|
+
resolveExecutionPath,
|
|
199
|
+
resolveGateRouterConfig,
|
|
200
|
+
shouldUseGateRouter,
|
|
201
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
const {
|
|
4
|
+
classifyPromptIntent,
|
|
5
|
+
normalizeExecutionPath,
|
|
6
|
+
normalizeGateRouterResult,
|
|
7
|
+
resolveExecutionPath,
|
|
8
|
+
resolveGateRouterConfig,
|
|
9
|
+
shouldUseGateRouter,
|
|
10
|
+
} = require("./gateRouter");
|
|
11
|
+
|
|
12
|
+
module.exports = {
|
|
13
|
+
classifyPromptIntent,
|
|
14
|
+
normalizeExecutionPath,
|
|
15
|
+
normalizeRouteAgentResult: normalizeGateRouterResult,
|
|
16
|
+
resolveExecutionPath,
|
|
17
|
+
resolveRouterFastPathConfig: resolveGateRouterConfig,
|
|
18
|
+
shouldUseRouterFastPath: shouldUseGateRouter,
|
|
19
|
+
normalizeGateRouterResult,
|
|
20
|
+
resolveGateRouterConfig,
|
|
21
|
+
shouldUseGateRouter,
|
|
22
|
+
};
|