fabiana 1.6.0 → 1.7.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.
@@ -29,6 +29,38 @@ export class TelegramAdapter {
29
29
  });
30
30
  console.log(`šŸ“Ø [telegram] Message queued: "${text.slice(0, 50)}"`);
31
31
  });
32
+ this.bot.on('photo', async (ctx) => {
33
+ if (ctx.chat.id !== this.chatId)
34
+ return;
35
+ // Pick the largest available size (last in array)
36
+ const photo = ctx.message.photo[ctx.message.photo.length - 1];
37
+ const caption = ctx.message.caption ?? '';
38
+ try {
39
+ const fileLink = await this.bot.telegram.getFileLink(photo.file_id);
40
+ const response = await fetch(fileLink.href);
41
+ if (!response.ok)
42
+ throw new Error(`HTTP ${response.status}`);
43
+ const buffer = Buffer.from(await response.arrayBuffer());
44
+ await fs.mkdir(paths.imagesDir, { recursive: true });
45
+ const filename = `photo-${Date.now()}.jpg`;
46
+ const imagePath = paths.images(filename);
47
+ await fs.writeFile(imagePath, buffer);
48
+ const text = caption || '[sent a photo]';
49
+ this.queue.push({
50
+ text,
51
+ senderId: String(ctx.from.id),
52
+ channelId: String(ctx.chat.id),
53
+ threadId: String(ctx.message.message_id),
54
+ timestamp: new Date(ctx.message.date * 1000),
55
+ source: 'telegram',
56
+ imagePaths: [imagePath],
57
+ });
58
+ console.log(`šŸ“Ø [telegram] Photo queued → ${imagePath}`);
59
+ }
60
+ catch (err) {
61
+ console.error('āŒ Failed to download Telegram photo:', err.message);
62
+ }
63
+ });
32
64
  this.bot.catch((err) => {
33
65
  console.error('Telegram error:', err);
34
66
  });
@@ -247,7 +247,18 @@ export async function runPiSession(mode, incomingMessage, channel, incomingMsg,
247
247
  if (mode === 'chat') {
248
248
  await sendStatus(pick(['on it.', 'give me a sec.', 'let me think.', 'sure, one moment.', 'on it!']));
249
249
  }
250
- await session.prompt(prompt);
250
+ // Load any attached images as base64 for the Pi SDK
251
+ let promptImages;
252
+ if (incomingMsg?.imagePaths?.length) {
253
+ promptImages = await Promise.all(incomingMsg.imagePaths.map(async (p) => {
254
+ const data = await fs.readFile(p);
255
+ const ext = p.split('.').pop()?.toLowerCase() ?? 'jpg';
256
+ const mimeType = ext === 'png' ? 'image/png' : ext === 'gif' ? 'image/gif' : ext === 'webp' ? 'image/webp' : 'image/jpeg';
257
+ return { type: 'image', data: data.toString('base64'), mimeType };
258
+ }));
259
+ console.log(` šŸ–¼ļø Attaching ${promptImages.length} image(s) to prompt`);
260
+ }
261
+ await session.prompt(prompt, promptImages ? { images: promptImages } : undefined);
251
262
  console.log('\nā³ Waiting for agent to complete...');
252
263
  await session.agent.waitForIdle();
253
264
  if (lastActivityWasThinking) {
package/dist/paths.js CHANGED
@@ -18,6 +18,8 @@ export const paths = {
18
18
  logs: (filename) => join(DATA_DIR, 'logs', filename),
19
19
  sessions: join(DATA_DIR, 'sessions'),
20
20
  agentTodo: join(DATA_DIR, 'agent-todo'),
21
+ imagesDir: join(DATA_DIR, 'images'),
22
+ images: (filename) => join(DATA_DIR, 'images', filename),
21
23
  conversations: join(DATA_DIR, 'conversations'),
22
24
  moodMd: join(DATA_DIR, 'memory', 'mood.md'),
23
25
  memoryDb: join(DATA_DIR, 'memory.db'),