pi-prompt-template-model 0.9.1 → 0.9.3

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/CHANGELOG.md CHANGED
@@ -2,6 +2,16 @@
2
2
 
3
3
  ## [Unreleased]
4
4
 
5
+ ## [0.9.3] - 2026-04-28
6
+
7
+ ### Fixed
8
+ - Delegated prompt templates now discover `pi-subagents` installs from project-local Pi npm paths and sibling npm package paths instead of the legacy `subagent` extension path, fixing #1. Thanks @hschne for the report.
9
+
10
+ ## [0.9.2] - 2026-04-28
11
+
12
+ ### Fixed
13
+ - Prompt templates now accept provider-qualified model IDs that contain additional slashes, such as `openrouter/openai/gpt-5.4`, across prompt loading, model selection, compare lineups, and `<if-model>` conditionals.
14
+
5
15
  ## [0.9.1] - 2026-04-26
6
16
 
7
17
  ### Fixed
package/README.md CHANGED
@@ -795,4 +795,3 @@ $@
795
795
  - In chains, model-less steps inherit the chain-start model snapshot, not the previous step's model. This is intentional for deterministic behavior.
796
796
  - Delegated `subagent` prompts require [pi-subagents](https://github.com/nicobailon/pi-subagents/).
797
797
  - `run-prompt` must be explicitly enabled with `/prompt-tool on`.
798
- rompt-tool on`.
@@ -13,7 +13,7 @@ bestOfN:
13
13
  - model: openai-codex/gpt-5.4-mini:high
14
14
  count: 2
15
15
  reviewers:
16
- # Reviewers use the base `reviewer` agent from `~/.pi/agent/extensions/subagent/agents/reviewer.md`.
16
+ # Reviewers use the base `reviewer` agent from pi-subagents.
17
17
  # These slots can override its default model, and they get a generated compare task built from
18
18
  # the original request, successful worker outputs/worktree summaries, and these slot instructions.
19
19
  # count works the same way here: it runs the same reviewer slot multiple times in parallel.
@@ -68,7 +68,8 @@ function getModelCandidates(modelSpec: string, registry: Pick<RegistryLike, "fin
68
68
  if (slashIndex !== -1) {
69
69
  const provider = modelSpec.slice(0, slashIndex);
70
70
  const modelId = modelSpec.slice(slashIndex + 1);
71
- if (!provider || !modelId || modelId.includes("/")) return [];
71
+ if (!provider || !modelId) return [];
72
+ if (modelId.split("/").some((segment) => segment.length === 0)) return [];
72
73
  const model = registry.find(provider, modelId);
73
74
  return model ? [model] : [];
74
75
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-prompt-template-model",
3
- "version": "0.9.1",
3
+ "version": "0.9.3",
4
4
  "type": "module",
5
5
  "description": "Prompt template model selector extension for pi coding agent",
6
6
  "author": "Nico Bailon",
package/prompt-loader.ts CHANGED
@@ -150,10 +150,13 @@ function normalizeStringField(
150
150
  function isValidModelSelectionSpec(spec: string): boolean {
151
151
  if (!spec || spec.includes("*") || /\s/.test(spec)) return false;
152
152
 
153
- const segments = spec.split("/");
154
- if (segments.length === 1) return true;
155
- if (segments.length !== 2) return false;
156
- return segments[0].length > 0 && segments[1].length > 0;
153
+ const slashIndex = spec.indexOf("/");
154
+ if (slashIndex === -1) return true;
155
+ if (slashIndex === 0) return false;
156
+ const modelId = spec.slice(slashIndex + 1);
157
+ if (modelId.length === 0) return false;
158
+ if (modelId.split("/").some((segment) => segment.length === 0)) return false;
159
+ return true;
157
160
  }
158
161
 
159
162
  function normalizeFrontmatterRecord(
@@ -1,5 +1,4 @@
1
1
  import { existsSync } from "node:fs";
2
- import { homedir } from "node:os";
3
2
  import { dirname, join, resolve } from "node:path";
4
3
  import { fileURLToPath, pathToFileURL } from "node:url";
5
4
 
@@ -115,10 +114,9 @@ const delegatedLiveState = new Map<string, DelegatedSubagentLiveState>();
115
114
  function runtimeCandidates(cwd: string): string[] {
116
115
  const fromEnv = process.env.PI_SUBAGENT_RUNTIME_ROOT?.trim();
117
116
  if (fromEnv) return [resolve(fromEnv)];
118
- const localSibling = resolve(dirname(fileURLToPath(import.meta.url)), "..", "subagent");
117
+ const localSibling = resolve(dirname(fileURLToPath(import.meta.url)), "..", "pi-subagents");
119
118
  return [
120
- resolve(cwd, ".pi", "agent", "extensions", "subagent"),
121
- join(homedir(), ".pi", "agent", "extensions", "subagent"),
119
+ resolve(cwd, ".pi", "npm", "node_modules", "pi-subagents"),
122
120
  localSibling,
123
121
  ];
124
122
  }
@@ -217,7 +215,7 @@ export async function ensureSubagentRuntime(cwd: string): Promise<SubagentRuntim
217
215
  const root = findSubagentRoot(cwd);
218
216
  if (!root) {
219
217
  throw new Error(
220
- "Delegated prompt execution requires the subagent extension runtime at ~/.pi/agent/extensions/subagent.",
218
+ "Delegated prompt execution requires pi-subagents. Install it with `pi install npm:pi-subagents` or set PI_SUBAGENT_RUNTIME_ROOT.",
221
219
  );
222
220
  }
223
221
 
@@ -47,10 +47,13 @@ function isValidSpec(spec: string): boolean {
47
47
  return segments.length === 2 && segments[0].length > 0 && segments[1] === "*";
48
48
  }
49
49
 
50
- const segments = spec.split("/");
51
- if (segments.length === 1) return true;
52
- if (segments.length !== 2) return false;
53
- return segments[0].length > 0 && segments[1].length > 0;
50
+ const slashIndex = spec.indexOf("/");
51
+ if (slashIndex === -1) return true;
52
+ if (slashIndex === 0) return false;
53
+ const modelId = spec.slice(slashIndex + 1);
54
+ if (modelId.length === 0) return false;
55
+ if (modelId.split("/").some((segment) => segment.length === 0)) return false;
56
+ return true;
54
57
  }
55
58
 
56
59
  function matchSpec(spec: string, model: ResolvedModelRef): boolean {