refactor(sdk): unify message types with pi-ai source of truth
Replace hand-written message/content types in @multica/sdk with `import type` from @mariozechner/pi-ai and @mariozechner/pi-agent-core. This ensures compile-time correctness and eliminates type drift between backend and frontend (e.g. "tool_use" vs "toolCall", "tool_result" vs "toolResult"). - stream.ts: re-export TextContent, ThinkingContent, ToolCall, ImageContent from pi-ai; use AgentEvent from pi-agent-core - rpc.ts: AgentMessageItem = pi-ai Message (no more manual mirroring) - connection-store.ts: use SDK types instead of inline hand-written ones - ContentBlock now includes ImageContent to match backend reality Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
parent
caee37c631
commit
ef4e57ffdd
6 changed files with 224 additions and 99 deletions
|
|
@ -33,8 +33,15 @@ export {
|
|||
export {
|
||||
StreamAction,
|
||||
type StreamPayload,
|
||||
type StreamEvent,
|
||||
type StreamMessageEvent,
|
||||
type StreamToolEvent,
|
||||
type AgentEvent,
|
||||
type ContentBlock,
|
||||
type TextContent,
|
||||
type ThinkingContent,
|
||||
type ToolCall,
|
||||
type ImageContent,
|
||||
// Backward-compatible aliases
|
||||
type TextBlock,
|
||||
type ThinkingBlock,
|
||||
type ToolCallBlock,
|
||||
extractTextFromEvent,
|
||||
} from "./stream";
|
||||
|
|
|
|||
|
|
@ -1,5 +1,7 @@
|
|||
/** RPC Actions - 请求/响应模式 */
|
||||
|
||||
import type { Message } from "@mariozechner/pi-ai";
|
||||
|
||||
export const RequestAction = "request" as const;
|
||||
export const ResponseAction = "response" as const;
|
||||
|
||||
|
|
@ -65,34 +67,11 @@ export interface GetAgentMessagesParams {
|
|||
limit?: number;
|
||||
}
|
||||
|
||||
/** Content block types from the agent engine */
|
||||
export interface TextContentBlock {
|
||||
type: "text";
|
||||
text: string;
|
||||
}
|
||||
|
||||
export interface ThinkingContentBlock {
|
||||
type: "thinking";
|
||||
thinking: string;
|
||||
}
|
||||
|
||||
export interface ToolCallBlock {
|
||||
type: "tool_use";
|
||||
id: string;
|
||||
name: string;
|
||||
input: unknown;
|
||||
}
|
||||
|
||||
export interface ImageContentBlock {
|
||||
type: "image";
|
||||
url: string;
|
||||
}
|
||||
|
||||
/** Agent message returned by getAgentMessages (mirrors pi-ai Message) */
|
||||
export type AgentMessageItem =
|
||||
| { role: "user"; content: string | (TextContentBlock | ImageContentBlock)[]; timestamp: number }
|
||||
| { role: "assistant"; content: (TextContentBlock | ThinkingContentBlock | ToolCallBlock)[]; timestamp: number }
|
||||
| { role: "tool_result"; toolCallId: string; content: (TextContentBlock | ImageContentBlock)[]; isError: boolean; timestamp: number }
|
||||
/**
|
||||
* Agent message returned by getAgentMessages.
|
||||
* This is pi-ai's Message type — the backend returns it as-is from SessionManager.loadMessages().
|
||||
*/
|
||||
export type AgentMessageItem = Message;
|
||||
|
||||
/** getAgentMessages - response payload */
|
||||
export interface GetAgentMessagesResult {
|
||||
|
|
|
|||
|
|
@ -1,49 +1,47 @@
|
|||
/** Stream Action - 流式消息传输 */
|
||||
/** Stream Action */
|
||||
|
||||
export const StreamAction = "stream" as const;
|
||||
|
||||
// --- Content block types (re-exported from pi-ai, the single source of truth) ---
|
||||
|
||||
import type {
|
||||
TextContent,
|
||||
ThinkingContent,
|
||||
ToolCall,
|
||||
ImageContent,
|
||||
} from "@mariozechner/pi-ai";
|
||||
import type { AgentEvent } from "@mariozechner/pi-agent-core";
|
||||
|
||||
export type { TextContent, ThinkingContent, ToolCall, ImageContent };
|
||||
export type { AgentEvent };
|
||||
|
||||
/** Backward-compatible aliases */
|
||||
export type TextBlock = TextContent;
|
||||
export type ThinkingBlock = ThinkingContent;
|
||||
export type ToolCallBlock = ToolCall;
|
||||
export type ContentBlock = TextContent | ThinkingContent | ToolCall | ImageContent;
|
||||
|
||||
// --- Stream event types ---
|
||||
|
||||
/**
|
||||
* AgentEvent types forwarded by the Hub to frontend clients.
|
||||
* These mirror the subset of AgentEvent from @mariozechner/pi-agent-core
|
||||
* that the Hub forwards (filtered at the Hub layer).
|
||||
* Hub forwards AgentEvent from pi-agent-core as-is.
|
||||
* StreamPayload wraps it with routing metadata.
|
||||
*/
|
||||
export interface StreamMessageEvent {
|
||||
type: "message_start" | "message_update" | "message_end";
|
||||
message: {
|
||||
id?: string;
|
||||
role: string;
|
||||
content?: Array<{ type: string; text?: string }>;
|
||||
};
|
||||
assistantMessageEvent?: unknown;
|
||||
}
|
||||
|
||||
export interface StreamToolEvent {
|
||||
type: "tool_execution_start" | "tool_execution_end";
|
||||
toolCallId: string;
|
||||
toolName: string;
|
||||
args?: unknown;
|
||||
result?: unknown;
|
||||
isError?: boolean;
|
||||
}
|
||||
|
||||
export type StreamEvent = StreamMessageEvent | StreamToolEvent;
|
||||
|
||||
/** 流消息 payload — wraps a raw AgentEvent with stream/agent identifiers */
|
||||
export interface StreamPayload {
|
||||
/** 流 ID,关联同一个流的所有消息 */
|
||||
streamId: string;
|
||||
/** 所属 agent ID */
|
||||
agentId: string;
|
||||
/** Raw agent event from the engine */
|
||||
event: StreamEvent;
|
||||
event: AgentEvent;
|
||||
}
|
||||
|
||||
/** Extract plain text from an AgentMessage content array */
|
||||
export function extractTextFromEvent(event: StreamMessageEvent): string {
|
||||
const content = event.message?.content;
|
||||
/** Extract plain text from an AgentEvent that carries a message */
|
||||
export function extractTextFromEvent(event: AgentEvent): string {
|
||||
if (!("message" in event)) return "";
|
||||
const msg = event.message;
|
||||
if (!msg || !("content" in msg)) return "";
|
||||
const content = msg.content;
|
||||
if (!Array.isArray(content)) return "";
|
||||
return content
|
||||
.filter((c) => c.type === "text")
|
||||
.filter((c): c is TextContent => c.type === "text")
|
||||
.map((c) => c.text ?? "")
|
||||
.join("");
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue