UNPKG

automagik-genie

Version:

Self-evolving AI agent orchestration framework with Model Context Protocol support

190 lines (189 loc) 7.53 kB
"use strict"; /** * Task Command - Pure headless task execution * * Creates a Forge task and returns immediately with task ID. * No browser opening, no monitoring. Designed for automation and scripting. * * Behavior: * 1. Create Forge task with agent * 2. Return task ID and URL immediately * 3. Task runs in background * 4. Exit (fire and forget) * * This preserves the old `genie run` behavior for backward compatibility. */ Object.defineProperty(exports, "__esModule", { value: true }); exports.runTask = runTask; const service_config_js_1 = require("../lib/service-config.js"); const headless_helpers_1 = require("../lib/headless-helpers"); const agent_resolver_1 = require("../lib/agent-resolver"); const forge_executor_1 = require("../lib/forge-executor"); const forge_helpers_1 = require("../lib/forge-helpers"); const executor_registry_1 = require("../lib/executor-registry"); const task_monitor_1 = require("../lib/task-monitor"); const task_service_js_1 = require("../cli-core/task-service.js"); async function runTask(parsed, config, paths) { const [subcommandOrAgent, ...restArgs] = parsed.commandArgs; if (!subcommandOrAgent) { console.error('Usage: genie task <agent> "<prompt>" OR genie task monitor <attempt-id>'); process.exit(1); } if (subcommandOrAgent === 'monitor') { return runTaskMonitor(restArgs, config, paths); } const agentName = subcommandOrAgent; const promptParts = restArgs; const prompt = promptParts.join(' ').trim(); if (!prompt) { console.error('Error: Prompt is required'); console.error('Usage: genie task <agent> "<prompt>"'); process.exit(1); } const resolvedAgentName = (0, agent_resolver_1.resolveAgentIdentifier)(agentName); const agentSpec = (0, agent_resolver_1.loadAgentSpec)(resolvedAgentName); const agentGenie = agentSpec.meta?.genie || {}; const agentMeta = agentSpec.meta || {}; // Resolve executor configuration (CLI flags override agent/config defaults) const executorKey = (0, executor_registry_1.normalizeExecutorKeyOrDefault)(parsed.options.executor || (0, executor_registry_1.normalizeExecutorValue)(agentGenie.executor) || config.defaults?.executor); // Derive executor variant matching Forge's naming convention const deriveVariantFromAgentName = (agentPath) => { // Forge variant naming: CODE_<AGENT_NAME> or CREATE_<AGENT_NAME> // Examples: code/explore → CODE_EXPLORE, create/writer → CREATE_WRITER const parts = agentPath.split('/'); const template = parts[0]; // code, create, etc. // Remove template and category folders (agents/, workflows/) let remaining = parts.slice(1); if (remaining.length > 0 && (remaining[0] === 'agents' || remaining[0] === 'workflows')) { remaining = remaining.slice(1); } // Join remaining parts with underscores and uppercase const agentName = remaining.join('_').toUpperCase(); // Prepend template prefix (CODE_, CREATE_, etc.) const templatePrefix = template.toUpperCase() + '_'; return templatePrefix + agentName; }; const executorVariant = (parsed.options.variant || // CLI flag (highest priority) agentMeta.forge_profile_name || // Explicit Forge profile name from frontmatter agentGenie.executorVariant || agentGenie.variant || deriveVariantFromAgentName(resolvedAgentName) || // Derive from agent name config.defaults?.executorVariant || // Config defaults (lowest priority) 'DEFAULT' // Ultimate fallback ).trim().toUpperCase(); const model = parsed.options.model || agentGenie.model || config.defaults?.model; const sessionName = parsed.options.name; const raw = parsed.options.raw || false; // Ensure Forge is running (quiet mode) await (0, headless_helpers_1.ensureForgeRunning)(true); const forgeExecutor = (0, forge_executor_1.createForgeExecutor)(); let sessionResult; try { sessionResult = await forgeExecutor.createTask({ agentName: resolvedAgentName, prompt, executorKey, executorVariant, executionMode: 'background', model, ...(sessionName && { name: sessionName }) }); } catch (error) { const reason = (0, forge_helpers_1.describeForgeError)(error); console.error(JSON.stringify({ error: `Failed to create task: ${reason}`, hint: forge_helpers_1.FORGE_RECOVERY_HINT }, null, 2)); process.exit(1); } const attemptId = sessionResult.attemptId; const taskUrl = sessionResult.forgeUrl; const sessionService = new task_service_js_1.TaskService({ paths: { tasksFile: paths.tasksFile } }); const store = sessionService.load(); const now = new Date().toISOString(); store.sessions[attemptId] = { agent: resolvedAgentName, taskId: sessionResult.taskId, projectId: sessionResult.projectId, executor: executorKey, executorVariant, model: model || undefined, status: 'running', created: now, lastUsed: now, lastPrompt: prompt.slice(0, 200), mode: 'background', forgeUrl: sessionResult.forgeUrl, background: true }; await sessionService.save(store); // Output based on --raw flag if (raw) { console.log(attemptId); } else { const jsonOutput = { task_id: attemptId, task_url: taskUrl, agent: resolvedAgentName, executor: `${executorKey}:${executorVariant}`, ...(model && { model }), status: 'started', message: 'Task running in background' }; console.log(JSON.stringify(jsonOutput, null, 2)); } process.exitCode = 0; } async function runTaskMonitor(args, _config, _paths) { const [attemptId] = args; if (!attemptId) { console.error('Usage: genie task monitor <attempt-id>'); process.exit(1); } const { baseUrl, token } = (0, service_config_js_1.getForgeConfig)(); console.log(`📡 Monitoring task attempt: ${attemptId}`); console.log(''); try { const result = await (0, task_monitor_1.monitorTaskCompletion)({ attemptId, baseUrl, token, onLog: (log) => { console.log(log); }, onStatus: (status) => { if (status !== 'running') { console.log(`Status: ${status}`); } } }); const jsonOutput = JSON.stringify({ task_url: result.task_url, result: result.output, status: result.status, duration_ms: result.duration_ms, attempt_id: attemptId, ...(result.error && { error: result.error }) }, null, 2); console.log(''); console.log('━'.repeat(60)); console.log(result.status === 'completed' ? '✅ Task Completed' : '❌ Task Failed'); console.log('━'.repeat(60)); console.log(''); console.log(jsonOutput); console.log(''); process.exitCode = result.status === 'completed' ? 0 : 1; } catch (error) { console.error(''); console.error('❌ Monitoring failed:', error); console.error(''); process.exitCode = 1; } }