UNPKG

@autobe/agent

Version:

AI backend server code generator

142 lines (134 loc) 4.42 kB
import { IAgenticaHistoryJson, MicroAgentica, MicroAgenticaHistory, } from "@agentica/core"; import { AutoBeConsentFunctionCallEvent, AutoBeEvent, AutoBeEventSource, } from "@autobe/interface"; import { StringUtil } from "@autobe/utils"; import { IPointer } from "tstl"; import typia from "typia"; import { v7 } from "uuid"; import { AutoBeConfigConstant } from "../constants/AutoBeConfigConstant"; import { AutoBeSystemPromptConstant } from "../constants/AutoBeSystemPromptConstant"; import { IAutoBeConfig } from "../structures/IAutoBeConfig"; import { IAutoBeVendor } from "../structures/IAutoBeVendor"; import { mergeSystemMessages } from "./mergeSystemMessages"; // import { supportFunctionCallFallback } from "./supportFunctionCallFallback"; import { supportMistral } from "./supportMistral"; /** * Generates automatic consent messages when AI hesitates and seeks permission * before function calling. * * Uses fast LLM (chatgpt) to analyze assistant messages and determine if * they're seeking function execution approval. Returns strong directive consent * message to break permission-seeking loops, or `null` if not applicable. * * @returns Consent message if applicable, `null` otherwise */ export const consentFunctionCall = async (props: { dispatch: (event: AutoBeEvent) => void; source: AutoBeEventSource; config: IAutoBeConfig; vendor: IAutoBeVendor; assistantMessage: string; // trimmed }): Promise<string | null> => { const dispatch = (result: AutoBeConsentFunctionCallEvent.IResult | null) => props.dispatch({ type: "consentFunctionCall", id: v7(), source: props.source, assistantMessage: props.assistantMessage, result, created_at: new Date().toISOString(), }); if (props.assistantMessage.length === 0) { const message: string = StringUtil.trim` You sent me an empty assistant message. Don't do such foolish thing again, and do the function calling properly. `; dispatch({ type: "consent", message, }); return message; } const pointer: IPointer<AutoBeConsentFunctionCallEvent.IResult | null> = { value: null, }; const agent: MicroAgentica = new MicroAgentica({ vendor: props.vendor, config: { ...(props.config ?? []), executor: { describe: false, }, retry: props.config?.retry ?? AutoBeConfigConstant.VALIDATION_RETRY, // stream: false, }, histories: [ { id: v7(), type: "systemMessage", text: AutoBeSystemPromptConstant.CONSENT_FUNCTION_CALL, created_at: new Date().toISOString(), } satisfies IAgenticaHistoryJson.ISystemMessage, { id: v7(), type: "assistantMessage", text: props.assistantMessage, created_at: new Date().toISOString(), } satisfies IAgenticaHistoryJson.IAssistantMessage, ], controllers: [ typia.llm.controller<IConsentApplication>("consent", { consent: (props) => { pointer.value = { type: "consent", message: props.message, }; }, notApplicable: () => { pointer.value = { type: "notApplicable", }; }, } satisfies IConsentApplication), ], }); supportMistral(agent, props.vendor); // supportFunctionCallFallback(agent, props.vendor); mergeSystemMessages(agent, props.vendor); const histories: MicroAgenticaHistory[] = await agent.conversate( "Analyze and judge this assistant message please.", ); if (pointer.value === null) { const last: MicroAgenticaHistory | undefined = histories[histories.length - 1]; if (last?.type === "assistantMessage") pointer.value = { type: "assistantMessage", message: last.text, }; } dispatch(pointer.value); return pointer.value?.type === "consent" ? pointer.value.message : null; }; interface IConsentApplication { /** * Generate authoritative consent message when assistant seeks function * execution approval. * * @param props.message Strong directive (1-2 sentences). E.g., "Execute * immediately. Do not ask again." */ consent(props: { message: string }): void; /** * Indicate assistant message doesn't require function calling consent (e.g., * general conversation, asking for parameters, etc.). */ notApplicable(): void; }