Skip to main content

agentmux_srv/messaging/telegram/
types.rs

1// Copyright 2026, AgentMux Corp.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Telegram Bot API wire types (getUpdates / sendMessage / editMessageText).
5//!
6//! `CallbackQuery` is parsed for wire compatibility (it can arrive in the same
7//! `getUpdates` batch as `message` updates) but is not acted on in v1 — inline
8//! keyboards / callback-query handling is explicitly out of scope for this PR
9//! (see spec §2.4, §10 PR 4).
10
11use serde::{Deserialize, Serialize};
12
13// ── Inbound (getUpdates) ────────────────────────────────────────────────────
14
15#[derive(Debug, Deserialize)]
16pub struct Update {
17    pub update_id: i64,
18    #[serde(default)]
19    pub message: Option<Message>,
20    #[serde(default)]
21    #[allow(dead_code)]
22    pub callback_query: Option<CallbackQuery>,
23}
24
25#[derive(Debug, Clone, Deserialize)]
26pub struct Message {
27    #[allow(dead_code)]
28    pub message_id: i64,
29    pub chat: Chat,
30    #[serde(default)]
31    pub from: Option<User>,
32    #[serde(default)]
33    pub text: Option<String>,
34    #[serde(default)]
35    #[allow(dead_code)]
36    pub date: i64,
37}
38
39#[derive(Debug, Clone, Deserialize)]
40pub struct Chat {
41    pub id: i64,
42    #[serde(rename = "type")]
43    #[allow(dead_code)]
44    pub type_: String,
45}
46
47#[derive(Debug, Clone, Deserialize)]
48pub struct User {
49    #[allow(dead_code)]
50    pub id: i64,
51    #[serde(default)]
52    pub username: Option<String>,
53    #[serde(default)]
54    pub is_bot: bool,
55}
56
57/// Inbound callback-query update (button tap). Not processed in v1 — see
58/// module doc comment.
59#[derive(Debug, Deserialize)]
60#[allow(dead_code)]
61pub struct CallbackQuery {
62    pub id: String,
63    pub from: User,
64    #[serde(default)]
65    pub data: Option<String>,
66    #[serde(default)]
67    pub message: Option<Message>,
68}
69
70// ── Bot API response envelope ───────────────────────────────────────────────
71
72#[derive(Debug, Deserialize)]
73// Explicit deserialize bound: without this, serde-derive's naive bound
74// inference for the `#[serde(default)]` field below adds `T: Default` even
75// though the field type is `Option<T>` (whose `Default` never needs `T:
76// Default`) — a known serde-derive quirk. Override to the bound we actually need.
77#[serde(bound(deserialize = "T: Deserialize<'de>"))]
78pub struct TelegramResponse<T> {
79    pub ok: bool,
80    #[serde(default)]
81    pub result: Option<T>,
82    #[serde(default)]
83    #[allow(dead_code)]
84    pub error_code: Option<i64>,
85    #[serde(default)]
86    pub description: Option<String>,
87    #[serde(default)]
88    pub parameters: Option<ResponseParameters>,
89}
90
91#[derive(Debug, Deserialize)]
92pub struct ResponseParameters {
93    /// Present on 429 responses: seconds to wait before retrying.
94    #[serde(default)]
95    pub retry_after: Option<u64>,
96    /// Bot API 7.8+: `"chat"` or `"user"` scope for a 429. Absent on older
97    /// responses / globally-scoped limits — treat missing as global scope.
98    #[serde(default)]
99    pub scope: Option<String>,
100}
101
102// ── Outbound (sendMessage / editMessageText) ────────────────────────────────
103
104#[derive(Debug, Serialize)]
105pub struct SendMessageBody {
106    pub chat_id: i64,
107    pub text: String,
108    pub parse_mode: &'static str,
109}
110
111#[derive(Debug, Serialize)]
112pub struct EditMessageTextBody {
113    pub chat_id: i64,
114    pub message_id: i64,
115    pub text: String,
116    pub parse_mode: &'static str,
117}