pi-advisor-flow 0.10.1-dev.1 → 0.11.1-dev.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,12 +4,17 @@ 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.11.0 - 2026-10-03
8
8
 
9
9
  ### Added
10
10
 
11
11
  - Native Pi Codemode composition for `ask_advisor`: scripts receive structured advice, IDs, normalized usage, and existing skip metadata, while interactive responses remain unchanged. Documented deterministic-check composition and explicit draft disclosure limits.
12
12
 
13
+ ### Fixed
14
+
15
+ - Advisor invocation guidelines no longer replace the whole system prompt, so prompt sections from other extensions, such as the list of MCP servers, still reach the model.
16
+ - Braces Vulnerability patched (CVE-2026-93687)
17
+
13
18
  ## 0.10.0 - 2026-10-02
14
19
 
15
20
  ### Added
package/dist/index.js CHANGED
@@ -1854,6 +1854,14 @@ var resolveConfiguredModel = async (ctx, ref, label) => {
1854
1854
  if (!model) {
1855
1855
  throw new Error(`${label} model not found: ${ref}`);
1856
1856
  }
1857
+ const { streamSimple } = ctx.modelRegistry;
1858
+ if (streamSimple) {
1859
+ return {
1860
+ model,
1861
+ ref,
1862
+ streamSimple: streamSimple.bind(ctx.modelRegistry)
1863
+ };
1864
+ }
1857
1865
  const auth = await ctx.modelRegistry.getApiKeyAndHeaders(model);
1858
1866
  if (!auth.ok) {
1859
1867
  throw new Error(auth.error);
@@ -1949,9 +1957,28 @@ var createCoalescedUpdate = (publish, intervalMs = ADVISOR_STREAM_UPDATE_INTERVA
1949
1957
  }
1950
1958
  };
1951
1959
  };
1952
- var collectTextStream = async (resolved, options, streamModel = stream) => {
1953
- let thinking = "";
1954
- let text = "";
1960
+ var SIMPLE_REASONING_LEVELS = ["minimal", "low", "medium", "high", "xhigh", "max"];
1961
+ var toSimpleReasoning = (effort) => {
1962
+ if (effort === undefined || effort === "off") {
1963
+ return;
1964
+ }
1965
+ const level = SIMPLE_REASONING_LEVELS.find((candidate) => candidate === effort);
1966
+ if (!level) {
1967
+ throw new Error(`Unsupported Advisor reasoning level: ${effort}`);
1968
+ }
1969
+ return level;
1970
+ };
1971
+ var createTextEventStream = (resolved, options, streamModel) => {
1972
+ const context = {
1973
+ messages: options.messages,
1974
+ systemPrompt: options.systemPrompt
1975
+ };
1976
+ if (!streamModel && resolved.streamSimple) {
1977
+ return resolved.streamSimple(resolved.model, context, {
1978
+ reasoning: toSimpleReasoning(options.reasoning),
1979
+ signal: options.signal
1980
+ });
1981
+ }
1955
1982
  const streamOptions = {
1956
1983
  apiKey: resolved.apiKey,
1957
1984
  env: resolved.env,
@@ -1962,7 +1989,12 @@ var collectTextStream = async (resolved, options, streamModel = stream) => {
1962
1989
  if (options.reasoning !== undefined) {
1963
1990
  streamOptions.reasoningEffort = options.reasoning;
1964
1991
  }
1965
- const eventStream = streamModel(resolved.model, { messages: options.messages, systemPrompt: options.systemPrompt }, streamOptions);
1992
+ return (streamModel ?? stream)(resolved.model, context, streamOptions);
1993
+ };
1994
+ var collectTextStream = async (resolved, options, streamModel) => {
1995
+ let thinking = "";
1996
+ let text = "";
1997
+ const eventStream = createTextEventStream(resolved, options, streamModel);
1966
1998
  for await (const event of eventStream) {
1967
1999
  if (event.type === "thinking_delta") {
1968
2000
  thinking += event.delta;
@@ -9025,7 +9057,9 @@ var registerToolLifecycle = ({
9025
9057
  ctx.ui.setStatus("advisor-usage", undefined);
9026
9058
  }
9027
9059
  });
9028
- pi.on("before_agent_start", (_event, ctx) => {
9060
+ pi.on("before_agent_start", (event, ctx) => {
9061
+ const { sections } = event.systemPromptOptions;
9062
+ delete sections.advisor_invocation_settings;
9029
9063
  if (!pi.getActiveTools().includes("ask_advisor")) {
9030
9064
  return;
9031
9065
  }
@@ -9039,13 +9073,11 @@ var registerToolLifecycle = ({
9039
9073
  guidelines.push(`Advisor calls remaining this session: ${budget}.
9040
9074
  Reserve calls for material decisions, repeated failures, or final review.`);
9041
9075
  }
9042
- return guidelines.length > 0 ? {
9043
- systemPrompt: `${ctx.getSystemPrompt()}
9044
-
9045
- Advisor invocation settings:
9076
+ if (guidelines.length > 0) {
9077
+ sections.advisor_invocation_settings = `Advisor invocation settings:
9046
9078
  ${guidelines.map((rule) => `- ${rule}`).join(`
9047
- `)}`
9048
- } : undefined;
9079
+ `)}`;
9080
+ }
9049
9081
  });
9050
9082
  pi.on("input", () => {
9051
9083
  session.clearFollowUps();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-advisor-flow",
3
- "version": "0.10.1-dev.1",
3
+ "version": "0.11.1-dev.1",
4
4
  "description": "Advanced Executor/Advisor flow for Pi, fully configurable and extendable.",
5
5
  "keywords": [
6
6
  "advisor",
@@ -93,6 +93,7 @@
93
93
  },
94
94
  "overrides": {
95
95
  "brace-expansion": "5.0.12",
96
+ "braces": "github:micromatch/braces#d0d575e55e74a4e0218e5248fafb79efc3e54ebb",
96
97
  "is-unicode-supported": "npm:@socketregistry/is-unicode-supported@1.0.5",
97
98
  "safe-buffer": "npm:@socketregistry/safe-buffer@1.0.9",
98
99
  "undici": "8.11.2"
@@ -2,19 +2,27 @@ import { stream } from "@earendil-works/pi-ai/compat";
2
2
  import type {
3
3
  Api,
4
4
  AssistantMessage,
5
+ AssistantMessageEventStream,
6
+ Context,
5
7
  Message,
6
8
  Model,
9
+ SimpleStreamOptions,
7
10
  } from "@earendil-works/pi-ai/compat";
8
11
  import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
9
12
 
10
13
  import { splitRef } from "./config/state.ts";
11
14
 
12
15
  export interface ResolvedConfiguredModel {
13
- apiKey: string;
16
+ apiKey?: string;
14
17
  env?: Record<string, string>;
15
18
  headers?: Record<string, string | null>;
16
19
  model: Model<Api>;
17
20
  ref: string;
21
+ streamSimple?: (
22
+ model: Model<Api>,
23
+ context: Context,
24
+ options?: SimpleStreamOptions
25
+ ) => AssistantMessageEventStream;
18
26
  }
19
27
 
20
28
  export const resolveConfiguredModel = async (
@@ -31,6 +39,14 @@ export const resolveConfiguredModel = async (
31
39
  if (!model) {
32
40
  throw new Error(`${label} model not found: ${ref}`);
33
41
  }
42
+ const { streamSimple } = ctx.modelRegistry;
43
+ if (streamSimple) {
44
+ return {
45
+ model,
46
+ ref,
47
+ streamSimple: streamSimple.bind(ctx.modelRegistry),
48
+ };
49
+ }
34
50
  const auth = await ctx.modelRegistry.getApiKeyAndHeaders(model);
35
51
  if (!auth.ok) {
36
52
  throw new Error(auth.error);
@@ -179,30 +195,61 @@ export const createCoalescedUpdate = <T>(
179
195
  };
180
196
  };
181
197
 
182
- export const collectTextStream = async (
198
+ const SIMPLE_REASONING_LEVELS: readonly NonNullable<
199
+ SimpleStreamOptions["reasoning"]
200
+ >[] = ["minimal", "low", "medium", "high", "xhigh", "max"];
201
+
202
+ const toSimpleReasoning = (
203
+ effort: string | undefined
204
+ ): SimpleStreamOptions["reasoning"] => {
205
+ if (effort === undefined || effort === "off") {
206
+ return undefined;
207
+ }
208
+ const level = SIMPLE_REASONING_LEVELS.find(
209
+ (candidate) => candidate === effort
210
+ );
211
+ if (!level) {
212
+ throw new Error(`Unsupported Advisor reasoning level: ${effort}`);
213
+ }
214
+ return level;
215
+ };
216
+
217
+ const createTextEventStream = (
183
218
  resolved: ResolvedConfiguredModel,
184
219
  options: CollectTextStreamOptions,
185
- streamModel: typeof stream = stream
186
- ): Promise<CollectedTextStream> => {
187
- let thinking = "";
188
- let text = "";
189
- const streamOptions: Parameters<typeof streamModel>[2] = {
220
+ streamModel?: typeof stream
221
+ ): AssistantMessageEventStream => {
222
+ const context: Context = {
223
+ messages: options.messages,
224
+ systemPrompt: options.systemPrompt,
225
+ };
226
+ if (!streamModel && resolved.streamSimple) {
227
+ return resolved.streamSimple(resolved.model, context, {
228
+ reasoning: toSimpleReasoning(options.reasoning),
229
+ signal: options.signal,
230
+ });
231
+ }
232
+ const streamOptions: NonNullable<Parameters<typeof stream>[2]> = {
190
233
  apiKey: resolved.apiKey,
191
234
  env: resolved.env,
192
235
  headers: resolved.headers,
193
- // SAFETY: stream() models the provider-facing reasoning field as never; options.reasoning is the Pi-facing effort string.
194
- reasoning: options.reasoning as never,
236
+ reasoning: options.reasoning,
195
237
  signal: options.signal,
196
238
  };
197
239
  if (options.reasoning !== undefined) {
198
- // SAFETY: reasoningEffort takes the same effort string; kept absent when reasoning is unset.
199
- streamOptions.reasoningEffort = options.reasoning as never;
240
+ streamOptions.reasoningEffort = options.reasoning;
200
241
  }
201
- const eventStream = streamModel(
202
- resolved.model,
203
- { messages: options.messages, systemPrompt: options.systemPrompt },
204
- streamOptions
205
- );
242
+ return (streamModel ?? stream)(resolved.model, context, streamOptions);
243
+ };
244
+
245
+ export const collectTextStream = async (
246
+ resolved: ResolvedConfiguredModel,
247
+ options: CollectTextStreamOptions,
248
+ streamModel?: typeof stream
249
+ ): Promise<CollectedTextStream> => {
250
+ let thinking = "";
251
+ let text = "";
252
+ const eventStream = createTextEventStream(resolved, options, streamModel);
206
253
 
207
254
  for await (const event of eventStream) {
208
255
  if (event.type === "thinking_delta") {
@@ -71,7 +71,9 @@ export const registerToolLifecycle = ({
71
71
  }
72
72
  });
73
73
 
74
- pi.on("before_agent_start", (_event, ctx) => {
74
+ pi.on("before_agent_start", (event, ctx) => {
75
+ const { sections } = event.systemPromptOptions;
76
+ delete sections.advisor_invocation_settings;
75
77
  if (!pi.getActiveTools().includes("ask_advisor")) {
76
78
  return;
77
79
  }
@@ -88,11 +90,9 @@ export const registerToolLifecycle = ({
88
90
  `Advisor calls remaining this session: ${budget}.\nReserve calls for material decisions, repeated failures, or final review.`
89
91
  );
90
92
  }
91
- return guidelines.length > 0
92
- ? {
93
- systemPrompt: `${ctx.getSystemPrompt()}\n\nAdvisor invocation settings:\n${guidelines.map((rule) => `- ${rule}`).join("\n")}`,
94
- }
95
- : undefined;
93
+ if (guidelines.length > 0) {
94
+ sections.advisor_invocation_settings = `Advisor invocation settings:\n${guidelines.map((rule) => `- ${rule}`).join("\n")}`;
95
+ }
96
96
  });
97
97
 
98
98
  pi.on("input", () => {