Add chat attachment support: surface metadata and download files - #488
Conversation
Previously, get_messages and search_messages completely ignored the attachment field on Chat API messages. This adds: - Attachment metadata (filename, type) displayed inline in get_messages and search_messages output - New download_chat_attachment tool that downloads attachments via the Chat API media endpoint and saves to local disk The download uses httpx with a Bearer token against the chat.googleapis.com/v1/media endpoint (with alt=media), which works correctly in both OAuth 2.0 and OAuth 2.1 modes. The attachment's downloadUri field is intentionally ignored as it points to chat.google.com which requires browser session cookies. Key details: - Uses attachmentDataRef.resourceName for the media endpoint URL - No new OAuth scopes required (existing chat_read is sufficient) - Tool registered in the extended tier - 10 unit tests covering metadata display, download, and edge cases
|
Caution Review failedThe pull request is closed. 📝 WalkthroughWalkthroughAdds attachment support for Google Chat: updates tool tiers, surfaces attachment metadata in message listing/search, implements Changes
Sequence DiagramsequenceDiagram
participant User as User/Client
participant Tool as download_chat_attachment
participant API as Google Chat API
participant Storage as Storage System
User->>Tool: download_chat_attachment(service, email, message_id, index)
activate Tool
Tool->>API: Fetch message & attachment metadata
activate API
API-->>Tool: Return attachments (+ media endpoint or dataRef)
deactivate API
alt Stateless preview
Tool->>API: Request media bytes from media endpoint
activate API
API-->>Tool: Attachment bytes
deactivate API
Tool->>Tool: Encode bytes to base64
Tool-->>User: Return base64 string
else Persistent save / URL
Tool->>API: Fetch attachment bytes (if needed)
activate API
API-->>Tool: Attachment bytes
deactivate API
Tool->>Storage: Save bytes / request temp URL
activate Storage
Storage-->>Tool: File path or download URL
deactivate Storage
Tool-->>User: Return file path or URL
end
deactivate Tool
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Possibly related PRs
Suggested labels
Poem
🚥 Pre-merge checks | ✅ 2 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
gchat/chat_tools.py (1)
520-526: Add an explicit timeout to the httpx download call.
Large attachments or slow networks can hang or exceed implicit defaults. Setting a timeout improves reliability and makes behavior predictable.Proposed fix
- async with httpx.AsyncClient(follow_redirects=True) as client: + timeout = httpx.Timeout(60.0) + async with httpx.AsyncClient(follow_redirects=True, timeout=timeout) as client: resp = await client.get( download_url, headers={"Authorization": f"Bearer {access_token}"}, )🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed. In `@gchat/chat_tools.py` around lines 520 - 526, The httpx download call lacks an explicit timeout causing potential hangs; update the download logic in gchat/chat_tools.py (around the access_token = service._http.credentials.token and async with httpx.AsyncClient(...) as client block) to pass a clear timeout (e.g., httpx.Timeout or a numeric seconds value) to the request (either when constructing AsyncClient or to client.get) so the GET to download_url uses a bounded timeout and fails predictably on slow networks.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.
Inline comments:
In `@gchat/chat_tools.py`:
- Around line 403-409: The search_messages output currently builds att_suffix
from attachment contentName only; update the attachment formatting in
gchat/chat_tools.py (where attachments, att_suffix and the output.append line
are defined) to include the MIME type too (e.g., use a.get("contentType") or a
fallback like "unknown") so each attachment is rendered as "filename, MIME type"
to match get_messages and the stated requirement; ensure the new att_suffix
string interpolation uses both a.get("contentName", "unnamed") and the MIME type
when constructing the appended message.
---
Nitpick comments:
In `@gchat/chat_tools.py`:
- Around line 520-526: The httpx download call lacks an explicit timeout causing
potential hangs; update the download logic in gchat/chat_tools.py (around the
access_token = service._http.credentials.token and async with
httpx.AsyncClient(...) as client block) to pass a clear timeout (e.g.,
httpx.Timeout or a numeric seconds value) to the request (either when
constructing AsyncClient or to client.get) so the GET to download_url uses a
bounded timeout and fails predictably on slow networks.
Summary
get_messagesandsearch_messagesnow display attachment metadata (filename, MIME type) inline when Chat messages contain images or filesdownload_chat_attachmenttool (extended tier) fetches attachment binary data via the Chat API media endpoint and saves to local disk — returns a file path in stdio mode or a temporary download URL in HTTP modechat_readscopeTest plan
uvx ruff check .— lint cleantests/gchat/test_chat_tools.pycovering metadata display, download success, HTTP mode, error handling, and edge casesget_messagesoutputdownload_chat_attachmentsuccessfully downloads images from ChatSummary by CodeRabbit
New Features
Tests
Style