feat(gmail): add --thread-id to drafts create/update for parity with send#674
Conversation
…send
`gmail send` accepts --thread-id ("uses latest message for headers") but
`gmail drafts create`/`update` only accepted --reply-to-message-id, so there
was no thread-aware reply path when composing a draft. Callers who knew the
thread (not the latest message id) had nowhere to put it; passing a thread id
into --reply-to-message-id silently mis-threads — the draft lands in the thread
via subject fallback but In-Reply-To/References never anchor to the parent's
RFC822 Message-Id, and there's no error.
Wire --thread-id into both draft commands, reusing the existing
prepareComposeReply/fetchReplyInfo thread path (selects the latest thread
message for reply headers):
- Mutually exclusive with --reply-to-message-id (matches `send`).
- --quote now accepts a thread target too.
- On update, a caller-provided --thread-id overrides the draft's existing
thread; the existing-draft thread fallback is preserved when omitted.
- dry-run/JSON gains a thread_id field.
Tests: create resolves to the thread's latest message and stamps threadId +
In-Reply-To/References; mutual-exclusion guard; update override. Regenerated
command docs.
Live-verified (redacted): `gog gmail drafts create --thread-id <T>` produced a
draft whose In-Reply-To/References equal the thread's latest message Message-Id
and whose threadId == <T> (scratch draft created, verified, deleted).
Closes openclaw#673.
|
Codex review: needs maintainer review before merge. Reviewed June 3, 2026, 4:50 PM ET / 20:50 UTC. Summary Reproducibility: yes. Source inspection shows current main supports Review metrics: 3 noteworthy metrics.
Merge readiness Overall follows the weaker of proof and patch quality, so missing proof can cap an otherwise strong patch. Next step before merge
Security Review detailsBest possible solution: Review and land this PR or an equivalent narrow change so draft create/update can target a Gmail thread through the existing reply helper; keep the linked issue open until the implementation merges. Do we have a high-confidence way to reproduce the issue? Yes. Source inspection shows current main supports Is this the best way to solve the issue? Yes. Reusing AGENTS.md: found and applied where relevant. Codex review notes: model gpt-5.5, reasoning high; reviewed against 096323d506b9. Label changesLabel justifications:
Evidence reviewedWhat I checked:
Likely related people:
What the crustacean ranks mean
Shiny media proof means a screenshot, video, or linked artifact directly shows the changed behavior. Runtime, network, CSP, and security claims still need visible diagnostics. How this review workflow works
|
Closes #673.
Problem
gmail sendaccepts--thread-id("uses latest message for headers"), butgmail drafts create/updateonly accepted--reply-to-message-id. There was no thread-aware reply path when composing a draft: a caller who knows the thread (but not the latest message id) had nowhere to put it, and passing a thread id into--reply-to-message-idsilently mis-threads — the draft lands in the thread via subject fallback butIn-Reply-To/Referencesnever anchor to the parent's RFC822Message-Id, with no error.Change
Wire
--thread-idintoGmailDraftsCreateCmdandGmailDraftsUpdateCmd, reusing the existingprepareComposeReply→fetchReplyInfothread path (which already selects the latest thread message for reply metadata). Narrow, matchessend:--reply-to-message-id(use only one of …, same guard assend).--quotenow accepts a thread target too.--thread-idoverrides the draft's existing thread; the existing-draft thread fallback is preserved when--thread-idis omitted (no behavior change for current callers).thread_idadded to the dry-run/JSON payload for both commands.docs/commands/gog-gmail-drafts-{create,update}.md.Tests
TestGmailDraftsCreateCmd_WithThreadID— resolves the thread's latest message; asserts the posted draft'sthreadIdand decoded rawIn-Reply-To: <latest@id>+References.TestGmailDraftsCreateCmd_ThreadIDAndMessageIDMutuallyExclusive— guard.TestGmailDraftsUpdateCmd_WithThreadIDOverridesExisting— caller thread overrides the draft's existing thread.go test ./internal/cmdgreen;make lint0 issues;make docs-commandsclean.Real-behavior proof (redacted live Gmail)
Built from this branch (
v0.21.1-…+dirty), against a real account:The draft's
threadIdequals the supplied--thread-id, and itsIn-Reply-To/Referencesequal the thread's latest message's RFC822Message-Id— exactly the anchoring that was missing before. Scratch draft was deleted afterward.(Reported via the gogcli-mcp wrapper, which currently resolves thread→latest-message client-side; once this ships the wrapper passes
--thread-idthrough directly.)