From 86ef2bd34b3454e2bf94335f89a5d7508ff2cc2e Mon Sep 17 00:00:00 2001 From: can1357 Date: Fri, 9 Jan 2026 12:11:50 +0100 Subject: [PATCH] chore: bump version to 3.34.0 --- bun.lock | 18 +-- packages/agent/CHANGELOG.md | 2 + packages/agent/package.json | 2 +- packages/agent/src/agent-loop.ts | 22 ++-- packages/agent/src/agent.ts | 4 +- packages/agent/src/proxy.ts | 4 +- packages/agent/src/types.ts | 2 +- packages/agent/test/agent-loop.test.ts | 16 +-- packages/agent/test/e2e.test.ts | 3 +- packages/ai/CHANGELOG.md | 2 + packages/ai/package.json | 2 +- packages/ai/src/cli.ts | 6 +- .../src/providers/openai-codex-responses.ts | 6 +- packages/ai/src/types.ts | 11 +- packages/ai/test/zen.test.ts | 8 +- packages/coding-agent/CHANGELOG.md | 2 + .../coding-agent/examples/extensions/todo.ts | 2 +- .../examples/hooks/custom-compaction.ts | 2 +- .../coding-agent/examples/hooks/handoff.ts | 2 +- packages/coding-agent/examples/hooks/qna.ts | 2 +- .../examples/sdk/02-custom-model.ts | 2 +- packages/coding-agent/package.json | 2 +- .../coding-agent/src/core/agent-session.ts | 41 ++++--- .../coding-agent/src/core/auth-storage.ts | 9 +- .../core/compaction/branch-summarization.ts | 2 +- .../src/core/compaction/compaction.ts | 2 +- .../coding-agent/src/core/compaction/utils.ts | 2 +- .../src/core/custom-tools/types.ts | 6 +- .../src/core/extensions/runner.ts | 16 +-- .../coding-agent/src/core/extensions/types.ts | 24 ++-- .../src/core/extensions/wrapper.ts | 11 +- .../coding-agent/src/core/hooks/runner.ts | 8 +- packages/coding-agent/src/core/hooks/types.ts | 12 +- packages/coding-agent/src/core/messages.ts | 6 +- .../coding-agent/src/core/model-registry.ts | 20 ++-- .../coding-agent/src/core/model-resolver.ts | 13 ++- packages/coding-agent/src/core/sdk.ts | 26 ++--- .../coding-agent/src/core/session-manager.ts | 22 ++-- .../coding-agent/src/core/tools/output.ts | 2 +- packages/coding-agent/src/core/tools/read.ts | 2 +- .../coding-agent/src/core/tools/task/index.ts | 2 +- .../coding-agent/src/core/tools/task/types.ts | 4 +- .../src/core/tools/task/worker.ts | 6 +- packages/coding-agent/src/main.ts | 10 +- .../components/assistant-message.ts | 6 +- .../interactive/components/custom-message.ts | 2 +- .../modes/interactive/components/footer.ts | 6 +- .../interactive/components/hook-message.ts | 2 +- .../interactive/components/model-selector.ts | 6 +- .../interactive/components/oauth-selector.ts | 2 +- .../interactive/components/status-line.ts | 6 +- .../src/modes/interactive/interactive-mode.ts | 106 ++++++++++-------- packages/coding-agent/src/modes/print-mode.ts | 2 +- .../coding-agent/src/modes/rpc/rpc-client.ts | 4 +- .../coding-agent/src/modes/rpc/rpc-types.ts | 2 +- .../coding-agent/src/utils/image-resize.ts | 12 +- .../test/agent-session-branching.test.ts | 2 +- .../test/agent-session-compaction.test.ts | 4 +- .../test/agent-session-concurrent.test.ts | 6 +- .../test/compaction-hooks.test.ts | 6 +- .../test/compaction-thinking-model.test.ts | 4 +- packages/coding-agent/test/compaction.test.ts | 4 +- .../test/streaming-render-debug.ts | 2 +- packages/coding-agent/test/utilities.ts | 4 +- packages/git-tool/CHANGELOG.md | 2 + packages/git-tool/package.json | 2 +- packages/tui/CHANGELOG.md | 2 + packages/tui/package.json | 2 +- 68 files changed, 299 insertions(+), 265 deletions(-) diff --git a/bun.lock b/bun.lock index 442ebd54e..05d1f7f97 100644 --- a/bun.lock +++ b/bun.lock @@ -20,7 +20,7 @@ }, "packages/agent": { "name": "@oh-my-pi/pi-agent-core", - "version": "3.33.0", + "version": "3.34.0", "dependencies": { "@oh-my-pi/pi-ai": "workspace:*", "@oh-my-pi/pi-tui": "workspace:*", @@ -32,7 +32,7 @@ }, "packages/ai": { "name": "@oh-my-pi/pi-ai", - "version": "0.42.0", + "version": "3.34.0", "bin": { "pi-ai": "./src/cli.ts", }, @@ -54,7 +54,7 @@ }, "packages/coding-agent": { "name": "@oh-my-pi/pi-coding-agent", - "version": "3.33.0", + "version": "3.34.0", "bin": { "omp": "src/cli.ts", }, @@ -95,7 +95,7 @@ }, "packages/git-tool": { "name": "@oh-my-pi/pi-git-tool", - "version": "3.33.0", + "version": "3.34.0", "devDependencies": { "@types/node": "^24.3.0", "vitest": "^3.2.4", @@ -103,7 +103,7 @@ }, "packages/tui": { "name": "@oh-my-pi/pi-tui", - "version": "3.33.0", + "version": "3.34.0", "dependencies": { "@types/mime-types": "^2.1.4", "chalk": "^5.5.0", @@ -652,8 +652,6 @@ "jackspeak": ["jackspeak@4.1.1", "", { "dependencies": { "@isaacs/cliui": "^8.0.2" } }, "sha512-zptv57P3GpL+O0I7VdMJNBZCu+BPHVQUk55Ft8/QCJjTVxrnJHuVuX/0Bl2A6/+2oyR/ZMEuFKwmzqqZ/U5nPQ=="], - "jiti": ["jiti@2.6.1", "", { "bin": { "jiti": "lib/jiti-cli.mjs" } }, "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ=="], - "jose": ["jose@6.1.3", "", {}, "sha512-0TpaTfihd4QMNwrz/ob2Bp7X04yuxJkjRGi4aKmOqwhov54i6u79oCv7T+C7lo70MKH6BesI3vscD1yb/yzKXQ=="], "js-tokens": ["js-tokens@9.0.1", "", {}, "sha512-mxa9E9ITFOt0ban3j6L5MpjwegGz6lBQmM1IJkWeBZGcMxto50+eWdjC/52xDbS2vy0k7vIMK0Fe2wfL9OQSpQ=="], @@ -970,12 +968,6 @@ "@oh-my-pi/pi-git-tool/@types/node": ["@types/node@24.10.4", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-vnDVpYPMzs4wunl27jHrfmwojOGKya0xyM3sH+UE5iv5uPS6vX7UIoh6m+vQc5LGBq52HBKPIn/zcSZVzeDEZg=="], - "@openai/agents/openai": ["openai@6.15.0", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-F1Lvs5BoVvmZtzkUEVyh8mDQPPFolq4F+xdsx/DO8Hee8YF3IGAlZqUIsF+DVGhqf4aU0a3bTghsxB6OIsRy1g=="], - - "@openai/agents-core/openai": ["openai@6.15.0", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-F1Lvs5BoVvmZtzkUEVyh8mDQPPFolq4F+xdsx/DO8Hee8YF3IGAlZqUIsF+DVGhqf4aU0a3bTghsxB6OIsRy1g=="], - - "@openai/agents-openai/openai": ["openai@6.15.0", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.25 || ^4.0" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-F1Lvs5BoVvmZtzkUEVyh8mDQPPFolq4F+xdsx/DO8Hee8YF3IGAlZqUIsF+DVGhqf4aU0a3bTghsxB6OIsRy1g=="], - "@types/ndjson/@types/node": ["@types/node@24.10.4", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-vnDVpYPMzs4wunl27jHrfmwojOGKya0xyM3sH+UE5iv5uPS6vX7UIoh6m+vQc5LGBq52HBKPIn/zcSZVzeDEZg=="], "@types/through/@types/node": ["@types/node@24.10.4", "", { "dependencies": { "undici-types": "~7.16.0" } }, "sha512-vnDVpYPMzs4wunl27jHrfmwojOGKya0xyM3sH+UE5iv5uPS6vX7UIoh6m+vQc5LGBq52HBKPIn/zcSZVzeDEZg=="], diff --git a/packages/agent/CHANGELOG.md b/packages/agent/CHANGELOG.md index beefacb4b..b8a935b8a 100644 --- a/packages/agent/CHANGELOG.md +++ b/packages/agent/CHANGELOG.md @@ -2,6 +2,8 @@ ## [Unreleased] +## [3.34.0] - 2026-01-09 + ## [3.33.0] - 2026-01-08 ### Fixed diff --git a/packages/agent/package.json b/packages/agent/package.json index 29f41ec22..fd25957a6 100644 --- a/packages/agent/package.json +++ b/packages/agent/package.json @@ -1,6 +1,6 @@ { "name": "@oh-my-pi/pi-agent-core", - "version": "3.33.0", + "version": "3.34.0", "description": "General-purpose agent with transport abstraction, state management, and attachment support", "type": "module", "main": "./src/index.ts", diff --git a/packages/agent/src/agent-loop.ts b/packages/agent/src/agent-loop.ts index a829e5f00..e096de334 100644 --- a/packages/agent/src/agent-loop.ts +++ b/packages/agent/src/agent-loop.ts @@ -30,7 +30,7 @@ export function agentLoop( context: AgentContext, config: AgentLoopConfig, signal?: AbortSignal, - streamFn?: StreamFn + streamFn?: StreamFn, ): EventStream { const stream = createAgentStream(); @@ -66,7 +66,7 @@ export function agentLoopContinue( context: AgentContext, config: AgentLoopConfig, signal?: AbortSignal, - streamFn?: StreamFn + streamFn?: StreamFn, ): EventStream { if (context.messages.length === 0) { throw new Error("Cannot continue: no messages in context"); @@ -94,13 +94,13 @@ export function agentLoopContinue( function createAgentStream(): EventStream { return new EventStream( (event: AgentEvent) => event.type === "agent_end", - (event: AgentEvent) => (event.type === "agent_end" ? event.messages : []) + (event: AgentEvent) => (event.type === "agent_end" ? event.messages : []), ); } function normalizeMessagesForProvider( messages: Context["messages"], - model: AgentLoopConfig["model"] + model: AgentLoopConfig["model"], ): Context["messages"] { if (model.provider !== "cerebras") { return messages; @@ -133,7 +133,7 @@ async function runLoop( config: AgentLoopConfig, signal: AbortSignal | undefined, stream: EventStream, - streamFn?: StreamFn + streamFn?: StreamFn, ): Promise { let firstTurn = true; // Check for steering messages at start (user may have typed while waiting) @@ -187,7 +187,7 @@ async function runLoop( stream, config.getSteeringMessages, config.getToolContext, - config.interruptMode + config.interruptMode, ); toolResults.push(...toolExecution.toolResults); steeringAfterTools = toolExecution.steeringMessages ?? null; @@ -234,7 +234,7 @@ async function streamAssistantResponse( config: AgentLoopConfig, signal: AbortSignal | undefined, stream: EventStream, - streamFn?: StreamFn + streamFn?: StreamFn, ): Promise { // Apply context transform if configured (AgentMessage[] → AgentMessage[]) let messages = context.messages; @@ -291,7 +291,7 @@ async function streamAssistantResponse( stopReason: "aborted", errorMessage, timestamp: Date.now(), - }; + }; if (addedPartial) { context.messages[context.messages.length - 1] = abortedMessage; } else { @@ -360,7 +360,7 @@ async function executeToolCalls( stream: EventStream, getSteeringMessages?: AgentLoopConfig["getSteeringMessages"], getToolContext?: AgentLoopConfig["getToolContext"], - interruptMode: AgentLoopConfig["interruptMode"] = "immediate" + interruptMode: AgentLoopConfig["interruptMode"] = "immediate", ): Promise<{ toolResults: ToolResultMessage[]; steeringMessages?: AgentMessage[] }> { const toolCalls = assistantMessage.content.filter((c) => c.type === "toolCall"); const results: ToolResultMessage[] = []; @@ -400,7 +400,7 @@ async function executeToolCalls( partialResult, }); }, - toolContext + toolContext, ); } catch (e) { result = { @@ -451,7 +451,7 @@ async function executeToolCalls( function skipToolCall( toolCall: Extract, - stream: EventStream + stream: EventStream, ): ToolResultMessage { const result: AgentToolResult = { content: [{ type: "text", text: "Skipped due to queued user message." }], diff --git a/packages/agent/src/agent.ts b/packages/agent/src/agent.ts index e02c5dce1..b67690445 100644 --- a/packages/agent/src/agent.ts +++ b/packages/agent/src/agent.ts @@ -264,7 +264,7 @@ export class Agent { async prompt(input: string | AgentMessage | AgentMessage[], images?: ImageContent[]) { if (this._state.isStreaming) { throw new Error( - "Agent is already processing a prompt. Use steer() or followUp() to queue messages, or wait for completion." + "Agent is already processing a prompt. Use steer() or followUp() to queue messages, or wait for completion.", ); } @@ -438,7 +438,7 @@ export class Agent { (c) => (c.type === "thinking" && c.thinking.trim().length > 0) || (c.type === "text" && c.text.trim().length > 0) || - (c.type === "toolCall" && c.name.trim().length > 0) + (c.type === "toolCall" && c.name.trim().length > 0), ); if (!onlyEmpty) { this.appendMessage(partial); diff --git a/packages/agent/src/proxy.ts b/packages/agent/src/proxy.ts index facb9e535..3c44e03af 100644 --- a/packages/agent/src/proxy.ts +++ b/packages/agent/src/proxy.ts @@ -24,7 +24,7 @@ class ProxyMessageEventStream extends EventStream, context: Context, options: ProxyS */ function processProxyEvent( proxyEvent: ProxyAssistantMessageEvent, - partial: AssistantMessage + partial: AssistantMessage, ): AssistantMessageEvent | undefined { switch (proxyEvent.type) { case "start": diff --git a/packages/agent/src/types.ts b/packages/agent/src/types.ts index 45c638a17..22880f91a 100644 --- a/packages/agent/src/types.ts +++ b/packages/agent/src/types.ts @@ -198,7 +198,7 @@ export interface AgentTool, signal?: AbortSignal, onUpdate?: AgentToolUpdateCallback, - context?: AgentToolContext + context?: AgentToolContext, ) => Promise>; /** Optional custom rendering for tool call display (returns UI component) */ diff --git a/packages/agent/test/agent-loop.test.ts b/packages/agent/test/agent-loop.test.ts index 3cd870ab4..79276ef3b 100644 --- a/packages/agent/test/agent-loop.test.ts +++ b/packages/agent/test/agent-loop.test.ts @@ -20,7 +20,7 @@ class MockAssistantStream extends EventStream { function createAssistantMessage( content: AssistantMessage["content"], - stopReason: AssistantMessage["stopReason"] = "stop" + stopReason: AssistantMessage["stopReason"] = "stop", ): AssistantMessage { return { role: "assistant", @@ -209,7 +209,7 @@ describe("agentLoop with AgentMessage", () => { }, convertToLlm: (messages) => { convertedMessages = messages.filter( - (m) => m.role === "user" || m.role === "assistant" || m.role === "toolResult" + (m) => m.role === "user" || m.role === "assistant" || m.role === "toolResult", ) as Message[]; return convertedMessages; }, @@ -274,7 +274,7 @@ describe("agentLoop with AgentMessage", () => { // First call: return tool call const message = createAssistantMessage( [{ type: "toolCall", id: "tool-1", name: "echo", arguments: { value: "hello" } }], - "toolUse" + "toolUse", ); stream.push({ type: "done", reason: "toolUse", message }); } else { @@ -355,7 +355,7 @@ describe("agentLoop with AgentMessage", () => { // Check if interrupt message is in context on second call if (callIndex === 1) { sawInterruptInContext = ctx.messages.some( - (m) => m.role === "user" && typeof m.content === "string" && m.content === "interrupt" + (m) => m.role === "user" && typeof m.content === "string" && m.content === "interrupt", ); } @@ -368,7 +368,7 @@ describe("agentLoop with AgentMessage", () => { { type: "toolCall", id: "tool-1", name: "echo", arguments: { value: "first" } }, { type: "toolCall", id: "tool-2", name: "echo", arguments: { value: "second" } }, ], - "toolUse" + "toolUse", ); mockStream.push({ type: "done", reason: "toolUse", message }); } else { @@ -390,7 +390,7 @@ describe("agentLoop with AgentMessage", () => { // Second tool should be skipped const toolEnds = events.filter( - (e): e is Extract => e.type === "tool_execution_end" + (e): e is Extract => e.type === "tool_execution_end", ); expect(toolEnds.length).toBe(2); expect(toolEnds[0].isError).toBeFalsy(); @@ -405,7 +405,7 @@ describe("agentLoop with AgentMessage", () => { e.type === "message_start" && e.message.role === "user" && typeof e.message.content === "string" && - e.message.content === "interrupt" + e.message.content === "interrupt", ); expect(queuedMessageEvent).toBeDefined(); diff --git a/packages/agent/test/e2e.test.ts b/packages/agent/test/e2e.test.ts index 7dbb9d672..8ad424568 100644 --- a/packages/agent/test/e2e.test.ts +++ b/packages/agent/test/e2e.test.ts @@ -414,7 +414,8 @@ describe("Agent.continue()", () => { it("should continue and process tool results", async () => { const agent = new Agent({ initialState: { - systemPrompt: "You are a helpful assistant. After getting a calculation result, state the answer clearly.", + systemPrompt: + "You are a helpful assistant. After getting a calculation result, state the answer clearly.", model, thinkingLevel: "off", tools: [calculateTool], diff --git a/packages/ai/CHANGELOG.md b/packages/ai/CHANGELOG.md index 9a7bf1394..674795a1d 100644 --- a/packages/ai/CHANGELOG.md +++ b/packages/ai/CHANGELOG.md @@ -2,6 +2,8 @@ ## [Unreleased] +## [3.34.0] - 2026-01-09 + ## [0.42.0] - 2026-01-09 ### Added diff --git a/packages/ai/package.json b/packages/ai/package.json index a76296aee..46ccf14a0 100644 --- a/packages/ai/package.json +++ b/packages/ai/package.json @@ -1,6 +1,6 @@ { "name": "@oh-my-pi/pi-ai", - "version": "0.42.0", + "version": "3.34.0", "description": "Unified LLM API with automatic model discovery and provider configuration", "type": "module", "main": "./src/index.ts", diff --git a/packages/ai/src/cli.ts b/packages/ai/src/cli.ts index b2940d2ec..fd1cb0773 100755 --- a/packages/ai/src/cli.ts +++ b/packages/ai/src/cli.ts @@ -46,7 +46,7 @@ async function login(provider: OAuthProvider): Promise { }, async () => { return await promptFn("Paste the authorization code:"); - } + }, ); break; @@ -71,7 +71,7 @@ async function login(provider: OAuthProvider): Promise { if (info.instructions) console.log(info.instructions); console.log(); }, - (msg) => console.log(msg) + (msg) => console.log(msg), ); break; @@ -82,7 +82,7 @@ async function login(provider: OAuthProvider): Promise { if (info.instructions) console.log(info.instructions); console.log(); }, - (msg) => console.log(msg) + (msg) => console.log(msg), ); break; case "openai-codex": diff --git a/packages/ai/src/providers/openai-codex-responses.ts b/packages/ai/src/providers/openai-codex-responses.ts index 52b47ace3..b625436c3 100644 --- a/packages/ai/src/providers/openai-codex-responses.ts +++ b/packages/ai/src/providers/openai-codex-responses.ts @@ -35,11 +35,7 @@ import { import { getCodexInstructions } from "./openai-codex/prompts/codex"; import { buildCodexPiBridge } from "./openai-codex/prompts/pi-codex-bridge"; import { buildCodexSystemPrompt } from "./openai-codex/prompts/system-prompt"; -import { - type CodexRequestOptions, - type RequestBody, - transformRequestBody, -} from "./openai-codex/request-transformer"; +import { type CodexRequestOptions, type RequestBody, transformRequestBody } from "./openai-codex/request-transformer"; import { parseCodexError, parseCodexSseStream } from "./openai-codex/response-handler"; import { transformMessages } from "./transorm-messages"; diff --git a/packages/ai/src/types.ts b/packages/ai/src/types.ts index 9d93f8819..728faf9ee 100644 --- a/packages/ai/src/types.ts +++ b/packages/ai/src/types.ts @@ -29,11 +29,12 @@ export interface ApiOptionsMap { } // Compile-time exhaustiveness check - this will fail if ApiOptionsMap doesn't have all KnownApi keys -type _CheckExhaustive = ApiOptionsMap extends Record - ? Record extends ApiOptionsMap - ? true - : ["ApiOptionsMap is missing some KnownApi values", Exclude] - : ["ApiOptionsMap doesn't extend Record"]; +type _CheckExhaustive = + ApiOptionsMap extends Record + ? Record extends ApiOptionsMap + ? true + : ["ApiOptionsMap is missing some KnownApi values", Exclude] + : ["ApiOptionsMap doesn't extend Record"]; const _exhaustive: _CheckExhaustive = true; // Helper type to get options for a specific API diff --git a/packages/ai/test/zen.test.ts b/packages/ai/test/zen.test.ts index cf9ee332d..ea9c2c2ac 100644 --- a/packages/ai/test/zen.test.ts +++ b/packages/ai/test/zen.test.ts @@ -1,9 +1,9 @@ import { describe, expect, it } from "vitest"; -import { MODELS } from "../src/models.generated.js"; -import { complete } from "../src/stream.js"; -import type { Model } from "../src/types.js"; +import { MODELS } from "../src/models.generated"; +import { complete } from "../src/stream"; +import type { Model } from "../src/types"; -describe("OpenCode Zen Models Smoke Test", () => { +describe.skipIf(!process.env.OPENCODE_API_KEY)("OpenCode Zen Models Smoke Test", () => { const zenModels = Object.values(MODELS.opencode); zenModels.forEach((model) => { diff --git a/packages/coding-agent/CHANGELOG.md b/packages/coding-agent/CHANGELOG.md index 41ec62e58..b6e02711f 100644 --- a/packages/coding-agent/CHANGELOG.md +++ b/packages/coding-agent/CHANGELOG.md @@ -2,6 +2,8 @@ ## [Unreleased] +## [3.34.0] - 2026-01-09 + ### Added - Added caching for system environment detection to improve startup performance diff --git a/packages/coding-agent/examples/extensions/todo.ts b/packages/coding-agent/examples/extensions/todo.ts index f2a059c07..5f3e91617 100644 --- a/packages/coding-agent/examples/extensions/todo.ts +++ b/packages/coding-agent/examples/extensions/todo.ts @@ -263,7 +263,7 @@ export default function (pi: ExtensionAPI) { return new Text( `${theme.fg("success", "✓ Added ") + theme.fg("accent", `#${added.id}`)} ${theme.fg("muted", added.text)}`, 0, - 0 + 0, ); } diff --git a/packages/coding-agent/examples/hooks/custom-compaction.ts b/packages/coding-agent/examples/hooks/custom-compaction.ts index 00aba5cfd..bb69098ae 100644 --- a/packages/coding-agent/examples/hooks/custom-compaction.ts +++ b/packages/coding-agent/examples/hooks/custom-compaction.ts @@ -45,7 +45,7 @@ export default function (pi: HookAPI) { `Custom compaction: summarizing ${allMessages.length} messages (${tokensBefore.toLocaleString()} tokens) with ${ model.id }...`, - "info" + "info", ); // Convert messages to readable text format diff --git a/packages/coding-agent/examples/hooks/handoff.ts b/packages/coding-agent/examples/hooks/handoff.ts index f8ed9658d..4b3cc316c 100644 --- a/packages/coding-agent/examples/hooks/handoff.ts +++ b/packages/coding-agent/examples/hooks/handoff.ts @@ -96,7 +96,7 @@ export default function (pi: HookAPI) { const response = await complete( ctx.model!, { systemPrompt: SYSTEM_PROMPT, messages: [userMessage] }, - { apiKey, signal: loader.signal } + { apiKey, signal: loader.signal }, ); if (response.stopReason === "aborted") { diff --git a/packages/coding-agent/examples/hooks/qna.ts b/packages/coding-agent/examples/hooks/qna.ts index ced93ee7c..1200b0fb2 100644 --- a/packages/coding-agent/examples/hooks/qna.ts +++ b/packages/coding-agent/examples/hooks/qna.ts @@ -87,7 +87,7 @@ export default function (pi: HookAPI) { const response = await complete( ctx.model!, { systemPrompt: SYSTEM_PROMPT, messages: [userMessage] }, - { apiKey, signal: loader.signal } + { apiKey, signal: loader.signal }, ); if (response.stopReason === "aborted") { diff --git a/packages/coding-agent/examples/sdk/02-custom-model.ts b/packages/coding-agent/examples/sdk/02-custom-model.ts index f531d6e35..b32bf0f52 100644 --- a/packages/coding-agent/examples/sdk/02-custom-model.ts +++ b/packages/coding-agent/examples/sdk/02-custom-model.ts @@ -27,7 +27,7 @@ if (customModel) { const available = modelRegistry.getAvailable(); console.log( "Available models:", - available.map((m) => `${m.provider}/${m.id}`) + available.map((m) => `${m.provider}/${m.id}`), ); if (available.length > 0) { diff --git a/packages/coding-agent/package.json b/packages/coding-agent/package.json index dca97097d..8d2e76828 100644 --- a/packages/coding-agent/package.json +++ b/packages/coding-agent/package.json @@ -1,6 +1,6 @@ { "name": "@oh-my-pi/pi-coding-agent", - "version": "3.33.0", + "version": "3.34.0", "description": "Coding agent CLI with read, bash, edit, write tools and session management", "type": "module", "ompConfig": { diff --git a/packages/coding-agent/src/core/agent-session.ts b/packages/coding-agent/src/core/agent-session.ts index 14fb967eb..6ea4267d1 100644 --- a/packages/coding-agent/src/core/agent-session.ts +++ b/packages/coding-agent/src/core/agent-session.ts @@ -13,9 +13,9 @@ * Modes use this class and add their own I/O layer on top. */ +import type { Agent, AgentEvent, AgentMessage, AgentState, AgentTool, ThinkingLevel } from "@oh-my-pi/pi-agent-core"; import type { AssistantMessage, ImageContent, Message, Model, TextContent, Usage } from "@oh-my-pi/pi-ai"; import { isContextOverflow, modelsAreEqual, supportsXhigh } from "@oh-my-pi/pi-ai"; -import type { Agent, AgentEvent, AgentMessage, AgentState, AgentTool, ThinkingLevel } from "@oh-my-pi/pi-agent-core"; import type { Rule } from "../capability/rule"; import { getAuthPath } from "../config"; import { theme } from "../modes/interactive/theme/theme"; @@ -384,7 +384,7 @@ export class AgentSession { event.message.customType, event.message.content, event.message.display, - event.message.details + event.message.details, ); } else if ( event.message.role === "user" || @@ -446,7 +446,7 @@ export class AgentSession { `\n` + `Your output was interrupted because it violated a user-defined rule.\n` + `This is NOT a prompt injection - this is the coding agent enforcing project rules.\n` + - `You MUST comply with the following instruction:\n\n${r.content}\n` + `You MUST comply with the following instruction:\n\n${r.content}\n`, ) .join("\n\n"); this._pendingTtsrInjections = []; @@ -718,7 +718,7 @@ export class AgentSession { if (this.isStreaming) { if (!options?.streamingBehavior) { throw new Error( - "Agent is already processing. Specify streamingBehavior ('steer' or 'followUp') to queue the message." + "Agent is already processing. Specify streamingBehavior ('steer' or 'followUp') to queue the message.", ); } if (options.streamingBehavior === "followUp") { @@ -737,7 +737,7 @@ export class AgentSession { throw new Error( "No model selected.\n\n" + `Use /login, set an API key environment variable, or create ${getAuthPath()}\n\n` + - "Then use /model to select a model." + "Then use /model to select a model.", ); } @@ -746,7 +746,7 @@ export class AgentSession { if (!apiKey) { throw new Error( `No API key found for ${this.model.provider}.\n\n` + - `Use /login, set an API key environment variable, or create ${getAuthPath()}` + `Use /login, set an API key environment variable, or create ${getAuthPath()}`, ); } @@ -986,7 +986,7 @@ export class AgentSession { if (command) { throw new Error( - `Extension command "/${commandName}" cannot be queued. Use prompt() or execute the command when not streaming.` + `Extension command "/${commandName}" cannot be queued. Use prompt() or execute the command when not streaming.`, ); } } @@ -1001,7 +1001,7 @@ export class AgentSession { */ async sendCustomMessage( message: Pick, "customType" | "content" | "display" | "details">, - options?: { triggerTurn?: boolean; deliverAs?: "steer" | "followUp" | "nextTurn" } + options?: { triggerTurn?: boolean; deliverAs?: "steer" | "followUp" | "nextTurn" }, ): Promise { const appMessage: CustomMessage = { role: "custom", @@ -1031,7 +1031,12 @@ export class AgentSession { } this.agent.appendMessage(appMessage); - this.sessionManager.appendCustomMessageEntry(message.customType, message.content, message.display, message.details); + this.sessionManager.appendCustomMessageEntry( + message.customType, + message.content, + message.display, + message.details, + ); } /** @@ -1176,7 +1181,7 @@ export class AgentSession { */ async cycleRoleModels( roleOrder: string[], - options?: { temporary?: boolean } + options?: { temporary?: boolean }, ): Promise { const availableModels = this._modelRegistry.getAvailable(); if (availableModels.length === 0) return undefined; @@ -1189,7 +1194,7 @@ export class AgentSession { for (const role of roleOrder) { const roleModelStr = role === "default" - ? this.settingsManager.getModelRole("default") ?? `${currentModel.provider}/${currentModel.id}` + ? (this.settingsManager.getModelRole("default") ?? `${currentModel.provider}/${currentModel.id}`) : this.settingsManager.getModelRole(role); if (!roleModelStr) continue; @@ -1454,7 +1459,7 @@ export class AgentSession { this.model, apiKey, customInstructions, - this._compactionAbortController.signal + this._compactionAbortController.signal, ); summary = result.summary; firstKeptEntryId = result.firstKeptEntryId; @@ -1627,7 +1632,7 @@ export class AgentSession { this.model, apiKey, undefined, - this._autoCompactionAbortController.signal + this._autoCompactionAbortController.signal, ); summary = compactResult.summary; firstKeptEntryId = compactResult.firstKeptEntryId; @@ -1684,7 +1689,7 @@ export class AgentSession { throw new Error( `Context overflow: ${ error instanceof Error ? error.message : "compaction failed" - }. Your input may be too large for the context window.` + }. Your input may be too large for the context window.`, ); } } finally { @@ -1722,7 +1727,7 @@ export class AgentSession { const err = message.errorMessage; // Match: overloaded_error, rate limit, 429, 500, 502, 503, 504, service unavailable, connection error return /overloaded|rate.?limit|too many requests|429|500|502|503|504|service.?unavailable|server error|internal error|connection.?error/i.test( - err + err, ); } @@ -1876,7 +1881,7 @@ export class AgentSession { async executeBash( command: string, onChunk?: (chunk: string) => void, - options?: { excludeFromContext?: boolean } + options?: { excludeFromContext?: boolean }, ): Promise { this._bashAbortController = new AbortController(); @@ -2107,7 +2112,7 @@ export class AgentSession { */ async navigateTree( targetId: string, - options: { summarize?: boolean; customInstructions?: string } = {} + options: { summarize?: boolean; customInstructions?: string } = {}, ): Promise<{ editorText?: string; cancelled: boolean; aborted?: boolean; summaryEntry?: BranchSummaryEntry }> { const oldLeafId = this.sessionManager.getLeafId(); @@ -2130,7 +2135,7 @@ export class AgentSession { const { entries: entriesToSummarize, commonAncestorId } = collectEntriesForBranchSummary( this.sessionManager, oldLeafId, - targetId + targetId, ); // Prepare event data diff --git a/packages/coding-agent/src/core/auth-storage.ts b/packages/coding-agent/src/core/auth-storage.ts index 894b094ee..8ef89585c 100644 --- a/packages/coding-agent/src/core/auth-storage.ts +++ b/packages/coding-agent/src/core/auth-storage.ts @@ -44,7 +44,10 @@ export class AuthStorage { * @param authPath - Primary path for reading/writing auth.json * @param fallbackPaths - Additional paths to check when reading (legacy support) */ - constructor(private authPath: string, private fallbackPaths: string[] = []) {} + constructor( + private authPath: string, + private fallbackPaths: string[] = [], + ) {} /** * Set a runtime API key override (not persisted to disk). @@ -173,7 +176,7 @@ export class AuthStorage { onAuth: (info: { url: string; instructions?: string }) => void; onPrompt: (prompt: { message: string; placeholder?: string }) => Promise; onProgress?: (message: string) => void; - } + }, ): Promise { let credentials: OAuthCredentials; @@ -181,7 +184,7 @@ export class AuthStorage { case "anthropic": credentials = await loginAnthropic( (url) => callbacks.onAuth({ url }), - () => callbacks.onPrompt({ message: "Paste the authorization code:" }) + () => callbacks.onPrompt({ message: "Paste the authorization code:" }), ); break; case "github-copilot": diff --git a/packages/coding-agent/src/core/compaction/branch-summarization.ts b/packages/coding-agent/src/core/compaction/branch-summarization.ts index fbc195545..2ac7cd1a1 100644 --- a/packages/coding-agent/src/core/compaction/branch-summarization.ts +++ b/packages/coding-agent/src/core/compaction/branch-summarization.ts @@ -5,9 +5,9 @@ * a summary of the branch being left so context isn't lost. */ +import type { AgentMessage } from "@oh-my-pi/pi-agent-core"; import type { Model } from "@oh-my-pi/pi-ai"; import { completeSimple } from "@oh-my-pi/pi-ai"; -import type { AgentMessage } from "@oh-my-pi/pi-agent-core"; import branchSummaryPrompt from "../../prompts/branch-summary.md" with { type: "text" }; import branchSummaryPreamble from "../../prompts/branch-summary-preamble.md" with { type: "text" }; import { diff --git a/packages/coding-agent/src/core/compaction/compaction.ts b/packages/coding-agent/src/core/compaction/compaction.ts index e5ad3ae09..8324ea2a5 100644 --- a/packages/coding-agent/src/core/compaction/compaction.ts +++ b/packages/coding-agent/src/core/compaction/compaction.ts @@ -5,9 +5,9 @@ * and after compaction the session is reloaded. */ +import type { AgentMessage } from "@oh-my-pi/pi-agent-core"; import type { AssistantMessage, Model, Usage } from "@oh-my-pi/pi-ai"; import { complete, completeSimple } from "@oh-my-pi/pi-ai"; -import type { AgentMessage } from "@oh-my-pi/pi-agent-core"; import compactionSummaryPrompt from "../../prompts/compaction-summary.md" with { type: "text" }; import compactionTurnPrefixPrompt from "../../prompts/compaction-turn-prefix.md" with { type: "text" }; import compactionUpdateSummaryPrompt from "../../prompts/compaction-update-summary.md" with { type: "text" }; diff --git a/packages/coding-agent/src/core/compaction/utils.ts b/packages/coding-agent/src/core/compaction/utils.ts index 03a088b6a..cac4fc9d9 100644 --- a/packages/coding-agent/src/core/compaction/utils.ts +++ b/packages/coding-agent/src/core/compaction/utils.ts @@ -2,8 +2,8 @@ * Shared utilities for compaction and branch summarization. */ -import type { Message } from "@oh-my-pi/pi-ai"; import type { AgentMessage } from "@oh-my-pi/pi-agent-core"; +import type { Message } from "@oh-my-pi/pi-ai"; import summarizationSystemPrompt from "../../prompts/summarization-system.md" with { type: "text" }; // ============================================================================ diff --git a/packages/coding-agent/src/core/custom-tools/types.ts b/packages/coding-agent/src/core/custom-tools/types.ts index f6813cf2d..3e65fd328 100644 --- a/packages/coding-agent/src/core/custom-tools/types.ts +++ b/packages/coding-agent/src/core/custom-tools/types.ts @@ -5,8 +5,8 @@ * They can provide custom rendering for tool calls and results in the TUI. */ -import type { Model } from "@oh-my-pi/pi-ai"; import type { AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core"; +import type { Model } from "@oh-my-pi/pi-ai"; import type { Component } from "@oh-my-pi/pi-tui"; import type { Static, TSchema } from "@sinclair/typebox"; import type { Theme } from "../../modes/interactive/theme/theme"; @@ -140,7 +140,7 @@ export interface CustomTool { params: Static, onUpdate: AgentToolUpdateCallback | undefined, ctx: CustomToolContext, - signal?: AbortSignal + signal?: AbortSignal, ): Promise>; /** Called on session lifecycle events - use to reconstruct state or cleanup resources */ @@ -154,7 +154,7 @@ export interface CustomTool { /** Factory function that creates a custom tool or array of tools */ export type CustomToolFactory = ( - pi: CustomToolAPI + pi: CustomToolAPI, ) => CustomTool | CustomTool[] | Promise | CustomTool[]>; /** Loaded custom tool with metadata and wrapped AgentTool */ diff --git a/packages/coding-agent/src/core/extensions/runner.ts b/packages/coding-agent/src/core/extensions/runner.ts index ef2cc9224..e8ff61a61 100644 --- a/packages/coding-agent/src/core/extensions/runner.ts +++ b/packages/coding-agent/src/core/extensions/runner.ts @@ -2,8 +2,8 @@ * Extension runner - executes extensions and manages their lifecycle. */ -import type { ImageContent, Model } from "@oh-my-pi/pi-ai"; import type { AgentMessage } from "@oh-my-pi/pi-agent-core"; +import type { ImageContent, Model } from "@oh-my-pi/pi-ai"; import type { KeyId } from "@oh-my-pi/pi-tui"; import { theme } from "../../modes/interactive/theme/theme"; import type { ModelRegistry } from "../model-registry"; @@ -53,7 +53,7 @@ export type BranchHandler = (entryId: string) => Promise<{ cancelled: boolean }> export type NavigateTreeHandler = ( targetId: string, - options?: { summarize?: boolean } + options?: { summarize?: boolean }, ) => Promise<{ cancelled: boolean }>; const noOpUIContext: ExtensionUIContext = { @@ -94,7 +94,7 @@ export class ExtensionRunner { extensions: LoadedExtension[], cwd: string, sessionManager: SessionManager, - modelRegistry: ModelRegistry + modelRegistry: ModelRegistry, ) { this.extensions = extensions; this.uiContext = noOpUIContext; @@ -215,7 +215,7 @@ export class ExtensionRunner { if (ExtensionRunner.RESERVED_SHORTCUTS.has(normalizedKey)) { console.warn( - `Extension shortcut '${key}' from ${shortcut.extensionPath} conflicts with built-in shortcut. Skipping.` + `Extension shortcut '${key}' from ${shortcut.extensionPath} conflicts with built-in shortcut. Skipping.`, ); continue; } @@ -223,7 +223,7 @@ export class ExtensionRunner { const existing = allShortcuts.get(normalizedKey); if (existing) { console.warn( - `Extension shortcut conflict: '${key}' registered by both ${existing.extensionPath} and ${shortcut.extensionPath}. Using ${shortcut.extensionPath}.` + `Extension shortcut conflict: '${key}' registered by both ${existing.extensionPath} and ${shortcut.extensionPath}. Using ${shortcut.extensionPath}.`, ); } allShortcuts.set(normalizedKey, shortcut); @@ -309,7 +309,7 @@ export class ExtensionRunner { } private isSessionBeforeEvent( - type: string + type: string, ): type is "session_before_switch" | "session_before_branch" | "session_before_compact" | "session_before_tree" { return ( type === "session_before_switch" || @@ -320,7 +320,7 @@ export class ExtensionRunner { } async emit( - event: ExtensionEvent + event: ExtensionEvent, ): Promise { const ctx = this.createContext(); let result: SessionBeforeCompactResult | SessionBeforeTreeResult | ToolResultEventResult | undefined; @@ -428,7 +428,7 @@ export class ExtensionRunner { async emitBeforeAgentStart( prompt: string, - images?: ImageContent[] + images?: ImageContent[], ): Promise { const ctx = this.createContext(); const messages: NonNullable[] = []; diff --git a/packages/coding-agent/src/core/extensions/types.ts b/packages/coding-agent/src/core/extensions/types.ts index 0b1c354d4..594c644ee 100644 --- a/packages/coding-agent/src/core/extensions/types.ts +++ b/packages/coding-agent/src/core/extensions/types.ts @@ -8,8 +8,8 @@ * - Interact with the user via UI primitives */ -import type { ImageContent, Model, TextContent, ToolResultMessage } from "@oh-my-pi/pi-ai"; import type { AgentMessage, AgentToolResult, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core"; +import type { ImageContent, Model, TextContent, ToolResultMessage } from "@oh-my-pi/pi-ai"; import type { Component, KeyId, TUI } from "@oh-my-pi/pi-tui"; import type { Static, TSchema } from "@sinclair/typebox"; import type { Theme } from "../../modes/interactive/theme/theme"; @@ -67,8 +67,8 @@ export interface ExtensionUIContext { factory: ( tui: TUI, theme: Theme, - done: (result: T) => void - ) => (Component & { dispose?(): void }) | Promise + done: (result: T) => void, + ) => (Component & { dispose?(): void }) | Promise, ): Promise; /** Set the text in the core input editor. */ @@ -178,7 +178,7 @@ export interface ToolDefinition, onUpdate: AgentToolUpdateCallback | undefined, ctx: ExtensionContext, - signal?: AbortSignal + signal?: AbortSignal, ): Promise>; /** Called on session lifecycle events - use to reconstruct state or cleanup resources */ @@ -490,7 +490,7 @@ export interface MessageRenderOptions { export type MessageRenderer = ( message: CustomMessage, options: MessageRenderOptions, - theme: Theme + theme: Theme, ) => Component | undefined; // ============================================================================ @@ -535,17 +535,17 @@ export interface ExtensionAPI { on(event: "session_start", handler: ExtensionHandler): void; on( event: "session_before_switch", - handler: ExtensionHandler + handler: ExtensionHandler, ): void; on(event: "session_switch", handler: ExtensionHandler): void; on( event: "session_before_branch", - handler: ExtensionHandler + handler: ExtensionHandler, ): void; on(event: "session_branch", handler: ExtensionHandler): void; on( event: "session_before_compact", - handler: ExtensionHandler + handler: ExtensionHandler, ): void; on(event: "session_compact", handler: ExtensionHandler): void; on(event: "session_shutdown", handler: ExtensionHandler): void; @@ -580,7 +580,7 @@ export interface ExtensionAPI { options: { description?: string; handler: (ctx: ExtensionContext) => Promise | void; - } + }, ): void; /** Register a CLI flag. */ @@ -590,7 +590,7 @@ export interface ExtensionAPI { description?: string; type: "boolean" | "string"; default?: boolean | string; - } + }, ): void; /** Get the value of a registered CLI flag. */ @@ -610,7 +610,7 @@ export interface ExtensionAPI { /** Send a custom message to the session. */ sendMessage( message: Pick, "customType" | "content" | "display" | "details">, - options?: { triggerTurn?: boolean; deliverAs?: "steer" | "followUp" | "nextTurn" } + options?: { triggerTurn?: boolean; deliverAs?: "steer" | "followUp" | "nextTurn" }, ): void; /** Append a custom entry to the session for state persistence (not sent to LLM). */ @@ -663,7 +663,7 @@ type HandlerFn = (...args: unknown[]) => Promise; export type SendMessageHandler = ( message: Pick, "customType" | "content" | "display" | "details">, - options?: { triggerTurn?: boolean; deliverAs?: "steer" | "followUp" | "nextTurn" } + options?: { triggerTurn?: boolean; deliverAs?: "steer" | "followUp" | "nextTurn" }, ) => void; export type AppendEntryHandler = (customType: string, data?: T) => void; diff --git a/packages/coding-agent/src/core/extensions/wrapper.ts b/packages/coding-agent/src/core/extensions/wrapper.ts index bbfacf316..f3dcc5a1c 100644 --- a/packages/coding-agent/src/core/extensions/wrapper.ts +++ b/packages/coding-agent/src/core/extensions/wrapper.ts @@ -2,8 +2,8 @@ * Tool wrappers for extensions. */ -import type { ImageContent, TextContent } from "@oh-my-pi/pi-ai"; import type { AgentTool, AgentToolContext, AgentToolUpdateCallback } from "@oh-my-pi/pi-agent-core"; +import type { ImageContent, TextContent } from "@oh-my-pi/pi-ai"; import type { Theme } from "../../modes/interactive/theme/theme"; import type { ExtensionRunner } from "./runner"; import type { ExtensionContext, RegisteredTool, ToolCallEventResult, ToolResultEventResult } from "./types"; @@ -26,7 +26,7 @@ export function wrapRegisteredTool(registeredTool: RegisteredTool, getContext: ( definition.renderResult?.( result, { expanded: options.expanded, isPartial: options.isPartial, spinnerFrame: options.spinnerFrame }, - theme as Theme + theme as Theme, ) : undefined, }; @@ -37,7 +37,7 @@ export function wrapRegisteredTool(registeredTool: RegisteredTool, getContext: ( */ export function wrapRegisteredTools( registeredTools: RegisteredTool[], - getContext: () => ExtensionContext + getContext: () => ExtensionContext, ): AgentTool[] { return registeredTools.map((rt) => wrapRegisteredTool(rt, getContext)); } @@ -55,7 +55,7 @@ export function wrapToolWithExtensions(tool: AgentTool, runner: Exten params: Record, signal?: AbortSignal, onUpdate?: AgentToolUpdateCallback, - context?: AgentToolContext + context?: AgentToolContext, ) => { // Emit tool_call event - extensions can block execution if (runner.hasHandlers("tool_call")) { @@ -113,7 +113,8 @@ export function wrapToolWithExtensions(tool: AgentTool, runner: Exten if (resultResult.isError === true && !executionError) { // Extension marks a successful result as error const textBlocks = (modifiedContent ?? []).filter((c): c is TextContent => c.type === "text"); - const errorText = textBlocks.map((t) => t.text).join("\n") || "Tool result marked as error by extension"; + const errorText = + textBlocks.map((t) => t.text).join("\n") || "Tool result marked as error by extension"; throw new Error(errorText); } if (resultResult.isError === false && executionError) { diff --git a/packages/coding-agent/src/core/hooks/runner.ts b/packages/coding-agent/src/core/hooks/runner.ts index ef5b90470..e1081657a 100644 --- a/packages/coding-agent/src/core/hooks/runner.ts +++ b/packages/coding-agent/src/core/hooks/runner.ts @@ -2,8 +2,8 @@ * Hook runner - executes hooks and manages their lifecycle. */ -import type { Model } from "@oh-my-pi/pi-ai"; import type { AgentMessage } from "@oh-my-pi/pi-agent-core"; +import type { Model } from "@oh-my-pi/pi-ai"; import { theme } from "../../modes/interactive/theme/theme"; import type { ModelRegistry } from "../model-registry"; import type { SessionManager } from "../session-manager"; @@ -272,7 +272,7 @@ export class HookRunner { * Check if event type is a session "before_*" event that can be cancelled. */ private isSessionBeforeEvent( - type: string + type: string, ): type is "session_before_switch" | "session_before_branch" | "session_before_compact" | "session_before_tree" { return ( type === "session_before_switch" || @@ -287,7 +287,7 @@ export class HookRunner { * Returns the result from session before_* / tool_result events (if any handler returns one). */ async emit( - event: HookEvent + event: HookEvent, ): Promise { const ctx = this.createContext(); let result: SessionBeforeCompactResult | SessionBeforeTreeResult | ToolResultEventResult | undefined; @@ -400,7 +400,7 @@ export class HookRunner { */ async emitBeforeAgentStart( prompt: string, - images?: import("@oh-my-pi/pi-ai").ImageContent[] + images?: import("@oh-my-pi/pi-ai").ImageContent[], ): Promise { const ctx = this.createContext(); let result: BeforeAgentStartEventResult | undefined; diff --git a/packages/coding-agent/src/core/hooks/types.ts b/packages/coding-agent/src/core/hooks/types.ts index e2b9da123..16a69ebe8 100644 --- a/packages/coding-agent/src/core/hooks/types.ts +++ b/packages/coding-agent/src/core/hooks/types.ts @@ -5,8 +5,8 @@ * and interact with the user via UI primitives. */ -import type { ImageContent, Message, Model, TextContent, ToolResultMessage } from "@oh-my-pi/pi-ai"; import type { AgentMessage } from "@oh-my-pi/pi-agent-core"; +import type { ImageContent, Message, Model, TextContent, ToolResultMessage } from "@oh-my-pi/pi-ai"; import type { Component, TUI } from "@oh-my-pi/pi-tui"; import type { Theme } from "../../modes/interactive/theme/theme"; import type { CompactionPreparation, CompactionResult } from "../compaction/index"; @@ -97,8 +97,8 @@ export interface HookUIContext { factory: ( tui: TUI, theme: Theme, - done: (result: T) => void - ) => (Component & { dispose?(): void }) | Promise + done: (result: T) => void, + ) => (Component & { dispose?(): void }) | Promise, ): Promise; /** @@ -632,7 +632,7 @@ export interface HookMessageRenderOptions { export type HookMessageRenderer = ( message: HookMessage, options: HookMessageRenderOptions, - theme: Theme + theme: Theme, ) => Component | undefined; /** @@ -658,7 +658,7 @@ export interface HookAPI { on(event: "session_branch", handler: HookHandler): void; on( event: "session_before_compact", - handler: HookHandler + handler: HookHandler, ): void; on(event: "session_compact", handler: HookHandler): void; on(event: "session_shutdown", handler: HookHandler): void; @@ -692,7 +692,7 @@ export interface HookAPI { */ sendMessage( message: Pick, "customType" | "content" | "display" | "details">, - triggerTurn?: boolean + triggerTurn?: boolean, ): void; /** diff --git a/packages/coding-agent/src/core/messages.ts b/packages/coding-agent/src/core/messages.ts index 9eeb24eab..6bd84fe1e 100644 --- a/packages/coding-agent/src/core/messages.ts +++ b/packages/coding-agent/src/core/messages.ts @@ -5,8 +5,8 @@ * and provides a transformer to convert them to LLM-compatible messages. */ -import type { ImageContent, Message, TextContent } from "@oh-my-pi/pi-ai"; import type { AgentMessage } from "@oh-my-pi/pi-agent-core"; +import type { ImageContent, Message, TextContent } from "@oh-my-pi/pi-ai"; export const COMPACTION_SUMMARY_PREFIX = `The conversation history before this point was compacted into the following summary: @@ -136,7 +136,7 @@ export function createBranchSummaryMessage(summary: string, fromId: string, time export function createCompactionSummaryMessage( summary: string, tokensBefore: number, - timestamp: string + timestamp: string, ): CompactionSummaryMessage { return { role: "compactionSummary", @@ -152,7 +152,7 @@ export function createCustomMessage( content: string | (TextContent | ImageContent)[], display: boolean, details: unknown | undefined, - timestamp: string + timestamp: string, ): CustomMessage { return { role: "custom", diff --git a/packages/coding-agent/src/core/model-registry.ts b/packages/coding-agent/src/core/model-registry.ts index 1c787cdbe..6b522972b 100644 --- a/packages/coding-agent/src/core/model-registry.ts +++ b/packages/coding-agent/src/core/model-registry.ts @@ -39,7 +39,7 @@ const ModelDefinitionSchema = Type.Object({ Type.Literal("anthropic-messages"), Type.Literal("google-generative-ai"), Type.Literal("google-vertex"), - ]) + ]), ), reasoning: Type.Boolean(), input: Type.Array(Type.Union([Type.Literal("text"), Type.Literal("image")])), @@ -66,7 +66,7 @@ const ProviderConfigSchema = Type.Object({ Type.Literal("anthropic-messages"), Type.Literal("google-generative-ai"), Type.Literal("google-vertex"), - ]) + ]), ), headers: Type.Optional(Type.Record(Type.String(), Type.String())), authHeader: Type.Optional(Type.Boolean()), @@ -126,7 +126,7 @@ export class ModelRegistry { constructor( readonly authStorage: AuthStorage, private modelsJsonPath: string | undefined = undefined, - private fallbackPaths: string[] = [] + private fallbackPaths: string[] = [], ) { // Set up fallback resolver for custom provider API keys this.authStorage.setFallbackResolver((provider) => { @@ -189,7 +189,9 @@ export class ModelRegistry { // Update github-copilot base URL based on OAuth credentials const copilotCred = this.authStorage.get("github-copilot"); if (copilotCred?.type === "oauth") { - const domain = copilotCred.enterpriseUrl ? normalizeDomain(copilotCred.enterpriseUrl) ?? undefined : undefined; + const domain = copilotCred.enterpriseUrl + ? (normalizeDomain(copilotCred.enterpriseUrl) ?? undefined) + : undefined; const baseUrl = getGitHubCopilotBaseUrl(copilotCred.access, domain); this.models = combined.map((m) => (m.provider === "github-copilot" ? { ...m, baseUrl } : m)); } else { @@ -265,7 +267,7 @@ export class ModelRegistry { return emptyCustomModelsResult(`Failed to parse models.json: ${error.message}\n\nFile: ${modelsJsonPath}`); } return emptyCustomModelsResult( - `Failed to load models.json: ${error instanceof Error ? error.message : error}\n\nFile: ${modelsJsonPath}` + `Failed to load models.json: ${error instanceof Error ? error.message : error}\n\nFile: ${modelsJsonPath}`, ); } } @@ -279,7 +281,7 @@ export class ModelRegistry { // Override-only config: just needs baseUrl (to override built-in) if (!providerConfig.baseUrl) { throw new Error( - `Provider ${providerName}: must specify either "baseUrl" (for override) or "models" (for replacement).` + `Provider ${providerName}: must specify either "baseUrl" (for override) or "models" (for replacement).`, ); } } else { @@ -297,7 +299,7 @@ export class ModelRegistry { if (!hasProviderApi && !hasModelApi) { throw new Error( - `Provider ${providerName}, model ${modelDef.id}: no "api" specified. Set at provider or model level.` + `Provider ${providerName}, model ${modelDef.id}: no "api" specified. Set at provider or model level.`, ); } @@ -329,7 +331,9 @@ export class ModelRegistry { // Merge headers: provider headers are base, model headers override let headers = - providerConfig.headers || modelDef.headers ? { ...providerConfig.headers, ...modelDef.headers } : undefined; + providerConfig.headers || modelDef.headers + ? { ...providerConfig.headers, ...modelDef.headers } + : undefined; // If authHeader is true, add Authorization header with resolved API key if (providerConfig.authHeader && providerConfig.apiKey) { diff --git a/packages/coding-agent/src/core/model-resolver.ts b/packages/coding-agent/src/core/model-resolver.ts index 2c50b35c1..ce2c42f3b 100644 --- a/packages/coding-agent/src/core/model-resolver.ts +++ b/packages/coding-agent/src/core/model-resolver.ts @@ -2,8 +2,8 @@ * Model resolution, scoping, and initial selection */ -import { type Api, type KnownProvider, type Model, modelsAreEqual } from "@oh-my-pi/pi-ai"; import type { ThinkingLevel } from "@oh-my-pi/pi-agent-core"; +import { type Api, type KnownProvider, type Model, modelsAreEqual } from "@oh-my-pi/pi-ai"; import chalk from "chalk"; import { minimatch } from "minimatch"; import { isValidThinkingLevel } from "../cli/args"; @@ -25,6 +25,7 @@ export const defaultModelPerProvider: Record = { cerebras: "zai-glm-4.6", zai: "glm-4.6", mistral: "devstral-medium-latest", + opencode: "claude-sonnet-4-5", }; export interface ScopedModel { @@ -79,7 +80,7 @@ function tryMatchModel(modelPattern: string, availableModels: Model[]): Mod const provider = modelPattern.substring(0, slashIndex); const modelId = modelPattern.substring(slashIndex + 1); const providerMatch = availableModels.find( - (m) => m.provider.toLowerCase() === provider.toLowerCase() && m.id.toLowerCase() === modelId.toLowerCase() + (m) => m.provider.toLowerCase() === provider.toLowerCase() && m.id.toLowerCase() === modelId.toLowerCase(), ); if (providerMatch) { return providerMatch; @@ -97,7 +98,7 @@ function tryMatchModel(modelPattern: string, availableModels: Model[]): Mod const matches = availableModels.filter( (m) => m.id.toLowerCase().includes(modelPattern.toLowerCase()) || - m.name?.toLowerCase().includes(modelPattern.toLowerCase()) + m.name?.toLowerCase().includes(modelPattern.toLowerCase()), ); if (matches.length === 0) { @@ -351,7 +352,7 @@ export async function restoreModelFromSession( savedModelId: string, currentModel: Model | undefined, shouldPrintMessages: boolean, - modelRegistry: ModelRegistry + modelRegistry: ModelRegistry, ): Promise<{ model: Model | undefined; fallbackMessage: string | undefined }> { const restoredModel = modelRegistry.find(savedProvider, savedModelId); @@ -427,7 +428,7 @@ export async function restoreModelFromSession( */ export async function findSmolModel( modelRegistry: ModelRegistry, - savedModel?: string + savedModel?: string, ): Promise | undefined> { const availableModels = modelRegistry.getAvailable(); if (availableModels.length === 0) return undefined; @@ -470,7 +471,7 @@ export async function findSmolModel( */ export async function findSlowModel( modelRegistry: ModelRegistry, - savedModel?: string + savedModel?: string, ): Promise | undefined> { const availableModels = modelRegistry.getAvailable(); if (availableModels.length === 0) return undefined; diff --git a/packages/coding-agent/src/core/sdk.ts b/packages/coding-agent/src/core/sdk.ts index d39fceb28..93d23ba84 100644 --- a/packages/coding-agent/src/core/sdk.ts +++ b/packages/coding-agent/src/core/sdk.ts @@ -27,8 +27,8 @@ */ import { join } from "node:path"; -import type { Model } from "@oh-my-pi/pi-ai"; import { Agent, type AgentTool, type ThinkingLevel } from "@oh-my-pi/pi-agent-core"; +import type { Model } from "@oh-my-pi/pi-ai"; import type { Component } from "@oh-my-pi/pi-tui"; import chalk from "chalk"; // Import discovery to register all providers on startup @@ -248,7 +248,7 @@ export async function discoverAuthStorage(agentDir: string = getDefaultAgentDir( */ export async function discoverModels( authStorage: AuthStorage, - agentDir: string = getDefaultAgentDir() + agentDir: string = getDefaultAgentDir(), ): Promise { const primaryPath = join(agentDir, "models.json"); // Get all models.json paths (user-level only), excluding the primary @@ -288,7 +288,7 @@ export function discoverSkills(cwd?: string, _agentDir?: string, settings?: Skil */ export function discoverContextFiles( cwd?: string, - _agentDir?: string + _agentDir?: string, ): Array<{ path: string; content: string; depth?: number }> { return loadContextFilesInternal({ cwd: cwd ?? process.cwd(), @@ -436,11 +436,11 @@ function customToolToDefinition(tool: CustomTool): ToolDefinition { const component = tool.renderResult?.( result, { expanded: options.expanded, isPartial: options.isPartial, spinnerFrame: options.spinnerFrame }, - theme + theme, ); // Return empty component if undefined to match Component type requirement return component ?? ({ render: () => [] } as unknown as Component); - } + } : undefined, [TOOL_DEFINITION_MARKER]: true, }; @@ -465,19 +465,19 @@ function createCustomToolsExtension(tools: CustomTool[]): ExtensionFactory { }; api.on("session_start", async (_event, ctx) => - runOnSession({ reason: "start", previousSessionFile: undefined }, ctx) + runOnSession({ reason: "start", previousSessionFile: undefined }, ctx), ); api.on("session_switch", async (event, ctx) => - runOnSession({ reason: "switch", previousSessionFile: event.previousSessionFile }, ctx) + runOnSession({ reason: "switch", previousSessionFile: event.previousSessionFile }, ctx), ); api.on("session_branch", async (event, ctx) => - runOnSession({ reason: "branch", previousSessionFile: event.previousSessionFile }, ctx) + runOnSession({ reason: "branch", previousSessionFile: event.previousSessionFile }, ctx), ); api.on("session_tree", async (_event, ctx) => - runOnSession({ reason: "tree", previousSessionFile: undefined }, ctx) + runOnSession({ reason: "tree", previousSessionFile: undefined }, ctx), ); api.on("session_shutdown", async (_event, ctx) => - runOnSession({ reason: "shutdown", previousSessionFile: undefined }, ctx) + runOnSession({ reason: "shutdown", previousSessionFile: undefined }, ctx), ); }; } @@ -659,7 +659,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {} if (options.hasUI && serverNames.length > 0) { process.stderr.write( chalk.gray(`Connecting to MCP servers: ${serverNames.join(", ")}... -`) +`), ); } }, @@ -728,7 +728,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {} configuredPaths, cwd, eventBus, - settingsManager.getDisabledExtensions() + settingsManager.getDisabledExtensions(), ); time("discoverAndLoadExtensions"); for (const { path, error } of extensionsResult.errors) { @@ -905,7 +905,7 @@ export async function createAgentSession(options: CreateAgentSessionOptions = {} transformContext: extensionRunner ? async (messages) => { return extensionRunner.emitContext(messages); - } + } : undefined, steeringMode: settingsManager.getSteeringMode(), followUpMode: settingsManager.getFollowUpMode(), diff --git a/packages/coding-agent/src/core/session-manager.ts b/packages/coding-agent/src/core/session-manager.ts index 601fb38c6..0e8f84d30 100644 --- a/packages/coding-agent/src/core/session-manager.ts +++ b/packages/coding-agent/src/core/session-manager.ts @@ -1,6 +1,6 @@ import { basename, join, resolve } from "node:path"; -import type { ImageContent, Message, TextContent, Usage } from "@oh-my-pi/pi-ai"; import type { AgentMessage } from "@oh-my-pi/pi-agent-core"; +import type { ImageContent, Message, TextContent, Usage } from "@oh-my-pi/pi-ai"; import { nanoid } from "nanoid"; import { getAgentDir as getDefaultAgentDir } from "../config"; import { resizeImage } from "../utils/image-resize"; @@ -304,7 +304,7 @@ function toError(value: unknown): Error { export function buildSessionContext( entries: SessionEntry[], leafId?: string | null, - byId?: Map + byId?: Map, ): SessionContext { // Build uuid index if not available if (!byId) { @@ -382,7 +382,7 @@ export function buildSessionContext( messages.push(entry.message); } else if (entry.type === "custom_message") { messages.push( - createCustomMessage(entry.customType, entry.content, entry.display, entry.details, entry.timestamp) + createCustomMessage(entry.customType, entry.content, entry.display, entry.details, entry.timestamp), ); } else if (entry.type === "branch_summary" && entry.summary) { messages.push(createBranchSummaryMessage(entry.summary, entry.fromId, entry.timestamp)); @@ -540,7 +540,7 @@ function getSortedSessions(sessionDir: string, storage: SessionStorage): RecentS /** Exported for testing */ export function findMostRecentSession( sessionDir: string, - storage: SessionStorage = new FileSessionStorage() + storage: SessionStorage = new FileSessionStorage(), ): string | null { const sessions = getSortedSessions(sessionDir, storage); return sessions[0]?.path || null; @@ -645,7 +645,7 @@ async function truncateForPersistence(obj: T, key?: string): Promise { const newItem = await truncateForPersistence(item, key); if (newItem !== item) changed = true; return newItem; - }) + }), ); return changed ? (result as T) : obj; } @@ -800,7 +800,7 @@ class NdjsonFileWriter { export function getRecentSessions( sessionDir: string, limit = 3, - storage: SessionStorage = new FileSessionStorage() + storage: SessionStorage = new FileSessionStorage(), ): RecentSessionInfo[] { return getSortedSessions(sessionDir, storage).slice(0, limit); } @@ -1021,7 +1021,7 @@ export class SessionManager { async () => { await this._closePersistWriterInternal(); }, - { ignoreError: true } + { ignoreError: true }, ); } @@ -1229,7 +1229,7 @@ export class SessionManager { firstKeptEntryId: string, tokensBefore: number, details?: T, - fromExtension?: boolean + fromExtension?: boolean, ): string { const entry: CompactionEntry = { type: "compaction", @@ -1272,7 +1272,7 @@ export class SessionManager { customType: string, content: string | (TextContent | ImageContent)[], display: boolean, - details?: T + details?: T, ): string { const entry: CustomMessageEntry = { type: "custom_message", @@ -1632,7 +1632,7 @@ export class SessionManager { static async open( path: string, sessionDir?: string, - storage: SessionStorage = new FileSessionStorage() + storage: SessionStorage = new FileSessionStorage(), ): Promise { // Extract cwd from session header if possible, otherwise use process.cwd() const entries = loadEntriesFromFile(path, storage); @@ -1653,7 +1653,7 @@ export class SessionManager { static async continueRecent( cwd: string, sessionDir?: string, - storage: SessionStorage = new FileSessionStorage() + storage: SessionStorage = new FileSessionStorage(), ): Promise { const dir = sessionDir ?? getDefaultSessionDir(cwd, storage); const mostRecent = findMostRecentSession(dir, storage); diff --git a/packages/coding-agent/src/core/tools/output.ts b/packages/coding-agent/src/core/tools/output.ts index ab73b948c..d0e4f4d63 100644 --- a/packages/coding-agent/src/core/tools/output.ts +++ b/packages/coding-agent/src/core/tools/output.ts @@ -6,8 +6,8 @@ import * as fs from "node:fs"; import * as path from "node:path"; -import type { TextContent } from "@oh-my-pi/pi-ai"; import type { AgentTool } from "@oh-my-pi/pi-agent-core"; +import type { TextContent } from "@oh-my-pi/pi-ai"; import type { Component } from "@oh-my-pi/pi-tui"; import { Text } from "@oh-my-pi/pi-tui"; import { Type } from "@sinclair/typebox"; diff --git a/packages/coding-agent/src/core/tools/read.ts b/packages/coding-agent/src/core/tools/read.ts index 3669be6cd..70cf4a384 100644 --- a/packages/coding-agent/src/core/tools/read.ts +++ b/packages/coding-agent/src/core/tools/read.ts @@ -1,7 +1,7 @@ import { homedir } from "node:os"; import path from "node:path"; -import type { ImageContent, TextContent } from "@oh-my-pi/pi-ai"; import type { AgentTool } from "@oh-my-pi/pi-agent-core"; +import type { ImageContent, TextContent } from "@oh-my-pi/pi-ai"; import type { Component } from "@oh-my-pi/pi-tui"; import { Text } from "@oh-my-pi/pi-tui"; import { Type } from "@sinclair/typebox"; diff --git a/packages/coding-agent/src/core/tools/task/index.ts b/packages/coding-agent/src/core/tools/task/index.ts index 26edc45ba..62a47915a 100644 --- a/packages/coding-agent/src/core/tools/task/index.ts +++ b/packages/coding-agent/src/core/tools/task/index.ts @@ -13,8 +13,8 @@ * - Session artifacts for debugging */ -import type { Usage } from "@oh-my-pi/pi-ai"; import type { AgentTool } from "@oh-my-pi/pi-agent-core"; +import type { Usage } from "@oh-my-pi/pi-ai"; import type { Theme } from "../../../modes/interactive/theme/theme"; import taskDescriptionTemplate from "../../../prompts/tools/task.md" with { type: "text" }; import { formatDuration } from "../render-utils"; diff --git a/packages/coding-agent/src/core/tools/task/types.ts b/packages/coding-agent/src/core/tools/task/types.ts index 0690eb643..6735729a6 100644 --- a/packages/coding-agent/src/core/tools/task/types.ts +++ b/packages/coding-agent/src/core/tools/task/types.ts @@ -59,12 +59,12 @@ export const taskSchema = Type.Object({ model: Type.Optional( Type.String({ description: "Model override for all tasks (fuzzy matching, e.g. 'sonnet', 'opus')", - }) + }), ), output: Type.Optional( Type.Any({ description: "JTD schema for structured subagent output (used by the complete tool)", - }) + }), ), tasks: Type.Array(taskItemSchema, { description: "Tasks to run in parallel", diff --git a/packages/coding-agent/src/core/tools/task/worker.ts b/packages/coding-agent/src/core/tools/task/worker.ts index 8084dc49b..1d3d80e9f 100644 --- a/packages/coding-agent/src/core/tools/task/worker.ts +++ b/packages/coding-agent/src/core/tools/task/worker.ts @@ -13,8 +13,8 @@ * 5. Parent can send { type: "abort" } to request cancellation */ -import type { Api, Model } from "@oh-my-pi/pi-ai"; import type { AgentEvent, ThinkingLevel } from "@oh-my-pi/pi-agent-core"; +import type { Api, Model } from "@oh-my-pi/pi-ai"; import type { AgentSessionEvent } from "../../agent-session"; import { parseModelPattern, parseModelString } from "../../model-resolver"; import { createAgentSession, discoverAuthStorage, discoverModels } from "../../sdk"; @@ -88,7 +88,7 @@ let pendingAbort = false; */ function resolveModelOverride( override: string | undefined, - modelRegistry: { getAvailable: () => Model[]; find: (provider: string, id: string) => Model | undefined } + modelRegistry: { getAvailable: () => Model[]; find: (provider: string, id: string) => Model | undefined }, ): { model?: Model; thinkingLevel?: ThinkingLevel } { if (!override) return {}; @@ -190,7 +190,7 @@ async function runTask(runState: RunState, payload: SubagentWorkerStartPayload): () => { void session.abort(); }, - { once: true, signal: sessionAbortController.signal } + { once: true, signal: sessionAbortController.signal }, ); // Initialize extensions (equivalent to CLI's extension initialization) diff --git a/packages/coding-agent/src/main.ts b/packages/coding-agent/src/main.ts index fc799d14a..e4a70a170 100644 --- a/packages/coding-agent/src/main.ts +++ b/packages/coding-agent/src/main.ts @@ -63,7 +63,7 @@ async function runInteractiveMode( lspServers: Array<{ name: string; status: "ready" | "error"; fileTypes: string[] }> | undefined, initialMessage?: string, initialImages?: ImageContent[], - fdPath: string | undefined = undefined + fdPath: string | undefined = undefined, ): Promise { const mode = new InteractiveMode(session, version, changelogMarkdown, setExtensionUIContext, lspServers, fdPath); @@ -120,7 +120,7 @@ async function runInteractiveMode( async function prepareInitialMessage( parsed: Args, - autoResizeImages: boolean + autoResizeImages: boolean, ): Promise<{ initialMessage?: string; initialImages?: ImageContent[]; @@ -262,7 +262,7 @@ async function buildSessionOptions( scopedModels: ScopedModel[], sessionManager: SessionManager | undefined, modelRegistry: ModelRegistry, - settingsManager: SettingsManager + settingsManager: SettingsManager, ): Promise { const options: CreateAgentSessionOptions = { cwd: parsed.cwd ?? process.cwd(), @@ -484,7 +484,7 @@ export async function main(args: string[]) { scopedModels, sessionManager, modelRegistry, - settingsManager + settingsManager, ); sessionOptions.authStorage = authStorage; sessionOptions.modelRegistry = modelRegistry; @@ -575,7 +575,7 @@ export async function main(args: string[]) { lspServers, initialMessage, initialImages, - fdPath + fdPath, ); } else { await runPrintMode(session, mode, parsed.messages, initialMessage, initialImages); diff --git a/packages/coding-agent/src/modes/interactive/components/assistant-message.ts b/packages/coding-agent/src/modes/interactive/components/assistant-message.ts index ed52b2fd3..08e30857b 100644 --- a/packages/coding-agent/src/modes/interactive/components/assistant-message.ts +++ b/packages/coding-agent/src/modes/interactive/components/assistant-message.ts @@ -33,7 +33,9 @@ export class AssistantMessageComponent extends Container { if ( message.content.length > 0 && - message.content.some((c) => (c.type === "text" && c.text.trim()) || (c.type === "thinking" && c.thinking.trim())) + message.content.some( + (c) => (c.type === "text" && c.text.trim()) || (c.type === "thinking" && c.thinking.trim()), + ) ) { this.contentContainer.addChild(new Spacer(1)); } @@ -61,7 +63,7 @@ export class AssistantMessageComponent extends Container { new Markdown(content.thinking.trim(), 1, 0, getMarkdownTheme(), { color: (text: string) => theme.fg("thinkingText", text), italic: true, - }) + }), ); this.contentContainer.addChild(new Spacer(1)); } diff --git a/packages/coding-agent/src/modes/interactive/components/custom-message.ts b/packages/coding-agent/src/modes/interactive/components/custom-message.ts index 3d3e61644..b1bb8c43b 100644 --- a/packages/coding-agent/src/modes/interactive/components/custom-message.ts +++ b/packages/coding-agent/src/modes/interactive/components/custom-message.ts @@ -89,7 +89,7 @@ export class CustomMessageComponent extends Container { this.box.addChild( new Markdown(text, 0, 0, getMarkdownTheme(), { color: (value: string) => theme.fg("customMessageText", value), - }) + }), ); } } diff --git a/packages/coding-agent/src/modes/interactive/components/footer.ts b/packages/coding-agent/src/modes/interactive/components/footer.ts index 827195f7a..95556dd71 100644 --- a/packages/coding-agent/src/modes/interactive/components/footer.ts +++ b/packages/coding-agent/src/modes/interactive/components/footer.ts @@ -181,9 +181,9 @@ export class FooterComponent implements Component { // Calculate context percentage from last message (input + output + cacheRead + cacheWrite) const contextTokens = lastAssistantMessage ? lastAssistantMessage.usage.input + - lastAssistantMessage.usage.output + - lastAssistantMessage.usage.cacheRead + - lastAssistantMessage.usage.cacheWrite + lastAssistantMessage.usage.output + + lastAssistantMessage.usage.cacheRead + + lastAssistantMessage.usage.cacheWrite : 0; const contextWindow = state.model?.contextWindow || 0; const contextPercentValue = contextWindow > 0 ? (contextTokens / contextWindow) * 100 : 0; diff --git a/packages/coding-agent/src/modes/interactive/components/hook-message.ts b/packages/coding-agent/src/modes/interactive/components/hook-message.ts index d711f9cbd..fb91db3ba 100644 --- a/packages/coding-agent/src/modes/interactive/components/hook-message.ts +++ b/packages/coding-agent/src/modes/interactive/components/hook-message.ts @@ -90,7 +90,7 @@ export class HookMessageComponent extends Container { this.box.addChild( new Markdown(text, 0, 0, getMarkdownTheme(), { color: (text: string) => theme.fg("customMessageText", text), - }) + }), ); } } diff --git a/packages/coding-agent/src/modes/interactive/components/model-selector.ts b/packages/coding-agent/src/modes/interactive/components/model-selector.ts index 86b1a5e60..73d5a66a6 100644 --- a/packages/coding-agent/src/modes/interactive/components/model-selector.ts +++ b/packages/coding-agent/src/modes/interactive/components/model-selector.ts @@ -93,7 +93,7 @@ export class ModelSelectorComponent extends Container { scopedModels: ReadonlyArray, onSelect: (model: Model, role: string) => void, onCancel: () => void, - options?: { temporaryOnly?: boolean } + options?: { temporaryOnly?: boolean }, ) { super(); @@ -327,7 +327,7 @@ export class ModelSelectorComponent extends Container { const maxVisible = 10; const startIndex = Math.max( 0, - Math.min(this.selectedIndex - Math.floor(maxVisible / 2), this.filteredModels.length - maxVisible) + Math.min(this.selectedIndex - Math.floor(maxVisible / 2), this.filteredModels.length - maxVisible), ); const endIndex = Math.min(startIndex + maxVisible, this.filteredModels.length); @@ -419,7 +419,7 @@ export class ModelSelectorComponent extends Container { const menuWidth = Math.max( visibleWidth(headerText), visibleWidth(hintText), - ...actionLines.map((line) => visibleWidth(line)) + ...actionLines.map((line) => visibleWidth(line)), ); // Menu header diff --git a/packages/coding-agent/src/modes/interactive/components/oauth-selector.ts b/packages/coding-agent/src/modes/interactive/components/oauth-selector.ts index 878cc3076..c2821cf99 100644 --- a/packages/coding-agent/src/modes/interactive/components/oauth-selector.ts +++ b/packages/coding-agent/src/modes/interactive/components/oauth-selector.ts @@ -21,7 +21,7 @@ export class OAuthSelectorComponent extends Container { mode: "login" | "logout", authStorage: AuthStorage, onSelect: (providerId: string) => void, - onCancel: () => void + onCancel: () => void, ) { super(); diff --git a/packages/coding-agent/src/modes/interactive/components/status-line.ts b/packages/coding-agent/src/modes/interactive/components/status-line.ts index 995f2ea77..6e07eee2d 100644 --- a/packages/coding-agent/src/modes/interactive/components/status-line.ts +++ b/packages/coding-agent/src/modes/interactive/components/status-line.ts @@ -225,9 +225,9 @@ export class StatusLineComponent implements Component { const contextTokens = lastAssistantMessage ? lastAssistantMessage.usage.input + - lastAssistantMessage.usage.output + - lastAssistantMessage.usage.cacheRead + - lastAssistantMessage.usage.cacheWrite + lastAssistantMessage.usage.output + + lastAssistantMessage.usage.cacheRead + + lastAssistantMessage.usage.cacheWrite : 0; const contextWindow = state.model?.contextWindow || 0; const contextPercent = contextWindow > 0 ? (contextTokens / contextWindow) * 100 : 0; diff --git a/packages/coding-agent/src/modes/interactive/interactive-mode.ts b/packages/coding-agent/src/modes/interactive/interactive-mode.ts index f86cfeac0..b17696866 100644 --- a/packages/coding-agent/src/modes/interactive/interactive-mode.ts +++ b/packages/coding-agent/src/modes/interactive/interactive-mode.ts @@ -6,8 +6,8 @@ import * as fs from "node:fs"; import * as os from "node:os"; import * as path from "node:path"; -import type { AssistantMessage, ImageContent, Message, OAuthProvider } from "@oh-my-pi/pi-ai"; import type { AgentMessage, ThinkingLevel } from "@oh-my-pi/pi-agent-core"; +import type { AssistantMessage, ImageContent, Message, OAuthProvider } from "@oh-my-pi/pi-ai"; import type { SlashCommand } from "@oh-my-pi/pi-tui"; import { CombinedAutocompleteProvider, @@ -181,8 +181,10 @@ export class InteractiveMode { version: string, changelogMarkdown: string | undefined = undefined, private setToolUIContext: (uiContext: ExtensionUIContext, hasUI: boolean) => void = () => {}, - private lspServers: Array<{ name: string; status: "ready" | "error"; fileTypes: string[] }> | undefined = undefined, - fdPath: string | undefined = undefined + private lspServers: + | Array<{ name: string; status: "ready" | "error"; fileTypes: string[] }> + | undefined = undefined, + fdPath: string | undefined = undefined, ) { this.session = session; this.version = version; @@ -268,7 +270,7 @@ export class InteractiveMode { const autocompleteProvider = new CombinedAutocompleteProvider( [...slashCommands, ...fileSlashCommands, ...hookCommands, ...customCommands], process.cwd(), - fdPath + fdPath, ); this.editor.setAutocompleteProvider(autocompleteProvider); } @@ -453,7 +455,7 @@ export class InteractiveMode { this.chatContainer.addChild(new Spacer(1)); this.chatContainer.addChild( - new Text(`${theme.fg("accent", `${theme.status.success} New session started`)}`, 1, 1) + new Text(`${theme.fg("accent", `${theme.status.success} New session started`)}`, 1, 1), ); this.ui.requestRender(); @@ -583,7 +585,7 @@ export class InteractiveMode { this.chatContainer.addChild(new Spacer(1)); this.chatContainer.addChild( - new Text(`${theme.fg("accent", `${theme.status.success} New session started`)}`, 1, 1) + new Text(`${theme.fg("accent", `${theme.status.success} New session started`)}`, 1, 1), ); this.ui.requestRender(); @@ -649,8 +651,8 @@ export class InteractiveMode { _factory: ( tui: TUI, theme: Theme, - done: (result: T) => void - ) => (Component & { dispose?(): void }) | Promise + done: (result: T) => void, + ) => (Component & { dispose?(): void }) | Promise, ) => undefined as T, setEditorText: () => {}, getEditorText: () => "", @@ -666,7 +668,7 @@ export class InteractiveMode { */ private async emitCustomToolSessionEvent( reason: "start" | "switch" | "branch" | "tree" | "shutdown", - previousSessionFile?: string + previousSessionFile?: string, ): Promise { const event = { reason, previousSessionFile }; const uiContext = this.session.extensionRunner?.getUIContext(); @@ -736,7 +738,7 @@ export class InteractiveMode { () => { this.hideHookSelector(); resolve(undefined); - } + }, ); this.editorContainer.clear(); @@ -780,7 +782,7 @@ export class InteractiveMode { () => { this.hideHookInput(); resolve(undefined); - } + }, ); this.editorContainer.clear(); @@ -817,7 +819,7 @@ export class InteractiveMode { () => { this.hideHookEditor(); resolve(undefined); - } + }, ); this.editorContainer.clear(); @@ -858,8 +860,8 @@ export class InteractiveMode { factory: ( tui: TUI, theme: Theme, - done: (result: T) => void - ) => (Component & { dispose?(): void }) | Promise + done: (result: T) => void, + ) => (Component & { dispose?(): void }) | Promise, ): Promise { const savedText = this.editor.getText(); @@ -1197,7 +1199,7 @@ export class InteractiveMode { (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), `Working${theme.format.ellipsis} (esc to interrupt)`, - getSymbolTheme().spinnerFrames + getSymbolTheme().spinnerFrames, ); this.statusContainer.addChild(this.loadingAnimation); this.startVoiceProgressTimer(); @@ -1243,7 +1245,7 @@ export class InteractiveMode { }, tool, this.ui, - this.sessionManager.getCwd() + this.sessionManager.getCwd(), ); component.setExpanded(this.toolOutputExpanded); this.chatContainer.addChild(component); @@ -1313,7 +1315,7 @@ export class InteractiveMode { }, tool, this.ui, - this.sessionManager.getCwd() + this.sessionManager.getCwd(), ); component.setExpanded(this.toolOutputExpanded); this.chatContainer.addChild(component); @@ -1384,7 +1386,7 @@ export class InteractiveMode { (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), `${reasonText}Auto-compacting${theme.format.ellipsis} (esc to cancel)`, - getSymbolTheme().spinnerFrames + getSymbolTheme().spinnerFrames, ); this.statusContainer.addChild(this.autoCompactionLoader); this.ui.requestRender(); @@ -1440,7 +1442,7 @@ export class InteractiveMode { (spinner) => theme.fg("warning", spinner), (text) => theme.fg("muted", text), `Retrying (${event.attempt}/${event.maxAttempts}) in ${delaySeconds}s${theme.format.ellipsis} (esc to cancel)`, - getSymbolTheme().spinnerFrames + getSymbolTheme().spinnerFrames, ); this.statusContainer.addChild(this.retryLoader); this.ui.requestRender(); @@ -1536,7 +1538,7 @@ export class InteractiveMode { message.exitCode, message.cancelled, message.truncated ? ({ truncated: true } as TruncationResult) : undefined, - message.fullOutputPath + message.fullOutputPath, ); this.chatContainer.addChild(component); break; @@ -1569,7 +1571,7 @@ export class InteractiveMode { for (const file of message.files) { const text = `${theme.fg("dim", `${theme.tree.last} `)}${theme.fg("muted", "Read")} ${theme.fg( "accent", - file.path + file.path, )} ${theme.fg("dim", `(${file.lineCount} lines)`)}`; this.chatContainer.addChild(new Text(text, 0, 0)); } @@ -1609,7 +1611,7 @@ export class InteractiveMode { */ private renderSessionContext( sessionContext: SessionContext, - options: { updateFooter?: boolean; populateHistory?: boolean } = {} + options: { updateFooter?: boolean; populateHistory?: boolean } = {}, ): void { this.pendingTools.clear(); @@ -1632,7 +1634,7 @@ export class InteractiveMode { { showImages: this.settingsManager.getShowImages() }, tool, this.ui, - this.sessionManager.getCwd() + this.sessionManager.getCwd(), ); component.setExpanded(this.toolOutputExpanded); this.chatContainer.addChild(component); @@ -2115,8 +2117,8 @@ export class InteractiveMode { theme.fg("muted", `New version ${newVersion} is available. Run: `) + theme.fg("accent", "omp update"), 1, - 0 - ) + 0, + ), ); this.chatContainer.addChild(new DynamicBorder((text) => theme.fg("warning", text))); this.ui.requestRender(); @@ -2208,7 +2210,7 @@ export class InteractiveMode { this.updateEditorTopBorder(); this.ui.requestRender(); }, - } + }, ); return { component: selector, focus: selector }; }); @@ -2383,7 +2385,7 @@ export class InteractiveMode { done(); this.ui.requestRender(); }, - options + options, ); return { component: selector, focus: selector }; }); @@ -2418,7 +2420,7 @@ export class InteractiveMode { () => { done(); this.ui.requestRender(); - } + }, ); return { component: selector, focus: selector.getMessageList() }; }); @@ -2477,7 +2479,7 @@ export class InteractiveMode { (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), "Summarizing branch... (esc to cancel)", - getSymbolTheme().spinnerFrames + getSymbolTheme().spinnerFrames, ); this.statusContainer.addChild(summaryLoader); this.ui.requestRender(); @@ -2521,7 +2523,7 @@ export class InteractiveMode { (entryId, label) => { this.sessionManager.appendLabelChange(entryId, label); this.ui.requestRender(); - } + }, ); return { component: selector, focus: selector }; }); @@ -2542,7 +2544,7 @@ export class InteractiveMode { }, () => { void this.shutdown(); - } + }, ); return { component: selector, focus: selector.getSessionList() }; }); @@ -2575,7 +2577,7 @@ export class InteractiveMode { if (mode === "logout") { const providers = this.session.modelRegistry.authStorage.list(); const loggedInProviders = providers.filter( - (p) => this.session.modelRegistry.authStorage.get(p)?.type === "oauth" + (p) => this.session.modelRegistry.authStorage.get(p)?.type === "oauth", ); if (loggedInProviders.length === 0) { this.showStatus("No OAuth providers logged in. Use /login first."); @@ -2640,9 +2642,15 @@ export class InteractiveMode { await this.session.modelRegistry.refresh(); this.chatContainer.addChild(new Spacer(1)); this.chatContainer.addChild( - new Text(theme.fg("success", `${theme.status.success} Successfully logged in to ${providerId}`), 1, 0) + new Text( + theme.fg("success", `${theme.status.success} Successfully logged in to ${providerId}`), + 1, + 0, + ), + ); + this.chatContainer.addChild( + new Text(theme.fg("dim", `Credentials saved to ${getAuthPath()}`), 1, 0), ); - this.chatContainer.addChild(new Text(theme.fg("dim", `Credentials saved to ${getAuthPath()}`), 1, 0)); this.ui.requestRender(); } catch (error: unknown) { this.showError(`Login failed: ${error instanceof Error ? error.message : String(error)}`); @@ -2654,9 +2662,15 @@ export class InteractiveMode { await this.session.modelRegistry.refresh(); this.chatContainer.addChild(new Spacer(1)); this.chatContainer.addChild( - new Text(theme.fg("success", `${theme.status.success} Successfully logged out of ${providerId}`), 1, 0) + new Text( + theme.fg("success", `${theme.status.success} Successfully logged out of ${providerId}`), + 1, + 0, + ), + ); + this.chatContainer.addChild( + new Text(theme.fg("dim", `Credentials removed from ${getAuthPath()}`), 1, 0), ); - this.chatContainer.addChild(new Text(theme.fg("dim", `Credentials removed from ${getAuthPath()}`), 1, 0)); this.ui.requestRender(); } catch (error: unknown) { this.showError(`Logout failed: ${error instanceof Error ? error.message : String(error)}`); @@ -2666,7 +2680,7 @@ export class InteractiveMode { () => { done(); this.ui.requestRender(); - } + }, ); return { component: selector, focus: selector }; }); @@ -2682,8 +2696,8 @@ export class InteractiveMode { process.platform === "darwin" ? ["open", urlOrPath] : process.platform === "win32" - ? ["cmd", "/c", "start", "", urlOrPath] - : ["xdg-open", urlOrPath]; + ? ["cmd", "/c", "start", "", urlOrPath] + : ["xdg-open", urlOrPath]; Bun.spawn(args, { stdin: "ignore", stdout: "ignore", stderr: "ignore" }); } catch { // Best-effort: browser opening is non-critical @@ -3001,7 +3015,9 @@ export class InteractiveMode { this.pendingTools.clear(); this.chatContainer.addChild(new Spacer(1)); - this.chatContainer.addChild(new Text(`${theme.fg("accent", `${theme.status.success} New session started`)}`, 1, 1)); + this.chatContainer.addChild( + new Text(`${theme.fg("accent", `${theme.status.success} New session started`)}`, 1, 1), + ); this.ui.requestRender(); } @@ -3035,8 +3051,8 @@ export class InteractiveMode { new Text( `${theme.fg("accent", `${theme.status.success} Debug log written`)}\n${theme.fg("muted", debugLogPath)}`, 1, - 1 - ) + 1, + ), ); this.ui.requestRender(); } @@ -3070,7 +3086,7 @@ export class InteractiveMode { this.ui.requestRender(); } }, - { excludeFromContext } + { excludeFromContext }, ); if (this.bashComponent) { @@ -3078,7 +3094,7 @@ export class InteractiveMode { result.exitCode, result.cancelled, result.truncated ? ({ truncated: true, content: result.output } as TruncationResult) : undefined, - result.fullOutputPath + result.fullOutputPath, ); } } catch (error) { @@ -3126,7 +3142,7 @@ export class InteractiveMode { (spinner) => theme.fg("accent", spinner), (text) => theme.fg("muted", text), label, - getSymbolTheme().spinnerFrames + getSymbolTheme().spinnerFrames, ); this.statusContainer.addChild(compactingLoader); this.ui.requestRender(); diff --git a/packages/coding-agent/src/modes/print-mode.ts b/packages/coding-agent/src/modes/print-mode.ts index 7007ef304..680e2b778 100644 --- a/packages/coding-agent/src/modes/print-mode.ts +++ b/packages/coding-agent/src/modes/print-mode.ts @@ -24,7 +24,7 @@ export async function runPrintMode( mode: "text" | "json", messages: string[], initialMessage?: string, - initialImages?: ImageContent[] + initialImages?: ImageContent[], ): Promise { // Extension runner already has no-op UI context by default (set in loader) // Set up extensions for print mode (no UI) diff --git a/packages/coding-agent/src/modes/rpc/rpc-client.ts b/packages/coding-agent/src/modes/rpc/rpc-client.ts index d34c7cff4..9bea1e8fb 100644 --- a/packages/coding-agent/src/modes/rpc/rpc-client.ts +++ b/packages/coding-agent/src/modes/rpc/rpc-client.ts @@ -4,8 +4,8 @@ * Spawns the agent in RPC mode and provides a typed API for all operations. */ -import type { ImageContent } from "@oh-my-pi/pi-ai"; import type { AgentEvent, AgentMessage, ThinkingLevel } from "@oh-my-pi/pi-agent-core"; +import type { ImageContent } from "@oh-my-pi/pi-ai"; import type { Subprocess } from "bun"; import type { SessionStats } from "../../core/agent-session"; import type { BashResult } from "../../core/bash-executor"; @@ -114,7 +114,7 @@ export class RpcClient { } } }, - }) + }), ) .getReader() as ReadableStreamDefaultReader; diff --git a/packages/coding-agent/src/modes/rpc/rpc-types.ts b/packages/coding-agent/src/modes/rpc/rpc-types.ts index 7c180527c..40f869995 100644 --- a/packages/coding-agent/src/modes/rpc/rpc-types.ts +++ b/packages/coding-agent/src/modes/rpc/rpc-types.ts @@ -5,8 +5,8 @@ * Responses and events are emitted as JSON lines on stdout. */ -import type { ImageContent, Model } from "@oh-my-pi/pi-ai"; import type { AgentMessage, ThinkingLevel } from "@oh-my-pi/pi-agent-core"; +import type { ImageContent, Model } from "@oh-my-pi/pi-ai"; import type { SessionStats } from "../../core/agent-session"; import type { BashResult } from "../../core/bash-executor"; import type { CompactionResult } from "../../core/compaction/index"; diff --git a/packages/coding-agent/src/utils/image-resize.ts b/packages/coding-agent/src/utils/image-resize.ts index de12c20a3..8260e17d5 100644 --- a/packages/coding-agent/src/utils/image-resize.ts +++ b/packages/coding-agent/src/utils/image-resize.ts @@ -33,7 +33,7 @@ const DEFAULT_OPTIONS: Required = { */ async function resizeImageWithImageMagick( img: ImageContent, - opts: Required + opts: Required, ): Promise { // Try to get dimensions first const dims = await getImageDimensionsWithImageMagick(img.data); @@ -47,7 +47,7 @@ async function resizeImageWithImageMagick( opts.maxWidth, opts.maxHeight, opts.maxBytes, - opts.jpegQuality + opts.jpegQuality, ); if (result) { @@ -77,7 +77,7 @@ async function resizeImageWithImageMagick( /** Helper to pick the smaller of two buffers */ function pickSmaller( a: { buffer: Buffer; mimeType: string }, - b: { buffer: Buffer; mimeType: string } + b: { buffer: Buffer; mimeType: string }, ): { buffer: Buffer; mimeType: string } { return a.buffer.length <= b.buffer.length ? a : b; } @@ -145,9 +145,11 @@ export async function resizeImage(img: ImageContent, options?: ImageResizeOption async function tryBothFormats( width: number, height: number, - jpegQuality: number + jpegQuality: number, ): Promise<{ buffer: Buffer; mimeType: string }> { - const resized = await sharp!(buffer).resize(width, height, { fit: "inside", withoutEnlargement: true }).toBuffer(); + const resized = await sharp!(buffer) + .resize(width, height, { fit: "inside", withoutEnlargement: true }) + .toBuffer(); const [pngBuffer, jpegBuffer] = await Promise.all([ sharp!(resized).png({ compressionLevel: 9 }).toBuffer(), diff --git a/packages/coding-agent/test/agent-session-branching.test.ts b/packages/coding-agent/test/agent-session-branching.test.ts index dc0669650..4526a4f39 100644 --- a/packages/coding-agent/test/agent-session-branching.test.ts +++ b/packages/coding-agent/test/agent-session-branching.test.ts @@ -11,8 +11,8 @@ import { afterEach, beforeEach, describe, expect, it } from "bun:test"; import { existsSync, mkdirSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; -import { getModel } from "@oh-my-pi/pi-ai"; import { Agent } from "@oh-my-pi/pi-agent-core"; +import { getModel } from "@oh-my-pi/pi-ai"; import { nanoid } from "nanoid"; import { AgentSession } from "../src/core/agent-session"; import { AuthStorage } from "../src/core/auth-storage"; diff --git a/packages/coding-agent/test/agent-session-compaction.test.ts b/packages/coding-agent/test/agent-session-compaction.test.ts index 61565c6f3..5d5fba733 100644 --- a/packages/coding-agent/test/agent-session-compaction.test.ts +++ b/packages/coding-agent/test/agent-session-compaction.test.ts @@ -11,8 +11,8 @@ import { afterEach, beforeEach, describe, expect, it } from "bun:test"; import { existsSync, mkdirSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; -import { getModel } from "@oh-my-pi/pi-ai"; import { Agent } from "@oh-my-pi/pi-agent-core"; +import { getModel } from "@oh-my-pi/pi-ai"; import { nanoid } from "nanoid"; import { AgentSession, type AgentSessionEvent } from "../src/core/agent-session"; import { AuthStorage } from "../src/core/auth-storage"; @@ -201,7 +201,7 @@ describe.skipIf(!API_KEY)("AgentSession compaction e2e", () => { // Check that no auto_compaction events were emitted for manual compaction const autoCompactionEvents = events.filter( - (e) => e.type === "auto_compaction_start" || e.type === "auto_compaction_end" + (e) => e.type === "auto_compaction_start" || e.type === "auto_compaction_end", ); // Manual compaction doesn't emit auto_compaction events expect(autoCompactionEvents.length).toBe(0); diff --git a/packages/coding-agent/test/agent-session-concurrent.test.ts b/packages/coding-agent/test/agent-session-concurrent.test.ts index 911f4e15f..377cf5668 100644 --- a/packages/coding-agent/test/agent-session-concurrent.test.ts +++ b/packages/coding-agent/test/agent-session-concurrent.test.ts @@ -6,8 +6,8 @@ import { afterEach, beforeEach, describe, expect, it } from "bun:test"; import { existsSync, mkdirSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; -import { type AssistantMessage, type AssistantMessageEvent, EventStream, getModel } from "@oh-my-pi/pi-ai"; import { Agent } from "@oh-my-pi/pi-agent-core"; +import { type AssistantMessage, type AssistantMessageEvent, EventStream, getModel } from "@oh-my-pi/pi-ai"; import { nanoid } from "nanoid"; import { AgentSession } from "../src/core/agent-session"; import { AuthStorage } from "../src/core/auth-storage"; @@ -24,7 +24,7 @@ class MockAssistantStream extends EventStream { // Second prompt should reject await expect(session.prompt("Second message")).rejects.toThrow( - "Agent is already processing. Specify streamingBehavior ('steer' or 'followUp') to queue the message." + "Agent is already processing. Specify streamingBehavior ('steer' or 'followUp') to queue the message.", ); // Cleanup diff --git a/packages/coding-agent/test/compaction-hooks.test.ts b/packages/coding-agent/test/compaction-hooks.test.ts index f5127ceb5..054079453 100644 --- a/packages/coding-agent/test/compaction-hooks.test.ts +++ b/packages/coding-agent/test/compaction-hooks.test.ts @@ -6,8 +6,8 @@ import { afterEach, beforeEach, describe, expect, it } from "bun:test"; import { existsSync, mkdirSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; -import { getModel } from "@oh-my-pi/pi-ai"; import { Agent } from "@oh-my-pi/pi-agent-core"; +import { getModel } from "@oh-my-pi/pi-ai"; import { nanoid } from "nanoid"; import { AgentSession } from "../src/core/agent-session"; import { AuthStorage } from "../src/core/auth-storage"; @@ -49,7 +49,7 @@ describe.skipIf(!API_KEY)("Compaction hooks", () => { function createHook( onBeforeCompact?: (event: SessionBeforeCompactEvent) => { cancel?: boolean; compaction?: any } | undefined, - onCompact?: (event: SessionCompactEvent) => void + onCompact?: (event: SessionCompactEvent) => void, ): LoadedHook { const handlers = new Map Promise)[]>(); @@ -154,7 +154,7 @@ describe.skipIf(!API_KEY)("Compaction hooks", () => { await session.compact(); const beforeCompactEvents = capturedEvents.filter( - (e): e is SessionBeforeCompactEvent => e.type === "session_before_compact" + (e): e is SessionBeforeCompactEvent => e.type === "session_before_compact", ); const compactEvents = capturedEvents.filter((e): e is SessionCompactEvent => e.type === "session_compact"); diff --git a/packages/coding-agent/test/compaction-thinking-model.test.ts b/packages/coding-agent/test/compaction-thinking-model.test.ts index 9c546320d..e41a995b7 100644 --- a/packages/coding-agent/test/compaction-thinking-model.test.ts +++ b/packages/coding-agent/test/compaction-thinking-model.test.ts @@ -12,8 +12,8 @@ import { afterEach, beforeEach, describe, expect, it } from "bun:test"; import { existsSync, mkdirSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; -import { getModel, type Model } from "@oh-my-pi/pi-ai"; import { Agent, type ThinkingLevel } from "@oh-my-pi/pi-agent-core"; +import { getModel, type Model } from "@oh-my-pi/pi-ai"; import { nanoid } from "nanoid"; import { AgentSession } from "../src/core/agent-session"; import { AuthStorage } from "../src/core/auth-storage"; @@ -47,7 +47,7 @@ describe.skipIf(!HAS_ANTIGRAVITY_AUTH)("Compaction with thinking models (Antigra async function createSession( modelId: "claude-opus-4-5-thinking" | "claude-sonnet-4-5", - thinkingLevel: ThinkingLevel = "high" + thinkingLevel: ThinkingLevel = "high", ) { const toolSession: ToolSession = { cwd: tempDir, diff --git a/packages/coding-agent/test/compaction.test.ts b/packages/coding-agent/test/compaction.test.ts index 346b34d57..33d2f04f6 100644 --- a/packages/coding-agent/test/compaction.test.ts +++ b/packages/coding-agent/test/compaction.test.ts @@ -1,9 +1,9 @@ import { beforeEach, describe, expect, it } from "bun:test"; import { readFileSync } from "node:fs"; import { join } from "node:path"; +import type { AgentMessage } from "@oh-my-pi/pi-agent-core"; import type { AssistantMessage, Usage } from "@oh-my-pi/pi-ai"; import { getModel } from "@oh-my-pi/pi-ai"; -import type { AgentMessage } from "@oh-my-pi/pi-agent-core"; import { type CompactionSettings, calculateContextTokens, @@ -216,7 +216,7 @@ describe("findCutPoint", () => { for (let i = 0; i < 10; i++) { entries.push(createMessageEntry(createUserMessage(`User ${i}`))); entries.push( - createMessageEntry(createAssistantMessage(`Assistant ${i}`, createMockUsage(0, 100, (i + 1) * 1000, 0))) + createMessageEntry(createAssistantMessage(`Assistant ${i}`, createMockUsage(0, 100, (i + 1) * 1000, 0))), ); } diff --git a/packages/coding-agent/test/streaming-render-debug.ts b/packages/coding-agent/test/streaming-render-debug.ts index 4316ee758..bdac62f18 100644 --- a/packages/coding-agent/test/streaming-render-debug.ts +++ b/packages/coding-agent/test/streaming-render-debug.ts @@ -17,7 +17,7 @@ initTheme("dark"); // Load the real fixture that caused the bug const fixtureMessage: AssistantMessage = JSON.parse( - readFileSync(join(import.meta.dir, "fixtures/assistant-message-with-thinking-code.json"), "utf-8") + readFileSync(join(import.meta.dir, "fixtures/assistant-message-with-thinking-code.json"), "utf-8"), ); // Extract thinking and text content diff --git a/packages/coding-agent/test/utilities.ts b/packages/coding-agent/test/utilities.ts index f679805fc..0eec6867a 100644 --- a/packages/coding-agent/test/utilities.ts +++ b/packages/coding-agent/test/utilities.ts @@ -5,8 +5,8 @@ import { existsSync, mkdirSync, rmSync } from "node:fs"; import { tmpdir } from "node:os"; import { join } from "node:path"; -import { getModel } from "@oh-my-pi/pi-ai"; import { Agent } from "@oh-my-pi/pi-agent-core"; +import { getModel } from "@oh-my-pi/pi-ai"; import { nanoid } from "nanoid"; import { AgentSession } from "../src/core/agent-session"; import { AuthStorage } from "../src/core/auth-storage"; @@ -145,7 +145,7 @@ export function buildTestTree( session: SessionManager, structure: { messages: Array<{ role: "user" | "assistant"; text: string; branchFrom?: string }>; - } + }, ): Map { const ids = new Map(); diff --git a/packages/git-tool/CHANGELOG.md b/packages/git-tool/CHANGELOG.md index 229e90412..a1e09a6ef 100644 --- a/packages/git-tool/CHANGELOG.md +++ b/packages/git-tool/CHANGELOG.md @@ -2,6 +2,8 @@ ## [Unreleased] +## [3.34.0] - 2026-01-09 + ## [3.33.0] - 2026-01-08 ## [3.32.0] - 2026-01-08 diff --git a/packages/git-tool/package.json b/packages/git-tool/package.json index 16a0e78fc..892c306e3 100644 --- a/packages/git-tool/package.json +++ b/packages/git-tool/package.json @@ -1,6 +1,6 @@ { "name": "@oh-my-pi/pi-git-tool", - "version": "3.33.0", + "version": "3.34.0", "description": "Structured Git tool with safety guards and typed output", "type": "module", "main": "./src/index.ts", diff --git a/packages/tui/CHANGELOG.md b/packages/tui/CHANGELOG.md index 28ec0eca8..71983182f 100644 --- a/packages/tui/CHANGELOG.md +++ b/packages/tui/CHANGELOG.md @@ -2,6 +2,8 @@ ## [Unreleased] +## [3.34.0] - 2026-01-09 + ## [3.33.0] - 2026-01-08 ## [3.32.0] - 2026-01-08 diff --git a/packages/tui/package.json b/packages/tui/package.json index 6a5092e56..7274098cb 100644 --- a/packages/tui/package.json +++ b/packages/tui/package.json @@ -1,6 +1,6 @@ { "name": "@oh-my-pi/pi-tui", - "version": "3.33.0", + "version": "3.34.0", "description": "Terminal User Interface library with differential rendering for efficient text-based applications", "type": "module", "main": "src/index.ts",