feat: bot-per-persona β each persona as its own Telegram bot (#29)#39
Open
mattmezza wants to merge 6 commits into
Open
feat: bot-per-persona β each persona as its own Telegram bot (#29)#39mattmezza wants to merge 6 commits into
mattmezza wants to merge 6 commits into
Conversation
d9f1c92 to
da0a145
Compare
Persona gains optional Telegram identity fields: bot_token (its own bot) and allowed_user_ids (per-bot ACL; empty inherits the global list). Schema migration adds the columns to existing personae DBs. Round-trips through markdown frontmatter and the store.
) Adds rung 0 to _resolve_persona: a "telegram:<persona>" channel binds straight to that persona β the bot that received the message is the persona. TelegramChannel now carries a channel_name (default "telegram") that it reports to the agent on every inbound message and topic bind, so history, persona resolution and approval routing all silo per bot.
β¦nds (#29) main: after the default bot, instantiate one TelegramChannel per persona that carries a bot_token, registered as channel "telegram:<persona>" and polled in-process; shutdown now stops every telegram bot. scheduler: _get_owner_chat_id resolves the owner for telegram:<persona> jobs from the bot's own allowlist (global fallback). Bare "telegram" unchanged.
Persona editor gains an "Own Telegram bot" card (token + allowed user IDs); PersonaUpsertIn carries the fields and the upsert parses the ACL into ints. Round-trips through both guided and raw markdown modes.
personae.mdx: new Bot-per-persona section, rung 0 in the resolution ladder, roadmap repointed to group multi-agent (#30). channels.mdx: per-persona bot note under Telegram. README: persona feature line.
β¦t tokens Adversarial review fixes: - main: one bad/duplicate persona token no longer aborts startup β each bot starts independently; tokens are deduped; partial-failure tears down already -started bots so none are left orphaned polling. Shutdown stops every bot independently (one failure can't strand the rest). - scheduler/agent: a telegram:<persona> job is generated AS that persona via a new process(persona_name=β¦) override, keeping the 'system' execution mode (auto-approved writes, no memory/reflection) β fixes jobs being written in the default identity. - admin: persona bot_token is redacted on read (like the global token) and not leaked via the raw markdown view. - telegram: persona bots skip topic auto-bind (rung 0 ignores it) and the global browser-status mirror (no cross-bot progress spam).
da0a145 to
a599f90
Compare
Owner
Author
|
The real test: two Telegram bots (the only true end-to-end)
|
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.
Closes #29.
Run each persona as its own Telegram bot β its own contact in your address book. The persona that handles a message is determined by which bot received it.
Design β one composite channel name
A persona-bot registers as
agent.channels["telegram:<persona>"]; the default bot stays baretelegram. Inbound passeschannel="telegram:<persona>"toprocess(). That one convention does three jobs at once:chat_id == user_idfor every bot, so the composite name is what stops two bots' DMs with the same user from sharing a(channel, user, chat)key.agent.channels["telegram:<persona>"].send(...), schedulerjob.channel="telegram:<persona>", and approvals reply via the bot that fired them (the channel string is threaded fromprocess()straight to_await_approvalβself.channels.get(channel)).telegram:<name>β persona<name>with no lookup (new top rung of the_resolve_personaladder from Per-chat persona binding + isolated contexts (channel-agnostic)Β #14).What changed
bot_token(+ optionalallowed_user_ids, else inherit the global list). Empty token β not a bot, reachable only via the default bot. Stored on thepersonaetable (new columns + migration for existing DBs); round-trips through markdown frontmatter and the admin editor.main.pyβ same process, N bots: the default bot plus oneTelegramChannelper persona that carries a token, each polled in-process. One bad/revoked/duplicate token can't take down the others (or WhatsApp/the scheduler); partial bring-up failure tears down already-started bots so none are left orphaned._resolve_personaβ top rung parsestelegram:<name>; falls through to the existing ladder for unknown names.channelacceptstelegram:<persona>(back-compat: baretelegram= default bot, no migration). A persona job is generated as that persona while keeping thesystemexecution mode (auto-approved writes, no memory/reflection).personae.mdx(new Bot-per-persona section, rung 0, roadmap repointed to Group multi-agent rooms β turn-taking + loop guardΒ #30),channels.mdx, README.Out of scope (per the issue)
Group multi-agent / turn-taking (#30); per-bot config beyond token + allowed-users.
Quality
Built understanding-first, then implemented, then ran two multi-agent adversarial review passes:
All 418 tests green,
ruffclean. New tests cover composite-channel resolution, persona-bot field persistence + token redaction, and persona-correct scheduled delivery.