@dougbots/pi-agents 0.1.0 → 0.1.1

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
@@ -69,6 +69,19 @@ PI_AGENT=jockey pi -c
69
69
 
70
70
  When `avenor_spawn(agent: "reviewer", backend: "pi")` is called, avenor spawns `pi --mode rpc` with `PI_AGENT=reviewer`. The agents extension applies the full profile (model, systemPrompt, tools, permissions) automatically.
71
71
 
72
+ Pass `model` as well to override only the profile's default model while retaining its prompt, tools, and permissions:
73
+
74
+ ```text
75
+ avenor_spawn(
76
+ agent: "reviewer",
77
+ model: "anthropic/claude-opus-4",
78
+ backend: "pi",
79
+ prompt: "Review the outage recovery changes",
80
+ )
81
+ ```
82
+
83
+ Explicit `--model` selection takes precedence over the profile default. Avenor forwards its `model` option to the pi subprocess as `--model`, so no agent config changes are needed for a one-off override.
84
+
72
85
  Requires [avenor](https://github.com/sdougbrown/avenor) with the pi backend (v0.3.3+). Model resolution falls back to `~/.pi/agent/agents.json` when the agent is not found in opencode config.
73
86
 
74
87
  ## Profile vs. agent
@@ -1,8 +1,8 @@
1
1
  import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
2
2
  import { getAgentDir } from "@earendil-works/pi-coding-agent";
3
- import { Type } from "typebox";
4
3
  import { readFileSync, existsSync } from "node:fs";
5
4
  import { join } from "node:path";
5
+ import { findCliModelOverride, parseModelSpecifier } from "./model-selection.ts";
6
6
 
7
7
  /* ------------------------------------------------------------------ */
8
8
  /* Types */
@@ -99,6 +99,10 @@ function checkBashPermission(
99
99
 
100
100
  export default async function (pi: ExtensionAPI) {
101
101
  const agents = loadAgentsConfig();
102
+ // Built-in flags are not exposed through pi.getFlag(). Avenor forwards its
103
+ // model option to pi as --model, so argv is the extension-level signal that
104
+ // the caller's model should take precedence over the profile default.
105
+ const cliModelOverride = findCliModelOverride(process.argv.slice(2));
102
106
  let activeAgent: { name: string; profile: AgentProfile } | null = null;
103
107
 
104
108
  /* ---- Apply agent profile to the current session ---- */
@@ -109,14 +113,23 @@ export default async function (pi: ExtensionAPI) {
109
113
  return false;
110
114
  }
111
115
 
112
- // Resolve model
113
- const [provider, modelId] = profile.model.split("/");
114
- const model = ctx.modelRegistry.find(provider, modelId);
115
- if (!model) {
116
- ctx.ui.notify(`Model "${profile.model}" not found in registry`, "error");
117
- return false;
116
+ // Explicit CLI selection wins over the profile default. This preserves
117
+ // `avenor_spawn(agent: ..., model: ..., backend: "pi")` overrides because
118
+ // Avenor forwards model to the pi subprocess as --model.
119
+ if (!cliModelOverride) {
120
+ const modelSpecifier = parseModelSpecifier(profile.model);
121
+ if (!modelSpecifier) {
122
+ ctx.ui.notify(`Invalid model "${profile.model}"; expected provider/model-id`, "error");
123
+ return false;
124
+ }
125
+
126
+ const model = ctx.modelRegistry.find(modelSpecifier.provider, modelSpecifier.modelId);
127
+ if (!model) {
128
+ ctx.ui.notify(`Model "${profile.model}" not found in registry`, "error");
129
+ return false;
130
+ }
131
+ await pi.setModel(model);
118
132
  }
119
- await pi.setModel(model);
120
133
 
121
134
  // Thinking level
122
135
  if (profile.thinkingLevel) {
@@ -0,0 +1,29 @@
1
+ export interface ModelSpecifier {
2
+ provider: string;
3
+ modelId: string;
4
+ }
5
+
6
+ /**
7
+ * Return the model explicitly supplied to pi, if any.
8
+ *
9
+ * Pi consumes --model itself, so extension flags cannot expose this value via
10
+ * pi.getFlag(). Inspecting argv lets agent profiles respect normal CLI
11
+ * precedence, including models forwarded by Avenor.
12
+ */
13
+ export function findCliModelOverride(argv: readonly string[]): string | undefined {
14
+ for (let index = 0; index < argv.length - 1; index += 1) {
15
+ if (argv[index] === "--model") return argv[index + 1];
16
+ }
17
+ return undefined;
18
+ }
19
+
20
+ /** Split provider/model-id at the first slash so model IDs may contain slashes. */
21
+ export function parseModelSpecifier(specifier: string): ModelSpecifier | undefined {
22
+ const separator = specifier.indexOf("/");
23
+ if (separator <= 0 || separator === specifier.length - 1) return undefined;
24
+
25
+ return {
26
+ provider: specifier.slice(0, separator),
27
+ modelId: specifier.slice(separator + 1),
28
+ };
29
+ }
package/package.json CHANGED
@@ -1,7 +1,10 @@
1
1
  {
2
2
  "name": "@dougbots/pi-agents",
3
- "version": "0.1.0",
3
+ "version": "0.1.1",
4
4
  "description": "Agent profiles for pi — preconfigured model, system prompt, tool restrictions, and permission gates",
5
+ "scripts": {
6
+ "test": "node --experimental-strip-types --test tests/*.test.mts"
7
+ },
5
8
  "keywords": ["pi-package", "pi", "pi-extension", "agents"],
6
9
  "license": "MIT",
7
10
  "repository": {