pi-advisor-flow 0.8.1-dev.1 → 0.8.1-dev.2

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,13 +4,11 @@ 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
- ## 0.8.1-dev.1 - 2026-09-23
7
+ ## Unreleased
8
8
 
9
- ### Fixed
9
+ ### Added
10
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.
11
+ - Published validated npm development previews for package changes on `main` under the `dev` dist-tag; stable installs continue to use `latest`.
14
12
 
15
13
  ## 0.8.0 - 2026-09-22
16
14
 
package/README.md CHANGED
@@ -46,6 +46,14 @@ Requires Pi 0.84.1 or later. Pi 0.85.0 is not supported (broken upstream release
46
46
  pi install npm:pi-advisor-flow
47
47
  ```
48
48
 
49
+ For npm consumers who want to test the latest development preview:
50
+
51
+ ```bash
52
+ npm install pi-advisor-flow@dev
53
+ ```
54
+
55
+ Preview builds use the next patch prerelease version (for example, `0.8.1-dev.1` after stable `0.8.0`) and are published only when a file included in the npm package changes. Each preview advances the `dev.N` sequence. Regular installs continue to use the stable `latest` version.
56
+
49
57
  You can also install from GitHub:
50
58
 
51
59
  ```bash
package/dist/index.js CHANGED
@@ -272,16 +272,6 @@ 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
-
285
275
  // src/content-utils.ts
286
276
  var isRecord = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
287
277
  var isRecordOf = (value) => Boolean(value) && typeof value === "object" && !Array.isArray(value);
@@ -2077,8 +2067,8 @@ var toolResultEntry = (message, toolResultMaxLines, toolResultMaxBytes, policies
2077
2067
  return `[Tool Result for ${toolName}] (excluded by Advisor tool policy)`;
2078
2068
  }
2079
2069
  if (policy === "summary") {
2080
- const capped2 = capToolResult(source, toolResultMaxLines, toolResultMaxBytes);
2081
- return `[Tool Result for ${toolName}] (output omitted by Advisor tool policy: summary; status: ${status}; ${capped2.totalLines} lines, ${capped2.totalBytes} bytes; source output was${capped2.truncated ? "" : " not"} truncated)`;
2070
+ const capped = capToolResult(source, toolResultMaxLines, toolResultMaxBytes);
2071
+ return `[Tool Result for ${toolName}] (output omitted by Advisor tool policy: summary; status: ${status}; ${capped.totalLines} lines, ${capped.totalBytes} bytes; source output was${capped.truncated ? "" : " not"} truncated)`;
2082
2072
  }
2083
2073
  const disclosed = redact ? redactSecrets(source) : source;
2084
2074
  const capped = capToolResult(disclosed, toolResultMaxLines, toolResultMaxBytes);
@@ -2118,17 +2108,17 @@ var selectRecentEntries = (entries, maxChars) => {
2118
2108
  }
2119
2109
  const newestTruncated = "[Newest entry truncated]";
2120
2110
  if (entries.length === 1) {
2121
- const prefix2 = `${newestTruncated}${separator}`;
2122
- return `${prefix2}${entries[0].slice(0, Math.max(0, maxChars - prefix2.length))}`.slice(0, maxChars);
2111
+ const prefix = `${newestTruncated}${separator}`;
2112
+ return `${prefix}${entries[0].slice(0, Math.max(0, maxChars - prefix.length))}`.slice(0, maxChars);
2123
2113
  }
2124
2114
  const selected = [];
2125
2115
  let selectedLength = 0;
2126
2116
  for (let index = entries.length - 1;index >= 0; index -= 1) {
2127
2117
  const entry = entries[index];
2128
2118
  const candidateCount = selected.length + 1;
2129
- const omitted2 = entries.length - candidateCount;
2119
+ const omitted = entries.length - candidateCount;
2130
2120
  const candidateLength = selectedLength + entry.length + (selected.length > 0 ? separator.length : 0);
2131
- if (omissionMarker(omitted2).length + separator.length + candidateLength > maxChars) {
2121
+ if (omissionMarker(omitted).length + separator.length + candidateLength > maxChars) {
2132
2122
  break;
2133
2123
  }
2134
2124
  selected.unshift(entry);
@@ -2824,17 +2814,17 @@ var setupAbortWatch = (parentSignal, timeoutMs) => {
2824
2814
  wasTimedOut: () => timedOut
2825
2815
  };
2826
2816
  };
2827
- var streamScoutResponse = async (dependencies, resolved, executorModel, executorEffort, manifest, parentSignal, timeoutMs, publish) => {
2817
+ var streamScoutResponse = async (dependencies, resolved, manifest, parentSignal, timeoutMs, publish) => {
2828
2818
  const { abortPromise, controller, teardown, wasTimedOut } = setupAbortWatch(parentSignal, timeoutMs);
2829
2819
  try {
2830
2820
  const collection = dependencies.collect(resolved, {
2831
2821
  messages: [manifestMessage(manifest)],
2832
2822
  onChunk: (thinking, text) => {
2833
2823
  if (!controller.signal.aborted) {
2834
- publish({ model: executorModel, text, thinking, type: "chunk" });
2824
+ publish({ model: executorRef, text, thinking, type: "chunk" });
2835
2825
  }
2836
2826
  },
2837
- reasoning: executorEffort,
2827
+ reasoning: executorEffortRef,
2838
2828
  signal: controller.signal,
2839
2829
  systemPrompt: SCOUT_SYSTEM
2840
2830
  });
@@ -2863,24 +2853,22 @@ var runAdvisorScout = async (ctx, manifest, parentSignal, onEvent, timeoutMs = S
2863
2853
  return { cancelled: true, ok: false };
2864
2854
  };
2865
2855
  const fallback = (category, message, usage) => {
2866
- const outcome2 = {
2856
+ const outcome = {
2867
2857
  category,
2868
2858
  message,
2869
2859
  metrics: usage === undefined ? baseMetrics(manifest, startedAt) : { ...baseMetrics(manifest, startedAt), usage },
2870
- model: effectiveExecutorRef(ctx),
2860
+ model: executorRef,
2871
2861
  ok: false
2872
2862
  };
2873
- publish({ outcome: outcome2, type: "fallback" });
2874
- return outcome2;
2863
+ publish({ outcome, type: "fallback" });
2864
+ return outcome;
2875
2865
  };
2876
2866
  if (parentSignal?.aborted) {
2877
2867
  return cancelled();
2878
2868
  }
2879
- const executorModel = effectiveExecutorRef(ctx);
2880
- const executorEffort = effectiveExecutorEffort(ctx);
2881
2869
  let resolved;
2882
2870
  try {
2883
- resolved = await dependencies.resolve(ctx, executorModel, "Scout");
2871
+ resolved = await dependencies.resolve(ctx, executorRef, "Scout");
2884
2872
  } catch (error) {
2885
2873
  if (parentSignal?.aborted) {
2886
2874
  return cancelled();
@@ -2891,8 +2879,8 @@ var runAdvisorScout = async (ctx, manifest, parentSignal, onEvent, timeoutMs = S
2891
2879
  if (parentSignal?.aborted) {
2892
2880
  return cancelled();
2893
2881
  }
2894
- publish({ model: executorModel, type: "call" });
2895
- const streamed = await streamScoutResponse(dependencies, resolved, executorModel, executorEffort, manifest, parentSignal, timeoutMs, publish);
2882
+ publish({ model: executorRef, type: "call" });
2883
+ const streamed = await streamScoutResponse(dependencies, resolved, manifest, parentSignal, timeoutMs, publish);
2896
2884
  if (!streamed.ok) {
2897
2885
  if (parentSignal?.aborted) {
2898
2886
  return cancelled();
@@ -2919,7 +2907,7 @@ var runAdvisorScout = async (ctx, manifest, parentSignal, onEvent, timeoutMs = S
2919
2907
  ]).size,
2920
2908
  usage: snapshotAdvisorUsage(streamed.streamed.usage)
2921
2909
  },
2922
- model: executorModel,
2910
+ model: executorRef,
2923
2911
  ok: true,
2924
2912
  selectedLabels: manifest.groups.filter((group) => group.required || selection.selectedIds.includes(group.id)).map((group) => group.label),
2925
2913
  selection
@@ -2970,12 +2958,12 @@ var curateAdvisorConversation = async (ctx, legacyConversation, signal, onScout,
2970
2958
  };
2971
2959
 
2972
2960
  // src/tools/prompts.ts
2973
- var advisorMessageText = (conversation, question, changes, draft, preferences, untracked2, tracked2) => {
2961
+ var advisorMessageText = (conversation, question, changes, draft, preferences, untracked, tracked) => {
2974
2962
  const safeConversation = escapeRepositoryText(conversation);
2975
2963
  const safeDraft = draft ? escapeRepositoryText(draft) : undefined;
2976
2964
  const safePreferences = preferences ? escapeRepositoryText(preferences) : undefined;
2977
- const safeUntracked = (untracked2 ?? []).map(escapeRepositoryText);
2978
- const safeTracked = (tracked2 ?? []).map(escapeRepositoryText);
2965
+ const safeUntracked = (untracked ?? []).map(escapeRepositoryText);
2966
+ const safeTracked = (tracked ?? []).map(escapeRepositoryText);
2979
2967
  const text = `${safeConversation ? `<conversation>
2980
2968
  ${safeConversation}
2981
2969
  </conversation>` : ""}${changes ? `
@@ -3088,16 +3076,16 @@ var assembleConsultationContext = async (options) => {
3088
3076
  const curated = await curateAdvisorConversation(ctx, legacyConversation, options.signal, options.onScout, advisorScoutEnabledRef, runAdvisorScout, options.currentInvocationId, conversationBudget);
3089
3077
  const preferences = await readProjectPreferences(ctx, ATTACHMENT_TEXT_MAX_BYTES, advisorRedactSecretsRef);
3090
3078
  const draftText = options.draft ? redactAndCapText(options.draft, ATTACHMENT_TEXT_MAX_BYTES, advisorRedactSecretsRef) : undefined;
3091
- const untracked2 = await readUntrackedFiles(ctx.cwd, options.includeUntracked ?? [], advisorUntrackedContentRef, advisorRedactSecretsRef);
3092
- const tracked2 = await readTrackedFiles(ctx.cwd, options.includeTracked ?? [], advisorTrackedFileContentRef, advisorRedactSecretsRef, Math.max(0, ATTACHMENTS_TOTAL_MAX_BYTES - untracked2.reduce((sum, item) => sum + item.bytes, 0)));
3079
+ const untracked = await readUntrackedFiles(ctx.cwd, options.includeUntracked ?? [], advisorUntrackedContentRef, advisorRedactSecretsRef);
3080
+ const tracked = await readTrackedFiles(ctx.cwd, options.includeTracked ?? [], advisorTrackedFileContentRef, advisorRedactSecretsRef, Math.max(0, ATTACHMENTS_TOTAL_MAX_BYTES - untracked.reduce((sum, item) => sum + item.bytes, 0)));
3093
3081
  return {
3094
3082
  changeText,
3095
3083
  conversation: curated.conversation,
3096
3084
  draftText,
3097
3085
  preferences,
3098
3086
  scout: curated.scout,
3099
- tracked: tracked2,
3100
- untracked: untracked2
3087
+ tracked,
3088
+ untracked
3101
3089
  };
3102
3090
  };
3103
3091
 
@@ -3161,11 +3149,11 @@ var parseAutomaticDecision = (text) => {
3161
3149
  if (!subsequent) {
3162
3150
  continue;
3163
3151
  }
3164
- const repeated2 = namedGroups(subsequent).decision.trim().toLowerCase();
3152
+ const repeated = namedGroups(subsequent).decision.trim().toLowerCase();
3165
3153
  if (openingFence) {
3166
- pendingFencedDecisions.push(repeated2);
3154
+ pendingFencedDecisions.push(repeated);
3167
3155
  } else {
3168
- decisions.push(repeated2);
3156
+ decisions.push(repeated);
3169
3157
  }
3170
3158
  }
3171
3159
  if (openingFence) {
@@ -4185,7 +4173,7 @@ var resolveActivationModels = async (runtime, ctx) => {
4185
4173
  if (!(advisorAuth.ok && advisorAuth.apiKey)) {
4186
4174
  return { error: `No API key for Advisor ${advisorRef}` };
4187
4175
  }
4188
- if (!isMarkedSubagent() && !await runtime.setExecutorModel(executor)) {
4176
+ if (!await runtime.setExecutorModel(executor)) {
4189
4177
  return { error: `No API key for Executor ${executorRef}` };
4190
4178
  }
4191
4179
  return {};
@@ -4231,7 +4219,7 @@ var activateAdvisor = async (runtime, args, ctx, announce = true) => {
4231
4219
  saveConfig(ctx, { persistAdvisor: true, persistExecutor: true });
4232
4220
  }
4233
4221
  runtime.pendingExecutorModelRef = undefined;
4234
- if (executorEffortRef && !isMarkedSubagent()) {
4222
+ if (executorEffortRef) {
4235
4223
  runtime.pi.setThinkingLevel(executorEffortRef);
4236
4224
  }
4237
4225
  if (!runtime.flowEnabled()) {
@@ -4242,22 +4230,20 @@ var activateAdvisor = async (runtime, args, ctx, announce = true) => {
4242
4230
  ]);
4243
4231
  }
4244
4232
  if (announce) {
4245
- const activeExecutorRef = effectiveExecutorRef(ctx);
4246
- const activeExecutorEffort = effectiveExecutorEffort(ctx);
4247
4233
  notify(ctx, `${ADVISOR_ACTIVATION_EXPLANATION}
4248
4234
 
4249
- Advisor flow ready — Executor: ${activeExecutorRef} (thinking: ${activeExecutorEffort || "default"}) · Advisor: ${advisorRef} (thinking: ${advisorEffortRef || "default"})`, "info");
4235
+ Advisor flow ready — Executor: ${executorRef} (thinking: ${executorEffortRef || "default"}) · Advisor: ${advisorRef} (thinking: ${advisorEffortRef || "default"})`, "info");
4250
4236
  }
4251
4237
  };
4252
4238
 
4253
4239
  // src/commands/lifecycle.ts
4254
- var registerCommandLifecycle = (runtime, activateAdvisor2) => {
4240
+ var registerCommandLifecycle = (runtime, activateAdvisor) => {
4255
4241
  runtime.pi.on("session_start", async (_event, ctx) => {
4256
4242
  runtime.pendingExecutorModelRef = undefined;
4257
4243
  try {
4258
4244
  loadConfig(ctx);
4259
4245
  if (alwaysOnRef) {
4260
- await activateAdvisor2("", ctx, false);
4246
+ await activateAdvisor("", ctx, false);
4261
4247
  }
4262
4248
  } catch (error) {
4263
4249
  const message = error instanceof Error ? error.message : String(error);
@@ -4265,7 +4251,7 @@ var registerCommandLifecycle = (runtime, activateAdvisor2) => {
4265
4251
  }
4266
4252
  });
4267
4253
  runtime.pi.on("model_select", (event, ctx) => {
4268
- if (event.source !== "set" || runtime.suppressModelSelectionSync || isMarkedSubagent()) {
4254
+ if (event.source !== "set" || runtime.suppressModelSelectionSync) {
4269
4255
  return;
4270
4256
  }
4271
4257
  const selected = `${event.model.provider}/${event.model.id}`;
@@ -4652,12 +4638,12 @@ var connectionFailure = (error) => {
4652
4638
  failure: new JevFailureError("network", `Jev connection failed: ${message}`)
4653
4639
  };
4654
4640
  };
4655
- var sleepWithAbort = (signal, ms) => new Promise((resolve2) => {
4656
- const timer = setTimeout(resolve2, ms);
4641
+ var sleepWithAbort = (signal, ms) => new Promise((resolve) => {
4642
+ const timer = setTimeout(resolve, ms);
4657
4643
  timer.unref?.();
4658
4644
  signal.addEventListener("abort", () => {
4659
4645
  clearTimeout(timer);
4660
- resolve2();
4646
+ resolve();
4661
4647
  }, { once: true });
4662
4648
  });
4663
4649
 
@@ -5644,56 +5630,6 @@ import { getKeybindings } from "@earendil-works/pi-tui";
5644
5630
  import { Key as Key2, matchesKey as matchesKey2, truncateToWidth as truncateToWidth5 } from "@earendil-works/pi-tui";
5645
5631
 
5646
5632
  // node_modules/@typesafe-ai/sdk/dist/index.mjs
5647
- var requestIdFrom = (headers) => headers.get("x-typesafe-request-id") ?? undefined;
5648
- var APIPromise = class APIPromise2 extends Promise {
5649
- #responsePromise;
5650
- #parseResponse;
5651
- #parsed;
5652
- constructor(responsePromise, parseResponse) {
5653
- super((resolve2) => resolve2(undefined));
5654
- this.#responsePromise = responsePromise;
5655
- this.#parseResponse = parseResponse;
5656
- }
5657
- asResponse() {
5658
- return this.#responsePromise;
5659
- }
5660
- async withResponse() {
5661
- const [data, response] = await Promise.all([this.#parse(), this.#responsePromise]);
5662
- return {
5663
- data,
5664
- response,
5665
- requestId: requestIdFrom(response.headers)
5666
- };
5667
- }
5668
- map(fn) {
5669
- return new APIPromise2(this.#responsePromise, () => this.#parse().then(fn));
5670
- }
5671
- #parse() {
5672
- this.#parsed ??= this.#responsePromise.then(this.#parseResponse);
5673
- return this.#parsed;
5674
- }
5675
- then(onfulfilled, onrejected) {
5676
- return this.#parse().then(onfulfilled, onrejected);
5677
- }
5678
- catch(onrejected) {
5679
- return this.#parse().catch(onrejected);
5680
- }
5681
- finally(onfinally) {
5682
- return this.#parse().finally(onfinally);
5683
- }
5684
- };
5685
- var ENV = {
5686
- apiKey: "TYPESAFE_API_KEY",
5687
- baseURL: "TYPESAFE_BASE_URL",
5688
- defaultModel: "TYPESAFE_DEFAULT_MODEL",
5689
- logLevel: "TYPESAFE_LOG_LEVEL"
5690
- };
5691
- var readEnv = (name) => {
5692
- if (typeof process === "undefined" || !process.env)
5693
- return;
5694
- return process.env[name]?.trim() || undefined;
5695
- };
5696
- var fromCodeOrEnv = (fromCode, envVar) => fromCode ?? readEnv(envVar);
5697
5633
  var range2 = (from, to) => Array.from({ length: to - from }, (_, i) => from + i);
5698
5634
  var DEFAULT_RETRY_POLICY = {
5699
5635
  maxRetries: 2,
@@ -5711,239 +5647,11 @@ var DEFAULT_RETRY_POLICY = {
5711
5647
  apiTimeoutError: true
5712
5648
  };
5713
5649
  DEFAULT_RETRY_POLICY.maxRetries;
5714
- var isRetryableStatus = (status, policy = DEFAULT_RETRY_POLICY) => policy.httpStatuses.has(status);
5715
- var parseRetryAfter = (headers, now = Date.now()) => {
5716
- const ms = Number(headers.get("retry-after-ms"));
5717
- if (headers.has("retry-after-ms") && Number.isFinite(ms) && ms >= 0)
5718
- return ms;
5719
- const raw = headers.get("retry-after");
5720
- if (raw === null)
5721
- return;
5722
- const seconds = Number(raw);
5723
- if (Number.isFinite(seconds))
5724
- return seconds >= 0 ? seconds * 1000 : undefined;
5725
- const date = Date.parse(raw);
5726
- if (!Number.isNaN(date))
5727
- return Math.max(0, date - now);
5728
- };
5729
- var retryDelayMs = (attempt, headers, policy = DEFAULT_RETRY_POLICY, random = Math.random) => {
5730
- if (policy.respectRetryAfter && headers !== undefined) {
5731
- const retryAfter = parseRetryAfter(headers);
5732
- if (retryAfter !== undefined && retryAfter <= policy.maxRetryAfterMs)
5733
- return retryAfter;
5734
- }
5735
- const exponential = Math.min(policy.backoffInitialMs * 2 ** attempt, policy.backoffMaxMs);
5736
- return Math.round(exponential * (1 - random() * policy.backoffJitter));
5737
- };
5738
- var sleep = (ms, signal) => new Promise((resolve2, reject) => {
5739
- if (signal?.aborted)
5740
- return reject(signal.reason);
5741
- const onAbort = () => {
5742
- clearTimeout(timer);
5743
- reject(signal?.reason);
5744
- };
5745
- const timer = setTimeout(() => {
5746
- signal?.removeEventListener("abort", onAbort);
5747
- resolve2();
5748
- }, ms);
5749
- signal?.addEventListener("abort", onAbort, { once: true });
5750
- });
5751
- var TypeSafeError = class extends Error {
5752
- constructor(message, options) {
5753
- super(message, options);
5754
- this.name = new.target.name;
5755
- }
5756
- };
5757
- var isRecord2 = (value) => typeof value === "object" && value !== null;
5758
- var extractMessage = (body) => {
5759
- if (typeof body === "string")
5760
- return body || undefined;
5761
- if (!isRecord2(body))
5762
- return;
5763
- const { error, message, detail } = body;
5764
- if (typeof error === "string")
5765
- return error;
5766
- if (isRecord2(error) && typeof error.message === "string")
5767
- return error.message;
5768
- if (typeof message === "string")
5769
- return message;
5770
- if (typeof detail === "string")
5771
- return detail;
5772
- if (isRecord2(detail) && typeof detail.message === "string")
5773
- return detail.message;
5774
- if (Array.isArray(detail))
5775
- return describeValidationErrors(detail);
5776
- };
5777
- var describeValidationErrors = (errors) => {
5778
- const parts = errors.flatMap((e) => {
5779
- if (!isRecord2(e) || typeof e.msg !== "string")
5780
- return [];
5781
- const loc = Array.isArray(e.loc) ? e.loc.filter((x) => x !== "body").join(".") : "";
5782
- return [loc ? `${loc}: ${e.msg}` : e.msg];
5783
- });
5784
- return parts.length > 0 ? parts.join("; ") : undefined;
5785
- };
5786
- var MAX_RAW_BODY_IN_MESSAGE = 200;
5787
- var APIError = class APIError2 extends TypeSafeError {
5788
- status;
5789
- headers;
5790
- body;
5791
- requestId;
5792
- constructor(status, body, headers, message) {
5793
- super(message ?? APIError2.describe(status, body));
5794
- this.status = status;
5795
- this.body = body;
5796
- this.headers = headers;
5797
- this.requestId = requestIdFrom(headers);
5798
- }
5799
- static describe(status, body) {
5800
- const detail = extractMessage(body);
5801
- if (detail)
5802
- return `${status} ${detail}`;
5803
- if (body === undefined)
5804
- return `${status} status code (no body)`;
5805
- const raw = typeof body === "string" ? body : JSON.stringify(body);
5806
- return `${status} ${raw.length > MAX_RAW_BODY_IN_MESSAGE ? `${raw.slice(0, MAX_RAW_BODY_IN_MESSAGE)}…` : raw}`;
5807
- }
5808
- static fromResponse(status, body, headers) {
5809
- if (status === 400)
5810
- return new BadRequestError(status, body, headers);
5811
- if (status === 401)
5812
- return new AuthenticationError(status, body, headers);
5813
- if (status === 403)
5814
- return new PermissionDeniedError(status, body, headers);
5815
- if (status === 404)
5816
- return new NotFoundError(status, body, headers);
5817
- if (status === 422)
5818
- return new UnprocessableEntityError(status, body, headers);
5819
- if (status === 429)
5820
- return new RateLimitError(status, body, headers);
5821
- if (status >= 500)
5822
- return new InternalServerError(status, body, headers);
5823
- return new APIError2(status, body, headers);
5824
- }
5825
- };
5826
- var BadRequestError = class extends APIError {
5827
- };
5828
- var AuthenticationError = class extends APIError {
5829
- };
5830
- var PermissionDeniedError = class extends APIError {
5831
- };
5832
- var NotFoundError = class extends APIError {
5833
- };
5834
- var UnprocessableEntityError = class extends APIError {
5835
- };
5836
- var RateLimitError = class extends APIError {
5837
- retryAfterMs = parseRetryAfter(this.headers);
5838
- };
5839
- var InternalServerError = class extends APIError {
5840
- };
5841
- var APIConnectionError = class extends TypeSafeError {
5842
- constructor(message = "Connection error.", options) {
5843
- super(message, options);
5844
- }
5845
- };
5846
- var APITimeoutError = class extends APIConnectionError {
5847
- timeoutMs;
5848
- constructor(timeoutMs, options) {
5849
- super(`Request timed out after ${timeoutMs}ms.`, options);
5850
- this.timeoutMs = timeoutMs;
5851
- }
5852
- };
5853
- var APIUserAbortError = class extends TypeSafeError {
5854
- constructor(message = "Request was aborted.", options) {
5855
- super(message, options);
5856
- }
5857
- };
5858
- var LOG_LEVELS = [
5859
- "debug",
5860
- "info",
5861
- "warn",
5862
- "error",
5863
- "off"
5864
- ];
5865
- var DEFAULT_LOG_LEVEL = "warn";
5866
- var isLogLevel = (value) => LOG_LEVELS.includes(value);
5867
- var parseLogLevel = (value, source) => {
5868
- if (isLogLevel(value))
5869
- return value;
5870
- throw new TypeSafeError(`Invalid log level "${value}" from ${source}. Expected one of: ${LOG_LEVELS.join(", ")}.`);
5871
- };
5872
- var PREFIX = "[typesafe-sdk]";
5873
- var consoleLogger = {
5874
- debug: (message, ...args) => console.debug(`${PREFIX} ${message}`, ...args),
5875
- info: (message, ...args) => console.info(`${PREFIX} ${message}`, ...args),
5876
- warn: (message, ...args) => console.warn(`${PREFIX} ${message}`, ...args),
5877
- error: (message, ...args) => console.error(`${PREFIX} ${message}`, ...args)
5878
- };
5879
- var RANK = {
5880
- debug: 0,
5881
- info: 1,
5882
- warn: 2,
5883
- error: 3,
5884
- off: 4
5885
- };
5886
- var drop = () => {};
5887
- var withLevel = (sink, level) => {
5888
- const enabled = (at) => RANK[at] >= RANK[level];
5889
- return {
5890
- debug: enabled("debug") ? (message, ...args) => sink.debug(message, ...args) : drop,
5891
- info: enabled("info") ? (message, ...args) => sink.info(message, ...args) : drop,
5892
- warn: enabled("warn") ? (message, ...args) => sink.warn(message, ...args) : drop,
5893
- error: enabled("error") ? (message, ...args) => sink.error(message, ...args) : drop
5894
- };
5895
- };
5896
- var KEY_HEADERS = /* @__PURE__ */ new Set([
5897
- "authorization",
5898
- "proxy-authorization",
5899
- "x-api-key"
5900
- ]);
5901
- var OPAQUE_HEADERS = /* @__PURE__ */ new Set(["cookie", "set-cookie"]);
5902
- var redactKey = (value) => {
5903
- const [scheme, secret] = value.includes(" ") ? value.split(/\s+/, 2) : [undefined, value];
5904
- const tail = secret && secret.length > 8 ? secret.slice(-4) : "";
5905
- return `${scheme ? `${scheme} ` : ""}***${tail}`;
5906
- };
5907
- var redact = (name, value) => {
5908
- const lower = name.toLowerCase();
5909
- if (KEY_HEADERS.has(lower))
5910
- return redactKey(value);
5911
- if (OPAQUE_HEADERS.has(lower))
5912
- return "***";
5913
- return value;
5914
- };
5915
- var redactHeaders = (headers) => Object.fromEntries(Object.entries(headers).map(([name, value]) => [name, redact(name, value)]));
5916
5650
  var noul = (instructions = null, criteria) => ({
5917
5651
  type: "noul",
5918
5652
  instructions,
5919
5653
  criteria
5920
5654
  });
5921
- var validateQuestions = (questions) => {
5922
- if (Object.keys(questions).length === 0)
5923
- throw new TypeSafeError("At least one question is required.");
5924
- for (const [name, question] of Object.entries(questions)) {
5925
- if (question.type !== "score")
5926
- continue;
5927
- if (!Array.isArray(question.criteria))
5928
- throw new TypeSafeError(`Score question "${name}" has criteria that are not a list; score criteria must be a list of descriptions indexed by score from zero.`);
5929
- if (question.criteria.length < 2)
5930
- throw new TypeSafeError(`Score question "${name}" has ${question.criteria.length} criteria; at least two scores are required.`);
5931
- }
5932
- };
5933
- var Models = class {
5934
- #transport;
5935
- constructor(transport) {
5936
- this.#transport = transport;
5937
- }
5938
- list(options = {}) {
5939
- return this.#transport.request("GET", "/v1/models", options).map(unwrapModels);
5940
- }
5941
- };
5942
- var unwrapModels = (wire) => {
5943
- if (Array.isArray(wire?.models))
5944
- return wire.models;
5945
- throw new TypeSafeError("Unexpected response shape from GET /v1/models; expected { models: [...] }.");
5946
- };
5947
5655
  var g = globalThis;
5948
5656
  var isBrowser = () => typeof g.window !== "undefined" && typeof g.window.document !== "undefined" && typeof g.navigator !== "undefined";
5949
5657
  var describeRuntime = () => {
@@ -5962,280 +5670,7 @@ var describeRuntime = () => {
5962
5670
  return "browser";
5963
5671
  return "unknown";
5964
5672
  };
5965
- var VERSION = "0.6.0";
5966
- var missingApiKey = () => {
5967
- throw new TypeSafeError(`No API key was provided. Pass \`apiKey\` to the TypeSafeClient constructor or set the ${ENV.apiKey} environment variable.`);
5968
- };
5969
- var missingFetch = () => {
5970
- throw new TypeSafeError("No global `fetch` is available in this runtime. Pass a `fetch` implementation to the TypeSafeClient constructor.");
5971
- };
5972
- var refuseBrowser = () => {
5973
- throw new TypeSafeError("TypeSafeClient is running in a browser, which would expose your API key to anyone using the page. Call the API from a server instead, or pass `dangerouslyAllowBrowser: true` if you understand the risk.");
5974
- };
5975
- var defaultFetch = (input, init) => globalThis.fetch(input, init);
5976
- var assertNonNegativeInteger = (name, value) => {
5977
- if (!Number.isInteger(value) || value < 0)
5978
- throw new TypeSafeError(`\`${name}\` must be a non-negative integer, got ${String(value)}.`);
5979
- return value;
5980
- };
5981
- var assertPositiveMs = (name, value) => {
5982
- if (!Number.isFinite(value) || value <= 0)
5983
- throw new TypeSafeError(`\`${name}\` must be a positive number of milliseconds, got ${String(value)}.`);
5984
- return value;
5985
- };
5986
- var assertNonNegativeMs = (name, value) => {
5987
- if (!Number.isFinite(value) || value < 0)
5988
- throw new TypeSafeError(`\`${name}\` must be a non-negative number of milliseconds, got ${String(value)}.`);
5989
- return value;
5990
- };
5991
- var assertFraction = (name, value) => {
5992
- if (!Number.isFinite(value) || value < 0 || value > 1)
5993
- throw new TypeSafeError(`\`${name}\` must be between 0 and 1, got ${String(value)}.`);
5994
- return value;
5995
- };
5996
- var assertStatusSet = (name, statuses) => {
5997
- for (const status of statuses)
5998
- if (!Number.isInteger(status) || status < 100 || status > 999)
5999
- throw new TypeSafeError(`\`${name}\` must contain HTTP status codes, got ${String(status)}.`);
6000
- return statuses;
6001
- };
6002
- var resolveRetryPolicy = (base, overrides) => {
6003
- const o = overrides ?? {};
6004
- return {
6005
- maxRetries: o.maxRetries === undefined ? base.maxRetries : assertNonNegativeInteger("retry.maxRetries", o.maxRetries),
6006
- backoffInitialMs: o.backoffInitialMs === undefined ? base.backoffInitialMs : assertNonNegativeMs("retry.backoffInitialMs", o.backoffInitialMs),
6007
- backoffMaxMs: o.backoffMaxMs === undefined ? base.backoffMaxMs : assertNonNegativeMs("retry.backoffMaxMs", o.backoffMaxMs),
6008
- backoffJitter: o.backoffJitter === undefined ? base.backoffJitter : assertFraction("retry.backoffJitter", o.backoffJitter),
6009
- httpStatuses: new Set(o.httpStatuses === undefined ? base.httpStatuses : assertStatusSet("retry.httpStatuses", o.httpStatuses)),
6010
- respectRetryAfter: o.respectRetryAfter ?? base.respectRetryAfter,
6011
- maxRetryAfterMs: o.maxRetryAfterMs === undefined ? base.maxRetryAfterMs : assertNonNegativeMs("retry.maxRetryAfterMs", o.maxRetryAfterMs),
6012
- apiConnectionError: o.apiConnectionError ?? base.apiConnectionError,
6013
- apiTimeoutError: o.apiTimeoutError ?? base.apiTimeoutError
6014
- };
6015
- };
6016
- var isRetryableError = (err, policy) => {
6017
- if (err instanceof APITimeoutError)
6018
- return policy.apiTimeoutError;
6019
- if (err instanceof APIConnectionError)
6020
- return policy.apiConnectionError;
6021
- return false;
6022
- };
6023
- var resolveLogLevel = (fromCode) => {
6024
- if (fromCode !== undefined)
6025
- return parseLogLevel(fromCode, "the `logLevel` option");
6026
- const fromEnv = readEnv(ENV.logLevel);
6027
- if (fromEnv !== undefined)
6028
- return parseLogLevel(fromEnv, ENV.logLevel);
6029
- return DEFAULT_LOG_LEVEL;
6030
- };
6031
- var stripTrailingSlashes = (url) => url.replace(/\/+$/, "");
6032
- var mergeHeaders = (...sources) => {
6033
- const entries = /* @__PURE__ */ new Map;
6034
- for (const source of sources)
6035
- for (const [name, value] of Object.entries(source))
6036
- if (value === undefined)
6037
- entries.delete(name.toLowerCase());
6038
- else
6039
- entries.set(name.toLowerCase(), [name, value]);
6040
- return Object.fromEntries(entries.values());
6041
- };
6042
- var bufferResponse = async (response, signal) => {
6043
- const reader = response.clone().body?.getReader();
6044
- if (!reader)
6045
- return;
6046
- const cancel = () => {
6047
- reader.cancel(signal.reason).catch(() => {});
6048
- response.body?.cancel(signal.reason).catch(() => {});
6049
- };
6050
- signal.addEventListener("abort", cancel, { once: true });
6051
- try {
6052
- if (signal.aborted)
6053
- cancel();
6054
- signal.throwIfAborted();
6055
- while (!(await reader.read()).done)
6056
- signal.throwIfAborted();
6057
- signal.throwIfAborted();
6058
- } finally {
6059
- signal.removeEventListener("abort", cancel);
6060
- reader.releaseLock();
6061
- }
6062
- };
6063
5673
  var RUNTIME = describeRuntime();
6064
- var TypeSafeClient = class {
6065
- #apiKey;
6066
- baseURL;
6067
- defaultModel;
6068
- logLevel;
6069
- logger;
6070
- retry;
6071
- timeout;
6072
- defaultHeaders;
6073
- fetch;
6074
- models;
6075
- #requestCount = 0;
6076
- constructor(config = {}) {
6077
- if (isBrowser() && !config.dangerouslyAllowBrowser)
6078
- refuseBrowser();
6079
- this.#apiKey = fromCodeOrEnv(config.apiKey, ENV.apiKey) ?? missingApiKey();
6080
- this.baseURL = stripTrailingSlashes(fromCodeOrEnv(config.baseURL, ENV.baseURL) ?? "https://api.typesafe.ai");
6081
- this.defaultModel = fromCodeOrEnv(config.defaultModel, ENV.defaultModel) ?? "jev-latest";
6082
- this.logLevel = resolveLogLevel(config.logLevel);
6083
- this.logger = withLevel(config.logger ?? consoleLogger, this.logLevel);
6084
- this.retry = resolveRetryPolicy(DEFAULT_RETRY_POLICY, config.retry);
6085
- this.timeout = assertPositiveMs("timeout", config.timeout ?? 1e4);
6086
- this.defaultHeaders = { ...config.defaultHeaders };
6087
- if (config.fetch === undefined && typeof globalThis.fetch !== "function")
6088
- missingFetch();
6089
- this.fetch = config.fetch ?? defaultFetch;
6090
- const transport = {
6091
- request: (method, path, options) => this.#request(method, path, options),
6092
- defaultModel: this.defaultModel
6093
- };
6094
- this.models = new Models(transport);
6095
- }
6096
- systemOne(request, options = {}) {
6097
- validateQuestions(request.questions);
6098
- const body = {
6099
- ...request,
6100
- model: request.model ?? this.defaultModel
6101
- };
6102
- return this.#request("POST", "/v1/systemone", {
6103
- ...options,
6104
- body
6105
- });
6106
- }
6107
- #request(method, path, options = {}) {
6108
- const resolved = {
6109
- method,
6110
- path,
6111
- body: options.body,
6112
- headers: mergeHeaders(this.defaultHeaders, options.headers ?? {}),
6113
- signal: options.signal,
6114
- timeout: options.timeout === undefined ? this.timeout : assertPositiveMs("timeout", options.timeout),
6115
- retry: resolveRetryPolicy(this.retry, options.retry)
6116
- };
6117
- const tag = `#${++this.#requestCount} ${method} ${path}`;
6118
- return new APIPromise(this.fetchWithRetries(tag, resolved), async (res) => {
6119
- const parsed = await parseBody(res);
6120
- this.logger.debug(`${tag} <- body`, parsed);
6121
- return parsed;
6122
- });
6123
- }
6124
- async fetchWithRetries(tag, req) {
6125
- const url = `${this.baseURL}${req.path}`;
6126
- const headers = mergeHeaders(req.headers, {
6127
- Authorization: `Bearer ${this.#apiKey}`,
6128
- Accept: "application/json",
6129
- "User-Agent": `typesafe-sdk/${VERSION}`,
6130
- "X-TypeSafe-SDK": `typesafe-sdk/${VERSION}`,
6131
- "X-TypeSafe-Runtime": RUNTIME,
6132
- "Content-Type": req.body === undefined ? undefined : "application/json",
6133
- "X-TypeSafe-Retry-Count": undefined
6134
- });
6135
- const body = req.body === undefined ? undefined : JSON.stringify(req.body);
6136
- for (let attempt = 0;; attempt++) {
6137
- const retriesLeft = req.retry.maxRetries - attempt;
6138
- const attemptHeaders = attempt === 0 ? headers : {
6139
- ...headers,
6140
- "X-TypeSafe-Retry-Count": String(attempt)
6141
- };
6142
- this.logger.debug(`${tag} -> ${url}`, {
6143
- headers: redactHeaders(attemptHeaders),
6144
- body: req.body
6145
- });
6146
- const started = Date.now();
6147
- let res;
6148
- try {
6149
- res = await this.attempt(tag, url, {
6150
- method: req.method,
6151
- headers: attemptHeaders,
6152
- body
6153
- }, req);
6154
- } catch (err) {
6155
- if (err instanceof APIUserAbortError || retriesLeft <= 0)
6156
- throw err;
6157
- if (!isRetryableError(err, req.retry))
6158
- throw err;
6159
- await this.backOff(tag, attempt, retriesLeft, err.message, undefined, req);
6160
- continue;
6161
- }
6162
- const requestId = requestIdFrom(res.headers);
6163
- this.logger.info(`${tag} <- ${res.status} in ${Date.now() - started}ms${requestId ? ` (request ${requestId})` : ""}`);
6164
- if (res.ok)
6165
- return res;
6166
- const errorBody = await parseBody(res);
6167
- this.logger.debug(`${tag} <- error body`, errorBody);
6168
- const error = APIError.fromResponse(res.status, errorBody, res.headers);
6169
- if (retriesLeft <= 0 || !isRetryableStatus(res.status, req.retry))
6170
- throw error;
6171
- await this.backOff(tag, attempt, retriesLeft, `${res.status}`, res.headers, req);
6172
- }
6173
- }
6174
- async attempt(tag, url, init, { signal, timeout }) {
6175
- const controller = new AbortController;
6176
- const abortFromCaller = () => controller.abort(signal?.reason);
6177
- if (signal?.aborted)
6178
- abortFromCaller();
6179
- signal?.addEventListener("abort", abortFromCaller, { once: true });
6180
- let timedOut = false;
6181
- const timer = setTimeout(() => {
6182
- timedOut = true;
6183
- controller.abort();
6184
- }, timeout);
6185
- const started = Date.now();
6186
- const elapsed = () => `${Date.now() - started}ms`;
6187
- try {
6188
- const response = await this.fetch(url, {
6189
- ...init,
6190
- signal: controller.signal
6191
- });
6192
- await bufferResponse(response, controller.signal);
6193
- return response;
6194
- } catch (err) {
6195
- if (signal?.aborted) {
6196
- this.logger.info(`${tag} aborted by caller after ${elapsed()}`);
6197
- throw new APIUserAbortError(undefined, { cause: err });
6198
- }
6199
- if (timedOut) {
6200
- this.logger.info(`${tag} timed out after ${elapsed()}`);
6201
- throw new APITimeoutError(timeout, { cause: err });
6202
- }
6203
- this.logger.info(`${tag} connection error after ${elapsed()}`, err);
6204
- throw new APIConnectionError(err instanceof Error ? `Connection error: ${err.message}` : undefined, { cause: err });
6205
- } finally {
6206
- clearTimeout(timer);
6207
- signal?.removeEventListener("abort", abortFromCaller);
6208
- }
6209
- }
6210
- async backOff(tag, attempt, retriesLeft, reason, headers, { retry, signal }) {
6211
- const delay = retryDelayMs(attempt, headers, retry);
6212
- const nth = attempt + 1;
6213
- const total = attempt + retriesLeft;
6214
- this.logger.info(`${tag} retrying in ${delay}ms (retry ${nth}/${total}) after ${reason}`);
6215
- try {
6216
- await sleep(delay, signal);
6217
- } catch (err) {
6218
- this.logger.info(`${tag} aborted by caller while waiting to retry`);
6219
- throw new APIUserAbortError(undefined, { cause: err });
6220
- }
6221
- }
6222
- };
6223
- var parseBody = async (res) => {
6224
- const text = await res.text();
6225
- if (text.length === 0)
6226
- return;
6227
- if ((res.headers.get("content-type") ?? "").includes("application/json"))
6228
- try {
6229
- return JSON.parse(text);
6230
- } catch {
6231
- return text;
6232
- }
6233
- try {
6234
- return JSON.parse(text);
6235
- } catch {
6236
- return text;
6237
- }
6238
- };
6239
5674
 
6240
5675
  // src/ui/masked-input.ts
6241
5676
  import { Input as Input2, truncateToWidth as truncateToWidth4 } from "@earendil-works/pi-tui";
@@ -7338,7 +6773,7 @@ import {
7338
6773
  writeFile
7339
6774
  } from "node:fs/promises";
7340
6775
  import { join as join5 } from "node:path";
7341
- import { setTimeout as sleep2 } from "node:timers/promises";
6776
+ import { setTimeout as sleep } from "node:timers/promises";
7342
6777
  import { getAgentDir as getAgentDir4 } from "@earendil-works/pi-coding-agent";
7343
6778
  var ADOPTIONS = [
7344
6779
  "followed",
@@ -7426,7 +6861,7 @@ var withOutcomeLock = async (run) => {
7426
6861
  }
7427
6862
  continue;
7428
6863
  }
7429
- await sleep2(5);
6864
+ await sleep(5);
7430
6865
  }
7431
6866
  }
7432
6867
  throw new Error("Timed out waiting to append an Advisor outcome.");
@@ -8328,8 +7763,8 @@ function registerPiAdvisor(pi) {
8328
7763
  });
8329
7764
  }
8330
7765
  export {
8331
- runAdvisorGate2 as runAdvisorGate,
8332
- parseAutomaticDecision2 as parseAutomaticDecision,
7766
+ consultAdvisor2 as consultAdvisor,
8333
7767
  registerPiAdvisor as default,
8334
- consultAdvisor2 as consultAdvisor
7768
+ parseAutomaticDecision2 as parseAutomaticDecision,
7769
+ runAdvisorGate2 as runAdvisorGate
8335
7770
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-advisor-flow",
3
- "version": "0.8.1-dev.1",
3
+ "version": "0.8.1-dev.2",
4
4
  "description": "Advanced Executor/Advisor flow for Pi, fully configurable and extendable.",
5
5
  "keywords": [
6
6
  "advisor",
@@ -1,10 +1,5 @@
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";
8
3
  import { parseArgs } from "../config/args.ts";
9
4
  import {
10
5
  advisorEffortRef,
@@ -56,7 +51,7 @@ const resolveActivationModels = async (
56
51
  if (!(advisorAuth.ok && advisorAuth.apiKey)) {
57
52
  return { error: `No API key for Advisor ${advisorRef}` };
58
53
  }
59
- if (!isMarkedSubagent() && !(await runtime.setExecutorModel(executor))) {
54
+ if (!(await runtime.setExecutorModel(executor))) {
60
55
  return { error: `No API key for Executor ${executorRef}` };
61
56
  }
62
57
  return {};
@@ -121,7 +116,7 @@ export const activateAdvisor = async (
121
116
  // an older inactive selection override an explicit activation argument on a
122
117
  // later attempt.
123
118
  runtime.pendingExecutorModelRef = undefined;
124
- if (executorEffortRef && !isMarkedSubagent()) {
119
+ if (executorEffortRef) {
125
120
  // SAFETY: executorEffortRef is operator-configured and trusted to name a ThinkingLevel.
126
121
  runtime.pi.setThinkingLevel(executorEffortRef as ThinkingLevel);
127
122
  }
@@ -133,11 +128,9 @@ export const activateAdvisor = async (
133
128
  ]);
134
129
  }
135
130
  if (announce) {
136
- const activeExecutorRef = effectiveExecutorRef(ctx);
137
- const activeExecutorEffort = effectiveExecutorEffort(ctx);
138
131
  notify(
139
132
  ctx,
140
- `${ADVISOR_ACTIVATION_EXPLANATION}\n\nAdvisor flow ready — Executor: ${activeExecutorRef} (thinking: ${activeExecutorEffort || "default"}) · Advisor: ${advisorRef} (thinking: ${advisorEffortRef || "default"})`,
133
+ `${ADVISOR_ACTIVATION_EXPLANATION}\n\nAdvisor flow ready — Executor: ${executorRef} (thinking: ${executorEffortRef || "default"}) · Advisor: ${advisorRef} (thinking: ${advisorEffortRef || "default"})`,
141
134
  "info"
142
135
  );
143
136
  }
@@ -1,6 +1,5 @@
1
1
  import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
2
2
 
3
- import { isMarkedSubagent } from "../child-session.ts";
4
3
  import {
5
4
  alwaysOnRef,
6
5
  executorRef,
@@ -41,11 +40,7 @@ export const registerCommandLifecycle = (
41
40
  // "restore" replays a stored session model and "cycle" changes the active
42
41
  // model without an explicit `/model` choice. Neither should redefine the
43
42
  // configured Executor.
44
- if (
45
- event.source !== "set" ||
46
- runtime.suppressModelSelectionSync ||
47
- isMarkedSubagent()
48
- ) {
43
+ if (event.source !== "set" || runtime.suppressModelSelectionSync) {
49
44
  return;
50
45
  }
51
46
  const selected = `${event.model.provider}/${event.model.id}`;
package/src/scout.ts CHANGED
@@ -1,10 +1,7 @@
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 {
5
- effectiveExecutorEffort,
6
- effectiveExecutorRef,
7
- } from "./child-session.ts";
4
+ import { executorEffortRef, executorRef } from "./config/state.ts";
8
5
  import { isRecord, isString } from "./content-utils.ts";
9
6
  import { collectTextStream, resolveConfiguredModel } from "./model-stream.ts";
10
7
  import type {
@@ -253,8 +250,6 @@ type ScoutStreamResult =
253
250
  const streamScoutResponse = async (
254
251
  dependencies: ScoutDependencies,
255
252
  resolved: ResolvedConfiguredModel,
256
- executorModel: string,
257
- executorEffort: string | undefined,
258
253
  manifest: ScoutManifest,
259
254
  parentSignal: AbortSignal | undefined,
260
255
  timeoutMs: number,
@@ -269,10 +264,10 @@ const streamScoutResponse = async (
269
264
  messages: [manifestMessage(manifest)],
270
265
  onChunk: (thinking, text) => {
271
266
  if (!controller.signal.aborted) {
272
- publish({ model: executorModel, text, thinking, type: "chunk" });
267
+ publish({ model: executorRef, text, thinking, type: "chunk" });
273
268
  }
274
269
  },
275
- reasoning: executorEffort,
270
+ reasoning: executorEffortRef,
276
271
  signal: controller.signal,
277
272
  systemPrompt: SCOUT_SYSTEM,
278
273
  });
@@ -322,7 +317,7 @@ export const runAdvisorScout = async (
322
317
  usage === undefined
323
318
  ? baseMetrics(manifest, startedAt)
324
319
  : { ...baseMetrics(manifest, startedAt), usage },
325
- model: effectiveExecutorRef(ctx),
320
+ model: executorRef,
326
321
  ok: false as const,
327
322
  };
328
323
  publish({ outcome, type: "fallback" });
@@ -333,11 +328,9 @@ export const runAdvisorScout = async (
333
328
  return cancelled();
334
329
  }
335
330
 
336
- const executorModel = effectiveExecutorRef(ctx);
337
- const executorEffort = effectiveExecutorEffort(ctx);
338
331
  let resolved: ResolvedConfiguredModel;
339
332
  try {
340
- resolved = await dependencies.resolve(ctx, executorModel, "Scout");
333
+ resolved = await dependencies.resolve(ctx, executorRef, "Scout");
341
334
  } catch (error) {
342
335
  if (parentSignal?.aborted) {
343
336
  return cancelled();
@@ -349,13 +342,11 @@ export const runAdvisorScout = async (
349
342
  if (parentSignal?.aborted) {
350
343
  return cancelled();
351
344
  }
352
- publish({ model: executorModel, type: "call" });
345
+ publish({ model: executorRef, type: "call" });
353
346
 
354
347
  const streamed = await streamScoutResponse(
355
348
  dependencies,
356
349
  resolved,
357
- executorModel,
358
- executorEffort,
359
350
  manifest,
360
351
  parentSignal,
361
352
  timeoutMs,
@@ -399,7 +390,7 @@ export const runAdvisorScout = async (
399
390
  ]).size,
400
391
  usage: snapshotAdvisorUsage(streamed.streamed.usage),
401
392
  },
402
- model: executorModel,
393
+ model: executorRef,
403
394
  ok: true as const,
404
395
  selectedLabels: manifest.groups
405
396
  .filter(
@@ -1,15 +0,0 @@
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;