yee88 0.3.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- yee88/__init__.py +1 -0
- yee88/api.py +116 -0
- yee88/backends.py +25 -0
- yee88/backends_helpers.py +14 -0
- yee88/cli/__init__.py +228 -0
- yee88/cli/config.py +320 -0
- yee88/cli/doctor.py +173 -0
- yee88/cli/init.py +113 -0
- yee88/cli/onboarding_cmd.py +126 -0
- yee88/cli/plugins.py +196 -0
- yee88/cli/run.py +419 -0
- yee88/cli/topic.py +355 -0
- yee88/commands.py +134 -0
- yee88/config.py +142 -0
- yee88/config_migrations.py +124 -0
- yee88/config_watch.py +146 -0
- yee88/context.py +9 -0
- yee88/directives.py +146 -0
- yee88/engines.py +53 -0
- yee88/events.py +170 -0
- yee88/ids.py +17 -0
- yee88/lockfile.py +158 -0
- yee88/logging.py +283 -0
- yee88/markdown.py +298 -0
- yee88/model.py +77 -0
- yee88/plugins.py +312 -0
- yee88/presenter.py +25 -0
- yee88/progress.py +99 -0
- yee88/router.py +113 -0
- yee88/runner.py +712 -0
- yee88/runner_bridge.py +619 -0
- yee88/runners/__init__.py +1 -0
- yee88/runners/claude.py +483 -0
- yee88/runners/codex.py +656 -0
- yee88/runners/mock.py +221 -0
- yee88/runners/opencode.py +505 -0
- yee88/runners/pi.py +523 -0
- yee88/runners/run_options.py +39 -0
- yee88/runners/tool_actions.py +90 -0
- yee88/runtime_loader.py +207 -0
- yee88/scheduler.py +159 -0
- yee88/schemas/__init__.py +1 -0
- yee88/schemas/claude.py +238 -0
- yee88/schemas/codex.py +169 -0
- yee88/schemas/opencode.py +51 -0
- yee88/schemas/pi.py +117 -0
- yee88/settings.py +360 -0
- yee88/telegram/__init__.py +20 -0
- yee88/telegram/api_models.py +37 -0
- yee88/telegram/api_schemas.py +152 -0
- yee88/telegram/backend.py +163 -0
- yee88/telegram/bridge.py +425 -0
- yee88/telegram/chat_prefs.py +242 -0
- yee88/telegram/chat_sessions.py +112 -0
- yee88/telegram/client.py +409 -0
- yee88/telegram/client_api.py +539 -0
- yee88/telegram/commands/__init__.py +12 -0
- yee88/telegram/commands/agent.py +196 -0
- yee88/telegram/commands/cancel.py +116 -0
- yee88/telegram/commands/dispatch.py +111 -0
- yee88/telegram/commands/executor.py +449 -0
- yee88/telegram/commands/file_transfer.py +586 -0
- yee88/telegram/commands/handlers.py +45 -0
- yee88/telegram/commands/media.py +143 -0
- yee88/telegram/commands/menu.py +139 -0
- yee88/telegram/commands/model.py +215 -0
- yee88/telegram/commands/overrides.py +159 -0
- yee88/telegram/commands/parse.py +30 -0
- yee88/telegram/commands/plan.py +16 -0
- yee88/telegram/commands/reasoning.py +234 -0
- yee88/telegram/commands/reply.py +23 -0
- yee88/telegram/commands/topics.py +332 -0
- yee88/telegram/commands/trigger.py +143 -0
- yee88/telegram/context.py +140 -0
- yee88/telegram/engine_defaults.py +86 -0
- yee88/telegram/engine_overrides.py +105 -0
- yee88/telegram/files.py +178 -0
- yee88/telegram/loop.py +1822 -0
- yee88/telegram/onboarding.py +1088 -0
- yee88/telegram/outbox.py +177 -0
- yee88/telegram/parsing.py +239 -0
- yee88/telegram/render.py +198 -0
- yee88/telegram/state_store.py +88 -0
- yee88/telegram/topic_state.py +334 -0
- yee88/telegram/topics.py +256 -0
- yee88/telegram/trigger_mode.py +68 -0
- yee88/telegram/types.py +63 -0
- yee88/telegram/voice.py +110 -0
- yee88/transport.py +53 -0
- yee88/transport_runtime.py +323 -0
- yee88/transports.py +76 -0
- yee88/utils/__init__.py +1 -0
- yee88/utils/git.py +87 -0
- yee88/utils/json_state.py +21 -0
- yee88/utils/paths.py +47 -0
- yee88/utils/streams.py +44 -0
- yee88/utils/subprocess.py +86 -0
- yee88/worktrees.py +135 -0
- yee88-0.3.0.dist-info/METADATA +116 -0
- yee88-0.3.0.dist-info/RECORD +103 -0
- yee88-0.3.0.dist-info/WHEEL +4 -0
- yee88-0.3.0.dist-info/entry_points.txt +11 -0
- yee88-0.3.0.dist-info/licenses/LICENSE +21 -0
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from pathlib import Path
|
|
4
|
+
|
|
5
|
+
import msgspec
|
|
6
|
+
|
|
7
|
+
from ..logging import get_logger
|
|
8
|
+
from ..model import ResumeToken
|
|
9
|
+
from .state_store import JsonStateStore
|
|
10
|
+
|
|
11
|
+
logger = get_logger(__name__)
|
|
12
|
+
|
|
13
|
+
STATE_VERSION = 1
|
|
14
|
+
STATE_FILENAME = "telegram_chat_sessions_state.json"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class _SessionState(msgspec.Struct, forbid_unknown_fields=False):
|
|
18
|
+
resume: str
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class _ChatState(msgspec.Struct, forbid_unknown_fields=False):
|
|
22
|
+
sessions: dict[str, _SessionState] = msgspec.field(default_factory=dict)
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
class _ChatSessionsState(msgspec.Struct, forbid_unknown_fields=False):
|
|
26
|
+
version: int
|
|
27
|
+
cwd: str | None = None
|
|
28
|
+
chats: dict[str, _ChatState] = msgspec.field(default_factory=dict)
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def resolve_sessions_path(config_path: Path) -> Path:
|
|
32
|
+
return config_path.with_name(STATE_FILENAME)
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def _chat_key(chat_id: int, owner_id: int | None) -> str:
|
|
36
|
+
owner = "chat" if owner_id is None else str(owner_id)
|
|
37
|
+
return f"{chat_id}:{owner}"
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
def _new_state() -> _ChatSessionsState:
|
|
41
|
+
return _ChatSessionsState(version=STATE_VERSION, chats={})
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class ChatSessionStore(JsonStateStore[_ChatSessionsState]):
|
|
45
|
+
def __init__(self, path: Path) -> None:
|
|
46
|
+
super().__init__(
|
|
47
|
+
path,
|
|
48
|
+
version=STATE_VERSION,
|
|
49
|
+
state_type=_ChatSessionsState,
|
|
50
|
+
state_factory=_new_state,
|
|
51
|
+
log_prefix="telegram.chat_sessions",
|
|
52
|
+
logger=logger,
|
|
53
|
+
)
|
|
54
|
+
|
|
55
|
+
async def get_session_resume(
|
|
56
|
+
self, chat_id: int, owner_id: int | None, engine: str
|
|
57
|
+
) -> ResumeToken | None:
|
|
58
|
+
async with self._lock:
|
|
59
|
+
self._reload_locked_if_needed()
|
|
60
|
+
chat = self._get_chat_locked(chat_id, owner_id)
|
|
61
|
+
if chat is None:
|
|
62
|
+
return None
|
|
63
|
+
entry = chat.sessions.get(engine)
|
|
64
|
+
if entry is None or not entry.resume:
|
|
65
|
+
return None
|
|
66
|
+
return ResumeToken(engine=engine, value=entry.resume)
|
|
67
|
+
|
|
68
|
+
async def sync_startup_cwd(self, cwd: Path) -> bool:
|
|
69
|
+
normalized = str(cwd.expanduser().resolve())
|
|
70
|
+
async with self._lock:
|
|
71
|
+
self._reload_locked_if_needed()
|
|
72
|
+
previous = self._state.cwd
|
|
73
|
+
cleared = False
|
|
74
|
+
if previous is not None and previous != normalized:
|
|
75
|
+
self._state.chats = {}
|
|
76
|
+
cleared = True
|
|
77
|
+
if previous != normalized:
|
|
78
|
+
self._state.cwd = normalized
|
|
79
|
+
self._save_locked()
|
|
80
|
+
return cleared
|
|
81
|
+
|
|
82
|
+
async def set_session_resume(
|
|
83
|
+
self, chat_id: int, owner_id: int | None, token: ResumeToken
|
|
84
|
+
) -> None:
|
|
85
|
+
async with self._lock:
|
|
86
|
+
self._reload_locked_if_needed()
|
|
87
|
+
if self._state.cwd is None:
|
|
88
|
+
self._state.cwd = str(Path.cwd().expanduser().resolve())
|
|
89
|
+
chat = self._ensure_chat_locked(chat_id, owner_id)
|
|
90
|
+
chat.sessions[token.engine] = _SessionState(resume=token.value)
|
|
91
|
+
self._save_locked()
|
|
92
|
+
|
|
93
|
+
async def clear_sessions(self, chat_id: int, owner_id: int | None) -> None:
|
|
94
|
+
async with self._lock:
|
|
95
|
+
self._reload_locked_if_needed()
|
|
96
|
+
chat = self._get_chat_locked(chat_id, owner_id)
|
|
97
|
+
if chat is None:
|
|
98
|
+
return
|
|
99
|
+
chat.sessions = {}
|
|
100
|
+
self._save_locked()
|
|
101
|
+
|
|
102
|
+
def _get_chat_locked(self, chat_id: int, owner_id: int | None) -> _ChatState | None:
|
|
103
|
+
return self._state.chats.get(_chat_key(chat_id, owner_id))
|
|
104
|
+
|
|
105
|
+
def _ensure_chat_locked(self, chat_id: int, owner_id: int | None) -> _ChatState:
|
|
106
|
+
key = _chat_key(chat_id, owner_id)
|
|
107
|
+
entry = self._state.chats.get(key)
|
|
108
|
+
if entry is not None:
|
|
109
|
+
return entry
|
|
110
|
+
entry = _ChatState()
|
|
111
|
+
self._state.chats[key] = entry
|
|
112
|
+
return entry
|
yee88/telegram/client.py
ADDED
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
import itertools
|
|
4
|
+
import time
|
|
5
|
+
from typing import Any
|
|
6
|
+
from collections.abc import Awaitable, Callable, Hashable
|
|
7
|
+
|
|
8
|
+
import anyio
|
|
9
|
+
import httpx
|
|
10
|
+
|
|
11
|
+
from ..logging import get_logger
|
|
12
|
+
from .api_models import Chat, ChatMember, File, ForumTopic, Message, Update, User
|
|
13
|
+
from .client_api import BotClient, HttpBotClient, TelegramRetryAfter
|
|
14
|
+
from .outbox import (
|
|
15
|
+
DELETE_PRIORITY,
|
|
16
|
+
EDIT_PRIORITY,
|
|
17
|
+
SEND_PRIORITY,
|
|
18
|
+
OutboxOp,
|
|
19
|
+
TelegramOutbox,
|
|
20
|
+
)
|
|
21
|
+
from .parsing import parse_incoming_update, poll_incoming
|
|
22
|
+
|
|
23
|
+
logger = get_logger(__name__)
|
|
24
|
+
|
|
25
|
+
__all__ = [
|
|
26
|
+
"BotClient",
|
|
27
|
+
"TelegramClient",
|
|
28
|
+
"TelegramRetryAfter",
|
|
29
|
+
"is_group_chat_id",
|
|
30
|
+
"parse_incoming_update",
|
|
31
|
+
"poll_incoming",
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
|
|
35
|
+
def is_group_chat_id(chat_id: int) -> bool:
|
|
36
|
+
return chat_id < 0
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
class TelegramClient:
|
|
40
|
+
def __init__(
|
|
41
|
+
self,
|
|
42
|
+
token: str | None = None,
|
|
43
|
+
*,
|
|
44
|
+
client: BotClient | None = None,
|
|
45
|
+
timeout_s: float = 120,
|
|
46
|
+
http_client: httpx.AsyncClient | None = None,
|
|
47
|
+
clock: Callable[[], float] = time.monotonic,
|
|
48
|
+
sleep: Callable[[float], Awaitable[None]] = anyio.sleep,
|
|
49
|
+
private_chat_rps: float = 1.0,
|
|
50
|
+
group_chat_rps: float = 20.0 / 60.0,
|
|
51
|
+
) -> None:
|
|
52
|
+
if client is not None:
|
|
53
|
+
if token is not None or http_client is not None:
|
|
54
|
+
raise ValueError("Provide either token or client, not both.")
|
|
55
|
+
self._client = client
|
|
56
|
+
else:
|
|
57
|
+
if token is None or not token:
|
|
58
|
+
raise ValueError("Telegram token is empty")
|
|
59
|
+
self._client = HttpBotClient(
|
|
60
|
+
token,
|
|
61
|
+
timeout_s=timeout_s,
|
|
62
|
+
http_client=http_client,
|
|
63
|
+
)
|
|
64
|
+
self._clock = clock
|
|
65
|
+
self._sleep = sleep
|
|
66
|
+
self._private_interval = (
|
|
67
|
+
0.0 if private_chat_rps <= 0 else 1.0 / private_chat_rps
|
|
68
|
+
)
|
|
69
|
+
self._group_interval = 0.0 if group_chat_rps <= 0 else 1.0 / group_chat_rps
|
|
70
|
+
self._outbox = TelegramOutbox(
|
|
71
|
+
interval_for_chat=self.interval_for_chat,
|
|
72
|
+
clock=clock,
|
|
73
|
+
sleep=sleep,
|
|
74
|
+
on_error=self.log_request_error,
|
|
75
|
+
on_outbox_error=self.log_outbox_failure,
|
|
76
|
+
)
|
|
77
|
+
self._seq = itertools.count()
|
|
78
|
+
|
|
79
|
+
def interval_for_chat(self, chat_id: int | None) -> float:
|
|
80
|
+
if chat_id is None:
|
|
81
|
+
return self._private_interval
|
|
82
|
+
if is_group_chat_id(chat_id):
|
|
83
|
+
return self._group_interval
|
|
84
|
+
return self._private_interval
|
|
85
|
+
|
|
86
|
+
def log_request_error(self, request: OutboxOp, exc: Exception) -> None:
|
|
87
|
+
logger.error(
|
|
88
|
+
"telegram.outbox.request_failed",
|
|
89
|
+
method=request.label,
|
|
90
|
+
error=str(exc),
|
|
91
|
+
error_type=exc.__class__.__name__,
|
|
92
|
+
)
|
|
93
|
+
|
|
94
|
+
def log_outbox_failure(self, exc: Exception) -> None:
|
|
95
|
+
logger.error(
|
|
96
|
+
"telegram.outbox.failed",
|
|
97
|
+
error=str(exc),
|
|
98
|
+
error_type=exc.__class__.__name__,
|
|
99
|
+
)
|
|
100
|
+
|
|
101
|
+
async def drop_pending_edits(self, *, chat_id: int, message_id: int) -> None:
|
|
102
|
+
await self._outbox.drop_pending(key=("edit", chat_id, message_id))
|
|
103
|
+
|
|
104
|
+
def unique_key(self, prefix: str) -> tuple[str, int]:
|
|
105
|
+
return (prefix, next(self._seq))
|
|
106
|
+
|
|
107
|
+
async def enqueue_op(
|
|
108
|
+
self,
|
|
109
|
+
*,
|
|
110
|
+
key: Hashable,
|
|
111
|
+
label: str,
|
|
112
|
+
execute: Callable[[], Awaitable[Any]],
|
|
113
|
+
priority: int,
|
|
114
|
+
chat_id: int | None,
|
|
115
|
+
wait: bool = True,
|
|
116
|
+
) -> Any:
|
|
117
|
+
request = OutboxOp(
|
|
118
|
+
execute=execute,
|
|
119
|
+
priority=priority,
|
|
120
|
+
queued_at=self._clock(),
|
|
121
|
+
chat_id=chat_id,
|
|
122
|
+
label=label,
|
|
123
|
+
)
|
|
124
|
+
return await self._outbox.enqueue(key=key, op=request, wait=wait)
|
|
125
|
+
|
|
126
|
+
async def close(self) -> None:
|
|
127
|
+
await self._outbox.close()
|
|
128
|
+
await self._client.close()
|
|
129
|
+
|
|
130
|
+
async def _call_with_retry_after(
|
|
131
|
+
self,
|
|
132
|
+
fn: Callable[[], Awaitable[Any]],
|
|
133
|
+
) -> Any:
|
|
134
|
+
while True:
|
|
135
|
+
try:
|
|
136
|
+
return await fn()
|
|
137
|
+
except TelegramRetryAfter as exc:
|
|
138
|
+
await self._sleep(exc.retry_after)
|
|
139
|
+
|
|
140
|
+
async def get_updates(
|
|
141
|
+
self,
|
|
142
|
+
offset: int | None,
|
|
143
|
+
timeout_s: int = 50,
|
|
144
|
+
allowed_updates: list[str] | None = None,
|
|
145
|
+
) -> list[Update] | None:
|
|
146
|
+
async def execute() -> list[Update] | None:
|
|
147
|
+
return await self._client.get_updates(
|
|
148
|
+
offset=offset,
|
|
149
|
+
timeout_s=timeout_s,
|
|
150
|
+
allowed_updates=allowed_updates,
|
|
151
|
+
)
|
|
152
|
+
|
|
153
|
+
return await self._call_with_retry_after(execute)
|
|
154
|
+
|
|
155
|
+
async def get_file(self, file_id: str) -> File | None:
|
|
156
|
+
async def execute() -> File | None:
|
|
157
|
+
return await self._client.get_file(file_id)
|
|
158
|
+
|
|
159
|
+
return await self._call_with_retry_after(execute)
|
|
160
|
+
|
|
161
|
+
async def download_file(self, file_path: str) -> bytes | None:
|
|
162
|
+
async def execute() -> bytes | None:
|
|
163
|
+
return await self._client.download_file(file_path)
|
|
164
|
+
|
|
165
|
+
return await self._call_with_retry_after(execute)
|
|
166
|
+
|
|
167
|
+
async def send_message(
|
|
168
|
+
self,
|
|
169
|
+
chat_id: int,
|
|
170
|
+
text: str,
|
|
171
|
+
reply_to_message_id: int | None = None,
|
|
172
|
+
disable_notification: bool | None = False,
|
|
173
|
+
message_thread_id: int | None = None,
|
|
174
|
+
entities: list[dict] | None = None,
|
|
175
|
+
parse_mode: str | None = None,
|
|
176
|
+
reply_markup: dict[str, Any] | None = None,
|
|
177
|
+
*,
|
|
178
|
+
replace_message_id: int | None = None,
|
|
179
|
+
) -> Message | None:
|
|
180
|
+
async def execute() -> Message | None:
|
|
181
|
+
return await self._client.send_message(
|
|
182
|
+
chat_id=chat_id,
|
|
183
|
+
text=text,
|
|
184
|
+
reply_to_message_id=reply_to_message_id,
|
|
185
|
+
disable_notification=disable_notification,
|
|
186
|
+
message_thread_id=message_thread_id,
|
|
187
|
+
entities=entities,
|
|
188
|
+
parse_mode=parse_mode,
|
|
189
|
+
reply_markup=reply_markup,
|
|
190
|
+
replace_message_id=replace_message_id,
|
|
191
|
+
)
|
|
192
|
+
|
|
193
|
+
if replace_message_id is not None:
|
|
194
|
+
await self._outbox.drop_pending(key=("edit", chat_id, replace_message_id))
|
|
195
|
+
result = await self.enqueue_op(
|
|
196
|
+
key=(
|
|
197
|
+
("send", chat_id, replace_message_id)
|
|
198
|
+
if replace_message_id is not None
|
|
199
|
+
else self.unique_key("send")
|
|
200
|
+
),
|
|
201
|
+
label="send_message",
|
|
202
|
+
execute=execute,
|
|
203
|
+
priority=SEND_PRIORITY,
|
|
204
|
+
chat_id=chat_id,
|
|
205
|
+
)
|
|
206
|
+
if replace_message_id is not None and result is not None:
|
|
207
|
+
await self.delete_message(chat_id=chat_id, message_id=replace_message_id)
|
|
208
|
+
return result
|
|
209
|
+
|
|
210
|
+
async def send_document(
|
|
211
|
+
self,
|
|
212
|
+
chat_id: int,
|
|
213
|
+
filename: str,
|
|
214
|
+
content: bytes,
|
|
215
|
+
reply_to_message_id: int | None = None,
|
|
216
|
+
message_thread_id: int | None = None,
|
|
217
|
+
disable_notification: bool | None = False,
|
|
218
|
+
caption: str | None = None,
|
|
219
|
+
) -> Message | None:
|
|
220
|
+
async def execute() -> Message | None:
|
|
221
|
+
return await self._client.send_document(
|
|
222
|
+
chat_id=chat_id,
|
|
223
|
+
filename=filename,
|
|
224
|
+
content=content,
|
|
225
|
+
reply_to_message_id=reply_to_message_id,
|
|
226
|
+
message_thread_id=message_thread_id,
|
|
227
|
+
disable_notification=disable_notification,
|
|
228
|
+
caption=caption,
|
|
229
|
+
)
|
|
230
|
+
|
|
231
|
+
return await self.enqueue_op(
|
|
232
|
+
key=self.unique_key("send_document"),
|
|
233
|
+
label="send_document",
|
|
234
|
+
execute=execute,
|
|
235
|
+
priority=SEND_PRIORITY,
|
|
236
|
+
chat_id=chat_id,
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
async def edit_message_text(
|
|
240
|
+
self,
|
|
241
|
+
chat_id: int,
|
|
242
|
+
message_id: int,
|
|
243
|
+
text: str,
|
|
244
|
+
entities: list[dict] | None = None,
|
|
245
|
+
parse_mode: str | None = None,
|
|
246
|
+
reply_markup: dict[str, Any] | None = None,
|
|
247
|
+
*,
|
|
248
|
+
wait: bool = True,
|
|
249
|
+
) -> Message | None:
|
|
250
|
+
async def execute() -> Message | None:
|
|
251
|
+
return await self._client.edit_message_text(
|
|
252
|
+
chat_id=chat_id,
|
|
253
|
+
message_id=message_id,
|
|
254
|
+
text=text,
|
|
255
|
+
entities=entities,
|
|
256
|
+
parse_mode=parse_mode,
|
|
257
|
+
reply_markup=reply_markup,
|
|
258
|
+
wait=wait,
|
|
259
|
+
)
|
|
260
|
+
|
|
261
|
+
return await self.enqueue_op(
|
|
262
|
+
key=("edit", chat_id, message_id),
|
|
263
|
+
label="edit_message_text",
|
|
264
|
+
execute=execute,
|
|
265
|
+
priority=EDIT_PRIORITY,
|
|
266
|
+
chat_id=chat_id,
|
|
267
|
+
wait=wait,
|
|
268
|
+
)
|
|
269
|
+
|
|
270
|
+
async def delete_message(
|
|
271
|
+
self,
|
|
272
|
+
chat_id: int,
|
|
273
|
+
message_id: int,
|
|
274
|
+
) -> bool:
|
|
275
|
+
await self.drop_pending_edits(chat_id=chat_id, message_id=message_id)
|
|
276
|
+
|
|
277
|
+
async def execute() -> bool:
|
|
278
|
+
return await self._client.delete_message(
|
|
279
|
+
chat_id=chat_id,
|
|
280
|
+
message_id=message_id,
|
|
281
|
+
)
|
|
282
|
+
|
|
283
|
+
return bool(
|
|
284
|
+
await self.enqueue_op(
|
|
285
|
+
key=("delete", chat_id, message_id),
|
|
286
|
+
label="delete_message",
|
|
287
|
+
execute=execute,
|
|
288
|
+
priority=DELETE_PRIORITY,
|
|
289
|
+
chat_id=chat_id,
|
|
290
|
+
)
|
|
291
|
+
)
|
|
292
|
+
|
|
293
|
+
async def set_my_commands(
|
|
294
|
+
self,
|
|
295
|
+
commands: list[dict[str, Any]],
|
|
296
|
+
*,
|
|
297
|
+
scope: dict[str, Any] | None = None,
|
|
298
|
+
language_code: str | None = None,
|
|
299
|
+
) -> bool:
|
|
300
|
+
async def execute() -> bool:
|
|
301
|
+
return await self._client.set_my_commands(
|
|
302
|
+
commands,
|
|
303
|
+
scope=scope,
|
|
304
|
+
language_code=language_code,
|
|
305
|
+
)
|
|
306
|
+
|
|
307
|
+
return bool(
|
|
308
|
+
await self.enqueue_op(
|
|
309
|
+
key=self.unique_key("set_my_commands"),
|
|
310
|
+
label="set_my_commands",
|
|
311
|
+
execute=execute,
|
|
312
|
+
priority=SEND_PRIORITY,
|
|
313
|
+
chat_id=None,
|
|
314
|
+
)
|
|
315
|
+
)
|
|
316
|
+
|
|
317
|
+
async def get_me(self) -> User | None:
|
|
318
|
+
async def execute() -> User | None:
|
|
319
|
+
return await self._client.get_me()
|
|
320
|
+
|
|
321
|
+
return await self.enqueue_op(
|
|
322
|
+
key=self.unique_key("get_me"),
|
|
323
|
+
label="get_me",
|
|
324
|
+
execute=execute,
|
|
325
|
+
priority=SEND_PRIORITY,
|
|
326
|
+
chat_id=None,
|
|
327
|
+
)
|
|
328
|
+
|
|
329
|
+
async def answer_callback_query(
|
|
330
|
+
self,
|
|
331
|
+
callback_query_id: str,
|
|
332
|
+
text: str | None = None,
|
|
333
|
+
show_alert: bool | None = None,
|
|
334
|
+
) -> bool:
|
|
335
|
+
async def execute() -> bool:
|
|
336
|
+
return await self._client.answer_callback_query(
|
|
337
|
+
callback_query_id=callback_query_id,
|
|
338
|
+
text=text,
|
|
339
|
+
show_alert=show_alert,
|
|
340
|
+
)
|
|
341
|
+
|
|
342
|
+
return bool(
|
|
343
|
+
await self.enqueue_op(
|
|
344
|
+
key=self.unique_key("answer_callback_query"),
|
|
345
|
+
label="answer_callback_query",
|
|
346
|
+
execute=execute,
|
|
347
|
+
priority=SEND_PRIORITY,
|
|
348
|
+
chat_id=None,
|
|
349
|
+
)
|
|
350
|
+
)
|
|
351
|
+
|
|
352
|
+
async def get_chat(self, chat_id: int) -> Chat | None:
|
|
353
|
+
async def execute() -> Chat | None:
|
|
354
|
+
return await self._client.get_chat(chat_id)
|
|
355
|
+
|
|
356
|
+
return await self.enqueue_op(
|
|
357
|
+
key=self.unique_key("get_chat"),
|
|
358
|
+
label="get_chat",
|
|
359
|
+
execute=execute,
|
|
360
|
+
priority=SEND_PRIORITY,
|
|
361
|
+
chat_id=chat_id,
|
|
362
|
+
)
|
|
363
|
+
|
|
364
|
+
async def get_chat_member(self, chat_id: int, user_id: int) -> ChatMember | None:
|
|
365
|
+
async def execute() -> ChatMember | None:
|
|
366
|
+
return await self._client.get_chat_member(chat_id, user_id)
|
|
367
|
+
|
|
368
|
+
return await self.enqueue_op(
|
|
369
|
+
key=self.unique_key("get_chat_member"),
|
|
370
|
+
label="get_chat_member",
|
|
371
|
+
execute=execute,
|
|
372
|
+
priority=SEND_PRIORITY,
|
|
373
|
+
chat_id=chat_id,
|
|
374
|
+
)
|
|
375
|
+
|
|
376
|
+
async def create_forum_topic(self, chat_id: int, name: str) -> ForumTopic | None:
|
|
377
|
+
async def execute() -> ForumTopic | None:
|
|
378
|
+
return await self._client.create_forum_topic(chat_id, name)
|
|
379
|
+
|
|
380
|
+
return await self.enqueue_op(
|
|
381
|
+
key=self.unique_key("create_forum_topic"),
|
|
382
|
+
label="create_forum_topic",
|
|
383
|
+
execute=execute,
|
|
384
|
+
priority=SEND_PRIORITY,
|
|
385
|
+
chat_id=chat_id,
|
|
386
|
+
)
|
|
387
|
+
|
|
388
|
+
async def edit_forum_topic(
|
|
389
|
+
self,
|
|
390
|
+
chat_id: int,
|
|
391
|
+
message_thread_id: int,
|
|
392
|
+
name: str,
|
|
393
|
+
) -> bool:
|
|
394
|
+
async def execute() -> bool:
|
|
395
|
+
return await self._client.edit_forum_topic(
|
|
396
|
+
chat_id,
|
|
397
|
+
message_thread_id,
|
|
398
|
+
name,
|
|
399
|
+
)
|
|
400
|
+
|
|
401
|
+
return bool(
|
|
402
|
+
await self.enqueue_op(
|
|
403
|
+
key=self.unique_key("edit_forum_topic"),
|
|
404
|
+
label="edit_forum_topic",
|
|
405
|
+
execute=execute,
|
|
406
|
+
priority=SEND_PRIORITY,
|
|
407
|
+
chat_id=chat_id,
|
|
408
|
+
)
|
|
409
|
+
)
|