Slack agent: GitHub read-only sub-agent, streaming robustness, native DM streaming - #125
Merged
Conversation
Slack ends long-lived native streams server-side; every later append
then fails with streaming_mode_mismatch. This killed a long BookStack
run mid-answer ("unexpected internal error"). StreamingReply now
demotes a dead stream to the edit-in-place engine on a fresh message
(deleting the half-streamed one), in flush, finalize, and fail paths,
so the answer still arrives. Detection is duck-typed on
exc.response["error"] so the module keeps working without slack_sdk.
Top-level DMs now use native streaming too: an inline stream is tried
first, threading off the user's message only if Slack requires it,
without poisoning the process-wide capability flag for channels.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
New slack_agent/agents/github/ package mirroring the BookStack one: nine read-only tools (repos, code search, files, PRs, issues, CI status) declared in TOOL_ACCESS, an httpx client hard-pinned to the VectorInstitute org (owner-qualified inputs cannot escape it), and a sub-agent streaming progress steps with source links. Auth is provider-based: AppInstallationAuth mints short-lived GitHub App installation tokens (RS256 JWT, installation auto-discovery, cached refresh); StaticTokenAuth covers a PAT. The deploy passes ORG_ACCESS_TOKEN as GITHUB_TOKEN for now; App credentials take precedence when their secrets land, making the credential itself read-only with no code change. The Anthropic streaming tool loop moved from the BookStack agent into agents/toolloop.py; both agents are now thin subclasses binding their client, tools, and prompts. The orchestrator gains real routing: sticky per-thread sessions, keyword scoring over sub-agent hints, BookStack as fallback; the active agent persists in session snapshots. scripts/verify_github_access.py exercises the live credential end to end using the same code path as the agent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
amrit110
added a commit
that referenced
this pull request
Aug 1, 2026
… DM streaming (#125) * Streaming: survive server-side stream death, native streaming in DMs Slack ends long-lived native streams server-side; every later append then fails with streaming_mode_mismatch. This killed a long BookStack run mid-answer ("unexpected internal error"). StreamingReply now demotes a dead stream to the edit-in-place engine on a fresh message (deleting the half-streamed one), in flush, finalize, and fail paths, so the answer still arrives. Detection is duck-typed on exc.response["error"] so the module keeps working without slack_sdk. Top-level DMs now use native streaming too: an inline stream is tried first, threading off the user's message only if Slack requires it, without poisoning the process-wide capability flag for channels. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * GitHub read-only sub-agent with org-pinned tools and real routing New slack_agent/agents/github/ package mirroring the BookStack one: nine read-only tools (repos, code search, files, PRs, issues, CI status) declared in TOOL_ACCESS, an httpx client hard-pinned to the VectorInstitute org (owner-qualified inputs cannot escape it), and a sub-agent streaming progress steps with source links. Auth is provider-based: AppInstallationAuth mints short-lived GitHub App installation tokens (RS256 JWT, installation auto-discovery, cached refresh); StaticTokenAuth covers a PAT. The deploy passes ORG_ACCESS_TOKEN as GITHUB_TOKEN for now; App credentials take precedence when their secrets land, making the credential itself read-only with no code change. The Anthropic streaming tool loop moved from the BookStack agent into agents/toolloop.py; both agents are now thin subclasses binding their client, tools, and prompts. The orchestrator gains real routing: sticky per-thread sessions, keyword scoring over sub-agent hints, BookStack as fallback; the active agent persists in session snapshots. scripts/verify_github_access.py exercises the live credential end to end using the same code path as the agent. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> * Assemble the dummy test PEM in pieces to satisfy detect-private-key Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> --------- Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
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
slack_agent/agents/github/package with nine read-only tools (repos, code search, files, PRs, issues, CI status), an httpx client hard-pinned to the VectorInstitute org, and provider-based auth (GitHub App installation tokens preferred,GITHUB_TOKENPAT fallback; the deploy passesORG_ACCESS_TOKENasGITHUB_TOKENfor now).agents/toolloop.py; BookStack and GitHub agents are thin subclasses.streaming_mode_mismatchon the next append), which killed a long BookStack run with "unexpected internal error".StreamingReplynow demotes dead streams to the edit-in-place engine mid-run, inflush,finalize, andfail, so the answer still arrives.Security posture
All GitHub tools are
readinTOOL_ACCESS; the capability manifest is generated from the actual roster, and the client discards owner-qualified repo inputs so lookups cannot leave the org. The interim credential is the write-capableORG_ACCESS_TOKEN; settingGH_APP_ID/GH_APP_INSTALLATION_ID/GH_APP_PRIVATE_KEY_B64secrets switches to short-lived read-only App tokens with no code change. No GitHub write tools should be added while the PAT is the credential.Test plan
pytest), ruff and mypy cleanscripts/verify_github_access.py(same code path as the agent) verified against the real org with a PAT🤖 Generated with Claude Code