@autobe/agent
Version:
AI backend server code generator
221 lines (212 loc) • 6.91 kB
text/typescript
import { IAgenticaController } from "@agentica/core";
import {
AutoBeAnalyze,
AutoBeEventSource,
AutoBeInterfaceAuthorization,
AutoBeInterfaceAuthorizationEvent,
AutoBeOpenApi,
AutoBeProgressEventBase,
} from "@autobe/interface";
import { NamingConvention } from "@typia/utils";
import { IPointer, Singleton } from "tstl";
import typia, { ILlmApplication, IValidation } from "typia";
import { v7 } from "uuid";
import { AutoBeContext } from "../../context/AutoBeContext";
import { executeCachedBatch } from "../../utils/executeCachedBatch";
import { AutoBePreliminaryController } from "../common/AutoBePreliminaryController";
import { transformInterfaceAuthorizationHistory } from "./histories/transformInterfaceAuthorizationHistory";
import { AutoBeInterfaceAuthorizationProgrammer } from "./programmers/AutoBeInterfaceAuthorizationProgrammer";
import { IAutoBeInterfaceAuthorizationApplication } from "./structures/IAutoBeInterfaceAuthorizationApplication";
import { AutoBeJsonSchemaFactory } from "./utils/AutoBeJsonSchemaFactory";
export async function orchestrateInterfaceAuthorization(
ctx: AutoBeContext,
props: {
instruction: string;
},
): Promise<AutoBeInterfaceAuthorization[]> {
const actors: AutoBeAnalyze.IActor[] = ctx.state().analyze?.actors ?? [];
const progress: AutoBeProgressEventBase = {
total: actors.length,
completed: 0,
};
return await executeCachedBatch(
ctx,
actors.map((a) => async (promptCacheKey) => {
const counter = new Singleton(() => ++progress.completed);
try {
const event: AutoBeInterfaceAuthorizationEvent = await process(ctx, {
actor: a,
progress,
counter,
promptCacheKey,
instruction: props.instruction,
});
ctx.dispatch(event);
return {
name: a.name,
operations: event.operations,
};
} catch (error) {
counter.get();
throw error;
}
}),
);
}
async function process(
ctx: AutoBeContext,
props: {
instruction: string;
actor: AutoBeAnalyze.IActor;
progress: AutoBeProgressEventBase;
counter: Singleton<number>;
promptCacheKey: string;
},
): Promise<AutoBeInterfaceAuthorizationEvent> {
const prefix: string = NamingConvention.camel(ctx.state().analyze!.prefix);
const preliminary: AutoBePreliminaryController<
| "analysisSections"
| "previousAnalysisSections"
| "databaseSchemas"
| "previousDatabaseSchemas"
| "complete"
> = new AutoBePreliminaryController({
application:
typia.json.application<IAutoBeInterfaceAuthorizationApplication>(),
source: SOURCE,
kinds: [
"analysisSections",
"previousAnalysisSections",
"databaseSchemas",
"previousDatabaseSchemas",
"complete",
],
state: ctx.state(),
dispatch: (e) => ctx.dispatch(e),
});
return await preliminary.orchestrate(ctx, async (out) => {
const pointer: IPointer<IAutoBeInterfaceAuthorizationApplication.IWrite | null> =
{
value: null,
};
const result: AutoBeContext.IResult = await ctx.conversate({
source: SOURCE,
controller: createController({
actor: props.actor,
build: (next) => {
pointer.value = next;
},
preliminary,
prefix,
}),
enforceFunctionCall: true,
promptCacheKey: props.promptCacheKey,
...transformInterfaceAuthorizationHistory({
state: ctx.state(),
prefix,
instruction: props.instruction,
actor: props.actor,
preliminary,
}),
});
if (pointer.value === null) return out(result)(null);
const operations: AutoBeOpenApi.IOperation[] =
AutoBeInterfaceAuthorizationProgrammer.fixOperations({
operations: pointer.value?.operations ?? [],
prefix,
});
return out(result)({
type: SOURCE,
id: v7(),
analysis: pointer.value.analysis,
rationale: pointer.value.rationale,
operations,
acquisition: preliminary.getAcquisition(),
metric: result.metric,
tokenUsage: result.tokenUsage,
created_at: new Date().toISOString(),
step: ctx.state().analyze?.step ?? 0,
total: props.progress.total,
completed: props.counter.get(),
} satisfies AutoBeInterfaceAuthorizationEvent);
});
}
function createController(props: {
prefix: string | null;
actor: AutoBeAnalyze.IActor;
preliminary: AutoBePreliminaryController<
| "analysisSections"
| "previousAnalysisSections"
| "databaseSchemas"
| "previousDatabaseSchemas"
| "complete"
>;
build: (next: IAutoBeInterfaceAuthorizationApplication.IWrite) => void;
}): IAgenticaController.IClass {
const validate = (
next: unknown,
): IValidation<IAutoBeInterfaceAuthorizationApplication.IProps> => {
const result: IValidation<IAutoBeInterfaceAuthorizationApplication.IProps> =
typia.validate<IAutoBeInterfaceAuthorizationApplication.IProps>(next);
if (result.success === false) return result;
else if (result.data.request.type !== "write")
return props.preliminary.validate({
thinking: result.data.thinking,
request: result.data.request,
});
const errors: IValidation.IError[] = [];
AutoBeInterfaceAuthorizationProgrammer.validateAuthorizationTypes({
errors,
actor: props.actor,
operations: result.data.request.operations,
accessor: "$input.request.operations",
});
result.data.request.operations.forEach((operation, index) =>
AutoBeInterfaceAuthorizationProgrammer.validateOperation({
errors,
prefix: props.prefix,
actor: props.actor,
operation,
accessor: `$input.request.operations[${index}]`,
}),
);
if (errors.length !== 0) {
return {
success: false,
errors,
data: next,
};
}
return result;
};
const application: ILlmApplication = props.preliminary.fixApplication(
typia.llm.application<IAutoBeInterfaceAuthorizationApplication>({
validate: {
process: validate,
},
}),
);
return {
protocol: "class",
name: SOURCE,
application,
execute: {
process: (next) => {
if (next.request.type === "write") {
for (const o of next.request.operations)
for (const p of o.parameters)
AutoBeJsonSchemaFactory.fixSchema(p.schema);
next.request.operations = next.request.operations.filter(
(operation) =>
AutoBeInterfaceAuthorizationProgrammer.filter({
actor: props.actor.kind,
operation,
}),
);
props.build(next.request);
}
},
} satisfies IAutoBeInterfaceAuthorizationApplication,
};
}
const SOURCE = "interfaceAuthorization" satisfies AutoBeEventSource;