jeo-code 0.7.56 → 0.7.58
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/CHANGELOG.md +29 -0
- package/README.ja.md +2 -2
- package/README.ko.md +2 -2
- package/README.md +2 -2
- package/README.zh.md +2 -2
- package/package.json +1 -1
- package/src/agent/config-schema.ts +14 -0
- package/src/agent/context-files.ts +25 -0
- package/src/agent/engine.ts +4 -2
- package/src/agent/prompt-router.ts +211 -34
- package/src/agent/state.ts +22 -1
- package/src/agent/subagents.ts +37 -3
- package/src/agent/tools.ts +169 -0
- package/src/ai/model-catalog-compat.ts +20 -4
- package/src/ai/model-catalog.ts +117 -83
- package/src/ai/model-discovery.ts +5 -1
- package/src/ai/model-manager.ts +17 -4
- package/src/auth/callback-server.ts +13 -3
- package/src/commands/doctor.ts +32 -6
- package/src/commands/launch.ts +1 -1
- package/src/tui/app.ts +2 -2
- package/src/tui/components/status.ts +1 -1
package/src/ai/model-manager.ts
CHANGED
|
@@ -146,10 +146,23 @@ export async function describeModel(
|
|
|
146
146
|
return { input, resolved, provider: resolveProvider(resolved) };
|
|
147
147
|
}
|
|
148
148
|
|
|
149
|
-
export type ModelRole = "smol" | "slow" | "plan";
|
|
150
|
-
|
|
151
|
-
/** Resolve a model role tier (smol/slow/plan) → configured tier model, else defaultModel. */
|
|
152
|
-
export function resolveRoleModel(
|
|
149
|
+
export type ModelRole = "smol" | "medium" | "high" | "xhigh" | "slow" | "plan";
|
|
150
|
+
|
|
151
|
+
/** Resolve a model role tier (smol/medium/high/xhigh/slow/plan) → configured tier model, else defaultModel. */
|
|
152
|
+
export function resolveRoleModel(
|
|
153
|
+
role: ModelRole,
|
|
154
|
+
config: {
|
|
155
|
+
defaultModel: string;
|
|
156
|
+
roles?: {
|
|
157
|
+
smol?: string;
|
|
158
|
+
medium?: string;
|
|
159
|
+
high?: string;
|
|
160
|
+
xhigh?: string;
|
|
161
|
+
slow?: string;
|
|
162
|
+
plan?: string;
|
|
163
|
+
};
|
|
164
|
+
},
|
|
165
|
+
): string {
|
|
153
166
|
return config.roles?.[role] || config.defaultModel;
|
|
154
167
|
}
|
|
155
168
|
|
|
@@ -58,13 +58,15 @@ h1.ok{color:#22d3ee}h1.fail{color:#f472b6}
|
|
|
58
58
|
p{margin:.25rem 0;color:#8b8b96;font-size:.92rem}
|
|
59
59
|
button{margin-top:1.5rem;padding:.55rem 1.6rem;border-radius:999px;border:1px solid #2a2a35;background:transparent;color:#e7e7ec;font:inherit;font-size:.88rem;cursor:pointer}
|
|
60
60
|
button:hover{background:#1b1c27}
|
|
61
|
-
.hint{margin-top:.9rem;font-size:.78rem;color:#5f5f6b}
|
|
61
|
+
.hint{margin-top:.9rem;font-size:.78rem;color:#5f5f6b}
|
|
62
|
+
.closed{display:none}</style></head>
|
|
62
63
|
<body><div class="card">
|
|
63
64
|
<img class="wordmark" alt="jeo" src="${JEO_WORDMARK_DATA_URI}">
|
|
64
65
|
<h1 class="__STATUS__">__TITLE__</h1>
|
|
65
66
|
<p>__MSG__</p>
|
|
66
67
|
<button id="jeo-close" type="button">Close</button>
|
|
67
68
|
<p class="hint">Closing automatically in <span id="jeo-countdown">__SECONDS__</span>s…</p>
|
|
69
|
+
<p class="hint closed" id="jeo-closed-msg">Window closed. You can close this tab.</p>
|
|
68
70
|
</div>
|
|
69
71
|
<script>__SCRIPT__</script>
|
|
70
72
|
</body></html>`;
|
|
@@ -78,8 +80,16 @@ const AUTO_CLOSE_SECONDS = 5;
|
|
|
78
80
|
|
|
79
81
|
function renderHtml(ok: boolean, msg: string): string {
|
|
80
82
|
const script = `(function(){
|
|
81
|
-
var n=${AUTO_CLOSE_SECONDS},el=document.getElementById("jeo-countdown"),btn=document.getElementById("jeo-close"),t;
|
|
82
|
-
function closeNow(){
|
|
83
|
+
var n=${AUTO_CLOSE_SECONDS},el=document.getElementById("jeo-countdown"),btn=document.getElementById("jeo-close"),closedMsg=document.getElementById("jeo-closed-msg"),t;
|
|
84
|
+
function closeNow(){
|
|
85
|
+
clearInterval(t);
|
|
86
|
+
var closed=window.close();
|
|
87
|
+
if(!closed){
|
|
88
|
+
btn.style.display="none";
|
|
89
|
+
el.parentElement.style.display="none";
|
|
90
|
+
closedMsg.classList.remove("closed");
|
|
91
|
+
}
|
|
92
|
+
}
|
|
83
93
|
t=setInterval(function(){n-=1;if(el)el.textContent=String(Math.max(n,0));if(n<=0)closeNow();},1000);
|
|
84
94
|
if(btn)btn.addEventListener("click",closeNow);
|
|
85
95
|
})();`;
|
package/src/commands/doctor.ts
CHANGED
|
@@ -8,7 +8,7 @@ import { meter } from "../tui/components/meter";
|
|
|
8
8
|
import { size } from "../tui/terminal";
|
|
9
9
|
import chalk from "chalk";
|
|
10
10
|
import { extractChatgptAccountId, CODEX_RESPONSES_URL } from "../ai/providers/openai-responses";
|
|
11
|
-
import { resolveTierModel } from "../agent/prompt-router";
|
|
11
|
+
import { resolveTierModel, tierModelPool } from "../agent/prompt-router";
|
|
12
12
|
|
|
13
13
|
interface ProbeResult {
|
|
14
14
|
status: "ok" | "fail" | "skipped";
|
|
@@ -197,8 +197,9 @@ export async function runDoctorCommand(args: string[] = []): Promise<void> {
|
|
|
197
197
|
if (routingEnabled) {
|
|
198
198
|
const tierCandidates: { tier: string; model: string | undefined }[] = [
|
|
199
199
|
{ tier: "trivial", model: config.routing?.tiers?.trivial?.model || config.roles?.smol },
|
|
200
|
-
{ tier: "standard", model: config.routing?.tiers?.standard?.model },
|
|
201
|
-
{ tier: "
|
|
200
|
+
{ tier: "standard", model: config.routing?.tiers?.standard?.model || config.roles?.medium || config.roles?.high },
|
|
201
|
+
{ tier: "high", model: config.routing?.tiers?.high?.model || config.roles?.high || config.roles?.medium },
|
|
202
|
+
{ tier: "complex", model: config.routing?.tiers?.complex?.model || config.roles?.xhigh || config.roles?.slow },
|
|
202
203
|
];
|
|
203
204
|
for (const { tier, model } of tierCandidates) {
|
|
204
205
|
if (!model) continue;
|
|
@@ -220,11 +221,36 @@ export async function runDoctorCommand(args: string[] = []): Promise<void> {
|
|
|
220
221
|
// informational — never affects ready/--strict, same contract as routingNotes.
|
|
221
222
|
const routingPreview: { tier: string; model: string; provider: string; source: string }[] = [];
|
|
222
223
|
if (routingEnabled) {
|
|
223
|
-
|
|
224
|
-
|
|
224
|
+
// Legacy role-tier fallback per tier, mirroring resolveTierModel's OWN precedence
|
|
225
|
+
// (not just the id it happens to already show up under `routing.tiers.*.model`) —
|
|
226
|
+
// so e.g. a `roles.medium`-only config correctly shows "configured", not
|
|
227
|
+
// "auto-selected", for `standard`.
|
|
228
|
+
|
|
229
|
+
for (const tier of ["trivial", "standard", "high", "complex"] as const) {
|
|
230
|
+
const legacyRole =
|
|
231
|
+
tier === "trivial" ? config.roles?.smol
|
|
232
|
+
: tier === "standard" ? config.roles?.medium || config.roles?.high
|
|
233
|
+
: tier === "high" ? config.roles?.high || config.roles?.medium
|
|
234
|
+
: config.roles?.xhigh || config.roles?.slow;
|
|
235
|
+
const explicit = config.routing?.tiers?.[tier]?.model || legacyRole;
|
|
225
236
|
const model = resolveTierModel(tier, config);
|
|
226
237
|
const provider = resolveProvider(model);
|
|
227
|
-
|
|
238
|
+
// crossProviderPoolPick (prompt-router.ts) is tried BEFORE every tier's own
|
|
239
|
+
// cheapest/strongest/mid-tier fallback, so a non-empty pool always wins over
|
|
240
|
+
// those once the flag is on — `.length > 0` alone is enough to know the pool,
|
|
241
|
+
// not the tier-specific fallback, produced `model`.
|
|
242
|
+
const pooled = !explicit && model !== config.defaultModel && !!config.routing?.crossProviderPool && tierModelPool(tier, config).length > 0;
|
|
243
|
+
const source = explicit
|
|
244
|
+
? "configured"
|
|
245
|
+
: model === config.defaultModel
|
|
246
|
+
? "defaultModel"
|
|
247
|
+
: pooled
|
|
248
|
+
? "auto-selected: cross-provider pool"
|
|
249
|
+
: tier === "trivial"
|
|
250
|
+
? "auto-selected: cheapest credentialed"
|
|
251
|
+
: tier === "high"
|
|
252
|
+
? "auto-selected: strongest mid-tier credentialed"
|
|
253
|
+
: "auto-selected: strongest credentialed";
|
|
228
254
|
routingPreview.push({ tier, model, provider, source });
|
|
229
255
|
}
|
|
230
256
|
}
|
package/src/commands/launch.ts
CHANGED
|
@@ -885,7 +885,7 @@ export async function runLaunchCommand(args: string[]): Promise<void> {
|
|
|
885
885
|
// selection must stay session-local: running sessions never influence each other.
|
|
886
886
|
const routingEnabled = sessionRouteOverride ?? !!turnConfig.routing?.enabled;
|
|
887
887
|
let routed = routingEnabled && !sessionModel
|
|
888
|
-
? await routePrompt(userInput, turnConfig, { hasImages: !!images?.length }).catch(() => null)
|
|
888
|
+
? await routePrompt(userInput, turnConfig, { hasImages: !!images?.length, sessionId }).catch(() => null)
|
|
889
889
|
: null;
|
|
890
890
|
// Fail-open credential gate: `routePrompt` only resolves a tier's model from
|
|
891
891
|
// config (routing.tiers/roles.smol/roles.slow/defaultModel) — it deliberately
|
package/src/tui/app.ts
CHANGED
|
@@ -73,7 +73,7 @@ export interface LaunchTuiOptions {
|
|
|
73
73
|
* gate fell back). Renders a persistent `⚡tier` marker in the status bar so the
|
|
74
74
|
* routed model stays visible without depending on the transient `[route]`
|
|
75
75
|
* console notice. See `StatusBarData.routedTier` in components/status.ts. */
|
|
76
|
-
routedTier?: "trivial" | "standard" | "complex";
|
|
76
|
+
routedTier?: "trivial" | "standard" | "high" | "complex";
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
export interface AgentEventsLike {
|
|
@@ -375,7 +375,7 @@ export class LaunchTui {
|
|
|
375
375
|
private readonly thinkingLevel?: string;
|
|
376
376
|
// PromptRouter's resolved tier when routing chose this turn's model; undefined when
|
|
377
377
|
// routing didn't engage. Renders the persistent `⚡tier` marker in the status bar.
|
|
378
|
-
private readonly routedTier?: "trivial" | "standard" | "complex";
|
|
378
|
+
private readonly routedTier?: "trivial" | "standard" | "high" | "complex";
|
|
379
379
|
|
|
380
380
|
constructor(opts: LaunchTuiOptions) {
|
|
381
381
|
// Backpressure-aware wrapper around the underlying writer (real stdout, or the
|
|
@@ -24,7 +24,7 @@ export interface StatusBarData {
|
|
|
24
24
|
* marker so the routed model stays visible without depending on the transient
|
|
25
25
|
* `[route] …` console notice, which intentionally stays silent for routine
|
|
26
26
|
* unescalated `standard`-tier turns. */
|
|
27
|
-
routedTier?: "trivial" | "standard" | "complex";
|
|
27
|
+
routedTier?: "trivial" | "standard" | "high" | "complex";
|
|
28
28
|
branch?: string;
|
|
29
29
|
/** Uncommitted-change count for the `?N` dirty flag; omit/0 = clean. */
|
|
30
30
|
dirtyCount?: number;
|