UNPKG

@autobe/agent

Version:

AI backend server code generator

244 lines (233 loc) 7.09 kB
import { IAgenticaController, MicroAgentica } from "@agentica/core"; import { AutoBeOpenApi } from "@autobe/interface"; import { ILlmApplication, ILlmSchema, OpenApiTypeChecker, } from "@samchon/openapi"; import { OpenApiV3_1Emender } from "@samchon/openapi/lib/converters/OpenApiV3_1Emender"; import { IPointer } from "tstl"; import typia from "typia"; import { v4 } from "uuid"; import { AutoBeSystemPromptConstant } from "../../constants/AutoBeSystemPromptConstant"; import { AutoBeContext } from "../../context/AutoBeContext"; import { assertSchemaModel } from "../../context/assertSchemaModel"; import { enforceToolCall } from "../../utils/enforceToolCall"; import { transformInterfaceHistories } from "./transformInterfaceHistories"; export function orchestrateInterfaceComplement<Model extends ILlmSchema.Model>( ctx: AutoBeContext<Model>, document: AutoBeOpenApi.IDocument, life: number = 8, ): Promise<AutoBeOpenApi.IComponents> { return step(ctx, document, life); } async function step<Model extends ILlmSchema.Model>( ctx: AutoBeContext<Model>, document: AutoBeOpenApi.IDocument, retry: number, ): Promise<AutoBeOpenApi.IComponents> { const missed: string[] = getMissed(document); if (missed.length === 0 || retry <= 0) return document.components; const pointer: IPointer<Record< string, AutoBeOpenApi.IJsonSchemaDescriptive > | null> = { value: null, }; const agentica: MicroAgentica<Model> = new MicroAgentica({ model: ctx.model, vendor: ctx.vendor, config: { ...(ctx.config ?? {}), executor: { describe: null, }, }, histories: [ ...transformInterfaceHistories( ctx.state(), AutoBeSystemPromptConstant.INTERFACE_COMPLEMENT, ), { id: v4(), created_at: new Date().toISOString(), type: "assistantMessage", text: [ "Here is the OpenAPI document what you've made:", "", "```json", JSON.stringify(document), "```", ].join("\n"), }, { id: v4(), created_at: new Date().toISOString(), type: "assistantMessage", text: [ "You have missed below schema types in the document.components.schemas:", "", ...missed.map((s) => `- ${s}`), ].join("\n"), }, ], tokenUsage: ctx.usage(), controllers: [ createApplication({ model: ctx.model, build: (next) => { pointer.value ??= {}; Object.assign( pointer.value, (OpenApiV3_1Emender.convertComponents({ schemas: next, }).schemas ?? {}) as Record< string, AutoBeOpenApi.IJsonSchemaDescriptive >, ); }, }), ], }); enforceToolCall(agentica); await agentica.conversate("Fill missing schema types please"); if (pointer.value === null) { // unreachable throw new Error( "Failed to fill missing schema types. No response from agentica.", ); } ctx.dispatch({ type: "interfaceComplement", missed, schemas: pointer.value, step: ctx.state().analyze?.step ?? 0, created_at: new Date().toISOString(), }); const newComponents: AutoBeOpenApi.IComponents = { schemas: { ...pointer.value, ...document.components.schemas, }, authorization: document.components.authorization, }; return step( ctx, { ...document, components: newComponents, }, retry - 1, ); } const getMissed = (document: AutoBeOpenApi.IDocument): string[] => { const missed: Set<string> = new Set(); const check = (name: string) => { if (document.components.schemas[name] === undefined) missed.add(name); }; for (const op of document.operations) { if (op.requestBody !== null) check(op.requestBody.typeName); if (op.responseBody !== null) check(op.responseBody.typeName); } for (const value of Object.values(document.components.schemas)) OpenApiTypeChecker.visit({ components: document.components, schema: value, closure: (next) => { if (OpenApiTypeChecker.isReference(next)) check(next.$ref.split("/").pop()!); }, }); return Array.from(missed); }; function createApplication<Model extends ILlmSchema.Model>(props: { model: Model; build: ( schemas: Record<string, AutoBeOpenApi.IJsonSchemaDescriptive>, ) => void; }): IAgenticaController.IClass<Model> { assertSchemaModel(props.model); const application: ILlmApplication<Model> = collection[ props.model ] as unknown as ILlmApplication<Model>; return { protocol: "class", name: "interface", application, execute: { complementComponents: (next) => { props.build(next.schemas); }, } satisfies IApplication, }; } const claude = typia.llm.application< IApplication, "claude", { reference: true } >(); const collection = { chatgpt: typia.llm.application< IApplication, "chatgpt", { reference: true } >(), claude, llama: claude, deepseek: claude, "3.1": claude, "3.0": typia.llm.application<IApplication, "3.0">(), }; interface IApplication { /** * Complements missing schema types * * This method fills in schema definitions that are referenced via $ref but * not yet defined in the `components.schemas` section. For example, if an API * operation references `{ "$ref": "#/components/schemas/UserProfile" }` but * `UserProfile` type is not defined in `components.schemas`, this method will * add the missing schema definition. * * This function is designed to be called via AI function calling mechanism to * ensure the OpenAPI document is complete and all referenced schemas are * properly defined. */ complementComponents(props: IComplementComponentsProps): void; } interface IComplementComponentsProps { /** * A collection of missing schema definitions that need to be added to the * OpenAPI document's `components.schemas` section. * * This object contains schema definitions for types that are referenced but * not yet defined: * * - Key: Schema name (`string`): The name of the schema type that will be * referenced in $ref statements * - Value: `AutoBeOpenApi.IJsonSchema` - The complete JSON Schema definition * for that type * * Example structure: * * ```typescript * { * "UserProfile": { * "type": "object", * "properties": { * "id": { "type": "string" }, * "name": { "type": "string" }, * "email": { "type": "string", "format": "email" } * }, * "required": ["id", "name", "email"] * } * } * ``` * * Each schema definition follows the JSON Schema specification and will be * directly inserted into the OpenAPI document's components.schemas section, * making them available for $ref references throughout the API * specification. */ schemas: Record<string, AutoBeOpenApi.IJsonSchemaDescriptive>; }