feat: draft → approve → file interaction, thread context, robustness - #46
Merged
Conversation
Interaction model (was: agent filed issues while drafting): - The LLM now only drafts: create_github_issue tool removed, sole tool is the terminal submit_prd. Filing is deterministic code (fileIssues) - LLM proposes, code disposes. - Approval gate: the bot posts the PRD draft, seeds its own checkmark reaction, and files only when a human adds a checkmark to the latest draft. Stale (superseded) drafts are rejected with a note. - DRY_RUN stays a global override on top of per-PRD approval: approved drafts produce would-be payloads only. - Partial filing failures are caught per story and reported as 'filed X of N' with per-story error messages. Thread context: - Follow-ups in a thread (or DM) fetch conversation history and pass it into the run, so 'make the non-goals stricter' revises the pending draft instead of starting over. Pending drafts are tracked in memory (lost on restart, documented). Robustness: - Agent runs abort after AGENT_TIMEOUT_MS (default 180s). - Slack replies truncated defensively at ~3900 chars. - Slack event ids deduped (FIFO, cap 1000). - Runs serialized per conversation via a promise-chain queue. - Placeholder ts is checked before chat.update. Config/logging: - PROVIDER=openai|anthropic|google with per-provider API key env and model defaults (gpt-4o-mini / claude-sonnet-4-6 / gemini-2.5-flash, verified against the installed catalogs). - One structured JSON log line per completed run (outcome drafted|filed|failed, durationMs, storyCount, dryRun). Docs: README rewritten for the new flow; AGENTS.md added with pi conventions, dry-run discipline, and the no-subsystem-without- producer-and-consumer rule.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Reworks the bot's interaction model and hardens the runtime, per the approved improvement list. Nothing is filed by the LLM anymore; filing requires an explicit human ✅ and (for real issues)
DRY_RUN=false.A. Interaction model: draft → approve → file
create_github_issuetool is gone; the agent's only tool is the terminalsubmit_prd. NewfileIssues(prd, github, dryRun)loopsprd.userStoriesand files one issue per story (title = story title, body = description + acceptance-criteria checklist). LLM proposes, code disposes.reaction_added. A human ✅ on the latest draft triggers filing; the bot's own reaction and bot users are ignored.DRY_RUN=true(default) the approval flow works end-to-end but only posts would-be payloads.B. Thread context
conversations.replies;conversations.historyfor flat DMs), bot messages marked as assistant context, and pass it intorunPrdAgent(idea, deps, history?)— so "make the non-goals stricter" revises the pending draft.C. Robustness
agent.abort()afterAGENT_TIMEOUT_MS(default 180000), surfaced as a "timed out" reply. Deviation: pi-agent-core 0.82.0'sprompt()has nomaxTurnsoption (checkeddist/agent.d.ts—prompt(input, images?)only), so no turn cap; timeout only.event_ids (cap 1000); duplicates dropped silently.tsis now checked beforechat.update(the oldts ?? ""wart is gone).D. Config + logging
PROVIDER=openai(default) |anthropic|google→ pi-ai'sopenaiProvider/anthropicProvider/googleProvider(export names verified in dist). API key env per provider (OPENAI_API_KEY/ANTHROPIC_API_KEY/GEMINI_API_KEY); model defaultsgpt-4o-mini/claude-sonnet-4-6/gemini-2.5-flash— all three verified to resolve non-undefined viamodels.getModel()at runtime.console.logper completed run: ts, conversation, durationMs, storyCount, dryRun, outcome (drafted|filed|failed), error.E. Docs
DRY_RUN=false), and the no-subsystem-without-producer-and-consumer rule.reactions:read,reactions:write) +reaction_addedevent subscription the approval flow needs.Test plan
bun test— 47 pass / 0 fail, no network or keys: filing loop incl. partial failure and dry-run, history prepend into the outgoing prompt, run timeout via abort, truncation, dedup incl. FIFO eviction, queue serialization + post-failure recovery, draft store supersede/stale semantics, provider config + model defaults + timeout parsing.bunx tsc --noEmit,bunx biome ci ., andbun install --frozen-lockfileall clean.src/is 698 lines.Not verified
Live Slack/GitHub E2E still hasn't been run (no workspace/tokens here). First real run should keep
DRY_RUN=trueand exercise draft → ✅ approve → would-be payloads before enabling real filing.