@meldscience/meld
Version:
pipeable one-shot prompt scripting toolkit
114 lines (99 loc) • 3.81 kB
text/typescript
import { readFileSync, existsSync } from 'fs';
import { ToolError } from './errors';
import { AIProvider } from './providers/anthropic';
import { loadConfig } from './config';
export interface Variation {
system?: string;
model?: string;
prompt?: string;
}
export interface OneshotOptions {
model: string; // e.g. "gpt-4" or "claude-2" or an alias
promptFile: string; // path to user prompt or direct text
system?: string; // optional single system prompt
systemFile?: string; // or read system prompt from file
variations?: (string | Variation)[]; // list of variation prompts or objects
iterations?: number; // number of responses per variation
}
export interface ResponseEnvelope {
variation?: string | Variation;
systemPrompt: string;
response: string;
model: string;
}
export class Oneshot {
private resolvedModel: string;
private systemPrompt: string = '';
constructor(
private options: OneshotOptions,
private provider: AIProvider
) {
// Resolve model alias if it exists
const config = loadConfig();
this.resolvedModel = config.modelAliases?.[options.model] || options.model;
}
async process(): Promise<ResponseEnvelope[]> {
// Check if prompt file exists
if (!existsSync(this.options.promptFile)) {
throw new ToolError(`Oneshot: Prompt file not found: ${this.options.promptFile}`, 'FILE_NOT_FOUND');
}
// Check if system file exists
if (this.options.systemFile && !existsSync(this.options.systemFile)) {
throw new ToolError(`Oneshot: System file not found: ${this.options.systemFile}`, 'FILE_NOT_FOUND');
}
// Initialize system prompt
this.systemPrompt = '';
if (this.options.system) {
this.systemPrompt = this.options.system;
} else if (this.options.systemFile) {
try {
this.systemPrompt = readFileSync(this.options.systemFile, 'utf-8');
} catch (error: any) {
throw new ToolError(`Oneshot: Failed to read system file: ${error.message}`, 'FILE_READ_ERROR');
}
}
// Get prompt content from file
let promptContent: string;
try {
promptContent = readFileSync(this.options.promptFile, 'utf-8');
} catch (error: any) {
throw new ToolError(`Oneshot: Failed to read prompt: ${error.message}`, 'FILE_READ_ERROR');
}
// Process variations
const variations = this.options.variations || [undefined];
const iterations = this.options.iterations || 1;
// Run all variations and iterations
const responses: ResponseEnvelope[] = [];
for (const variation of variations) {
for (let i = 0; i < iterations; i++) {
// Handle variation object or string
let variationPrompt = '';
let variationSystem = this.systemPrompt;
let variationModel = this.resolvedModel;
if (typeof variation === 'string') {
variationPrompt = variation;
} else if (variation) {
variationPrompt = variation.prompt || '';
variationSystem = variation.system || this.systemPrompt;
if (variation.model) {
const config = loadConfig();
variationModel = config.modelAliases?.[variation.model] || variation.model;
}
}
const combinedPrompt = variationPrompt ? `${promptContent}\n\n${variationPrompt}` : promptContent;
const response = await this.provider.sendPrompt({
model: variationModel,
systemPrompt: variationSystem,
userPrompt: combinedPrompt
});
responses.push({
variation,
systemPrompt: variationSystem,
response,
model: variationModel
});
}
}
return responses;
}
}