blob: 14b33f667270625ad7fce309ae53a989c35ad137 [file]
import type { LlmConnection } from '@maka/core';
import {
createScriptedMetaAgent,
type MetaAgent,
type MetaAgentCompletion,
} from './prompt-candidate-loop.js';
import { runOneShotCompletion } from './one-shot-completion.js';
const META_AGENT_SYSTEM =
'You optimize a single benchmark system prompt. Reply with exactly one JSON object ' +
'{"systemPrompt":"...","summary":"...","candidateRationale":{"editedSurface":"system_prompt","evidenceRefs":["rsi-sig:id"],"hypothesis":"short plain text","targetedFix":"short plain text","predictedFixes":["held-in-task-id"],"riskTasks":["held-in-task-id"]}} ' +
'and nothing else - no markdown fences, no prose. ' +
'Use failurePattern only as a coarse fallback when no evidence id is available.';
export interface CreateAiSdkMetaAgentInput {
connection: LlmConnection;
apiKey: string;
modelId: string;
system?: string;
maxOutputTokens?: number;
abortSignal?: AbortSignal;
/** Injectable text generator (default: runOneShotCompletion). Tests pass a fake. */
generate?: (input: { prompt: string; system?: string }) => Promise<string>;
}
/** A real meta-agent completion backed by a single tool-less model call
* (deepseek-v4-flash by default), with JSON extracted so the strict
* parseMetaAgentResult succeeds even when the model adds fences or prose. */
export function createAiSdkMetaAgentCompletion(
input: CreateAiSdkMetaAgentInput,
): MetaAgentCompletion {
const system = input.system ?? META_AGENT_SYSTEM;
const generate =
input.generate ??
((args) =>
runOneShotCompletion({
connection: input.connection,
apiKey: input.apiKey,
modelId: input.modelId,
prompt: args.prompt,
...(args.system !== undefined ? { system: args.system } : {}),
...(input.maxOutputTokens !== undefined ? { maxOutputTokens: input.maxOutputTokens } : {}),
...(input.abortSignal ? { abortSignal: input.abortSignal } : {}),
}));
return async ({ prompt }) => extractJsonObject(await generate({ prompt, system }));
}
export function createAiSdkMetaAgent(input: CreateAiSdkMetaAgentInput): MetaAgent {
return createScriptedMetaAgent({ complete: createAiSdkMetaAgentCompletion(input) });
}
/** Models often wrap JSON in ```json fences or surround it with prose; extract the
* single top-level JSON object so the strict parseMetaAgentResult does not throw. */
export function extractJsonObject(raw: string): string {
const trimmed = raw.trim();
const fenced = trimmed.match(/^```(?:json)?\s*([\s\S]*?)\s*```$/);
const body = (fenced ? fenced[1] : trimmed).trim();
if (body.startsWith('{') && body.endsWith('}')) return body;
const start = body.indexOf('{');
const end = body.lastIndexOf('}');
if (start >= 0 && end > start) return body.slice(start, end + 1);
return body;
}