Skip to main content

TelegramChannel

Struct TelegramChannel 

pub struct TelegramChannel { /* private fields */ }
Expand description

Telegram channel — long-polls the Bot API for updates

Implementations§

Source§

impl TelegramChannel

Source

pub fn new( bot_token: String, alias: impl Into<String>, peer_resolver: Arc<dyn Fn() -> Vec<String> + Send + Sync>, mention_only: bool, ) -> Self

Source

pub fn with_voice_peer_resolver( self, voice_peer_resolver: Arc<dyn Fn() -> Vec<String> + Send + Sync>, ) -> Self

Set the resolver used to resolve voice-chat peers live (no cached state).

Source

pub fn with_approval_timeout_secs(self, secs: u64) -> Self

Override the approval prompt timeout (default 120s).

Source

pub fn with_ack_reactions(self, enabled: bool) -> Self

Configure whether Telegram-native acknowledgement reactions are sent.

Source

pub fn with_proxy_url(self, proxy_url: Option<String>) -> Self

Set a per-channel proxy URL that overrides the global proxy config.

Source

pub fn with_tool_command_specs(self, specs: Vec<(String, String)>) -> Self

Store pre-computed tool command specs for bot command registration.

Source

pub fn with_workspace_dir(self, dir: PathBuf) -> Self

Configure workspace directory for saving downloaded attachments.

Source

pub fn with_streaming( self, stream_mode: StreamMode, draft_update_interval_ms: u64, ) -> Self

Configure streaming mode for progressive draft updates.

Source

pub fn with_api_base(self, api_base: String) -> Self

Override the Telegram Bot API base URL. Useful for local Bot API servers or testing.

Source

pub fn with_transcription(self, config: TranscriptionConfig) -> Self

Configure voice transcription.

Source

pub fn with_typed_transcription_providers( self, typed: &TranscriptionProviders, agent_alias: &str, ) -> Self

Source

pub fn with_agent_transcription_provider(self, alias: impl Into<String>) -> Self

Set the agent transcription provider alias on the internal TranscriptionManager. Must be called after with_transcription. No-op if transcription was not configured. The alias should be the provider type key (“groq”, “openai”, etc.) registered in the TranscriptionManager, or the full “type.alias” form (the type prefix is extracted).

Source

pub fn with_tts(self, config: &Config) -> Self

Source

pub fn with_persistence(self, config: Arc<RwLock<Config>>) -> Self

write a paired user into peer_groups and save. The long-running daemon sets this from the orchestrator; tests and one-shot callers leave it unset (pairing works at runtime, doesn’t persist).

Source

pub async fn send_document( &self, chat_id: &str, thread_id: Option<&str>, file_path: &Path, caption: Option<&str>, ) -> Result<()>

Send a document/file to a Telegram chat

Source

pub async fn send_document_bytes( &self, chat_id: &str, thread_id: Option<&str>, file_bytes: Vec<u8>, file_name: &str, caption: Option<&str>, ) -> Result<()>

Send a document from bytes (in-memory) to a Telegram chat

Source

pub async fn send_photo( &self, chat_id: &str, thread_id: Option<&str>, file_path: &Path, caption: Option<&str>, ) -> Result<()>

Send a photo to a Telegram chat

Source

pub async fn send_photo_bytes( &self, chat_id: &str, thread_id: Option<&str>, file_bytes: Vec<u8>, file_name: &str, caption: Option<&str>, ) -> Result<()>

Send a photo from bytes (in-memory) to a Telegram chat

Source

pub async fn send_video( &self, chat_id: &str, thread_id: Option<&str>, file_path: &Path, caption: Option<&str>, ) -> Result<()>

Send a video to a Telegram chat

Source

pub async fn send_audio( &self, chat_id: &str, thread_id: Option<&str>, file_path: &Path, caption: Option<&str>, ) -> Result<()>

Send an audio file to a Telegram chat

Source

pub async fn send_voice( &self, chat_id: &str, thread_id: Option<&str>, file_path: &Path, caption: Option<&str>, ) -> Result<()>

Send a voice message to a Telegram chat

Source

pub async fn send_document_by_url( &self, chat_id: &str, thread_id: Option<&str>, url: &str, caption: Option<&str>, ) -> Result<()>

Send a file by URL (Telegram will download it)

Source

pub async fn send_photo_by_url( &self, chat_id: &str, thread_id: Option<&str>, url: &str, caption: Option<&str>, ) -> Result<()>

Send a photo by URL (Telegram will download it)

Source

pub async fn send_video_by_url( &self, chat_id: &str, thread_id: Option<&str>, url: &str, caption: Option<&str>, ) -> Result<()>

Send a video by URL (Telegram will download it)

Source

pub async fn send_audio_by_url( &self, chat_id: &str, thread_id: Option<&str>, url: &str, caption: Option<&str>, ) -> Result<()>

Send an audio file by URL (Telegram will download it)

Source

pub async fn send_voice_by_url( &self, chat_id: &str, thread_id: Option<&str>, url: &str, caption: Option<&str>, ) -> Result<()>

Send a voice message by URL (Telegram will download it)

Trait Implementations§

Source§

impl Attributable for TelegramChannel

Source§

fn role(&self) -> Role

Source§

fn alias(&self) -> &str

Source§

impl Channel for TelegramChannel

Source§

fn self_addressed_mention(&self) -> Option<String>

Telegram users mention the bot as @bot_username in chat. The cached bot_username from getMe is already the bare form; prepend @ to match what arrives in inbound message text.

Source§

fn name(&self) -> &str

Human-readable channel name
Source§

fn self_handle(&self) -> Option<String>

Self-loop guard for multi-agent runs: the bot’s own handle/identity on this channel, so the orchestrator can drop inbound events whose sender matches. A bot must never respond to its own messages, even if a misconfigured peer group lists the bot’s handle as an external peer. Read more
Source§

fn supports_draft_updates(&self) -> bool

Whether this channel supports progressive message updates via draft edits.
Source§

fn send_draft<'life0, 'life1, 'async_trait>( &'life0 self, message: &'life1 SendMessage, ) -> Pin<Box<dyn Future<Output = Result<Option<String>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Send an initial draft message. Returns a platform-specific message ID for later edits.
Source§

fn update_draft<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, recipient: &'life1 str, message_id: &'life2 str, text: &'life3 str, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait,

Update a previously sent draft message with new accumulated content.
Source§

fn finalize_draft<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, recipient: &'life1 str, message_id: &'life2 str, text: &'life3 str, suppress_voice: bool, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait,

Finalize a draft with the complete response (e.g. apply Markdown formatting). suppress_voice forces text delivery even on voice-only peers.
Source§

fn cancel_draft<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, recipient: &'life1 str, message_id: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Cancel and remove a previously sent draft message if the channel supports it.
Source§

fn send<'life0, 'life1, 'async_trait>( &'life0 self, message: &'life1 SendMessage, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Send a message through this channel
Source§

fn listen<'life0, 'async_trait>( &'life0 self, tx: Sender<ChannelMessage>, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Start listening for incoming messages (long-running)
Source§

fn health_check<'life0, 'async_trait>( &'life0 self, ) -> Pin<Box<dyn Future<Output = bool> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait,

Check if channel is healthy
Source§

fn start_typing<'life0, 'life1, 'async_trait>( &'life0 self, recipient: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Signal that the bot is processing a response (e.g. “typing” indicator).
Source§

fn stop_typing<'life0, 'life1, 'async_trait>( &'life0 self, _recipient: &'life1 str, ) -> Pin<Box<dyn Future<Output = Result<()>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait,

Stop any active typing indicator.
Source§

fn request_approval<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, recipient: &'life1 str, request: &'life2 ChannelApprovalRequest, ) -> Pin<Box<dyn Future<Output = Result<Option<ChannelApprovalResponse>>> + Send + 'async_trait>>
where Self: 'async_trait, 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait,

Request interactive tool-call approval from the channel operator. Read more
Source§

fn send_choice<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, recipient: &'life1 str, prompt: &'life2 str, options: &'life3 [(String, String)], ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, Self: 'async_trait,

Send a discrete-choice prompt with options. Read more
Source§

fn supports_outbound_send(&self) -> bool

Whether send actually delivers a message OUTBOUND on this channel. Default true. An INBOUND-ONLY transport (e.g. an AMQP trigger source whose send is a deliberate no-op that returns Ok) overrides this to false, so a surface that must genuinely deliver - such as the SOP approval route adapter - can refuse to route to it (and report the misconfiguration) instead of silently succeeding without sending anything.
Source§

fn drop_self_messages(&self, msg: &ChannelMessage) -> bool

Whether the orchestrator should drop an inbound message as self-authored (multi-agent self-loop guard). Default compares msg.sender against Self::self_handle case-insensitively after stripping a leading @ from each side. Override only for platforms whose identity comparison is non-string.
Source§

fn forge_request<'life0, 'async_trait>( &'life0 self, _request: ForgeApiRequest, ) -> Pin<Box<dyn Future<Output = Result<ForgeApiResponse, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, Self: 'async_trait,

Source§

fn is_direct_message(&self, _msg: &ChannelMessage) -> bool

Whether an inbound message is a direct one-to-one conversation with the bot. A DM is definitionally addressed to the bot, so the orchestrator skips the reply-intent classifier and goes straight to the tool-capable agent turn. Default false: channels that cannot prove a one-to-one context keep the classifier precheck.
Source§

fn supports_multi_message_streaming(&self) -> bool

Whether this channel supports multi-message streaming delivery.
Source§

fn multi_message_delay_ms(&self) -> u64

Minimum delay (ms) between sending each paragraph in multi-message mode.
Source§

fn update_draft_progress<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, _recipient: &'life1 str, _message_id: &'life2 str, _text: &'life3 str, ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, Self: 'async_trait,

Show a progress/status update (e.g. tool execution status).
Source§

fn add_reaction<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, _channel_id: &'life1 str, _message_id: &'life2 str, _emoji: &'life3 str, ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, Self: 'async_trait,

Add a reaction (emoji) to a message.
Source§

fn remove_reaction<'life0, 'life1, 'life2, 'life3, 'async_trait>( &'life0 self, _channel_id: &'life1 str, _message_id: &'life2 str, _emoji: &'life3 str, ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, 'life3: 'async_trait, Self: 'async_trait,

Remove a reaction (emoji) from a message previously added by this bot.
Source§

fn pin_message<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _channel_id: &'life1 str, _message_id: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: 'async_trait,

Pin a message in the channel.
Source§

fn unpin_message<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _channel_id: &'life1 str, _message_id: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: 'async_trait,

Unpin a previously pinned message.
Source§

fn redact_message<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _channel_id: &'life1 str, _message_id: &'life2 str, _reason: Option<String>, ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: 'async_trait,

Redact (delete) a message from the channel.
Source§

fn create_room<'life0, 'life1, 'async_trait>( &'life0 self, _options: &'life1 RoomCreationOptions, ) -> Pin<Box<dyn Future<Output = Result<String, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, Self: 'async_trait,

Create a new platform room/conversation when the channel supports it.
Source§

fn invite_user<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _room_id: &'life1 str, _user_id: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<(), Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: 'async_trait,

Invite a user to an existing platform room/conversation.
Source§

fn request_approval_attributed<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, recipient: &'life1 str, request: &'life2 ChannelApprovalRequest, ) -> Pin<Box<dyn Future<Output = Result<Option<AttributedApprovalResponse>, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: 'async_trait,

Like Channel::request_approval, but also reports which back-channel produced the decision when this channel fans the request out. Default delegates to Channel::request_approval with decided_by: None; only a fan-out bridge needs to override.
Source§

fn send_gate_prompt<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _recipient: &'life1 str, _prompt: &'life2 ChannelGatePrompt, ) -> Pin<Box<dyn Future<Output = Result<bool, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: 'async_trait,

Present a long-lived, out-of-band gate prompt (e.g. a parked SOP approval) on this channel, rendered natively — an embed with one button per choice on Discord, an inline keyboard on Telegram, and so on. Read more
Source§

fn finalize_gate_prompt<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _reference: &'life1 str, _outcome: &'life2 str, ) -> Pin<Box<dyn Future<Output = Result<bool, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: 'async_trait,

Mark a previously sent gate prompt as resolved: strip its interactive controls and replace the body with outcome (e.g. “Approved by @user — run resumed”), so a decided gate cannot be clicked again and the decision is visible in place. reference is the same correlation key the prompt was sent with. Best-effort: Ok(false) when this channel has nothing to finalize (no native prompt, or the mapping was lost to a restart) — the gate state itself is never affected.
Source§

fn request_choice<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _question: &'life1 str, _choices: &'life2 [String], _timeout: Duration, ) -> Pin<Box<dyn Future<Output = Result<Option<String>, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: 'async_trait,

Ask the user a multiple-choice question and return the chosen option’s text. Read more
Source§

fn request_multi_choice<'life0, 'life1, 'life2, 'async_trait>( &'life0 self, _question: &'life1 str, _choices: &'life2 [String], _min_items: usize, _max_items: usize, _timeout: Duration, ) -> Pin<Box<dyn Future<Output = Result<Option<Vec<String>>, Error>> + Send + 'async_trait>>
where 'life0: 'async_trait, 'life1: 'async_trait, 'life2: 'async_trait, Self: 'async_trait,

Source§

fn supports_free_form_ask(&self) -> bool

Whether this channel can answer free-form (no-choices) ask_user questions via the standard send + listen flow. Channels that only handle structured choices return false so callers fail fast with a useful error instead of timing out on listen.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

§

impl<T> Instrument for T

§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided [Span], returning an Instrumented wrapper. Read more
§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
§

impl<T> PolicyExt for T
where T: ?Sized,

§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] only if self and other return Action::Follow. Read more
§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns [Action::Follow] if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V

§

impl<T> WithSubscriber for T

§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a [WithDispatch] wrapper. Read more
§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,