UNPKG

askexperts

Version:

AskExperts SDK: build and use AI experts - ask them questions and pay with bitcoin on an open protocol

143 lines 6.36 kB
import { SimplePool } from "nostr-tools"; import { debugError, debugExpert, enableAllDebug, enableErrorDebug, } from "../../../common/debug.js"; import { createDBClientForCommands } from "../utils.js"; import { ExpertWorker } from "../../../experts/worker/ExpertWorker.js"; // We no longer need the RunningExpert interface as it's encapsulated in ExpertWorker /** * Run all enabled experts from the database * * @param options Command options */ export async function runAllExperts(options) { // Enable debug if requested if (options.debug) enableAllDebug(); else enableErrorDebug(); // Check interval in milliseconds (default: 30 seconds) const checkInterval = options.interval || 30000; // Expert start delay in milliseconds (default: 1000ms) const startDelay = options.startDelay || 1000; try { debugExpert("Initializing shared resources..."); // Only use local DB for this command const db = await createDBClientForCommands({}); // Create a shared pool const pool = new SimplePool(); // Get RAG host and port from environment const ragHost = process.env.CHROMA_HOST; const ragPort = process.env.CHROMA_PORT ? parseInt(process.env.CHROMA_PORT) : undefined; // We'll create docstore clients on demand when starting each expert // This allows us to support both local and remote docstores // Create ExpertWorker const worker = new ExpertWorker(pool, ragHost, ragPort); // Create a promise that resolves when SIGINT/SIGTERM is received const globalStopPromise = new Promise((resolve) => { const sigHandler = () => { debugExpert("\nReceived SIGINT/SIGTERM. Shutting down all experts..."); resolve(); // Final cleaning after all experts are stopped setTimeout(async () => { await worker[Symbol.asyncDispose](); pool.destroy(); debugExpert("All experts shut down and resources cleaned up"); process.exit(0); }, 1000); }; // SIGINT and SIGTERM process.on("SIGINT", sigHandler); process.on("SIGTERM", sigHandler); }); // Function to start an expert async function startExpert(expert) { try { // Get wallet for the expert using the wallet client const wallet = await db.getWallet(expert.wallet_id); if (!wallet) { throw new Error(`Wallet with ID ${expert.wallet_id} not found for expert ${expert.nickname}`); } const nwcString = wallet.nwc; // Start the expert await worker.startExpert(expert, nwcString); // Pause a bit to avoid overloading relays await new Promise((ok) => setTimeout(ok, startDelay)); } catch (error) { debugError(`Error starting expert ${expert.nickname} (${expert.pubkey}):`, error); } } // Function to check for experts to start/stop async function checkExperts() { const experts = await db.listExperts(); // Get list of running experts const runningPubkeys = Array.from(worker.getRunningExpertPubkeys()); // Find experts to start (enabled and not already running) const expertsToStart = experts.filter((expert) => !expert.disabled && !runningPubkeys.includes(expert.pubkey)); // Find experts to stop (disabled or no longer in DB) const expertsToStop = runningPubkeys.filter((pubkey) => { const expert = experts.find((e) => e.pubkey === pubkey); return !expert || expert.disabled; }); // Start new experts for (const expert of expertsToStart) { debugExpert(`Starting new expert ${expert.nickname} (${expert.pubkey})`); await startExpert(expert); } // Stop disabled experts for (const pubkey of expertsToStop) { debugExpert(`Stopping expert ${pubkey} (disabled or removed)`); worker.stopExpert(pubkey); } } // Initial check for experts to start await checkExperts(); // Set up interval to periodically check for new/disabled experts const intervalId = setInterval(checkExperts, checkInterval); // When global stop is triggered, stop all experts globalStopPromise.then(async () => { clearInterval(intervalId); // Dispose worker (which will stop all experts and clean up payment managers) await worker[Symbol.asyncDispose](); }); debugExpert(`All enabled experts started. Checking for changes every ${checkInterval / 1000} seconds.`); debugExpert("Press Ctrl+C to exit."); // Wait for the global stop promise await globalStopPromise; } catch (error) { debugError("Error running all experts:", error); throw error; } } /** * Register the all experts command with the CLI * * @param program The commander program or parent command */ export function registerAllCommand(program) { const command = program .command("all") .description("Run all enabled experts from the database") .option("-d, --debug", "Enable debug logging") .option("-i, --interval <ms>", "Check interval in milliseconds (default: 30000)", parseInt) .option("-s, --start-delay <ms>", "Delay between starting experts in milliseconds (default: 1000)", parseInt) .action(async (cmdOptions) => { // Convert command options to AllExpertsCommandOptions const options = { debug: cmdOptions.debug, interval: cmdOptions.interval, startDelay: cmdOptions.startDelay, }; try { await runAllExperts(options); } catch (error) { debugError("Error running all experts:", error); process.exit(1); } }); // No remote options for this command - only works with local DB } //# sourceMappingURL=all.js.map