sprag-cli 3.61.0 → 3.62.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/docs/CODEX.ko.md +18 -8
- package/docs/CODEX.md +17 -6
- package/package.json +1 -1
- package/src/codex-delegation.js +55 -4
- package/src/codex-doctor.js +2 -2
- package/src/commands/codex-delegate.js +21 -7
- package/src/commands/codex.js +11 -1
- package/src/seed-rules.js +3 -3
package/docs/CODEX.ko.md
CHANGED
|
@@ -158,19 +158,29 @@ Claude를 설치하지 않은 Codex 첫 사용자도 기록을 쌓기 전에 프
|
|
|
158
158
|
sprag seed --agent codex
|
|
159
159
|
sprag seed accept all --global --agent codex
|
|
160
160
|
sprag delegate shared status --agent codex
|
|
161
|
+
sprag delegate on --agent codex
|
|
162
|
+
# 자동으로 정해진 난도별 모델을 바꾸고 싶을 때만:
|
|
161
163
|
sprag delegate shared map T2 --from PARENT_MODEL --model SMALL_MODEL --effort high --agent codex
|
|
162
164
|
sprag delegate shared map T1 --from PARENT_MODEL --model MEDIUM_MODEL --effort medium --agent codex
|
|
163
|
-
sprag delegate on --agent codex
|
|
164
165
|
```
|
|
165
166
|
|
|
166
167
|
등록 전에 전역과 프로젝트 범위를 선택합니다. 프로젝트에만 적용하려면 `--global` 대신
|
|
167
|
-
`--project`를 지정하십시오.
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
168
|
+
`--project`를 지정하십시오.
|
|
169
|
+
|
|
170
|
+
`map` 줄은 선택 사항입니다. 매핑하지 않은 난도는 Claude Code가 `haiku`와 `sonnet`을 실제 모델로
|
|
171
|
+
풀듯이 자동으로 정해집니다. 부모 모델의 공급자에서 가격이 매겨져 있고(게이트웨이 `/model/info` 가격,
|
|
172
|
+
OpenAI 직접 호출이면 공개 가격), 부모보다 싸며, 이 사용자의 Codex 세션에서 이미 실행된 모델 가운데
|
|
173
|
+
가장 싼 모델이 T2, 그다음 모델이 T1이 됩니다. 그런 모델이 하나뿐이면 T1은 메인 모델이 처리하고, 하나도
|
|
174
|
+
없으면 두 난도 모두 메인 모델이 처리합니다. 자동 결정은 `delegate on` 상태에서만 동작하고, route-scan이
|
|
175
|
+
기록한 실행 모델을 쓰며, 아무것도 저장하지 않으므로 가격이나 실행 이력이 바뀌면 그대로 따라갑니다.
|
|
176
|
+
`delegate shared status`와 설치 출력에 정해진 모델이 표시되고, 정해지지 않으면 그 이유가 표시됩니다.
|
|
177
|
+
끄려면 `sprag delegate shared auto off --agent codex`를 실행하십시오.
|
|
178
|
+
|
|
179
|
+
명시한 매핑은 해당 난도에서 자동 결정보다 우선합니다. 매핑은 출발 모델·공급자·난도가 일치할 때만
|
|
180
|
+
적용하고, 한 번 지정하면 승인된 모든 작업 유형에서 사용합니다. 공급자는 Codex 설정에서 읽으며
|
|
181
|
+
`--provider ID`로 지정할 수도 있습니다. 매핑이나 자동 결정만으로 절감 효과를 확인한 것은 아닙니다.
|
|
182
|
+
Codex에서 승인할 때 `.claude` 파일은 만들지 않으며, 나중에 Claude를 시작하면 같은 정책을 Claude용
|
|
183
|
+
모델 표기로 생성합니다.
|
|
174
184
|
|
|
175
185
|
프롬프트 훅은 단순 작업에 T2, 여러 단계가 필요한 작업에 T1을 제시하고, 매핑된 난도마다 route 줄을
|
|
176
186
|
따로 줍니다. 부모는 작업에 맞는 모델 하나를 선택하고 독립적인 작업 명세, 상한, `fork_turns "none"`과
|
package/docs/CODEX.md
CHANGED
|
@@ -223,16 +223,27 @@ A Codex-first user needs no Claude installation or transcript history:
|
|
|
223
223
|
sprag seed --agent codex
|
|
224
224
|
sprag seed accept all --global --agent codex # or --project, after choosing scope
|
|
225
225
|
sprag delegate shared status --agent codex
|
|
226
|
+
sprag delegate on --agent codex
|
|
227
|
+
# optional, to override the automatic tier models:
|
|
226
228
|
sprag delegate shared map T2 --from PARENT_MODEL --model SMALL_MODEL --effort high --agent codex
|
|
227
229
|
sprag delegate shared map T1 --from PARENT_MODEL --model MEDIUM_MODEL --effort medium --agent codex
|
|
228
|
-
sprag delegate on --agent codex
|
|
229
230
|
```
|
|
230
231
|
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
232
|
+
The map lines are optional. A tier without a mapping resolves automatically,
|
|
233
|
+
the way Claude Code resolves `haiku` and `sonnet`: the cheapest model that is
|
|
234
|
+
priced on the parent's provider (gateway `/model/info` prices, or OpenAI list
|
|
235
|
+
prices for direct calls), costs less than the parent, and has already run in
|
|
236
|
+
your Codex sessions becomes T2, and the next one up becomes T1. With a single
|
|
237
|
+
such model T1 stays on the main agent; with none, both do. Resolution needs
|
|
238
|
+
`delegate on`, uses the route scan's observed models, and follows price or
|
|
239
|
+
history changes without storing anything. `delegate shared status` and the
|
|
240
|
+
install output show the resolved models and, when nothing resolves, why.
|
|
241
|
+
`sprag delegate shared auto off --agent codex` turns it off.
|
|
242
|
+
|
|
243
|
+
An explicit mapping wins for its tier. Each one applies to one exact parent
|
|
244
|
+
model, provider, and tier, across every approved category; `--provider ID`
|
|
245
|
+
overrides the provider read from Codex config. Mappings and automatic choices
|
|
246
|
+
do not prove savings, and no Haiku/Sonnet-to-GPT equivalence is assumed.
|
|
236
247
|
Codex seed acceptance writes the common registry without creating `.claude`;
|
|
237
248
|
Claude renders its own view when it is installed or starts later.
|
|
238
249
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sprag-cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.62.0",
|
|
4
4
|
"description": "Lower your Claude Code bill without changing how you work: simple tasks go to cheaper models, documents go in as compact Markdown, and the statusline shows spend and savings live. Works with Codex too.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|
package/src/codex-delegation.js
CHANGED
|
@@ -11,6 +11,8 @@ import { newRouteId, recordCodexDelegation } from './codex-ledger.js';
|
|
|
11
11
|
import { readCodexTailLines } from './codex-parser.js';
|
|
12
12
|
import { loadConfig } from './config.js';
|
|
13
13
|
import { loadSharedModelRules, sharedModelRulesForProject, sharedRuleBounds, SHARED_RULE_TIERS } from './shared-model-rules.js';
|
|
14
|
+
import { codexPriceBook, readCodexPrices } from './codex-cache-policy.js';
|
|
15
|
+
import { codexRunCost } from './gateway-prices.js';
|
|
14
16
|
|
|
15
17
|
export const CODEX_ROUTE_CATEGORIES = ['paste', 'translate', 'explore', 'read', 'check', 'run'];
|
|
16
18
|
const MARKER = '<!-- sprag:codex:delegation -->';
|
|
@@ -41,10 +43,59 @@ export function codexSharedTargets(cfg) {
|
|
|
41
43
|
});
|
|
42
44
|
}
|
|
43
45
|
|
|
44
|
-
|
|
46
|
+
// A request of this shape (input to output about 5:1) ranks models by price.
|
|
47
|
+
const RANKING_USAGE = { input: 10000, output: 2000 };
|
|
48
|
+
const routeScanFile = (dir) => join(dir, 'codex-route-scan.json');
|
|
49
|
+
|
|
50
|
+
function observedCodexModels(dir, provider) {
|
|
51
|
+
try {
|
|
52
|
+
const data = JSON.parse(readFileSync(routeScanFile(dir), 'utf8'));
|
|
53
|
+
const prefix = `${provider}|`;
|
|
54
|
+
return (Array.isArray(data?.observedModels) ? data.observedModels : [])
|
|
55
|
+
.filter((key) => typeof key === 'string' && key.startsWith(prefix)).map((key) => key.slice(prefix.length));
|
|
56
|
+
} catch { return []; }
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* The models Codex resolves T2 and T1 to when the user mapped none, the way
|
|
61
|
+
* Claude Code resolves `haiku` and `sonnet`. Only a model that is priced on the
|
|
62
|
+
* parent's provider, costs less than the parent, and has already run in this
|
|
63
|
+
* user's Codex sessions qualifies, so the hint never names a model the gateway
|
|
64
|
+
* cannot serve. The cheapest is T2 and the next one up is T1; with a single
|
|
65
|
+
* candidate T1 stays on the main agent. Returns { targets, reason }.
|
|
66
|
+
*/
|
|
67
|
+
export function autoCodexSharedTargets({ dir = userDataDir(), home = codexUserDir(), model, provider, now = Date.now() } = {}) {
|
|
68
|
+
if (!safeId(model) || !safeId(provider)) return { targets: [], reason: 'unknown parent model or provider' };
|
|
69
|
+
const book = codexPriceBook(provider, readCodexPrices({ now, home, dir }), { home });
|
|
70
|
+
if (!book) return { targets: [], reason: `no price table for ${provider}` };
|
|
71
|
+
const cost = (m) => codexRunCost(RANKING_USAGE, book.prices[m]);
|
|
72
|
+
const parent = cost(model);
|
|
73
|
+
if (parent === null) return { targets: [], reason: `${model} is not priced on ${provider}` };
|
|
74
|
+
const cheaper = [...new Set(observedCodexModels(dir, provider))]
|
|
75
|
+
.filter((m) => m !== model && safeId(m)).map((m) => ({ model: m, usd: cost(m) }))
|
|
76
|
+
.filter((x) => x.usd !== null && x.usd < parent).sort((a, b) => a.usd - b.usd || a.model.localeCompare(b.model));
|
|
77
|
+
if (!cheaper.length) return { targets: [], reason: `no cheaper priced model has run in your Codex sessions on ${provider}` };
|
|
78
|
+
const targets = cheaper.slice(0, 2).map((x, i) => ({ tier: i === 0 ? 'T2' : 'T1', from: model, model: x.model, provider, auto: true }));
|
|
79
|
+
return { targets, reason: null };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* Explicit mappings win per tier. Without one, a tier resolves automatically
|
|
84
|
+
* unless the user turned that off; resolution runs only for an enabled Codex
|
|
85
|
+
* delegation, so a caller without the hook's config never routes by accident.
|
|
86
|
+
*/
|
|
87
|
+
export function codexTierTargets({ cfg = loadConfig(), dir = userDataDir(), home = codexUserDir(), model, provider = codexProviderName() } = {}) {
|
|
88
|
+
const explicit = codexSharedTargets(cfg).filter((t) => t.from === model && t.provider === provider);
|
|
89
|
+
if (cfg.codex?.delegate !== true || cfg.codex?.sharedRules?.auto === false) return explicit;
|
|
90
|
+
const auto = autoCodexSharedTargets({ dir, home, model, provider }).targets
|
|
91
|
+
.filter((t) => !explicit.some((e) => e.tier === t.tier));
|
|
92
|
+
return [...explicit, ...auto];
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export function sharedCodexModelRules({ cfg = loadConfig(), dir = userDataDir(), home = codexUserDir(), root, start = root,
|
|
45
96
|
model, provider = codexProviderName() } = {}) {
|
|
46
97
|
if (cfg.codex?.sharedRules?.enabled === false) return [];
|
|
47
|
-
const targets =
|
|
98
|
+
const targets = codexTierTargets({ cfg, dir, home, model, provider });
|
|
48
99
|
return sharedModelRulesForProject(loadSharedModelRules({ dir }), start).flatMap((rule) => {
|
|
49
100
|
const target = targets.find((t) => t.tier === rule.tier);
|
|
50
101
|
return target ? [{ ...rule, ...target, source: 'shared', status: 'active' }] : [];
|
|
@@ -210,7 +261,7 @@ export function codexRouteHint(payload, opts = {}) {
|
|
|
210
261
|
record({ id, parentSessionId: payload?.session_id ?? null, turnId: payload?.turn_id ?? null, via: 'prompt',
|
|
211
262
|
source: shared ? 'shared' : 'rule', category: route.category, scope: route.scope, from: payload?.model, to: route.model,
|
|
212
263
|
provider: route.provider || provider, effort: route.effort ?? null, contextTokens: ctx, targetRoot: route.targetRoot ?? null,
|
|
213
|
-
...(shared ? { tier: route.tier, sharedSignature: route.sharedSignature, ...(offerId ? { offerId } : {}) }
|
|
264
|
+
...(shared ? { tier: route.tier, sharedSignature: route.sharedSignature, ...(offerId ? { offerId } : {}), ...(route.auto ? { mapping: 'auto' } : {}) }
|
|
214
265
|
: { ruleCreatedAt: route.createdAt ?? null }) }, { dir: opts.dir });
|
|
215
266
|
} catch { /* Accounting is optional; the hint still applies. */ }
|
|
216
267
|
return id;
|
|
@@ -268,7 +319,7 @@ export function codexDelegationTool(payload, { cfg = {}, root = payload?.cwd ||
|
|
|
268
319
|
let rules = given;
|
|
269
320
|
if (!rules) { try { rules = loadCodexModelRules({ dir }); } catch { rules = []; } }
|
|
270
321
|
const provider = payload.model_provider || codexProviderName({ home });
|
|
271
|
-
const routes = explicit ? [] : matchingRoutes(input.message, { model: payload.model, provider, root, start: payload.cwd, rules, cfg, dir });
|
|
322
|
+
const routes = explicit ? [] : matchingRoutes(input.message, { model: payload.model, provider, root, start: payload.cwd, rules, cfg, dir, home });
|
|
272
323
|
// Only the caller can choose a shared policy's tier. A shared match without a
|
|
273
324
|
// model goes back to the caller with the mapped choices instead of a guessed
|
|
274
325
|
// downgrade, or a default target that ignores the tier.
|
package/src/codex-doctor.js
CHANGED
|
@@ -17,13 +17,13 @@ export const CODEX_CAPABILITIES = [
|
|
|
17
17
|
{ feature: 'korean', support: 'supported', command: 'sprag korean status --agent codex', note: 'Session guidance and recognized write-target lint; shared preference.' },
|
|
18
18
|
{ feature: 'cohesion', support: 'supported', command: 'sprag cohesion status --agent codex', note: 'Shared English guidance preference.' },
|
|
19
19
|
{ feature: 'doc2md', support: 'supported', command: 'sprag doc2md status --agent codex', note: 'Shared converter, prompt paths, supported file reads, and recognized document/cache write guards; not arbitrary shell extraction.' },
|
|
20
|
-
{ feature: 'delegate', support: 'supported', command: 'sprag delegate on --agent codex', note: 'Native routing and shared delegation policies
|
|
20
|
+
{ feature: 'delegate', support: 'supported', command: 'sprag delegate on --agent codex', note: 'Native routing and shared delegation policies; tier models resolve from priced models already run in Codex, or from explicit mappings. Explicit models/custom roles preserved; bounds are guidance, not enforced limits.' },
|
|
21
21
|
{ feature: 'routing-saved', support: 'partial', command: 'sprag route-scan savings --agent codex', note: 'Sprag-routed child usage with matching LiteLLM prices; counterfactual estimate, not billed savings. Unpriced runs stay unknown.' },
|
|
22
22
|
{ feature: 'cache-timer', support: 'partial', command: 'sprag cache status --refresh --agent codex', note: 'Documented minimum retention after recorded cache usage; LiteLLM deployments resolved through model/info. Unknown routes show age; exact expiry is not reported.' },
|
|
23
23
|
{ feature: 'mode', support: 'partial', command: 'sprag mode --agent codex', note: 'Labels, color, and timer apply to panel/statusline; Claude TTL buckets do not.' },
|
|
24
24
|
{ feature: 'upgrade', support: 'manual', command: 'sprag upgrade --print --agent codex', note: 'Skip the Claude npm postinstall; reinstall Codex hooks after upgrade.' },
|
|
25
25
|
{ feature: 'route-scan', support: 'supported', command: 'sprag route-scan --agent codex', note: 'Recurring simple turns grouped by project, provider, and parent model; explicit approval before routing.' },
|
|
26
|
-
{ feature: 'seed', support: 'supported', command: 'sprag seed --agent codex', note: 'Shared delegation policies plus agent-compatible ratchet presets. Explicit scope;
|
|
26
|
+
{ feature: 'seed', support: 'supported', command: 'sprag seed --agent codex', note: 'Shared delegation policies plus agent-compatible ratchet presets. Explicit scope; tier models resolve automatically or by mapping. No Claude installation needed.' },
|
|
27
27
|
{ feature: 'transcript ratchet', support: 'supported', command: 'sprag --statusline --agent codex', note: 'Recent repeated tool failures become ratchet? candidates; no automatic rule registration.' },
|
|
28
28
|
{ feature: 'compact-window', support: 'native', note: 'Codex uses model_auto_compact_token_limit; no Claude autoCompactWindow heuristic.' },
|
|
29
29
|
{ feature: 'cost / exact cache expiry', support: 'unavailable', note: 'Not measured in rollout logs; never estimated with Anthropic prices.' },
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { loadConfig, saveConfig } from '../config.js';
|
|
2
2
|
import { configureCodexHooks } from '../codex-installer.js';
|
|
3
3
|
import { validateCodexTarget, loadCodexModelRules, addCodexModelRule, removeCodexModelRule,
|
|
4
|
-
validateCodexSharedTarget, codexSharedTargets, codexDelegateMinContext, DEFAULT_DELEGATE_MIN_CONTEXT
|
|
4
|
+
validateCodexSharedTarget, codexSharedTargets, codexDelegateMinContext, DEFAULT_DELEGATE_MIN_CONTEXT,
|
|
5
|
+
autoCodexSharedTargets } from '../codex-delegation.js';
|
|
5
6
|
import { findCodexCandidate, resolveCodexCandidate } from '../codex-route-scan.js';
|
|
6
7
|
import { codexRoutingSavedTotals, loadCodexLedger } from '../codex-ledger.js';
|
|
7
8
|
import { codexRuleHealth, codexRulesInReview } from '../codex-rule-health.js';
|
|
@@ -23,13 +24,23 @@ function printShared(cfg, { details = false } = {}) {
|
|
|
23
24
|
for (const t of targets) console.log(`${t.provider} | ${t.from} | ${t.tier} -> ${t.model}${t.effort ? ` (${t.effort})` : ''}`);
|
|
24
25
|
}
|
|
25
26
|
// A mapping routes only sessions on the parent model it names, so a tier
|
|
26
|
-
// mapped for another model still leaves the configured model unrouted.
|
|
27
|
-
|
|
28
|
-
const
|
|
27
|
+
// mapped for another model still leaves the configured model unrouted. A tier
|
|
28
|
+
// without one resolves automatically, the way Claude Code resolves haiku/sonnet.
|
|
29
|
+
const own = (tier) => targets.find((t) => t.provider === provider && t.tier === tier && (!parent || t.from === parent));
|
|
30
|
+
const autoOn = cfg.codex?.sharedRules?.auto !== false;
|
|
31
|
+
const auto = autoOn && parent ? autoCodexSharedTargets({ model: parent, provider }) : { targets: [], reason: autoOn ? 'Codex config names no default model' : 'off' };
|
|
32
|
+
const tiers = [...new Set(policies.map((r) => r.tier))];
|
|
33
|
+
for (const tier of tiers) {
|
|
34
|
+
const t = own(tier) || auto.targets.find((a) => a.tier === tier);
|
|
35
|
+
if (t) console.log(`${tier} -> ${t.model}${t.effort ? ` (${t.effort})` : ''}${t.auto ? ' (auto: cheaper priced model already run in Codex)' : ''}`);
|
|
36
|
+
}
|
|
37
|
+
const missing = tiers.filter((tier) => !own(tier) && !auto.targets.some((a) => a.tier === tier));
|
|
29
38
|
if (missing.length) {
|
|
30
|
-
console.log(`Unmapped tiers for ${parent || 'any parent model'} on ${provider || 'unknown provider'}: ${missing.join(', ')}
|
|
39
|
+
console.log(`Unmapped tiers for ${parent || 'any parent model'} on ${provider || 'unknown provider'}: ${missing.join(', ')}`
|
|
40
|
+
+ `${autoOn && auto.reason ? ` (auto: ${auto.reason})` : ''}. `
|
|
31
41
|
+ `Set: sprag delegate shared map <T1|T2> --from ${parent || '<parent-model>'} --model <target-model> --agent codex`);
|
|
32
42
|
}
|
|
43
|
+
console.log(`Automatic tier models: ${autoOn ? 'on' : 'off'} (turn ${autoOn ? 'off' : 'on'}: sprag delegate shared auto ${autoOn ? 'off' : 'on'} --agent codex)`);
|
|
33
44
|
if (!parent && targets.length) console.log('Codex config names no default model; each mapping routes only sessions on its --from model.');
|
|
34
45
|
const minimum = codexDelegateMinContext(cfg);
|
|
35
46
|
console.log(`Shared prompt guidance starts at ${minimum} parent input tokens${cfg.codex?.delegateMinContext === minimum ? '' : ' (default)'}. `
|
|
@@ -48,8 +59,8 @@ export function run({ args, getArg, hasFlag, root }) {
|
|
|
48
59
|
const cfg = loadConfig();
|
|
49
60
|
if (sub === 'shared') {
|
|
50
61
|
const action = args[2] || 'status';
|
|
51
|
-
if (!['status', 'on', 'off', 'map', 'unmap', 'min-context'].includes(action)) {
|
|
52
|
-
throw new Error('Usage: delegate shared status|on|off|map <T1|T2>|unmap <T1|T2>|min-context <tokens|default
|
|
62
|
+
if (!['status', 'on', 'off', 'map', 'unmap', 'min-context', 'auto'].includes(action)) {
|
|
63
|
+
throw new Error('Usage: delegate shared status|on|off|map <T1|T2>|unmap <T1|T2>|min-context <tokens|default>|auto on|off --agent codex');
|
|
53
64
|
}
|
|
54
65
|
if (hasFlag('--global') || hasFlag('--project')) throw new Error('Shared policies retain their approved scope; mappings do not change it.');
|
|
55
66
|
const provided = (flag) => args.some((arg) => arg === flag || arg.startsWith(`${flag}=`));
|
|
@@ -71,6 +82,9 @@ export function run({ args, getArg, hasFlag, root }) {
|
|
|
71
82
|
if (!targets.some(same)) throw new Error('No matching shared tier mapping; specify --from and the correct provider.');
|
|
72
83
|
cfg.codex = { ...cfg.codex, sharedRules: { ...cfg.codex?.sharedRules, targets: targets.filter((t) => !same(t)) } };
|
|
73
84
|
}
|
|
85
|
+
} else if (action === 'auto') {
|
|
86
|
+
if (!['on', 'off'].includes(args[3])) throw new Error('Usage: delegate shared auto on|off --agent codex');
|
|
87
|
+
cfg.codex = { ...cfg.codex, sharedRules: { ...cfg.codex?.sharedRules, auto: args[3] === 'on' } };
|
|
74
88
|
} else if (action === 'min-context') {
|
|
75
89
|
const value = args[3];
|
|
76
90
|
if (value === 'default') {
|
package/src/commands/codex.js
CHANGED
|
@@ -32,6 +32,7 @@ Usage: sprag <command> --agent codex [options]
|
|
|
32
32
|
Optional --provider <id> and --effort <level>
|
|
33
33
|
delegate shared unmap T1|T2 Remove a mapping: --from <parent> [--provider <id>]
|
|
34
34
|
delegate shared min-context N Parent input tokens before shared guidance; default resets
|
|
35
|
+
delegate shared auto on|off Resolve unmapped tiers from priced models already run in Codex
|
|
35
36
|
route-scan [--refresh] Discover recurring simple turns in local logs
|
|
36
37
|
route-scan dismiss R<N> Dismiss a candidate without registering a rule
|
|
37
38
|
route-scan savings Attributed routing estimates; --refresh or --format json
|
|
@@ -418,7 +419,16 @@ export async function run({ args, version }) {
|
|
|
418
419
|
console.log('After approval, start or resume Codex and run: sprag panel doctor --agent codex');
|
|
419
420
|
if (panel.mode === 'window') console.log('Some Codex versions defer SessionStart until the first prompt. For immediate opening on typing codex: sprag panel shell install --agent codex (optional zsh integration).');
|
|
420
421
|
console.log('Existing config.toml, Claude Code settings, and ratchet rules are preserved.');
|
|
421
|
-
|
|
422
|
+
try {
|
|
423
|
+
const { codexModelName, codexProviderName } = await import('../agent.js');
|
|
424
|
+
const { autoCodexSharedTargets } = await import('../codex-delegation.js');
|
|
425
|
+
const parent = codexModelName(), provider = codexProviderName();
|
|
426
|
+
const auto = parent ? autoCodexSharedTargets({ model: parent, provider }) : { targets: [], reason: 'Codex config names no default model' };
|
|
427
|
+
console.log(auto.targets.length
|
|
428
|
+
? `Delegation tiers for ${parent} on ${provider} (auto): ${auto.targets.map((t) => `${t.tier} -> ${t.model}`).join(', ')}. Change: sprag delegate shared status --agent codex`
|
|
429
|
+
: `Delegation tiers: not resolved yet (${auto.reason}). They resolve once a cheaper priced model has run in Codex, or map one: sprag delegate shared map T2 --from <parent> --model <target> --agent codex`);
|
|
430
|
+
} catch (e) { debug('codex:auto-tiers', e); }
|
|
431
|
+
console.log('First-use delegation: sprag seed --agent codex to approve policies, then sprag delegate on --agent codex. No Claude installation is required.');
|
|
422
432
|
console.log('Korean guidance is opt-in: sprag korean on --agent codex');
|
|
423
433
|
return;
|
|
424
434
|
}
|
package/src/seed-rules.js
CHANGED
|
@@ -150,8 +150,8 @@ export function pendingSeeds({ lang = userLanguage(), root = findProjectRoot(),
|
|
|
150
150
|
|
|
151
151
|
function codexSeedText(p, lang) {
|
|
152
152
|
const text = lang === 'ko'
|
|
153
|
-
? `"${p.label}" 유형의 ${p.tier === 'T2' ? '단순' : '중간 난도'} 작업은 ${p.tier}에 위임합니다. 실행 모델은 Codex
|
|
154
|
-
: `${p.tier === 'T2' ? 'Simple' : 'Moderate'} "${p.labelEn}" tasks use ${p.tier}.
|
|
153
|
+
? `"${p.label}" 유형의 ${p.tier === 'T2' ? '단순' : '중간 난도'} 작업은 ${p.tier}에 위임합니다. 실행 모델은 Codex가 자동으로 정하거나 매핑으로 지정합니다.`
|
|
154
|
+
: `${p.tier === 'T2' ? 'Simple' : 'Moderate'} "${p.labelEn}" tasks use ${p.tier}. Codex resolves the execution model automatically or from a mapping.`;
|
|
155
155
|
return composeRuleText(text, p, lang);
|
|
156
156
|
}
|
|
157
157
|
|
|
@@ -292,7 +292,7 @@ export function seedOfferBlock({ lang = userLanguage(), root = findProjectRoot()
|
|
|
292
292
|
' 3. Decide one at a time: ask about each rule below and run its command as soon as they answer',
|
|
293
293
|
` 4. Register none: ${cmd('skip all')} (never offered again)`,
|
|
294
294
|
'Always confirm the scope with the user before running an accept command.',
|
|
295
|
-
'Delegation policies are shared across Claude and Codex; approval retains the chosen scope. Codex execution also requires delegate on
|
|
295
|
+
'Delegation policies are shared across Claude and Codex; approval retains the chosen scope. Codex execution also requires delegate on; tier models resolve from cheaper priced models already run in Codex, or from mappings: sprag delegate shared status --agent codex. Never assume Claude model names are Codex models.',
|
|
296
296
|
...pending.map((s) => ` [${s.id}] ${s.ruleText}`),
|
|
297
297
|
].join('\n');
|
|
298
298
|
}
|