@photon-ai/flux 0.3.2 → 0.3.3
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 +44 -15
- package/dist/index.js +121 -38
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -31,8 +31,8 @@ Flux is an open-sourced CLI tool that lets developers build and deploy LangChain
|
|
|
31
31
|
## Installation
|
|
32
32
|
|
|
33
33
|
```
|
|
34
|
-
npm install @photon-
|
|
35
|
-
bun add @photon-
|
|
34
|
+
npm install @photon-ai/flux
|
|
35
|
+
bun add @photon-ai/flux
|
|
36
36
|
```
|
|
37
37
|
|
|
38
38
|
---
|
|
@@ -41,13 +41,13 @@ bun add @photon-cli/flux
|
|
|
41
41
|
|
|
42
42
|
| Command | Description |
|
|
43
43
|
|---------|-------------|
|
|
44
|
-
| `npx @photon-
|
|
45
|
-
| `npx @photon-
|
|
46
|
-
| `npx @photon-
|
|
47
|
-
| `npx @photon-
|
|
48
|
-
| `npx @photon-
|
|
49
|
-
| `npx @photon-
|
|
50
|
-
| `npx @photon-
|
|
44
|
+
| `npx @photon-ai/flux` | Show help |
|
|
45
|
+
| `npx @photon-ai/flux whoami` | Check account |
|
|
46
|
+
| `npx @photon-ai/flux login` | Login and signup|
|
|
47
|
+
| `npx @photon-ai/flux logout` | Logout |
|
|
48
|
+
| `npx @photon-ai/flux run --local` | Start the development server (local mode) |
|
|
49
|
+
| `npx @photon-ai/flux run --prod` | Start with live iMessage bridge |
|
|
50
|
+
| `npx @photon-ai/flux validate` | Check your code for errors |
|
|
51
51
|
|
|
52
52
|
---
|
|
53
53
|
|
|
@@ -57,6 +57,15 @@ Message +16286298650 with you phone number to text the LangChain agent that you
|
|
|
57
57
|
|
|
58
58
|
---
|
|
59
59
|
|
|
60
|
+
## Log in
|
|
61
|
+
|
|
62
|
+
Authentication is based on iMessage:
|
|
63
|
+
- The user (client) sends a code to the Flux number to prove phone ownership.
|
|
64
|
+
- The server generates a UUID per login attempt. It then waits for the iMessage text from the client with the UUID. Once verified, it will issue a token.
|
|
65
|
+
- Credentials (token, phone, timestamp) are saved to credentials.json. This way, the user only has to log in once.
|
|
66
|
+
|
|
67
|
+
---
|
|
68
|
+
|
|
60
69
|
## Usage
|
|
61
70
|
|
|
62
71
|
#### Step 1: Create LangChain Agent
|
|
@@ -77,11 +86,31 @@ export default {
|
|
|
77
86
|
Authenticate with your phone number and iMessage:
|
|
78
87
|
|
|
79
88
|
```
|
|
80
|
-
npx @photon-
|
|
89
|
+
npx @photon-ai/flux login
|
|
81
90
|
|
|
82
91
|
Enter your phone number (e.g. +15551234567): +1234567890
|
|
83
|
-
[FLUX]
|
|
84
|
-
[FLUX]
|
|
92
|
+
[FLUX] Requesting verification code...
|
|
93
|
+
[FLUX] Verification code: d33gwu
|
|
94
|
+
[FLUX] Opening iMessage to send verification code...
|
|
95
|
+
[FLUX] Please send the code "d33gwu" to +16286298650 via iMessage.
|
|
96
|
+
[FLUX] Waiting for verification...
|
|
97
|
+
[FLUX] Successfully logged in as +1234567890
|
|
98
|
+
```
|
|
99
|
+
|
|
100
|
+
If already logged in:
|
|
101
|
+
|
|
102
|
+
```
|
|
103
|
+
npx @photon-ai/flux login
|
|
104
|
+
|
|
105
|
+
[FLUX] Already logged in as +1234567890
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Log out:
|
|
109
|
+
|
|
110
|
+
```
|
|
111
|
+
npx @photon-ai/flux logout
|
|
112
|
+
|
|
113
|
+
[FLUX] Logged out.
|
|
85
114
|
```
|
|
86
115
|
|
|
87
116
|
### Step 3: Validate
|
|
@@ -89,7 +118,7 @@ Enter your phone number (e.g. +15551234567): +1234567890
|
|
|
89
118
|
Validate that your agent works and exports correctly:
|
|
90
119
|
|
|
91
120
|
```
|
|
92
|
-
npx @photon-
|
|
121
|
+
npx @photon-ai/flux validate
|
|
93
122
|
|
|
94
123
|
[FLUX] Validating agent.ts...
|
|
95
124
|
[FLUX] Agent is valid!
|
|
@@ -100,7 +129,7 @@ npx @photon-cli/flux validate
|
|
|
100
129
|
Test your agent through your terminal (no iMessage connection):
|
|
101
130
|
|
|
102
131
|
```
|
|
103
|
-
npx @photon-
|
|
132
|
+
npx @photon-ai/flux run --local
|
|
104
133
|
|
|
105
134
|
[FLUX] Welcome to Flux! Your agent is loaded.
|
|
106
135
|
[FLUX] Type a message to test it. Press Ctrl+C to exit.
|
|
@@ -115,7 +144,7 @@ Agent: Hello! How can I assist you today?
|
|
|
115
144
|
Run your agent locally and connect it to the iMessage bridge. When you message the FLUX number with your phone number, you will receive the output of your LangChain agent:
|
|
116
145
|
|
|
117
146
|
```
|
|
118
|
-
npx @photon-
|
|
147
|
+
npx @photon-ai/flux run --prod
|
|
119
148
|
|
|
120
149
|
[FLUX] Loading agent from agent.ts...
|
|
121
150
|
[FLUX] Agent loaded successfully!
|
package/dist/index.js
CHANGED
|
@@ -11,6 +11,7 @@ var p3 = require('net');
|
|
|
11
11
|
var util = require('util');
|
|
12
12
|
var worker_threads = require('worker_threads');
|
|
13
13
|
var readline = require('readline');
|
|
14
|
+
var child_process = require('child_process');
|
|
14
15
|
|
|
15
16
|
var _documentCurrentScript = typeof document !== 'undefined' ? document.currentScript : null;
|
|
16
17
|
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
@@ -58169,12 +58170,17 @@ async function createGrpcClient(address, grpcOptionsOrServiceImpls, ...serviceIm
|
|
|
58169
58170
|
|
|
58170
58171
|
// src/service.ts
|
|
58171
58172
|
var FluxService = class extends Service("FluxService") {
|
|
58173
|
+
// Message handling
|
|
58172
58174
|
sendMessage = server();
|
|
58173
58175
|
messageStream = bidi();
|
|
58174
58176
|
registerAgent = server();
|
|
58175
58177
|
unregisterAgent = server();
|
|
58176
58178
|
onIncomingMessage = client();
|
|
58177
|
-
|
|
58179
|
+
// Authentication - iMessage verification flow
|
|
58180
|
+
getDynamicCode = server();
|
|
58181
|
+
waitingVerified = server();
|
|
58182
|
+
validateToken = server();
|
|
58183
|
+
revokeToken = server();
|
|
58178
58184
|
};
|
|
58179
58185
|
|
|
58180
58186
|
// src/flux-client.ts
|
|
@@ -58182,9 +58188,11 @@ var GRPC_SERVER_ADDRESS = process.env.FLUX_SERVER_ADDRESS || "fluxy.photon.codes
|
|
|
58182
58188
|
var FluxClient = class {
|
|
58183
58189
|
client = null;
|
|
58184
58190
|
phoneNumber;
|
|
58191
|
+
token;
|
|
58185
58192
|
onMessage;
|
|
58186
|
-
constructor(phoneNumber, onMessage) {
|
|
58193
|
+
constructor(phoneNumber, token, onMessage) {
|
|
58187
58194
|
this.phoneNumber = phoneNumber.replace(/[\s\-\(\)]/g, "");
|
|
58195
|
+
this.token = token;
|
|
58188
58196
|
this.onMessage = onMessage;
|
|
58189
58197
|
}
|
|
58190
58198
|
async connect() {
|
|
@@ -58198,7 +58206,7 @@ var FluxClient = class {
|
|
|
58198
58206
|
}
|
|
58199
58207
|
async register() {
|
|
58200
58208
|
if (!this.client) throw new Error("Not connected. Call connect() first.");
|
|
58201
|
-
const result = await this.client.FluxService.registerAgent(this.phoneNumber);
|
|
58209
|
+
const result = await this.client.FluxService.registerAgent(this.phoneNumber, this.token);
|
|
58202
58210
|
if (result.success) {
|
|
58203
58211
|
console.log(`[FLUX] Registered agent for ${this.phoneNumber}`);
|
|
58204
58212
|
this.startMessageStream();
|
|
@@ -58245,8 +58253,9 @@ var FluxClient = class {
|
|
|
58245
58253
|
};
|
|
58246
58254
|
var GRPC_SERVER_ADDRESS2 = process.env.FLUX_SERVER_ADDRESS || "fluxy.photon.codes:443";
|
|
58247
58255
|
var CONFIG_DIR = m3__namespace.join(process.env.HOME || "~", ".flux");
|
|
58248
|
-
var CONFIG_FILE = m3__namespace.join(CONFIG_DIR, "
|
|
58249
|
-
|
|
58256
|
+
var CONFIG_FILE = m3__namespace.join(CONFIG_DIR, "credentials.json");
|
|
58257
|
+
var VERIFICATION_NUMBER = "+16286298650";
|
|
58258
|
+
function loadCredentials() {
|
|
58250
58259
|
try {
|
|
58251
58260
|
if (U__namespace.existsSync(CONFIG_FILE)) {
|
|
58252
58261
|
return JSON.parse(U__namespace.readFileSync(CONFIG_FILE, "utf-8"));
|
|
@@ -58255,13 +58264,13 @@ function loadConfig() {
|
|
|
58255
58264
|
}
|
|
58256
58265
|
return {};
|
|
58257
58266
|
}
|
|
58258
|
-
function
|
|
58267
|
+
function saveCredentials(credentials) {
|
|
58259
58268
|
if (!U__namespace.existsSync(CONFIG_DIR)) {
|
|
58260
58269
|
U__namespace.mkdirSync(CONFIG_DIR, { recursive: true });
|
|
58261
58270
|
}
|
|
58262
|
-
U__namespace.writeFileSync(CONFIG_FILE, JSON.stringify(
|
|
58271
|
+
U__namespace.writeFileSync(CONFIG_FILE, JSON.stringify(credentials, null, 2));
|
|
58263
58272
|
}
|
|
58264
|
-
function
|
|
58273
|
+
function clearCredentials() {
|
|
58265
58274
|
if (U__namespace.existsSync(CONFIG_FILE)) {
|
|
58266
58275
|
U__namespace.unlinkSync(CONFIG_FILE);
|
|
58267
58276
|
}
|
|
@@ -58278,50 +58287,124 @@ async function prompt(question) {
|
|
|
58278
58287
|
});
|
|
58279
58288
|
});
|
|
58280
58289
|
}
|
|
58290
|
+
function openIMessage(to, body) {
|
|
58291
|
+
return new Promise((resolve, reject) => {
|
|
58292
|
+
const url = `sms:${to}&body=${encodeURIComponent(body)}`;
|
|
58293
|
+
const command = process.platform === "darwin" ? `open "${url}"` : process.platform === "win32" ? `start "" "${url}"` : `xdg-open "${url}"`;
|
|
58294
|
+
child_process.exec(command, (error) => {
|
|
58295
|
+
if (error) {
|
|
58296
|
+
reject(error);
|
|
58297
|
+
} else {
|
|
58298
|
+
resolve();
|
|
58299
|
+
}
|
|
58300
|
+
});
|
|
58301
|
+
});
|
|
58302
|
+
}
|
|
58303
|
+
async function createGrpcClientWithRetry() {
|
|
58304
|
+
const clientImpl = FluxService.Client({
|
|
58305
|
+
async onIncomingMessage() {
|
|
58306
|
+
return { received: true };
|
|
58307
|
+
}
|
|
58308
|
+
});
|
|
58309
|
+
return await createGrpcClient(GRPC_SERVER_ADDRESS2, clientImpl);
|
|
58310
|
+
}
|
|
58281
58311
|
async function login() {
|
|
58312
|
+
const existing = loadCredentials();
|
|
58313
|
+
if (existing.token) {
|
|
58314
|
+
try {
|
|
58315
|
+
const client2 = await createGrpcClientWithRetry();
|
|
58316
|
+
const result = await client2.FluxService.validateToken(existing.token);
|
|
58317
|
+
if (result.valid) {
|
|
58318
|
+
console.log(`[FLUX] Already logged in as ${result.phone}`);
|
|
58319
|
+
return result.phone;
|
|
58320
|
+
}
|
|
58321
|
+
} catch {
|
|
58322
|
+
}
|
|
58323
|
+
clearCredentials();
|
|
58324
|
+
}
|
|
58282
58325
|
const phoneNumber = await prompt("Enter your phone number (e.g. +15551234567): ");
|
|
58283
58326
|
if (!phoneNumber.match(/^\+?[0-9]{10,15}$/)) {
|
|
58284
|
-
console.error("Invalid phone number format.");
|
|
58327
|
+
console.error("[FLUX] Invalid phone number format.");
|
|
58285
58328
|
process.exit(1);
|
|
58286
58329
|
}
|
|
58287
|
-
|
|
58330
|
+
const normalizedPhone = phoneNumber.startsWith("+") ? phoneNumber : `+${phoneNumber}`;
|
|
58331
|
+
console.log("[FLUX] Requesting verification code...");
|
|
58288
58332
|
try {
|
|
58289
|
-
const
|
|
58290
|
-
|
|
58291
|
-
|
|
58292
|
-
|
|
58293
|
-
|
|
58294
|
-
const client2 = await createGrpcClient(GRPC_SERVER_ADDRESS2, clientImpl);
|
|
58295
|
-
const result = await client2.FluxService.validateUser(phoneNumber);
|
|
58296
|
-
if (result.error) {
|
|
58297
|
-
console.error(`[FLUX] Login failed: ${result.error}`);
|
|
58333
|
+
const client2 = await createGrpcClientWithRetry();
|
|
58334
|
+
const clientId = crypto.randomUUID();
|
|
58335
|
+
const codeResult = await client2.FluxService.getDynamicCode(clientId, normalizedPhone);
|
|
58336
|
+
if (codeResult.error) {
|
|
58337
|
+
console.error(`[FLUX] Failed to get verification code: ${codeResult.error}`);
|
|
58298
58338
|
process.exit(1);
|
|
58299
58339
|
}
|
|
58300
|
-
|
|
58301
|
-
|
|
58302
|
-
|
|
58303
|
-
|
|
58340
|
+
const code = codeResult.code;
|
|
58341
|
+
console.log(`[FLUX] Verification code: ${code}`);
|
|
58342
|
+
console.log(`[FLUX] Opening iMessage to send verification code...`);
|
|
58343
|
+
try {
|
|
58344
|
+
await openIMessage(VERIFICATION_NUMBER, code);
|
|
58345
|
+
console.log(`[FLUX] Please send the code "${code}" to ${VERIFICATION_NUMBER} via iMessage.`);
|
|
58346
|
+
} catch {
|
|
58347
|
+
console.log(`[FLUX] Could not open iMessage automatically.`);
|
|
58348
|
+
console.log(`[FLUX] Please manually send "${code}" to ${VERIFICATION_NUMBER} via iMessage.`);
|
|
58304
58349
|
}
|
|
58305
|
-
|
|
58306
|
-
|
|
58307
|
-
|
|
58350
|
+
console.log("[FLUX] Waiting for verification...");
|
|
58351
|
+
const verifyResult = await client2.FluxService.waitingVerified(clientId);
|
|
58352
|
+
if (verifyResult.error || !verifyResult.token) {
|
|
58353
|
+
console.error(`[FLUX] Verification failed: ${verifyResult.error || "No token received"}`);
|
|
58354
|
+
process.exit(1);
|
|
58355
|
+
}
|
|
58356
|
+
const credentials = {
|
|
58357
|
+
token: verifyResult.token,
|
|
58358
|
+
phone: normalizedPhone,
|
|
58359
|
+
authenticatedAt: (/* @__PURE__ */ new Date()).toISOString()
|
|
58360
|
+
};
|
|
58361
|
+
saveCredentials(credentials);
|
|
58362
|
+
console.log(`[FLUX] Successfully logged in as ${normalizedPhone}`);
|
|
58363
|
+
return normalizedPhone;
|
|
58308
58364
|
} catch (error) {
|
|
58309
58365
|
console.error(`[FLUX] Failed to connect to server: ${error.message}`);
|
|
58310
58366
|
console.error(`[FLUX] Make sure the Flux server is running at ${GRPC_SERVER_ADDRESS2}`);
|
|
58311
58367
|
process.exit(1);
|
|
58312
58368
|
}
|
|
58313
58369
|
}
|
|
58314
|
-
function logout() {
|
|
58315
|
-
|
|
58370
|
+
async function logout() {
|
|
58371
|
+
const credentials = loadCredentials();
|
|
58372
|
+
if (credentials.token) {
|
|
58373
|
+
try {
|
|
58374
|
+
const client2 = await createGrpcClientWithRetry();
|
|
58375
|
+
await client2.FluxService.revokeToken(credentials.token);
|
|
58376
|
+
} catch {
|
|
58377
|
+
}
|
|
58378
|
+
}
|
|
58379
|
+
clearCredentials();
|
|
58316
58380
|
console.log("[FLUX] Logged out.");
|
|
58317
58381
|
}
|
|
58318
|
-
async function
|
|
58319
|
-
const
|
|
58320
|
-
if (
|
|
58321
|
-
|
|
58382
|
+
async function getAuthToken() {
|
|
58383
|
+
const credentials = loadCredentials();
|
|
58384
|
+
if (credentials.token && credentials.phone) {
|
|
58385
|
+
try {
|
|
58386
|
+
const client2 = await createGrpcClientWithRetry();
|
|
58387
|
+
const result = await client2.FluxService.validateToken(credentials.token);
|
|
58388
|
+
if (result.valid) {
|
|
58389
|
+
return { token: credentials.token, phone: result.phone };
|
|
58390
|
+
}
|
|
58391
|
+
} catch {
|
|
58392
|
+
}
|
|
58393
|
+
console.log("[FLUX] Session expired. Please log in again.");
|
|
58394
|
+
clearCredentials();
|
|
58322
58395
|
}
|
|
58323
58396
|
console.log("[FLUX] Not logged in.");
|
|
58324
|
-
|
|
58397
|
+
const phone = await login();
|
|
58398
|
+
const newCredentials = loadCredentials();
|
|
58399
|
+
if (!newCredentials.token) {
|
|
58400
|
+
console.error("[FLUX] Login failed.");
|
|
58401
|
+
process.exit(1);
|
|
58402
|
+
}
|
|
58403
|
+
return { token: newCredentials.token, phone };
|
|
58404
|
+
}
|
|
58405
|
+
function loadConfig() {
|
|
58406
|
+
const credentials = loadCredentials();
|
|
58407
|
+
return { phoneNumber: credentials.phone };
|
|
58325
58408
|
}
|
|
58326
58409
|
var AGENT_FILE_NAME = "agent.ts";
|
|
58327
58410
|
var tsxRegistered = false;
|
|
@@ -58439,7 +58522,7 @@ async function runLocal() {
|
|
|
58439
58522
|
askQuestion();
|
|
58440
58523
|
}
|
|
58441
58524
|
async function runProd() {
|
|
58442
|
-
const phoneNumber = await
|
|
58525
|
+
const { token, phone: phoneNumber } = await getAuthToken();
|
|
58443
58526
|
const agentPath = findAgentFile();
|
|
58444
58527
|
if (!agentPath) {
|
|
58445
58528
|
console.error("[FLUX] No agent.ts or agent.js found in current directory.");
|
|
@@ -58454,7 +58537,7 @@ async function runProd() {
|
|
|
58454
58537
|
console.log(`[FLUX] Loading agent from ${m3__namespace.basename(agentPath)}...`);
|
|
58455
58538
|
const agent = await loadAgent(agentPath);
|
|
58456
58539
|
console.log("[FLUX] Agent loaded successfully!");
|
|
58457
|
-
const flux = new FluxClient(phoneNumber, async (message) => {
|
|
58540
|
+
const flux = new FluxClient(phoneNumber, token, async (message) => {
|
|
58458
58541
|
console.log(`[FLUX] Processing message from ${message.userPhoneNumber}: ${message.text}`);
|
|
58459
58542
|
try {
|
|
58460
58543
|
const response = await agent.invoke({
|
|
@@ -58488,10 +58571,10 @@ async function main() {
|
|
|
58488
58571
|
switch (command) {
|
|
58489
58572
|
case "login":
|
|
58490
58573
|
await login();
|
|
58491
|
-
|
|
58574
|
+
process.exit(0);
|
|
58492
58575
|
case "logout":
|
|
58493
|
-
logout();
|
|
58494
|
-
|
|
58576
|
+
await logout();
|
|
58577
|
+
process.exit(0);
|
|
58495
58578
|
case "run":
|
|
58496
58579
|
if (flag === "--local") {
|
|
58497
58580
|
await runLocal();
|