Model resolution (from oh-my-openagent/model-core): 6-step priority resolution pipeline (UI select -> user config -> category default -> user fallback -> policy chain -> system default), provider fallback chains, fuzzy model matching, error classification, provider-specific model ID transforms. 14 files, zero runtime deps. Multi-batch matcher (from boocontext-audit): 6 batch types (Observational, Actionable, PreviouslyApplied, Disambiguation, ResponseAnalysis, LowCriticality) for behavioral guideline evaluation. RelationalResolver with iterative convergence (DEPENDS_ON, PRIORITIZES, ENTAILS, TAG_ALL, TAG_PRIORITIZES). SchematicGenerator abstract class with retry and execution plans. 4 files.
205 lines
4.9 KiB
TypeScript
205 lines
4.9 KiB
TypeScript
/**
|
|
* Schematic generator for behavioral guideline batches.
|
|
*
|
|
* Port of boocontext-audit/src/generation.ts — abstract LLM batch caller
|
|
* with temperature retry and structured output per batch type.
|
|
*/
|
|
|
|
import { type GenerationInfo } from './matching.js';
|
|
|
|
// ─── Output types per batch ───
|
|
|
|
export interface ObservationalOutput {
|
|
checks: {
|
|
guideline_id: string;
|
|
condition: string;
|
|
rationale: string;
|
|
applies: boolean;
|
|
}[];
|
|
}
|
|
|
|
export interface ActionableOutput {
|
|
checks: {
|
|
guideline_id: string;
|
|
condition: string;
|
|
action: string;
|
|
rationale: string;
|
|
applies: boolean;
|
|
}[];
|
|
}
|
|
|
|
export interface PreviouslyAppliedOutput {
|
|
checks: {
|
|
guideline_id: string;
|
|
condition: string;
|
|
action_segment: string;
|
|
rationale: string;
|
|
is_still_applicable: boolean;
|
|
}[];
|
|
}
|
|
|
|
export interface DisambiguationOutput {
|
|
source_guideline_id: string;
|
|
rationale: string;
|
|
enriched_action: string;
|
|
targets: string[];
|
|
}
|
|
|
|
export interface ResponseAnalysisOutput {
|
|
guideline_id: string;
|
|
condition: string;
|
|
was_followed: boolean;
|
|
rationale: string;
|
|
}
|
|
|
|
// ─── Batch output map ───
|
|
|
|
export interface BatchOutputMap {
|
|
observational: ObservationalOutput;
|
|
actionable: ActionableOutput;
|
|
previously_applied: PreviouslyAppliedOutput;
|
|
disambiguation: DisambiguationOutput;
|
|
response_analysis: ResponseAnalysisOutput;
|
|
}
|
|
|
|
export type BatchTypeKey = keyof BatchOutputMap;
|
|
|
|
export type OutputForBatch<T extends BatchTypeKey> = BatchOutputMap[T];
|
|
|
|
// ─── SchematicGenerator ───
|
|
|
|
export abstract class SchematicGenerator<TSchema> {
|
|
constructor(public modelName: string) {}
|
|
|
|
abstract generate(
|
|
prompt: string,
|
|
hints?: Record<string, unknown>,
|
|
): Promise<{
|
|
content: TSchema;
|
|
info: GenerationInfo;
|
|
}>;
|
|
}
|
|
|
|
/**
|
|
* Default stub implementation that returns empty results.
|
|
* Replace with a real LLM caller in production.
|
|
*/
|
|
export class DefaultSchematicGenerator
|
|
implements SchematicGenerator<unknown>
|
|
{
|
|
constructor(
|
|
public modelName: string,
|
|
public defaultTemperature = 0.7,
|
|
) {}
|
|
|
|
async generate(
|
|
_prompt: string,
|
|
hints?: Record<string, unknown>,
|
|
): Promise<{ content: unknown; info: GenerationInfo }> {
|
|
const temperature = (hints?.temperature as number) ?? this.defaultTemperature;
|
|
return {
|
|
content: {},
|
|
info: {
|
|
model: this.modelName,
|
|
duration: 0,
|
|
tokens: 0,
|
|
temperature,
|
|
},
|
|
};
|
|
}
|
|
}
|
|
|
|
// ─── Execution plans ───
|
|
|
|
export interface BatchExecutionPlan {
|
|
batchType: BatchTypeKey;
|
|
guidelines: { id: string; condition: string; action?: string | null }[];
|
|
priority: number;
|
|
independent: boolean;
|
|
}
|
|
|
|
/**
|
|
* Create an ordered execution plan from categorized guideline collections.
|
|
* Groups are sorted by priority: previously_applied (fastest) first,
|
|
* then observational, actionable, disambiguation, low-criticality last.
|
|
*/
|
|
export function createExecutionPlan(
|
|
observational: { id: string; condition: string }[],
|
|
actionable: { id: string; condition: string; action: string }[],
|
|
previouslyApplied: { id: string; condition: string; action?: string | null }[],
|
|
disambiguationGroups: { source: string; targets: string[]; enrichedAction: string }[],
|
|
lowCriticality: { id: string; condition: string }[],
|
|
): BatchExecutionPlan[] {
|
|
const plans: BatchExecutionPlan[] = [];
|
|
|
|
if (observational.length > 0) {
|
|
plans.push({
|
|
batchType: 'observational',
|
|
guidelines: observational.map((g) => ({ id: g.id, condition: g.condition })),
|
|
priority: 1,
|
|
independent: true,
|
|
});
|
|
}
|
|
|
|
if (actionable.length > 0) {
|
|
plans.push({
|
|
batchType: 'actionable',
|
|
guidelines: actionable.map((g) => ({
|
|
id: g.id,
|
|
condition: g.condition,
|
|
action: g.action,
|
|
})),
|
|
priority: 2,
|
|
independent: true,
|
|
});
|
|
}
|
|
|
|
if (previouslyApplied.length > 0) {
|
|
plans.push({
|
|
batchType: 'previously_applied',
|
|
guidelines: previouslyApplied.map((g) => ({
|
|
id: g.id,
|
|
condition: g.condition,
|
|
action: g.action,
|
|
})),
|
|
priority: 0,
|
|
independent: true,
|
|
});
|
|
}
|
|
|
|
if (disambiguationGroups.length > 0) {
|
|
plans.push({
|
|
batchType: 'disambiguation',
|
|
guidelines: disambiguationGroups.map((g) => ({
|
|
id: g.source,
|
|
condition: g.enrichedAction,
|
|
})),
|
|
priority: 3,
|
|
independent: true,
|
|
});
|
|
}
|
|
|
|
if (lowCriticality.length > 0) {
|
|
plans.push({
|
|
batchType: 'observational',
|
|
guidelines: lowCriticality.map((g) => ({ id: g.id, condition: g.condition })),
|
|
priority: 10,
|
|
independent: true,
|
|
});
|
|
}
|
|
|
|
return plans.sort((a, b) => a.priority - b.priority);
|
|
}
|
|
|
|
/**
|
|
* Compute retry temperatures: base + 0.2 * attempt.
|
|
* Provides progressive temperature increases for failed calls.
|
|
*/
|
|
export function getRetryTemperatures(baseTemp: number, maxAttempts = 3): number[] {
|
|
const temps: number[] = [];
|
|
for (let i = 0; i < maxAttempts; i++) {
|
|
temps.push(baseTemp + i * 0.2);
|
|
}
|
|
return temps;
|
|
}
|