makecindy / makecindy/cindy

[Feature] 为 assistant 任务结果增加统一的交付物预览与附件操作区

Open
#139 3 comments 0 reactions 0 assignees View on GitHub
feature
Dominant language
TypeScript
Stars
2.7k
Forks
401
Avg merge
21h 48m
Merged PRs (30d)
776

Description

## 使用场景

用户让 Cindy 完成生成海报、图片、视频、音频、3D 模型或导出文件等任务时,当前聊天通常只能看到 Markdown 文本、工具过程,或某个工具结果里的单张媒体。用户需要自己从正文或工具调用中判断“最终产物是什么、文件在哪里、如何打开”。

对比 Codex 的任务输出体验,用户期望一次任务完成后看到清晰的结果交付区:运行摘要、主产物缩略图、点击放大、下载/复制/Open in 等操作,以及源文件和支持文件附件卡片。

## 现状

桌面端已经具备很多底层能力,但这些能力没有被统一到 assistant 最终回复:

- `ChatImageView` / `ImageLightbox` 已支持点击放大、gallery、缩放、复制、另存为、默认应用打开和发送到对话。
- `cindy-media://` 媒体总仓、媒体引用账本和媒体 IPC 已存在。
- `AgentActionRow` / `MessageStream` 能从 tool result 顶层的 `xdt_image_url(s)`、`xdt_video_urls`、`xdt_audio_tracks`、`_xdt_model_files` 提取并渲染媒体。
- Ghost 卡片支持沙箱 HTML、图片 lightbox 和 `data-ghost-action` 交互。
- 但 `ChatMessage` 没有通用的 assistant-side `artifacts/deliverables` 字段,`images/files` 主要是用户输入附件。
- `AssistantMessage` 普通路径只有 Markdown,Ghost 路径只有自绘 HTML 卡片,没有统一的“主产物 + 附件列表 + 操作行”。
- Ghost 卡片持久化/推送目前主要保存 `callId/ghostId/html/height/state`,没有产物清单、文件名、MIME、尺寸、来源或动作能力。
- 媒体落库目前主要通过扫描消息内容挂 `session-attachment` 引用,能够保住字节,但没有消息级交付物语义。
- `maker-shared/payloadSummary` 已能解析部分媒体 action,但桌面端仍使用自己的媒体解析器,desktop/mobile 对同一 tool result 的 action 展示存在分叉。

相关代码:

- `apps/desktop/src/renderer/lib/ccAgent.types.ts`
- `apps/desktop/src/renderer/lib/makerChatStore.ts`
- `apps/desktop/src/renderer/components/chat/AssistantMessage.tsx`
- `apps/desktop/src/renderer/components/chat/AgentActionRow.tsx`
- `apps/desktop/src/renderer/components/chat/MessageStream.tsx`
- `apps/desktop/src/main/cindy-brain/cardService.ts`
- `apps/desktop/src/main/cindy-brain/cardStoreDb.ts`
- `apps/desktop/src/main/cindy-media/chatAttachments.ts`

## 诉求

为 assistant 的一次 turn 建立统一的交付物投影,使不同来源的产物(tool result、Ghost、Codex/Claude 生成文件、导出文件)都可以用同一套结构渲染:

1. 结果摘要和运行元数据,例如耗时、技能/模式、完成状态。
2. 一个或多个主产物预览,图片/视频可点击进入现有 lightbox。
3. 统一操作行:Preview、Download/Save as、Open in、Copy、Reveal 等。
4. Supporting files 附件卡片:显示文件名、MIME/大小,并提供没有预览时的文件 fallback。
5. 可折叠的 provenance/details:来源工具、源文件、派生关系、hash 等。
6. 历史回放、远程会话和 Ghost 卡片场景保持一致。
7. 对旧消息和旧的 `xdt_*` 字段保持兼容,不能因没有 manifest 而丢失现有媒体。

建议的最小数据形态类似:

```ts
type AssistantArtifact = {
id: string;
role: 'primary' | 'supporting' | 'source';
uri: string;
filename: string;
mime: string;
bytes?: number;
width?: number;
height?: number;
durationMs?: number;
previewUri?: string;
actions?: Array<'preview' | 'download' | 'open' | 'copy' | 'reveal'>;
provenance?: {
sourceAssets?: string[];
tool?: string;
sha256?: string;
};
};
```

第一阶段可以将 manifest 投影到现有 `ChatMessage`/assistant content,不必立即引入远端 server;长期可演进为独立的 message-artifacts 表,并复用现有 `cindy-media` blob/ref 生命周期。

## 建议方案

- 增加 assistant turn 的结构化 output/artifact manifest,并在 live event、消息落库、历史 map 三条路径保持一致。
- 新增通用 `DeliverableStrip`/artifact renderer,复用现有 `ChatImageView`、`ImageLightbox`、文件预览和 media IPC。
- 将现有 `xdt_image_urls` 等字段适配为 artifact,旧工具无需立即改造。
- Ghost 的 card-update 除 HTML 外携带可选 artifact manifest;HTML 保留自定义视觉和插件动作,宿主负责标准附件区。
- 统一 desktop 与 mobile 对 `_xdt_actions`、媒体动作和远程取件状态的安全解析;动作需要 allowlist、inflight 锁和失败态。
- 操作能力由客户端按本机/远程环境过滤,服务端只提供产物语义和安全引用;不要让服务端决定本机具体“Open in”应用。

## 验收标准

- 生成一张图片时,完成消息下方出现稳定的主产物缩略图;点击进入现有图片 lightbox,历史重开后仍可用。
- 同一 turn 生成多张图片时,显示缩略图集合,并支持 gallery/左右切换。
- 生成图片、视频、音频、3D 模型和普通文件时,均有统一附件卡片;不可预览的文件有明确的下载/打开 fallback。
- `Open in`、Save as、Copy、Reveal 等操作在本地、远程和不可用场景正确显示/禁用,并提供错误反馈。
- Ghost 卡片既保留自绘 HTML/交互,又能在卡片下方显示标准化 supporting artifacts。
- 旧的 Markdown 图片和 `xdt_*` tool result 行为不回归;没有 manifest 的消息继续按现有路径渲染。
- assistant live streaming、消息持久化、历史回放、session share 和远程 device-link 至少各有一条测试覆盖。
- 不把 base64 大文件塞进普通 assistant 文本;产物字节继续复用 `cindy-media`。

## 范围说明

这是 desktop/shared packages 的体验与消息投影问题,主 issue 应在 `makecindy/cindy-temp`。当前 `cindy-server` 主要承载认证、设备互联和 Slack hook,不是本地 Maker 聊天 renderer;只有未来要让 artifact 跨 Slack/device-link 传输时,才需要在 `cindy-protocol` 增加相应的跨端契约。

Contributor guide

Open the contributing guide

Research direction

Start by tracing the artifact and message paths in ccAgent.types.ts, makerChatStore.ts, AssistantMessage.tsx, AgentActionRow.tsx, and MessageStream.tsx, then review cardService.ts, cardStoreDb.ts, and chatAttachments.ts. Compare existing xdt_* parsing, Ghost persistence, and media IPC behavior. Done means a compatible assistant artifact projection works across live messages, persistence, history, Ghost cards, and the stated media/file acceptance cases with tests.

Written by the indexing model from the issue text.

Assessment

Tech stack
typescript
Domain
desktop, frontend
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.