Skip to content

feat: unify Slack + Telegram into dual-transport agents (inbox-buddy, hn-monitor, joke-bot, spotify-releases)#91

Merged
khaliqgant merged 2 commits into
mainfrom
unify-inbox-buddy
Jun 24, 2026
Merged

feat: unify Slack + Telegram into dual-transport agents (inbox-buddy, hn-monitor, joke-bot, spotify-releases)#91
khaliqgant merged 2 commits into
mainfrom
unify-inbox-buddy

Conversation

@khaliqgant

@khaliqgant khaliqgant commented Jun 24, 2026

Copy link
Copy Markdown
Member

What

Completes the dual-transport unification across the personal-use agents (piloted on hn-monitor in #88/#89). Each agent that had a separate *-telegram sibling is now one agent that runs over Slack, Telegram, or both — gated by the new workforce#252 optional integrations feature.

agent before after
inbox-buddy inbox-buddy + inbox-buddy-telegram unified, dispatch by event type, reply-on-origin
joke-bot joke-bot + joke-bot-telegram unified; Slack @mention / relay DM / Telegram message + cron fan-out
spotify-releases spotify-releases + spotify-releases-telegram unified; cron delivers to each configured transport
hn-monitor already unified, both providers always connected migrated to enabledByInput gating

workforce#252 optional integrations (the enabling mechanism)

  • Each transport integration is optional: true + enabledByInput: '<INPUT>'. The provider connection + trigger register only when that input is non-empty, so a single-transport deploy never wires up the other provider.
  • Gates: inbox-buddy/joke-bot slack→SLACK_CHANNEL, telegram→TELEGRAM_CHAT; spotify slack→SLACK_USER, telegram→TELEGRAM_CHAT.
  • These fields landed in persona-kit 4.1.12 (4.1.3 silently drops them) → bumped @agentworkforce/persona-kit + agentworkforce CLI to ^4.1.12.

Behavior notes

  • inbox-buddy / joke-bot dispatch by event.type and reply on the origin transport (a Slack question is answered in Slack, never mirrored). joke-bot keeps its Slack-only capabilities.conversational routing + relay-inbox path; its daily "joke of the day" fans out to every configured transport.
  • spotify-releases adopts the Telegram sibling's robust checkpoint (notified-set dedup, per-transport delivery confirmation, advance only on full success); memory tags unified to spotify-releases:{last-check,notified}.
  • Gate-on-id semantics: providing the channel/chat/user id both enables and restricts that transport. At least one must be set.

Tests

  • Repointed the Telegram tests at the unified agents; added dual-transport dispatch / trigger-registration / optional-integration invariants, joke-bot Slack-mention + wrong-channel fail-closed + cron fan-out-to-both, and spotify Slack-DM coverage.
  • Full suite 166/166 green; tsc --noEmit clean; all four personas compile via the CLI with the gating fields emitted.
  • Deleted inbox-buddy-telegram/, joke-bot-telegram/, spotify-releases-telegram/.

Follow-up (separate repo)

The creating-cloud-persona skill (in the skills repo) documents PersonaIntegrationConfig but not optional/enabledByInput or the dual-transport pattern — being updated separately.

🤖 Generated with Claude Code

Collapses inbox-buddy + inbox-buddy-telegram into a single agent that chats
over Slack, Telegram, or both. One persona declares both transports; the
handler registers both webhook triggers (slack.app_mention + telegram.message),
dispatches by event type, and always replies on the ORIGIN transport (a Slack
question is answered in Slack, never mirrored). The Gmail data path + model call
are transport-agnostic and shared via a single composeAnswer core.

Uses the new workforce#252 optional-integration gating: slack/telegram are each
`optional: true` + `enabledByInput` (SLACK_CHANNEL / TELEGRAM_CHAT), so a
single-transport deploy never connects the other provider. These fields landed
in persona-kit 4.1.12 (4.1.3 silently drops them), so bump persona-kit + the
agentworkforce CLI to ^4.1.12.

Also migrate hn-monitor to the same enabledByInput gating (it previously declared
both integrations unconditionally with only its inputs optional, so it still
connected both providers).

- Delete inbox-buddy-telegram/ (superseded)
- Tests: dual-transport dispatch + trigger registration + optional-integration
  invariants; repoint the Telegram inbox tests at the unified agent
- Full suite 162/162 green

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@gemini-code-assist

Copy link
Copy Markdown

Warning

You have reached your daily quota limit. Please wait up to 24 hours and I will start processing your requests again!

@coderabbitai

coderabbitai Bot commented Jun 24, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@khaliqgant, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 55 minutes. Learn how PR review limits work.

Your organization has used up its prepaid credits, and credit purchases are no longer available. Enable the review add-on in the billing tab to keep reviews running — you're only billed for reviews past your plan's rate limits ($0.25/file).

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: 692ad5c4-2468-46c5-be75-ce0231d80132

📥 Commits

Reviewing files that changed from the base of the PR and between c9b7634 and 09cb0a0.

⛔ Files ignored due to path filters (10)
  • inbox-buddy-telegram/avatar.png is excluded by !**/*.png
  • inbox-buddy-telegram/banner.png is excluded by !**/*.png
  • inbox-buddy-telegram/card.png is excluded by !**/*.png
  • joke-bot-telegram/avatar.png is excluded by !**/*.png
  • joke-bot-telegram/banner.png is excluded by !**/*.png
  • joke-bot-telegram/card.png is excluded by !**/*.png
  • package-lock.json is excluded by !**/package-lock.json
  • spotify-releases-telegram/avatar.png is excluded by !**/*.png
  • spotify-releases-telegram/banner.png is excluded by !**/*.png
  • spotify-releases-telegram/card.png is excluded by !**/*.png
📒 Files selected for processing (22)
  • hn-monitor/persona.ts
  • inbox-buddy-telegram/README.md
  • inbox-buddy-telegram/agent.ts
  • inbox-buddy-telegram/persona.ts
  • inbox-buddy/README.md
  • inbox-buddy/agent.ts
  • inbox-buddy/persona.ts
  • joke-bot-telegram/README.md
  • joke-bot-telegram/agent.ts
  • joke-bot-telegram/persona.ts
  • joke-bot/README.md
  • joke-bot/agent.ts
  • joke-bot/persona.ts
  • package.json
  • spotify-releases-telegram/README.md
  • spotify-releases-telegram/agent.ts
  • spotify-releases-telegram/persona.ts
  • spotify-releases/README.md
  • spotify-releases/agent.ts
  • spotify-releases/persona.ts
  • tests/inbox-buddy.test.mjs
  • tests/telegram-agents.test.mjs
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch unify-inbox-buddy

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

…nsport agents

Completes the dual-transport rollout begun with inbox-buddy + hn-monitor.

joke-bot: one agent over Slack and/or Telegram. Dispatches by event type across
four paths — Slack @mention, relay-inbox DM, Telegram message, and a daily cron
"joke of the day" that fans out to EVERY configured transport. Replies on the
origin transport; keeps the Slack-only capabilities.conversational routing.

spotify-releases: cron-only, delivers the release digest to each configured
transport (Slack DM to SLACK_USER and/or Telegram message to TELEGRAM_CHAT).
Adopts the robust checkpoint from the Telegram sibling (notified-set dedup,
per-transport delivery confirmation, advance only on full success) and unifies
the memory tags to spotify-releases:{last-check,notified}.

Both use workforce#252 optional-integration gating (slack/telegram each optional
+ enabledByInput on their id input), so a single-transport deploy never connects
the other provider. joke-bot gates slack→SLACK_CHANNEL, telegram→TELEGRAM_CHAT;
spotify gates slack→SLACK_USER, telegram→TELEGRAM_CHAT.

- Delete joke-bot-telegram/ and spotify-releases-telegram/ (superseded)
- Tests: repoint Telegram tests at the unified agents; add Slack-side coverage
  (joke-bot @mention reply + wrong-channel fail-closed + cron fan-out to both;
  spotify Slack DM). Full suite 166/166 green.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
@khaliqgant khaliqgant changed the title feat: unify Slack + Telegram into dual-transport agents (inbox-buddy + hn-monitor gating) feat: unify Slack + Telegram into dual-transport agents (inbox-buddy, hn-monitor, joke-bot, spotify-releases) Jun 24, 2026
@agent-relay-code

Copy link
Copy Markdown
Contributor

Review of PR #91feat(inbox-buddy): unify Slack + Telegram into one dual-transport agent

What this PR does

Mirrors the already-merged hn-monitor unify (#88/#89): collapses the separate inbox-buddy-telegram agent into the main inbox-buddy as a single dual-transport agent.

  • Deletes inbox-buddy-telegram/ (README, agent.ts, persona.ts, 3 PNGs).
  • inbox-buddy/agent.ts gains a telegram.message trigger + handleTelegramMessage, dispatching by event type with a shared transport-agnostic composeAnswer core; always replies on the origin transport.
  • inbox-buddy/persona.ts makes slack/telegram integrations optional: true + enabledByInput (workforce#252 opt-in gating); google-mail stays required.
  • hn-monitor/persona.ts gets the same optional/enabledByInput gating (consistent with its already-unified handler; both inputs declared).
  • package.json bumps persona-kit and agentworkforce to ^4.1.12 (required for the new persona fields); README updated; tests updated to the unified import path.

Verification (ran the canonical CI command end-to-end)

  • tsc --noEmit (typecheck): clean.
  • Full npm test (compile ALL TypeScript → node --test tests/*.test.mjs): 162/162 pass, EXIT 0 in a clean CI-like env.
  • No dangling references to the deleted inbox-buddy-telegram anywhere in the repo.
  • Installed persona-kit@4.1.12 honors optional/enabledByInput via parseIntegrations (asserted by the persona invariant test, which passes).

Note on initial local test failures (not a defect)

My first npm test showed 4 failures. These are sandbox environment leakage, not PR/code problems:

  • SLACK_CHANNEL=C0ALQ06AAUT is exported in this box; input() resolves env-first, so slackSkipReason rejected the tests' C_CHAT channel → handler skipped before complete().
  • WORKFORCE_SANDBOX_ROOT=/home/daytona/workspace is exported; resolveMountRoot prefers it over the tests' RELAYFILE_MOUNT_ROOT, so seed threads weren't found.

Unsetting those (CI does not set them) yields 162/162 green. No code change is warranted — and I deliberately did not modify the gating logic, which is correct fail-safe behavior.

Housekeeping

npm install had incidentally dropped one "extraneous": true line in package-lock.json. That edit is unrelated to the PR, so I git restored the lockfile. Working tree is clean.

Addressed comments

  • No bot or human review comments were present in the provided PR context (.workforce/context.json contains only PR metadata; per instructions I did not use the gh CLI). Nothing to reconcile.

Advisory Notes

  • None. The hn-monitor/persona.ts change is in-scope (it's the same workforce#252 opt-in integration pattern this PR establishes, on an agent already unified for dual transport, with both referenced inputs declared), so it does not warrant scoping out.

No files were changed by this review. The PR builds, typechecks, and passes its full test suite cleanly; deletions leave no dangling references.

I am not printing READY: I cannot observe live CI status or GitHub mergeability from this sandbox (those are post-harness, cloud-reported actions), so I cannot assert that every required check has completed and the PR is conflict-free — which READY requires.

@agent-relay-code

Copy link
Copy Markdown
Contributor

Review: PR #91 — unify Slack + Telegram into dual-transport agents

Summary

This PR collapses three *-telegram sibling agents (inbox-buddy-telegram, joke-bot-telegram, spotify-releases-telegram) into their primary agents, making inbox-buddy, joke-bot, and spotify-releases dual-transport (Slack and/or Telegram), gated per-transport via the new persona-kit optional + enabledByInput fields (workforce#252). hn-monitor/persona.ts is migrated to the same gating pattern. Deletes the three telegram dirs (code + PNGs), bumps @agentworkforce/persona-kit and agentworkforce to ^4.1.12, and regenerates package-lock.json.

I made no file edits — nothing met the "mechanical, non-semantic" bar, and the remaining items are intentional design changes for a human to confirm. The working tree is clean.

Verification

  • npm ci — clean (lockfile consistent with package.json).
  • npm run typecheck (tsc --noEmit) — passes. Confirms the new persona fields and the refactored interfaces (composeAnswer, SlackChat, SlackDM, dual-transport dispatch) all compile against persona-kit 4.1.12.
  • npm test (the canonical command) — all 166 tests pass in a clean environment.
  • No stale references to deleted dirs (*-telegram) or the old spotify:last-check memory tag anywhere in the repo. ../shared/telegram.ts exists and exports every symbol the unified agents now import.

CI-status caveat (important for the human)

In this sandbox 5 tests fail, but only because the sandbox exports SLACK_CHANNEL, WORKFORCE_SANDBOX_ROOT, and RELAYFILE_*, which the agents' input()/resolveMountRoot() read with higher precedence than the test-injected values — so the tests see the sandbox's env instead of their fixtures. Re-running with those vars unset yields 166/166 pass. This is an environment artifact, not a PR defect; a clean CI runner (no such vars) is green. I could not confirm GitHub's actual check status from the provided metadata.

Addressed comments

  • No bot or human review comments were present. .workforce/ contains only pr.diff, changed-files.txt, and context.json (metadata only); context.json carries no review threads. Nothing to reconcile.

Findings (left as comments, not auto-applied — semantic)

  • joke-bot / spotify-releases: Slack receipt check changed from throw to warn. Old code did if (!result?.ts) throw new Error('Slack reply returned no receipt ts'); new code logs a warning and proceeds (joke-bot/agent.ts slack/relay paths, spotify-releases uses ok: Boolean(res?.ts)). This softens a fail-loud path. It is consistent with the documented "cloud writeback can outrun the wait" rationale and matches the Telegram transport's existing tolerance, and it's the author's deliberate design — but it is a real error-handling semantic change, so flagging for human sign-off rather than editing. Note spotify-releases compensates correctly: a no-receipt send leaves delivered=false, so the checkpoint does not advance and releases re-notify next tick (covered by the "does not checkpoint after a no-receipt send" test).

Advisory Notes

  • One-time re-notify on first deploy (spotify-releases). The memory tag was renamed spotify:last-checkspotify-releases:last-check (and a new spotify-releases:notified set added). On the first tick after deploy, loadLastCheck returns the 0000-00-00 default, and with the > since>= since change the agent will treat recent releases as new. The new notified set prevents duplicate sends within/after that run, but the first post-migration digest may be larger than usual. Intentional namespacing; no action needed, just be aware.
  • recall().reverse() in joke-bot correctly flips the mock/real newest-first recall into the oldest-first order buildPrompt documents; the "replays memory oldest-first" test guards it. Looks right.

No merge-blocking issues found in the code itself, but I cannot confirm from here that all required GitHub checks have completed and are green, nor that GitHub reports the PR mergeable. Because that gate is unverified, I am not printing READY.

@khaliqgant khaliqgant merged commit fccd5b8 into main Jun 24, 2026
2 checks passed
@khaliqgant khaliqgant deleted the unify-inbox-buddy branch June 24, 2026 17:21
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