mirror of
https://github.com/badlogic/pi-mono.git
synced 2026-11-05 23:37:25 +00:00
Merge remote-tracking branch 'origin/main' into dev
This commit is contained in:
commit
58ea6c0ba5
46 changed files with 540 additions and 206 deletions
|
|
@ -35,7 +35,7 @@
|
|||
- `packages/tui` (`node:test`): `node --test test/specific.test.ts`
|
||||
- If you create or modify a test file, run it and iterate on test or implementation until it passes.
|
||||
- For `packages/coding-agent/test/suite/`, use `test/suite/harness.ts` + the faux provider. No real provider APIs, keys, or paid tokens.
|
||||
- Put issue-specific regressions under `packages/coding-agent/test/suite/regressions/` named `<issue-number>-<short-slug>.test.ts`.
|
||||
- When regressions tests for fixing a github issue, add a comment with the github issue number next to the test.
|
||||
- For ad-hoc scripts, `write` them to a temp file (e.g. `/tmp`), run, edit if needed, remove when done. Don't embed multi-line scripts in `bash` commands.
|
||||
- Never commit unless the user asks.
|
||||
|
||||
|
|
|
|||
60
package-lock.json
generated
60
package-lock.json
generated
|
|
@ -5329,11 +5329,11 @@
|
|||
},
|
||||
"packages/agent": {
|
||||
"name": "@earendil-works/pi-agent-core",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@earendil-works/pi-ai": "^0.84.3",
|
||||
"@earendil-works/pi-telemetry": "^0.84.3",
|
||||
"@earendil-works/pi-ai": "^0.84.4",
|
||||
"@earendil-works/pi-telemetry": "^0.84.4",
|
||||
"diff": "8.0.4",
|
||||
"ignore": "7.0.5",
|
||||
"typebox": "1.3.7",
|
||||
|
|
@ -5358,12 +5358,12 @@
|
|||
},
|
||||
"packages/ai": {
|
||||
"name": "@earendil-works/pi-ai",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "0.91.1",
|
||||
"@aws-sdk/client-bedrock-runtime": "3.1048.0",
|
||||
"@earendil-works/pi-telemetry": "^0.84.3",
|
||||
"@earendil-works/pi-telemetry": "^0.84.4",
|
||||
"@google/genai": "1.52.0",
|
||||
"@smithy/node-http-handler": "4.7.3",
|
||||
"http-proxy-agent": "7.0.2",
|
||||
|
|
@ -5386,10 +5386,10 @@
|
|||
},
|
||||
"packages/client": {
|
||||
"name": "@earendil-works/pi-client",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@earendil-works/pi-protocol": "^0.84.3"
|
||||
"@earendil-works/pi-protocol": "^0.84.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"shx": "0.4.0",
|
||||
|
|
@ -5401,14 +5401,14 @@
|
|||
},
|
||||
"packages/coding-agent": {
|
||||
"name": "@earendil-works/pi-coding-agent",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@earendil-works/pi-agent-core": "^0.84.3",
|
||||
"@earendil-works/pi-ai": "^0.84.3",
|
||||
"@earendil-works/pi-client": "^0.84.3",
|
||||
"@earendil-works/pi-protocol": "^0.84.3",
|
||||
"@earendil-works/pi-tui": "^0.84.3",
|
||||
"@earendil-works/pi-agent-core": "^0.84.4",
|
||||
"@earendil-works/pi-ai": "^0.84.4",
|
||||
"@earendil-works/pi-client": "^0.84.4",
|
||||
"@earendil-works/pi-protocol": "^0.84.4",
|
||||
"@earendil-works/pi-tui": "^0.84.4",
|
||||
"@silvia-odwyer/photon-node": "0.3.4",
|
||||
"chalk": "5.6.2",
|
||||
"cross-spawn": "7.0.6",
|
||||
|
|
@ -5447,32 +5447,32 @@
|
|||
},
|
||||
"packages/coding-agent/examples/extensions/custom-provider-anthropic": {
|
||||
"name": "pi-extension-custom-provider-anthropic",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "0.52.0"
|
||||
}
|
||||
},
|
||||
"packages/coding-agent/examples/extensions/custom-provider-gitlab-duo": {
|
||||
"name": "pi-extension-custom-provider-gitlab-duo",
|
||||
"version": "0.84.3"
|
||||
"version": "0.84.4"
|
||||
},
|
||||
"packages/coding-agent/examples/extensions/gondolin": {
|
||||
"name": "pi-extension-gondolin",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"dependencies": {
|
||||
"@earendil-works/gondolin": "0.12.0"
|
||||
}
|
||||
},
|
||||
"packages/coding-agent/examples/extensions/sandbox": {
|
||||
"name": "pi-extension-sandbox",
|
||||
"version": "1.14.3",
|
||||
"version": "1.14.4",
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sandbox-runtime": "0.0.26"
|
||||
}
|
||||
},
|
||||
"packages/coding-agent/examples/extensions/with-deps": {
|
||||
"name": "pi-extension-with-deps",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"dependencies": {
|
||||
"ms": "2.1.3"
|
||||
},
|
||||
|
|
@ -5526,10 +5526,10 @@
|
|||
},
|
||||
"packages/evals": {
|
||||
"name": "@earendil-works/pi-evals",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"devDependencies": {
|
||||
"@earendil-works/pi-ai": "^0.84.3",
|
||||
"@earendil-works/pi-coding-agent": "^0.84.3",
|
||||
"@earendil-works/pi-ai": "^0.84.4",
|
||||
"@earendil-works/pi-coding-agent": "^0.84.4",
|
||||
"@types/node": "22.19.19",
|
||||
"shx": "0.4.0",
|
||||
"typescript": "5.9.3",
|
||||
|
|
@ -5539,7 +5539,7 @@
|
|||
},
|
||||
"packages/protocol": {
|
||||
"name": "@earendil-works/pi-protocol",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"typebox": "1.3.7"
|
||||
|
|
@ -5554,11 +5554,11 @@
|
|||
},
|
||||
"packages/server": {
|
||||
"name": "@earendil-works/pi-server",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@earendil-works/pi-agent-core": "^0.84.3",
|
||||
"@earendil-works/pi-protocol": "^0.84.3"
|
||||
"@earendil-works/pi-agent-core": "^0.84.4",
|
||||
"@earendil-works/pi-protocol": "^0.84.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"shx": "0.4.0",
|
||||
|
|
@ -5570,11 +5570,11 @@
|
|||
},
|
||||
"packages/session-backends/sqlite-node": {
|
||||
"name": "@earendil-works/pi-session-backend-sqlite-node",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@earendil-works/pi-agent-core": "^0.84.3",
|
||||
"@earendil-works/pi-ai": "^0.84.3"
|
||||
"@earendil-works/pi-agent-core": "^0.84.4",
|
||||
"@earendil-works/pi-ai": "^0.84.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitest/coverage-v8": "4.1.9",
|
||||
|
|
@ -5586,7 +5586,7 @@
|
|||
},
|
||||
"packages/telemetry": {
|
||||
"name": "@earendil-works/pi-telemetry",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"@types/node": "22.19.19",
|
||||
|
|
@ -5598,7 +5598,7 @@
|
|||
},
|
||||
"packages/tui": {
|
||||
"name": "@earendil-works/pi-tui",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"get-east-asian-width": "1.6.0",
|
||||
|
|
|
|||
|
|
@ -2,20 +2,11 @@
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.84.4] - 2026-08-28
|
||||
|
||||
### Breaking Changes
|
||||
|
||||
- Replaced the unfinished harness runtime and record-log session model with the shared entry/register/usage, operation-state, session, search, and public harness contracts specified for the durable harness.
|
||||
- Added the required replay-stable invocation metadata argument to `AgentHarnessTool.execute()`.
|
||||
- Required storage backends to return exact post-commit `SessionStats` in `CommitResult.stats`.
|
||||
|
||||
### Added
|
||||
|
||||
- Added scheduler-facing harness execution primitives (`accept`, fenced `drive`, `requestAbort`, and `inspectExecution`) plus replay-stable tool invocation identities.
|
||||
- Added isolated harness execution primitives for assistant streaming and durable-boundary tool phases.
|
||||
- Added direct-drive foundation primitives for split effect admission, deterministic commit gating, invocation-fenced progress writes, and injectable session id generation.
|
||||
- Added durable `AgentHarness` prompt acceptance and minimal no-tool execution with recovery, lifecycle events, usage settlement, and terminal cleanup.
|
||||
- Added assistant request recovery, durable retry waits, deferred suspension, and missing-identity suspension to `AgentHarness`.
|
||||
- Added durable tool planning, context-bound sequential and parallel execution, ordered result settlement, and safe tool replay recovery to `AgentHarness`.
|
||||
- Changed `prepareNextTurn` and `prepareNextTurnWithContext` to run only after `shouldStopAfterTurn` and queued-message checks determine that the agent loop will start another assistant turn. They no longer run after final or terminating turns; move end-of-run work to `agent_end` handling ([#6879](https://github.com/earendil-works/pi/issues/6879)).
|
||||
|
||||
### Fixed
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@earendil-works/pi-agent-core",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"description": "General-purpose agent with transport abstraction, state management, and attachment support",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
|
|
@ -55,8 +55,8 @@
|
|||
"prepublishOnly": "npm run build"
|
||||
},
|
||||
"dependencies": {
|
||||
"@earendil-works/pi-ai": "^0.84.3",
|
||||
"@earendil-works/pi-telemetry": "^0.84.3",
|
||||
"@earendil-works/pi-ai": "^0.84.4",
|
||||
"@earendil-works/pi-telemetry": "^0.84.4",
|
||||
"diff": "8.0.4",
|
||||
"ignore": "7.0.5",
|
||||
"typebox": "1.3.7",
|
||||
|
|
|
|||
|
|
@ -19,6 +19,7 @@ import type {
|
|||
AgentTool,
|
||||
AgentToolCall,
|
||||
AgentToolResult,
|
||||
PrepareNextTurnContext,
|
||||
StreamFn,
|
||||
} from "./types.ts";
|
||||
|
||||
|
|
@ -162,7 +163,7 @@ async function runLoop(
|
|||
): Promise<void> {
|
||||
let currentContext = initialContext;
|
||||
let config = initialConfig;
|
||||
let firstTurn = true;
|
||||
let lastCompletedTurn: PrepareNextTurnContext | undefined;
|
||||
// Check for steering messages at start (user may have typed while waiting)
|
||||
let pendingMessages: AgentMessage[] = (await config.getSteeringMessages?.()) || [];
|
||||
|
||||
|
|
@ -172,10 +173,28 @@ async function runLoop(
|
|||
|
||||
// Inner loop: process tool calls and steering messages
|
||||
while (hasMoreToolCalls || pendingMessages.length > 0) {
|
||||
if (!firstTurn) {
|
||||
if (lastCompletedTurn) {
|
||||
const nextTurnSnapshot = await config.prepareNextTurn?.(lastCompletedTurn);
|
||||
if (nextTurnSnapshot) {
|
||||
currentContext = nextTurnSnapshot.context ?? currentContext;
|
||||
config = {
|
||||
...config,
|
||||
model: nextTurnSnapshot.model ?? config.model,
|
||||
reasoning:
|
||||
nextTurnSnapshot.thinkingLevel === undefined
|
||||
? config.reasoning
|
||||
: nextTurnSnapshot.thinkingLevel === "off"
|
||||
? undefined
|
||||
: nextTurnSnapshot.thinkingLevel,
|
||||
};
|
||||
}
|
||||
// Preparation can be long-running (for example, compaction). Pick up steering
|
||||
// queued while it ran. Only poll again if the earlier poll returned nothing;
|
||||
// otherwise one-at-a-time mode would deliver two messages in this turn.
|
||||
if (pendingMessages.length === 0) {
|
||||
pendingMessages = (await config.getSteeringMessages?.()) || [];
|
||||
}
|
||||
await emit({ type: "turn_start" });
|
||||
} else {
|
||||
firstTurn = false;
|
||||
}
|
||||
|
||||
// Process pending messages (inject before next assistant response)
|
||||
|
|
@ -223,35 +242,14 @@ async function runLoop(
|
|||
|
||||
await emit({ type: "turn_end", message, toolResults });
|
||||
|
||||
const nextTurnContext = {
|
||||
lastCompletedTurn = {
|
||||
message,
|
||||
toolResults,
|
||||
context: currentContext,
|
||||
newMessages,
|
||||
};
|
||||
const nextTurnSnapshot = await config.prepareNextTurn?.(nextTurnContext);
|
||||
if (nextTurnSnapshot) {
|
||||
currentContext = nextTurnSnapshot.context ?? currentContext;
|
||||
config = {
|
||||
...config,
|
||||
model: nextTurnSnapshot.model ?? config.model,
|
||||
reasoning:
|
||||
nextTurnSnapshot.thinkingLevel === undefined
|
||||
? config.reasoning
|
||||
: nextTurnSnapshot.thinkingLevel === "off"
|
||||
? undefined
|
||||
: nextTurnSnapshot.thinkingLevel,
|
||||
};
|
||||
}
|
||||
|
||||
if (
|
||||
await config.shouldStopAfterTurn?.({
|
||||
message,
|
||||
toolResults,
|
||||
context: currentContext,
|
||||
newMessages,
|
||||
})
|
||||
) {
|
||||
if (await config.shouldStopAfterTurn?.(lastCompletedTurn)) {
|
||||
await emit({ type: "agent_end", messages: newMessages });
|
||||
return;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -214,6 +214,7 @@ export interface AgentLoopConfig extends SimpleStreamOptions {
|
|||
*
|
||||
* If it returns true, the loop emits `agent_end` and exits before polling steering or follow-up queues,
|
||||
* without starting another LLM call. The current assistant response and any tool executions finish normally.
|
||||
* This callback sees the completed-turn context and runs before `prepareNextTurn`.
|
||||
*
|
||||
* Use this to request a graceful stop after the current turn, e.g. before context gets too full.
|
||||
*
|
||||
|
|
@ -222,8 +223,8 @@ export interface AgentLoopConfig extends SimpleStreamOptions {
|
|||
shouldStopAfterTurn?: (context: ShouldStopAfterTurnContext) => boolean | Promise<boolean>;
|
||||
|
||||
/**
|
||||
* Called after `turn_end` and before the loop decides whether another provider request should start.
|
||||
* Return replacement context/model/thinking state to affect the next turn in this run.
|
||||
* Called after `turn_end` when the loop will continue, immediately before the next turn starts.
|
||||
* Return replacement context/model/thinking state to affect that turn.
|
||||
* Return undefined to keep using the current context/config.
|
||||
*/
|
||||
prepareNextTurn?: (
|
||||
|
|
|
|||
|
|
@ -1048,11 +1048,13 @@ describe("agentLoop with AgentMessage", () => {
|
|||
tools: [tool],
|
||||
};
|
||||
let convertedSecondTurnSystemPrompt = "";
|
||||
let prepareCalls = 0;
|
||||
let prepared = false;
|
||||
const config: AgentLoopConfig = {
|
||||
model: createModel(),
|
||||
convertToLlm: identityConverter,
|
||||
prepareNextTurn: async ({ context: currentContext }) => {
|
||||
prepareCalls++;
|
||||
if (prepared) return undefined;
|
||||
prepared = true;
|
||||
return {
|
||||
|
|
@ -1098,6 +1100,7 @@ describe("agentLoop with AgentMessage", () => {
|
|||
}
|
||||
|
||||
expect(llmCalls).toBe(2);
|
||||
expect(prepareCalls).toBe(1);
|
||||
expect(convertedSecondTurnSystemPrompt).toBe("second prompt");
|
||||
});
|
||||
|
||||
|
|
|
|||
|
|
@ -2,10 +2,20 @@
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.84.4] - 2026-08-28
|
||||
|
||||
### Added
|
||||
|
||||
- Added the experimental vision-capable `deepseek-v4-flash-vision-exp` model to the DeepSeek catalog.
|
||||
|
||||
### Fixed
|
||||
|
||||
- Fixed OpenAI-compatible Chat Completions ignoring an explicitly requested `toolChoice` when no tools are defined.
|
||||
- Fixed thinking signature serialization to run once after the signature is complete ([#8671](https://github.com/earendil-works/pi/pull/8671)).
|
||||
- Fixed fragmented Mistral tool calls splitting when continuation chunks omit the tool-call ID ([#8387](https://github.com/earendil-works/pi/issues/8387)).
|
||||
- Fixed OpenAI-compatible reasoning replay to merge consecutive streamed text and summary `reasoning_details` deltas.
|
||||
- Fixed the Cloudflare AI Gateway catalog to include supported `workers-ai/*` passthrough models omitted by models.dev.
|
||||
- Fixed OpenRouter reasoning controls by deriving `off` support and available effort levels from OpenRouter's model metadata, preventing reasoning-mandatory models from receiving `effort: "none"` ([#8614](https://github.com/earendil-works/pi/pull/8614) by [@davidbrai](https://github.com/davidbrai)).
|
||||
|
||||
## [0.84.3] - 2026-08-24
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@earendil-works/pi-ai",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"description": "Unified LLM API with automatic model discovery and provider configuration",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
|
|
@ -66,7 +66,7 @@
|
|||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "0.91.1",
|
||||
"@aws-sdk/client-bedrock-runtime": "3.1048.0",
|
||||
"@earendil-works/pi-telemetry": "^0.84.3",
|
||||
"@earendil-works/pi-telemetry": "^0.84.4",
|
||||
"@google/genai": "1.52.0",
|
||||
"@smithy/node-http-handler": "4.7.3",
|
||||
"http-proxy-agent": "7.0.2",
|
||||
|
|
|
|||
|
|
@ -561,7 +561,7 @@ async function consumeChatStream(
|
|||
let currentBlock: TextContent | ThinkingContent | null = null;
|
||||
const blocks = output.content;
|
||||
const blockIndex = () => blocks.length - 1;
|
||||
const toolBlocksByKey = new Map<string, number>();
|
||||
const toolBlocksByKey = new Map<string | number, number>();
|
||||
|
||||
const finishCurrentBlock = (block?: typeof currentBlock) => {
|
||||
if (!block) return;
|
||||
|
|
@ -690,7 +690,7 @@ async function consumeChatStream(
|
|||
toolCall.id && toolCall.id !== "null"
|
||||
? toolCall.id
|
||||
: deriveMistralToolCallId(`toolcall:${toolCall.index ?? 0}`, 0);
|
||||
const key = `${callId}:${toolCall.index || 0}`;
|
||||
const key = toolCall.index ?? callId;
|
||||
const existingIndex = toolBlocksByKey.get(key);
|
||||
let block: (ToolCall & { partialArgs?: string }) | undefined;
|
||||
|
||||
|
|
|
|||
|
|
@ -245,6 +245,21 @@ export const IMAGE_MODELS = {
|
|||
cacheWrite: 0,
|
||||
},
|
||||
} satisfies ImagesModel<"openrouter-images">,
|
||||
"meta/muse-image": {
|
||||
id: "meta/muse-image",
|
||||
name: "Meta: Muse Image",
|
||||
api: "openrouter-images",
|
||||
provider: "openrouter",
|
||||
baseUrl: "https://openrouter.ai/api/v1",
|
||||
input: ["text", "image"],
|
||||
output: ["image"],
|
||||
cost: {
|
||||
input: 0,
|
||||
output: 0,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
} satisfies ImagesModel<"openrouter-images">,
|
||||
"microsoft/mai-image-2.5": {
|
||||
id: "microsoft/mai-image-2.5",
|
||||
name: "Microsoft: MAI-Image-2.5",
|
||||
|
|
@ -485,6 +500,66 @@ export const IMAGE_MODELS = {
|
|||
cacheWrite: 0,
|
||||
},
|
||||
} satisfies ImagesModel<"openrouter-images">,
|
||||
"recraft/recraft-v4-styles": {
|
||||
id: "recraft/recraft-v4-styles",
|
||||
name: "Recraft: Recraft V4 Styles",
|
||||
api: "openrouter-images",
|
||||
provider: "openrouter",
|
||||
baseUrl: "https://openrouter.ai/api/v1",
|
||||
input: ["text", "image"],
|
||||
output: ["image"],
|
||||
cost: {
|
||||
input: 0,
|
||||
output: 0,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
} satisfies ImagesModel<"openrouter-images">,
|
||||
"recraft/recraft-v4-styles-pro": {
|
||||
id: "recraft/recraft-v4-styles-pro",
|
||||
name: "Recraft: Recraft V4 Styles Pro",
|
||||
api: "openrouter-images",
|
||||
provider: "openrouter",
|
||||
baseUrl: "https://openrouter.ai/api/v1",
|
||||
input: ["text", "image"],
|
||||
output: ["image"],
|
||||
cost: {
|
||||
input: 0,
|
||||
output: 0,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
} satisfies ImagesModel<"openrouter-images">,
|
||||
"recraft/recraft-v4-styles-pro-vector": {
|
||||
id: "recraft/recraft-v4-styles-pro-vector",
|
||||
name: "Recraft: Recraft V4 Styles Pro Vector",
|
||||
api: "openrouter-images",
|
||||
provider: "openrouter",
|
||||
baseUrl: "https://openrouter.ai/api/v1",
|
||||
input: ["text", "image"],
|
||||
output: ["image"],
|
||||
cost: {
|
||||
input: 0,
|
||||
output: 0,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
} satisfies ImagesModel<"openrouter-images">,
|
||||
"recraft/recraft-v4-styles-vector": {
|
||||
id: "recraft/recraft-v4-styles-vector",
|
||||
name: "Recraft: Recraft V4 Styles Vector",
|
||||
api: "openrouter-images",
|
||||
provider: "openrouter",
|
||||
baseUrl: "https://openrouter.ai/api/v1",
|
||||
input: ["text", "image"],
|
||||
output: ["image"],
|
||||
cost: {
|
||||
input: 0,
|
||||
output: 0,
|
||||
cacheRead: 0,
|
||||
cacheWrite: 0,
|
||||
},
|
||||
} satisfies ImagesModel<"openrouter-images">,
|
||||
"recraft/recraft-v4-vector": {
|
||||
id: "recraft/recraft-v4-vector",
|
||||
name: "Recraft: Recraft V4 Vector",
|
||||
|
|
|
|||
|
|
@ -235,7 +235,7 @@ describe("Mistral HTTP transport", () => {
|
|||
]);
|
||||
});
|
||||
|
||||
it("parses native thinking, text, tool calls, and cached-token usage", async () => {
|
||||
it("parses native thinking, text, fragmented tool calls, and cached-token usage", async () => {
|
||||
const model = getModel("mistral", "mistral-large-latest");
|
||||
const context: Context = {
|
||||
messages: [{ role: "user", content: "hello", timestamp: 1 }],
|
||||
|
|
@ -292,9 +292,8 @@ describe("Mistral HTTP transport", () => {
|
|||
delta: {
|
||||
tool_calls: [
|
||||
{
|
||||
id: "abc123456",
|
||||
index: 0,
|
||||
function: { name: "lookup", arguments: '"pi"}' },
|
||||
function: { name: "", arguments: '"pi"}' },
|
||||
},
|
||||
],
|
||||
},
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.84.4] - 2026-08-28
|
||||
|
||||
## [0.84.3] - 2026-08-24
|
||||
|
||||
## [0.84.2] - 2026-08-14
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@earendil-works/pi-client",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"description": "Transport-neutral client for remote pi sessions over framed CBOR bytes",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
|
|
@ -47,7 +47,7 @@
|
|||
"node": ">=22.19.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@earendil-works/pi-protocol": "^0.84.3"
|
||||
"@earendil-works/pi-protocol": "^0.84.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"shx": "0.4.0",
|
||||
|
|
|
|||
|
|
@ -2,9 +2,21 @@
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.84.4] - 2026-08-28
|
||||
|
||||
### New Features
|
||||
|
||||
- **Terminal capability overrides** — Override detected terminal hyperlink, image, and truecolor support. See [Capability Overrides](docs/terminal-setup.md#capability-overrides).
|
||||
- **Extension UI prompt events** — Integrations can distinguish active agent work from time spent waiting for `ctx.ui` prompts. See [Extension UI prompt events](docs/extensions.md#ui_prompt_start--ui_prompt_end).
|
||||
- **RPC queue clearing** — Retrieve and clear queued steering and follow-up messages with `clear_queue`. See [RPC `clear_queue`](docs/rpc.md#clear_queue).
|
||||
- **Fullscreen selection copy controls** — Disable automatic selection copying in fullscreen mode and use Ctrl+X to copy the active selection. See [UI & Display](docs/settings.md#ui--display).
|
||||
- **DeepSeek V4 Flash Vision (experimental)** — Use the vision-capable model through the built-in DeepSeek provider. See [API Keys](docs/providers.md#api-keys).
|
||||
|
||||
### Added
|
||||
|
||||
- Added `ui_prompt_start` and `ui_prompt_end` extension events so host integrations can distinguish active agent work from waiting on user-facing `ctx.ui` prompts ([#5329](https://github.com/earendil-works/pi/issues/5329)).
|
||||
- Added `ui_prompt_start` and `ui_prompt_end` extension events so host integrations can distinguish active agent work from waiting on user-facing `ctx.ui` prompts ([#8355](https://github.com/earendil-works/pi/pull/8355) by [@cristinaponcela](https://github.com/cristinaponcela)).
|
||||
- Added `detectSupportedImageMimeTypeFromFile()` to the public library exports ([#8600](https://github.com/earendil-works/pi/pull/8600) by [@xl0](https://github.com/xl0)).
|
||||
- Added inherited experimental vision-capable `deepseek-v4-flash-vision-exp` model support.
|
||||
- Added transcript usage notices for compaction and branch summaries when cache miss notices are enabled.
|
||||
- Added RPC `clear_queue` to retrieve and remove queued steering and follow-up messages ([#8432](https://github.com/earendil-works/pi/issues/8432)).
|
||||
- Added environment variables and advanced settings for overriding auto-detected terminal hyperlink, image, and truecolor capabilities ([#8665](https://github.com/earendil-works/pi/issues/8665)).
|
||||
|
|
@ -17,7 +29,18 @@
|
|||
- Fixed resumed sessions corrupting the next appended entry when their JSONL file lacks a trailing newline ([#8345](https://github.com/earendil-works/pi/issues/8345)).
|
||||
- Fixed extension messages sent with `triggerTurn: false` while the agent is running being inserted between a tool call and its result, which made providers that validate message order reject the replayed history. They are now appended once the turn's tool results are in ([#8537](https://github.com/earendil-works/pi/issues/8537)).
|
||||
- Fixed compaction and branch summaries forcing `toolChoice: "none"` ([#8649](https://github.com/earendil-works/pi/issues/8649), [#8638](https://github.com/earendil-works/pi/issues/8638)).
|
||||
- Fixed large tool results crossing the auto-compaction threshold being sent to the provider before compaction. Pi now compacts between tool execution and the next assistant response in the same run, and restores interactive progress when that run resumes ([#6879](https://github.com/earendil-works/pi/issues/6879)).
|
||||
- Fixed Google Vertex requests failing with `HttpsProxyAgent is not a constructor` when the bundled Node.js runtime uses an HTTP(S) proxy ([#8610](https://github.com/earendil-works/pi/issues/8610)).
|
||||
- Fixed saving a default model from a non-empty model scope so it remains available in that scope.
|
||||
- Fixed inherited `@` file autocomplete ranking to prefer direct and shallower matches over similarly ranked nested paths ([#8669](https://github.com/earendil-works/pi/pull/8669)).
|
||||
- Fixed inherited OpenAI-compatible streams serializing thinking signatures repeatedly during streaming ([#8671](https://github.com/earendil-works/pi/pull/8671)).
|
||||
- Fixed inherited main-screen rendering crashing when image-heavy output exceeded V8's string length limit ([#8028](https://github.com/earendil-works/pi/issues/8028)).
|
||||
- Fixed inherited fullscreen double-click word selection splitting paths and kebab-case tokens on `/` and `-` ([#8676](https://github.com/earendil-works/pi/pull/8676)).
|
||||
- Fixed inherited Cloudflare AI Gateway catalogs omitting supported `workers-ai/*` passthrough models.
|
||||
- Fixed inherited OpenAI-compatible reasoning replay to merge consecutive streamed text and summary `reasoning_details` deltas.
|
||||
- Fixed inherited OpenRouter reasoning controls so reasoning-mandatory models do not receive `effort: "none"` ([#8614](https://github.com/earendil-works/pi/pull/8614) by [@davidbrai](https://github.com/davidbrai)).
|
||||
- Fixed inherited OpenAI-compatible Chat Completions ignoring an explicitly requested `toolChoice` when no tools are defined.
|
||||
- Fixed inherited fragmented Mistral tool calls splitting when continuation chunks omit the tool-call ID ([#8387](https://github.com/earendil-works/pi/issues/8387)).
|
||||
|
||||
## [0.84.3] - 2026-08-24
|
||||
|
||||
|
|
@ -86,7 +109,7 @@
|
|||
- Added `session_compact_failed` extension events so compaction failures and aborts expose their reason, retry state, source, and error message to handlers ([#8175](https://github.com/earendil-works/pi/issues/8175)).
|
||||
- Fixed truncated compaction and branch summaries being persisted when generation reaches its output token limit ([#7048](https://github.com/earendil-works/pi/issues/7048)).
|
||||
- Fixed npm package update checks treating older registry versions as available updates, preventing `pi update` from downgrading already-newer installed packages ([#8226](https://github.com/earendil-works/pi/issues/8226)).
|
||||
- Fixed built-in llama.cpp models disappearing from `/model` when `/llama` refreshed a configured server under `PI_OFFLINE`, and included idle-slept `sleeping` router models plus autoloadable unloaded presets in the selectable catalog ([#8167](https://github.com/earendil-works/pi/issues/8167)).
|
||||
- Fixed built-in llama.cpp models disappearing from `/model` when `/llama` refreshed a configured server under `PI_OFFLINE`, and included idle-slept `sleeping` router models plus autoloadable unloaded presets in the selectable catalog ([#8558](https://github.com/earendil-works/pi/pull/8558) by [@cristinaponcela](https://github.com/cristinaponcela)).
|
||||
- Fixed `pi.registerFlag()` accepting default values that do not match the declared flag type ([#8064](https://github.com/earendil-works/pi/issues/8064)).
|
||||
- Fixed Z.AI Coding Plan defaults referencing the removed GLM-5.1 model ([#8096](https://github.com/earendil-works/pi/issues/8096)).
|
||||
- Fixed repeated ambiguous truncated-response recovery being mislabeled as context overflow ([#8130](https://github.com/earendil-works/pi/issues/8130)).
|
||||
|
|
|
|||
|
|
@ -34,6 +34,8 @@ contextTokens > contextWindow - reserveTokens
|
|||
|
||||
By default, `reserveTokens` is 16384 tokens (configurable in `~/.pi/agent/settings.json` or `<project-dir>/.pi/settings.json`). This leaves room for the LLM's response.
|
||||
|
||||
During a multi-turn agent run, Pi checks this threshold after tools finish and their results are appended, before starting the next assistant response. If the threshold is crossed, Pi compacts inside the same agent run and resumes with the summary and retained messages. It skips this between-turn check when the completed tool batch terminates the run and no queued message requires another response. Pi also checks the threshold before a new user prompt and after a low-level agent run ends.
|
||||
|
||||
You can also trigger manually with `/compact [instructions]`, where optional instructions focus the summary.
|
||||
|
||||
### How It Works
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "pi-extension-custom-provider",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "pi-extension-custom-provider",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "^0.52.0"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "pi-extension-custom-provider-anthropic",
|
||||
"private": true,
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"clean": "echo 'nothing to clean'",
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "pi-extension-custom-provider-gitlab-duo",
|
||||
"private": true,
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"clean": "echo 'nothing to clean'",
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "pi-extension-gondolin",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "pi-extension-gondolin",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"dependencies": {
|
||||
"@earendil-works/gondolin": "0.12.0"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "pi-extension-gondolin",
|
||||
"private": true,
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"clean": "echo 'nothing to clean'",
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "pi-extension-sandbox",
|
||||
"version": "1.14.3",
|
||||
"version": "1.14.4",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "pi-extension-sandbox",
|
||||
"version": "1.14.3",
|
||||
"version": "1.14.4",
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sandbox-runtime": "^0.0.26"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "pi-extension-sandbox",
|
||||
"private": true,
|
||||
"version": "1.14.3",
|
||||
"version": "1.14.4",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"clean": "echo 'nothing to clean'",
|
||||
|
|
|
|||
|
|
@ -1,12 +1,12 @@
|
|||
{
|
||||
"name": "pi-extension-with-deps",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "pi-extension-with-deps",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"dependencies": {
|
||||
"ms": "^2.1.3"
|
||||
},
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "pi-extension-with-deps",
|
||||
"private": true,
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"clean": "echo 'nothing to clean'",
|
||||
|
|
|
|||
52
packages/coding-agent/install-lock/package-lock.json
generated
52
packages/coding-agent/install-lock/package-lock.json
generated
|
|
@ -1,14 +1,14 @@
|
|||
{
|
||||
"name": "@earendil-works/pi-coding-agent-install",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@earendil-works/pi-coding-agent-install",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"dependencies": {
|
||||
"@earendil-works/pi-coding-agent": "0.84.3"
|
||||
"@earendil-works/pi-coding-agent": "0.84.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22.19.0"
|
||||
|
|
@ -450,12 +450,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@earendil-works/pi-agent-core": {
|
||||
"version": "0.84.3",
|
||||
"resolved": "https://registry.npmjs.org/@earendil-works/pi-agent-core/-/pi-agent-core-0.84.3.tgz",
|
||||
"version": "0.84.4",
|
||||
"resolved": "https://registry.npmjs.org/@earendil-works/pi-agent-core/-/pi-agent-core-0.84.4.tgz",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@earendil-works/pi-ai": "^0.84.3",
|
||||
"@earendil-works/pi-telemetry": "^0.84.3",
|
||||
"@earendil-works/pi-ai": "^0.84.4",
|
||||
"@earendil-works/pi-telemetry": "^0.84.4",
|
||||
"diff": "8.0.4",
|
||||
"ignore": "7.0.5",
|
||||
"typebox": "1.3.7",
|
||||
|
|
@ -466,13 +466,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@earendil-works/pi-ai": {
|
||||
"version": "0.84.3",
|
||||
"resolved": "https://registry.npmjs.org/@earendil-works/pi-ai/-/pi-ai-0.84.3.tgz",
|
||||
"version": "0.84.4",
|
||||
"resolved": "https://registry.npmjs.org/@earendil-works/pi-ai/-/pi-ai-0.84.4.tgz",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "0.91.1",
|
||||
"@aws-sdk/client-bedrock-runtime": "3.1048.0",
|
||||
"@earendil-works/pi-telemetry": "^0.84.3",
|
||||
"@earendil-works/pi-telemetry": "^0.84.4",
|
||||
"@google/genai": "1.52.0",
|
||||
"@smithy/node-http-handler": "4.7.3",
|
||||
"http-proxy-agent": "7.0.2",
|
||||
|
|
@ -489,26 +489,26 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@earendil-works/pi-client": {
|
||||
"version": "0.84.3",
|
||||
"resolved": "https://registry.npmjs.org/@earendil-works/pi-client/-/pi-client-0.84.3.tgz",
|
||||
"version": "0.84.4",
|
||||
"resolved": "https://registry.npmjs.org/@earendil-works/pi-client/-/pi-client-0.84.4.tgz",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@earendil-works/pi-protocol": "^0.84.3"
|
||||
"@earendil-works/pi-protocol": "^0.84.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22.19.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@earendil-works/pi-coding-agent": {
|
||||
"version": "0.84.3",
|
||||
"resolved": "https://registry.npmjs.org/@earendil-works/pi-coding-agent/-/pi-coding-agent-0.84.3.tgz",
|
||||
"version": "0.84.4",
|
||||
"resolved": "https://registry.npmjs.org/@earendil-works/pi-coding-agent/-/pi-coding-agent-0.84.4.tgz",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@earendil-works/pi-agent-core": "^0.84.3",
|
||||
"@earendil-works/pi-ai": "^0.84.3",
|
||||
"@earendil-works/pi-client": "^0.84.3",
|
||||
"@earendil-works/pi-protocol": "^0.84.3",
|
||||
"@earendil-works/pi-tui": "^0.84.3",
|
||||
"@earendil-works/pi-agent-core": "^0.84.4",
|
||||
"@earendil-works/pi-ai": "^0.84.4",
|
||||
"@earendil-works/pi-client": "^0.84.4",
|
||||
"@earendil-works/pi-protocol": "^0.84.4",
|
||||
"@earendil-works/pi-tui": "^0.84.4",
|
||||
"@silvia-odwyer/photon-node": "0.3.4",
|
||||
"chalk": "5.6.2",
|
||||
"cross-spawn": "7.0.6",
|
||||
|
|
@ -536,8 +536,8 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@earendil-works/pi-protocol": {
|
||||
"version": "0.84.3",
|
||||
"resolved": "https://registry.npmjs.org/@earendil-works/pi-protocol/-/pi-protocol-0.84.3.tgz",
|
||||
"version": "0.84.4",
|
||||
"resolved": "https://registry.npmjs.org/@earendil-works/pi-protocol/-/pi-protocol-0.84.4.tgz",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"typebox": "1.3.7"
|
||||
|
|
@ -547,16 +547,16 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@earendil-works/pi-telemetry": {
|
||||
"version": "0.84.3",
|
||||
"resolved": "https://registry.npmjs.org/@earendil-works/pi-telemetry/-/pi-telemetry-0.84.3.tgz",
|
||||
"version": "0.84.4",
|
||||
"resolved": "https://registry.npmjs.org/@earendil-works/pi-telemetry/-/pi-telemetry-0.84.4.tgz",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=22.19.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@earendil-works/pi-tui": {
|
||||
"version": "0.84.3",
|
||||
"resolved": "https://registry.npmjs.org/@earendil-works/pi-tui/-/pi-tui-0.84.3.tgz",
|
||||
"version": "0.84.4",
|
||||
"resolved": "https://registry.npmjs.org/@earendil-works/pi-tui/-/pi-tui-0.84.4.tgz",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"get-east-asian-width": "1.6.0",
|
||||
|
|
|
|||
|
|
@ -1,10 +1,10 @@
|
|||
{
|
||||
"name": "@earendil-works/pi-coding-agent-install",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"private": true,
|
||||
"description": "Lockfile root used by the Pi installer and updater.",
|
||||
"dependencies": {
|
||||
"@earendil-works/pi-coding-agent": "0.84.3"
|
||||
"@earendil-works/pi-coding-agent": "0.84.4"
|
||||
},
|
||||
"overrides": {
|
||||
"protobufjs": "7.6.5",
|
||||
|
|
|
|||
46
packages/coding-agent/npm-shrinkwrap.json
generated
46
packages/coding-agent/npm-shrinkwrap.json
generated
|
|
@ -1,19 +1,19 @@
|
|||
{
|
||||
"name": "@earendil-works/pi-coding-agent",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@earendil-works/pi-coding-agent",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@earendil-works/pi-agent-core": "^0.84.3",
|
||||
"@earendil-works/pi-ai": "^0.84.3",
|
||||
"@earendil-works/pi-client": "^0.84.3",
|
||||
"@earendil-works/pi-protocol": "^0.84.3",
|
||||
"@earendil-works/pi-tui": "^0.84.3",
|
||||
"@earendil-works/pi-agent-core": "^0.84.4",
|
||||
"@earendil-works/pi-ai": "^0.84.4",
|
||||
"@earendil-works/pi-client": "^0.84.4",
|
||||
"@earendil-works/pi-protocol": "^0.84.4",
|
||||
"@earendil-works/pi-tui": "^0.84.4",
|
||||
"@silvia-odwyer/photon-node": "0.3.4",
|
||||
"chalk": "5.6.2",
|
||||
"cross-spawn": "7.0.6",
|
||||
|
|
@ -476,12 +476,12 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@earendil-works/pi-agent-core": {
|
||||
"version": "0.84.3",
|
||||
"resolved": "https://registry.npmjs.org/@earendil-works/pi-agent-core/-/pi-agent-core-0.84.3.tgz",
|
||||
"version": "0.84.4",
|
||||
"resolved": "https://registry.npmjs.org/@earendil-works/pi-agent-core/-/pi-agent-core-0.84.4.tgz",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@earendil-works/pi-ai": "^0.84.3",
|
||||
"@earendil-works/pi-telemetry": "^0.84.3",
|
||||
"@earendil-works/pi-ai": "^0.84.4",
|
||||
"@earendil-works/pi-telemetry": "^0.84.4",
|
||||
"diff": "8.0.4",
|
||||
"ignore": "7.0.5",
|
||||
"typebox": "1.3.7",
|
||||
|
|
@ -492,13 +492,13 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@earendil-works/pi-ai": {
|
||||
"version": "0.84.3",
|
||||
"resolved": "https://registry.npmjs.org/@earendil-works/pi-ai/-/pi-ai-0.84.3.tgz",
|
||||
"version": "0.84.4",
|
||||
"resolved": "https://registry.npmjs.org/@earendil-works/pi-ai/-/pi-ai-0.84.4.tgz",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@anthropic-ai/sdk": "0.91.1",
|
||||
"@aws-sdk/client-bedrock-runtime": "3.1048.0",
|
||||
"@earendil-works/pi-telemetry": "^0.84.3",
|
||||
"@earendil-works/pi-telemetry": "^0.84.4",
|
||||
"@google/genai": "1.52.0",
|
||||
"@smithy/node-http-handler": "4.7.3",
|
||||
"http-proxy-agent": "7.0.2",
|
||||
|
|
@ -515,19 +515,19 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@earendil-works/pi-client": {
|
||||
"version": "0.84.3",
|
||||
"resolved": "https://registry.npmjs.org/@earendil-works/pi-client/-/pi-client-0.84.3.tgz",
|
||||
"version": "0.84.4",
|
||||
"resolved": "https://registry.npmjs.org/@earendil-works/pi-client/-/pi-client-0.84.4.tgz",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@earendil-works/pi-protocol": "^0.84.3"
|
||||
"@earendil-works/pi-protocol": "^0.84.4"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=22.19.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@earendil-works/pi-protocol": {
|
||||
"version": "0.84.3",
|
||||
"resolved": "https://registry.npmjs.org/@earendil-works/pi-protocol/-/pi-protocol-0.84.3.tgz",
|
||||
"version": "0.84.4",
|
||||
"resolved": "https://registry.npmjs.org/@earendil-works/pi-protocol/-/pi-protocol-0.84.4.tgz",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"typebox": "1.3.7"
|
||||
|
|
@ -537,16 +537,16 @@
|
|||
}
|
||||
},
|
||||
"node_modules/@earendil-works/pi-telemetry": {
|
||||
"version": "0.84.3",
|
||||
"resolved": "https://registry.npmjs.org/@earendil-works/pi-telemetry/-/pi-telemetry-0.84.3.tgz",
|
||||
"version": "0.84.4",
|
||||
"resolved": "https://registry.npmjs.org/@earendil-works/pi-telemetry/-/pi-telemetry-0.84.4.tgz",
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=22.19.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@earendil-works/pi-tui": {
|
||||
"version": "0.84.3",
|
||||
"resolved": "https://registry.npmjs.org/@earendil-works/pi-tui/-/pi-tui-0.84.3.tgz",
|
||||
"version": "0.84.4",
|
||||
"resolved": "https://registry.npmjs.org/@earendil-works/pi-tui/-/pi-tui-0.84.4.tgz",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"get-east-asian-width": "1.6.0",
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@earendil-works/pi-coding-agent",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"description": "Coding agent CLI with read, bash, edit, write tools and session management",
|
||||
"type": "module",
|
||||
"piConfig": {
|
||||
|
|
@ -44,11 +44,11 @@
|
|||
"prepublishOnly": "npm run clean && npm run build && npm run shrinkwrap"
|
||||
},
|
||||
"dependencies": {
|
||||
"@earendil-works/pi-agent-core": "^0.84.3",
|
||||
"@earendil-works/pi-ai": "^0.84.3",
|
||||
"@earendil-works/pi-client": "^0.84.3",
|
||||
"@earendil-works/pi-protocol": "^0.84.3",
|
||||
"@earendil-works/pi-tui": "^0.84.3",
|
||||
"@earendil-works/pi-agent-core": "^0.84.4",
|
||||
"@earendil-works/pi-ai": "^0.84.4",
|
||||
"@earendil-works/pi-client": "^0.84.4",
|
||||
"@earendil-works/pi-protocol": "^0.84.4",
|
||||
"@earendil-works/pi-tui": "^0.84.4",
|
||||
"@silvia-odwyer/photon-node": "0.3.4",
|
||||
"chalk": "5.6.2",
|
||||
"cross-spawn": "7.0.6",
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ import { readFileSync } from "node:fs";
|
|||
import { basename, dirname } from "node:path";
|
||||
import type {
|
||||
Agent,
|
||||
AgentContext,
|
||||
AgentEvent,
|
||||
AgentMessage,
|
||||
AgentState,
|
||||
|
|
@ -539,6 +540,25 @@ export class AgentSession {
|
|||
};
|
||||
}
|
||||
|
||||
private async _compactBeforeNextAssistantResponse(context: AgentContext): Promise<AgentContext> {
|
||||
const model = this.model;
|
||||
const settings = this.settingsManager.getCompactionSettings();
|
||||
|
||||
if (
|
||||
!model ||
|
||||
model.contextWindow <= 0 ||
|
||||
!shouldCompact(estimateContextTokens(context.messages).tokens, model.contextWindow, settings)
|
||||
) {
|
||||
return context;
|
||||
}
|
||||
|
||||
await this._runAutoCompaction("threshold", false);
|
||||
return {
|
||||
...context,
|
||||
messages: this.agent.state.messages.slice(),
|
||||
};
|
||||
}
|
||||
|
||||
private _installAgentNextTurnRefresh(): void {
|
||||
const previousPrepareNextTurnWithContext =
|
||||
this.agent.prepareNextTurnWithContext ??
|
||||
|
|
@ -546,13 +566,14 @@ export class AgentSession {
|
|||
? async (_turn: PrepareNextTurnContext, signal?: AbortSignal) => await this.agent.prepareNextTurn?.(signal)
|
||||
: undefined);
|
||||
this.agent.prepareNextTurnWithContext = async (turn, signal) => {
|
||||
const previousSnapshot = await previousPrepareNextTurnWithContext?.(turn, signal);
|
||||
const previousContext = previousSnapshot?.context ?? turn.context;
|
||||
const context = await this._compactBeforeNextAssistantResponse(turn.context);
|
||||
const previousSnapshot = await previousPrepareNextTurnWithContext?.({ ...turn, context }, signal);
|
||||
const nextContext = previousSnapshot?.context ?? context;
|
||||
|
||||
return {
|
||||
...previousSnapshot,
|
||||
context: {
|
||||
...previousContext,
|
||||
...nextContext,
|
||||
systemPrompt: this._systemPromptOverride ?? this._baseSystemPrompt,
|
||||
tools: this.agent.state.tools.slice(),
|
||||
},
|
||||
|
|
|
|||
|
|
@ -2095,6 +2095,16 @@ export class InteractiveMode {
|
|||
}
|
||||
}
|
||||
|
||||
private showWorkingStatusIndicator(): void {
|
||||
this.showStatusIndicator(
|
||||
new WorkingStatusIndicator(
|
||||
this.ui,
|
||||
this.workingMessage ?? this.defaultWorkingMessage,
|
||||
this.workingIndicatorOptions,
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
private setWorkingVisible(visible: boolean): void {
|
||||
this.workingVisible = visible;
|
||||
if (!visible) {
|
||||
|
|
@ -2103,13 +2113,7 @@ export class InteractiveMode {
|
|||
return;
|
||||
}
|
||||
if (this.session.isStreaming && this.activeStatusIndicator?.kind !== "working") {
|
||||
this.showStatusIndicator(
|
||||
new WorkingStatusIndicator(
|
||||
this.ui,
|
||||
this.workingMessage ?? this.defaultWorkingMessage,
|
||||
this.workingIndicatorOptions,
|
||||
),
|
||||
);
|
||||
this.showWorkingStatusIndicator();
|
||||
}
|
||||
this.ui.requestRender();
|
||||
}
|
||||
|
|
@ -3118,23 +3122,22 @@ export class InteractiveMode {
|
|||
switch (event.type) {
|
||||
case "agent_start":
|
||||
this.pendingTools.clear();
|
||||
if (this.settingsManager.getShowTerminalProgress()) {
|
||||
this.ui.terminal.setProgress(true);
|
||||
}
|
||||
// Restore main escape handler if retry handler is still active
|
||||
// (retry success event fires later, but we need main handler now)
|
||||
if (this.retryEscapeHandler) {
|
||||
this.defaultEditor.onEscape = this.retryEscapeHandler;
|
||||
this.retryEscapeHandler = undefined;
|
||||
}
|
||||
break;
|
||||
|
||||
case "turn_start":
|
||||
if (this.settingsManager.getShowTerminalProgress()) {
|
||||
this.ui.terminal.setProgress(true);
|
||||
}
|
||||
if (this.workingVisible) {
|
||||
this.showStatusIndicator(
|
||||
new WorkingStatusIndicator(
|
||||
this.ui,
|
||||
this.workingMessage ?? this.defaultWorkingMessage,
|
||||
this.workingIndicatorOptions,
|
||||
),
|
||||
);
|
||||
if (this.activeStatusIndicator?.kind !== "working") {
|
||||
this.showWorkingStatusIndicator();
|
||||
}
|
||||
} else {
|
||||
this.clearStatusIndicator();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -197,6 +197,37 @@ describe("InteractiveMode compaction events", () => {
|
|||
expect(fakeThis.flushCompactionQueue).toHaveBeenCalledWith({ willRetry: false });
|
||||
});
|
||||
|
||||
test("updates the working state when the same agent run resumes after compaction", async () => {
|
||||
const fakeThis = {
|
||||
isInitialized: true,
|
||||
footer: { invalidate: vi.fn() },
|
||||
activeStatusIndicator: undefined,
|
||||
workingVisible: true,
|
||||
showWorkingStatusIndicator: vi.fn(),
|
||||
clearStatusIndicator: vi.fn(),
|
||||
settingsManager: { getShowTerminalProgress: () => true },
|
||||
ui: { requestRender: vi.fn(), terminal: { setProgress: vi.fn() } },
|
||||
};
|
||||
const handleEvent = Reflect.get(InteractiveMode.prototype, "handleEvent") as (
|
||||
this: typeof fakeThis,
|
||||
event: { type: "turn_start" },
|
||||
) => Promise<void>;
|
||||
|
||||
await handleEvent.call(fakeThis, { type: "turn_start" });
|
||||
|
||||
expect(fakeThis.ui.terminal.setProgress).toHaveBeenCalledWith(true);
|
||||
expect(fakeThis.showWorkingStatusIndicator).toHaveBeenCalledTimes(1);
|
||||
expect(fakeThis.clearStatusIndicator).not.toHaveBeenCalled();
|
||||
expect(fakeThis.ui.requestRender).toHaveBeenCalledTimes(1);
|
||||
|
||||
fakeThis.workingVisible = false;
|
||||
await handleEvent.call(fakeThis, { type: "turn_start" });
|
||||
|
||||
expect(fakeThis.showWorkingStatusIndicator).toHaveBeenCalledTimes(1);
|
||||
expect(fakeThis.clearStatusIndicator).toHaveBeenCalledTimes(1);
|
||||
expect(fakeThis.ui.requestRender).toHaveBeenCalledTimes(2);
|
||||
});
|
||||
|
||||
test("preserves steering behavior when flushing into an active agent run", async () => {
|
||||
const fakeThis = {
|
||||
compactionQueuedMessages: [{ text: "change direction", mode: "steer" as const }],
|
||||
|
|
|
|||
|
|
@ -8,9 +8,3 @@ Rules:
|
|||
- Do not use real provider APIs, real API keys, network calls, or paid tokens
|
||||
- Keep these tests CI-safe and deterministic
|
||||
- Do not use or extend the legacy `test/test-harness.ts` path unless a missing capability forces it
|
||||
|
||||
Organization:
|
||||
- Put broad lifecycle and characterization tests directly under `test/suite/`
|
||||
- Put issue-specific regression tests under `test/suite/regressions/`
|
||||
- Name regression tests as `<issue-number>-<short-slug>.test.ts`
|
||||
- Example: `test/suite/regressions/2023-queued-slash-command-followup.test.ts`
|
||||
|
|
|
|||
|
|
@ -1,12 +1,14 @@
|
|||
import type { AgentMessage } from "@earendil-works/pi-agent-core";
|
||||
import type { AgentMessage, AgentTool } from "@earendil-works/pi-agent-core";
|
||||
import {
|
||||
type AssistantMessage,
|
||||
type Context,
|
||||
createAssistantMessageEventStream,
|
||||
fauxAssistantMessage,
|
||||
fauxToolCall,
|
||||
type Model,
|
||||
type SimpleStreamOptions,
|
||||
} from "@earendil-works/pi-ai";
|
||||
import { Type } from "typebox";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { estimateTokens } from "../../src/core/compaction/index.ts";
|
||||
import { createHarness, getUserTexts, type Harness } from "./harness.ts";
|
||||
|
|
@ -392,6 +394,175 @@ describe("AgentSession compaction characterization", () => {
|
|||
expect(harness.session.getLastAssistantText()).toBe("completed response");
|
||||
});
|
||||
|
||||
it("compacts after a tool result before the next assistant request in the same run", async () => {
|
||||
const toolResult = `large-tool-result:${"x".repeat(6800)}`;
|
||||
const largeTool: AgentTool = {
|
||||
name: "large_result",
|
||||
label: "Large result",
|
||||
description: "Returns enough content to cross the compaction threshold",
|
||||
parameters: Type.Object({}),
|
||||
execute: async () => ({ content: [{ type: "text", text: toolResult }], details: {} }),
|
||||
};
|
||||
const order: string[] = [];
|
||||
const harness = await createHarness({
|
||||
models: [{ id: "faux-1", contextWindow: 2600, maxTokens: 100 }],
|
||||
settings: { compaction: { enabled: true, reserveTokens: 400, keepRecentTokens: 1750 } },
|
||||
tools: [largeTool],
|
||||
extensionFactories: [
|
||||
(pi) => {
|
||||
pi.on("session_before_compact", (event) => {
|
||||
order.push("compaction");
|
||||
return {
|
||||
compaction: {
|
||||
summary: "compacted history",
|
||||
firstKeptEntryId: event.preparation.firstKeptEntryId,
|
||||
tokensBefore: event.preparation.tokensBefore,
|
||||
details: {},
|
||||
},
|
||||
};
|
||||
});
|
||||
},
|
||||
],
|
||||
});
|
||||
harnesses.push(harness);
|
||||
let resumedRequest = "";
|
||||
harness.setResponses([
|
||||
fauxAssistantMessage(`old-history:${"a".repeat(800)}`),
|
||||
fauxAssistantMessage(`recent-history:${"b".repeat(800)}`),
|
||||
fauxAssistantMessage(fauxToolCall("large_result", {}), { stopReason: "toolUse" }),
|
||||
(context) => {
|
||||
order.push("provider");
|
||||
resumedRequest = JSON.stringify(context.messages);
|
||||
return fauxAssistantMessage("finished after compaction");
|
||||
},
|
||||
]);
|
||||
|
||||
await harness.session.prompt("seed old history");
|
||||
await harness.session.prompt("seed recent history");
|
||||
const agentStartsBefore = harness.eventsOfType("agent_start").length;
|
||||
await harness.session.prompt("run the large tool");
|
||||
|
||||
expect(order).toEqual(["compaction", "provider"]);
|
||||
expect(harness.eventsOfType("agent_start")).toHaveLength(agentStartsBefore + 1);
|
||||
expect(harness.eventsOfType("compaction_start").at(-1)).toEqual({
|
||||
type: "compaction_start",
|
||||
reason: "threshold",
|
||||
});
|
||||
expect(resumedRequest).toContain("compacted history");
|
||||
expect(resumedRequest).toContain("large-tool-result");
|
||||
expect(harness.session.getLastAssistantText()).toBe("finished after compaction");
|
||||
});
|
||||
|
||||
it("includes steering queued during compaction in the resumed assistant request", async () => {
|
||||
const largeTool: AgentTool = {
|
||||
name: "large_result",
|
||||
label: "Large result",
|
||||
description: "Returns enough content to cross the compaction threshold",
|
||||
parameters: Type.Object({}),
|
||||
execute: async () => ({
|
||||
content: [{ type: "text", text: `large-tool-result:${"x".repeat(6800)}` }],
|
||||
details: {},
|
||||
}),
|
||||
};
|
||||
let markCompactionStarted = () => {};
|
||||
const compactionStarted = new Promise<void>((resolve) => {
|
||||
markCompactionStarted = resolve;
|
||||
});
|
||||
let releaseCompaction = () => {};
|
||||
const compactionReleased = new Promise<void>((resolve) => {
|
||||
releaseCompaction = resolve;
|
||||
});
|
||||
const harness = await createHarness({
|
||||
models: [{ id: "faux-1", contextWindow: 2600, maxTokens: 100 }],
|
||||
settings: { compaction: { enabled: true, reserveTokens: 400, keepRecentTokens: 1750 } },
|
||||
tools: [largeTool],
|
||||
extensionFactories: [
|
||||
(pi) => {
|
||||
pi.on("session_before_compact", async (event) => {
|
||||
markCompactionStarted();
|
||||
await compactionReleased;
|
||||
return {
|
||||
compaction: {
|
||||
summary: "compacted history",
|
||||
firstKeptEntryId: event.preparation.firstKeptEntryId,
|
||||
tokensBefore: event.preparation.tokensBefore,
|
||||
details: {},
|
||||
},
|
||||
};
|
||||
});
|
||||
},
|
||||
],
|
||||
});
|
||||
harnesses.push(harness);
|
||||
let resumedRequest = "";
|
||||
harness.setResponses([
|
||||
fauxAssistantMessage(`old-history:${"a".repeat(800)}`),
|
||||
fauxAssistantMessage(`recent-history:${"b".repeat(800)}`),
|
||||
fauxAssistantMessage(fauxToolCall("large_result", {}), { stopReason: "toolUse" }),
|
||||
(context) => {
|
||||
resumedRequest = JSON.stringify(context.messages);
|
||||
return fauxAssistantMessage("finished after compaction");
|
||||
},
|
||||
fauxAssistantMessage("finished after delayed steering"),
|
||||
]);
|
||||
|
||||
await harness.session.prompt("seed old history");
|
||||
await harness.session.prompt("seed recent history");
|
||||
const promptPromise = harness.session.prompt("run the large tool");
|
||||
await compactionStarted;
|
||||
await harness.session.steer("change direction");
|
||||
releaseCompaction();
|
||||
await promptPromise;
|
||||
|
||||
expect(resumedRequest).toContain("change direction");
|
||||
expect(harness.faux.state.callCount).toBe(4);
|
||||
});
|
||||
|
||||
it("does not compact after a terminating tool result", async () => {
|
||||
const terminatingTool: AgentTool = {
|
||||
name: "terminate_with_large_result",
|
||||
label: "Terminate with large result",
|
||||
description: "Returns enough content to cross the compaction threshold, then terminates",
|
||||
parameters: Type.Object({}),
|
||||
execute: async () => ({
|
||||
content: [{ type: "text", text: `large-tool-result:${"x".repeat(6800)}` }],
|
||||
details: {},
|
||||
terminate: true,
|
||||
}),
|
||||
};
|
||||
const harness = await createHarness({
|
||||
models: [{ id: "faux-1", contextWindow: 2600, maxTokens: 100 }],
|
||||
settings: { compaction: { enabled: true, reserveTokens: 400, keepRecentTokens: 1750 } },
|
||||
tools: [terminatingTool],
|
||||
extensionFactories: [
|
||||
(pi) => {
|
||||
pi.on("session_before_compact", (event) => ({
|
||||
compaction: {
|
||||
summary: "unexpected compaction",
|
||||
firstKeptEntryId: event.preparation.firstKeptEntryId,
|
||||
tokensBefore: event.preparation.tokensBefore,
|
||||
details: {},
|
||||
},
|
||||
}));
|
||||
},
|
||||
],
|
||||
});
|
||||
harnesses.push(harness);
|
||||
harness.setResponses([
|
||||
fauxAssistantMessage(`old-history:${"a".repeat(800)}`),
|
||||
fauxAssistantMessage(`recent-history:${"b".repeat(800)}`),
|
||||
fauxAssistantMessage(fauxToolCall("terminate_with_large_result", {}), { stopReason: "toolUse" }),
|
||||
]);
|
||||
|
||||
await harness.session.prompt("seed old history");
|
||||
await harness.session.prompt("seed recent history");
|
||||
await harness.session.prompt("run the terminating tool");
|
||||
|
||||
expect(harness.eventsOfType("compaction_start")).toEqual([]);
|
||||
expect(harness.sessionManager.getEntries().filter((entry) => entry.type === "compaction")).toEqual([]);
|
||||
expect(harness.getPendingResponseCount()).toBe(0);
|
||||
});
|
||||
|
||||
it("does not compact when a length stop reaches the desired output limit", async () => {
|
||||
const harness = await createHarness({
|
||||
models: [{ id: "faux-1", contextWindow: 1_000_000, maxTokens: 100 }],
|
||||
|
|
|
|||
|
|
@ -23,7 +23,7 @@ describe("issue #7253: manual compaction during an active response", () => {
|
|||
}
|
||||
});
|
||||
|
||||
it("runs only the requested manual compaction when the previous turn crossed the threshold", async () => {
|
||||
it("persists the aborted response before running the requested manual compaction", async () => {
|
||||
let markSecondResponseStarted = () => {};
|
||||
const secondResponseStarted = new Promise<void>((resolve) => {
|
||||
markSecondResponseStarted = resolve;
|
||||
|
|
@ -34,8 +34,8 @@ describe("issue #7253: manual compaction during an active response", () => {
|
|||
});
|
||||
|
||||
const harness = await createHarness({
|
||||
models: [{ id: "faux-1", contextWindow: 1000, maxTokens: 100 }],
|
||||
settings: { compaction: { enabled: true, reserveTokens: 999, keepRecentTokens: 2 } },
|
||||
models: [{ id: "faux-1", contextWindow: 1000, maxTokens: 1000 }],
|
||||
settings: { compaction: { enabled: true, reserveTokens: 200, keepRecentTokens: 2 } },
|
||||
tools: [createNoopTool()],
|
||||
extensionFactories: [
|
||||
(pi) => {
|
||||
|
|
@ -56,7 +56,7 @@ describe("issue #7253: manual compaction during an active response", () => {
|
|||
async () => {
|
||||
markSecondResponseStarted();
|
||||
await secondResponseReleased;
|
||||
return fauxAssistantMessage("second response");
|
||||
return fauxAssistantMessage(`second response:${"x".repeat(4000)}`);
|
||||
},
|
||||
]);
|
||||
|
||||
|
|
@ -70,6 +70,14 @@ describe("issue #7253: manual compaction during an active response", () => {
|
|||
|
||||
expect(harness.eventsOfType("compaction_start").map((event) => event.reason)).toEqual(["manual"]);
|
||||
expect(harness.eventsOfType("compaction_end").map((event) => event.reason)).toEqual(["manual"]);
|
||||
expect(harness.sessionManager.getEntries().filter((entry) => entry.type === "compaction")).toHaveLength(1);
|
||||
const entries = harness.sessionManager.getEntries();
|
||||
const abortedResponseIndex = entries.findIndex(
|
||||
(entry) =>
|
||||
entry.type === "message" && entry.message.role === "assistant" && entry.message.stopReason === "aborted",
|
||||
);
|
||||
const compactionIndex = entries.findIndex((entry) => entry.type === "compaction");
|
||||
expect(abortedResponseIndex).toBeGreaterThan(-1);
|
||||
expect(compactionIndex).toBeGreaterThan(abortedResponseIndex);
|
||||
expect(entries.filter((entry) => entry.type === "compaction")).toHaveLength(1);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@earendil-works/pi-evals",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"private": true,
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
|
|
@ -9,8 +9,8 @@
|
|||
"test": "vitest run --config vitest.test.config.ts"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@earendil-works/pi-ai": "^0.84.3",
|
||||
"@earendil-works/pi-coding-agent": "^0.84.3",
|
||||
"@earendil-works/pi-ai": "^0.84.4",
|
||||
"@earendil-works/pi-coding-agent": "^0.84.4",
|
||||
"@types/node": "22.19.19",
|
||||
"shx": "0.4.0",
|
||||
"typescript": "5.9.3",
|
||||
|
|
|
|||
|
|
@ -2,9 +2,7 @@
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Removed
|
||||
|
||||
- Removed the unused manual-action run-result and lane-snapshot wire fields. `PROTOCOL_VERSION` remains unchanged because no shipped producer emitted them.
|
||||
## [0.84.4] - 2026-08-28
|
||||
|
||||
## [0.84.3] - 2026-08-24
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@earendil-works/pi-protocol",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"description": "Transport-neutral CBOR protocol for remote pi sessions",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.84.4] - 2026-08-28
|
||||
|
||||
## [0.84.3] - 2026-08-24
|
||||
|
||||
## [0.84.2] - 2026-08-14
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@earendil-works/pi-server",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"description": "experimental server package for pi",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
|
|
@ -47,8 +47,8 @@
|
|||
"node": ">=22.19.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@earendil-works/pi-agent-core": "^0.84.3",
|
||||
"@earendil-works/pi-protocol": "^0.84.3"
|
||||
"@earendil-works/pi-agent-core": "^0.84.4",
|
||||
"@earendil-works/pi-protocol": "^0.84.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"shx": "0.4.0",
|
||||
|
|
|
|||
|
|
@ -2,9 +2,7 @@
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
### Changed
|
||||
|
||||
- Returned exact post-commit session totals from SQLite storage commits.
|
||||
## [0.84.4] - 2026-08-28
|
||||
|
||||
## [0.84.3] - 2026-08-24
|
||||
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@earendil-works/pi-session-backend-sqlite-node",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"description": "Node sqlite session backend for @earendil-works/pi-agent-core sessions",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
|
|
@ -35,8 +35,8 @@
|
|||
"node": ">=22.19.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@earendil-works/pi-ai": "^0.84.3",
|
||||
"@earendil-works/pi-agent-core": "^0.84.3"
|
||||
"@earendil-works/pi-ai": "^0.84.4",
|
||||
"@earendil-works/pi-agent-core": "^0.84.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@vitest/coverage-v8": "4.1.9",
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.84.4] - 2026-08-28
|
||||
|
||||
## [0.84.3] - 2026-08-24
|
||||
|
||||
## [0.84.2] - 2026-08-14
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@earendil-works/pi-telemetry",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"description": "Vendor-neutral telemetry contracts and typed schema utilities for pi",
|
||||
"type": "module",
|
||||
"main": "./dist/index.js",
|
||||
|
|
|
|||
|
|
@ -2,6 +2,8 @@
|
|||
|
||||
## [Unreleased]
|
||||
|
||||
## [0.84.4] - 2026-08-28
|
||||
|
||||
### Added
|
||||
|
||||
- Added environment and programmatic overrides for OSC 8 hyperlinks, inline image protocols, and truecolor terminal capabilities ([#8665](https://github.com/earendil-works/pi/issues/8665)).
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "@earendil-works/pi-tui",
|
||||
"version": "0.84.3",
|
||||
"version": "0.84.4",
|
||||
"description": "Terminal User Interface library with differential rendering for efficient text-based applications",
|
||||
"type": "module",
|
||||
"main": "dist/index.js",
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue