UNPKG

naisys

Version:

NAISYS - Autonomous AI agent runner with built-in context management and cost tracking

171 lines 7.12 kB
import { buildDefaultAgentConfig, builtInLlmModels, CODEX_REFRESH_TOKEN_VAR, LlmApiType, } from "@naisys/common"; import { askQuestion, cwdWithTilde, loadAgentConfigs, } from "@naisys/common-node"; import fs from "fs"; import yaml from "js-yaml"; import os from "os"; import path from "path"; const CODEX_SUBSCRIPTION_PROVIDER_NAME = "OpenAI Codex Subscription"; export function getNaisysWizardConfig(hubClient, integratedHub, options = {}) { if (hubClient) { return { title: "NAISYS Setup (Hub Client)", sections: [ { type: "fields", comment: "Generate one per host in the Supervisor (Hosts → host → Access Key). The key alone identifies this NAISYS instance.", fields: [{ key: "HOST_ACCESS_KEY", label: "Host Access Key" }], }, { type: "fields", comment: "Local configuration", fields: [ { key: "NAISYS_FOLDER", label: "NAISYS Data Folder", defaultValue: cwdWithTilde(), }, ], }, ], }; } return { title: "NAISYS Setup", sections: [ { type: "fields", comment: "Agent home files and NAISYS specific databases will be stored here", fields: [ { key: "NAISYS_FOLDER", label: "NAISYS Data Folder", defaultValue: cwdWithTilde(), }, { key: "NAISYS_HOSTNAME", label: "Hostname", defaultValue: os.hostname(), }, ], }, { type: "providers", comment: "Leave API keys blank if not using the service. OpenAI Codex Subscription is connected later through Supervisor Variables.", label: "AI Providers", options: [ { name: "OpenAI", fields: [{ key: "OPENAI_API_KEY", label: "OpenAI API Key" }], }, { name: CODEX_SUBSCRIPTION_PROVIDER_NAME, fields: [], onSelected: options.onCodexSubscriptionSelected, }, { name: "Google", fields: [ { key: "GOOGLE_API_KEY", label: "Google API Key" }, { key: "GOOGLE_SEARCH_ENGINE_ID", label: "Google Search Engine ID", }, ], }, { name: "Anthropic", fields: [{ key: "ANTHROPIC_API_KEY", label: "Anthropic API Key" }], }, { name: "XAI", fields: [{ key: "XAI_API_KEY", label: "XAI API Key" }], }, { name: "OpenRouter", fields: [ { key: "OPENROUTER_API_KEY", label: "OpenRouter API Key" }, ], }, ], }, { type: "fields", comment: "Spend limits apply to all agents using this .env file", fields: [ { key: "SPEND_LIMIT_DOLLARS", label: "Spend Limit (dollars)" }, { key: "SPEND_LIMIT_HOURS", label: "Spend Limit Period (hours)" }, ], }, ...(integratedHub ? [ { type: "fields", comment: "Integrated hub/supervisor server (--integrated-hub mode)", fields: [ { key: "SERVER_PORT", label: "Server Port" }, { key: "ALLOW_PASSWORD_LOGIN", label: "Allow Supervisor Password Sign-in", }, ], }, ] : []), ], }; } /** Available models ordered by preference (excludes none/mock) */ const availableModels = builtInLlmModels.filter((m) => m.apiKeyVar && m.apiType !== LlmApiType.None && m.apiType !== LlmApiType.Mock); const preferredCodexModel = availableModels.find((m) => m.apiType === LlmApiType.OpenAIOAuth); function hasConfiguredCredentials(model) { return Boolean(process.env[model.apiKeyVar] || (model.apiType === LlmApiType.OpenAIOAuth && process.env[CODEX_REFRESH_TOKEN_VAR])); } export function printCodexSubscriptionSetupInstructions() { console.log("\n OpenAI Codex Subscription selected. After Supervisor opens, go to Variables and click OpenAI Codex OAuth Setup."); console.log(" Finish that flow to connect your subscription and save the required variables.\n"); } /** * If no agent path was provided and no agent configs exist in cwd, * offer to create a default assistant.yaml. Prefer a configured provider, but * use OpenAI Codex when the subscription provider was selected so first-time * users can complete subscription setup from Supervisor's Variables page after * startup. */ export async function ensureAgentConfig(agentPath, options = {}) { if (agentPath) return; // Check if there are any non-admin agents that would load from cwd try { const users = loadAgentConfigs(""); const hasNonAdmin = Array.from(users.values()).some((u) => u.username !== "admin"); if (hasNonAdmin) return; } catch { // No configs found, fall through to offer creation } const configuredModel = availableModels.find(hasConfiguredCredentials); const model = (options.useCodexSubscription ? preferredCodexModel : undefined) ?? configuredModel; if (!model) { console.log("\n No agent configs found and no AI provider configured. Run with --setup to configure one."); return; } if (!process.stdin.isTTY) return; const answer = await askQuestion(`\n No agent config found. Create a default assistant using ${model.label}? (Y/n) `); if (answer && !answer.toLowerCase().startsWith("y")) { return; } const config = buildDefaultAgentConfig("andy"); config.shellModel = model.key; config.supervisorApiHints = true; const filePath = path.resolve("assistant.yaml"); fs.writeFileSync(filePath, yaml.dump(config)); console.log(` Created ${filePath} using ${model.key}\n`); } //# sourceMappingURL=naisysSetup.js.map