sortie-dogs 0.2.6 → 0.2.7
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/README.md +28 -19
- package/dist/plugin/model-routing.d.ts +38 -12
- package/dist/plugin/model-routing.js +59 -26
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -160,7 +160,7 @@ Optional settings in `.opencode/sortie-dogs.json`:
|
|
|
160
160
|
- `readOnlyTools` adds host-specific tool names that never change files, such as
|
|
161
161
|
MCP tools. Unknown tools are denied for a bound session by default.
|
|
162
162
|
- `dedicatedWorkerModel` selects the single model every worker role resolves to.
|
|
163
|
-
It defaults to `openai/gpt-5.6-
|
|
163
|
+
It defaults to `openai/gpt-5.6-luna` with variant `max`; declare your own when
|
|
164
164
|
that model is unavailable or when you want a different worker effort. Worker
|
|
165
165
|
roles always resolve to this one target and cannot be routed per role.
|
|
166
166
|
- `continuation` bounds the batch loop. After a terminal unit and its checkpoint,
|
|
@@ -180,7 +180,7 @@ Optional settings in `.opencode/sortie-dogs.json`:
|
|
|
180
180
|
exactly three bounded scouts before implementation begins.
|
|
181
181
|
- **Writes stay inside the assignment.** Exact source or operation manifests
|
|
182
182
|
gate edits and handoffs.
|
|
183
|
-
- **One accountable implementation path.**
|
|
183
|
+
- **One accountable implementation path.** One dedicated worker handles
|
|
184
184
|
implementation, remediation, and blocker resolution.
|
|
185
185
|
- **Evidence before completion.** Canonical validation, risk-based review, and
|
|
186
186
|
terminal evidence gate coordinator-owned completion and commits.
|
|
@@ -207,8 +207,8 @@ dog-coordinator: completion evidence accepted
|
|
|
207
207
|
criteria, a write manifest, and validation requirements.
|
|
208
208
|
2. **Exactly three scouts** — bounded, read-only investigation collects
|
|
209
209
|
complementary evidence without expanding the write scope.
|
|
210
|
-
3. **Dedicated worker** — the
|
|
211
|
-
and also owns scoped remediation or blocker resolution.
|
|
210
|
+
3. **Dedicated worker** — the dedicated worker implements only the approved
|
|
211
|
+
manifest and also owns scoped remediation or blocker resolution.
|
|
212
212
|
4. **Canonical validation** — the declared test or build command must produce
|
|
213
213
|
acceptable evidence.
|
|
214
214
|
5. **Risk-based review** — high-risk candidates receive independent review;
|
|
@@ -258,19 +258,26 @@ untouched.
|
|
|
258
258
|
|
|
259
259
|
## Model routing
|
|
260
260
|
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
261
|
+
Every default route is one model at a different reasoning effort, because
|
|
262
|
+
published cost curves put a cheap model at high effort above an expensive model
|
|
263
|
+
at mid effort on both solve rate and price. Sortie-dogs therefore buys effort,
|
|
264
|
+
not model tiers, wherever the work allows it.
|
|
265
|
+
|
|
266
|
+
`dog-coordinator` defaults to `openai/gpt-5.6-luna` with the `max` variant. The
|
|
267
|
+
coordinator produces dispatches rather than code, and one malformed dispatch
|
|
268
|
+
discards an entire worker session, so top effort here costs less than the work it
|
|
269
|
+
protects. `dog-scout` defaults to the same model with the `high` variant, since
|
|
270
|
+
gathering bounded evidence is retrieval rather than reasoning and that tier is
|
|
271
|
+
where the curve gives the most per unit of cost. Project-local routing can
|
|
272
|
+
override either default.
|
|
266
273
|
|
|
267
274
|
The `implementation`, `remediation`, `blocker-resolution`, and `dog-worker`
|
|
268
|
-
roles always use the dedicated worker target, `openai/gpt-5.6-
|
|
269
|
-
`
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
275
|
+
roles always use the dedicated worker target, `openai/gpt-5.6-luna` with the
|
|
276
|
+
`max` variant. Worker effort stays at the top of that model's range while review
|
|
277
|
+
effort stays above it on a stronger model, which is what mandatory source review
|
|
278
|
+
is for. Declare `dedicatedWorkerModel` as `openai/gpt-5.6-sol` when you would
|
|
279
|
+
rather pay for the stronger worker model up front; that target stays in the
|
|
280
|
+
built-in catalog for exactly this reason. `modelRouting`
|
|
274
281
|
cannot replace those routes, and only `dedicatedWorkerModel` moves them. For other explicitly
|
|
275
282
|
routed roles, resolution is deterministic: Sortie-dogs tries the preferred
|
|
276
283
|
target, then ordered fallbacks. Roles without either a built-in default or an
|
|
@@ -280,7 +287,9 @@ explicit route keep OpenCode's already selected model.
|
|
|
280
287
|
review and strategy lose their value when they run on the model that produced
|
|
281
288
|
the candidate. Both default to `anthropic/claude-opus-5` when the catalog
|
|
282
289
|
declares it, and otherwise fall back to `openai/gpt-5.6-sol` with the `xhigh`
|
|
283
|
-
variant
|
|
290
|
+
variant. That fallback stays on the stronger model rather than matching the
|
|
291
|
+
worker target, because review has to be able to reject work the worker just
|
|
292
|
+
produced. A host that redeclares
|
|
284
293
|
`dedicatedWorkerModel` keeps that target as its first fallback, since such a
|
|
285
294
|
host may not serve the shipped model at all. Nothing here requires a particular
|
|
286
295
|
vendor: both roles stay fully configurable, so declare whichever model you can
|
|
@@ -290,10 +299,10 @@ actually serve.
|
|
|
290
299
|
{
|
|
291
300
|
"modelRouting": {
|
|
292
301
|
"dog-coordinator": {
|
|
293
|
-
"preferred": { "model": "openai/gpt-5.6-luna", "variant": "
|
|
302
|
+
"preferred": { "model": "openai/gpt-5.6-luna", "variant": "max" }
|
|
294
303
|
},
|
|
295
304
|
"dog-scout": {
|
|
296
|
-
"preferred": { "model": "openai/gpt-5.6-luna", "variant": "
|
|
305
|
+
"preferred": { "model": "openai/gpt-5.6-luna", "variant": "high" }
|
|
297
306
|
},
|
|
298
307
|
"dog-reviewer": {
|
|
299
308
|
"preferred": { "model": "anthropic/claude-opus-5" },
|
|
@@ -306,7 +315,7 @@ actually serve.
|
|
|
306
315
|
"modelCatalog": {
|
|
307
316
|
"project": [
|
|
308
317
|
{ "model": "openai/gpt-5.6-sol", "variants": ["medium", "xhigh"] },
|
|
309
|
-
{ "model": "openai/gpt-5.6-luna", "variants": ["
|
|
318
|
+
{ "model": "openai/gpt-5.6-luna", "variants": ["max", "high"] },
|
|
310
319
|
{ "model": "anthropic/claude-opus-5" }
|
|
311
320
|
]
|
|
312
321
|
}
|
|
@@ -7,28 +7,50 @@ export interface RoleModelRoute {
|
|
|
7
7
|
readonly fallback?: readonly ModelTarget[];
|
|
8
8
|
}
|
|
9
9
|
export type ModelRoutingConfig = Readonly<Record<string, RoleModelRoute>>;
|
|
10
|
-
export declare const DEDICATED_SOL_MODEL = "openai/gpt-5.6-sol";
|
|
11
10
|
/**
|
|
12
|
-
*
|
|
13
|
-
*
|
|
14
|
-
*
|
|
11
|
+
* The published DeepSWE cost curve settles the worker target: the cheap model at top reasoning effort
|
|
12
|
+
* solves more than the expensive model at mid effort while costing a fraction of it, so paying for the
|
|
13
|
+
* expensive model by default bought a lower solve rate. Worker effort therefore sits at the top of the
|
|
14
|
+
* cheap model's range, and review effort stays above it on a stronger model, which is what the
|
|
15
|
+
* mandatory source review is for.
|
|
15
16
|
*/
|
|
16
|
-
export declare const
|
|
17
|
-
export declare const
|
|
17
|
+
export declare const DEDICATED_WORKER_MODEL = "openai/gpt-5.6-luna";
|
|
18
|
+
export declare const DEDICATED_WORKER_VARIANT = "max";
|
|
19
|
+
/**
|
|
20
|
+
* The stronger, far more expensive worker target a host may still select deliberately. It is no longer
|
|
21
|
+
* a default route: it stays declared so an explicit dedicatedWorkerModel resolves against the catalog
|
|
22
|
+
* without extra host configuration.
|
|
23
|
+
*/
|
|
24
|
+
export declare const ESCALATION_WORKER_MODEL = "openai/gpt-5.6-sol";
|
|
25
|
+
export declare const ESCALATION_WORKER_VARIANT = "medium";
|
|
26
|
+
export declare const DEDICATED_WORKER_ROLES: readonly ["implementation", "remediation", "blocker-resolution", "sol-worker-mk2a2", "dog-worker"];
|
|
18
27
|
/** Ordered last-resort targets used only when the host proves a policy target unavailable. */
|
|
19
28
|
export declare const DEFAULT_FREE_TIER_FALLBACK_MODELS: readonly string[];
|
|
20
29
|
/** The dedicated worker target this build ships with when a host declares no target of its own. */
|
|
21
30
|
export declare const DEFAULT_DEDICATED_WORKER_TARGET: ModelTarget;
|
|
31
|
+
/** The declared escalation target for a host that chooses to pay for the stronger worker model. */
|
|
32
|
+
export declare const ESCALATION_WORKER_TARGET: ModelTarget;
|
|
22
33
|
/**
|
|
23
34
|
* Fixed worker routes for one dedicated target. Which target is dedicated is a host decision, but
|
|
24
35
|
* every worker role resolves to that single target and never to a fallback.
|
|
25
36
|
*/
|
|
26
37
|
export declare function dedicatedWorkerRouting(target?: ModelTarget): ModelRoutingConfig;
|
|
27
|
-
export declare const
|
|
38
|
+
export declare const DEDICATED_WORKER_ROUTING: ModelRoutingConfig;
|
|
28
39
|
export declare const FIXED_MODEL_ROUTING: ModelRoutingConfig;
|
|
29
40
|
export declare const RECOMMENDED_LUNA_MODEL = "openai/gpt-5.6-luna";
|
|
30
|
-
|
|
31
|
-
|
|
41
|
+
/**
|
|
42
|
+
* Dispatch quality, not code output, is what the coordinator spends effort on, and one malformed
|
|
43
|
+
* dispatch discards an entire worker session, so the coordinator runs at the top of the cheap model's
|
|
44
|
+
* range where that whole session costs less than the work it protects. Evidence gathering is retrieval
|
|
45
|
+
* rather than reasoning, so the scout sits one tier lower where the cost curve is steepest per point.
|
|
46
|
+
*/
|
|
47
|
+
export declare const RECOMMENDED_COORDINATOR_VARIANT = "max";
|
|
48
|
+
export declare const RECOMMENDED_SCOUT_VARIANT = "high";
|
|
49
|
+
export declare const RECOMMENDED_LUNA_ROLE_VARIANTS: Readonly<{
|
|
50
|
+
readonly "dog-coordinator": "max";
|
|
51
|
+
readonly "dog-scout": "high";
|
|
52
|
+
}>;
|
|
53
|
+
export declare const RECOMMENDED_LUNA_ROLES: readonly string[];
|
|
32
54
|
/** Configurable MkII defaults. Project-local and global configuration may override these routes. */
|
|
33
55
|
export declare const RECOMMENDED_LUNA_ROUTING: ModelRoutingConfig;
|
|
34
56
|
/**
|
|
@@ -39,8 +61,12 @@ export declare const RECOMMENDED_LUNA_ROUTING: ModelRoutingConfig;
|
|
|
39
61
|
export declare const RECOMMENDED_CONSULTATION_MODEL = "anthropic/claude-opus-5";
|
|
40
62
|
export declare const RECOMMENDED_CONSULTATION_ROLES: readonly string[];
|
|
41
63
|
/** Review and advice carry the reasoning effort the worker target intentionally does not spend. */
|
|
42
|
-
export declare const
|
|
43
|
-
/**
|
|
64
|
+
export declare const CONSULTATION_FALLBACK_VARIANT = "xhigh";
|
|
65
|
+
/**
|
|
66
|
+
* The shipped consultation fallback. Review has to be able to reject work the worker just produced, so
|
|
67
|
+
* it stays on the stronger model even though the worker no longer defaults to it; a fallback equal to
|
|
68
|
+
* the worker target would review that work with exactly the capability that produced it.
|
|
69
|
+
*/
|
|
44
70
|
export declare const DEFAULT_CONSULTATION_FALLBACK_TARGET: ModelTarget;
|
|
45
71
|
/**
|
|
46
72
|
* Consultation prefers the strongest declared reasoning model. A host that relocated the dedicated
|
|
@@ -55,7 +81,7 @@ export declare const RECOMMENDED_CONSULTATION_ROUTING: ModelRoutingConfig;
|
|
|
55
81
|
/** Every configurable role route this build recommends before host configuration is applied. */
|
|
56
82
|
export declare function recommendedRoleRouting(fallbackTarget?: ModelTarget): ModelRoutingConfig;
|
|
57
83
|
export declare const RECOMMENDED_ROLE_ROUTING: ModelRoutingConfig;
|
|
58
|
-
export declare function
|
|
84
|
+
export declare function isDedicatedWorkerRole(role: string): boolean;
|
|
59
85
|
export declare function isFixedModelRole(role: string): boolean;
|
|
60
86
|
export interface CatalogModel {
|
|
61
87
|
readonly model: string;
|
|
@@ -1,12 +1,21 @@
|
|
|
1
1
|
import { CONSULTATION_ROLE_POLICY } from "../core/consultation.js";
|
|
2
|
-
export const DEDICATED_SOL_MODEL = "openai/gpt-5.6-sol";
|
|
3
2
|
/**
|
|
4
|
-
*
|
|
5
|
-
*
|
|
6
|
-
*
|
|
3
|
+
* The published DeepSWE cost curve settles the worker target: the cheap model at top reasoning effort
|
|
4
|
+
* solves more than the expensive model at mid effort while costing a fraction of it, so paying for the
|
|
5
|
+
* expensive model by default bought a lower solve rate. Worker effort therefore sits at the top of the
|
|
6
|
+
* cheap model's range, and review effort stays above it on a stronger model, which is what the
|
|
7
|
+
* mandatory source review is for.
|
|
7
8
|
*/
|
|
8
|
-
export const
|
|
9
|
-
export const
|
|
9
|
+
export const DEDICATED_WORKER_MODEL = "openai/gpt-5.6-luna";
|
|
10
|
+
export const DEDICATED_WORKER_VARIANT = "max";
|
|
11
|
+
/**
|
|
12
|
+
* The stronger, far more expensive worker target a host may still select deliberately. It is no longer
|
|
13
|
+
* a default route: it stays declared so an explicit dedicatedWorkerModel resolves against the catalog
|
|
14
|
+
* without extra host configuration.
|
|
15
|
+
*/
|
|
16
|
+
export const ESCALATION_WORKER_MODEL = "openai/gpt-5.6-sol";
|
|
17
|
+
export const ESCALATION_WORKER_VARIANT = "medium";
|
|
18
|
+
export const DEDICATED_WORKER_ROLES = [
|
|
10
19
|
"implementation",
|
|
11
20
|
"remediation",
|
|
12
21
|
"blocker-resolution",
|
|
@@ -17,34 +26,50 @@ export const DEDICATED_SOL_ROLES = [
|
|
|
17
26
|
export const DEFAULT_FREE_TIER_FALLBACK_MODELS = Object.freeze([
|
|
18
27
|
"opencode/deepseek-v4-flash-free",
|
|
19
28
|
]);
|
|
20
|
-
const
|
|
29
|
+
const dedicatedWorkerRoleSet = new Set(DEDICATED_WORKER_ROLES);
|
|
21
30
|
/** The dedicated worker target this build ships with when a host declares no target of its own. */
|
|
22
31
|
export const DEFAULT_DEDICATED_WORKER_TARGET = Object.freeze({
|
|
23
|
-
model:
|
|
24
|
-
variant:
|
|
32
|
+
model: DEDICATED_WORKER_MODEL,
|
|
33
|
+
variant: DEDICATED_WORKER_VARIANT,
|
|
34
|
+
});
|
|
35
|
+
/** The declared escalation target for a host that chooses to pay for the stronger worker model. */
|
|
36
|
+
export const ESCALATION_WORKER_TARGET = Object.freeze({
|
|
37
|
+
model: ESCALATION_WORKER_MODEL,
|
|
38
|
+
variant: ESCALATION_WORKER_VARIANT,
|
|
25
39
|
});
|
|
26
40
|
/**
|
|
27
41
|
* Fixed worker routes for one dedicated target. Which target is dedicated is a host decision, but
|
|
28
42
|
* every worker role resolves to that single target and never to a fallback.
|
|
29
43
|
*/
|
|
30
44
|
export function dedicatedWorkerRouting(target = DEFAULT_DEDICATED_WORKER_TARGET) {
|
|
31
|
-
return Object.freeze(Object.fromEntries(
|
|
45
|
+
return Object.freeze(Object.fromEntries(DEDICATED_WORKER_ROLES.map((role) => [role, Object.freeze({
|
|
32
46
|
preferred: Object.freeze(target.variant === undefined
|
|
33
47
|
? { model: target.model }
|
|
34
48
|
: { model: target.model, variant: target.variant }),
|
|
35
49
|
})])));
|
|
36
50
|
}
|
|
37
|
-
export const
|
|
38
|
-
export const FIXED_MODEL_ROUTING =
|
|
51
|
+
export const DEDICATED_WORKER_ROUTING = dedicatedWorkerRouting();
|
|
52
|
+
export const FIXED_MODEL_ROUTING = DEDICATED_WORKER_ROUTING;
|
|
39
53
|
const fixedModelRoleSet = new Set(Object.keys(FIXED_MODEL_ROUTING));
|
|
40
54
|
export const RECOMMENDED_LUNA_MODEL = "openai/gpt-5.6-luna";
|
|
41
|
-
|
|
42
|
-
|
|
55
|
+
/**
|
|
56
|
+
* Dispatch quality, not code output, is what the coordinator spends effort on, and one malformed
|
|
57
|
+
* dispatch discards an entire worker session, so the coordinator runs at the top of the cheap model's
|
|
58
|
+
* range where that whole session costs less than the work it protects. Evidence gathering is retrieval
|
|
59
|
+
* rather than reasoning, so the scout sits one tier lower where the cost curve is steepest per point.
|
|
60
|
+
*/
|
|
61
|
+
export const RECOMMENDED_COORDINATOR_VARIANT = "max";
|
|
62
|
+
export const RECOMMENDED_SCOUT_VARIANT = "high";
|
|
63
|
+
export const RECOMMENDED_LUNA_ROLE_VARIANTS = Object.freeze({
|
|
64
|
+
"dog-coordinator": RECOMMENDED_COORDINATOR_VARIANT,
|
|
65
|
+
"dog-scout": RECOMMENDED_SCOUT_VARIANT,
|
|
66
|
+
});
|
|
67
|
+
export const RECOMMENDED_LUNA_ROLES = Object.freeze(Object.keys(RECOMMENDED_LUNA_ROLE_VARIANTS));
|
|
43
68
|
/** Configurable MkII defaults. Project-local and global configuration may override these routes. */
|
|
44
|
-
export const RECOMMENDED_LUNA_ROUTING = Object.freeze(Object.fromEntries(
|
|
69
|
+
export const RECOMMENDED_LUNA_ROUTING = Object.freeze(Object.fromEntries(Object.entries(RECOMMENDED_LUNA_ROLE_VARIANTS).map(([role, variant]) => [role, Object.freeze({
|
|
45
70
|
preferred: Object.freeze({
|
|
46
71
|
model: RECOMMENDED_LUNA_MODEL,
|
|
47
|
-
variant
|
|
72
|
+
variant,
|
|
48
73
|
}),
|
|
49
74
|
})])));
|
|
50
75
|
/**
|
|
@@ -55,11 +80,15 @@ export const RECOMMENDED_LUNA_ROUTING = Object.freeze(Object.fromEntries(RECOMME
|
|
|
55
80
|
export const RECOMMENDED_CONSULTATION_MODEL = "anthropic/claude-opus-5";
|
|
56
81
|
export const RECOMMENDED_CONSULTATION_ROLES = Object.freeze(Object.values(CONSULTATION_ROLE_POLICY));
|
|
57
82
|
/** Review and advice carry the reasoning effort the worker target intentionally does not spend. */
|
|
58
|
-
export const
|
|
59
|
-
/**
|
|
83
|
+
export const CONSULTATION_FALLBACK_VARIANT = "xhigh";
|
|
84
|
+
/**
|
|
85
|
+
* The shipped consultation fallback. Review has to be able to reject work the worker just produced, so
|
|
86
|
+
* it stays on the stronger model even though the worker no longer defaults to it; a fallback equal to
|
|
87
|
+
* the worker target would review that work with exactly the capability that produced it.
|
|
88
|
+
*/
|
|
60
89
|
export const DEFAULT_CONSULTATION_FALLBACK_TARGET = Object.freeze({
|
|
61
|
-
model:
|
|
62
|
-
variant:
|
|
90
|
+
model: ESCALATION_WORKER_MODEL,
|
|
91
|
+
variant: CONSULTATION_FALLBACK_VARIANT,
|
|
63
92
|
});
|
|
64
93
|
function frozenTarget(target) {
|
|
65
94
|
return Object.freeze(target.variant === undefined
|
|
@@ -97,8 +126,8 @@ export function recommendedRoleRouting(fallbackTarget = DEFAULT_DEDICATED_WORKER
|
|
|
97
126
|
});
|
|
98
127
|
}
|
|
99
128
|
export const RECOMMENDED_ROLE_ROUTING = recommendedRoleRouting();
|
|
100
|
-
export function
|
|
101
|
-
return
|
|
129
|
+
export function isDedicatedWorkerRole(role) {
|
|
130
|
+
return dedicatedWorkerRoleSet.has(role);
|
|
102
131
|
}
|
|
103
132
|
export function isFixedModelRole(role) {
|
|
104
133
|
return fixedModelRoleSet.has(role);
|
|
@@ -107,12 +136,16 @@ export function isFixedModelRole(role) {
|
|
|
107
136
|
export const BUILT_IN_MODEL_CATALOG = Object.freeze({
|
|
108
137
|
global: Object.freeze([
|
|
109
138
|
Object.freeze({
|
|
110
|
-
model:
|
|
111
|
-
variants: Object.freeze([
|
|
139
|
+
model: DEDICATED_WORKER_MODEL,
|
|
140
|
+
variants: Object.freeze([
|
|
141
|
+
DEDICATED_WORKER_VARIANT,
|
|
142
|
+
RECOMMENDED_COORDINATOR_VARIANT,
|
|
143
|
+
RECOMMENDED_SCOUT_VARIANT,
|
|
144
|
+
].filter((variant, index, all) => all.indexOf(variant) === index)),
|
|
112
145
|
}),
|
|
113
146
|
Object.freeze({
|
|
114
|
-
model:
|
|
115
|
-
variants: Object.freeze([
|
|
147
|
+
model: ESCALATION_WORKER_MODEL,
|
|
148
|
+
variants: Object.freeze([ESCALATION_WORKER_VARIANT, CONSULTATION_FALLBACK_VARIANT]),
|
|
116
149
|
}),
|
|
117
150
|
]),
|
|
118
151
|
});
|