@dougbots/pi-agents 0.2.0 → 0.3.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/README.md CHANGED
@@ -76,8 +76,14 @@ session and restored by `/resume`.
76
76
 
77
77
  `PI_AGENT_PROFILE=<name>` is an explicit launch-time override; `PROFILE=<name>`
78
78
  is accepted as a convenience alias. Both take precedence over a saved session
79
- selection. Explicit `--model` still takes precedence over an agent-profile's
80
- model.
79
+ selection. Explicit `--model` and `--thinking` still take precedence over an
80
+ agent-profile's model and thinking level.
81
+
82
+ While a session has a profile active, the extension reflects it into
83
+ `process.env.PI_AGENT_PROFILE` (cleared on `/agent-profile none`). Child
84
+ processes inherit it, so tooling like `agent-model.sh <role> pi` resolves the
85
+ same model the session runs, and fresh dispatches from the session stay on the
86
+ active profile.
81
87
 
82
88
  ## Commands
83
89
 
@@ -114,7 +120,7 @@ avenor_spawn(
114
120
  )
115
121
  ```
116
122
 
117
- 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.
123
+ Explicit `--model` and `--thinking` selections take precedence over the profile defaults. Avenor forwards a roster entry's `model` and `thinking` to the pi subprocess as `--model` and `--thinking`, so no agent config changes are needed for a one-off override, and a roster entry that names an agent keeps its own thinking level.
118
124
 
119
125
  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.
120
126
 
@@ -9,7 +9,7 @@ import {
9
9
  type AgentProfilesConfig,
10
10
  type ThinkingLevel,
11
11
  } from "./agent-profile.ts";
12
- import { findCliModelOverride, parseModelSpecifier } from "./model-selection.ts";
12
+ import { findCliModelOverride, findCliThinkingOverride, parseModelSpecifier } from "./model-selection.ts";
13
13
 
14
14
  /* ------------------------------------------------------------------ */
15
15
  /* Types */
@@ -137,10 +137,12 @@ function checkBashPermission(
137
137
  export default async function (pi: ExtensionAPI) {
138
138
  const agents = loadAgentsConfig();
139
139
  const { profiles: agentProfiles, errors: agentProfileConfigErrors } = loadAgentProfilesConfig();
140
- // Built-in flags are not exposed through pi.getFlag(). Avenor forwards its
141
- // model option to pi as --model, so argv is the extension-level signal that
142
- // the caller's model should take precedence over the profile default.
140
+ // Built-in flags are not exposed through pi.getFlag(). Avenor forwards a
141
+ // roster entry's model and thinking level to pi as --model and --thinking,
142
+ // so argv is the extension-level signal that the caller's choice should take
143
+ // precedence over the profile default.
143
144
  const cliModelOverride = findCliModelOverride(process.argv.slice(2));
145
+ const cliThinkingOverride = findCliThinkingOverride(process.argv.slice(2));
144
146
  let activeAgent: { name: string; profile: AgentProfile } | null = null;
145
147
  let activeAgentProfileName: string | undefined;
146
148
 
@@ -161,6 +163,20 @@ export default async function (pi: ExtensionAPI) {
161
163
  );
162
164
  }
163
165
 
166
+ /**
167
+ * Surface the session's active agent-profile to child processes.
168
+ *
169
+ * agent-model.sh resolves a role's effective model by reading
170
+ * $PI_AGENT_PROFILE; absent a launch-time override, the interactive
171
+ * /agent-profile selection is otherwise invisible to anything pi spawns.
172
+ * Mirroring it into the env lets the resolver agree with the session and,
173
+ * since children inherit it, keeps fresh dispatches on the same profile.
174
+ */
175
+ function syncProfileEnv(name: string | undefined) {
176
+ if (name) process.env.PI_AGENT_PROFILE = name;
177
+ else delete process.env.PI_AGENT_PROFILE;
178
+ }
179
+
164
180
  /** Apply a named agent-profile, optionally saving the choice in this session. */
165
181
  async function selectAgentProfile(
166
182
  name: string | undefined,
@@ -175,6 +191,7 @@ export default async function (pi: ExtensionAPI) {
175
191
  const previousName = activeAgentProfileName;
176
192
  activeAgentProfileName = name;
177
193
  setAgentProfileStatus(ctx);
194
+ syncProfileEnv(name);
178
195
 
179
196
  // The active role must receive a new effective model/thinking level now;
180
197
  // future roles resolve the overlay when /agent is invoked. Do not persist
@@ -182,6 +199,7 @@ export default async function (pi: ExtensionAPI) {
182
199
  if (activeAgent && !(await applyAgent(activeAgent.name, ctx))) {
183
200
  activeAgentProfileName = previousName;
184
201
  setAgentProfileStatus(ctx);
202
+ syncProfileEnv(previousName);
185
203
  return false;
186
204
  }
187
205
 
@@ -215,7 +233,7 @@ export default async function (pi: ExtensionAPI) {
215
233
  await pi.setModel(model);
216
234
  }
217
235
 
218
- if (profile.thinkingLevel) pi.setThinkingLevel(profile.thinkingLevel);
236
+ if (profile.thinkingLevel && !cliThinkingOverride) pi.setThinkingLevel(profile.thinkingLevel);
219
237
 
220
238
  // Tool restrictions — best-effort against currently registered tools.
221
239
  // tool_call handler enforces restrictions regardless of registration timing.
@@ -4,19 +4,30 @@ export interface ModelSpecifier {
4
4
  }
5
5
 
6
6
  /**
7
- * Return the model explicitly supplied to pi, if any.
7
+ * Return the value pi received for a built-in flag, if any.
8
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.
9
+ * Pi consumes its built-in flags itself, so extension flags cannot expose
10
+ * these values via pi.getFlag(). Inspecting argv lets agent profiles respect
11
+ * normal CLI precedence, including the model and thinking level Avenor
12
+ * forwards from a roster entry.
12
13
  */
13
- export function findCliModelOverride(argv: readonly string[]): string | undefined {
14
+ function findCliFlagValue(argv: readonly string[], flag: string): string | undefined {
14
15
  for (let index = 0; index < argv.length - 1; index += 1) {
15
- if (argv[index] === "--model") return argv[index + 1];
16
+ if (argv[index] === flag) return argv[index + 1];
16
17
  }
17
18
  return undefined;
18
19
  }
19
20
 
21
+ /** Return the model explicitly supplied to pi, if any. */
22
+ export function findCliModelOverride(argv: readonly string[]): string | undefined {
23
+ return findCliFlagValue(argv, "--model");
24
+ }
25
+
26
+ /** Return the thinking level explicitly supplied to pi, if any. */
27
+ export function findCliThinkingOverride(argv: readonly string[]): string | undefined {
28
+ return findCliFlagValue(argv, "--thinking");
29
+ }
30
+
20
31
  /** Split provider/model-id at the first slash so model IDs may contain slashes. */
21
32
  export function parseModelSpecifier(specifier: string): ModelSpecifier | undefined {
22
33
  const separator = specifier.indexOf("/");
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@dougbots/pi-agents",
3
- "version": "0.2.0",
3
+ "version": "0.3.0",
4
4
  "description": "Agent profiles for pi — preconfigured model, system prompt, tool restrictions, and permission gates",
5
5
  "scripts": {
6
6
  "test": "node --experimental-strip-types --test tests/*.test.mts"