UNPKG

newo

Version:

NEWO CLI: Professional command-line tool with modular architecture for NEWO AI Agent development. Features account migration, integration management, webhook automation, AKB knowledge base, project attributes, sandbox testing, IDN-based file management, r

306 lines 13.2 kB
/** * Sandbox Chat Command Handler * Supports both single-command and interactive modes */ import { makeClient } from '../../api.js'; import { getValidAccessToken } from '../../auth.js'; import { selectSingleCustomer } from '../customer-selection.js'; import { getChatHistory } from '../../api.js'; import { findSandboxConnector, createChatSession, sendMessage, pollForResponse, extractAgentMessages, formatDebugInfo } from '../../sandbox/chat.js'; /** * Handle sandbox command * Usage: * npx newo sandbox "Hello" --customer <idn> # Single message mode * npx newo sandbox --actor <actor_id> "Follow up" # Continue existing chat * npx newo sandbox --interactive # Interactive mode (TBD) */ export async function handleSandboxCommand(customerConfig, args, verbose) { const quiet = Boolean(args.quiet || args.q); // Save original console functions const originalConsoleLog = console.log; const originalConsoleError = console.error; const originalConsoleWarn = console.warn; // In quiet mode, set environment variable to suppress auth logging AND suppress console if (quiet) { process.env.NEWO_QUIET_MODE = 'true'; console.log = () => { }; console.error = () => { }; console.warn = () => { }; } try { // Select customer const customerArg = args.customer; const result = selectSingleCustomer(customerConfig, customerArg); if (!result.selectedCustomer) { if (!quiet) { console.error = originalConsoleError; console.error('❌ No customer selected'); } process.exit(1); } // Get access token and create client (quiet mode already suppressing logs) const token = await getValidAccessToken(result.selectedCustomer); const client = await makeClient(quiet ? false : verbose, token); // Restore console for our own output if (quiet) { console.log = originalConsoleLog; console.error = originalConsoleError; console.warn = originalConsoleWarn; } // Check for interactive mode const interactive = args.interactive || args.i; if (interactive) { if (!quiet) { console.log('❌ Interactive mode not yet implemented'); console.log(' Use single-command mode: npx newo sandbox "your message"'); } process.exit(1); } // Check if continuing existing chat const actorId = args.actor; // Extract message from arguments (position depends on whether --actor is used) const messageArg = args._[1]; if (!messageArg) { if (!quiet) { console.log('❌ Message is required'); console.log('Usage: npx newo sandbox "your message" [--actor <id>]'); console.log(' or: npx newo sandbox --actor <id> "your message"'); } process.exit(1); } // Convert to string (minimist may parse numbers) const message = String(messageArg); if (message.trim() === '') { if (!quiet) console.log('❌ Message cannot be empty'); process.exit(1); } if (actorId) { // Continue existing chat await continueExistingChat(client, actorId, message, verbose, quiet, originalConsoleLog, originalConsoleError, originalConsoleWarn); } else { // Start new chat await startNewChat(client, message, verbose, quiet, originalConsoleLog, originalConsoleError, originalConsoleWarn); } } catch (error) { // Restore console for error reporting if (quiet) { console.error = originalConsoleError; console.log = originalConsoleLog; console.warn = originalConsoleWarn; } console.error('❌ Sandbox chat error:', error.message); if (verbose && error.response?.data) { console.error(' Response data:', JSON.stringify(error.response.data, null, 2)); } process.exit(1); } finally { // Always restore console functions and clear quiet mode flag if (quiet) { console.log = originalConsoleLog; console.error = originalConsoleError; console.warn = originalConsoleWarn; delete process.env.NEWO_QUIET_MODE; } } } /** * Start a new sandbox chat and send a message */ async function startNewChat(client, message, verbose, quiet = false, originalConsoleLog = console.log, _originalConsoleError = console.error, _originalConsoleWarn = console.warn) { if (!quiet) console.log('🔧 Starting new sandbox chat...\n'); // Find sandbox connector const connector = await findSandboxConnector(client, quiet ? false : verbose); if (!connector) { if (!quiet) { console.error('❌ No running sandbox connector found'); console.error(' Please ensure you have a sandbox connector configured in your NEWO project'); } process.exit(1); } // Create chat session const session = await createChatSession(client, connector, quiet ? false : verbose); if (!quiet) { console.log(`\n📋 Chat Session Created:`); console.log(` Chat ID (actor_id): ${session.user_actor_id}`); console.log(` Persona ID: ${session.user_persona_id}`); console.log(` Connector: ${session.connector_idn}`); console.log(` External ID: ${session.external_id}\n`); console.log(`📤 You: ${message}\n`); } else { // In quiet mode, output Chat ID FIRST to stdout originalConsoleLog(`CHAT_ID:${session.user_actor_id}`); originalConsoleLog(`You: ${message}`); } const sentAt = await sendMessage(client, session, message, quiet ? false : verbose); // Poll for response const { acts, agentPersonaId } = await pollForResponse(client, session, sentAt, quiet ? false : verbose); if (acts.length === 0) { if (!quiet) { console.log('⏱️ No response received within timeout period'); console.log(` You can continue this chat with: npx newo sandbox --actor ${session.user_actor_id} "your message"`); } return; } // Update session with agent_persona_id session.agent_persona_id = agentPersonaId; // Extract agent messages - show only the MOST RECENT one const agentMessages = extractAgentMessages(acts); if (agentMessages.length > 0) { // Show only the latest agent message (messages are in reverse chronological order from API) const latestAgentMessage = agentMessages[0]; if (latestAgentMessage) { if (quiet) { // Quiet mode: ONLY message content originalConsoleLog(`Agent: ${latestAgentMessage.source_text || latestAgentMessage.original_text}`); } else { // Normal mode: full output console.log('🤖 Agent:'); console.log(` ${latestAgentMessage.source_text || latestAgentMessage.original_text}`); console.log(''); if (verbose && agentMessages.length > 1) { console.log(`ℹ️ Note: Received ${agentMessages.length} agent messages, showing latest only\n`); } } } } // In quiet mode, skip all debug output and continuation info completely if (quiet) { return; // Exit early, showing only messages } // Display debug information (skip in quiet mode) if (!quiet) { if (verbose) { console.log('\n📊 Debug Information:'); console.log(formatDebugInfo(acts)); console.log(''); } else { // Show condensed debug info for single-command mode console.log('📊 Debug Summary:'); const agentActs = acts.filter(a => a.is_agent); if (agentActs.length > 0) { const lastAct = agentActs[agentActs.length - 1]; if (lastAct) { console.log(` Flow: ${lastAct.flow_idn || 'N/A'}`); console.log(` Skill: ${lastAct.skill_idn || 'N/A'}`); console.log(` Session: ${lastAct.session_id}`); } console.log(` Acts Processed: ${acts.length} (${agentActs.length} agent, ${acts.length - agentActs.length} system)`); } console.log(''); } // Show continuation info console.log(`💡 To continue this conversation:`); console.log(` npx newo sandbox --actor ${session.user_actor_id} "your next message"`); console.log(''); } } /** * Continue an existing sandbox chat */ async function continueExistingChat(client, actorId, message, verbose, quiet = false, originalConsoleLog = console.log, _originalConsoleError = console.error, _originalConsoleWarn = console.warn) { if (!quiet) { console.log(`💬 Continuing chat...`); console.log(` Chat ID: ${actorId}\n`); } // First, get current chat history to find the last message ID const historyResponse = await getChatHistory(client, { user_actor_id: actorId, page: 1, per: 100 }); // Get the last message ID let lastMessageId = null; if (historyResponse.items && historyResponse.items.length > 0) { const lastItem = historyResponse.items[0]; if (lastItem && 'id' in lastItem) { lastMessageId = lastItem.id; } } if (verbose && lastMessageId && !quiet) { console.log(`📌 Last message ID: ${lastMessageId}`); } // Create a temporary session for the existing chat const session = { user_actor_id: actorId, user_persona_id: 'unknown', // Not needed for continuation agent_persona_id: null, connector_idn: 'sandbox', session_id: null, external_id: 'continuation' }; // Send message (use original console in quiet mode) if (quiet) { originalConsoleLog(`You: ${message}`); } else { console.log(`📤 You: ${message}\n`); } const sentAt = await sendMessage(client, session, message, quiet ? false : verbose); // Poll for response using timestamp-based filtering const { acts } = await pollForResponse(client, session, sentAt, quiet ? false : verbose); if (acts.length === 0) { if (!quiet) { console.log('⏱️ No response received within timeout period'); console.log(` You can continue this chat with: npx newo sandbox --actor ${actorId} "your message"`); } return; } // Extract agent messages - show only the MOST RECENT one const agentMessages = extractAgentMessages(acts); if (agentMessages.length > 0) { // Show only the latest agent message (messages are in reverse chronological order from API) const latestAgentMessage = agentMessages[0]; if (latestAgentMessage) { if (quiet) { // Quiet mode: ONLY message content originalConsoleLog(`Agent: ${latestAgentMessage.source_text || latestAgentMessage.original_text}`); return; // Exit immediately, no debug output } else { // Normal mode: full output console.log('🤖 Agent:'); console.log(` ${latestAgentMessage.source_text || latestAgentMessage.original_text}`); console.log(''); if (verbose && agentMessages.length > 1) { console.log(`ℹ️ Note: Received ${agentMessages.length} agent messages, showing latest only\n`); } } } } // Display debug information (skip in quiet mode) if (!quiet) { if (verbose) { console.log('\n📊 Debug Information:'); console.log(formatDebugInfo(acts)); console.log(''); } else { // Show condensed debug info console.log('📊 Debug Summary:'); const agentActs = acts.filter(a => a.is_agent); if (agentActs.length > 0) { const lastAct = agentActs[agentActs.length - 1]; if (lastAct) { console.log(` Flow: ${lastAct.flow_idn || 'N/A'}`); console.log(` Skill: ${lastAct.skill_idn || 'N/A'}`); console.log(` Session: ${lastAct.session_id}`); } console.log(` Acts Processed: ${acts.length} (${agentActs.length} agent, ${acts.length - agentActs.length} user)`); } console.log(''); } // Show continuation info console.log(`💡 To continue this conversation:`); console.log(` npx newo sandbox --actor ${actorId} "your next message"`); console.log(''); } } //# sourceMappingURL=sandbox.js.map