pi-spark 0.27.0 → 0.28.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
@@ -1,5 +1,25 @@
1
1
  # Changelog
2
2
 
3
+ ## [0.28.1](https://github.com/zlliang/pi-spark/compare/v0.28.0...v0.28.1) (2026-10-04)
4
+
5
+
6
+ ### Bug Fixes
7
+
8
+ * isolate background sessions for all providers, closes [#82](https://github.com/zlliang/pi-spark/issues/82) ([1ade72b](https://github.com/zlliang/pi-spark/commit/1ade72b71d2799ce3eeb0517f9ad0694f50e9d3a))
9
+ * **presets:** keep selector order and focus active preset ([b688b4d](https://github.com/zlliang/pi-spark/commit/b688b4dac32100e3c07e7d7d1dc84a8161d7f4b5))
10
+ * support Pi 1.0 ([c7bd177](https://github.com/zlliang/pi-spark/commit/c7bd1770e2d5134c6951be16a9c1fc5e5ab594fa))
11
+
12
+ ## [0.28.0](https://github.com/zlliang/pi-spark/compare/v0.27.0...v0.28.0) (2026-09-22)
13
+
14
+
15
+ ### ⚠ BREAKING CHANGES
16
+
17
+ * use Pi 0.87 context projections for recaps and titles
18
+
19
+ ### Bug Fixes
20
+
21
+ * use Pi 0.87 context projections for recaps and titles ([a822fa3](https://github.com/zlliang/pi-spark/commit/a822fa350f1146123d46a7dbf53d812947ff7b49))
22
+
3
23
  ## [0.27.0](https://github.com/zlliang/pi-spark/compare/v0.26.0...v0.27.0) (2026-09-20)
4
24
 
5
25
 
@@ -77,3 +77,5 @@ Use the [`measuring-model-cache`](../.agents/skills/measuring-model-cache/SKILL.
77
77
  ---
78
78
 
79
79
  **Update Sep 19, 2026:** Background calls now use Pi 0.86's `ctx.modelRegistry.streamSimple(...).result()` to support extension-registered providers and resolve authentication automatically. Independent Codex UUIDv7 sessions and cleanup in `finally` remain unchanged.
80
+
81
+ **Update Oct 4, 2026:** OpenCode also requires a session ID, sent as the `x-opencode-session` header. Every background call now gets an independent UUIDv7 session ID, regardless of provider.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "pi-spark",
3
- "version": "0.27.0",
3
+ "version": "0.28.1",
4
4
  "description": "Pi package that polishes your daily experience",
5
5
  "keywords": [
6
6
  "pi-coding-agent",
@@ -44,17 +44,17 @@
44
44
  "zod": "^4.4.3"
45
45
  },
46
46
  "peerDependencies": {
47
- "@earendil-works/pi-agent-core": ">=0.86.0",
48
- "@earendil-works/pi-ai": ">=0.86.0",
49
- "@earendil-works/pi-coding-agent": ">=0.86.0",
50
- "@earendil-works/pi-tui": ">=0.86.0",
47
+ "@earendil-works/pi-agent-core": ">=1.0.0",
48
+ "@earendil-works/pi-ai": ">=1.0.0",
49
+ "@earendil-works/pi-coding-agent": ">=1.0.0",
50
+ "@earendil-works/pi-tui": ">=1.0.0",
51
51
  "typebox": "*"
52
52
  },
53
53
  "devDependencies": {
54
- "@earendil-works/pi-agent-core": ">=0.86.0",
55
- "@earendil-works/pi-ai": ">=0.86.0",
56
- "@earendil-works/pi-coding-agent": ">=0.86.0",
57
- "@earendil-works/pi-tui": ">=0.86.0",
54
+ "@earendil-works/pi-agent-core": ">=1.0.0",
55
+ "@earendil-works/pi-ai": ">=1.0.0",
56
+ "@earendil-works/pi-coding-agent": ">=1.0.0",
57
+ "@earendil-works/pi-tui": ">=1.0.0",
58
58
  "@types/node": "*",
59
59
  "typebox": "*",
60
60
  "typescript": "^7.0.2"
@@ -1,4 +1,4 @@
1
- import { uuidv7 } from "@earendil-works/pi-agent-core";
1
+ import { uuidv7 } from "@earendil-works/pi-ai";
2
2
  import { readStoredCredential } from "@earendil-works/pi-coding-agent";
3
3
  import prettyMilliseconds from "pretty-ms";
4
4
 
@@ -12,13 +12,11 @@ export async function showPresetSelector(ctx: ExtensionContext, presetManager: P
12
12
  }
13
13
 
14
14
  const selected = await ctx.ui.custom<string | null>((tui, theme, _keybindings, done) => {
15
- const items = presetManager.keys
16
- .toSorted((a, b) => Number(presetManager.isActive(ctx, b)) - Number(presetManager.isActive(ctx, a)))
17
- .map((key) => ({
18
- value: key,
19
- label: presetManager.isActive(ctx, key) ? `${key} ${theme.fg("success", "✓")} ` : key,
20
- description: presetManager.describe(key),
21
- }));
15
+ const items = presetManager.keys.map((key) => ({
16
+ value: key,
17
+ label: presetManager.isActive(ctx, key) ? `${key} ${theme.fg("success", "✓")} ` : key,
18
+ description: presetManager.describe(key),
19
+ }));
22
20
 
23
21
  const container = new Container();
24
22
  container.addChild(new DynamicBorder((s: string) => theme.fg("border", s)));
@@ -34,6 +32,10 @@ export async function showPresetSelector(ctx: ExtensionContext, presetManager: P
34
32
  scrollInfo: (text) => theme.fg("dim", text),
35
33
  noMatch: (text) => theme.fg("warning", text),
36
34
  });
35
+
36
+ const activeIndex = presetManager.keys.findIndex((key) => presetManager.isActive(ctx, key));
37
+ if (activeIndex > 0) selectList.setSelectedIndex(activeIndex);
38
+
37
39
  selectList.onSelect = (item) => done(item.value);
38
40
  selectList.onCancel = () => done(null);
39
41
  box.addChild(selectList);
@@ -1,6 +1,6 @@
1
1
  import parseDuration from "parse-duration";
2
2
  import * as z from "zod";
3
- import { convertToLlm, sessionEntryToContextMessages } from "@earendil-works/pi-coding-agent";
3
+ import { convertToLlm } from "@earendil-works/pi-coding-agent";
4
4
 
5
5
  import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
6
6
 
@@ -69,7 +69,7 @@ export class IdleListener {
69
69
  }
70
70
 
71
71
  private check(ctx: ExtensionContext): void {
72
- const canEnter = ctx.isIdle() && ctx.sessionManager.buildContextEntries().some((entry) => convertToLlm(sessionEntryToContextMessages(entry)).length > 0);
72
+ const canEnter = ctx.isIdle() && convertToLlm(ctx.sessionManager.buildSessionProjection().messages).some((message) => message.role !== "system");
73
73
  if (!canEnter) {
74
74
  this.lastEditorText = undefined;
75
75
  if (this.entered) {
@@ -1,4 +1,4 @@
1
- import { convertToLlm, serializeConversation, sessionEntryToContextMessages } from "@earendil-works/pi-coding-agent";
1
+ import { convertToLlm, serializeConversation } from "@earendil-works/pi-coding-agent";
2
2
 
3
3
  import { clearRecapWidget, setRecapLoadingWidget, setRecapTextWidget } from "./widget";
4
4
  import { sanitizeText } from "../../utils/format";
@@ -109,7 +109,7 @@ export class RecapManager {
109
109
  }
110
110
 
111
111
  private buildPrompt(ctx: ExtensionContext): string {
112
- const messages = ctx.sessionManager.buildContextEntries().flatMap(sessionEntryToContextMessages);
112
+ const messages = ctx.sessionManager.buildSessionProjection().messages;
113
113
  const text = serializeConversation(convertToLlm(messages));
114
114
  const conversation = text.length > MAX_CONVERSATION_CHARS ? text.slice(-MAX_CONVERSATION_CHARS) : text;
115
115
 
@@ -91,7 +91,7 @@ export class TitleManager {
91
91
  }
92
92
 
93
93
  private buildPrompt(ctx: ExtensionContext): string {
94
- const messages = ctx.sessionManager.getBranch().filter((entry) => entry.type === "message").map((entry) => entry.message);
94
+ const messages = ctx.sessionManager.buildSessionProjection().messages;
95
95
  const text = serializeConversation(convertToLlm(messages));
96
96
  const conversation = text.length > MAX_CONVERSATION_CHARS ? text.slice(0, MAX_CONVERSATION_CHARS) : text;
97
97
 
@@ -1,5 +1,4 @@
1
- import { uuidv7 } from "@earendil-works/pi-agent-core";
2
- import { clampThinkingLevel, cleanupSessionResources } from "@earendil-works/pi-ai";
1
+ import { clampThinkingLevel, cleanupSessionResources, uuidv7 } from "@earendil-works/pi-ai";
3
2
 
4
3
  import { formatModel } from "./format";
5
4
 
@@ -26,12 +25,11 @@ type ThinkingLevelSelection = {
26
25
  };
27
26
 
28
27
  /**
29
- * Completes a one-shot background request, using an isolated session for OpenAI Codex models.
28
+ * Completes a one-shot background request in an isolated session, so providers that route by
29
+ * session, such as OpenAI Codex and OpenCode, keep it apart from the main thread.
30
30
  * See [the investigation](../../docs/background-model-calls-and-openai-codex-sessions.md).
31
31
  */
32
32
  export async function completeBackground(ctx: ExtensionContext, model: Model<Api>, context: Context, options?: ModelsSimpleStreamOptions): Promise<AssistantMessage> {
33
- if (model.api !== "openai-codex-responses") return ctx.modelRegistry.streamSimple(model, context, options).result();
34
-
35
33
  const sessionId = uuidv7();
36
34
 
37
35
  try {