@photon-ai/flux 0.6.3 → 0.6.6
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 +81 -0
- package/dist/index.js +67 -18
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -249,6 +249,37 @@ The `splitIntoMessages` helper function splits messages using `\n` and then loop
|
|
|
249
249
|
|
|
250
250
|
For example, `"Hello!\nHow are you?\nNice to meet you!"` will be sent as three separate message bubbles.
|
|
251
251
|
|
|
252
|
+
## Tapbacks
|
|
253
|
+
|
|
254
|
+
Agents can send tapback reactions (love, like, dislike, laugh, emphasize, question). When your agent receives a message, it can react to it using the `sendTapback` function.
|
|
255
|
+
|
|
256
|
+
To use `sendTapback`, you need to:
|
|
257
|
+
1. Capture `sendTapback` in `onInit` once at startup
|
|
258
|
+
2. Call it in `invoke` when processing messages
|
|
259
|
+
|
|
260
|
+
```
|
|
261
|
+
import { FluxAgent, SendTapbackFn } from '@photon-ai/flux';
|
|
262
|
+
|
|
263
|
+
let sendTapback: SendTapbackFn | undefined;
|
|
264
|
+
|
|
265
|
+
const agent: FluxAgent = {
|
|
266
|
+
onInit: async (_sendMessage, _sendTapback) => {
|
|
267
|
+
sendTapback = _sendTapback; // Save it for later
|
|
268
|
+
},
|
|
269
|
+
|
|
270
|
+
invoke: async ({ message, userPhoneNumber, messageGuid }) => {
|
|
271
|
+
// Now you can use it
|
|
272
|
+
if (sendTapback && messageGuid) {
|
|
273
|
+
await sendTapback(messageGuid, 'love', userPhoneNumber);
|
|
274
|
+
}
|
|
275
|
+
|
|
276
|
+
return "Hello!";
|
|
277
|
+
},
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
export default agent;
|
|
281
|
+
```
|
|
282
|
+
|
|
252
283
|
## 💡 Examples
|
|
253
284
|
|
|
254
285
|
### Weather Agent
|
|
@@ -313,6 +344,56 @@ export default {
|
|
|
313
344
|
};
|
|
314
345
|
```
|
|
315
346
|
|
|
347
|
+
### Chatbot with Tapbacks
|
|
348
|
+
|
|
349
|
+
A conversational chatbot with tapback functionalities:
|
|
350
|
+
|
|
351
|
+
```
|
|
352
|
+
import "dotenv/config";
|
|
353
|
+
import OpenAI from "openai";
|
|
354
|
+
|
|
355
|
+
const openai = new OpenAI();
|
|
356
|
+
const conversations = new Map<string, Array<{ role: "user" | "assistant" | "system"; content: string }>>();
|
|
357
|
+
|
|
358
|
+
let sendTapback: ((messageGuid: string, reaction: string, userPhoneNumber: string) => Promise<boolean>) | undefined;
|
|
359
|
+
|
|
360
|
+
export default {
|
|
361
|
+
onInit: async (_sendMessage: any, _sendTapback: any) => {
|
|
362
|
+
sendTapback = _sendTapback;
|
|
363
|
+
},
|
|
364
|
+
|
|
365
|
+
invoke: async ({ message, userPhoneNumber, messageGuid }: { message: string; userPhoneNumber: string; messageGuid?: string }) => {
|
|
366
|
+
// Get or create conversation history
|
|
367
|
+
if (!conversations.has(userPhoneNumber)) {
|
|
368
|
+
conversations.set(userPhoneNumber, [{
|
|
369
|
+
role: "system",
|
|
370
|
+
content: "You are a friendly iMessage assistant. Keep responses concise. For positive messages, start with [TAPBACK:love], [TAPBACK:laugh], or [TAPBACK:like]."
|
|
371
|
+
}]);
|
|
372
|
+
}
|
|
373
|
+
const history = conversations.get(userPhoneNumber)!;
|
|
374
|
+
history.push({ role: "user", content: message });
|
|
375
|
+
|
|
376
|
+
// Call OpenAI
|
|
377
|
+
const completion = await openai.chat.completions.create({
|
|
378
|
+
model: "gpt-4o-mini",
|
|
379
|
+
messages: history,
|
|
380
|
+
});
|
|
381
|
+
|
|
382
|
+
let response = completion.choices[0]?.message?.content || "Hello!";
|
|
383
|
+
|
|
384
|
+
// Extract and send tapback if present
|
|
385
|
+
const tapbackMatch = response.match(/^\[TAPBACK:(love|like|laugh|emphasize)\]/i);
|
|
386
|
+
if (tapbackMatch && sendTapback && messageGuid) {
|
|
387
|
+
await sendTapback(messageGuid, tapbackMatch[1].toLowerCase(), userPhoneNumber);
|
|
388
|
+
response = response.replace(tapbackMatch[0], "").trim();
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
history.push({ role: "assistant", content: response });
|
|
392
|
+
return response;
|
|
393
|
+
},
|
|
394
|
+
};
|
|
395
|
+
```
|
|
396
|
+
|
|
316
397
|
## Why Flux?
|
|
317
398
|
|
|
318
399
|
Connecting agents to messaging platforms traditionally involves complex processes like setting up servers, configuring webhooks, and dealing with platform APIs. Most solutions rely on SMS or WhatsApp, which can be unintuitive for many users.
|
package/dist/index.js
CHANGED
|
@@ -52185,26 +52185,20 @@ var FluxClient = class {
|
|
|
52185
52185
|
}
|
|
52186
52186
|
return result.success;
|
|
52187
52187
|
}
|
|
52188
|
-
async sendTapback(messageGuid, reaction) {
|
|
52188
|
+
async sendTapback(messageGuid, reaction, chat) {
|
|
52189
52189
|
if (!this.client) throw new Error("Not connected. Call connect() first.");
|
|
52190
|
-
const payload = { messageGuid, reaction };
|
|
52191
|
-
console.log(`[FLUX DEBUG] sendTapback called`);
|
|
52192
|
-
console.log(`[FLUX DEBUG] Payload: ${JSON.stringify(payload)}`);
|
|
52193
|
-
console.log(`[FLUX DEBUG] Payload keys: ${Object.keys(payload).join(", ")}`);
|
|
52194
|
-
console.log(`[FLUX DEBUG] Server: ${GRPC_SERVER_ADDRESS}`);
|
|
52195
52190
|
try {
|
|
52196
|
-
|
|
52197
|
-
|
|
52198
|
-
|
|
52199
|
-
|
|
52200
|
-
|
|
52201
|
-
|
|
52191
|
+
const result = await this.client.FluxService.sendTapback({
|
|
52192
|
+
messageGuid,
|
|
52193
|
+
reaction,
|
|
52194
|
+
chat
|
|
52195
|
+
});
|
|
52196
|
+
if (!result.success) {
|
|
52202
52197
|
console.error(`[FLUX] Tapback failed: ${result.error}`);
|
|
52203
52198
|
}
|
|
52204
52199
|
return result.success;
|
|
52205
52200
|
} catch (error) {
|
|
52206
|
-
console.error(`[FLUX
|
|
52207
|
-
console.error(`[FLUX DEBUG] Error stack: ${error.stack}`);
|
|
52201
|
+
console.error(`[FLUX] Tapback error: ${error.message}`);
|
|
52208
52202
|
return false;
|
|
52209
52203
|
}
|
|
52210
52204
|
}
|
|
@@ -52422,6 +52416,37 @@ async function loadAgent(agentPath) {
|
|
|
52422
52416
|
return agent;
|
|
52423
52417
|
}
|
|
52424
52418
|
|
|
52419
|
+
// src/memory.ts
|
|
52420
|
+
var Memory = class {
|
|
52421
|
+
store = /* @__PURE__ */ new Map();
|
|
52422
|
+
// Add a message to a conversation
|
|
52423
|
+
add(phoneNumber, message) {
|
|
52424
|
+
const normalized = this.normalizePhone(phoneNumber);
|
|
52425
|
+
if (!this.store.has(normalized)) {
|
|
52426
|
+
this.store.set(normalized, []);
|
|
52427
|
+
}
|
|
52428
|
+
this.store.get(normalized).push(message);
|
|
52429
|
+
}
|
|
52430
|
+
// Get all messages for a conversation
|
|
52431
|
+
get(phoneNumber) {
|
|
52432
|
+
const normalized = this.normalizePhone(phoneNumber);
|
|
52433
|
+
return this.store.get(normalized) || [];
|
|
52434
|
+
}
|
|
52435
|
+
// Clear history for a specific conversation, or all if no phone provided
|
|
52436
|
+
clear(phoneNumber) {
|
|
52437
|
+
if (phoneNumber) {
|
|
52438
|
+
this.store.delete(this.normalizePhone(phoneNumber));
|
|
52439
|
+
} else {
|
|
52440
|
+
this.store.clear();
|
|
52441
|
+
}
|
|
52442
|
+
}
|
|
52443
|
+
// Normalize phone number format
|
|
52444
|
+
normalizePhone(phone) {
|
|
52445
|
+
return phone.replace(/[\s\-\(\)]/g, "");
|
|
52446
|
+
}
|
|
52447
|
+
};
|
|
52448
|
+
var memory = new Memory();
|
|
52449
|
+
|
|
52425
52450
|
// src/index.ts
|
|
52426
52451
|
function splitIntoMessages2(response) {
|
|
52427
52452
|
if (!response.includes("\n")) {
|
|
@@ -52469,17 +52494,29 @@ async function runLocal() {
|
|
|
52469
52494
|
input: process.stdin,
|
|
52470
52495
|
output: process.stdout
|
|
52471
52496
|
});
|
|
52497
|
+
const localPhoneNumber = "+1234567890";
|
|
52472
52498
|
const askQuestion = () => {
|
|
52473
52499
|
rl.question("You: ", async (input) => {
|
|
52474
52500
|
if (!input.trim()) {
|
|
52475
52501
|
askQuestion();
|
|
52476
52502
|
return;
|
|
52477
52503
|
}
|
|
52504
|
+
memory.add(localPhoneNumber, {
|
|
52505
|
+
role: "user",
|
|
52506
|
+
content: input,
|
|
52507
|
+
timestamp: Date.now()
|
|
52508
|
+
});
|
|
52478
52509
|
console.log("[FLUX] Thinking...");
|
|
52479
52510
|
try {
|
|
52480
52511
|
const response = await agent.invoke({
|
|
52481
52512
|
message: input,
|
|
52482
|
-
userPhoneNumber:
|
|
52513
|
+
userPhoneNumber: localPhoneNumber,
|
|
52514
|
+
history: memory.get(localPhoneNumber)
|
|
52515
|
+
});
|
|
52516
|
+
memory.add(localPhoneNumber, {
|
|
52517
|
+
role: "assistant",
|
|
52518
|
+
content: response,
|
|
52519
|
+
timestamp: Date.now()
|
|
52483
52520
|
});
|
|
52484
52521
|
const messages = splitIntoMessages2(response);
|
|
52485
52522
|
for (const msg of messages) {
|
|
@@ -52523,12 +52560,24 @@ async function runProd() {
|
|
|
52523
52560
|
console.log("[FLUX] Agent loaded successfully!");
|
|
52524
52561
|
const flux = new FluxClient(phoneNumber, token, async (message) => {
|
|
52525
52562
|
console.log(`[FLUX] Processing message from ${message.userPhoneNumber}: ${message.text}`);
|
|
52563
|
+
memory.add(message.userPhoneNumber, {
|
|
52564
|
+
role: "user",
|
|
52565
|
+
content: message.text,
|
|
52566
|
+
timestamp: Date.now(),
|
|
52567
|
+
imageBase64: message.imageBase64
|
|
52568
|
+
});
|
|
52526
52569
|
try {
|
|
52527
52570
|
const response = await agent.invoke({
|
|
52528
52571
|
message: message.text,
|
|
52529
52572
|
userPhoneNumber: message.userPhoneNumber,
|
|
52530
52573
|
messageGuid: message.messageGuid,
|
|
52531
|
-
imageBase64: message.imageBase64
|
|
52574
|
+
imageBase64: message.imageBase64,
|
|
52575
|
+
history: memory.get(message.userPhoneNumber)
|
|
52576
|
+
});
|
|
52577
|
+
memory.add(message.userPhoneNumber, {
|
|
52578
|
+
role: "assistant",
|
|
52579
|
+
content: response,
|
|
52580
|
+
timestamp: Date.now()
|
|
52532
52581
|
});
|
|
52533
52582
|
console.log(`[FLUX] Agent response: ${response}`);
|
|
52534
52583
|
return response;
|
|
@@ -52550,8 +52599,8 @@ async function runProd() {
|
|
|
52550
52599
|
}
|
|
52551
52600
|
return true;
|
|
52552
52601
|
},
|
|
52553
|
-
async (messageGuid, reaction) => {
|
|
52554
|
-
return flux.sendTapback(messageGuid, reaction);
|
|
52602
|
+
async (messageGuid, reaction, chat) => {
|
|
52603
|
+
return flux.sendTapback(messageGuid, reaction, chat);
|
|
52555
52604
|
}
|
|
52556
52605
|
);
|
|
52557
52606
|
}
|