diff --git a/CHANGELOG.md b/CHANGELOG.md index 4b1bada54..d58658041 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,7 @@ ### Fixed - Media: preserve GIF animation when uploading to Discord/other providers (skip JPEG optimization for image/gif). +- Agent runtime: update pi-mono dependencies to 0.31.1 (agent-core split). ### Breaking - Skills config schema moved under `skills.*`: diff --git a/package.json b/package.json index ed36668e5..da86103a1 100644 --- a/package.json +++ b/package.json @@ -72,9 +72,9 @@ "@grammyjs/transformer-throttler": "^1.2.1", "@clack/prompts": "^0.11.0", "@homebridge/ciao": "^1.3.4", - "@mariozechner/pi-agent-core": "^0.30.2", - "@mariozechner/pi-ai": "^0.30.2", - "@mariozechner/pi-coding-agent": "^0.30.2", + "@mariozechner/pi-agent-core": "^0.31.1", + "@mariozechner/pi-ai": "^0.31.1", + "@mariozechner/pi-coding-agent": "^0.31.1", "@sinclair/typebox": "^0.34.45", "@whiskeysockets/baileys": "7.0.0-rc.9", "ajv": "^8.17.1", @@ -134,7 +134,7 @@ }, "patchedDependencies": { "@mariozechner/pi-ai": "patches/@mariozechner__pi-ai.patch", - "@mariozechner/pi-coding-agent@0.30.2": "patches/@mariozechner__pi-coding-agent@0.30.2.patch" + "@mariozechner/pi-coding-agent@0.31.1": "patches/@mariozechner__pi-coding-agent@0.31.1.patch" } }, "vitest": { diff --git a/patches/@mariozechner__pi-coding-agent@0.30.2.patch b/patches/@mariozechner__pi-coding-agent@0.31.1.patch similarity index 100% rename from patches/@mariozechner__pi-coding-agent@0.30.2.patch rename to patches/@mariozechner__pi-coding-agent@0.31.1.patch diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 3d711b26e..64b3171a6 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -11,9 +11,9 @@ patchedDependencies: '@mariozechner/pi-ai': hash: bf3e904ebaad236b8c3bb48c7d1150a1463735e783acaab6d15d6cd381b43832 path: patches/@mariozechner__pi-ai.patch - '@mariozechner/pi-coding-agent@0.30.2': + '@mariozechner/pi-coding-agent@0.31.1': hash: d0d5ffa1bfda8a0f9d14a5e73a074014346d3edbdb2ffc91444d3be5119f5745 - path: patches/@mariozechner__pi-coding-agent@0.30.2.patch + path: patches/@mariozechner__pi-coding-agent@0.31.1.patch importers: @@ -29,14 +29,14 @@ importers: specifier: ^1.3.4 version: 1.3.4 '@mariozechner/pi-agent-core': - specifier: ^0.30.2 - version: 0.30.2(ws@8.18.3)(zod@4.2.1) + specifier: ^0.31.1 + version: 0.31.1(ws@8.18.3)(zod@4.2.1) '@mariozechner/pi-ai': - specifier: ^0.30.2 - version: 0.30.2(patch_hash=bf3e904ebaad236b8c3bb48c7d1150a1463735e783acaab6d15d6cd381b43832)(ws@8.18.3)(zod@4.2.1) + specifier: ^0.31.1 + version: 0.31.1(patch_hash=bf3e904ebaad236b8c3bb48c7d1150a1463735e783acaab6d15d6cd381b43832)(ws@8.18.3)(zod@4.2.1) '@mariozechner/pi-coding-agent': - specifier: ^0.30.2 - version: 0.30.2(patch_hash=d0d5ffa1bfda8a0f9d14a5e73a074014346d3edbdb2ffc91444d3be5119f5745)(ws@8.18.3)(zod@4.2.1) + specifier: ^0.31.1 + version: 0.31.1(patch_hash=d0d5ffa1bfda8a0f9d14a5e73a074014346d3edbdb2ffc91444d3be5119f5745)(ws@8.18.3)(zod@4.2.1) '@sinclair/typebox': specifier: 0.34.45 version: 0.34.45 @@ -738,22 +738,22 @@ packages: peerDependencies: lit: ^3.3.1 - '@mariozechner/pi-agent-core@0.30.2': - resolution: {integrity: sha512-N+4JpOHdBOi5qIlSGz+flfE4xl/iJTsmFyJ653CL7UZMrKUBJZARBi7OYLZ2y84buVkFJajL7T5AbzXIjclaOw==} + '@mariozechner/pi-agent-core@0.31.1': + resolution: {integrity: sha512-skY2ZGrVbTkbTpdHql3mR0//BbLeqwKWQ0bnoI2H7YHbR5bTDSaYwtRtSdEgfPVgTk+WBQaZOZOv6be4qCAsww==} engines: {node: '>=20.0.0'} - '@mariozechner/pi-ai@0.30.2': - resolution: {integrity: sha512-+8JlLRW1xMHDrgHbRxLMbJ7/LL/c2evZetKAjEEJJtOc/hbax9Dfw+7OSRiZn9oSkT0S12/qy44a76gpRpghhQ==} + '@mariozechner/pi-ai@0.31.1': + resolution: {integrity: sha512-mqqitu/69ofLPmQEj7m04SvPQZEX+uacLHU9oQxz1c1khclsjw2S7G/v5P/3jK4hZjoZfHkPJRwPMFvEbo3wAA==} engines: {node: '>=20.0.0'} hasBin: true - '@mariozechner/pi-coding-agent@0.30.2': - resolution: {integrity: sha512-6p/cvWmyOcNIi8qnuok77qPeEfdIvxUWrJR1gHpKEziLJA9ZygxMcAXFBaPvM0TP5Hj3Qwhs4qIupL0ygd3wng==} + '@mariozechner/pi-coding-agent@0.31.1': + resolution: {integrity: sha512-S+IQMYJssNFXQcdk8iB3tY0b1Idi0gAZCdwGCkTSG+vGghO0rdo+vQ+/v5KM6BhW2XsKiYz/2XCG8237iVwINA==} engines: {node: '>=20.0.0'} hasBin: true - '@mariozechner/pi-tui@0.30.2': - resolution: {integrity: sha512-UuqEgNWi6cG9hBImVytqP703J8z65B0pvlBKsnRoVljZ1U8TTyfdpd375oc8NONHtYKKmsSR4OLyG+zA56EEHw==} + '@mariozechner/pi-tui@0.31.1': + resolution: {integrity: sha512-79hDQPAMPxKO0HKoXiFLp1HFbRDwweYL31l2wlsEzhPYgIYvx0Ii7X+KK4yMjjfDc4SjX6ZmSnJ4MUFAanuVzA==} engines: {node: '>=20.0.0'} '@mistralai/mistralai@1.10.0': @@ -2682,10 +2682,6 @@ packages: resolution: {integrity: sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==} engines: {node: '>=12'} - string-width@8.1.0: - resolution: {integrity: sha512-Kxl3KJGb/gxkaUMOjRsQ8IrXiGW75O4E3RPjFIINOVH8AMl2SQ/yWdTzWwF3FevIX9LcMAjJW+GRwAlAbTSXdg==} - engines: {node: '>=20'} - string_decoder@1.1.1: resolution: {integrity: sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==} @@ -3474,10 +3470,10 @@ snapshots: transitivePeerDependencies: - tailwindcss - '@mariozechner/pi-agent-core@0.30.2(ws@8.18.3)(zod@4.2.1)': + '@mariozechner/pi-agent-core@0.31.1(ws@8.18.3)(zod@4.2.1)': dependencies: - '@mariozechner/pi-ai': 0.30.2(patch_hash=bf3e904ebaad236b8c3bb48c7d1150a1463735e783acaab6d15d6cd381b43832)(ws@8.18.3)(zod@4.2.1) - '@mariozechner/pi-tui': 0.30.2 + '@mariozechner/pi-ai': 0.31.1(patch_hash=bf3e904ebaad236b8c3bb48c7d1150a1463735e783acaab6d15d6cd381b43832)(ws@8.18.3)(zod@4.2.1) + '@mariozechner/pi-tui': 0.31.1 transitivePeerDependencies: - '@modelcontextprotocol/sdk' - bufferutil @@ -3486,7 +3482,7 @@ snapshots: - ws - zod - '@mariozechner/pi-ai@0.30.2(patch_hash=bf3e904ebaad236b8c3bb48c7d1150a1463735e783acaab6d15d6cd381b43832)(ws@8.18.3)(zod@4.2.1)': + '@mariozechner/pi-ai@0.31.1(patch_hash=bf3e904ebaad236b8c3bb48c7d1150a1463735e783acaab6d15d6cd381b43832)(ws@8.18.3)(zod@4.2.1)': dependencies: '@anthropic-ai/sdk': 0.71.2(zod@4.2.1) '@google/genai': 1.34.0 @@ -3506,11 +3502,11 @@ snapshots: - ws - zod - '@mariozechner/pi-coding-agent@0.30.2(patch_hash=d0d5ffa1bfda8a0f9d14a5e73a074014346d3edbdb2ffc91444d3be5119f5745)(ws@8.18.3)(zod@4.2.1)': + '@mariozechner/pi-coding-agent@0.31.1(patch_hash=d0d5ffa1bfda8a0f9d14a5e73a074014346d3edbdb2ffc91444d3be5119f5745)(ws@8.18.3)(zod@4.2.1)': dependencies: - '@mariozechner/pi-agent-core': 0.30.2(ws@8.18.3)(zod@4.2.1) - '@mariozechner/pi-ai': 0.30.2(patch_hash=bf3e904ebaad236b8c3bb48c7d1150a1463735e783acaab6d15d6cd381b43832)(ws@8.18.3)(zod@4.2.1) - '@mariozechner/pi-tui': 0.30.2 + '@mariozechner/pi-agent-core': 0.31.1(ws@8.18.3)(zod@4.2.1) + '@mariozechner/pi-ai': 0.31.1(patch_hash=bf3e904ebaad236b8c3bb48c7d1150a1463735e783acaab6d15d6cd381b43832)(ws@8.18.3)(zod@4.2.1) + '@mariozechner/pi-tui': 0.31.1 chalk: 5.6.2 cli-highlight: 2.1.11 diff: 8.0.2 @@ -3526,13 +3522,13 @@ snapshots: - ws - zod - '@mariozechner/pi-tui@0.30.2': + '@mariozechner/pi-tui@0.31.1': dependencies: '@types/mime-types': 2.1.4 chalk: 5.6.2 + get-east-asian-width: 1.4.0 marked: 15.0.12 mime-types: 3.0.2 - string-width: 8.1.0 '@mistralai/mistralai@1.10.0': dependencies: @@ -5564,11 +5560,6 @@ snapshots: emoji-regex: 9.2.2 strip-ansi: 7.1.2 - string-width@8.1.0: - dependencies: - get-east-asian-width: 1.4.0 - strip-ansi: 7.1.2 - string_decoder@1.1.1: dependencies: safe-buffer: 5.1.2 diff --git a/src/agents/bash-tools.ts b/src/agents/bash-tools.ts index 30e43a875..964a5b2cd 100644 --- a/src/agents/bash-tools.ts +++ b/src/agents/bash-tools.ts @@ -1,6 +1,6 @@ import { type ChildProcessWithoutNullStreams, spawn } from "node:child_process"; import { randomUUID } from "node:crypto"; -import type { AgentTool, AgentToolResult } from "@mariozechner/pi-ai"; +import type { AgentTool, AgentToolResult } from "@mariozechner/pi-agent-core"; import { Type } from "@sinclair/typebox"; import { @@ -94,7 +94,7 @@ export type BashToolDetails = export function createBashTool( defaults?: BashToolDefaults, - // biome-ignore lint/suspicious/noExplicitAny: TypeBox schema type from pi-ai uses a different module instance. + // biome-ignore lint/suspicious/noExplicitAny: TypeBox schema type from pi-agent-core uses a different module instance. ): AgentTool { const defaultBackgroundMs = clampNumber( defaults?.backgroundMs ?? readEnvInt("PI_BASH_YIELD_MS"), @@ -358,7 +358,7 @@ const processSchema = Type.Object({ export function createProcessTool( defaults?: ProcessToolDefaults, - // biome-ignore lint/suspicious/noExplicitAny: TypeBox schema type from pi-ai uses a different module instance. + // biome-ignore lint/suspicious/noExplicitAny: TypeBox schema type from pi-agent-core uses a different module instance. ): AgentTool { if (defaults?.cleanupMs !== undefined) { setJobTtlMs(defaults.cleanupMs); diff --git a/src/agents/clawdis-tools.ts b/src/agents/clawdis-tools.ts index b538c244d..9242bb24e 100644 --- a/src/agents/clawdis-tools.ts +++ b/src/agents/clawdis-tools.ts @@ -1,7 +1,7 @@ import crypto from "node:crypto"; import fs from "node:fs/promises"; -import type { AgentTool, AgentToolResult } from "@mariozechner/pi-ai"; +import type { AgentTool, AgentToolResult } from "@mariozechner/pi-agent-core"; import { Type } from "@sinclair/typebox"; import { browserCloseTab, @@ -46,7 +46,7 @@ import { callGateway } from "../gateway/call.js"; import { detectMime, imageMimeFromFormat } from "../media/mime.js"; import { sanitizeToolResultImages } from "./tool-images.js"; -// biome-ignore lint/suspicious/noExplicitAny: TypeBox schema type from pi-ai uses a different module instance. +// biome-ignore lint/suspicious/noExplicitAny: TypeBox schema type from pi-agent-core uses a different module instance. type AnyAgentTool = AgentTool; const DEFAULT_GATEWAY_URL = "ws://127.0.0.1:18789"; diff --git a/src/agents/pi-embedded-helpers.ts b/src/agents/pi-embedded-helpers.ts index 69313ec8e..8d2debc70 100644 --- a/src/agents/pi-embedded-helpers.ts +++ b/src/agents/pi-embedded-helpers.ts @@ -1,8 +1,11 @@ import fs from "node:fs/promises"; import path from "node:path"; -import type { AppMessage } from "@mariozechner/pi-agent-core"; -import type { AgentToolResult, AssistantMessage } from "@mariozechner/pi-ai"; +import type { + AgentMessage, + AgentToolResult, +} from "@mariozechner/pi-agent-core"; +import type { AssistantMessage } from "@mariozechner/pi-ai"; import { sanitizeContentBlocksImages } from "./tool-images.js"; import type { WorkspaceBootstrapFile } from "./workspace.js"; @@ -36,12 +39,12 @@ export async function ensureSessionHeader(params: { type ContentBlock = AgentToolResult["content"][number]; export async function sanitizeSessionMessagesImages( - messages: AppMessage[], + messages: AgentMessage[], label: string, -): Promise { +): Promise { // We sanitize historical session messages because Anthropic can reject a request // if the transcript contains oversized base64 images (see MAX_IMAGE_DIMENSION_PX). - const out: AppMessage[] = []; + const out: AgentMessage[] = []; for (const msg of messages) { if (!msg || typeof msg !== "object") { out.push(msg); @@ -50,7 +53,7 @@ export async function sanitizeSessionMessagesImages( const role = (msg as { role?: unknown }).role; if (role === "toolResult") { - const toolMsg = msg as Extract; + const toolMsg = msg as Extract; const content = Array.isArray(toolMsg.content) ? toolMsg.content : []; const nextContent = (await sanitizeContentBlocksImages( content as ContentBlock[], @@ -61,7 +64,7 @@ export async function sanitizeSessionMessagesImages( } if (role === "user") { - const userMsg = msg as Extract; + const userMsg = msg as Extract; const content = userMsg.content; if (Array.isArray(content)) { const nextContent = (await sanitizeContentBlocksImages( diff --git a/src/agents/pi-embedded-runner.ts b/src/agents/pi-embedded-runner.ts index 1e880125b..d7774cfbe 100644 --- a/src/agents/pi-embedded-runner.ts +++ b/src/agents/pi-embedded-runner.ts @@ -3,7 +3,7 @@ import fs from "node:fs/promises"; import os from "node:os"; import path from "node:path"; -import type { AppMessage, ThinkingLevel } from "@mariozechner/pi-agent-core"; +import type { AgentMessage, ThinkingLevel } from "@mariozechner/pi-agent-core"; import { type Api, type AssistantMessage, @@ -448,8 +448,7 @@ export async function runEmbeddedPiAgent(params: { model, thinkingLevel, systemPrompt, - // TODO(steipete): Once pi-mono publishes file-magic MIME detection in `read` image payloads, - // remove `createClawdisCodingTools()` and use upstream `codingTools` again. + // Custom tool set: extra bash/process + read image sanitization. tools, sessionManager, settingsManager, @@ -502,7 +501,7 @@ export async function runEmbeddedPiAgent(params: { Math.max(1, params.timeoutMs), ); - let messagesSnapshot: AppMessage[] = []; + let messagesSnapshot: AgentMessage[] = []; let sessionIdUsed = session.sessionId; const onAbort = () => { abortRun(); @@ -543,7 +542,7 @@ export async function runEmbeddedPiAgent(params: { const lastAssistant = messagesSnapshot .slice() .reverse() - .find((m) => (m as AppMessage)?.role === "assistant") as + .find((m) => (m as AgentMessage)?.role === "assistant") as | AssistantMessage | undefined; diff --git a/src/agents/pi-embedded-subscribe.ts b/src/agents/pi-embedded-subscribe.ts index dd1b8a262..421e49454 100644 --- a/src/agents/pi-embedded-subscribe.ts +++ b/src/agents/pi-embedded-subscribe.ts @@ -1,4 +1,4 @@ -import type { AgentEvent, AppMessage } from "@mariozechner/pi-agent-core"; +import type { AgentEvent, AgentMessage } from "@mariozechner/pi-agent-core"; import type { AssistantMessage } from "@mariozechner/pi-ai"; import type { AgentSession } from "@mariozechner/pi-coding-agent"; @@ -234,7 +234,7 @@ export function subscribeEmbeddedPiSession(params: { } if (evt.type === "message_update") { - const msg = (evt as AgentEvent & { message: AppMessage }).message; + const msg = (evt as AgentEvent & { message: AgentMessage }).message; if (msg?.role === "assistant") { const assistantEvent = ( evt as AgentEvent & { assistantMessageEvent?: unknown } @@ -298,7 +298,7 @@ export function subscribeEmbeddedPiSession(params: { } if (evt.type === "message_end") { - const msg = (evt as AgentEvent & { message: AppMessage }).message; + const msg = (evt as AgentEvent & { message: AgentMessage }).message; if (msg?.role === "assistant") { const cleaned = params.enforceFinalTag ? stripThinkingSegments( diff --git a/src/agents/pi-tools.ts b/src/agents/pi-tools.ts index b7c9c9cc4..811321cfe 100644 --- a/src/agents/pi-tools.ts +++ b/src/agents/pi-tools.ts @@ -1,4 +1,4 @@ -import type { AgentTool, AgentToolResult } from "@mariozechner/pi-ai"; +import type { AgentTool, AgentToolResult } from "@mariozechner/pi-agent-core"; import { codingTools, readTool } from "@mariozechner/pi-coding-agent"; import { Type } from "@sinclair/typebox"; @@ -13,8 +13,8 @@ import { import { createClawdisTools } from "./clawdis-tools.js"; import { sanitizeToolResultImages } from "./tool-images.js"; -// TODO(steipete): Remove this wrapper once pi-mono ships file-magic MIME detection -// for `read` image payloads in `@mariozechner/pi-coding-agent` (then switch back to `codingTools` directly). +// NOTE(steipete): Upstream read now does file-magic MIME detection; we keep the wrapper +// to normalize payloads and sanitize oversized images before they hit providers. type ToolContentBlock = AgentToolResult["content"][number]; type ImageContentBlock = Extract; type TextContentBlock = Extract; @@ -103,7 +103,7 @@ async function normalizeReadImageResult( return { ...result, content: nextContent }; } -// biome-ignore lint/suspicious/noExplicitAny: TypeBox schema type from pi-ai uses a different module instance. +// biome-ignore lint/suspicious/noExplicitAny: TypeBox schema type from pi-agent-core uses a different module instance. type AnyAgentTool = AgentTool; function extractEnumValues(schema: unknown): unknown[] | undefined { diff --git a/src/agents/tool-images.ts b/src/agents/tool-images.ts index a5915957d..35e6ca4f7 100644 --- a/src/agents/tool-images.ts +++ b/src/agents/tool-images.ts @@ -1,4 +1,4 @@ -import type { AgentToolResult } from "@mariozechner/pi-ai"; +import type { AgentToolResult } from "@mariozechner/pi-agent-core"; import { getImageMetadata, resizeToJpeg } from "../media/image-ops.js"; diff --git a/src/discord/monitor.test.ts b/src/discord/monitor.test.ts index de1d24d4a..385e970a5 100644 --- a/src/discord/monitor.test.ts +++ b/src/discord/monitor.test.ts @@ -6,8 +6,8 @@ import { normalizeDiscordSlug, resolveDiscordChannelConfig, resolveDiscordGuildEntry, - resolveGroupDmAllow, resolveDiscordReplyTarget, + resolveGroupDmAllow, } from "./monitor.js"; const fakeGuild = (id: string, name: string) => diff --git a/src/discord/monitor.ts b/src/discord/monitor.ts index cf9d611e8..3e37e9889 100644 --- a/src/discord/monitor.ts +++ b/src/discord/monitor.ts @@ -14,7 +14,10 @@ import { formatAgentEnvelope } from "../auto-reply/envelope.js"; import { getReplyFromConfig } from "../auto-reply/reply.js"; import { SILENT_REPLY_TOKEN } from "../auto-reply/tokens.js"; import type { ReplyPayload } from "../auto-reply/types.js"; -import type { DiscordSlashCommandConfig, ReplyToMode } from "../config/config.js"; +import type { + DiscordSlashCommandConfig, + ReplyToMode, +} from "../config/config.js"; import { loadConfig } from "../config/config.js"; import { resolveStorePath, updateLastRoute } from "../config/sessions.js"; import { danger, isVerbose, logVerbose, warn } from "../globals.js"; diff --git a/src/telegram/bot.ts b/src/telegram/bot.ts index d5f3eb335..e842ef172 100644 --- a/src/telegram/bot.ts +++ b/src/telegram/bot.ts @@ -249,7 +249,9 @@ async function deliverReplies(params: { continue; } const replyToId = - replyToMode === "off" ? undefined : resolveTelegramReplyId(reply.replyToId); + replyToMode === "off" + ? undefined + : resolveTelegramReplyId(reply.replyToId); const mediaList = reply.mediaUrls?.length ? reply.mediaUrls : reply.mediaUrl