whatsapp-pi 1.0.16 → 1.0.19
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 +6 -3
- package/package.json +9 -1
- package/src/ui/menu.handler.ts +0 -40
- package/whatsapp-pi.ts +9 -58
package/README.md
CHANGED
|
@@ -6,6 +6,8 @@
|
|
|
6
6
|
|
|
7
7
|
A WhatsApp integration extension for the **[Pi Coding Agent](https://github.com/mariozechner/pi-coding-agent)**.
|
|
8
8
|
|
|
9
|
+
[](https://github.com/RaphaCastelloes/whatsapp-pi)
|
|
10
|
+
|
|
9
11
|
Pi is a powerful agentic AI coding assistant that operates in your terminal. This extension allows you to chat and pair-program with your Pi agent directly through WhatsApp, featuring message filtering, allow-listing, and reliable message delivery.
|
|
10
12
|
|
|
11
13
|
## Features
|
|
@@ -40,10 +42,12 @@ pi --whatsapp
|
|
|
40
42
|
|
|
41
43
|
## Development / Testing
|
|
42
44
|
|
|
43
|
-
If you are developing or testing the extension locally:
|
|
45
|
+
If you are developing or testing the extension locally, you can clone the repository from [GitHub](https://github.com/RaphaCastelloes/whatsapp-pi):
|
|
44
46
|
|
|
45
|
-
1.
|
|
47
|
+
1. Clone and install dependencies:
|
|
46
48
|
```bash
|
|
49
|
+
git clone https://github.com/RaphaCastelloes/whatsapp-pi.git
|
|
50
|
+
cd whatsapp-pi
|
|
47
51
|
npm install
|
|
48
52
|
```
|
|
49
53
|
|
|
@@ -67,7 +71,6 @@ pi -e whatsapp-pi.ts --verbose
|
|
|
67
71
|
- **Connect WhatsApp** - Start WhatsApp connection (shows QR code for first-time setup)
|
|
68
72
|
- **Disconnect WhatsApp** - Stop WhatsApp connection
|
|
69
73
|
- **Logoff (Delete Session)** - Remove all credentials and session data
|
|
70
|
-
- **Reset Conversation** - Clear all conversation history
|
|
71
74
|
- **Allowed Numbers** - Manage contacts that can interact with Pi
|
|
72
75
|
- **Blocked Numbers** - View ignored numbers and manage them
|
|
73
76
|
|
package/package.json
CHANGED
|
@@ -1,9 +1,17 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "whatsapp-pi",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.19",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"description": "WhatsApp integration extension for Pi",
|
|
6
6
|
"main": "whatsapp-pi.ts",
|
|
7
|
+
"repository": {
|
|
8
|
+
"type": "git",
|
|
9
|
+
"url": "git+https://github.com/RaphaCastelloes/whatsapp-pi.git"
|
|
10
|
+
},
|
|
11
|
+
"bugs": {
|
|
12
|
+
"url": "https://github.com/RaphaCastelloes/whatsapp-pi/issues"
|
|
13
|
+
},
|
|
14
|
+
"homepage": "https://github.com/RaphaCastelloes/whatsapp-pi#readme",
|
|
7
15
|
"files": [
|
|
8
16
|
"whatsapp-pi.ts",
|
|
9
17
|
"src"
|
package/src/ui/menu.handler.ts
CHANGED
|
@@ -26,12 +26,10 @@ export class MenuHandler {
|
|
|
26
26
|
|
|
27
27
|
if (registered) {
|
|
28
28
|
options.push('Logoff (Delete Session)');
|
|
29
|
-
options.push('Reset Conversation');
|
|
30
29
|
}
|
|
31
30
|
|
|
32
31
|
options.push('Allowed Numbers');
|
|
33
32
|
options.push('Blocked Numbers');
|
|
34
|
-
options.push('Vision Settings');
|
|
35
33
|
options.push('Back');
|
|
36
34
|
|
|
37
35
|
const choice = await ctx.ui.select(`WhatsApp (Status: ${status})`, options);
|
|
@@ -55,21 +53,12 @@ export class MenuHandler {
|
|
|
55
53
|
ctx.ui.notify('Logged off and credentials deleted', 'info');
|
|
56
54
|
}
|
|
57
55
|
break;
|
|
58
|
-
case 'Reset Conversation':
|
|
59
|
-
const confirmReset = await ctx.ui.confirm('Reset', 'Clear all conversation history?');
|
|
60
|
-
if (confirmReset) {
|
|
61
|
-
await ctx.newSession();
|
|
62
|
-
}
|
|
63
|
-
break;
|
|
64
56
|
case 'Allowed Numbers':
|
|
65
57
|
await this.manageAllowList(ctx);
|
|
66
58
|
break;
|
|
67
59
|
case 'Blocked Numbers':
|
|
68
60
|
await this.manageBlockList(ctx);
|
|
69
61
|
break;
|
|
70
|
-
case 'Vision Settings':
|
|
71
|
-
await this.manageVisionSettings(ctx);
|
|
72
|
-
break;
|
|
73
62
|
}
|
|
74
63
|
}
|
|
75
64
|
|
|
@@ -162,33 +151,4 @@ export class MenuHandler {
|
|
|
162
151
|
await this.manageBlockList(ctx);
|
|
163
152
|
}
|
|
164
153
|
}
|
|
165
|
-
|
|
166
|
-
private async manageVisionSettings(ctx: ExtensionCommandContext) {
|
|
167
|
-
const key = this.sessionManager.getOpenaiKey();
|
|
168
|
-
const model = this.sessionManager.getVisionModel();
|
|
169
|
-
|
|
170
|
-
const options = [
|
|
171
|
-
`API Key: ${key ? '********' : '(Not Set)'}`,
|
|
172
|
-
`Vision Model: ${model}`,
|
|
173
|
-
'Back'
|
|
174
|
-
];
|
|
175
|
-
|
|
176
|
-
const choice = await ctx.ui.select('Vision Settings', options);
|
|
177
|
-
|
|
178
|
-
if (choice?.startsWith('API Key:')) {
|
|
179
|
-
const newKey = await ctx.ui.input('Enter OpenAI API Key (leave empty to clear):');
|
|
180
|
-
await this.sessionManager.setOpenaiKey(newKey || '');
|
|
181
|
-
ctx.ui.notify('OpenAI Key updated', 'info');
|
|
182
|
-
await this.manageVisionSettings(ctx);
|
|
183
|
-
} else if (choice?.startsWith('Vision Model:')) {
|
|
184
|
-
const newModel = await ctx.ui.input('Enter Vision Model (e.g., gpt-4o, gpt-4o-mini):', model);
|
|
185
|
-
if (newModel) {
|
|
186
|
-
await this.sessionManager.setVisionModel(newModel);
|
|
187
|
-
ctx.ui.notify('Vision model updated', 'info');
|
|
188
|
-
}
|
|
189
|
-
await this.manageVisionSettings(ctx);
|
|
190
|
-
} else {
|
|
191
|
-
await this.handleCommand(ctx);
|
|
192
|
-
}
|
|
193
|
-
}
|
|
194
154
|
}
|
package/whatsapp-pi.ts
CHANGED
|
@@ -162,55 +162,14 @@ export default function (pi: ExtensionAPI) {
|
|
|
162
162
|
// Always log to console so it appears in the TUI log pane
|
|
163
163
|
console.log(`[WhatsApp-Pi] ${pushName} (+${sender}): ${text}`);
|
|
164
164
|
|
|
165
|
-
//
|
|
166
|
-
if (imageBuffer && imageMimeType
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
method: "POST",
|
|
174
|
-
headers: {
|
|
175
|
-
"Content-Type": "application/json",
|
|
176
|
-
"Authorization": `Bearer ${openAiKey}`
|
|
177
|
-
},
|
|
178
|
-
body: JSON.stringify({
|
|
179
|
-
model: visionModel,
|
|
180
|
-
messages: [
|
|
181
|
-
{
|
|
182
|
-
role: "user",
|
|
183
|
-
content: [
|
|
184
|
-
{ type: "text", text: "Descreva esta imagem em detalhes. Se houver texto, transcreva-o." },
|
|
185
|
-
{
|
|
186
|
-
type: "image_url",
|
|
187
|
-
image_url: {
|
|
188
|
-
url: `data:${imageMimeType};base64,${imageBuffer.toString('base64')}`
|
|
189
|
-
}
|
|
190
|
-
}
|
|
191
|
-
]
|
|
192
|
-
}
|
|
193
|
-
],
|
|
194
|
-
max_tokens: 500
|
|
195
|
-
})
|
|
196
|
-
});
|
|
197
|
-
|
|
198
|
-
if (response.ok) {
|
|
199
|
-
const data = await response.json() as any;
|
|
200
|
-
const description = data.choices[0].message.content;
|
|
201
|
-
text = `${text}\n\n[Análise da Imagem por ${visionModel}]:\n${description}`;
|
|
202
|
-
// Clear buffer/mime so we don't send the image again to Pi
|
|
203
|
-
imageBuffer = undefined;
|
|
204
|
-
imageMimeType = undefined;
|
|
205
|
-
} else {
|
|
206
|
-
const error = await response.text();
|
|
207
|
-
console.error(`[WhatsApp-Pi] OpenAI Vision API error:`, error);
|
|
208
|
-
text = `${text}\n\n[Erro na análise da imagem: API retornou ${response.status}]`;
|
|
209
|
-
}
|
|
210
|
-
} catch (e) {
|
|
211
|
-
console.error(`[WhatsApp-Pi] Failed to analyze image with OpenAI:`, e);
|
|
212
|
-
text = `${text}\n\n[Erro ao processar imagem com OpenAI]`;
|
|
213
|
-
}
|
|
165
|
+
// Use a standard delivery for ALL messages to ensure TUI consistency
|
|
166
|
+
if (imageBuffer && imageMimeType) {
|
|
167
|
+
pi.sendUserMessage([
|
|
168
|
+
{ type: "text", text: `Mensagem de ${pushName} (+${sender}): ${text}` },
|
|
169
|
+
{ type: "image", data: imageBuffer.toString('base64'), mimeType: imageMimeType }
|
|
170
|
+
], { deliverAs: "followUp" });
|
|
171
|
+
} else {
|
|
172
|
+
pi.sendUserMessage(`Mensagem de ${pushName} (+${sender}): ${text}`, { deliverAs: "followUp" });
|
|
214
173
|
}
|
|
215
174
|
|
|
216
175
|
// Handle commands
|
|
@@ -233,15 +192,7 @@ export default function (pi: ExtensionAPI) {
|
|
|
233
192
|
return;
|
|
234
193
|
}
|
|
235
194
|
|
|
236
|
-
|
|
237
|
-
if (imageBuffer && imageMimeType) {
|
|
238
|
-
pi.sendUserMessage([
|
|
239
|
-
{ type: "text", text: `Mensagem de ${pushName} (+${sender}): ${text}` },
|
|
240
|
-
{ type: "image", data: imageBuffer.toString('base64'), mimeType: imageMimeType }
|
|
241
|
-
], { deliverAs: "followUp" });
|
|
242
|
-
} else {
|
|
243
|
-
pi.sendUserMessage(`Mensagem de ${pushName} (+${sender}): ${text}`, { deliverAs: "followUp" });
|
|
244
|
-
}
|
|
195
|
+
|
|
245
196
|
});
|
|
246
197
|
|
|
247
198
|
// Register commands
|