diff --git a/src/api/types.ts b/src/api/types.ts
index 6ec5f14..c0aff93 100644
--- a/src/api/types.ts
+++ b/src/api/types.ts
@@ -278,6 +278,25 @@ export type AiChatEvent = ({
conversation_id?: string
}
+/**
+ * 多模态消息内容片(F-260614-05 Phase 2b 前端类型,对齐后端 df-ai-core ContentPart)。
+ *
+ * 后端 serde:`#[serde(tag = "type", rename_all = "snake_case")]`,
+ * 前端 discriminator 用字面量 `type` 字段('text' | 'image'),与后端 wire 格式严格对齐。
+ * Image 片:url / base64 二选一(base64 非空时 url 忽略),media_type 仅 base64 模式必填。
+ */
+export type ContentPart =
+ | { type: 'text'; text: string }
+ | {
+ type: 'image'
+ url?: string | null
+ base64?: string | null
+ /** base64 模式必填(image/png|jpeg|webp|gif);url 模式可空 */
+ media_type?: string | null
+ /** 可选 alt(vision 模型/降级文本时用) */
+ alt?: string | null
+ }
+
/** AI 消息(前端渲染用,isError 标记错误消息用于差异化样式) */
export interface AiMessage {
id: string
@@ -287,6 +306,13 @@ export interface AiMessage {
toolCalls?: AiToolCallInfo[]
/** 生成该消息的 model(仅 assistant 消息,历史消息从 DB 读) */
model?: string
+ /**
+ * 多模态内容片(F-260614-05 Phase 2b)。
+ * undefined/空=纯文本消息(content 即全部载荷);非空含 Image 片=多模态消息,
+ * 用户气泡内渲染 (base64 data URI 或 url)。仅 user 消息有(parts 来自粘贴/拖拽输入)。
+ * 历史消息从 DB JSON 反序列化时透传(useAiConversations switchConversation)。
+ */
+ parts?: ContentPart[]
timestamp: number
}
diff --git a/src/components/AiChat.vue b/src/components/AiChat.vue
index b7c512e..0c75145 100644
--- a/src/components/AiChat.vue
+++ b/src/components/AiChat.vue
@@ -410,6 +410,20 @@