gemini-bridge 0.0.1

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/.env.example ADDED
@@ -0,0 +1,27 @@
1
+ # Telegram Token (required)
2
+ # Get this from @BotFather on Telegram
3
+ TELEGRAM_TOKEN=your_telegram_bot_token_here
4
+
5
+ # Typing indicator refresh interval in milliseconds (optional, default: 4000)
6
+ TYPING_INTERVAL_MS=4000
7
+
8
+ # Gemini command and mode options
9
+ GEMINI_COMMAND=gemini
10
+ # GEMINI_APPROVAL_MODE=default
11
+ # GEMINI_MODEL=
12
+
13
+ # How ACP permission options are auto-selected when requested by the agent.
14
+ # Supported: allow_once, reject_once, cancelled
15
+ ACP_PERMISSION_STRATEGY=allow_once
16
+
17
+ # Gemini overall timeout in milliseconds (optional, default: 120000)
18
+ GEMINI_TIMEOUT_MS=120000
19
+
20
+ # Gemini no-output timeout in milliseconds (optional, default: 60000)
21
+ # Set to 0 to disable idle-timeout behavior.
22
+ GEMINI_NO_OUTPUT_TIMEOUT_MS=60000
23
+
24
+ # Maximum response length in characters (optional, default: 4000)
25
+ # Prevents memory issues with very long responses
26
+ # Telegram has a 4096 character limit per message anyway
27
+ MAX_RESPONSE_LENGTH=4000
package/EXAMPLES.md ADDED
@@ -0,0 +1,286 @@
1
+ # Examples and Extensions
2
+
3
+ This file contains examples of how to extend and customize the Telegram-Gemini bridge.
4
+
5
+ ## Example 1: Adding Command Handlers
6
+
7
+ You can add special commands that trigger different behaviors:
8
+
9
+ ```javascript
10
+ // Add this before the general text handler in index.js
11
+
12
+ // Handle /start command
13
+ bot.start((ctx) => {
14
+ ctx.reply(
15
+ '👋 Welcome to Gemini CLI Bridge!\n\n' +
16
+ 'Send me any message and I\'ll forward it to your local Gemini agent.\n\n' +
17
+ 'Features:\n' +
18
+ '• Real-time streaming responses\n' +
19
+ '• Access to local tools via MCP\n' +
20
+ '• Persistent conversation context\n\n' +
21
+ 'Just start chatting!'
22
+ );
23
+ });
24
+
25
+ // Handle /help command
26
+ bot.help((ctx) => {
27
+ ctx.reply(
28
+ '💡 How to use:\n\n' +
29
+ '1. Send any message or question\n' +
30
+ '2. Wait for Gemini to process it\n' +
31
+ '3. Watch the response stream in real-time\n\n' +
32
+ 'Your Gemini CLI session is persistent, so context is maintained across messages!'
33
+ );
34
+ });
35
+ ```
36
+
37
+ ## Example 2: Adding Typing Indicator
38
+
39
+ Show that the bot is "typing" while processing:
40
+
41
+ ```javascript
42
+ bot.on('text', async (ctx) => {
43
+ let fullResponse = "";
44
+
45
+ try {
46
+ // Show typing indicator
47
+ await ctx.sendChatAction('typing');
48
+
49
+ const info = await ctx.reply("🤔 Thinking...");
50
+
51
+ // Continue typing periodically
52
+ const typingInterval = setInterval(() => {
53
+ ctx.sendChatAction('typing').catch(() => {});
54
+ }, 5000);
55
+
56
+ const { textStream } = await streamText({
57
+ model: geminiAgent,
58
+ prompt: ctx.message.text,
59
+ });
60
+
61
+ // ... rest of the streaming logic
62
+
63
+ // Stop typing indicator
64
+ clearInterval(typingInterval);
65
+
66
+ } catch (error) {
67
+ // ... error handling
68
+ }
69
+ });
70
+ ```
71
+
72
+ ## Example 3: Adding Response Time Tracking
73
+
74
+ Track how long responses take:
75
+
76
+ ```javascript
77
+ bot.on('text', async (ctx) => {
78
+ let fullResponse = "";
79
+ const startTime = Date.now();
80
+
81
+ try {
82
+ const info = await ctx.reply("🤔 Thinking...");
83
+
84
+ const { textStream } = await streamText({
85
+ model: geminiAgent,
86
+ prompt: ctx.message.text,
87
+ });
88
+
89
+ for await (const delta of textStream) {
90
+ fullResponse += delta;
91
+ // ... update logic
92
+ }
93
+
94
+ const responseTime = ((Date.now() - startTime) / 1000).toFixed(2);
95
+
96
+ // Add response time to final message
97
+ await ctx.telegram.editMessageText(
98
+ ctx.chat.id,
99
+ info.message_id,
100
+ null,
101
+ `${fullResponse}\n\n⏱️ _Responded in ${responseTime}s_`,
102
+ { parse_mode: 'Markdown' }
103
+ );
104
+
105
+ } catch (error) {
106
+ // ... error handling
107
+ }
108
+ });
109
+ ```
110
+
111
+ ## Example 4: User Whitelisting
112
+
113
+ Restrict bot access to specific users:
114
+
115
+ ```javascript
116
+ // Add at the top after imports
117
+ const ALLOWED_USERS = process.env.ALLOWED_USER_IDS?.split(',').map(id => parseInt(id)) || [];
118
+
119
+ // Add middleware before handlers
120
+ bot.use(async (ctx, next) => {
121
+ const userId = ctx.from?.id;
122
+
123
+ if (ALLOWED_USERS.length > 0 && !ALLOWED_USERS.includes(userId)) {
124
+ await ctx.reply('⛔ Sorry, you are not authorized to use this bot.');
125
+ return;
126
+ }
127
+
128
+ return next();
129
+ });
130
+ ```
131
+
132
+ Then add to `.env`:
133
+ ```env
134
+ ALLOWED_USER_IDS=123456789,987654321
135
+ ```
136
+
137
+ ## Example 5: Conversation Context Reset
138
+
139
+ Add a command to reset the Gemini CLI session:
140
+
141
+ ```javascript
142
+ bot.command('reset', async (ctx) => {
143
+ try {
144
+ // You would need to implement session management
145
+ // This is a simplified example
146
+ await ctx.reply('🔄 Context reset! Starting fresh conversation.');
147
+ } catch (error) {
148
+ await ctx.reply('❌ Failed to reset context.');
149
+ }
150
+ });
151
+ ```
152
+
153
+ ## Example 6: Adding Message Queue
154
+
155
+ Handle multiple concurrent messages gracefully:
156
+
157
+ ```javascript
158
+ import PQueue from 'p-queue';
159
+
160
+ const queue = new PQueue({ concurrency: 1 });
161
+
162
+ bot.on('text', async (ctx) => {
163
+ // Add to queue
164
+ queue.add(async () => {
165
+ // ... your message handling logic
166
+ });
167
+
168
+ if (queue.size > 0) {
169
+ await ctx.reply(`⏳ ${queue.size} message(s) in queue...`);
170
+ }
171
+ });
172
+ ```
173
+
174
+ ## Example 7: Custom Gemini CLI Arguments
175
+
176
+ Pass custom arguments to Gemini CLI:
177
+
178
+ ```javascript
179
+ const geminiAgent = new ACP({
180
+ command: 'gemini',
181
+ args: [
182
+ '--protocol', 'acp',
183
+ '--model', 'gemini-2.0-flash-exp', // Specify model
184
+ '--max-tokens', '2048', // Set token limit
185
+ '--temperature', '0.7' // Control creativity
186
+ ]
187
+ });
188
+ ```
189
+
190
+ ## Example 8: Error Recovery with Retry
191
+
192
+ Add automatic retry on failures:
193
+
194
+ ```javascript
195
+ async function streamWithRetry(prompt, maxRetries = 3) {
196
+ for (let attempt = 1; attempt <= maxRetries; attempt++) {
197
+ try {
198
+ return await streamText({
199
+ model: geminiAgent,
200
+ prompt: prompt,
201
+ });
202
+ } catch (error) {
203
+ if (attempt === maxRetries) throw error;
204
+ console.log(`Attempt ${attempt} failed, retrying...`);
205
+ await new Promise(resolve => setTimeout(resolve, 1000 * attempt));
206
+ }
207
+ }
208
+ }
209
+
210
+ bot.on('text', async (ctx) => {
211
+ // ...
212
+ const { textStream } = await streamWithRetry(ctx.message.text);
213
+ // ...
214
+ });
215
+ ```
216
+
217
+ ## Example 9: Logging User Interactions
218
+
219
+ Track usage patterns:
220
+
221
+ ```javascript
222
+ import fs from 'fs/promises';
223
+
224
+ bot.on('text', async (ctx) => {
225
+ const logEntry = {
226
+ timestamp: new Date().toISOString(),
227
+ userId: ctx.from.id,
228
+ username: ctx.from.username,
229
+ message: ctx.message.text,
230
+ };
231
+
232
+ await fs.appendFile(
233
+ 'interaction_log.jsonl',
234
+ JSON.stringify(logEntry) + '\n'
235
+ );
236
+
237
+ // ... rest of handler
238
+ });
239
+ ```
240
+
241
+ ## Example 10: Rich Formatting
242
+
243
+ Use Telegram's formatting options:
244
+
245
+ ```javascript
246
+ // In your message updates
247
+ await ctx.telegram.editMessageText(
248
+ ctx.chat.id,
249
+ info.message_id,
250
+ null,
251
+ formatResponse(fullResponse),
252
+ { parse_mode: 'Markdown' }
253
+ );
254
+
255
+ function formatResponse(text) {
256
+ // Convert **bold** to Telegram bold
257
+ text = text.replace(/\*\*(.*?)\*\*/g, '*$1*');
258
+
259
+ // Convert `code` to Telegram code
260
+ text = text.replace(/`([^`]+)`/g, '`$1`');
261
+
262
+ return text;
263
+ }
264
+ ```
265
+
266
+ ## Tips for Extensions
267
+
268
+ 1. **Keep it modular**: Create separate files for complex features
269
+ 2. **Handle errors**: Always wrap async operations in try-catch
270
+ 3. **Test locally**: Use `npm run dev` for quick iteration
271
+ 4. **Monitor performance**: Log timing and memory usage
272
+ 5. **Document changes**: Update README when adding features
273
+
274
+ ## Contributing
275
+
276
+ Have a cool extension? Share it by:
277
+ 1. Adding it to this file
278
+ 2. Creating an example in `/examples` directory
279
+ 3. Opening a pull request
280
+
281
+ ---
282
+
283
+ For more ideas, check out:
284
+ - [Telegraf documentation](https://telegraf.js.org/)
285
+ - [Vercel AI SDK docs](https://sdk.vercel.ai/)
286
+ - [Gemini CLI documentation](https://github.com/google/generative-ai-docs)
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Hainan Zhao
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/QUICKSTART.md ADDED
@@ -0,0 +1,98 @@
1
+ # Quick Start Guide
2
+
3
+ Get your Telegram-Gemini bridge running in 5 minutes!
4
+
5
+ ## Prerequisites Checklist
6
+
7
+ - [ ] Node.js 18+ installed (`node --version`)
8
+ - [ ] Gemini CLI installed (`gemini --version`)
9
+ - [ ] Telegram bot token from [@BotFather](https://t.me/BotFather)
10
+
11
+ ## Setup Steps
12
+
13
+ ### 1. Install Dependencies
14
+ ```bash
15
+ npm install
16
+ ```
17
+
18
+ ### 2. Configure Environment
19
+ ```bash
20
+ cp .env.example .env
21
+ ```
22
+
23
+ Edit `.env` and add your bot token:
24
+ ```env
25
+ TELEGRAM_TOKEN=1234567890:ABCdefGHIjklMNOpqrsTUVwxyz
26
+ ```
27
+
28
+ ### 3. Test Gemini CLI
29
+ Verify Gemini CLI supports ACP:
30
+ ```bash
31
+ gemini --protocol acp
32
+ ```
33
+
34
+ ### 4. Run the Bridge
35
+
36
+ **Quick test:**
37
+ ```bash
38
+ npm start
39
+ ```
40
+
41
+ **Development (auto-restart):**
42
+ ```bash
43
+ npm run dev
44
+ ```
45
+
46
+ **Production (with PM2):**
47
+ ```bash
48
+ npm install -g pm2
49
+ pm2 start ecosystem.config.json
50
+ pm2 logs
51
+ ```
52
+
53
+ ## Verify It's Working
54
+
55
+ 1. Open Telegram
56
+ 2. Find your bot (search for the username you gave it)
57
+ 3. Send a message: "Hello!"
58
+ 4. You should see "🤔 Thinking..." followed by Gemini's response
59
+
60
+ ## Common Issues
61
+
62
+ ### "TELEGRAM_TOKEN is required"
63
+ - Check your `.env` file exists
64
+ - Verify the token is on the line `TELEGRAM_TOKEN=...`
65
+ - No quotes needed around the token
66
+
67
+ ### "command not found: gemini"
68
+ - Install Gemini CLI first
69
+ - Verify with: `which gemini`
70
+
71
+ ### Bot doesn't respond
72
+ - Check logs: `pm2 logs` (if using PM2)
73
+ - Or check console output
74
+ - Verify your bot token is correct
75
+
76
+ ### Rate limit errors (429)
77
+ - Increase `UPDATE_INTERVAL_MS` in `.env` to 2000 or higher
78
+ - Restart the bot
79
+
80
+ ## Next Steps
81
+
82
+ - Read the full [README.md](README.md) for detailed configuration
83
+ - Configure MCP servers for tool use
84
+ - Set up auto-start with PM2
85
+
86
+ ## Getting Help
87
+
88
+ - Check [README.md](README.md) troubleshooting section
89
+ - Review Gemini CLI documentation
90
+ - Open an issue on GitHub
91
+
92
+ ---
93
+
94
+ **Pro tip:** Keep the bridge running with PM2 and set it to auto-start on boot:
95
+ ```bash
96
+ pm2 startup
97
+ pm2 save
98
+ ```