Feat/inbox ai - #93
Conversation
Replies to inbox messages could only be composed in the web view and were sent to the platform immediately, with no way to draft one for review or to create one programmatically. Give InboxReply a draft -> sent/failed lifecycle (migration 0002 backfills existing rows to "sent") and add apps/inbox/services.py as the single source of truth the web views, a new /api/v1/inbox REST router, and six new MCP tools all delegate to. Drafting is gated on use_inbox; delivering a reply is gated on reply_from_inbox. Message/reply lookups are scoped to the API key's workspace and account allowlist. The web composer now shows pending drafts with Send / Discard controls. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Serialize draft mutations, replay idempotent reply creation, reject mixed MCP send modes, and sanitize provider failures. Add regression coverage for concurrency, retries, and delivery persistence. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: f99502ac08
ℹ️ About Codex in GitHub
Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".
| sent = list( | ||
| message.replies.filter(status=InboxReply.Status.SENT) | ||
| .order_by("-sent_at", "-created_at") | ||
| .values_list("body", flat=True)[:8] |
There was a problem hiding this comment.
Include ancestor replies in threaded AI context
When the target is a follow-up with parent_message_id, earlier outbound replies are stored on the ancestor messages, but this query only reads message.replies. The generated context therefore includes the parent messages while omitting the account's answers between them, so suggestions can repeat or contradict what the team already said. Collect sent replies from the traversed message chain, still applying the existing workspace/account bounds and eight-reply limit.
Useful? React with 👍 / 👎.
| def _noop(apps, schema_editor): | ||
| pass |
There was a problem hiding this comment.
Backfill nullable sent_at before reversing migration
If this migration is rolled back after any draft or failed reply has been created, those rows have sent_at = NULL; the reverse AlterField then restores the old non-null auto_now_add column and PostgreSQL cannot apply SET NOT NULL. The reverse data migration should populate or remove these lifecycle-only rows before the schema is reverted instead of doing nothing, otherwise a deployment rollback can fail.
Useful? React with 👍 / 👎.
What does this PR do?
Why?
How to test
Checklist
pytest)ruff check .andruff format --check .)