@triflux/remote 10.86.0 → 10.87.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.
|
@@ -24,7 +24,13 @@ import {
|
|
|
24
24
|
import { dirname, join } from "node:path";
|
|
25
25
|
|
|
26
26
|
import { normalizeCodexProfileName } from "../../scripts/lib/codex-profile-config.mjs";
|
|
27
|
-
import {
|
|
27
|
+
import {
|
|
28
|
+
EFFORT_ORDER,
|
|
29
|
+
modelEffortFromProfile,
|
|
30
|
+
profileFromModelEffort,
|
|
31
|
+
resolveCodexModelEffort,
|
|
32
|
+
} from "@triflux/core/scripts/lib/model-effort.mjs";
|
|
33
|
+
import { AGY_FAMILY_PROFILES } from "../../scripts/lib/model-family-resolver.mjs";
|
|
28
34
|
|
|
29
35
|
export const STATES = Object.freeze({
|
|
30
36
|
PLANNING: "PLANNING",
|
|
@@ -50,7 +56,8 @@ const DEFAULT_CLAUDE_MODEL = "fable";
|
|
|
50
56
|
const DEFAULT_ESCALATION_CHAIN = Object.freeze([
|
|
51
57
|
Object.freeze({
|
|
52
58
|
cli: "codex",
|
|
53
|
-
|
|
59
|
+
family: "astra",
|
|
60
|
+
effort: "max",
|
|
54
61
|
}),
|
|
55
62
|
Object.freeze({ cli: "claude", model: DEFAULT_CLAUDE_MODEL }),
|
|
56
63
|
]);
|
|
@@ -155,6 +162,39 @@ export function createRetryStateMachine(options = {}) {
|
|
|
155
162
|
chain: state.cliChain,
|
|
156
163
|
});
|
|
157
164
|
}
|
|
165
|
+
const current = state.cliChain[state.cliIndex];
|
|
166
|
+
const next = state.cliChain[state.cliIndex + 1];
|
|
167
|
+
if (
|
|
168
|
+
current.cli === "codex" &&
|
|
169
|
+
next.cli === "codex" &&
|
|
170
|
+
current.family &&
|
|
171
|
+
next.family
|
|
172
|
+
) {
|
|
173
|
+
try {
|
|
174
|
+
const base = resolveCodexModelEffort(current, options);
|
|
175
|
+
const promoted = resolveCodexModelEffort(next, options);
|
|
176
|
+
if (
|
|
177
|
+
promoted.effort !== next.effort &&
|
|
178
|
+
base.model === promoted.model &&
|
|
179
|
+
base.effort === promoted.effort
|
|
180
|
+
) {
|
|
181
|
+
return transition(STATES.BUDGET_EXCEEDED, {
|
|
182
|
+
reason: "escalation-not-promoted",
|
|
183
|
+
escalated: false,
|
|
184
|
+
model: promoted.model,
|
|
185
|
+
requestedEffort: next.effort,
|
|
186
|
+
effort: promoted.effort,
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
} catch (error) {
|
|
190
|
+
if (error.code !== "unsupported-effort") throw error;
|
|
191
|
+
return transition(STATES.BUDGET_EXCEEDED, {
|
|
192
|
+
reason: "unsupported-escalation-effort",
|
|
193
|
+
escalated: false,
|
|
194
|
+
error: error.message,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
}
|
|
158
198
|
state.cliIndex += 1;
|
|
159
199
|
state.iterations = 0;
|
|
160
200
|
state.stuckCounter = 0;
|
|
@@ -306,11 +346,34 @@ function normalizeEscalationChainEntry(entry, index, source) {
|
|
|
306
346
|
}
|
|
307
347
|
const profile = typeof entry.profile === "string" ? entry.profile.trim() : "";
|
|
308
348
|
const normalizedProfile = normalizeEscalationProfile(profile);
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
349
|
+
const provider = entry.cli === "agy" ? "antigravity" : entry.cli;
|
|
350
|
+
if (provider === "codex" || provider === "antigravity") {
|
|
351
|
+
const explicit = entry.family !== undefined || entry.effort !== undefined;
|
|
352
|
+
let spec = explicit
|
|
353
|
+
? typeof entry.family === "string" && typeof entry.effort === "string"
|
|
354
|
+
? modelEffortFromProfile(provider, entry.family, entry.effort)
|
|
355
|
+
: null
|
|
356
|
+
: modelEffortFromProfile(
|
|
357
|
+
provider,
|
|
358
|
+
provider === "codex" ? normalizedProfile : profile,
|
|
359
|
+
);
|
|
360
|
+
if (explicit && !spec)
|
|
361
|
+
throw new Error(`${source}: chain[${index}] has invalid family/effort`);
|
|
362
|
+
if (spec) {
|
|
363
|
+
if (provider === "codex" && spec.effort === "ultra")
|
|
364
|
+
spec = { family: "astra", effort: "max" };
|
|
365
|
+
const legacy = profileFromModelEffort(provider, spec);
|
|
366
|
+
const normalized = { cli: entry.cli, ...spec };
|
|
367
|
+
if (legacy) normalized.profile = legacy;
|
|
368
|
+
if (provider === "antigravity" && legacy) {
|
|
369
|
+
normalized.model = entry.model || AGY_FAMILY_PROFILES[legacy]?.model;
|
|
370
|
+
if (typeof normalized.model !== "string" || !normalized.model.trim())
|
|
371
|
+
throw new Error(
|
|
372
|
+
`${source}: chain[${index}].model must be a non-empty string`,
|
|
373
|
+
);
|
|
374
|
+
}
|
|
375
|
+
return normalized;
|
|
376
|
+
}
|
|
314
377
|
}
|
|
315
378
|
if (typeof entry.model !== "string" || entry.model.trim() === "") {
|
|
316
379
|
throw new Error(
|
|
@@ -319,6 +382,11 @@ function normalizeEscalationChainEntry(entry, index, source) {
|
|
|
319
382
|
}
|
|
320
383
|
const normalized = { cli: entry.cli, model: entry.model };
|
|
321
384
|
if (profile) normalized.profile = profile;
|
|
385
|
+
if (entry.effort !== undefined) {
|
|
386
|
+
if (!EFFORT_ORDER.includes(entry.effort))
|
|
387
|
+
throw new Error(`${source}: chain[${index}] has invalid effort`);
|
|
388
|
+
normalized.effort = entry.effort;
|
|
389
|
+
}
|
|
322
390
|
return normalized;
|
|
323
391
|
}
|
|
324
392
|
|
package/package.json
CHANGED
|
@@ -9,130 +9,134 @@ import {
|
|
|
9
9
|
resolveCodexProfileConfigValues,
|
|
10
10
|
} from "./codex-profile-config.mjs";
|
|
11
11
|
import { resolveGeminiProfileForPurpose } from "./gemini-profiles.mjs";
|
|
12
|
+
import {
|
|
13
|
+
modelEffortFromProfile,
|
|
14
|
+
profileFromModelEffort,
|
|
15
|
+
} from "@triflux/core/scripts/lib/model-effort.mjs";
|
|
12
16
|
|
|
13
17
|
const policy = {
|
|
14
18
|
executor: {
|
|
15
|
-
|
|
19
|
+
codex: { family: "sol", effort: "high" },
|
|
16
20
|
timeoutSec: 1080,
|
|
17
21
|
mcpHint: "implement",
|
|
18
22
|
subcommand: "exec",
|
|
19
23
|
},
|
|
20
24
|
codex: {
|
|
21
|
-
|
|
25
|
+
codex: { family: "sol", effort: "high" },
|
|
22
26
|
timeoutSec: 1080,
|
|
23
27
|
mcpHint: "implement",
|
|
24
28
|
subcommand: "exec",
|
|
25
29
|
},
|
|
26
30
|
"build-fixer": {
|
|
27
|
-
|
|
31
|
+
codex: { family: "luna", effort: "high" },
|
|
28
32
|
timeoutSec: 540,
|
|
29
33
|
mcpHint: "implement",
|
|
30
34
|
subcommand: "exec",
|
|
31
35
|
},
|
|
32
36
|
cleanup: {
|
|
33
|
-
|
|
37
|
+
codex: { family: "sol", effort: "medium" },
|
|
34
38
|
timeoutSec: 540,
|
|
35
39
|
mcpHint: "implement",
|
|
36
40
|
subcommand: "exec",
|
|
37
41
|
},
|
|
38
42
|
deslop: {
|
|
39
|
-
|
|
43
|
+
codex: { family: "sol", effort: "medium" },
|
|
40
44
|
timeoutSec: 540,
|
|
41
45
|
mcpHint: "implement",
|
|
42
46
|
subcommand: "exec",
|
|
43
47
|
},
|
|
44
48
|
debugger: {
|
|
45
|
-
|
|
49
|
+
codex: { family: "astra", effort: "xhigh" },
|
|
46
50
|
timeoutSec: 900,
|
|
47
51
|
mcpHint: "implement",
|
|
48
52
|
subcommand: "exec",
|
|
49
53
|
},
|
|
50
54
|
"deep-executor": {
|
|
51
|
-
|
|
55
|
+
codex: { family: "astra", effort: "xhigh" },
|
|
52
56
|
timeoutSec: 3600,
|
|
53
57
|
mcpHint: "implement",
|
|
54
58
|
subcommand: "exec",
|
|
55
59
|
},
|
|
56
60
|
architect: {
|
|
57
|
-
|
|
61
|
+
codex: { family: "astra", effort: "xhigh" },
|
|
58
62
|
timeoutSec: 3600,
|
|
59
63
|
mcpHint: "analyze",
|
|
60
64
|
subcommand: "exec",
|
|
61
65
|
},
|
|
62
66
|
critic: {
|
|
63
|
-
|
|
67
|
+
codex: { family: "astra", effort: "xhigh" },
|
|
64
68
|
timeoutSec: 3600,
|
|
65
69
|
mcpHint: "analyze",
|
|
66
70
|
subcommand: "exec",
|
|
67
71
|
},
|
|
68
72
|
planner: {
|
|
69
|
-
|
|
73
|
+
codex: { family: "astra", effort: "xhigh" },
|
|
70
74
|
timeoutSec: 3600,
|
|
71
75
|
mcpHint: "analyze",
|
|
72
76
|
subcommand: "exec",
|
|
73
77
|
},
|
|
74
78
|
analyst: {
|
|
75
|
-
|
|
79
|
+
codex: { family: "astra", effort: "xhigh" },
|
|
76
80
|
timeoutSec: 3600,
|
|
77
81
|
mcpHint: "analyze",
|
|
78
82
|
subcommand: "exec",
|
|
79
83
|
},
|
|
80
84
|
"code-reviewer": {
|
|
81
|
-
|
|
85
|
+
codex: { family: "sol", effort: "high" },
|
|
82
86
|
timeoutSec: 1800,
|
|
83
87
|
mcpHint: "review",
|
|
84
88
|
subcommand: "review",
|
|
85
89
|
},
|
|
86
90
|
"quality-reviewer": {
|
|
87
|
-
|
|
91
|
+
codex: { family: "sol", effort: "high" },
|
|
88
92
|
timeoutSec: 1800,
|
|
89
93
|
mcpHint: "review",
|
|
90
94
|
subcommand: "review",
|
|
91
95
|
},
|
|
92
96
|
"security-reviewer": {
|
|
93
|
-
|
|
97
|
+
codex: { family: "astra", effort: "xhigh" },
|
|
94
98
|
timeoutSec: 1800,
|
|
95
99
|
mcpHint: "review",
|
|
96
100
|
subcommand: "review",
|
|
97
101
|
},
|
|
98
102
|
scientist: {
|
|
99
|
-
|
|
103
|
+
codex: { family: "sol", effort: "high" },
|
|
100
104
|
timeoutSec: 1440,
|
|
101
105
|
mcpHint: "analyze",
|
|
102
106
|
subcommand: "exec",
|
|
103
107
|
},
|
|
104
108
|
"document-specialist": {
|
|
105
|
-
|
|
109
|
+
codex: { family: "terra", effort: "high" },
|
|
106
110
|
timeoutSec: 1440,
|
|
107
111
|
mcpHint: "analyze",
|
|
108
112
|
subcommand: "exec",
|
|
109
113
|
},
|
|
110
114
|
"scientist-deep": {
|
|
111
|
-
|
|
115
|
+
codex: { family: "astra", effort: "xhigh" },
|
|
112
116
|
timeoutSec: 3600,
|
|
113
117
|
mcpHint: "analyze",
|
|
114
118
|
subcommand: "exec",
|
|
115
119
|
},
|
|
116
120
|
verifier: {
|
|
117
|
-
|
|
121
|
+
codex: { family: "sol", effort: "high" },
|
|
118
122
|
timeoutSec: 1200,
|
|
119
123
|
mcpHint: "review",
|
|
120
124
|
subcommand: "review",
|
|
121
125
|
},
|
|
122
126
|
"test-engineer": {
|
|
123
|
-
|
|
127
|
+
codex: { family: "sol", effort: "high" },
|
|
124
128
|
timeoutSec: 1200,
|
|
125
129
|
mcpHint: "implement",
|
|
126
130
|
subcommand: "exec",
|
|
127
131
|
},
|
|
128
132
|
"qa-tester": {
|
|
129
|
-
|
|
133
|
+
codex: { family: "sol", effort: "high" },
|
|
130
134
|
timeoutSec: 1200,
|
|
131
135
|
mcpHint: "review",
|
|
132
136
|
subcommand: "review",
|
|
133
137
|
},
|
|
134
138
|
spark: {
|
|
135
|
-
|
|
139
|
+
codex: { family: "luna", effort: "low" },
|
|
136
140
|
timeoutSec: 180,
|
|
137
141
|
mcpHint: "implement",
|
|
138
142
|
subcommand: "exec",
|
|
@@ -140,13 +144,13 @@ const policy = {
|
|
|
140
144
|
// These entries are only for explicit direct-Codex overrides. agent-map.json
|
|
141
145
|
// remains the provider-selection authority for their normal execution.
|
|
142
146
|
designer: {
|
|
143
|
-
|
|
147
|
+
codex: { family: "astra", effort: "xhigh" },
|
|
144
148
|
timeoutSec: 900,
|
|
145
149
|
mcpHint: "implement",
|
|
146
150
|
subcommand: "exec",
|
|
147
151
|
},
|
|
148
152
|
writer: {
|
|
149
|
-
|
|
153
|
+
codex: { family: "terra", effort: "high" },
|
|
150
154
|
timeoutSec: 900,
|
|
151
155
|
mcpHint: "implement",
|
|
152
156
|
subcommand: "exec",
|
|
@@ -154,7 +158,11 @@ const policy = {
|
|
|
154
158
|
};
|
|
155
159
|
|
|
156
160
|
function freezePolicy(entry) {
|
|
157
|
-
return Object.freeze({
|
|
161
|
+
return Object.freeze({
|
|
162
|
+
...entry,
|
|
163
|
+
codex: Object.freeze({ ...entry.codex }),
|
|
164
|
+
profile: profileFromModelEffort("codex", entry.codex),
|
|
165
|
+
});
|
|
158
166
|
}
|
|
159
167
|
|
|
160
168
|
const CODEX_AGENT_POLICY = Object.freeze(
|
|
@@ -264,16 +272,16 @@ export function resolveNestedCodexAgentProfile(
|
|
|
264
272
|
: NESTED_GLOBAL_PROFILE_OVERRIDES.has(globalOverride)
|
|
265
273
|
? globalOverride
|
|
266
274
|
: "auto";
|
|
267
|
-
const fallback = resolveCodexAgentProfile(agent);
|
|
268
275
|
const candidate = resolveCodexAgentProfile(agent, {
|
|
269
276
|
profileOverride: effectiveOverride,
|
|
270
277
|
retryProfile,
|
|
271
278
|
nested: true,
|
|
272
279
|
allowCustom: true,
|
|
273
280
|
});
|
|
274
|
-
const { effort } =
|
|
275
|
-
|
|
276
|
-
|
|
281
|
+
const { effort } =
|
|
282
|
+
modelEffortFromProfile("codex", candidate) ||
|
|
283
|
+
resolveCodexProfileConfigValues(candidate, { codexHome });
|
|
284
|
+
return effort?.toLowerCase() === "ultra" ? "astra_max" : candidate;
|
|
277
285
|
}
|
|
278
286
|
|
|
279
287
|
const EXPECTED_DURATION_BY_AGENT = Object.freeze({
|
|
@@ -365,6 +373,7 @@ export function resolveAgentRoute(
|
|
|
365
373
|
);
|
|
366
374
|
}
|
|
367
375
|
}
|
|
376
|
+
const { family, effort } = modelEffortFromProfile("codex", resolvedOverride);
|
|
368
377
|
return [
|
|
369
378
|
provider,
|
|
370
379
|
policy.profile,
|
|
@@ -378,6 +387,8 @@ export function resolveAgentRoute(
|
|
|
378
387
|
NATIVE_CODEX_AGENTS.has(agent),
|
|
379
388
|
byAuthor ? reviewAuthor : "",
|
|
380
389
|
usageSwitch,
|
|
390
|
+
effort,
|
|
391
|
+
family,
|
|
381
392
|
];
|
|
382
393
|
}
|
|
383
394
|
|
|
@@ -9,6 +9,11 @@ import {
|
|
|
9
9
|
import { homedir } from "node:os";
|
|
10
10
|
import { dirname, join } from "node:path";
|
|
11
11
|
import { writeRotatedBackup } from "./backup-rotation.mjs";
|
|
12
|
+
import {
|
|
13
|
+
modelEffortFromProfile,
|
|
14
|
+
normalizeCodexProfileName,
|
|
15
|
+
resolveCodexModelEffort,
|
|
16
|
+
} from "@triflux/core/scripts/lib/model-effort.mjs";
|
|
12
17
|
import {
|
|
13
18
|
CODEX_FAMILY_PROFILES,
|
|
14
19
|
modelFamilyPaths,
|
|
@@ -16,46 +21,42 @@ import {
|
|
|
16
21
|
writeModelFile,
|
|
17
22
|
} from "./model-family-resolver.mjs";
|
|
18
23
|
|
|
19
|
-
|
|
20
|
-
ultra: "ultra",
|
|
21
|
-
max: "max",
|
|
22
|
-
xhigh: "xhigh",
|
|
23
|
-
high: "high",
|
|
24
|
-
med: "medium",
|
|
25
|
-
medium: "medium",
|
|
26
|
-
low: "low",
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
const LEGACY_CANONICAL_PROFILE_ALIASES = Object.freeze({
|
|
30
|
-
gpt56_sol_xhigh: "astra_xhigh",
|
|
31
|
-
gpt56_sol_max: "astra_max",
|
|
32
|
-
gpt56_sol_ultra: "astra_ultra",
|
|
33
|
-
gpt56_terra_high: "sol_high",
|
|
34
|
-
gpt56_terra_med: "sol_med",
|
|
35
|
-
});
|
|
24
|
+
export { normalizeCodexProfileName };
|
|
36
25
|
|
|
37
|
-
export function
|
|
38
|
-
const
|
|
39
|
-
const
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
26
|
+
export function managedCodexProfileContents(opts = {}) {
|
|
27
|
+
const { profiles, families } = resolveModelFamilies("codex", opts);
|
|
28
|
+
const contents = {};
|
|
29
|
+
for (const [name, { model, effort }] of Object.entries(profiles)) {
|
|
30
|
+
contents[name] =
|
|
31
|
+
`model = "${model}"\nmodel_reasoning_effort = "${effort}"\n`;
|
|
32
|
+
}
|
|
33
|
+
for (const [family, { model }] of Object.entries(families)) {
|
|
34
|
+
contents[family] = `model = "${model}"\n`;
|
|
35
|
+
}
|
|
36
|
+
return { profiles, contents };
|
|
45
37
|
}
|
|
46
38
|
|
|
47
39
|
export function ensureManagedCodexProfiles(opts = {}) {
|
|
48
40
|
const { codexHome } = modelFamilyPaths(opts);
|
|
49
|
-
const { profiles } =
|
|
41
|
+
const { profiles, contents } = managedCodexProfileContents(opts);
|
|
50
42
|
let changed = 0;
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
43
|
+
const families = new Set(
|
|
44
|
+
Object.values(CODEX_FAMILY_PROFILES).map(({ family }) => family),
|
|
45
|
+
);
|
|
46
|
+
for (const [name, content] of Object.entries(contents)) {
|
|
47
|
+
const path = join(codexHome, `${name}.config.toml`);
|
|
48
|
+
if (families.has(name) && existsSync(path)) {
|
|
49
|
+
const existing = readFileSync(path, "utf8");
|
|
50
|
+
if (existing !== content) {
|
|
51
|
+
const backup = writeRotatedBackup(path, existing, {
|
|
52
|
+
label: "bak-model-family",
|
|
53
|
+
suffix: stamp(),
|
|
54
|
+
mode: privateFileMode(path),
|
|
55
|
+
});
|
|
56
|
+
opts.notice?.(`Codex 가족 프로필 백업: ${backup}`);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
if (writeModelFile(path, content)) changed++;
|
|
59
60
|
}
|
|
60
61
|
return { changed, profiles };
|
|
61
62
|
}
|
|
@@ -72,45 +73,25 @@ function readProfileScalar(raw, key) {
|
|
|
72
73
|
return value || null;
|
|
73
74
|
}
|
|
74
75
|
|
|
75
|
-
|
|
76
|
-
* Resolve a Codex effort profile name (e.g. "sol_high") to the `-c key=value`
|
|
77
|
-
* config overrides that `codex exec` accepts, so the headless CLI lanes can
|
|
78
|
-
* select a profile WITHOUT `codex exec --profile <name>`. codex 0.134+ rejects
|
|
79
|
-
* `--profile X` whenever config.toml still contains an inline `[profiles.X]`
|
|
80
|
-
* table (which codex itself re-injects when it rewrites config.toml), so the
|
|
81
|
-
* `-c` form is immune and needs no config mutation / sanitize race.
|
|
82
|
-
*
|
|
83
|
-
* SSOT = the per-profile file `~/.codex/<name>.config.toml` written by
|
|
84
|
-
* `tfx setup`; falls back to deriving the effort from the `<...>_<effort>`
|
|
85
|
-
* naming convention when the file is absent. Returns the keys that resolve, in
|
|
86
|
-
* `key="value"` TOML-scalar form ready to be shell-quoted by the caller.
|
|
87
|
-
*
|
|
88
|
-
* @param {string} profileName
|
|
89
|
-
* @param {{ codexHome?: string }} [opts]
|
|
90
|
-
* @returns {string[]} e.g. ['model="gpt-6.1-sol"', 'model_reasoning_effort="high"']
|
|
91
|
-
*/
|
|
76
|
+
// 관리 이름의 effort는 변환 표가 정한다. custom 파일은 ultra 제한 판정에 사용한다.
|
|
92
77
|
export function resolveCodexProfileConfigValues(profileName, opts = {}) {
|
|
93
78
|
if (typeof profileName !== "string" || !profileName) {
|
|
94
79
|
return { model: null, effort: null };
|
|
95
80
|
}
|
|
96
81
|
const normalizedProfileName = normalizeCodexProfileName(profileName);
|
|
82
|
+
const managed = modelEffortFromProfile("codex", normalizedProfileName);
|
|
97
83
|
const codexHome =
|
|
98
84
|
opts.codexHome || process.env.CODEX_HOME || join(homedir(), ".codex");
|
|
99
85
|
let model = null;
|
|
100
|
-
let effort = null;
|
|
86
|
+
let effort = managed ? resolveCodexModelEffort(managed, opts).effort : null;
|
|
101
87
|
try {
|
|
102
88
|
const raw = readFileSync(
|
|
103
89
|
join(codexHome, `${normalizedProfileName}.config.toml`),
|
|
104
90
|
"utf8",
|
|
105
91
|
);
|
|
106
92
|
model = readProfileScalar(raw, "model");
|
|
107
|
-
effort = readProfileScalar(raw, "model_reasoning_effort");
|
|
108
|
-
} catch {
|
|
109
|
-
const suffix = /_(ultra|max|xhigh|high|med|medium|low)$/.exec(
|
|
110
|
-
normalizedProfileName,
|
|
111
|
-
);
|
|
112
|
-
if (suffix) effort = EFFORT_BY_SUFFIX[suffix[1]] || null;
|
|
113
|
-
}
|
|
93
|
+
if (!managed) effort = readProfileScalar(raw, "model_reasoning_effort");
|
|
94
|
+
} catch {}
|
|
114
95
|
return { model, effort };
|
|
115
96
|
}
|
|
116
97
|
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { copyFileSync, existsSync, readFileSync } from "node:fs";
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
|
+
import { normalizeGeminiProfileName } from "@triflux/core/scripts/lib/model-effort.mjs";
|
|
3
4
|
import {
|
|
4
5
|
AGY_FAMILY_PROFILES,
|
|
5
6
|
modelFamilyPaths,
|
|
@@ -17,11 +18,7 @@ const DEFAULT_GEMINI_PROFILES = {
|
|
|
17
18
|
),
|
|
18
19
|
};
|
|
19
20
|
|
|
20
|
-
export
|
|
21
|
-
const raw = String(name ?? "").trim();
|
|
22
|
-
// Flash 가족은 뺐다. 옛 Flash 이름은 effort 와 상관없이 더 빠른 Argon Low 로 보낸다.
|
|
23
|
-
return raw.replace(/^flash\d*(?:_(?:low|high))?$/, "argon_low");
|
|
24
|
-
}
|
|
21
|
+
export { normalizeGeminiProfileName };
|
|
25
22
|
|
|
26
23
|
// ── 용도별 effort (SSOT) ──
|
|
27
24
|
// Argon 가족 안에서 역할에 따라 effort 를 나눈다. 키는 tfx 에이전트/역할 이름
|
|
@@ -39,7 +39,8 @@ export const AGY_FAMILY_PROFILES = Object.freeze({
|
|
|
39
39
|
});
|
|
40
40
|
const DAY_MS = 86_400_000;
|
|
41
41
|
const CODEX_SLUG = /^gpt-(\d+(?:\.\d+)*)-(sol|astra|terra|luna)$/;
|
|
42
|
-
const AGY_SLUG =
|
|
42
|
+
const AGY_SLUG =
|
|
43
|
+
/^gemini-(\d+(?:\.\d+)*)-(argon)-(none|low|medium|high|xhigh|max|ultra)$/;
|
|
43
44
|
|
|
44
45
|
function compareVersions(a, b) {
|
|
45
46
|
const left = a.split(".").map(Number);
|
|
@@ -59,10 +60,11 @@ export function selectCodexModel(models, family, effort) {
|
|
|
59
60
|
return (
|
|
60
61
|
match?.[2] === family &&
|
|
61
62
|
item.visibility === "list" &&
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
63
|
+
(effort === undefined ||
|
|
64
|
+
(Array.isArray(item.supported_reasoning_levels) &&
|
|
65
|
+
item.supported_reasoning_levels.some(
|
|
66
|
+
(level) => (level?.effort ?? level) === effort,
|
|
67
|
+
)))
|
|
66
68
|
);
|
|
67
69
|
})
|
|
68
70
|
.sort((a, b) =>
|
|
@@ -89,7 +91,7 @@ export function selectAgyModel(models, family, effort) {
|
|
|
89
91
|
const match = AGY_SLUG.exec(item?.slug);
|
|
90
92
|
return (
|
|
91
93
|
match?.[2] === family &&
|
|
92
|
-
match?.[3] === effort &&
|
|
94
|
+
(effort === undefined || match?.[3] === effort) &&
|
|
93
95
|
typeof item.model === "string"
|
|
94
96
|
);
|
|
95
97
|
})
|
|
@@ -203,7 +205,7 @@ export function resolveModelFamilies(provider, opts = {}) {
|
|
|
203
205
|
if (provider === "codex") {
|
|
204
206
|
const cachePath = join(paths.codexHome, "models_cache.json");
|
|
205
207
|
sourceSignature = signature(cachePath);
|
|
206
|
-
if (sourceSignature !== previous.sourceSignature)
|
|
208
|
+
if (sourceSignature !== previous.sourceSignature || !previous.families)
|
|
207
209
|
catalog = readCodexModelCatalog(opts);
|
|
208
210
|
if (
|
|
209
211
|
sourceSignature.endsWith(":missing") &&
|
|
@@ -266,6 +268,8 @@ export function resolveModelFamilies(provider, opts = {}) {
|
|
|
266
268
|
}
|
|
267
269
|
const profiles = {};
|
|
268
270
|
const selectedProfiles = {};
|
|
271
|
+
const families = {};
|
|
272
|
+
const selectedFamilies = {};
|
|
269
273
|
const pins = readJson(paths.pinsPath) || {};
|
|
270
274
|
for (const [name, definition] of Object.entries(definitions)) {
|
|
271
275
|
const saved = previous.profiles?.[name];
|
|
@@ -329,13 +333,74 @@ export function resolveModelFamilies(provider, opts = {}) {
|
|
|
329
333
|
fetched_at: null,
|
|
330
334
|
};
|
|
331
335
|
}
|
|
336
|
+
if (provider === "codex" && !Object.hasOwn(families, definition.family)) {
|
|
337
|
+
const latest = selectCodexModel(catalog?.models, definition.family);
|
|
338
|
+
const lastFamily =
|
|
339
|
+
previous.families?.[definition.family] || profiles[name];
|
|
340
|
+
families[definition.family] =
|
|
341
|
+
latest &&
|
|
342
|
+
(!lastFamily.fetched_at ||
|
|
343
|
+
!catalog.fetched_at ||
|
|
344
|
+
Date.parse(catalog.fetched_at) >= Date.parse(lastFamily.fetched_at))
|
|
345
|
+
? { model: latest.slug, fetched_at: catalog.fetched_at || fetchedAt }
|
|
346
|
+
: { model: lastFamily.model, fetched_at: lastFamily.fetched_at };
|
|
347
|
+
selectedFamilies[definition.family] =
|
|
348
|
+
typeof pin === "string" &&
|
|
349
|
+
CODEX_SLUG.exec(pin)?.[2] === definition.family
|
|
350
|
+
? { model: pin, source: paths.pinsPath, fetched_at: null }
|
|
351
|
+
: { ...families[definition.family] };
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
if (provider === "agy") {
|
|
355
|
+
const latest = selectAgyModel(catalog?.models, "argon");
|
|
356
|
+
// 옛 기록에는 가족 ID가 없으므로 마지막 성공 프로필의 표시 이름에서 복원한다.
|
|
357
|
+
const savedModels = [
|
|
358
|
+
...Object.values(AGY_FAMILY_PROFILES),
|
|
359
|
+
...Object.values(profiles),
|
|
360
|
+
].flatMap((profile) => {
|
|
361
|
+
const match = /^Gemini (\d+(?:\.\d+)*) Argon \(/i.exec(profile.model);
|
|
362
|
+
return match
|
|
363
|
+
? [{ ...profile, slug: `gemini-${match[1]}-argon-${profile.effort}` }]
|
|
364
|
+
: [];
|
|
365
|
+
});
|
|
366
|
+
const saved = selectAgyModel(savedModels, "argon");
|
|
367
|
+
const last = previous.families?.argon || {
|
|
368
|
+
model: saved.slug.replace(/-[^-]+$/, ""),
|
|
369
|
+
fetched_at: saved.fetched_at,
|
|
370
|
+
};
|
|
371
|
+
families.argon =
|
|
372
|
+
latest &&
|
|
373
|
+
(!last.fetched_at ||
|
|
374
|
+
!catalog.fetched_at ||
|
|
375
|
+
Date.parse(catalog.fetched_at) >= Date.parse(last.fetched_at))
|
|
376
|
+
? {
|
|
377
|
+
model: latest.slug.replace(/-[^-]+$/, ""),
|
|
378
|
+
fetched_at: catalog.fetched_at || fetchedAt,
|
|
379
|
+
}
|
|
380
|
+
: last;
|
|
381
|
+
const pin = pins.argon;
|
|
382
|
+
selectedFamilies.argon =
|
|
383
|
+
typeof pin === "string" && AGY_SLUG.test(`${pin}-low`)
|
|
384
|
+
? { model: pin, source: paths.pinsPath, fetched_at: null }
|
|
385
|
+
: { ...families.argon };
|
|
386
|
+
const supported = catalog?.models
|
|
387
|
+
?.filter((item) =>
|
|
388
|
+
item.slug.startsWith(`${selectedFamilies.argon.model}-`),
|
|
389
|
+
)
|
|
390
|
+
.map((item) => AGY_SLUG.exec(item.slug)?.[3])
|
|
391
|
+
.filter(Boolean);
|
|
392
|
+
if (supported?.length) selectedFamilies.argon.supportedEfforts = supported;
|
|
332
393
|
}
|
|
333
394
|
const record = {
|
|
334
395
|
sourceSignature,
|
|
335
396
|
checked_at: checkedAt || null,
|
|
336
397
|
profiles,
|
|
337
398
|
selectedProfiles,
|
|
399
|
+
families,
|
|
338
400
|
};
|
|
339
401
|
if (opts.persist !== false) saveJson(recordPath, record);
|
|
340
|
-
return {
|
|
402
|
+
return {
|
|
403
|
+
profiles: selectedProfiles,
|
|
404
|
+
families: selectedFamilies,
|
|
405
|
+
};
|
|
341
406
|
}
|