pi-advisor-flow 0.8.1-dev.2 → 0.8.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/CHANGELOG.md CHANGED
@@ -4,7 +4,13 @@ All notable changes to this project are documented here.
4
4
 
5
5
  The format follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0/).
6
6
 
7
- ## Unreleased
7
+ ## 0.8.1 - 2026-09-23
8
+
9
+ ### Fixed
10
+
11
+ - Preserve a native subagent's host-selected model and thinking level when `alwaysOn` or explicit `/advisor` activation runs in a process marked with `PI_SUBAGENT_CHILD=1`.
12
+ - Keep marked child model selections out of the persisted parent Executor configuration.
13
+ - Run Advisor Scout with the marked child's active model and thinking level instead of replacing them with the configured parent Executor.
8
14
 
9
15
  ### Added
10
16
 
package/dist/index.js CHANGED
@@ -272,6 +272,16 @@ var splitRef = (ref) => {
272
272
  return i === -1 ? ["openai-codex", ref] : [ref.slice(0, i), ref.slice(i + 1)];
273
273
  };
274
274
 
275
+ // src/child-session.ts
276
+ var isMarkedSubagent = () => process.env.PI_SUBAGENT_CHILD === "1";
277
+ var effectiveExecutorRef = (ctx) => {
278
+ if (isMarkedSubagent() && ctx.model) {
279
+ return `${ctx.model.provider}/${ctx.model.id}`;
280
+ }
281
+ return executorRef;
282
+ };
283
+ var effectiveExecutorEffort = (ctx) => isMarkedSubagent() ? ctx.thinkingLevel : executorEffortRef;
284
+
275
285
  // src/content-utils.ts
276
286
  var isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
277
287
  var isRecordOf = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
@@ -2814,17 +2824,17 @@ var setupAbortWatch = (parentSignal, timeoutMs) => {
2814
2824
  wasTimedOut: () => timedOut
2815
2825
  };
2816
2826
  };
2817
- var streamScoutResponse = async (dependencies, resolved, manifest, parentSignal, timeoutMs, publish) => {
2827
+ var streamScoutResponse = async (dependencies, resolved, executorModel, executorEffort, manifest, parentSignal, timeoutMs, publish) => {
2818
2828
  const { abortPromise, controller, teardown, wasTimedOut } = setupAbortWatch(parentSignal, timeoutMs);
2819
2829
  try {
2820
2830
  const collection = dependencies.collect(resolved, {
2821
2831
  messages: [manifestMessage(manifest)],
2822
2832
  onChunk: (thinking, text) => {
2823
2833
  if (!controller.signal.aborted) {
2824
- publish({ model: executorRef, text, thinking, type: "chunk" });
2834
+ publish({ model: executorModel, text, thinking, type: "chunk" });
2825
2835
  }
2826
2836
  },
2827
- reasoning: executorEffortRef,
2837
+ reasoning: executorEffort,
2828
2838
  signal: controller.signal,
2829
2839
  systemPrompt: SCOUT_SYSTEM
2830
2840
  });
@@ -2857,7 +2867,7 @@ var runAdvisorScout = async (ctx, manifest, parentSignal, onEvent, timeoutMs = S
2857
2867
  category,
2858
2868
  message,
2859
2869
  metrics: usage === undefined ? baseMetrics(manifest, startedAt) : { ...baseMetrics(manifest, startedAt), usage },
2860
- model: executorRef,
2870
+ model: effectiveExecutorRef(ctx),
2861
2871
  ok: false
2862
2872
  };
2863
2873
  publish({ outcome, type: "fallback" });
@@ -2866,9 +2876,11 @@ var runAdvisorScout = async (ctx, manifest, parentSignal, onEvent, timeoutMs = S
2866
2876
  if (parentSignal?.aborted) {
2867
2877
  return cancelled();
2868
2878
  }
2879
+ const executorModel = effectiveExecutorRef(ctx);
2880
+ const executorEffort = effectiveExecutorEffort(ctx);
2869
2881
  let resolved;
2870
2882
  try {
2871
- resolved = await dependencies.resolve(ctx, executorRef, "Scout");
2883
+ resolved = await dependencies.resolve(ctx, executorModel, "Scout");
2872
2884
  } catch (error) {
2873
2885
  if (parentSignal?.aborted) {
2874
2886
  return cancelled();
@@ -2879,8 +2891,8 @@ var runAdvisorScout = async (ctx, manifest, parentSignal, onEvent, timeoutMs = S
2879
2891
  if (parentSignal?.aborted) {
2880
2892
  return cancelled();
2881
2893
  }
2882
- publish({ model: executorRef, type: "call" });
2883
- const streamed = await streamScoutResponse(dependencies, resolved, manifest, parentSignal, timeoutMs, publish);
2894
+ publish({ model: executorModel, type: "call" });
2895
+ const streamed = await streamScoutResponse(dependencies, resolved, executorModel, executorEffort, manifest, parentSignal, timeoutMs, publish);
2884
2896
  if (!streamed.ok) {
2885
2897
  if (parentSignal?.aborted) {
2886
2898
  return cancelled();
@@ -2907,7 +2919,7 @@ var runAdvisorScout = async (ctx, manifest, parentSignal, onEvent, timeoutMs = S
2907
2919
  ]).size,
2908
2920
  usage: snapshotAdvisorUsage(streamed.streamed.usage)
2909
2921
  },
2910
- model: executorRef,
2922
+ model: executorModel,
2911
2923
  ok: true,
2912
2924
  selectedLabels: manifest.groups.filter((group) => group.required || selection.selectedIds.includes(group.id)).map((group) => group.label),
2913
2925
  selection
@@ -4173,7 +4185,7 @@ var resolveActivationModels = async (runtime, ctx) => {
4173
4185
  if (!(advisorAuth.ok && advisorAuth.apiKey)) {
4174
4186
  return { error: `No API key for Advisor ${advisorRef}` };
4175
4187
  }
4176
- if (!await runtime.setExecutorModel(executor)) {
4188
+ if (!isMarkedSubagent() && !await runtime.setExecutorModel(executor)) {
4177
4189
  return { error: `No API key for Executor ${executorRef}` };
4178
4190
  }
4179
4191
  return {};
@@ -4219,7 +4231,7 @@ var activateAdvisor = async (runtime, args, ctx, announce = true) => {
4219
4231
  saveConfig(ctx, { persistAdvisor: true, persistExecutor: true });
4220
4232
  }
4221
4233
  runtime.pendingExecutorModelRef = undefined;
4222
- if (executorEffortRef) {
4234
+ if (executorEffortRef && !isMarkedSubagent()) {
4223
4235
  runtime.pi.setThinkingLevel(executorEffortRef);
4224
4236
  }
4225
4237
  if (!runtime.flowEnabled()) {
@@ -4230,9 +4242,11 @@ var activateAdvisor = async (runtime, args, ctx, announce = true) => {
4230
4242
  ]);
4231
4243
  }
4232
4244
  if (announce) {
4245
+ const activeExecutorRef = effectiveExecutorRef(ctx);
4246
+ const activeExecutorEffort = effectiveExecutorEffort(ctx);
4233
4247
  notify(ctx, `${ADVISOR_ACTIVATION_EXPLANATION}
4234
4248
 
4235
- Advisor flow ready — Executor: ${executorRef} (thinking: ${executorEffortRef || "default"}) · Advisor: ${advisorRef} (thinking: ${advisorEffortRef || "default"})`, "info");
4249
+ Advisor flow ready — Executor: ${activeExecutorRef} (thinking: ${activeExecutorEffort || "default"}) · Advisor: ${advisorRef} (thinking: ${advisorEffortRef || "default"})`, "info");
4236
4250
  }
4237
4251
  };
4238
4252
 
@@ -4251,7 +4265,7 @@ var registerCommandLifecycle = (runtime, activateAdvisor) => {
4251
4265
  }
4252
4266
  });
4253
4267
  runtime.pi.on("model_select", (event, ctx) => {
4254
- if (event.source !== "set" || runtime.suppressModelSelectionSync) {
4268
+ if (event.source !== "set" || runtime.suppressModelSelectionSync || isMarkedSubagent()) {
4255
4269
  return;
4256
4270
  }
4257
4271
  const selected = `${event.model.provider}/${event.model.id}`;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-advisor-flow",
3
- "version": "0.8.1-dev.2",
3
+ "version": "0.8.1",
4
4
  "description": "Advanced Executor/Advisor flow for Pi, fully configurable and extendable.",
5
5
  "keywords": [
6
6
  "advisor",
@@ -0,0 +1,15 @@
1
+ import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
2
+
3
+ import { executorEffortRef, executorRef } from "./config/state.ts";
4
+
5
+ export const isMarkedSubagent = () => process.env.PI_SUBAGENT_CHILD === "1";
6
+
7
+ export const effectiveExecutorRef = (ctx: ExtensionContext) => {
8
+ if (isMarkedSubagent() && ctx.model) {
9
+ return `${ctx.model.provider}/${ctx.model.id}`;
10
+ }
11
+ return executorRef;
12
+ };
13
+
14
+ export const effectiveExecutorEffort = (ctx: ExtensionContext) =>
15
+ isMarkedSubagent() ? ctx.thinkingLevel : executorEffortRef;
@@ -1,5 +1,10 @@
1
1
  import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
2
2
 
3
+ import {
4
+ effectiveExecutorEffort,
5
+ effectiveExecutorRef,
6
+ isMarkedSubagent,
7
+ } from "../child-session.ts";
3
8
  import { parseArgs } from "../config/args.ts";
4
9
  import {
5
10
  advisorEffortRef,
@@ -51,7 +56,7 @@ const resolveActivationModels = async (
51
56
  if (!(advisorAuth.ok && advisorAuth.apiKey)) {
52
57
  return { error: `No API key for Advisor ${advisorRef}` };
53
58
  }
54
- if (!(await runtime.setExecutorModel(executor))) {
59
+ if (!isMarkedSubagent() && !(await runtime.setExecutorModel(executor))) {
55
60
  return { error: `No API key for Executor ${executorRef}` };
56
61
  }
57
62
  return {};
@@ -116,7 +121,7 @@ export const activateAdvisor = async (
116
121
  // an older inactive selection override an explicit activation argument on a
117
122
  // later attempt.
118
123
  runtime.pendingExecutorModelRef = undefined;
119
- if (executorEffortRef) {
124
+ if (executorEffortRef && !isMarkedSubagent()) {
120
125
  // SAFETY: executorEffortRef is operator-configured and trusted to name a ThinkingLevel.
121
126
  runtime.pi.setThinkingLevel(executorEffortRef as ThinkingLevel);
122
127
  }
@@ -128,9 +133,11 @@ export const activateAdvisor = async (
128
133
  ]);
129
134
  }
130
135
  if (announce) {
136
+ const activeExecutorRef = effectiveExecutorRef(ctx);
137
+ const activeExecutorEffort = effectiveExecutorEffort(ctx);
131
138
  notify(
132
139
  ctx,
133
- `${ADVISOR_ACTIVATION_EXPLANATION}\n\nAdvisor flow ready — Executor: ${executorRef} (thinking: ${executorEffortRef || "default"}) · Advisor: ${advisorRef} (thinking: ${advisorEffortRef || "default"})`,
140
+ `${ADVISOR_ACTIVATION_EXPLANATION}\n\nAdvisor flow ready — Executor: ${activeExecutorRef} (thinking: ${activeExecutorEffort || "default"}) · Advisor: ${advisorRef} (thinking: ${advisorEffortRef || "default"})`,
134
141
  "info"
135
142
  );
136
143
  }
@@ -1,5 +1,6 @@
1
1
  import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
2
2
 
3
+ import { isMarkedSubagent } from "../child-session.ts";
3
4
  import {
4
5
  alwaysOnRef,
5
6
  executorRef,
@@ -40,7 +41,11 @@ export const registerCommandLifecycle = (
40
41
  // "restore" replays a stored session model and "cycle" changes the active
41
42
  // model without an explicit `/model` choice. Neither should redefine the
42
43
  // configured Executor.
43
- if (event.source !== "set" || runtime.suppressModelSelectionSync) {
44
+ if (
45
+ event.source !== "set" ||
46
+ runtime.suppressModelSelectionSync ||
47
+ isMarkedSubagent()
48
+ ) {
44
49
  return;
45
50
  }
46
51
  const selected = `${event.model.provider}/${event.model.id}`;
package/src/scout.ts CHANGED
@@ -1,7 +1,10 @@
1
1
  import type { Message } from "@earendil-works/pi-ai/compat";
2
2
  import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
3
3
 
4
- import { executorEffortRef, executorRef } from "./config/state.ts";
4
+ import {
5
+ effectiveExecutorEffort,
6
+ effectiveExecutorRef,
7
+ } from "./child-session.ts";
5
8
  import { isRecord, isString } from "./content-utils.ts";
6
9
  import { collectTextStream, resolveConfiguredModel } from "./model-stream.ts";
7
10
  import type {
@@ -250,6 +253,8 @@ type ScoutStreamResult =
250
253
  const streamScoutResponse = async (
251
254
  dependencies: ScoutDependencies,
252
255
  resolved: ResolvedConfiguredModel,
256
+ executorModel: string,
257
+ executorEffort: string | undefined,
253
258
  manifest: ScoutManifest,
254
259
  parentSignal: AbortSignal | undefined,
255
260
  timeoutMs: number,
@@ -264,10 +269,10 @@ const streamScoutResponse = async (
264
269
  messages: [manifestMessage(manifest)],
265
270
  onChunk: (thinking, text) => {
266
271
  if (!controller.signal.aborted) {
267
- publish({ model: executorRef, text, thinking, type: "chunk" });
272
+ publish({ model: executorModel, text, thinking, type: "chunk" });
268
273
  }
269
274
  },
270
- reasoning: executorEffortRef,
275
+ reasoning: executorEffort,
271
276
  signal: controller.signal,
272
277
  systemPrompt: SCOUT_SYSTEM,
273
278
  });
@@ -317,7 +322,7 @@ export const runAdvisorScout = async (
317
322
  usage === undefined
318
323
  ? baseMetrics(manifest, startedAt)
319
324
  : { ...baseMetrics(manifest, startedAt), usage },
320
- model: executorRef,
325
+ model: effectiveExecutorRef(ctx),
321
326
  ok: false as const,
322
327
  };
323
328
  publish({ outcome, type: "fallback" });
@@ -328,9 +333,11 @@ export const runAdvisorScout = async (
328
333
  return cancelled();
329
334
  }
330
335
 
336
+ const executorModel = effectiveExecutorRef(ctx);
337
+ const executorEffort = effectiveExecutorEffort(ctx);
331
338
  let resolved: ResolvedConfiguredModel;
332
339
  try {
333
- resolved = await dependencies.resolve(ctx, executorRef, "Scout");
340
+ resolved = await dependencies.resolve(ctx, executorModel, "Scout");
334
341
  } catch (error) {
335
342
  if (parentSignal?.aborted) {
336
343
  return cancelled();
@@ -342,11 +349,13 @@ export const runAdvisorScout = async (
342
349
  if (parentSignal?.aborted) {
343
350
  return cancelled();
344
351
  }
345
- publish({ model: executorRef, type: "call" });
352
+ publish({ model: executorModel, type: "call" });
346
353
 
347
354
  const streamed = await streamScoutResponse(
348
355
  dependencies,
349
356
  resolved,
357
+ executorModel,
358
+ executorEffort,
350
359
  manifest,
351
360
  parentSignal,
352
361
  timeoutMs,
@@ -390,7 +399,7 @@ export const runAdvisorScout = async (
390
399
  ]).size,
391
400
  usage: snapshotAdvisorUsage(streamed.streamed.usage),
392
401
  },
393
- model: executorRef,
402
+ model: executorModel,
394
403
  ok: true as const,
395
404
  selectedLabels: manifest.groups
396
405
  .filter(