AK-134 - Conversation Initiation from Agent#362
Conversation
amithad
left a comment
There was a problem hiding this comment.
Spec-only PR (design.md / spec.md / plan.md for AK-134) — reviewed against ak-dev-write-spec, ak-dev-architecture, and the messaging-integration conventions. No implementation code, so spec-conformance checks on code don't apply.
Overall: a strong, well-verified spec set.
- Nearly every
path:lineclaim checks out againstdevelop: the integration session-id derivation points (Slack/WhatsApp/Telegram/Messenger/Instagram/Teams/Gmail), queue pipeline citations, response-handler behavior,threadconfig gate,ConversationThreadManagersignatures (first_prompt,append_message,RLock),SQSHandler.send_message_to_output_queuekwargs,SessionStoreBuilder's valkey ImportError pattern, the Terraform response-store pattern, and the negative grep-claims (resolve_session_idunused inak-py/src; no serverless DynamoDB tables). - Design → spec → plan traceability is complete: every design requirement maps to a spec section, every spec component to exactly one plan iteration, and the tests + docs/skills-sync iterations are present.
- The error-handling table covers the details specs routinely omit: exception scopes, the singleton concurrency contract, the hot-path lookup cost, and the duplicate-send-on-redelivery rationale for
complete()never raising.
Findings (inline): 1 suggestion, 2 questions, 3 nits.
[suggestion]spec.md:103 — reuse the sharedcore/util/driver/drivers instead of writing new per-module thin drivers; theRedisDrivercitation points at the wrong file.[question]spec.md:95 — the reverse session→thread lookup has no named consumer.[question]plan.md:82 — the flat specs slated for deletion don't exist ondevelop.[nit]s:thread_idnaming collision in the manager signatures; "fixed or agent-generated" leftover; PNG vs Mermaid diagram.
Not anchorable inline:
[question]Staging: all three documents land in one PR, whileak-dev-write-specexpectsdesign.mdto survive its review cycles beforespec.mdis written. The docs hint a v1 cycle happened (plan.md's "superseded flat specs", spec.md's "v1 same-session guard") — please state in the PR description where the design review took place.[nit]PR title/template: spec-only PRs take adocs:conventional title (e.g.docs: add design, spec and plan for AK-134 agent-initiated conversations), the template should mark Documentation update rather than New feature, note that implementation follows in a separate PR, and mark the N/A testing/checklist items as such.- Trivial citation drift: the
thread:root field is atconfig.py:393, not:397(cited in both design.md and spec.md). - CI: the two failing e2e jobs (
api/multimodal/openai,memory/key-value-cache) can't be caused by a docs-only diff — likely flaky/infra; worth a re-run before merge.
amithad
left a comment
There was a problem hiding this comment.
Re-review — the PR grew from spec-only into the full implementation (core initiation/ package, deployment wiring, 8 integration resolve points, Terraform, docs, skills, example, 4 test files). Reviewed the revised spec set first, then walked the implementation against the spec's requirements checklist.
Previous review: all six findings addressed — Mermaid diagram, shared-driver reuse (with corrected citations), the reverse-lookup consumer named in design+spec and implemented (get_messaging_integration_thread_id + reply-delivery contract), naming fixes, flat-spec plan step dropped, config.py:393. The spec revisions are consistent with the implementation.
Spec conformance: excellent. Every design/spec requirement I checked is implemented and tested: presence-gated feature (mapping_table), platform-blind runner (tool dispatches; Terraform grants the runner no table access), single choke points (resolve_session_id / complete()), never-raising complete() with the duplicate-send rationale, INITIATION guards in all four stock handler methods, save-if-absent bind, all eight integration derivation points wrapped, POST /api/v1/chat rewrite-and-return with tests, valkey ImportError pattern, target_details kept off the tool schema (strict-schema constraint, documented in spec). Tests cover both SQS record shapes, the override contract end-to-end (send → bind → AK thread), and the never-raise guarantees. The skills/docs sync is unusually thorough.
Findings (1 blocker, 1 suggestion, 1 nit — inline):
[blocker]examples/api/slack-initiation/server.py:91— the example's flagship DM flow never resolves replies: it binds the DM channel id, but the Slack handler resolvesthread_ts, so Monroe's reply always lands in a fresh, context-less session — the exact failure AK-134 exists to fix.[suggestion]docs/docs/advanced/conversation-initiation.md:2— the new page is missing fromdocs/sidebars.js(explicit items list), so it's unreachable from the docs navigation.[nit]docs/specs/ak-134/spec.md:206— spec's Terraform/IAM wording no longer matches the (better) implementation; align it since the spec ships in this PR.
Not anchorable inline:
[nit]plan.md iteration 10.2 commits to updatingdocs/docs/deployment/pages that describe response-handler customization — none were touched.deployment/aws-containerized.md:143("each writing … records to the response store … On permanent failure … writes an error record") andadvanced/queue-mode-guide.md'sECSOutputConsumerdescriptions now have an INITIATION exception; a one-line note + link to the new page would close the gap (or record in plan.md that no update was needed).[nit]PR title: now an implementation PR — conventional-commit form per the code-quality guidelines, e.g.feat: agent-initiated conversations via messaging platforms (AK-134); and the template's "Changes Made" section is still empty.
CI is fully green (lint, CodeQL, unit tests, all e2e including the new slack-initiation job — note that job cannot exercise the DM reply path, which is why the blocker got past it).
| response = await client.chat_postMessage(channel=channel, text=message) | ||
| # DM replies arrive as top-level messages keyed by the DM channel id; | ||
| # channel replies arrive threaded under the posted message's ts. | ||
| return channel if channel != target else response["ts"] |
There was a problem hiding this comment.
[blocker] The DM path never resolves replies — binding the DM channel id can't match what the inbound handler resolves, so the example's headline scenario ("When Monroe replies to the DM, the reply resolves … to the initiated session") silently fails into a context-less session.
slack_chat.pyderives the inbound key asthread_ts = body.get("thread_ts") or body["ts"]and callsresolve_session_id(thread_ts)— the channel id is never passed to resolution.- So after binding
D999: a top-level DM reply resolves its own ts (miss), and a thread-reply resolves the bot message's ts (also a miss — the mapping key is the channel id). No DM reply style ever hits the mapping. - This violates the round-trip rule this PR itself adds to
ak-dev-new-messaging-integration/SKILL.md: "The returned id MUST equal the id your inbound webhook derives from a reply (before resolution)". - The channel case (
target=C…) is correct: bindresponse["ts"], thread-replies resolve it. Only DMs are broken. - Suggested fix (core, preferred): in
slack_chat.handle(), whenbody.get("channel_type") == "im"and thethread_tsresolution came back unchanged, also tryself.resolve_session_id(channel)— then the DM-channel binding works for every reply style, and DM continuity holds. Alternative (example-only): returnresponse["ts"]for DMs too and document that recipients must reply in-thread — fragile, since the natural DM reply is top-level. - Whichever way: update
server_test.py:125(it currently asserts the wrong assumption,thread_id == "D999" # DM replies arrive keyed by the DM channel id) and add a test that exercises the inbound DM-reply resolution — the current suite only covers the outbound half, which is how this slipped past a green CI.
Description
The design for initiation of a conversation from agent, implementation and an api example
Type of Change
Related Issues
Fixes #
Relates to #
Changes Made
Testing
Checklist
Screenshots (if applicable)
Additional Notes