import { randomUUID } from "node:crypto";
import { register } from "@arizeai/phoenix-otel";
/**
* Initialize Phoenix tracing for the CLI agent
* This should be imported before any AI SDK calls
*/
const provider = register({
projectName: "cli-agent-starter-kit",
// Use local Phoenix by default, can be overridden with PHOENIX_COLLECTOR_ENDPOINT
url: process.env.PHOENIX_COLLECTOR_ENDPOINT || "http://localhost:6006",
// API key for Phoenix Cloud (optional)
apiKey: process.env.PHOENIX_API_KEY,
// Use batch processing for better performance
batch: true,
});
/**
* Generate a unique session ID for this CLI session
* All traces created during this session will share this ID
*
* Use with withSpan from @arizeai/openinference-core:
* const handler = withSpan(async () => {...}, {
* name: "interaction",
* kind: "CHAIN",
* attributes: { "session.id": SESSION_ID }
* });
*/
export const SESSION_ID = randomUUID();
/**
* Flush all pending spans before the process exits
* This is critical for CLI applications that exit quickly
*/
export async function flush() {
try {
await provider.shutdown();
// Silent shutdown - spans are flushed successfully
} catch (error) {
// Always log errors
// eslint-disable-next-line no-console
console.error("Error flushing Phoenix spans:", error);
}
}
// Handle graceful shutdown on normal exit
process.on("beforeExit", async () => {
await flush();
});
// Handle SIGINT (Ctrl+C)
process.on("SIGINT", async () => {
await flush();
process.exit(0);
});
// Handle SIGTERM
process.on("SIGTERM", async () => {
await flush();
process.exit(0);
});
// Handle uncaught exceptions
process.on("uncaughtException", async (error) => {
// eslint-disable-next-line no-console
console.error("Uncaught exception:", error);
await flush();
process.exit(1);
});
// Handle unhandled promise rejections
process.on("unhandledRejection", async (reason) => {
// eslint-disable-next-line no-console
console.error("Unhandled rejection:", reason);
await flush();
process.exit(1);
});