Fix CustomMessageEntry content type to match UserMessage

content: string | (TextContent | ImageContent)[]

This matches the UserMessage type from pi-ai, so content can be
passed directly to AppMessage without conversion.
This commit is contained in:
Mario Zechner 2025-12-26 22:50:04 +01:00
parent 9da36e5ac6
commit 3ecaaa5937
2 changed files with 11 additions and 30 deletions

View file

@ -110,10 +110,10 @@ Hook-injected messages that participate in LLM context. Unlike `CustomEntry<T>`
```typescript ```typescript
export interface CustomMessageEntry<T = unknown> extends SessionEntryBase { export interface CustomMessageEntry<T = unknown> extends SessionEntryBase {
type: "custom_message"; type: "custom_message";
customType: string; // Hook identifier customType: string; // Hook identifier
content: (string | Attachment)[]; // Message content content: string | (TextContent | ImageContent)[]; // Message content (same as UserMessage)
details?: T; // Hook-specific data for state reconstruction on reload details?: T; // Hook-specific data for state reconstruction on reload
display: boolean; // Whether to display in TUI display: boolean; // Whether to display in TUI
} }
``` ```

View file

@ -1,4 +1,5 @@
import type { AppMessage, Attachment } from "@mariozechner/pi-agent-core"; import type { AppMessage } from "@mariozechner/pi-agent-core";
import type { ImageContent, TextContent } from "@mariozechner/pi-ai";
import { randomUUID } from "crypto"; import { randomUUID } from "crypto";
import { import {
appendFileSync, appendFileSync,
@ -101,7 +102,7 @@ export interface LabelEntry extends SessionEntryBase {
export interface CustomMessageEntry<T = unknown> extends SessionEntryBase { export interface CustomMessageEntry<T = unknown> extends SessionEntryBase {
type: "custom_message"; type: "custom_message";
customType: string; customType: string;
content: (string | Attachment)[]; content: string | (TextContent | ImageContent)[];
details?: T; details?: T;
display: boolean; display: boolean;
} }
@ -161,31 +162,11 @@ export function createSummaryMessage(summary: string, timestamp: string): AppMes
}; };
} }
/** Convert CustomMessageEntry content to AppMessage format */ /** Convert CustomMessageEntry to AppMessage format */
function createCustomMessage(entry: CustomMessageEntry): AppMessage { function createCustomMessage(entry: CustomMessageEntry): AppMessage {
// Convert content array to AppMessage content format
const content = entry.content.map((item) => {
if (typeof item === "string") {
return { type: "text" as const, text: item };
}
// Attachment - convert to appropriate content type
if (item.type === "image") {
return {
type: "image" as const,
data: item.content,
mimeType: item.mimeType,
};
}
// Document attachment - use extracted text or indicate document
return {
type: "text" as const,
text: item.extractedText ?? `[Document: ${item.fileName}]`,
};
});
return { return {
role: "user", role: "user",
content, content: entry.content,
timestamp: new Date(entry.timestamp).getTime(), timestamp: new Date(entry.timestamp).getTime(),
}; };
} }
@ -684,14 +665,14 @@ export class SessionManager {
/** /**
* Append a custom message entry (for hooks) that participates in LLM context. * Append a custom message entry (for hooks) that participates in LLM context.
* @param customType Hook identifier for filtering on reload * @param customType Hook identifier for filtering on reload
* @param content Message content (strings and attachments) * @param content Message content (string or TextContent/ImageContent array)
* @param display Whether to show in TUI (true = styled display, false = hidden) * @param display Whether to show in TUI (true = styled display, false = hidden)
* @param details Optional hook-specific metadata (not sent to LLM) * @param details Optional hook-specific metadata (not sent to LLM)
* @returns Entry id * @returns Entry id
*/ */
appendCustomMessageEntry<T = unknown>( appendCustomMessageEntry<T = unknown>(
customType: string, customType: string,
content: (string | Attachment)[], content: string | (TextContent | ImageContent)[],
display: boolean, display: boolean,
details?: T, details?: T,
): string { ): string {