Skip to content

Slack agent: GitHub read-only sub-agent, streaming robustness, native DM streaming - #125

Merged
amrit110 merged 3 commits into
mainfrom
slack-github-subagent
Aug 1, 2026
Merged

Slack agent: GitHub read-only sub-agent, streaming robustness, native DM streaming#125
amrit110 merged 3 commits into
mainfrom
slack-github-subagent

Conversation

@amrit110

@amrit110 amrit110 commented Aug 1, 2026

Copy link
Copy Markdown
Member

Summary

  • GitHub sub-agent (read-only): new 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_TOKEN PAT fallback; the deploy passes ORG_ACCESS_TOKEN as GITHUB_TOKEN for now).
  • Shared tool loop: the Anthropic streaming loop moved from the BookStack agent into agents/toolloop.py; BookStack and GitHub agents are thin subclasses.
  • Real orchestrator routing: sticky per-thread sessions plus keyword scoring over sub-agent hints, BookStack as fallback; active agent persists in session snapshots.
  • Streaming fix (production bug): Slack ends long-lived native streams server-side (streaming_mode_mismatch on the next append), which killed a long BookStack run with "unexpected internal error". StreamingReply now demotes dead streams to the edit-in-place engine mid-run, in flush, finalize, and fail, so the answer still arrives.
  • Native streaming in DMs: top-level DMs try an inline stream first, threading only if Slack requires it, so DMs get the same UX as channels.

Security posture

All GitHub tools are read in TOOL_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-capable ORG_ACCESS_TOKEN; setting GH_APP_ID / GH_APP_INSTALLATION_ID / GH_APP_PRIVATE_KEY_B64 secrets 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

  • 468 tests pass (pytest), ruff and mypy clean
  • New suites: GitHub App JWT/token flow, org pinning, tool trimming, orchestrator routing, settings resolution, dead-stream demotion and DM stream start regressions
  • Live check: scripts/verify_github_access.py (same code path as the agent) verified against the real org with a PAT

🤖 Generated with Claude Code

amrit110 and others added 3 commits July 31, 2026 21:02
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
amrit110 merged commit 107c919 into main Aug 1, 2026
9 checks passed
@amrit110
amrit110 deleted the slack-github-subagent branch August 1, 2026 01:11
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>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant