Libra CodeHub

CedarCopilot/cedar-mail

Branch: staging

feat(chat): let the agent request a Google Drive file with a picker card

merged#2926CedarCopilot

CedarCopilot wants to merge 2 commits into staging from worktree-send-it-drive-file-request

Customer behavior verdict

Libra exercised 1 changed behavior; none regressed.

Who this touches

  • A Drive-file request produces a usable picker card in the originating thread: Libra no longer holds the traces from the last 7 days before this change, so it cannot count who used it; open pull requests are counted on live traffic.
  • Picking a Drive file adds it to the knowledge base and resumes the same thread: Libra no longer holds the traces from the last 7 days before this change, so it cannot count who used it; open pull requests are counted on live traffic.
  • A previously added Drive file is not imported again: Libra no longer holds the traces from the last 7 days before this change, so it cannot count who used it; open pull requests are counted on live traffic.
  • Document-write action scopes preserve mutation and request-file boundaries: Libra cannot measure who uses this yet; it has not mapped this to a production entry point yet; it will trace it through the import graph on a coming run.
  • kb.createKbFromGoogleDrive: Libra no longer holds the traces from the last 7 days before this change, so it cannot count who used it; open pull requests are counted on live traffic.
  • kb.listKbDocuments: Libra no longer holds the traces from the last 7 days before this change, so it cannot count who used it; open pull requests are counted on live traffic.
  • Web chat renders a usable Google Drive picker request: Held on this PR; the scenario fails when this is broken on purpose.
  • Document-write action scopes remain restricted while request-file is viewer-hidden: This scenario failed on both revisions. Libra has not established whether the cause is existing behavior or the scenario itself.
  • A tool call an agent makes for a user finishes with a result: Libra could not tell on this PR.

What Libra verified

  • Web chat renders a usable Google Drive picker request

    Libra ran this behavior against the change and confirmed the check detects when it breaks.

    Technical evidence
    • the web chat processor accepts a well-formed request-file card with its purpose and server-minted id
    • the streamed picker card is persisted with the same server-minted id and purpose for its target thread

    Changed code: requestDriveFileResponseProcessor.ts.

Live on prod, 0 of 10 surfaces working, 2 days leftTimeline and evidence
  1. Opened
    Sep 23, 2026, 3:50 PM
  2. Sep 23, 2026, 4:20 PM
  3. Merged
    Sep 23, 2026, 4:38 PM
  4. Live on prod
    Sep 23, 2026, 4:38 PM
  5. Observed 0 hours, 10 surfaces, 6 requests
    Sep 23, 2026, 4:38 PM
  6. Watching

    Live on prod, 0 of 10 surfaces working, 2 days left

    Sep 23, 2026, 4:38 PM
  7. Pipelines steady after this deploy
    Sep 23, 2026, 4:38 PM

Behaviors Libra is checking

The chat response processor accepts only well-formed requestDriveFile responses and inserts the server-minted card into the target thread as an assistant message.Not checked
prod
The request-file action requires only the document family's docs:read scope rather than a write scope.Not checked
prod
On headless or autonomous surfaces, request-file returns instructions for either sharing a public Google link or reconnecting Google through /settings/connections?tab=slides instead of attempting to render a picker.Not checked
prod
The request-file action rejects calls that omit the requestFile parameters object with a structured tool error.Not checked
prod
When the agent calls document-write with action request-file in interactive chat, Cedar streams a requestDriveFile card containing the purpose and a server-generated message ID and tells the agent to wait for the user's selection.Not checked
prod
Each request-file invocation emits an operational log describing the surface, whether a card was shown, and the purpose length without logging the purpose text itself.Not checked
prod

Libra found 10 production surfaces on prod but could not judge any of them yet. 1 surface had under 20 requests, so Libra has not judged it; 9 surfaces had no requests at all. Libra checks hourly for 3 days after each deploy.

Summary

  • Cedar's Google grant is drive.file, so an agent can only read files a user picked in the app; a share, an email address or a pasted link grants nothing. The agent kept telling users to share with a "service account" that does not exist (a customer hit this on a template deck).
  • New request-file action on document-write. In web chat it streams a "Choose from Drive" card that opens the Google Picker, saves the pick to the org knowledge base and messages the agent so its next turn starts. On Slack, cron and MCP (no picker possible) it returns the two ways to hand over a file.
  • A link-shared Google file pasted as write-document sourceUrl is now read through Google's export endpoints instead of scraping a sign-in page. A private file fails with both options spelled out for the agent, and with a neutral message for humans.
  • cedar-configuration and external-systems docs name the two ways in and forbid the service-account advice.

Known limits, decided deliberately

  • The KB row is org-visible, but the picked file is readable only through the picking user's drive.file grant. The requester's own runs work; a teammate's run sees the entry and cannot read it. A user-scoped entry is a follow-up.
  • request-file lives on document-write, so viewers do not see it. The scope-map classification is explicit and commented.

Test plan

  • pnpm run autofix:local pieces (brand check, oxlint --deny-warnings, pnpm deps:check, mail jest) pass locally and in CI. chatHistoryList.test.ts failed once on my machine (it hard-codes "February" from a relative date) and passes in CI; this branch does not touch it.
  • Full server vitest (src/): 1,161 files / 14,489 tests pass (run before the review-fix commits). After the fixes and the final staging merge I re-ran the affected areas (src/mastra/mcp, src/mastra/skills/account-config, src/mastra/tools, src/services/kb): 143 files / 2,288 tests pass.
  • Server and mail typecheck exit 0 (mail after react-router typegen).
  • New tests: google-public-link.test.ts (parsing, streaming size cap, stalled body, status classification, host allowlist, log shape), url-scraper-google.test.ts, documentTool.test.ts (request-file on interactive and autonomous surfaces), writeDocumentTool.test.ts, scope-map.test.ts, chat-message-persistence.test.ts, requestDriveFileResponseProcessor.test.tsx, requestDriveFileRenderer.test.tsx.
  • Agent-feature battle test: NOT RUN. apps/server/.claude/skills/playbook-instruction-eval/request-file-eval.ts measures how often the model reaches for request-file (6 cases x 5 trials, claude-sonnet-5). It passes --dry; the live run was not approved (est. $1-2). The description is squeezed to about 60 bytes under the 2KB tool-description budget, so the fire rate is worth measuring before or soon after merge.
  • Three independent thermo-review rounds; every finding fixed, including removing an unrelated agent-env change (kept as a separate patch). Greptile's three P2 comments (server-side idempotency in createKbFromGoogleDrive, absolute imports in the new mail tests, casts in a new test helper) are fixed in dc2142e33.

Verify in prod

  • Axiom dataset cedar-prod (or cedar-staging):
    ['cedar-prod'] | where _time > ago(1h) and message == "kb.google-public-link.read"
    | summarize count() by outcome, tostring(kind)
    
    Attrs: operation, kind, outcome (ok / not_public / too_large / extraction_failed / html_response / http_error / unexpected_host / fetch_failed), httpStatus, contentType, bytes, durationMs. No file id, URL or content is ever logged. fetch_failed goes through logError.
    ['cedar-prod'] | where _time > ago(1h) and message == "document-write.request-file"
    | summarize count() by tostring(surface), tostring(cardShown)
    
    Attrs: operation, cardShown, surface (interactive / autonomous), purposeChars (never the text).
  • CloudWatch: `/aws/ecs/
Show production surfaces and changed-file mapping

Production surfaces

SurfaceRequestsErrorsp95UsersVerdict
/api/trpc/admin.documents.readByPath0 → 60 → 0 (0%)not measured → 231 ms0Insufficient traffic
6 requests, under the 20 Libra needs
execute_tool read-document0 → 00 → 0 (0%)not measured0No traffic
No requests recorded since this deploy.
/api/trpc/documents.getDoc3 → 00 → 0 (0%)200 ms → not measured0No traffic
No requests recorded since this deploy.
POST /api/trpc/documents.getDoc2 → 00 → 0 (0%)200 ms → not measured0No traffic
No requests recorded since this deploy.
execute_tool write-document1 → 00 → 0 (0%)625 ms → not measured0No traffic
No requests recorded since this deploy.
execute_tool list-documents0 → 00 → 0 (0%)not measured0No traffic
No requests recorded since this deploy.
trpc.documents.getDoc1 → 00 → 0 (0%)177 ms → not measured0No traffic
No requests recorded since this deploy.
/api/trpc/documents.getAncestors0 → 00 → 0 (0%)not measured0No traffic
No requests recorded since this deploy.
POST /api/trpc/documents.getAncestors0 → 00 → 0 (0%)not measured0No traffic
No requests recorded since this deploy.
useGooglePicker.KB_DRIVE_MIMES0 → 00 → 0 (0%)not measured0No traffic
No requests recorded since this deploy.

Changed files → surfaces

  • apps/server/src/mastra/tools/document/documentTool.ts/api/trpc/admin.documents.readByPathexecute_tool read-document/api/trpc/documents.getDocPOST /api/trpc/documents.getDocexecute_tool write-documentexecute_tool list-documents+3
  • apps/mail/modules/cedar-os/__tests__/requestDriveFileRenderer.test.tsxno production surface mapped
  • apps/mail/modules/cedar-os/__tests__/store/agentConnection/responseProcessors/requestDriveFileResponseProcessor.test.tsxno production surface mapped
  • apps/mail/modules/cedar-os/src/store/agentConnection/responseProcessors/initializeResponseProcessorRegistry.tsno production surface mapped
  • apps/mail/modules/cedar-os/src/store/agentConnection/responseProcessors/requestDriveFileResponseProcessor.tsno production surface mapped
  • apps/mail/modules/cedar-os/src/store/messages/renderers/RequestDriveFileRenderer.tsxno production surface mapped
  • apps/mail/modules/cedar-os/src/store/messages/renderers/initializeMessageRendererRegistry.tsxno production surface mapped
  • apps/mail/modules/integrations/google-slides-manager.tsxno production surface mapped
  • apps/mail/modules/integrations/use-google-picker.tsno production surface mapped
  • apps/server/.claude/skills/cedar-configuration/knowledge-and-collateral.mdno production surface mapped
  • apps/server/.claude/skills/external-systems/google-drive.mdno production surface mapped
  • apps/server/.claude/skills/playbook-instruction-eval/request-file-eval.tsno production surface mapped
  • apps/server/src/mastra/mcp/external/__tests__/mutating-actions-are-administrable.test.tsno production surface mapped
  • apps/server/src/mastra/mcp/external/__tests__/scope-map.test.tsno production surface mapped
  • apps/server/src/mastra/mcp/external/scope-map.tsno production surface mapped
  • apps/server/src/mastra/tools/document/__tests__/documentTool.test.tsno production surface mapped
  • apps/server/src/mastra/tools/document/__tests__/writeDocumentTool.test.tsno production surface mapped
  • apps/server/src/mastra/tools/document/documentTool.schemas.tsno production surface mapped
  • apps/server/src/mastra/tools/document/writeDocumentTool.tsno production surface mapped
  • apps/server/src/mastra/utils/__tests__/chat-message-persistence.test.tsno production surface mapped
  • apps/server/src/mastra/utils/approval-policy.tsno production surface mapped
  • apps/server/src/services/kb/__tests__/create-kb-from-google-drive.test.tsno production surface mapped
  • apps/server/src/services/kb/__tests__/google-public-link.test.tsno production surface mapped
  • apps/server/src/services/kb/__tests__/url-scraper-google.test.tsno production surface mapped
  • apps/server/src/services/kb/google-public-link.tsno production surface mapped
  • apps/server/src/services/kb/helpers.tsno production surface mapped
  • apps/server/src/services/kb/url-scraper.tsno production surface mapped