opencode-telegram-bot 1.0.9 → 1.1.0

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.
package/README.md CHANGED
@@ -112,10 +112,26 @@ These are handled directly by the Telegram bot:
112
112
  | `/model` | Show current model and usage hints |
113
113
  | `/model <keyword>` | Search models by keyword |
114
114
  | `/model default` | Reset to the default model |
115
+ | `/agent` | Show current agent and switch (plan, build, ...) |
116
+ | `/agent <name>` | Switch directly to a named agent |
115
117
  | `/usage` | Show token and cost usage for this session |
116
118
  | `/help` | Show available commands |
117
119
 
118
- The bot also registers these commands in Telegram's command menu (the `/` button), plus any OpenCode server commands discovered at startup (excluding hidden ones like `/init` and `/review`).
120
+ ### Interactive Questions
121
+
122
+ When the OpenCode agent asks a question (e.g. to clarify intent or pick from options), the bot forwards it to Telegram as **inline keyboard buttons**. Tap an option to answer, or tap **Dismiss** to reject the question.
123
+
124
+ If the bot restarts while a question is pending, it automatically re-sends the question buttons on startup so the session is not left stuck.
125
+
126
+ ```
127
+ Agent: Which area do you want to focus on?
128
+ [Code review] [Bug fix] [New feature] [Dismiss]
129
+
130
+ You: [tap "Bug fix"]
131
+ Bot: Answered: Bug fix
132
+ ```
133
+
134
+ The bot also registers these commands in Telegram's command menu (the `/` button), plus any OpenCode server commands discovered at startup.
119
135
 
120
136
  ### Verbose Mode
121
137
 
@@ -163,6 +179,33 @@ Other commands:
163
179
  - `/model` shows the current model and usage hints
164
180
  - `/model default` resets to the server default
165
181
 
182
+ ### Agent Switching
183
+
184
+ OpenCode supports multiple agents: **build** (default, full edit access), **plan** (read-only analysis), and others. Use `/agent` to see and switch between them:
185
+
186
+ ```
187
+ You: /agent
188
+ Bot: Current agent: build
189
+
190
+ Available agents:
191
+ - build (active) -- The default agent
192
+ - plan -- Plan mode. Disallows all edit tools.
193
+ - general -- General-purpose agent
194
+ - explore -- Codebase explorer
195
+
196
+ [build] [plan] [general] [explore]
197
+
198
+ You: [tap "plan"]
199
+ (button message is deleted)
200
+ Bot: Agent: plan | Model: claude-opus-4 | Verbose: off [pinned]
201
+ ```
202
+
203
+ ### Pinned Status Message
204
+
205
+ A pinned message at the top of the chat shows the current agent, model, and verbose mode. It updates automatically when any of these change — via `/agent`, `/model`, or `/verbose`. The pinned message is the only confirmation; no separate reply is sent.
206
+
207
+ Agent, model, and verbose selections are per-chat and persist across bot restarts.
208
+
166
209
  ## Usage
167
210
 
168
211
  Use `/usage` to see the current session's token counts and estimated cost:
@@ -250,6 +293,15 @@ Sessions survive bot restarts. The bot saves the chat-to-session mapping to `ses
250
293
 
251
294
  This means you can restart the bot (or even delete `sessions.json`) and it will reconnect to existing sessions automatically.
252
295
 
296
+ ## Resilience
297
+
298
+ The bot is designed to survive restarts and failures:
299
+
300
+ - **Drop pending updates** -- On startup, stale Telegram updates are discarded so old button clicks and messages from a previous run are not replayed.
301
+ - **Pending question recovery** -- If the bot restarts while the agent is waiting for a question answer, the question is re-sent to Telegram on startup so the session can be unblocked.
302
+ - **Global error handler** -- Unhandled errors in Telegram update handlers are logged instead of crashing the process.
303
+ - **Handler timeout** -- Telegraf's handler timeout is set to 10 minutes (up from 90 seconds) to accommodate long-running LLM responses.
304
+
253
305
  ## Environment Variables
254
306
 
255
307
  | Variable | Required | Description |
package/dist/app.d.ts CHANGED
@@ -1,25 +1,33 @@
1
1
  interface OpencodeClientLike {
2
2
  session: {
3
- list: (options?: any) => Promise<any>;
4
- create: (options: any) => Promise<any>;
5
- update: (options: any) => Promise<any>;
6
- delete: (options: any) => Promise<any>;
7
- get: (options: any) => Promise<any>;
8
- messages: (options: any) => Promise<any>;
9
- command: (options: any) => Promise<any>;
10
- promptAsync: (options: any) => Promise<any>;
3
+ list: (params?: any, options?: any) => Promise<any>;
4
+ create: (params: any, options?: any) => Promise<any>;
5
+ update: (params: any, options?: any) => Promise<any>;
6
+ delete: (params: any, options?: any) => Promise<any>;
7
+ get: (params: any, options?: any) => Promise<any>;
8
+ messages: (params: any, options?: any) => Promise<any>;
9
+ command: (params: any, options?: any) => Promise<any>;
10
+ promptAsync: (params: any, options?: any) => Promise<any>;
11
11
  };
12
12
  command: {
13
- list: (options?: any) => Promise<any>;
13
+ list: (params?: any, options?: any) => Promise<any>;
14
14
  };
15
15
  provider: {
16
- list: (options?: any) => Promise<any>;
16
+ list: (params?: any, options?: any) => Promise<any>;
17
17
  };
18
18
  path: {
19
- get: (options?: any) => Promise<any>;
19
+ get: (params?: any, options?: any) => Promise<any>;
20
20
  };
21
21
  event: {
22
- subscribe: (options?: any) => Promise<any>;
22
+ subscribe: (params?: any, options?: any) => Promise<any>;
23
+ };
24
+ question: {
25
+ list: (params?: any, options?: any) => Promise<any>;
26
+ reply: (params: any, options?: any) => Promise<any>;
27
+ reject: (params: any, options?: any) => Promise<any>;
28
+ };
29
+ app: {
30
+ agents: (params?: any, options?: any) => Promise<any>;
23
31
  };
24
32
  }
25
33
  interface StartOptions {
@@ -32,15 +40,18 @@ interface StartOptions {
32
40
  }
33
41
  interface TelegramBot {
34
42
  use: (fn: (ctx: any, next: () => Promise<void>) => Promise<void> | void) => void;
43
+ catch: (fn: (err: unknown, ctx: any) => void) => void;
35
44
  start: (fn: (ctx: any) => void | Promise<void>) => void;
36
45
  help: (fn: (ctx: any) => void | Promise<void>) => void;
37
46
  command: (command: string, fn: (ctx: any) => void | Promise<void>) => void;
38
47
  on: (event: string, fn: (ctx: any) => void | Promise<void>) => void;
39
48
  action: (trigger: string | RegExp, fn: (ctx: any) => void | Promise<void>) => void;
40
- launch: () => Promise<void>;
49
+ launch: (options?: {
50
+ dropPendingUpdates?: boolean;
51
+ }) => Promise<void>;
41
52
  stop: (reason?: string) => void;
42
53
  telegram: {
43
- sendMessage: (chatId: number, text: string, options?: Record<string, unknown>) => Promise<void>;
54
+ sendMessage: (chatId: number, text: string, options?: Record<string, unknown>) => Promise<any>;
44
55
  deleteMessage: (chatId: number, messageId: number) => Promise<void>;
45
56
  sendDocument: (chatId: number, file: {
46
57
  source: Buffer;
@@ -53,6 +64,9 @@ interface TelegramBot {
53
64
  command: string;
54
65
  description: string;
55
66
  }>) => Promise<unknown>;
67
+ pinChatMessage: (chatId: number, messageId: number, extra?: Record<string, unknown>) => Promise<void>;
68
+ unpinChatMessage: (chatId: number, messageId?: number) => Promise<void>;
69
+ editMessageText: (chatId: number | undefined, messageId: number | undefined, inlineMessageId: string | undefined, text: string, extra?: Record<string, unknown>) => Promise<void>;
56
70
  };
57
71
  }
58
72
  export declare function startTelegram(options: StartOptions): Promise<TelegramBot>;