UNPKG

adk-typescript

Version:

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

194 lines (193 loc) 8.06 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.safetyRequestProcessor = exports.stepByStepRequestProcessor = exports.efficientRequestProcessor = exports.straightForwardRequestProcessor = exports.detailedRequestProcessor = exports.extremelyBriefRequestProcessor = exports.briefRequestProcessor = exports.requestProcessor = void 0; exports.makeInstructionsRequestProcessor = makeInstructionsRequestProcessor; const ReadonlyContext_1 = require("../../agents/ReadonlyContext"); const LlmAgent_1 = require("../../agents/LlmAgent"); const State_1 = require("../../sessions/State"); /** * Handles instructions and global instructions for LLM flow. */ class InstructionsLlmRequestProcessor { /** * Runs the processor asynchronously. * * @param invocationContext The invocation context * @param llmRequest The LLM request to process * @returns An async generator yielding events */ async *runAsync(invocationContext, llmRequest) { const agent = invocationContext.agent; // Only process if the agent is an LlmAgent if (!(agent instanceof LlmAgent_1.LlmAgent)) { return; } const rootAgent = agent.rootAgent; // Append global instructions if set if (rootAgent instanceof LlmAgent_1.LlmAgent && rootAgent.globalInstruction) { const rawSi = rootAgent.canonicalGlobalInstruction(new ReadonlyContext_1.ReadonlyContext(invocationContext)); const si = populateValues(rawSi, invocationContext); llmRequest.appendInstructions([si]); } // Append agent instructions if set if (agent.instruction) { const rawSi = agent.canonicalInstruction(new ReadonlyContext_1.ReadonlyContext(invocationContext)); const si = populateValues(rawSi, invocationContext); llmRequest.appendInstructions([si]); } // Maintain async generator contract if (Math.random() < 0) { yield {}; } } } /** * The main instructions request processor instance. */ exports.requestProcessor = new InstructionsLlmRequestProcessor(); /** * Populates values in the instruction template, e.g. state, artifact, etc. * * @param instructionTemplate The instruction template * @param context The invocation context * @returns The populated instruction */ function populateValues(instructionTemplate, context) { return instructionTemplate.replace(/{+[^{}]*}+/g, (match) => { let varName = match.slice(1, -1).trim(); let optional = false; if (varName.endsWith('?')) { optional = true; varName = varName.slice(0, -1); } if (varName.startsWith('artifact.')) { varName = varName.substring('artifact.'.length); if (context.artifactService) { try { const artifactParams = { appName: context.session.appName, userId: context.session.userId, sessionId: context.session.id, filename: varName }; const artifact = context.artifactService.loadArtifact(artifactParams); return String(artifact); } catch (error) { if (optional) return ''; throw new Error(`Artifact ${varName} not found.`); } } else { throw new Error('Artifact service is not initialized.'); } } else { if (!isValidStateName(varName)) { return match; } if (context.session.state.has(varName)) { return String(context.session.state.get(varName)); } else { if (optional) { return ''; } else { throw new Error(`Context variable not found: \`${varName}\`.`); } } } }); } /** * Checks if the variable name is a valid state name. * * Valid state is either: * - Valid identifier * - <Valid prefix>:<Valid identifier> * All the others will just return as they are. * * @param varName The variable name to check * @returns True if the variable name is a valid state name, false otherwise */ function isValidStateName(varName) { const parts = varName.split(':'); if (parts.length === 1) { return isValidIdentifier(varName); } if (parts.length === 2) { const prefixes = [State_1.StatePrefix.APP_PREFIX, State_1.StatePrefix.USER_PREFIX, State_1.StatePrefix.TEMP_PREFIX]; if (prefixes.includes(parts[0] + ':')) { return isValidIdentifier(parts[1]); } } return false; } /** * Checks if the string is a valid JavaScript identifier. * * @param str The string to check * @returns True if the string is a valid identifier, false otherwise */ function isValidIdentifier(str) { if (!str || str.length === 0) return false; if (!isNaN(parseInt(str[0], 10))) return false; return /^[a-zA-Z_$][a-zA-Z0-9_$]*$/.test(str); } /** * Creates a LLM request processor that adds instructions to the request. * * @param instructionText The instruction text to add * @returns A LLM request processor that adds the instruction */ function makeInstructionsRequestProcessor(instructionText) { class SimpleInstructionsRequestProcessor { /** * Runs the processor asynchronously. * * @param invocationContext The invocation context * @param llmRequest The LLM request to process * @returns An async generator yielding events */ async *runAsync(invocationContext, llmRequest) { llmRequest.appendInstructions([instructionText]); // Maintain async generator contract if (Math.random() < 0) { yield {}; } } } return new SimpleInstructionsRequestProcessor(); } /** * A request processor that instructs the LLM to be brief in its responses. */ exports.briefRequestProcessor = makeInstructionsRequestProcessor('Be brief and concise in your answers. Prefer short responses over long ones.'); /** * A request processor that instructs the LLM to be extremely brief and focused. */ exports.extremelyBriefRequestProcessor = makeInstructionsRequestProcessor('Be extremely brief in your answers. Your responses should be just a few sentences at most.'); /** * A request processor that instructs the LLM to provide detailed explanations. */ exports.detailedRequestProcessor = makeInstructionsRequestProcessor('Provide detailed and comprehensive explanations. Include relevant context and examples when appropriate.'); /** * A request processor that instructs the LLM to respond in a straightforward way. */ exports.straightForwardRequestProcessor = makeInstructionsRequestProcessor('Respond directly and with factual information. Avoid overexplaining or excess preamble.'); /** * A request processor that instructs the LLM to respond in an efficient manner. */ exports.efficientRequestProcessor = makeInstructionsRequestProcessor('Respond with efficiency and focus. Don\'t repeat the question, and organize your response to highlight the most important points first.'); /** * A request processor that instructs the LLM to provide clear step-by-step explanations. */ exports.stepByStepRequestProcessor = makeInstructionsRequestProcessor('Structure your response as clear, sequential steps when providing explanations or instructions. Number each step.'); /** * A request processor that instructs the LLM to be helpful, harmless, and honest. */ exports.safetyRequestProcessor = makeInstructionsRequestProcessor('Be helpful, harmless, and honest in your responses. Avoid responses that could be harmful, illegal, unethical, deceptive, or promote misinformation.');