@henryqw/pi-task-models 4.0.0 → 4.0.2

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 CHANGED
@@ -1,11 +1,13 @@
1
1
  # `@henryqw/pi-task-models`
2
2
 
3
- Choose shared `fast`, `balanced`, `frontier`, and `fav` model profiles for consumer-owned Model Tasks.
3
+ Choose shared model and thinking routes for extension tasks named `fast`, `balanced`, `frontier`, and `fav`.
4
+
5
+ ![Pi showing task model profiles and task routes](./example.png)
4
6
 
5
7
  ## Why
6
8
 
7
- - **Created for**: Remove duplicated model pickers and catalogs that extensions once owned separately.
8
- - **Advantage**: One shared profile control plane keeps routes consistent while each consumer owns its task identity, intent, and default profile.
9
+ - **Created for**: Pi users who want one place to route model work started by several extensions.
10
+ - **Advantage**: Reuse profile choices while each extension keeps ownership of its task and default.
9
11
 
10
12
  ## Install
11
13
 
@@ -13,26 +15,32 @@ Choose shared `fast`, `balanced`, `frontier`, and `fav` model profiles for consu
13
15
  pi install npm:@henryqw/pi-task-models
14
16
  ```
15
17
 
18
+ Run `/task-models` after installation. Configure each profile that your installed consumers require.
19
+
16
20
  ## With
17
21
 
18
22
  | Package | Why |
19
23
  | --- | --- |
20
- | `@henryqw/pi-auto-compact` | Consumer. Its local compaction task defaults to `fast`. |
21
- | `@henryqw/pi-herdr-btw` | Consumer. Its local side-thread task defaults to `fast`. |
22
- | `@henryqw/pi-herdr-rename` | Consumer. Its local rename task defaults to `fast`. |
23
- | `@henryqw/pi-memory` | Consumer. Its local candidate-review task defaults to `balanced`. |
24
- | `@henryqw/pi-multi-codex` | Improves. Numbered Codex slots dedupe to one route. |
25
- | `@henryqw/pi-subagent` | Consumer. Its local delegation task defaults to `fast`; callers can declare their own task. |
24
+ | [`@henryqw/pi-auto-compact`](https://pi.henry.wang/extensions/pi-auto-compact) | Consumer. Its local compaction task defaults to `fast`. |
25
+ | [`@henryqw/pi-herdr-btw`](https://pi.henry.wang/extensions/pi-herdr-btw) | Consumer. Its local side-thread task defaults to `fast`. |
26
+ | [`@henryqw/pi-herdr-rename`](https://pi.henry.wang/extensions/pi-herdr-rename) | Consumer. Its local rename task defaults to `fast`. |
27
+ | [`@henryqw/pi-memory`](https://pi.henry.wang/extensions/pi-memory) | Consumer. Its local candidate-review task defaults to `balanced`. |
28
+ | [`@henryqw/pi-multi-codex`](https://pi.henry.wang/extensions/pi-multi-codex) | Improves. Numbered Codex slots dedupe to one route. |
29
+ | [`@henryqw/pi-prompt-creator`](https://pi.henry.wang/extensions/pi-prompt-creator) | Consumer. Its local prompt-drafting task defaults to `fast`. |
30
+ | [`@henryqw/pi-subagent`](https://pi.henry.wang/extensions/pi-subagent) | Consumer. Its local delegation task defaults to `fast`; callers can declare their own task. |
26
31
 
27
32
  ## Use
28
33
 
29
- Use `/task-models` to select a profile or override an active task's default profile.
34
+ Run `/task-models` to complete the first setup:
30
35
 
31
- ### Profile selection
36
+ 1. Select `fast`.
37
+ 2. Choose a primary model from Pi's effective registry, then choose its thinking level.
38
+ 3. Choose a different fallback model and thinking level, or choose `None`.
39
+ 4. Reopen `/task-models`. The `fast` row now shows the saved route instead of `not configured`.
32
40
 
33
- Selecting a profile sets its primary model, primary thinking, optional fallback model, and fallback thinking. One completed flow writes the whole profile.
41
+ Repeat these steps for `balanced`, `frontier`, or `fav` when a consumer needs them. The `fav` profile has no fallback.
34
42
 
35
- Selecting an active task sets its explicit override. Choosing its consumer-declared default removes that override.
43
+ Select an active task to override its declared profile. Choosing that task's declared default removes the override.
36
44
 
37
45
  ### Active declarations
38
46
 
@@ -40,6 +48,8 @@ Consumers register declarations at extension load. When `/task-models` opens, th
40
48
 
41
49
  The control plane lists each active task's effective profile. Hidden explicit assignments stay stored when a consumer is disabled.
42
50
 
51
+ ![Task routing from consumer declaration to route or error](./docs/task-routing-architecture.svg)
52
+
43
53
  ### Scoped models, aliases, and fallback
44
54
 
45
55
  Menus and resolution use the current session's `ctx.scopedModels`, including pinned thinking. An empty scope uses Pi's full available model registry. Numbered Codex account aliases are deduplicated.
@@ -50,21 +60,23 @@ Fallback choices exclude the selected primary. BTW selects the first authenticat
50
60
 
51
61
  The shared JSON file is at `~/.pi/agent/config/pi-task-models/config.json`. Consumers use `loadTaskModelsConfig()` for validated values. They never read or write this file. Only explicit `/task-models` actions save it.
52
62
 
63
+ The following JSON shows structure only. Every model ID is a placeholder and must not be copied.
64
+
53
65
  ```json
54
66
  {
55
67
  "profiles": {
56
68
  "fast": {
57
- "primary": { "model": "openai-codex/gpt-fast", "thinkingLevel": "low" },
58
- "fallback": { "model": "other-provider/fast-model", "thinkingLevel": "low" }
69
+ "primary": { "model": "<provider>/<fast-model-from-Pi>", "thinkingLevel": "low" },
70
+ "fallback": { "model": "<provider>/<fallback-model-from-Pi>", "thinkingLevel": "low" }
59
71
  },
60
72
  "balanced": {
61
- "primary": { "model": "openai-codex/gpt-balanced", "thinkingLevel": "high" }
73
+ "primary": { "model": "<provider>/<balanced-model-from-Pi>", "thinkingLevel": "high" }
62
74
  },
63
75
  "frontier": {
64
- "primary": { "model": "openai-codex/gpt-frontier", "thinkingLevel": "max" }
76
+ "primary": { "model": "<provider>/<frontier-model-from-Pi>", "thinkingLevel": "max" }
65
77
  },
66
78
  "fav": {
67
- "primary": { "model": "openai-codex/gpt-favorite", "thinkingLevel": "high" }
79
+ "primary": { "model": "<provider>/<favorite-model-from-Pi>", "thinkingLevel": "high" }
68
80
  }
69
81
  },
70
82
  "tasks": {
@@ -73,6 +85,8 @@ The shared JSON file is at `~/.pi/agent/config/pi-task-models/config.json`. Cons
73
85
  }
74
86
  ```
75
87
 
88
+ Use exact model IDs offered by `/task-models`. Pi's registry, not this example, defines available models.
89
+
76
90
  | Field | Required | Possible values | Default |
77
91
  | --- | --- | --- | --- |
78
92
  | `profiles` | No | Object keyed by `fast`, `balanced`, `frontier`, `fav`; unknown profile names are rejected | `{}` (no profiles configured) |
@@ -0,0 +1,180 @@
1
+ <!DOCTYPE html>
2
+ <html lang="en">
3
+ <head>
4
+ <meta charset="UTF-8">
5
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
6
+ <title>Task model routing architecture</title>
7
+ <link href="https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&family=Geist:wght@400;500;600&family=Geist+Mono:wght@400;500;600&family=Noto+Sans+KR:wght@400;500;600&family=Noto+Serif+KR:wght@400&display=swap" rel="stylesheet">
8
+ <style>
9
+ *, *::before, *::after { box-sizing: border-box; }
10
+ html, body { margin: 0; min-height: 100%; }
11
+ body {
12
+ background: #f0eee9;
13
+ color: #101828;
14
+ font-family: 'Geist', system-ui, sans-serif;
15
+ padding: 40px;
16
+ }
17
+ main { margin: 0 auto; max-width: 1280px; }
18
+ .eyebrow {
19
+ color: #4c5665;
20
+ font: 500 8px 'Geist Mono', ui-monospace, monospace;
21
+ letter-spacing: .16em;
22
+ margin: 0 0 8px;
23
+ text-transform: uppercase;
24
+ }
25
+ h1 {
26
+ font: 400 28px 'Instrument Serif', serif;
27
+ margin: 0 0 24px;
28
+ }
29
+ svg { display: block; height: auto; width: 100%; }
30
+ </style>
31
+ </head>
32
+ <body>
33
+ <main>
34
+ <p class="eyebrow">Architecture · Task routing</p>
35
+ <h1>How a consumer gets a viable task model route</h1>
36
+
37
+ <svg width="1280" height="720" viewBox="0 0 1280 720" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="task-routing-architecture-title task-routing-architecture-desc">
38
+ <title id="task-routing-architecture-title">Task model routing architecture</title>
39
+ <desc id="task-routing-architecture-desc">Architecture diagram showing an active consumer declaring a ModelTask to the shared task-models control plane, which selects an explicit override or declared default profile and resolves primary then fallback routes; Pi’s effective model registry determines availability and canonical IDs, scoped models make pinned thinking authoritative, and an empty scope falls back to Pi’s full model registry; viable routes return to the consumer and failures remain visible as TaskRouteError.</desc>
40
+ <defs>
41
+ <style>
42
+ .zone { fill: #e6e4de; stroke: rgba(16,24,40,.141); stroke-width: 1; }
43
+ .zone-label { fill: #6a7282; font: 500 8px 'Geist Mono', monospace; letter-spacing: .16em; }
44
+ .node-mask { fill: #f0eee9; }
45
+ .node { fill: #fff; stroke: #101828; stroke-width: 1; }
46
+ .node-input { fill: rgba(76,86,101,.10); stroke: #6a7282; stroke-width: 1; }
47
+ .node-store { fill: rgba(16,24,40,.05); stroke: #4c5665; stroke-width: 1; }
48
+ .node-external { fill: rgba(16,24,40,.03); stroke: rgba(16,24,40,.30); stroke-width: 1; }
49
+ .node-focal { fill: rgba(29,78,216,.08); stroke: #1d4ed8; stroke-width: 1.2; }
50
+ .node-error { fill: rgba(16,24,40,.02); stroke: rgba(16,24,40,.42); stroke-width: 1; stroke-dasharray: 4 4; }
51
+ .tag { fill: none; stroke: rgba(16,24,40,.34); stroke-width: .8; }
52
+ .tag-focal { fill: none; stroke: rgba(29,78,216,.55); stroke-width: .8; }
53
+ .tag-text { fill: #6a7282; font: 500 8px 'Geist Mono', monospace; letter-spacing: .08em; text-anchor: middle; }
54
+ .tag-text-focal { fill: #1d4ed8; font: 500 8px 'Geist Mono', monospace; letter-spacing: .08em; text-anchor: middle; }
55
+ .name { fill: #101828; font: 600 14px 'Geist', sans-serif; text-anchor: middle; }
56
+ .sub { fill: #4c5665; font: 400 10px 'Geist Mono', monospace; text-anchor: middle; }
57
+ .edge { fill: none; stroke: #4c5665; stroke-width: 1.2; marker-end: url(#arrow); }
58
+ .edge-route { fill: none; stroke: #1d4ed8; stroke-width: 1.2; marker-end: url(#arrow-accent); }
59
+ .edge-error { fill: none; stroke: #6a7282; stroke-width: 1; stroke-dasharray: 5 4; marker-end: url(#arrow); }
60
+ .label-mask { fill: #f0eee9; }
61
+ .label { fill: #4c5665; font: 500 10px 'Geist Mono', monospace; letter-spacing: .04em; text-anchor: middle; }
62
+ .key { fill: #101828; font: 400 14px 'Geist', sans-serif; }
63
+ .key-note { fill: #4c5665; font: 500 10px 'Geist Mono', monospace; letter-spacing: .04em; text-anchor: end; }
64
+ </style>
65
+ <marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
66
+ <polygon points="0 0,8 3,0 6" fill="#4c5665"/>
67
+ </marker>
68
+ <marker id="arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
69
+ <polygon points="0 0,8 3,0 6" fill="#1d4ed8"/>
70
+ </marker>
71
+ <marker id="arrow-link" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
72
+ <polygon points="0 0,8 3,0 6" fill="#1d4ed8"/>
73
+ </marker>
74
+ </defs>
75
+
76
+ <rect width="1280" height="720" fill="#f0eee9"/>
77
+
78
+ <!-- Shared control-plane boundary -->
79
+ <rect class="zone" x="280" y="96" width="672" height="456" rx="8"/>
80
+ <rect x="292" y="104" width="256" height="16" rx="2" fill="#f0eee9"/>
81
+ <text class="zone-label" x="304" y="116">SHARED TASK-MODELS CONTROL PLANE</text>
82
+
83
+ <!-- Connectors are drawn before nodes -->
84
+ <line class="edge" x1="264" y1="224" x2="304" y2="224"/>
85
+ <line class="edge" x1="496" y1="224" x2="528" y2="224"/>
86
+ <line class="edge" x1="720" y1="224" x2="752" y2="224"/>
87
+ <line class="edge-route" x1="928" y1="224" x2="968" y2="224"/>
88
+ <line class="edge" x1="400" y1="400" x2="400" y2="288"/>
89
+ <path class="edge" d="M152 536 V552 Q152 560 160 560 H808 Q816 560 816 552 V288"/>
90
+ <path class="edge-error" d="M864 288 V336 Q864 344 872 344 H1096 Q1104 344 1104 352 V400"/>
91
+
92
+ <!-- Connector labels -->
93
+ <rect class="label-mask" x="408" y="332" width="56" height="12" rx="2"/>
94
+ <text class="label" x="436" y="340">CONFIG</text>
95
+ <rect class="label-mask" x="568" y="540" width="128" height="12" rx="2"/>
96
+ <text class="label" x="632" y="548">REGISTRY RULES</text>
97
+ <rect class="label-mask" x="952" y="324" width="72" height="12" rx="2"/>
98
+ <text class="label" x="988" y="332">NO VIABLE</text>
99
+
100
+ <!-- Opaque masks -->
101
+ <rect class="node-mask" x="40" y="160" width="224" height="128" rx="6"/>
102
+ <rect class="node-mask" x="304" y="160" width="192" height="128" rx="6"/>
103
+ <rect class="node-mask" x="528" y="160" width="192" height="128" rx="6"/>
104
+ <rect class="node-mask" x="752" y="160" width="176" height="128" rx="6"/>
105
+ <rect class="node-mask" x="968" y="160" width="272" height="128" rx="6"/>
106
+ <rect class="node-mask" x="40" y="376" width="224" height="160" rx="6"/>
107
+ <rect class="node-mask" x="304" y="400" width="192" height="120" rx="6"/>
108
+ <rect class="node-mask" x="968" y="400" width="272" height="120" rx="6"/>
109
+
110
+ <!-- Active consumer and declaration -->
111
+ <rect class="node-input" x="40" y="160" width="224" height="128" rx="6"/>
112
+ <rect class="tag" x="52" y="172" width="72" height="16" rx="2"/>
113
+ <text class="tag-text" x="88" y="184">CONSUMER</text>
114
+ <text class="name" x="152" y="224">Active consumer extension</text>
115
+ <text class="sub" x="152" y="248">OWNS MODELTASK DECLARATION</text>
116
+ <text class="sub" x="152" y="264">registerModelTask(ModelTask)</text>
117
+
118
+ <!-- Control-plane stages -->
119
+ <rect class="node" x="304" y="160" width="192" height="128" rx="6"/>
120
+ <rect class="tag" x="316" y="172" width="56" height="16" rx="2"/>
121
+ <text class="tag-text" x="344" y="184">SELECT</text>
122
+ <text class="name" x="400" y="224">Effective task profile</text>
123
+ <text class="sub" x="400" y="248">EXPLICIT TASK OVERRIDE</text>
124
+ <text class="sub" x="400" y="264">OR DECLARED DEFAULT</text>
125
+
126
+ <rect class="node" x="528" y="160" width="192" height="128" rx="6"/>
127
+ <rect class="tag" x="540" y="172" width="56" height="16" rx="2"/>
128
+ <text class="tag-text" x="568" y="184">PROFILE</text>
129
+ <text class="name" x="624" y="224">Selected profile</text>
130
+ <text class="sub" x="624" y="248">PRIMARY + FALLBACK MODEL</text>
131
+ <text class="sub" x="624" y="264">THINKING LEVEL FOR EACH</text>
132
+
133
+ <rect class="node-focal" x="752" y="160" width="176" height="128" rx="6"/>
134
+ <rect class="tag-focal" x="764" y="172" width="56" height="16" rx="2"/>
135
+ <text class="tag-text-focal" x="792" y="184">RESOLVE</text>
136
+ <text class="name" x="840" y="224">Route resolver</text>
137
+ <text class="sub" x="840" y="248">PRIMARY FIRST</text>
138
+ <text class="sub" x="840" y="264">FALLBACK SECOND</text>
139
+
140
+ <!-- Consumer result -->
141
+ <rect class="node-input" x="968" y="160" width="272" height="128" rx="6"/>
142
+ <rect class="tag" x="980" y="172" width="56" height="16" rx="2"/>
143
+ <text class="tag-text" x="1008" y="184">RETURN</text>
144
+ <text class="name" x="1104" y="224">Consumer receives routes</text>
145
+ <text class="sub" x="1104" y="248">VIABLE PRIMARY → FALLBACK</text>
146
+ <text class="sub" x="1104" y="264">CANONICAL MODEL + THINKING</text>
147
+
148
+ <!-- Authorities and visible failure -->
149
+ <rect class="node-external" x="40" y="376" width="224" height="160" rx="6"/>
150
+ <rect class="tag" x="52" y="388" width="32" height="16" rx="2"/>
151
+ <text class="tag-text" x="68" y="400">PI</text>
152
+ <text class="name" x="152" y="432">Effective model registry</text>
153
+ <text class="sub" x="152" y="456">SCOPED MODELS</text>
154
+ <text class="sub" x="152" y="472">PINNED THINKING IS AUTHORITATIVE</text>
155
+ <text class="sub" x="152" y="488">EMPTY SCOPE → FULL PI REGISTRY</text>
156
+ <text class="sub" x="152" y="504">AVAILABILITY + CANONICAL IDS</text>
157
+
158
+ <rect class="node-store" x="304" y="400" width="192" height="120" rx="6"/>
159
+ <rect class="tag" x="316" y="412" width="56" height="16" rx="2"/>
160
+ <text class="tag-text" x="344" y="424">CONFIG</text>
161
+ <text class="name" x="400" y="448">Task-models config</text>
162
+ <text class="sub" x="400" y="472">PROFILES + TASK OVERRIDES</text>
163
+ <text class="sub" x="400" y="488">ONLY TASK-MODELS WRITES</text>
164
+
165
+ <rect class="node-error" x="968" y="400" width="272" height="120" rx="6"/>
166
+ <rect class="tag" x="980" y="412" width="48" height="16" rx="2"/>
167
+ <text class="tag-text" x="1004" y="424">ERROR</text>
168
+ <text class="name" x="1104" y="448">Visible TaskRouteError</text>
169
+ <text class="sub" x="1104" y="472">CONFIG · PROFILE · NO-ROUTE</text>
170
+ <text class="sub" x="1104" y="488">RUN /TASK-MODELS</text>
171
+
172
+ <!-- Bottom reading key -->
173
+ <line x1="40" y1="624" x2="1240" y2="624" stroke="rgba(16,24,40,.141)" stroke-width=".8"/>
174
+ <text class="zone-label" x="40" y="656">OWNERSHIP</text>
175
+ <text class="key" x="144" y="656">Only task-models writes config. Consumers use its API.</text>
176
+ <text class="key-note" x="1240" y="656">PRIMARY → FALLBACK · FAILURE STAYS VISIBLE</text>
177
+ </svg>
178
+ </main>
179
+ </body>
180
+ </html>
@@ -0,0 +1,143 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <svg width="1280" height="720" viewBox="0 0 1280 720" xmlns="http://www.w3.org/2000/svg" role="img" aria-labelledby="task-routing-architecture-title task-routing-architecture-desc">
3
+ <title id="task-routing-architecture-title">Task model routing architecture</title>
4
+ <desc id="task-routing-architecture-desc">Architecture diagram showing an active consumer declaring a ModelTask to the shared task-models control plane, which selects an explicit override or declared default profile and resolves primary then fallback routes; Pi’s effective model registry determines availability and canonical IDs, scoped models make pinned thinking authoritative, and an empty scope falls back to Pi’s full model registry; viable routes return to the consumer and failures remain visible as TaskRouteError.</desc>
5
+ <defs>
6
+ <style>
7
+ @import url("https://fonts.googleapis.com/css2?family=Instrument+Serif:ital@0;1&amp;family=Geist:wght@400;500;600&amp;family=Geist+Mono:wght@400;500;600&amp;family=Noto+Sans+KR:wght@400;500;600&amp;family=Noto+Serif+KR:wght@400&amp;display=swap");
8
+ .zone { fill: #e6e4de; stroke: rgba(16,24,40,.141); stroke-width: 1; }
9
+ .zone-label { fill: #6a7282; font: 500 8px 'Geist Mono', monospace; letter-spacing: .16em; }
10
+ .node-mask { fill: #f0eee9; }
11
+ .node { fill: #fff; stroke: #101828; stroke-width: 1; }
12
+ .node-input { fill: rgba(76,86,101,.10); stroke: #6a7282; stroke-width: 1; }
13
+ .node-store { fill: rgba(16,24,40,.05); stroke: #4c5665; stroke-width: 1; }
14
+ .node-external { fill: rgba(16,24,40,.03); stroke: rgba(16,24,40,.30); stroke-width: 1; }
15
+ .node-focal { fill: rgba(29,78,216,.08); stroke: #1d4ed8; stroke-width: 1.2; }
16
+ .node-error { fill: rgba(16,24,40,.02); stroke: rgba(16,24,40,.42); stroke-width: 1; stroke-dasharray: 4 4; }
17
+ .tag { fill: none; stroke: rgba(16,24,40,.34); stroke-width: .8; }
18
+ .tag-focal { fill: none; stroke: rgba(29,78,216,.55); stroke-width: .8; }
19
+ .tag-text { fill: #6a7282; font: 500 8px 'Geist Mono', monospace; letter-spacing: .08em; text-anchor: middle; }
20
+ .tag-text-focal { fill: #1d4ed8; font: 500 8px 'Geist Mono', monospace; letter-spacing: .08em; text-anchor: middle; }
21
+ .name { fill: #101828; font: 600 14px 'Geist', sans-serif; text-anchor: middle; }
22
+ .sub { fill: #4c5665; font: 400 10px 'Geist Mono', monospace; text-anchor: middle; }
23
+ .edge { fill: none; stroke: #4c5665; stroke-width: 1.2; marker-end: url(#arrow); }
24
+ .edge-route { fill: none; stroke: #1d4ed8; stroke-width: 1.2; marker-end: url(#arrow-accent); }
25
+ .edge-error { fill: none; stroke: #6a7282; stroke-width: 1; stroke-dasharray: 5 4; marker-end: url(#arrow); }
26
+ .label-mask { fill: #f0eee9; }
27
+ .label { fill: #4c5665; font: 500 10px 'Geist Mono', monospace; letter-spacing: .04em; text-anchor: middle; }
28
+ .key { fill: #101828; font: 400 14px 'Geist', sans-serif; }
29
+ .key-note { fill: #4c5665; font: 500 10px 'Geist Mono', monospace; letter-spacing: .04em; text-anchor: end; }
30
+ </style>
31
+ <marker id="arrow" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
32
+ <polygon points="0 0,8 3,0 6" fill="#4c5665"/>
33
+ </marker>
34
+ <marker id="arrow-accent" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
35
+ <polygon points="0 0,8 3,0 6" fill="#1d4ed8"/>
36
+ </marker>
37
+ <marker id="arrow-link" markerWidth="8" markerHeight="6" refX="7" refY="3" orient="auto">
38
+ <polygon points="0 0,8 3,0 6" fill="#1d4ed8"/>
39
+ </marker>
40
+ </defs>
41
+
42
+ <rect width="1280" height="720" fill="#f0eee9"/>
43
+
44
+ <!-- Shared control-plane boundary -->
45
+ <rect class="zone" x="280" y="96" width="672" height="456" rx="8"/>
46
+ <rect x="292" y="104" width="256" height="16" rx="2" fill="#f0eee9"/>
47
+ <text class="zone-label" x="304" y="116">SHARED TASK-MODELS CONTROL PLANE</text>
48
+
49
+ <!-- Connectors are drawn before nodes -->
50
+ <line class="edge" x1="264" y1="224" x2="304" y2="224"/>
51
+ <line class="edge" x1="496" y1="224" x2="528" y2="224"/>
52
+ <line class="edge" x1="720" y1="224" x2="752" y2="224"/>
53
+ <line class="edge-route" x1="928" y1="224" x2="968" y2="224"/>
54
+ <line class="edge" x1="400" y1="400" x2="400" y2="288"/>
55
+ <path class="edge" d="M152 536 V552 Q152 560 160 560 H808 Q816 560 816 552 V288"/>
56
+ <path class="edge-error" d="M864 288 V336 Q864 344 872 344 H1096 Q1104 344 1104 352 V400"/>
57
+
58
+ <!-- Connector labels -->
59
+ <rect class="label-mask" x="408" y="332" width="56" height="12" rx="2"/>
60
+ <text class="label" x="436" y="340">CONFIG</text>
61
+ <rect class="label-mask" x="568" y="540" width="128" height="12" rx="2"/>
62
+ <text class="label" x="632" y="548">REGISTRY RULES</text>
63
+ <rect class="label-mask" x="952" y="324" width="72" height="12" rx="2"/>
64
+ <text class="label" x="988" y="332">NO VIABLE</text>
65
+
66
+ <!-- Opaque masks -->
67
+ <rect class="node-mask" x="40" y="160" width="224" height="128" rx="6"/>
68
+ <rect class="node-mask" x="304" y="160" width="192" height="128" rx="6"/>
69
+ <rect class="node-mask" x="528" y="160" width="192" height="128" rx="6"/>
70
+ <rect class="node-mask" x="752" y="160" width="176" height="128" rx="6"/>
71
+ <rect class="node-mask" x="968" y="160" width="272" height="128" rx="6"/>
72
+ <rect class="node-mask" x="40" y="376" width="224" height="160" rx="6"/>
73
+ <rect class="node-mask" x="304" y="400" width="192" height="120" rx="6"/>
74
+ <rect class="node-mask" x="968" y="400" width="272" height="120" rx="6"/>
75
+
76
+ <!-- Active consumer and declaration -->
77
+ <rect class="node-input" x="40" y="160" width="224" height="128" rx="6"/>
78
+ <rect class="tag" x="52" y="172" width="72" height="16" rx="2"/>
79
+ <text class="tag-text" x="88" y="184">CONSUMER</text>
80
+ <text class="name" x="152" y="224">Active consumer extension</text>
81
+ <text class="sub" x="152" y="248">OWNS MODELTASK DECLARATION</text>
82
+ <text class="sub" x="152" y="264">registerModelTask(ModelTask)</text>
83
+
84
+ <!-- Control-plane stages -->
85
+ <rect class="node" x="304" y="160" width="192" height="128" rx="6"/>
86
+ <rect class="tag" x="316" y="172" width="56" height="16" rx="2"/>
87
+ <text class="tag-text" x="344" y="184">SELECT</text>
88
+ <text class="name" x="400" y="224">Effective task profile</text>
89
+ <text class="sub" x="400" y="248">EXPLICIT TASK OVERRIDE</text>
90
+ <text class="sub" x="400" y="264">OR DECLARED DEFAULT</text>
91
+
92
+ <rect class="node" x="528" y="160" width="192" height="128" rx="6"/>
93
+ <rect class="tag" x="540" y="172" width="56" height="16" rx="2"/>
94
+ <text class="tag-text" x="568" y="184">PROFILE</text>
95
+ <text class="name" x="624" y="224">Selected profile</text>
96
+ <text class="sub" x="624" y="248">PRIMARY + FALLBACK MODEL</text>
97
+ <text class="sub" x="624" y="264">THINKING LEVEL FOR EACH</text>
98
+
99
+ <rect class="node-focal" x="752" y="160" width="176" height="128" rx="6"/>
100
+ <rect class="tag-focal" x="764" y="172" width="56" height="16" rx="2"/>
101
+ <text class="tag-text-focal" x="792" y="184">RESOLVE</text>
102
+ <text class="name" x="840" y="224">Route resolver</text>
103
+ <text class="sub" x="840" y="248">PRIMARY FIRST</text>
104
+ <text class="sub" x="840" y="264">FALLBACK SECOND</text>
105
+
106
+ <!-- Consumer result -->
107
+ <rect class="node-input" x="968" y="160" width="272" height="128" rx="6"/>
108
+ <rect class="tag" x="980" y="172" width="56" height="16" rx="2"/>
109
+ <text class="tag-text" x="1008" y="184">RETURN</text>
110
+ <text class="name" x="1104" y="224">Consumer receives routes</text>
111
+ <text class="sub" x="1104" y="248">VIABLE PRIMARY → FALLBACK</text>
112
+ <text class="sub" x="1104" y="264">CANONICAL MODEL + THINKING</text>
113
+
114
+ <!-- Authorities and visible failure -->
115
+ <rect class="node-external" x="40" y="376" width="224" height="160" rx="6"/>
116
+ <rect class="tag" x="52" y="388" width="32" height="16" rx="2"/>
117
+ <text class="tag-text" x="68" y="400">PI</text>
118
+ <text class="name" x="152" y="432">Effective model registry</text>
119
+ <text class="sub" x="152" y="456">SCOPED MODELS</text>
120
+ <text class="sub" x="152" y="472">PINNED THINKING IS AUTHORITATIVE</text>
121
+ <text class="sub" x="152" y="488">EMPTY SCOPE → FULL PI REGISTRY</text>
122
+ <text class="sub" x="152" y="504">AVAILABILITY + CANONICAL IDS</text>
123
+
124
+ <rect class="node-store" x="304" y="400" width="192" height="120" rx="6"/>
125
+ <rect class="tag" x="316" y="412" width="56" height="16" rx="2"/>
126
+ <text class="tag-text" x="344" y="424">CONFIG</text>
127
+ <text class="name" x="400" y="448">Task-models config</text>
128
+ <text class="sub" x="400" y="472">PROFILES + TASK OVERRIDES</text>
129
+ <text class="sub" x="400" y="488">ONLY TASK-MODELS WRITES</text>
130
+
131
+ <rect class="node-error" x="968" y="400" width="272" height="120" rx="6"/>
132
+ <rect class="tag" x="980" y="412" width="48" height="16" rx="2"/>
133
+ <text class="tag-text" x="1004" y="424">ERROR</text>
134
+ <text class="name" x="1104" y="448">Visible TaskRouteError</text>
135
+ <text class="sub" x="1104" y="472">CONFIG · PROFILE · NO-ROUTE</text>
136
+ <text class="sub" x="1104" y="488">RUN /TASK-MODELS</text>
137
+
138
+ <!-- Bottom reading key -->
139
+ <line x1="40" y1="624" x2="1240" y2="624" stroke="rgba(16,24,40,.141)" stroke-width=".8"/>
140
+ <text class="zone-label" x="40" y="656">OWNERSHIP</text>
141
+ <text class="key" x="144" y="656">Only task-models writes config. Consumers use its API.</text>
142
+ <text class="key-note" x="1240" y="656">PRIMARY → FALLBACK · FAILURE STAYS VISIBLE</text>
143
+ </svg>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@henryqw/pi-task-models",
3
- "version": "4.0.0",
3
+ "version": "4.0.2",
4
4
  "description": "Shared task model profiles and routing for HenryQW Pi extensions.",
5
5
  "keywords": [
6
6
  "pi-package",
@@ -18,7 +18,8 @@
18
18
  "dist",
19
19
  "extensions",
20
20
  "README.md",
21
- "CONTEXT.md"
21
+ "CONTEXT.md",
22
+ "docs"
22
23
  ],
23
24
  "types": "./dist/index.d.ts",
24
25
  "exports": {
@@ -40,11 +41,11 @@
40
41
  },
41
42
  "repository": {
42
43
  "type": "git",
43
- "url": "git+https://github.com/HenryQW/pi-packages.git",
44
- "directory": "packages/pi-task-models"
44
+ "url": "git+https://github.com/HenryQW/pi-harness.git",
45
+ "directory": "extensions/pi-task-models"
45
46
  },
46
47
  "bugs": {
47
- "url": "https://github.com/HenryQW/pi-packages/issues"
48
+ "url": "https://github.com/HenryQW/pi-harness/issues"
48
49
  },
49
50
  "publishConfig": {
50
51
  "access": "public"
@@ -52,7 +53,8 @@
52
53
  "pi": {
53
54
  "extensions": [
54
55
  "./extensions/task-models.ts"
55
- ]
56
+ ],
57
+ "image": "https://raw.githubusercontent.com/HenryQW/pi-harness/main/extensions/pi-task-models/example.png"
56
58
  },
57
59
  "dependencies": {
58
60
  "@henryqw/pi-config-store": "^0.1.0"