UNPKG

adk-typescript

Version:

TypeScript port of Google's Agent Development Kit (ADK)

297 lines (296 loc) 12.4 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || (function () { var ownKeys = function(o) { ownKeys = Object.getOwnPropertyNames || function (o) { var ar = []; for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k; return ar; }; return ownKeys(o); }; return function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]); __setModuleDefault(result, mod); return result; }; })(); Object.defineProperty(exports, "__esModule", { value: true }); exports.runInputFile = runInputFile; exports.runInteractively = runInteractively; exports.runCli = runCli; const fs = __importStar(require("fs")); const path = __importStar(require("path")); const readline = __importStar(require("readline")); const util_1 = require("util"); const InMemoryArtifactService_1 = require("../artifacts/InMemoryArtifactService"); const runners_1 = require("../runners"); const InMemorySessionService_1 = require("../sessions/InMemorySessionService"); const envs = __importStar(require("./utils/envs")); /** * Run an agent using input from a file * * @param appName Name of the application * @param userId User ID to create the session with * @param rootAgent The root agent to run * @param artifactService Service for managing artifacts * @param sessionService Service for managing sessions * @param inputPath Path to the input file * @returns The created session */ async function runInputFile(appName, userId, rootAgent, artifactService, sessionService, inputPath) { const runner = new runners_1.Runner({ appName, agent: rootAgent, artifactService, sessionService, }); const inputFileRaw = await (0, util_1.promisify)(fs.readFile)(inputPath, 'utf-8'); const inputFile = JSON.parse(inputFileRaw); // Add time to state const state = { ...inputFile.state, _time: new Date() }; // Create a new session with the state const session = await sessionService.createSession({ appName, userId, state, }); for (const query of inputFile.queries) { console.log(`[user]: ${query}`); const content = { role: 'user', parts: [{ text: query }] }; for await (const event of runner.runAsync({ userId: session.userId, sessionId: session.id, newMessage: content, })) { if (event.content && event.content.parts) { const text = event.content.parts .map((part) => part.text || '') .join(''); if (text) { console.log(`[${event.author}]: ${text}`); } } } } return session; } /** * Run an agent interactively via CLI * * @param rootAgent The root agent to run * @param artifactService Service for managing artifacts * @param session The session to use * @param sessionService Service for managing sessions */ async function runInteractively(rootAgent, artifactService, session, sessionService) { const runner = new runners_1.Runner({ appName: session.appName, agent: rootAgent, artifactService, sessionService, }); const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); const ask = (q) => new Promise(resolve => rl.question(q, resolve)); let isRunning = true; while (isRunning) { const query = (await ask('[user]: ')).trim(); if (!query) continue; if (query === 'exit') { isRunning = false; break; } const content = { role: 'user', parts: [{ text: query }] }; for await (const event of runner.runAsync({ userId: session.userId, sessionId: session.id, newMessage: content, })) { if (event.content && event.content.parts) { const text = event.content.parts .map((part) => part.text || '') .join(''); if (text) { console.log(`[${event.author}]: ${text}`); } } } } rl.close(); } /** * Extract conversation contents from session events * * @param session The session to extract contents from * @returns Array of conversation contents */ function getSessionContents(session) { if (!session.events) return []; return session.events .filter(event => event.content && event.content.parts && event.content.parts.length > 0) .map(event => event.content); } /** * Run the CLI for a specific agent * * @param options Configuration options * @param options.agentParentDir The parent directory of the agent * @param options.agentFolderName The folder name of the agent * @param options.replayFile Optional path to a replay JSON file with initial state and queries * @param options.resumeFile Optional path to a previously saved session file * @param options.saveSession Whether to save the session after running */ async function runCli({ agentParentDir, agentFolderName, replayFile, resumeFile, saveSession = false, }) { // Add agent parent directory to the module search path if (!process.env.PYTHONPATH?.includes(agentParentDir)) { process.env.PYTHONPATH = (process.env.PYTHONPATH || '') + path.delimiter + agentParentDir; } // Initialize services const artifactService = new InMemoryArtifactService_1.InMemoryArtifactService(); const sessionService = new InMemorySessionService_1.InMemorySessionService(); const userId = 'test_user'; // Create a default session let session = await sessionService.createSession({ appName: agentFolderName, userId, }); // Resolve the agent path more carefully let agentModulePath; // Check if we're in the agent directory or parent directory const currentDir = process.cwd(); const tentativeSrcPath = path.resolve(currentDir, agentFolderName, 'src'); const directSrcPath = path.resolve(currentDir, 'src'); // In TypeScript we use agent.ts directly instead of index.ts // This better matches the Python ADK where agent.py is the main file if (fs.existsSync(path.resolve(tentativeSrcPath, 'agent.ts'))) { // If we're in the parent directory and agent folder has src/agent.ts agentModulePath = path.resolve(tentativeSrcPath, 'agent.ts'); } else if (fs.existsSync(path.resolve(directSrcPath, 'agent.ts'))) { // If we're already in the agent directory and src/agent.ts exists agentModulePath = path.resolve(directSrcPath, 'agent.ts'); } else { // Fall back to directly looking for agent.ts in the specified path agentModulePath = path.resolve(process.cwd(), agentParentDir, agentFolderName, 'agent.ts'); } console.log(`Loading agent from: ${agentModulePath}`); try { // Load environment variables for the agent envs.loadDotenvForAgent(agentFolderName, agentParentDir); // Use ts-node to load the TypeScript module try { // First try using ts-node/register to load the module require('ts-node/register'); const agentModule = require(agentModulePath); // Get the rootAgent from the module const rootAgent = agentModule.rootAgent || (agentModule.default && agentModule.default.rootAgent); if (!rootAgent) { throw new Error(`Could not find rootAgent in module ${agentModulePath}. Make sure it exports a 'rootAgent' property.`); } if (replayFile) { // Run with replay file (creates a new session and runs queries) session = await runInputFile(agentFolderName, userId, rootAgent, artifactService, sessionService, replayFile); } else if (resumeFile) { // Load session from file and replay events const sessionRaw = await (0, util_1.promisify)(fs.readFile)(resumeFile, 'utf-8'); const loadedSession = JSON.parse(sessionRaw); // Merge session data into our session object session.id = loadedSession.id || session.id; session.appName = loadedSession.appName || session.appName; session.userId = loadedSession.userId || session.userId; session.state = loadedSession.state || session.state; // Replay all events from the loaded session if (loadedSession.events && Array.isArray(loadedSession.events)) { for (const event of loadedSession.events) { await sessionService.appendEvent({ session, event }); // Display the content for each event if (event.content && event.content.parts && event.content.parts.length > 0) { const text = event.content.parts[0].text; if (text) { if (event.author === 'user') { console.log(`[user]: ${text}`); } else { console.log(`[${event.author}]: ${text}`); } } } } } // Continue with interactive mode await runInteractively(rootAgent, artifactService, session, sessionService); } else { // Run interactively without input file console.log(`Running agent ${rootAgent.name}, type exit to exit.`); await runInteractively(rootAgent, artifactService, session, sessionService); } // Save session if requested if (saveSession) { let sessionPath; if (replayFile) { sessionPath = replayFile.replace('.input.json', '.session.json'); } else { // Ask for session ID const rl = readline.createInterface({ input: process.stdin, output: process.stdout, }); const sessionId = await new Promise(resolve => { rl.question('Session ID to save: ', resolve); }); rl.close(); sessionPath = path.join(path.dirname(agentModulePath), `${sessionId}.session.json`); } // Fetch updated session const updatedSession = await sessionService.getSession({ appName: session.appName, userId: session.userId, sessionId: session.id, }) || session; // Save session to file await (0, util_1.promisify)(fs.writeFile)(sessionPath, JSON.stringify(updatedSession, null, 2)); console.log('Session saved to', sessionPath); } } catch (error) { console.error('Error loading agent module:', error); process.exit(1); } } catch (error) { console.error('Error running CLI:', error); process.exit(1); } }