Add core Tracer/RunContext types and LlmTool base class

This commit is contained in:
2026-08-12 20:53:27 +02:00
parent 3ca58194e6
commit ee4aba83e8
4 changed files with 169 additions and 0 deletions

59
src/core/llm/LlmTool.ts Normal file
View File

@@ -0,0 +1,59 @@
import type { PromptService } from '../langfuse/PromptService';
import type { ChatMessage, LlmClient } from './LlmClient';
import type { RunContext } from './RunContext';
export abstract class LlmTool<TInput, TOutput> {
protected abstract readonly promptName: string;
constructor(
protected readonly promptService: PromptService,
protected readonly llmClient: LlmClient
) {}
protected abstract buildVariables(input: TInput, ctx: RunContext): Record<string, unknown>;
protected async preProcess(input: TInput, _ctx: RunContext): Promise<TInput> {
return input;
}
protected async postProcess(output: TOutput, _input: TInput, _ctx: RunContext): Promise<TOutput> {
return output;
}
protected abstract parseOutput(raw: string, ctx: RunContext): TOutput;
async runAsync(input: TInput, ctx: RunContext): Promise<TOutput> {
const processedInput = await this.preProcess(input, ctx);
const variables = this.buildVariables(processedInput, ctx);
const compiled = await this.promptService.getCompiled(this.promptName, variables);
const model = String(compiled.config.model ?? 'gpt-4o-mini');
const temperature =
typeof compiled.config.temperature === 'number' ? compiled.config.temperature : undefined;
const maxTokens =
typeof compiled.config.maxTokens === 'number' ? compiled.config.maxTokens : undefined;
const messages: ChatMessage[] = compiled.messages;
const generation = ctx.trace.startGeneration({
name: this.promptName,
model,
input: messages,
metadata: { promptVersion: compiled.version },
});
let raw: string;
try {
const result = await this.llmClient.chat(messages, { model, temperature, maxTokens });
raw = result.content;
generation.end({ output: raw, usage: result.usage });
} catch (err) {
generation.end({ output: null, metadata: { error: String(err) } });
throw err;
}
const parsed = this.parseOutput(raw, ctx);
const output = await this.postProcess(parsed, processedInput, ctx);
ctx.logger.info({ tool: this.promptName }, 'llm tool completed');
return output;
}
}

View File

@@ -0,0 +1,7 @@
import type { Logger } from '../logging/logger';
import type { TraceHandle } from './Tracer';
export interface RunContext {
trace: TraceHandle;
logger: Logger;
}

26
src/core/llm/Tracer.ts Normal file
View File

@@ -0,0 +1,26 @@
export interface GenerationInput {
name: string;
model: string;
input: unknown;
metadata?: Record<string, unknown>;
}
export interface GenerationOutput {
output: unknown;
usage?: { promptTokens?: number; completionTokens?: number; totalTokens?: number };
metadata?: Record<string, unknown>;
}
export interface GenerationHandle {
end(output: GenerationOutput): void;
}
export interface TraceHandle {
readonly id: string;
startGeneration(input: GenerationInput): GenerationHandle;
}
export abstract class Tracer {
abstract startTrace(name: string, metadata?: Record<string, unknown>): TraceHandle;
abstract flush(): Promise<void>;
}