dsh-autotier 0.1.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/AGENTS.md +93 -0
- package/CHANGELOG.md +85 -0
- package/LICENSE +201 -0
- package/README.es.md +247 -0
- package/README.hi.md +241 -0
- package/README.md +245 -0
- package/README.pt.md +246 -0
- package/README.zh.md +221 -0
- package/SECURITY.md +55 -0
- package/THIRD_PARTY_NOTICES.md +63 -0
- package/cordis.patch.yml +125 -0
- package/docs/preset-row.md +61 -0
- package/docs/supporting-lanes.md +45 -0
- package/lib/index.js +2848 -0
- package/lib/types/command.d.ts +17 -0
- package/lib/types/command.d.ts.map +1 -0
- package/lib/types/config.d.ts +94 -0
- package/lib/types/config.d.ts.map +1 -0
- package/lib/types/guard-rules.d.ts +97 -0
- package/lib/types/guard-rules.d.ts.map +1 -0
- package/lib/types/guard.d.ts +70 -0
- package/lib/types/guard.d.ts.map +1 -0
- package/lib/types/index.d.ts +60 -0
- package/lib/types/index.d.ts.map +1 -0
- package/lib/types/intent.d.ts +179 -0
- package/lib/types/intent.d.ts.map +1 -0
- package/lib/types/judge.d.ts +50 -0
- package/lib/types/judge.d.ts.map +1 -0
- package/lib/types/policy.d.ts +109 -0
- package/lib/types/policy.d.ts.map +1 -0
- package/lib/types/routing.d.ts +135 -0
- package/lib/types/routing.d.ts.map +1 -0
- package/lib/types/schema.d.ts +134 -0
- package/lib/types/schema.d.ts.map +1 -0
- package/lib/types/service.d.ts +67 -0
- package/lib/types/service.d.ts.map +1 -0
- package/lib/types/state.d.ts +46 -0
- package/lib/types/state.d.ts.map +1 -0
- package/lib/types/tiers.d.ts +103 -0
- package/lib/types/tiers.d.ts.map +1 -0
- package/lib/types/tools.d.ts +26 -0
- package/lib/types/tools.d.ts.map +1 -0
- package/lib/types/types.d.ts +96 -0
- package/lib/types/types.d.ts.map +1 -0
- package/package.json +179 -0
- package/src/command.ts +73 -0
- package/src/config.ts +358 -0
- package/src/guard-rules.ts +303 -0
- package/src/guard.ts +285 -0
- package/src/index.ts +149 -0
- package/src/intent.ts +484 -0
- package/src/judge.ts +150 -0
- package/src/policy.ts +246 -0
- package/src/routing.ts +575 -0
- package/src/schema.ts +295 -0
- package/src/service.ts +131 -0
- package/src/state.ts +134 -0
- package/src/tiers.ts +212 -0
- package/src/tools.ts +128 -0
- package/src/types.ts +120 -0
package/cordis.patch.yml
ADDED
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
# dsh-autotier: automatic model-tier routing for DeepSeek Harness.
|
|
2
|
+
#
|
|
3
|
+
# One user instruction enters, one tier decision comes out. Complex intent is
|
|
4
|
+
# planned on the strong tier and implemented on the cheap tier; simple intent is
|
|
5
|
+
# designed and implemented on the cheap tier directly. High-risk tool calls are
|
|
6
|
+
# denied while the cheap tier executes, and repeated failures escalate to the
|
|
7
|
+
# strong tier with a TTL fallback. Everything below is a Schemastery-validated
|
|
8
|
+
# config field; an invalid value fails loudly at load time.
|
|
9
|
+
- insert:
|
|
10
|
+
- id: autotier
|
|
11
|
+
name: dsh-autotier
|
|
12
|
+
# `sessions` is plural: the host service is `ctx.sessions`, and a
|
|
13
|
+
# non-existent name here would leave this plugin PENDING forever.
|
|
14
|
+
inject: [settings, llm, tools, commands, sessions]
|
|
15
|
+
config:
|
|
16
|
+
# ---- tiers ----------------------------------------------------------
|
|
17
|
+
tiers:
|
|
18
|
+
# The planning/review tier. `effort` is the adapter-owned vocabulary
|
|
19
|
+
# off | low | high | max; `medium` does not exist and would fail every
|
|
20
|
+
# request with UNSUPPORTED_REASONING_EFFORT.
|
|
21
|
+
strong:
|
|
22
|
+
provider: deepseek-official
|
|
23
|
+
model: deepseek-v4-pro
|
|
24
|
+
effort: high
|
|
25
|
+
# false = this tier's effort overrides the session's own.
|
|
26
|
+
followSession: false
|
|
27
|
+
# Ordered fallback landings (provider/model) used when the tier is
|
|
28
|
+
# unavailable. The chain is deduplicated and must not name the tier
|
|
29
|
+
# itself; validation refuses a self-referential chain at load time.
|
|
30
|
+
fallback: []
|
|
31
|
+
# The implementation tier.
|
|
32
|
+
cheap:
|
|
33
|
+
provider: deepseek-official
|
|
34
|
+
model: deepseek-v4-flash
|
|
35
|
+
effort: low
|
|
36
|
+
# true = inherit the session's effort, so an explicit user choice
|
|
37
|
+
# still wins inside the cheap tier.
|
|
38
|
+
followSession: true
|
|
39
|
+
fallback: []
|
|
40
|
+
# Image-capable landing: a turn carrying images is routed here,
|
|
41
|
+
# because a text-only model silently substitutes image placeholders.
|
|
42
|
+
vision:
|
|
43
|
+
provider: deepseek-official
|
|
44
|
+
model: deepseek-v4-flash-vision-exp
|
|
45
|
+
# ---- intent classification -----------------------------------------
|
|
46
|
+
intent:
|
|
47
|
+
# Confidence at or above which the deterministic rule layer decides
|
|
48
|
+
# without calling the judge model.
|
|
49
|
+
ruleThreshold: 0.7
|
|
50
|
+
# Attempt-first middle band: scores in [tauLow, ruleThreshold) start on
|
|
51
|
+
# the cheap tier and escalate on a signal. Disabled until the
|
|
52
|
+
# calibration corpus lands.
|
|
53
|
+
attemptBand:
|
|
54
|
+
enabled: false
|
|
55
|
+
tauLow: 0.45
|
|
56
|
+
# Application-side double threshold that stops tier flapping between
|
|
57
|
+
# turns; the decision threshold above is unchanged.
|
|
58
|
+
hysteresis:
|
|
59
|
+
toStrong: 0.8
|
|
60
|
+
toCheap: 0.6
|
|
61
|
+
# Declarative rule table. Rules are evaluated by descending priority;
|
|
62
|
+
# the first match wins, and a guard denial always outranks a rule.
|
|
63
|
+
# `when.patterns` are regular expressions matched against the user
|
|
64
|
+
# text, `when.tools` against the tool name, `when.cwd` against the
|
|
65
|
+
# workspace path (empty = no constraint). `tier` is cheap | strong.
|
|
66
|
+
# Example entry:
|
|
67
|
+
# - id: plan-first
|
|
68
|
+
# when:
|
|
69
|
+
# patterns: ['^plan\\b', 'architecture']
|
|
70
|
+
# tools: []
|
|
71
|
+
# cwd: ''
|
|
72
|
+
# tier: strong
|
|
73
|
+
# priority: 10
|
|
74
|
+
rules: []
|
|
75
|
+
# The low-confidence judge: a cheap model classifies intent only.
|
|
76
|
+
judge:
|
|
77
|
+
enabled: true
|
|
78
|
+
# Empty = pick the first catalog model whose id contains "flash".
|
|
79
|
+
model: ''
|
|
80
|
+
temperature: 0
|
|
81
|
+
maxTokens: 16
|
|
82
|
+
cooldownMs: 30000
|
|
83
|
+
timeoutMs: 2000
|
|
84
|
+
# Consecutive judge failures after which the current turn skips the
|
|
85
|
+
# judge instead of paying its timeout on every request.
|
|
86
|
+
unavailableSkip: 2
|
|
87
|
+
# Per-scenario switches: coding, review, planning, retrieval, batch,
|
|
88
|
+
# daily, longText, multimodal.
|
|
89
|
+
scenarios:
|
|
90
|
+
coding: true
|
|
91
|
+
review: true
|
|
92
|
+
planning: true
|
|
93
|
+
retrieval: true
|
|
94
|
+
batch: true
|
|
95
|
+
daily: true
|
|
96
|
+
longText: true
|
|
97
|
+
multimodal: true
|
|
98
|
+
# Ambiguity arbitration: cost-first | quality-first | balanced.
|
|
99
|
+
costMode: balanced
|
|
100
|
+
# ---- high-risk guard ------------------------------------------------
|
|
101
|
+
guard:
|
|
102
|
+
enabled: true
|
|
103
|
+
# Tiers whose execution the guard protects (cheap only).
|
|
104
|
+
tiers: [cheap]
|
|
105
|
+
# Commands, tools or path prefixes that never trip the guard.
|
|
106
|
+
whitelist: []
|
|
107
|
+
# Self-modification surfaces that force strong-tier review.
|
|
108
|
+
protectedPaths: ['.dsh', 'AGENTS.md', 'package.json', '.github/workflows']
|
|
109
|
+
# Relationship with dsh-defend: auto audits coexistence, none stays
|
|
110
|
+
# silent. The guard never weakens dsh-defend.
|
|
111
|
+
interopDefend: auto
|
|
112
|
+
# ---- failure escalation ---------------------------------------------
|
|
113
|
+
escalation:
|
|
114
|
+
# Failures within windowMs that reach this count escalate the tier.
|
|
115
|
+
threshold: 2
|
|
116
|
+
windowMs: 60000
|
|
117
|
+
# How long an escalation stays in effect before falling back.
|
|
118
|
+
ttlMs: 180000
|
|
119
|
+
# TTL used after a fallback landing was taken.
|
|
120
|
+
fallbackTtlMs: 300000
|
|
121
|
+
# Count same-signature recurrences instead of every failure.
|
|
122
|
+
signature: true
|
|
123
|
+
# auto | strong | cheap | delegated | off. `delegated` means the session
|
|
124
|
+
# carries an explicit model selection that autotier must not fight.
|
|
125
|
+
routingMode: auto
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Optional preset prompt section
|
|
2
|
+
|
|
3
|
+
`dsh-autotier` is a **host-plane** plugin: the profile row applies to every
|
|
4
|
+
session and routing works with no preset change. This page is for users who want
|
|
5
|
+
the model to *know* which tier it is running on.
|
|
6
|
+
|
|
7
|
+
## Why this is optional
|
|
8
|
+
|
|
9
|
+
The host row is registered on the root scope, so it covers every agent,
|
|
10
|
+
including subagents, without touching any preset. A preset section only adds
|
|
11
|
+
model-facing text — it never changes routing, and the plugin works correctly
|
|
12
|
+
when the section is absent (`/tier status` reports `prompt-section: absent`).
|
|
13
|
+
|
|
14
|
+
This is deliberate: shipping a preset with the package would freeze a snapshot
|
|
15
|
+
of the host's `standard` preset and drift on every harness release.
|
|
16
|
+
|
|
17
|
+
## The row
|
|
18
|
+
|
|
19
|
+
Add one row to **your own** agent preset's `cordis.patch.yml` (the file that
|
|
20
|
+
declares the preset's plugin rows):
|
|
21
|
+
|
|
22
|
+
```yaml
|
|
23
|
+
- insert:
|
|
24
|
+
- id: autotier-prompt
|
|
25
|
+
name: '@deepseek-ai/dsh-system-prompt'
|
|
26
|
+
config:
|
|
27
|
+
sections:
|
|
28
|
+
- name: autotier
|
|
29
|
+
text: |-
|
|
30
|
+
You are running under dsh-autotier routing. The active tier is
|
|
31
|
+
chosen per turn: complex work is planned on the strong tier and
|
|
32
|
+
implemented on the cheap tier; simple work runs on the cheap tier
|
|
33
|
+
throughout. If a tool call is denied by the high-risk guard, do not
|
|
34
|
+
retry it — report what you were about to do and let the tier
|
|
35
|
+
escalate.
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
The exact `sections` shape is owned by the host `system-prompt` package; if your
|
|
39
|
+
harness version expects a different key, follow the error the Loader prints —
|
|
40
|
+
the plugin itself does not depend on this row.
|
|
41
|
+
|
|
42
|
+
## Verifying it took effect
|
|
43
|
+
|
|
44
|
+
`/tier status` prints the live routing state; the optional section itself is
|
|
45
|
+
visible in the assembled system prompt, not in `/tier` output. If you rename the
|
|
46
|
+
section, keep the name `autotier` so you can find it in the prompt.
|
|
47
|
+
|
|
48
|
+
## Per-preset isolation
|
|
49
|
+
|
|
50
|
+
If you want a preset to opt out of routing entirely, compose the plugin inside
|
|
51
|
+
an `isolate` realm instead of the root scope:
|
|
52
|
+
|
|
53
|
+
```yaml
|
|
54
|
+
- isolate:
|
|
55
|
+
autotier: true
|
|
56
|
+
insert:
|
|
57
|
+
- id: autotier
|
|
58
|
+
name: dsh-autotier
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
A realm-isolated row only affects the sessions of that preset.
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# Supporting lanes: compaction and title generation
|
|
2
|
+
|
|
3
|
+
`dsh-autotier` routes **conversation requests** — the ones the agent loop
|
|
4
|
+
assembles for a turn. Two other host seams make their own model calls and are
|
|
5
|
+
deliberately left alone:
|
|
6
|
+
|
|
7
|
+
| Lane | Host seam | Owner package |
|
|
8
|
+
|---|---|---|
|
|
9
|
+
| Context compaction | its own model settings | `@deepseek-ai/dsh-compaction` |
|
|
10
|
+
| Session titles | its own model settings | `@deepseek-ai/dsh-session-title-llm` |
|
|
11
|
+
|
|
12
|
+
Routing them from here would be wrong twice over: they are not turn-scoped, so a
|
|
13
|
+
per-turn tier decision does not apply, and rewriting their calls would surprise a
|
|
14
|
+
user who configured them explicitly.
|
|
15
|
+
|
|
16
|
+
## Aligning their cost profile
|
|
17
|
+
|
|
18
|
+
If you want the whole harness to sit on the cheap model, point each lane's own
|
|
19
|
+
configuration at the same landing as `tiers.cheap`:
|
|
20
|
+
|
|
21
|
+
```yaml
|
|
22
|
+
- insert:
|
|
23
|
+
- id: compaction
|
|
24
|
+
name: '@deepseek-ai/dsh-compaction'
|
|
25
|
+
config:
|
|
26
|
+
provider: deepseek-official
|
|
27
|
+
model: deepseek-v4-flash
|
|
28
|
+
reasoningEffort: low
|
|
29
|
+
|
|
30
|
+
- id: session-title-llm
|
|
31
|
+
name: '@deepseek-ai/dsh-session-title-first-prompt-llm'
|
|
32
|
+
config:
|
|
33
|
+
provider: deepseek-official
|
|
34
|
+
model: deepseek-v4-flash
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
The key names above are the host packages' own; check the installed version's
|
|
38
|
+
schema if a row is rejected. `dsh-autotier` never writes these rows.
|
|
39
|
+
|
|
40
|
+
## Judge calls
|
|
41
|
+
|
|
42
|
+
The low-confidence judge uses `intent.judge.model` (or the first catalog model
|
|
43
|
+
whose id contains `flash`) through the ordinary `ctx.llm` path. It is a separate,
|
|
44
|
+
short request with its own `maxTokens` and `timeoutMs`, so it never inherits a
|
|
45
|
+
tier's landing — pin it to a cheap model on purpose.
|