@henryqw/pi-task-models 0.2.0 → 0.4.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/CONTEXT.md CHANGED
@@ -5,7 +5,7 @@ Pi Task Models stores shared task profiles and task-to-profile assignments for H
5
5
  ## Language
6
6
 
7
7
  **Task Profile**:
8
- Named shared route set (`fast`, `balanced`, or `frontier`) with a required primary route and optional fallback route.
8
+ Named shared route set (`fast`, `balanced`, `frontier`, or `fav`) with a required primary route and optional fallback route (`fav` has no fallback).
9
9
  _Avoid_: package-owned model picker, per-extension model catalog
10
10
 
11
11
  **Task Route**:
package/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # `@henryqw/pi-task-models`
2
2
 
3
- Shared `fast`, `balanced`, and `frontier` model profiles for HenryQW Pi extensions.
3
+ Shared `fast`, `balanced`, `frontier`, and `fav` model profiles for HenryQW Pi extensions.
4
4
 
5
5
  ## Install
6
6
 
@@ -13,6 +13,8 @@ pi install npm:@henryqw/pi-task-models
13
13
  | Package | Why |
14
14
  | --- | --- |
15
15
  | `@henryqw/pi-auto-compact` | Consumer. Compaction defaults to the `fast` profile. |
16
+ | `@henryqw/pi-auto-dag` | Consumer. Implement uses `balanced`; review uses `frontier`. |
17
+ | `@henryqw/pi-herdr-btw` | Consumer. Side-thread launch uses the `fast` profile. |
16
18
  | `@henryqw/pi-herdr-rename` | Consumer. Rename uses the `fast` profile. |
17
19
  | `@henryqw/pi-subagent` | Consumer. Delegation defaults to `balanced`; caller may override it. |
18
20
  | `@henryqw/pi-multi-codex` | Improves. Numbered Codex slots dedupe to one route. |
@@ -25,7 +27,7 @@ pi install npm:@henryqw/pi-task-models
25
27
 
26
28
  Selecting a profile sets primary model, primary thinking, optional fallback model, then fallback thinking. One completed flow writes the whole profile. Selecting a task changes its assignment.
27
29
 
28
- Menus and resolution use the current session's `ctx.scopedModels`, including pinned thinking. Empty scope uses Pi's full available model registry. Numbered Codex account aliases are deduplicated. Fallback choices exclude the selected primary. Hidden task assignments stay stored when a package is disabled.
30
+ Menus and resolution use the current session's `ctx.scopedModels`, including pinned thinking. Empty scope uses Pi's full available model registry. Numbered Codex account aliases are deduplicated. Fallback choices exclude the selected primary. Hidden task assignments stay stored when a package is disabled. BTW selects the first authenticated viable route before pane launch.
29
31
 
30
32
  Package also exports config and route-resolution helpers for consumers.
31
33
 
@@ -45,12 +47,18 @@ Package also exports config and route-resolution helpers for consumers.
45
47
  },
46
48
  "frontier": {
47
49
  "primary": { "model": "openai-codex/gpt-frontier", "thinkingLevel": "max" }
50
+ },
51
+ "fav": {
52
+ "primary": { "model": "openai-codex/gpt-favorite", "thinkingLevel": "high" }
48
53
  }
49
54
  },
50
55
  "tasks": {
56
+ "pi-herdr-btw/btw": "fast",
51
57
  "pi-herdr-rename/rename": "fast",
52
58
  "pi-auto-compact/autoCompact": "fast",
53
- "pi-subagent/delegateTask": "balanced"
59
+ "pi-subagent/delegateTask": "balanced",
60
+ "pi-auto-dag/implement": "balanced",
61
+ "pi-auto-dag/review": "frontier"
54
62
  }
55
63
  }
56
64
  ```
@@ -59,6 +67,8 @@ Each configured profile needs one primary model and thinking level. Fallback is
59
67
 
60
68
  Reads are strict. Malformed or unknown values fail visibly and never rewrite the file. Only explicit `/task-models` actions write config.
61
69
 
70
+ Consumers can call `resolveConfiguredTaskRoute(ctx, taskId)` to read strict shared config, choose usable primary or fallback route, and fail with `/task-models` guidance when assignment, profile, or route is unavailable.
71
+
62
72
  ## Remove
63
73
 
64
74
  ```bash
package/dist/index.d.ts CHANGED
@@ -1,12 +1,15 @@
1
1
  import { type ExtensionAPI, type ExtensionContext } from "@earendil-works/pi-coding-agent";
2
- export declare const PROFILE_NAMES: readonly ["fast", "balanced", "frontier"];
2
+ export declare const PROFILE_NAMES: readonly ["fast", "balanced", "frontier", "fav"];
3
3
  export type ProfileName = (typeof PROFILE_NAMES)[number];
4
4
  export declare const THINKING_LEVELS: readonly ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
5
5
  export type ThinkingLevel = (typeof THINKING_LEVELS)[number];
6
6
  export declare const DEFAULT_TASK_ASSIGNMENTS: {
7
+ readonly "pi-herdr-btw/btw": "fast";
7
8
  readonly "pi-herdr-rename/rename": "fast";
8
9
  readonly "pi-auto-compact/autoCompact": "fast";
9
10
  readonly "pi-subagent/delegateTask": "balanced";
11
+ readonly "pi-auto-dag/implement": "balanced";
12
+ readonly "pi-auto-dag/review": "frontier";
10
13
  };
11
14
  export type TaskModelRoute = {
12
15
  model: string;
@@ -46,6 +49,7 @@ export declare function supportedThinkingLevels(model: AvailableModel): Thinking
46
49
  export declare function availableTaskModels(ctx: ExtensionContext): AvailableModel[];
47
50
  export declare function taskThinkingLevels(ctx: ExtensionContext, model: AvailableModel): ThinkingLevel[];
48
51
  export declare function resolveTaskModelRoute(ctx: ExtensionContext, route: TaskModelRoute): ResolvedTaskRoute | undefined;
52
+ export declare function resolveConfiguredTaskRoute(ctx: ExtensionContext, task: string, agentDir?: string): ResolvedTaskRoute;
49
53
  export declare function orderedProfileRoutes(profile: TaskModelProfile): TaskModelRoute[];
50
54
  export declare function activeTaskPackages(pi: Pick<ExtensionAPI, "getCommands" | "getAllTools">, tasks?: Readonly<Record<string, ProfileName>>): ActiveTaskPackage[];
51
55
  export declare function createTaskModelsExtension(pi: ExtensionAPI, options?: {
package/dist/index.js CHANGED
@@ -2,12 +2,15 @@ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
2
2
  import { dirname, join } from "node:path";
3
3
  import { getSupportedThinkingLevels } from "@earendil-works/pi-ai";
4
4
  import { getAgentDir } from "@earendil-works/pi-coding-agent";
5
- export const PROFILE_NAMES = ["fast", "balanced", "frontier"];
5
+ export const PROFILE_NAMES = ["fast", "balanced", "frontier", "fav"];
6
6
  export const THINKING_LEVELS = ["off", "minimal", "low", "medium", "high", "xhigh", "max"];
7
7
  export const DEFAULT_TASK_ASSIGNMENTS = {
8
+ "pi-herdr-btw/btw": "fast",
8
9
  "pi-herdr-rename/rename": "fast",
9
10
  "pi-auto-compact/autoCompact": "fast",
10
11
  "pi-subagent/delegateTask": "balanced",
12
+ "pi-auto-dag/implement": "balanced",
13
+ "pi-auto-dag/review": "frontier",
11
14
  };
12
15
  const CODEX_ALIAS = /^openai-codex-(?:[2-9]|[1-9]\d+)$/;
13
16
  const CONFIG_FILE = "pi-task-models.json";
@@ -80,6 +83,8 @@ function parseConfig(value) {
80
83
  if (!isTaskProfile(profile))
81
84
  throw new Error(`${name} profile is invalid.`);
82
85
  const profileName = name;
86
+ if (profileName === "fav" && profile.fallback)
87
+ throw new Error("fav profile has no fallback.");
83
88
  profiles[profileName] = {
84
89
  primary: normalizeRoute(profile.primary),
85
90
  ...(profile.fallback ? { fallback: normalizeRoute(profile.fallback) } : {}),
@@ -111,6 +116,8 @@ export function readTaskModelsConfig(agentDir = getAgentDir()) {
111
116
  }
112
117
  }
113
118
  export function writeTaskModelsConfig(config, agentDir = getAgentDir()) {
119
+ if (config.profiles.fav?.fallback)
120
+ throw new Error("fav profile has no fallback.");
114
121
  const file = configPath(agentDir);
115
122
  mkdirSync(dirname(file), { recursive: true });
116
123
  writeFileSync(file, `${JSON.stringify(normalizeConfig(config), null, 2)}\n`);
@@ -190,6 +197,27 @@ export function resolveTaskModelRoute(ctx, route) {
190
197
  ? { model, thinkingLevel: route.thinkingLevel }
191
198
  : undefined;
192
199
  }
200
+ export function resolveConfiguredTaskRoute(ctx, task, agentDir = getAgentDir()) {
201
+ let config;
202
+ try {
203
+ config = readTaskModelsConfig(agentDir);
204
+ }
205
+ catch {
206
+ throw new Error("Couldn't read task model config. Run /task-models.");
207
+ }
208
+ const profileName = config.tasks[task];
209
+ if (!profileName)
210
+ throw new Error(`Task ${task} is not assigned to a profile. Run /task-models.`);
211
+ const profile = config.profiles[profileName];
212
+ if (!profile)
213
+ throw new Error(`Task ${task} profile ${profileName} is not configured. Run /task-models.`);
214
+ for (const route of orderedProfileRoutes(profile)) {
215
+ const resolved = resolveTaskModelRoute(ctx, route);
216
+ if (resolved)
217
+ return resolved;
218
+ }
219
+ throw new Error(`Task ${task} profile ${profileName} has no available route. Run /task-models.`);
220
+ }
193
221
  export function orderedProfileRoutes(profile) {
194
222
  return profile.fallback ? [profile.primary, profile.fallback] : [profile.primary];
195
223
  }
@@ -280,19 +308,24 @@ export function createTaskModelsExtension(pi, options) {
280
308
  const primary = await selectRoute(ctx, `Profile ${profile} primary`, models);
281
309
  if (!primary)
282
310
  return;
283
- const fallbackModels = models.filter((model) => canonicalModelReference(model) !== primary.model);
284
- const fallbackModel = await ctx.ui.select(`Profile ${profile} fallback`, [
285
- "None",
286
- ...fallbackModels.map((model) => modelReference(model)),
287
- ]);
288
- if (!fallbackModel)
289
- return;
290
- const fallback = fallbackModel === "None"
291
- ? undefined
292
- : await selectThinkingLevel(ctx, `Profile ${profile} fallback`, fallbackModels, fallbackModel);
293
- if (fallbackModel !== "None" && !fallback)
294
- return;
295
- config.profiles[profile] = { primary, ...(fallback ? { fallback } : {}) };
311
+ if (profile === "fav") {
312
+ config.profiles[profile] = { primary };
313
+ }
314
+ else {
315
+ const fallbackModels = models.filter((model) => canonicalModelReference(model) !== primary.model);
316
+ const fallbackModel = await ctx.ui.select(`Profile ${profile} fallback`, [
317
+ "None",
318
+ ...fallbackModels.map((model) => modelReference(model)),
319
+ ]);
320
+ if (!fallbackModel)
321
+ return;
322
+ const fallback = fallbackModel === "None"
323
+ ? undefined
324
+ : await selectThinkingLevel(ctx, `Profile ${profile} fallback`, fallbackModels, fallbackModel);
325
+ if (fallbackModel !== "None" && !fallback)
326
+ return;
327
+ config.profiles[profile] = { primary, ...(fallback ? { fallback } : {}) };
328
+ }
296
329
  if (!save())
297
330
  return;
298
331
  ctx.ui.notify(`${profile} profile saved.`, "info");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@henryqw/pi-task-models",
3
- "version": "0.2.0",
3
+ "version": "0.4.0",
4
4
  "description": "Shared task model profiles and routing for HenryQW Pi extensions.",
5
5
  "keywords": [
6
6
  "pi-package",