feat(interactive-shell): set up Telegram from a pasted token via a gated action tool (#3933)#4071
Conversation
Greptile code reviewThis repo uses Greptile for automated review. Before merge, aim for Confidence Score: 5/5 with zero unresolved review threads — see CONTRIBUTING.md. Run a review — add a PR comment with: Give it ~5-10 minutes (sometimes longer) for results, then fix feedback and re-trigger until you reach Confidence Score: 5/5. Optional: automate with the greploop skill. |
Greptile SummaryThis PR adds a
Confidence Score: 4/5The credential-write path runs unconditionally; the execution gate the PR description promises is not present in the code. The llm_provider tool calls allow_tool and execution_allowed before mutating state; configure_telegram calls neither and writes to the integration store unconditionally. Under the current alpha policy this makes no user-visible difference, but execution_policy.py documents that guardrail re-introduction should hook through exactly this mechanism, so the tool won't be controllable without another code change when that happens. The rest of the change is correct and well-tested. tools/interactive_shell/actions/configure_telegram.py — the upsert_integration call at line 59 is not preceded by any execution-gate check. Important Files Changed
Sequence Diagram%%{init: {'theme': 'neutral'}}%%
sequenceDiagram
participant User
participant ActionAgent as Action Agent (LLM)
participant Tool as configure_telegram tool
participant TelegramAPI as Telegram Bot API
participant Store as integrations.store
User->>ActionAgent: Pastes bot token + set up Telegram
ActionAgent->>Tool: call configure_telegram(bot_token, chat_id?)
Tool->>Tool: strip / blank-check token
alt missing token
Tool-->>ActionAgent: ok false, error missing_bot_token
else token present
Tool->>TelegramAPI: GET /bot_token/getMe
alt invalid / revoked token
TelegramAPI-->>Tool: 4xx or ok false
Tool->>Tool: redact token from detail string
Tool-->>ActionAgent: ok false, error redacted detail
else valid token
TelegramAPI-->>Tool: ok true, result username
Tool->>Store: upsert_integration telegram credentials
Store-->>Tool: saved
Tool-->>ActionAgent: ok true, detail Connected to bot, chat_id_set bool
end
end
ActionAgent-->>User: reports outcome no token echoed
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
sequenceDiagram
participant User
participant ActionAgent as Action Agent (LLM)
participant Tool as configure_telegram tool
participant TelegramAPI as Telegram Bot API
participant Store as integrations.store
User->>ActionAgent: Pastes bot token + set up Telegram
ActionAgent->>Tool: call configure_telegram(bot_token, chat_id?)
Tool->>Tool: strip / blank-check token
alt missing token
Tool-->>ActionAgent: ok false, error missing_bot_token
else token present
Tool->>TelegramAPI: GET /bot_token/getMe
alt invalid / revoked token
TelegramAPI-->>Tool: 4xx or ok false
Tool->>Tool: redact token from detail string
Tool-->>ActionAgent: ok false, error redacted detail
else valid token
TelegramAPI-->>Tool: ok true, result username
Tool->>Store: upsert_integration telegram credentials
Store-->>Tool: saved
Tool-->>ActionAgent: ok true, detail Connected to bot, chat_id_set bool
end
end
ActionAgent-->>User: reports outcome no token echoed
Reviews (2): Last reviewed commit: "feat(interactive-shell): set up Telegram..." | Re-trigger Greptile |
…ction tool When a user pastes a Telegram bot token in the REPL and asks to set it up, the agent could only launch the interactive `/integrations setup telegram` wizard, which then re-prompts for the token — it couldn't take the token from chat, verify it, and save it. This adds a `configure_telegram` action tool: given a bot token (and optional chat id) the action agent extracted from the message, it validates the token against the Telegram Bot API via the integration-layer verifier and, on success, saves the integration. The token is never echoed — the verifier's failure detail can embed it (via the request URL), so it's redacted before being shown. - Selection is the action agent's job via normal tool-calling; there is no keyword/regex detection of tokens (per tools/interactive_shell/AGENTS.md). - The tool stays UI-agnostic (validate + persist, no surface imports), matching the other action tools after the Tracer-Cloud#4065 runtime-ports refactor. - Registered in registry_index, the TOOL_MODULES manifest, and action_names; classified in the telemetry coverage allowlist; the two tools -> integrations edges are baselined in .importlinter.strict alongside the existing ones. Tests cover missing token, invalid token (verify fails, nothing saved, token redacted on the failure path too), valid token (verify then save without echoing the secret), and optional chat id.
bd6261c to
028f765
Compare
|
@greptile review |
cerencamkiran
left a comment
There was a problem hiding this comment.
The pr description says this action is gated like llm_provider, but I can't see an execution_allowed check before upsert_integration(). Maybe add a test for that too. Good work btw.
|
@cerencamkiran good catch, that line was stale. I dropped the |
Thanks for your response! #4065 was my PR, and it didn't remove the execution gates. It moved the runtime dependency behind ports, but llm_provider still uses execution_allowed. That's why I asked. |
You're right, my bad, I mixed that up. #4065 moved gating behind ports, it |
|
@Davidson3556 nice work, but we need to shape the agent interaction UX better here.. the agent UX should follow a similar patter as of onboarding, like see here https://www.opensre.com/docs/messaging/telegram#step-4-configure-the-integration
IMO we can re-use the CLI commands or the common utility function which calls the CLI commands, thats how we keep it DRY. and we need to abstract similar patterns for all such tool integrations not just telegram. Lets discuss more on this in dicsord first. |
| credentials: dict[str, Any] = {"bot_token": bot_token} | ||
| if chat_id: | ||
| credentials["default_chat_id"] = chat_id | ||
| upsert_integration("telegram", {"credentials": credentials}) |
There was a problem hiding this comment.
This is a mutating credential write, but unlike llm_set_provider there’s no allow_tool / execution_allowed check before upsert_integration(). You mentioned you’d add this via a port — that should land before merge so future guardrails can hook in consistently.
|
|
||
| from integrations.store import upsert_integration | ||
|
|
||
| credentials: dict[str, Any] = {"bot_token": bot_token} |
There was a problem hiding this comment.
upsert_integration replaces the whole Telegram record. If the user only pastes a new token (no chat_id in args), any existing default_chat_id is dropped. Slack setup merges existing credentials for this reason — worth doing the same here via get_integration("telegram").
|
|
||
| # Never echo the token back; the verifier's detail names the bot, not the secret. | ||
| ctx.console.print(f"[green]✓ {escape(detail)} Saved to the integration store.[/]") | ||
| ctx.session.record("configure_telegram", "telegram", ok=True) |
There was a problem hiding this comment.
Onboarding warns when no default chat id is set (Hermes/watchdog/delivery need it). This tool saves token-only setup silently — a warning on success would help avoid “configured but can’t deliver” confusion.
|
Nice work overall |
…he agent Setting up an integration is the same work wherever the values come from — the onboarding wizard prompts for them, the interactive-shell action tool gets them from a message the agent parsed. Only the collection differs, so this extracts everything after it into integrations/setup_flow.py: merge over the stored record, verify, persist, and report the vendor's advisory. It lives in integrations/ so the surfaces/ wizard and the tools/ action tool can share one implementation without either reaching across layers, and validation reuses the existing per-vendor verifier registry — a vendor that can already be verified only needs a SetupSpec to become settable. configure_telegram becomes a thin adapter over it, which fixes two review findings: - Supplying one field no longer discards the rest of the record, so pasting a fresh token keeps an already-configured default_chat_id. - A token-only setup now warns that Hermes, watchdog, and scheduled deliveries need TELEGRAM_DEFAULT_CHAT_ID, instead of saving silently. Secret redaction is now generic (any field marked secret is scrubbed from verifier detail) rather than a Telegram-specific string replace, and required fields are checked before the verifier registry is primed.
…at-module rule The vendor-first layout invariant only permits flat modules under integrations/ for shared cross-cutting infra. setup_flow is exactly that — it sits alongside store/registry/verify and is not a vendor integration.
|
@Davidson3556 telegram fields should be enforced as per comments earlier, its not as I see in chat :/ |
|
I just checked code, chat is optional by default, we should take a look into this, because it wont work without chat ID |
|
@Davidson3556 Im taking a look at this, let me check of the scope here what we can do |
|
Thanks |
|
Hey closing this as per our discussion. |








Fixes #3933
Describe the changes you have made in this PR -
Follow-up to the docs-grounding PR (#4021), addressing muddlebee's point: when a user pastes a Telegram bot token in the REPL and asks to set it up, the agent should just do it.
Before this, the agent could only launch the interactive
/integrations setup telegramwizard, which then re-prompts for the token — so pasting it in chat didn't help. This adds aconfigure_telegramaction tool. Given a bot token (and optional chat id) the action agent pulled out of the message, it validates the token against the Telegram Bot API and, on success, saves the integration. The token is never printed back.How it fits the existing patterns:
tools/interactive_shell/AGENTS.md).surfaces/UI imports, matching the other action tools (sentry_fix,sample_alert) after the refactor(agent): extract runtime ports from action tools #4065 runtime-ports refactor. It is atools -> integrationsdependency only.integrations.telegram.verifier.verify_telegram), so a bad token fails with a reason instead of saving junk. The verifier's failure detail can embed the token (via the request URL), so the token is redacted before it's shown, on success or failure.registry_index.pyfallback descriptors, theTOOL_MODULESmanifest, andaction_names.py. It is also classified in the telemetry coverage allowlist.Demo/Screenshot for feature changes and bug fixes -
Live end-to-end run in the REPL. I pasted a fake bot token and asked the agent to set up Telegram; the action agent picked the new
configure_telegramtool on its own, validated the token against the real Telegram Bot API, and reported the failure with a reason:That is muddlebee's flow — paste token → agent verifies → error + reason — with a real LLM selecting the tool (not the old wizard) and a real Telegram API call. The success path (valid token → saved, token never echoed) is covered by the unit tests, since I don't have a real bot token to put in a public PR.
Verification:
make typecheckclean (1249 files),make lint/make format-checkclean,make test-scope2648 passed / 1 skipped.Code Understanding and AI Usage
Did you use AI assistance (ChatGPT, Claude, Copilot, etc.) to write any part of this code?
If you used AI assistance:
Explain your implementation approach:
I first checked whether this already worked, both by driving the live REPL (it just relaunched the wizard) and by reading the code (every Telegram setup path was
questionary-interactive, and there was no action tool for integration setup). The tool validates before it persists — using the integration-layer verifierintegrations.telegram.verifier.verify_telegram— so a bad token fails with a reason instead of saving junk, and the token is redacted from the verifier's detail so it's never printed. The tool stays UI-agnostic (nosurfacesimports), matching the other action tools likesentry_fixafter the #4065 runtime-ports refactor, rather than reaching into surfaces for a confirmation gate. The main non-obvious work was registration: the registry has a static descriptor index plus a module manifest, and there are contract tests that fail loudly if a new tool is missing from either — I hit two of them and wired the tool into all the required places. I kept the tool Telegram-specific rather than a generic "configure integration" tool, since Telegram is the reference case and each integration has a different credential shape; generalizing can come later.Checklist before requesting a review