mirror of
https://github.com/coder/coder.git
synced 2026-09-24 15:04:27 +08:00
feat(coderd/x/chatd): agent-created file attachments in chat (#24280)
Agents can already see workspace files and take screenshots, but users could not download those artifacts from chat. This PR adds durable chat attachments to chatd. `attach_file`, explicit `computer` screenshot actions (not the automatic post-action screenshots), and `propose_plan` now fetch bytes over the agent connection, store them in `chat_files`, link them to the chat, and carry attachment metadata in tool responses so `buildAssistantPartsForPersist` can materialize ordinary `type:"file"` assistant parts that the chat file APIs serve. The same storage helpers are reused for other artifact-producing paths. `wait_agent` recordings and thumbnails are stored as chat files and linked back to the parent chat, with best-effort relinking so parent chats retain those artifacts without leaving orphaned rows when chat-file caps reject links. `storeChatAttachment` wraps insert + link in one transaction, files are capped at 10 MB each and 20 per chat, and serving defaults to `Content-Disposition: attachment` with an explicit inline-safe allowlist. This PR also consolidates chat-file media policy in `coderd/chatfiles`. Uploads and tool-generated attachments share byte-based MIME detection, SVG blocking, inline-safety rules, and compatible `text/plain` refinement for JSON, CSV, and Markdown. Prompt construction still only inlines synthetic pasted text for model consumption; assistant-created attachments are persisted for the user and intentionally not replayed into later LLM turns. UI follow-up lives in #24281. Relates to CODAGT-91
This commit is contained in:
+3
-1
@@ -212,6 +212,7 @@ type ChatMessagePart struct {
|
||||
URL string `json:"url" variants:"source"`
|
||||
Title string `json:"title,omitempty" variants:"source?"`
|
||||
MediaType string `json:"media_type" variants:"file"`
|
||||
Name string `json:"name,omitempty" variants:"file?"`
|
||||
Data []byte `json:"data,omitempty" variants:"file?"`
|
||||
FileID uuid.NullUUID `json:"file_id,omitempty" format:"uuid" variants:"file?"`
|
||||
FileName string `json:"file_name" variants:"file-reference"`
|
||||
@@ -327,11 +328,12 @@ func ChatMessageToolResult(toolCallID, toolName string, result json.RawMessage,
|
||||
}
|
||||
|
||||
// ChatMessageFile builds a file chat message part.
|
||||
func ChatMessageFile(fileID uuid.UUID, mediaType string) ChatMessagePart {
|
||||
func ChatMessageFile(fileID uuid.UUID, mediaType string, name string) ChatMessagePart {
|
||||
return ChatMessagePart{
|
||||
Type: ChatMessagePartTypeFile,
|
||||
FileID: uuid.NullUUID{UUID: fileID, Valid: true},
|
||||
MediaType: mediaType,
|
||||
Name: name,
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user