UNPKG

@autobe/agent

Version:

AI backend server code generator

201 lines (190 loc) 5.86 kB
import { IAgenticaController, IAgenticaTokenUsageJson, MicroAgentica, } from "@agentica/core"; import { AutoBeImageDescribeDraft, AutoBeImageDescribeDraftEvent, AutoBeProgressEventBase, AutoBeUserConversateContent, AutoBeUserImageConversateContent, } from "@autobe/interface"; import { IPointer } from "tstl"; import typia, { ILlmApplication, IValidation } from "typia"; import { v7 } from "uuid"; import { AutoBeContext } from "../../context/AutoBeContext"; import { createAutoBeUserMessageContent } from "../../factory/createAutoBeMessageContent"; import { mergeSystemMessages } from "../../factory/mergeSystemMessages"; // import { supportFunctionCallFallback } from "../../factory/supportFunctionCallFallback"; import { supportMistral } from "../../factory/supportMistral"; import { executeCachedBatch } from "../../utils/executeCachedBatch"; import { transformImageDescribeDraftHistories } from "./histories/transformImageDescribeDraftHistories"; import { IAutoBeImageDescribeDraftApplication } from "./structures/IAutoBeImageDescribeDraftApplication"; export const orchestrateImageDescribeDrafts = async ( ctx: AutoBeContext, props: { content: AutoBeUserConversateContent[]; }, ): Promise<AutoBeImageDescribeDraft[]> => { const [imageContents, otherContents] = props.content.reduce( (acc, cur) => { if (cur.type === "image") { acc[0].push(cur); } else { acc[1].push(cur); } return acc; }, [ [] as AutoBeUserImageConversateContent[], [] as AutoBeUserConversateContent[], ], ); const progress: AutoBeProgressEventBase = { total: imageContents.length, completed: 0, }; // Process each image individually const drafts: (AutoBeImageDescribeDraft | null)[] = await executeCachedBatch( ctx, imageContents.map((imageContent) => async (promptCacheKey) => { try { const event: AutoBeImageDescribeDraftEvent = await process(ctx, { imageContents: [imageContent], // Single image userContents: otherContents, progress, promptCacheKey, }); ctx.dispatch(event); return { ...event, image: imageContent, description: event.draft, }; } catch { return null; } }), ); return drafts.filter((d) => d !== null); }; async function process( ctx: AutoBeContext, props: { imageContents: AutoBeUserImageConversateContent[]; userContents: AutoBeUserConversateContent[]; progress: AutoBeProgressEventBase; promptCacheKey: string; }, ): Promise<AutoBeImageDescribeDraftEvent> { const pointer: IPointer<IAutoBeImageDescribeDraftApplication.IProps | null> = { value: null, }; const content: AutoBeUserConversateContent[] = [ ...props.imageContents, ...props.userContents, ]; const agent: MicroAgentica = new MicroAgentica({ vendor: ctx.vendor, config: { executor: { describe: false, }, retry: ctx.retry, // stream: false, }, histories: transformImageDescribeDraftHistories(), controllers: [ createController({ build: (next) => { pointer.value = next; }, }), ], }); supportMistral(agent, { api: ctx.vendor.api, model: ctx.vendor.model, options: ctx.vendor.options, semaphore: typeof ctx.vendor.semaphore === "number" ? ctx.vendor.semaphore : ctx.vendor.semaphore?.max(), }); // supportFunctionCallFallback(agent, { // api: ctx.vendor.api, // model: ctx.vendor.model, // options: ctx.vendor.options, // semaphore: // typeof ctx.vendor.semaphore === "number" // ? ctx.vendor.semaphore // : ctx.vendor.semaphore?.max(), // }); mergeSystemMessages(agent, { api: ctx.vendor.api, model: ctx.vendor.model, options: ctx.vendor.options, semaphore: typeof ctx.vendor.semaphore === "number" ? ctx.vendor.semaphore : ctx.vendor.semaphore?.max(), }); agent.on("request", (e) => { if (!!e.body.tools?.length) { e.body.tool_choice = "required"; } }); await agent.conversate( content.map((c) => createAutoBeUserMessageContent({ content: c })), ); const tokenUsage: IAgenticaTokenUsageJson.IComponent = agent .getTokenUsage() .toJSON().aggregate; ctx.usage().record(tokenUsage, ["facade"]); props.progress.completed += props.imageContents.length; if (pointer.value === null) throw new Error("Failed to analyze image."); const event: AutoBeImageDescribeDraftEvent = { type: "imageDescribeDraft", id: v7(), observation: pointer.value.observation, analysis: pointer.value.analysis, topics: pointer.value.topics, summary: pointer.value.summary, draft: pointer.value.description, completed: props.progress.completed, tokenUsage, total: props.progress.total, created_at: new Date().toISOString(), }; return event; } function createController(props: { build: (next: IAutoBeImageDescribeDraftApplication.IProps) => void; }): IAgenticaController.IClass { const validate = ( next: unknown, ): IValidation<IAutoBeImageDescribeDraftApplication.IProps> => { const result: IValidation<IAutoBeImageDescribeDraftApplication.IProps> = typia.validate<IAutoBeImageDescribeDraftApplication.IProps>(next); if (result.success === false) return result; return result; }; const application: ILlmApplication = typia.llm.application<IAutoBeImageDescribeDraftApplication>({ validate: { analyzeImage: validate, }, }); return { protocol: "class", name: "image", application, execute: { analyzeImage: (next) => { props.build(next); }, } satisfies IAutoBeImageDescribeDraftApplication, }; }