Use proper HookAppMessage type instead of _hookData marker

Following the same pattern as BashExecutionMessage:
- HookAppMessage has role: 'hookMessage' with customType, content, display, details
- isHookAppMessage() type guard for checking message type
- messageTransformer converts to user message for LLM context
- TUI checks isHookAppMessage() for rendering as CustomMessageComponent

This makes the API clean for anyone building on AgentSession - they can
use the type guard instead of knowing about internal marker fields.
This commit is contained in:
Mario Zechner 2025-12-27 01:42:00 +01:00
parent 357bd946c2
commit 75a9c3c714
4 changed files with 111 additions and 81 deletions

View file

@ -26,10 +26,26 @@ export interface BashExecutionMessage {
timestamp: number;
}
import type { ImageContent, TextContent } from "@mariozechner/pi-ai";
/**
* Message type for hook-injected messages via sendMessage().
* These are custom messages that hooks can inject into the conversation.
*/
export interface HookAppMessage<T = unknown> {
role: "hookMessage";
customType: string;
content: (TextContent | ImageContent)[];
display: boolean;
details?: T;
timestamp: number;
}
// Extend CustomMessages via declaration merging
declare module "@mariozechner/pi-agent-core" {
interface CustomMessages {
bashExecution: BashExecutionMessage;
hookMessage: HookAppMessage;
}
}
@ -44,6 +60,13 @@ export function isBashExecutionMessage(msg: AppMessage | Message): msg is BashEx
return (msg as BashExecutionMessage).role === "bashExecution";
}
/**
* Type guard for HookAppMessage.
*/
export function isHookAppMessage(msg: AppMessage | Message): msg is HookAppMessage {
return (msg as HookAppMessage).role === "hookMessage";
}
// ============================================================================
// Message Formatting
// ============================================================================
@ -91,6 +114,14 @@ export function messageTransformer(messages: AppMessage[]): Message[] {
timestamp: m.timestamp,
};
}
if (isHookAppMessage(m)) {
// Convert hook message to user message
return {
role: "user",
content: m.content,
timestamp: m.timestamp,
};
}
// Pass through standard LLM roles
if (m.role === "user" || m.role === "assistant" || m.role === "toolResult") {
return m as Message;