@cephalization/phoenix-insight 1.0.3 → 1.1.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.
- package/README.md +19 -0
- package/dist/cli.js +69 -10
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -6,6 +6,25 @@ Phoenix Insight brings AI-powered analysis to your [Phoenix](https://github.com/
|
|
|
6
6
|
|
|
7
7
|
This filesystem-native approach provides transparency that traditional APIs can't match. Every query the agent runs is visible and reproducible. You can inspect the exact files it reads, copy its commands, and run them yourself. The data is just files, and the analysis is just bash, making AI-driven observability debuggable, auditable, and extensible with any tool in your Unix toolkit.
|
|
8
8
|
|
|
9
|
+
## Requirements
|
|
10
|
+
|
|
11
|
+
- **Node.js v22 or newer** - Required for the CLI to run
|
|
12
|
+
- **Anthropic API key** - Required for the AI agent
|
|
13
|
+
|
|
14
|
+
Set your Anthropic API key before running:
|
|
15
|
+
|
|
16
|
+
```bash
|
|
17
|
+
export ANTHROPIC_API_KEY=sk-ant-api03-...
|
|
18
|
+
```
|
|
19
|
+
|
|
20
|
+
Or add it to your shell profile for persistence:
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
echo 'export ANTHROPIC_API_KEY=sk-ant-api03-...' >> ~/.zshrc # or ~/.bashrc
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
You can get an API key from [console.anthropic.com](https://console.anthropic.com/).
|
|
27
|
+
|
|
9
28
|
## Installation
|
|
10
29
|
|
|
11
30
|
```bash
|
package/dist/cli.js
CHANGED
|
@@ -2709,6 +2709,7 @@ Make sure to build the UI package first: pnpm --filter @cephalization/phoenix-in
|
|
|
2709
2709
|
);
|
|
2710
2710
|
}
|
|
2711
2711
|
return new Promise((resolve2, reject) => {
|
|
2712
|
+
const activeConnections = /* @__PURE__ */ new Set();
|
|
2712
2713
|
const httpServer = createServer((req, res) => {
|
|
2713
2714
|
const urlPath = req.url ?? "/";
|
|
2714
2715
|
let filePath = sanitizePath(urlPath, distPath);
|
|
@@ -2760,6 +2761,12 @@ Make sure to build the UI package first: pnpm --filter @cephalization/phoenix-in
|
|
|
2760
2761
|
res.end("Internal Server Error");
|
|
2761
2762
|
});
|
|
2762
2763
|
});
|
|
2764
|
+
httpServer.on("connection", (socket) => {
|
|
2765
|
+
activeConnections.add(socket);
|
|
2766
|
+
socket.on("close", () => {
|
|
2767
|
+
activeConnections.delete(socket);
|
|
2768
|
+
});
|
|
2769
|
+
});
|
|
2763
2770
|
httpServer.on("error", (err) => {
|
|
2764
2771
|
reject(err);
|
|
2765
2772
|
});
|
|
@@ -2781,6 +2788,12 @@ Make sure to build the UI package first: pnpm --filter @cephalization/phoenix-in
|
|
|
2781
2788
|
}
|
|
2782
2789
|
});
|
|
2783
2790
|
});
|
|
2791
|
+
},
|
|
2792
|
+
forceClose() {
|
|
2793
|
+
for (const socket of activeConnections) {
|
|
2794
|
+
socket.destroy();
|
|
2795
|
+
}
|
|
2796
|
+
activeConnections.clear();
|
|
2784
2797
|
}
|
|
2785
2798
|
});
|
|
2786
2799
|
});
|
|
@@ -2955,6 +2968,19 @@ var PhoenixWebSocketServer = class {
|
|
|
2955
2968
|
});
|
|
2956
2969
|
});
|
|
2957
2970
|
}
|
|
2971
|
+
/**
|
|
2972
|
+
* Force terminate all WebSocket connections immediately.
|
|
2973
|
+
* Use this when graceful close doesn't complete in time.
|
|
2974
|
+
*/
|
|
2975
|
+
forceClose() {
|
|
2976
|
+
if (!this.wss) {
|
|
2977
|
+
return;
|
|
2978
|
+
}
|
|
2979
|
+
for (const client of this.clients) {
|
|
2980
|
+
client.terminate();
|
|
2981
|
+
}
|
|
2982
|
+
this.clients.clear();
|
|
2983
|
+
}
|
|
2958
2984
|
};
|
|
2959
2985
|
function createWebSocketServer(httpServer, options) {
|
|
2960
2986
|
const server = new PhoenixWebSocketServer(options);
|
|
@@ -3317,6 +3343,26 @@ function formatBashCommand(command) {
|
|
|
3317
3343
|
return firstLine.substring(0, 80) + (firstLine.length > 80 ? "..." : "");
|
|
3318
3344
|
}
|
|
3319
3345
|
}
|
|
3346
|
+
function ensureAnthropicApiKey() {
|
|
3347
|
+
if (!process.env.ANTHROPIC_API_KEY) {
|
|
3348
|
+
console.error(
|
|
3349
|
+
"\n\u274C Error: Missing ANTHROPIC_API_KEY environment variable\n"
|
|
3350
|
+
);
|
|
3351
|
+
console.error("The Anthropic API key is required to run the AI agent.\n");
|
|
3352
|
+
console.error("To fix this, set the environment variable:\n");
|
|
3353
|
+
console.error(" export ANTHROPIC_API_KEY=sk-ant-api03-...\n");
|
|
3354
|
+
console.error(
|
|
3355
|
+
"Or add it to your shell profile (~/.zshrc, ~/.bashrc, etc.):\n"
|
|
3356
|
+
);
|
|
3357
|
+
console.error(
|
|
3358
|
+
" echo 'export ANTHROPIC_API_KEY=sk-ant-api03-...' >> ~/.zshrc\n"
|
|
3359
|
+
);
|
|
3360
|
+
console.error(
|
|
3361
|
+
"You can get an API key from: https://console.anthropic.com/\n"
|
|
3362
|
+
);
|
|
3363
|
+
process.exit(1);
|
|
3364
|
+
}
|
|
3365
|
+
}
|
|
3320
3366
|
function handleError(error, context) {
|
|
3321
3367
|
console.error(`
|
|
3322
3368
|
\u274C Error ${context}:`);
|
|
@@ -3401,16 +3447,17 @@ Configuration:
|
|
|
3401
3447
|
Set PHOENIX_INSIGHT_CONFIG env var to override the default config location.
|
|
3402
3448
|
|
|
3403
3449
|
Examples:
|
|
3404
|
-
$ phoenix-insight
|
|
3405
|
-
$ phoenix-insight "What are the slowest traces?"
|
|
3406
|
-
$ phoenix-insight --interactive
|
|
3407
|
-
$ phoenix-insight --local "Show me error patterns"
|
|
3408
|
-
$ phoenix-insight --local --stream "Analyze recent experiments"
|
|
3409
|
-
$ phoenix-insight --config ./my-config.json "Analyze traces"
|
|
3410
|
-
$ phoenix-insight ui
|
|
3411
|
-
$ phoenix-insight ui --port 8080
|
|
3412
|
-
$ phoenix-insight ui --no-open
|
|
3413
|
-
$
|
|
3450
|
+
$ phoenix-insight # Start interactive mode
|
|
3451
|
+
$ phoenix-insight "What are the slowest traces?" # Single query (sandbox mode)
|
|
3452
|
+
$ phoenix-insight --interactive # Explicitly start interactive mode
|
|
3453
|
+
$ phoenix-insight --local "Show me error patterns" # Local mode with persistence
|
|
3454
|
+
$ phoenix-insight --local --stream "Analyze recent experiments" # Local mode with streaming
|
|
3455
|
+
$ phoenix-insight --config ./my-config.json "Analyze traces" # Use custom config file
|
|
3456
|
+
$ phoenix-insight ui # Start web UI on localhost:6007
|
|
3457
|
+
$ phoenix-insight ui --port 8080 # Start web UI on custom port
|
|
3458
|
+
$ phoenix-insight ui --no-open # Start web UI without opening browser
|
|
3459
|
+
$ opencode run "Analyze my spans" -f $(pxi snapshot latest)/_context.md # Analyze phoenix data with OpenCode agent
|
|
3460
|
+
$ phoenix-insight help # Show this help message
|
|
3414
3461
|
`
|
|
3415
3462
|
).hook("preAction", async (thisCommand) => {
|
|
3416
3463
|
const opts = thisCommand.opts();
|
|
@@ -3560,6 +3607,7 @@ program.argument("[query]", "Query to run against Phoenix data").option(
|
|
|
3560
3607
|
await runInteractiveMode();
|
|
3561
3608
|
return;
|
|
3562
3609
|
}
|
|
3610
|
+
ensureAnthropicApiKey();
|
|
3563
3611
|
if (config.trace) {
|
|
3564
3612
|
initializeObservability({
|
|
3565
3613
|
enabled: true,
|
|
@@ -3682,6 +3730,7 @@ function openBrowser(url) {
|
|
|
3682
3730
|
});
|
|
3683
3731
|
}
|
|
3684
3732
|
async function runUIServer(options) {
|
|
3733
|
+
ensureAnthropicApiKey();
|
|
3685
3734
|
const config = getConfig();
|
|
3686
3735
|
const port = options.port ?? 6007;
|
|
3687
3736
|
const shouldOpen = options.open !== false;
|
|
@@ -3766,21 +3815,30 @@ async function runUIServer(options) {
|
|
|
3766
3815
|
openBrowser(url);
|
|
3767
3816
|
}
|
|
3768
3817
|
let isShuttingDown = false;
|
|
3818
|
+
const SHUTDOWN_TIMEOUT_MS = 3e3;
|
|
3769
3819
|
const shutdown = async (signal) => {
|
|
3770
3820
|
if (isShuttingDown) return;
|
|
3771
3821
|
isShuttingDown = true;
|
|
3772
3822
|
console.log(`
|
|
3773
3823
|
|
|
3774
3824
|
\u{1F4E5} Received ${signal}, shutting down gracefully...`);
|
|
3825
|
+
const forceExitTimeout = setTimeout(() => {
|
|
3826
|
+
console.log("\u23F1\uFE0F Shutdown timeout reached, forcing exit...");
|
|
3827
|
+
wsServer.forceClose();
|
|
3828
|
+
uiServer.forceClose();
|
|
3829
|
+
process.exit(0);
|
|
3830
|
+
}, SHUTDOWN_TIMEOUT_MS);
|
|
3775
3831
|
try {
|
|
3776
3832
|
await wsServer.close();
|
|
3777
3833
|
await uiServer.close();
|
|
3778
3834
|
await sessionManager.cleanup();
|
|
3779
3835
|
await mode.cleanup();
|
|
3780
3836
|
await shutdownObservability();
|
|
3837
|
+
clearTimeout(forceExitTimeout);
|
|
3781
3838
|
console.log("\u{1F44B} Server stopped. Goodbye!");
|
|
3782
3839
|
process.exit(0);
|
|
3783
3840
|
} catch (error) {
|
|
3841
|
+
clearTimeout(forceExitTimeout);
|
|
3784
3842
|
console.error("Error during shutdown:", error);
|
|
3785
3843
|
process.exit(1);
|
|
3786
3844
|
}
|
|
@@ -3794,6 +3852,7 @@ async function runUIServer(options) {
|
|
|
3794
3852
|
}
|
|
3795
3853
|
}
|
|
3796
3854
|
async function runInteractiveMode() {
|
|
3855
|
+
ensureAnthropicApiKey();
|
|
3797
3856
|
const config = getConfig();
|
|
3798
3857
|
console.log("\u{1F680} Phoenix Insight Interactive Mode");
|
|
3799
3858
|
console.log(
|