askexperts
Version:
AskExperts SDK: build and use AI experts - ask them questions and pay with bitcoin on an open protocol
184 lines • 6.29 kB
JavaScript
import { debugError, debugExpert, enableAllDebug, enableErrorDebug, } from "../../../common/debug.js";
import { SimplePool } from "nostr-tools";
import dotenv from "dotenv";
import { createDBClientForCommands } from "../utils.js";
import { ExpertWorker } from "../../../experts/worker/ExpertWorker.js";
/**
* Get an expert by nickname or pubkey
*
* @param identifier Nickname or pubkey of the expert
* @returns The expert if found, null otherwise
*/
async function getExpertByNicknameOrPubkey(db, identifier, options) {
// First try to get by pubkey
let expert = await db.getExpert(identifier);
// If not found, try to find by nickname
if (!expert) {
// We need to search through all experts to find by nickname
const experts = await db.listExperts();
expert = experts.find((e) => e.nickname === identifier) || null;
}
return expert;
}
/**
* Get wallet for an expert
*
* @param walletId ID of the wallet
* @returns The wallet
* @throws Error if wallet not found
*/
async function getWalletForExpert(db, walletId) {
const wallet = await db.getWallet(walletId);
if (!wallet) {
throw new Error(`Wallet with ID ${walletId} not found`);
}
return wallet;
}
/**
* Run a Nostr expert
*
* @param expert The expert to run
* @param options Command options
*/
async function runNostrExpert(db, expert, options) {
try {
// Get wallet for the expert
const wallet = await getWalletForExpert(db, expert.wallet_id);
const nwcString = wallet.nwc;
// Parse environment variables using dotenv
const envVars = dotenv.parse(expert.env);
// Get RAG host and port from environment
const ragHost = envVars.CHROMA_HOST || process.env.CHROMA_HOST;
const ragPortStr = envVars.CHROMA_PORT || process.env.CHROMA_PORT;
const ragPort = ragPortStr ? parseInt(ragPortStr) : undefined;
// Create a shared pool
const pool = new SimplePool();
// Create ExpertWorker
const worker = new ExpertWorker(pool, ragHost, ragPort);
// Set up signal handling
const onStop = new Promise((ok) => {
const sigHandler = async () => {
debugExpert("\nReceived SIGINT. Shutting down expert...");
// Stop the expert
ok();
// Final cleaning
await worker[Symbol.asyncDispose]();
pool.destroy();
debugExpert("Expert shut down");
};
// SIGINT and SIGTERM
process.on("SIGINT", sigHandler);
process.on("SIGTERM", sigHandler);
});
// Start the expert
await worker.startExpert(expert, nwcString);
debugExpert("Press Ctrl+C to exit.");
// Wait for stop signal
await onStop;
}
catch (error) {
debugError("Error running Nostr expert:", error);
throw error;
}
}
/**
* Run an OpenRouter expert
*
* @param expert The expert to run
* @param options Command options
*/
async function runOpenRouterExpert(db, expert, options) {
try {
// Get wallet for the expert
const wallet = await getWalletForExpert(db, expert.wallet_id);
const nwcString = wallet.nwc;
// Create a shared pool
const pool = new SimplePool();
// Create ExpertWorker
const worker = new ExpertWorker(pool);
// Set up signal handling
const onStop = new Promise((ok) => {
const sigHandler = async () => {
debugExpert("\nReceived SIGINT. Shutting down expert...");
// Stop the expert
ok();
// Final cleaning
await worker[Symbol.asyncDispose]();
pool.destroy();
debugExpert("Expert shut down");
};
// SIGINT and SIGTERM
process.on("SIGINT", sigHandler);
process.on("SIGTERM", sigHandler);
});
// Start the expert
await worker.startExpert(expert, nwcString);
debugExpert("Press Ctrl+C to exit.");
// Wait for stop signal
await onStop;
}
catch (error) {
debugError("Error running OpenRouter expert:", error);
throw error;
}
}
/**
* Run an expert with the given identifier (nickname or pubkey)
*
* @param identifier Nickname or pubkey of the expert
* @param options Command options
*/
export async function runExpert(identifier, options) {
// Enable debug if requested
if (options.debug)
enableAllDebug();
else
enableErrorDebug();
// Only use local DB for this command
const db = await createDBClientForCommands({});
try {
// Get expert by nickname or pubkey
const expert = await getExpertByNicknameOrPubkey(db, identifier, options);
if (!expert) {
throw new Error(`Expert with nickname or pubkey '${identifier}' not found`);
}
debugExpert(`Found expert: ${expert.nickname} (${expert.pubkey})`);
// Run expert based on type
if (expert.type === "nostr") {
await runNostrExpert(db, expert, options);
}
else if (expert.type === "openrouter") {
await runOpenRouterExpert(db, expert, options);
}
else {
throw new Error(`Unknown expert type: ${expert.type}`);
}
}
catch (error) {
debugError("Error running expert:", error);
throw error;
}
}
/**
* Register the run expert command with the CLI
*
* @param program The commander program or parent command
*/
export function registerRunCommand(program) {
const command = program
.command("run")
.description("Run an expert by nickname or pubkey")
.argument("<identifier>", "Nickname or pubkey of the expert to run")
.option("-d, --debug", "Enable debug logging")
.action(async (identifier, options) => {
try {
await runExpert(identifier, options);
}
catch (error) {
debugError("Error running expert:", error);
process.exit(1);
}
});
// No remote options for this command - only works with local DB
}
//# sourceMappingURL=run.js.map