UNPKG

@ai2070/l0

Version:

L0: The Missing Reliability Substrate for AI

226 lines 7.83 kB
import { l0 } from "./runtime/l0"; export async function pipe(steps, input, options = {}) { const { name, stopOnError = true, timeout, signal, monitoring, onStart, onComplete, onError, onProgress, metadata = {}, } = options; const startTime = Date.now(); const stepResults = []; let currentInput = input; let finalOutput = input; let pipelineError; let pipelineStatus = "success"; let timeoutId; const timeoutPromise = timeout ? new Promise((_, reject) => { timeoutId = setTimeout(() => reject(new Error(`Pipeline timeout after ${timeout}ms`)), timeout); }) : null; try { if (onStart) { await onStart(input); } for (let i = 0; i < steps.length; i++) { const step = steps[i]; const stepStartTime = Date.now(); if (signal?.aborted) { throw new Error("Pipeline aborted"); } const context = { stepIndex: i, totalSteps: steps.length, previousResults: stepResults, metadata, signal, }; if (onProgress) { await onProgress(i, steps.length); } if (step.condition) { const shouldRun = await step.condition(currentInput, context); if (!shouldRun) { stepResults.push({ stepName: step.name, stepIndex: i, input: currentInput, output: currentInput, l0Result: undefined, status: "skipped", duration: Date.now() - stepStartTime, startTime: stepStartTime, endTime: Date.now(), }); continue; } } try { const l0Options = await step.fn(currentInput, context); const executeStep = async () => { const result = await l0({ ...l0Options, signal, monitoring, }); let content = ""; for await (const event of result.stream) { if (event.type === "token" && event.value) { content += event.value; } } return { ...result, state: { ...result.state, content: content || result.state.content, }, }; }; const l0Result = timeoutPromise ? await Promise.race([executeStep(), timeoutPromise]) : await executeStep(); const stepOutput = step.transform ? await step.transform(l0Result, context) : l0Result.state.content; const stepResult = { stepName: step.name, stepIndex: i, input: currentInput, output: stepOutput, l0Result, status: "success", duration: Date.now() - stepStartTime, startTime: stepStartTime, endTime: Date.now(), }; stepResults.push(stepResult); if (step.onComplete) { await step.onComplete(stepResult, context); } currentInput = stepOutput; finalOutput = stepOutput; } catch (error) { const stepError = error instanceof Error ? error : new Error(String(error)); const stepResult = { stepName: step.name, stepIndex: i, input: currentInput, output: undefined, l0Result: undefined, status: "error", error: stepError, duration: Date.now() - stepStartTime, startTime: stepStartTime, endTime: Date.now(), }; stepResults.push(stepResult); if (step.onError) { await step.onError(stepError, context); } if (onError) { await onError(stepError, i); } if (stopOnError) { pipelineError = stepError; pipelineStatus = "error"; break; } else { pipelineStatus = "partial"; } } } } catch (error) { pipelineError = error instanceof Error ? error : new Error(String(error)); pipelineStatus = "error"; } finally { if (timeoutId) { clearTimeout(timeoutId); } } const result = { name, output: finalOutput, steps: stepResults, status: pipelineStatus, error: pipelineError, duration: Date.now() - startTime, startTime, endTime: Date.now(), metadata, }; if (onComplete) { await onComplete(result); } return result; } export function createPipeline(steps, options = {}) { const pipelineSteps = [...steps]; const pipelineOptions = { ...options }; const pipeline = { name: options.name, steps: pipelineSteps, options: pipelineOptions, async run(input) { return pipe(pipelineSteps, input, pipelineOptions); }, addStep(step) { pipelineSteps.push(step); return pipeline; }, removeStep(name) { const index = pipelineSteps.findIndex((s) => s.name === name); if (index !== -1) { pipelineSteps.splice(index, 1); } return pipeline; }, getStep(name) { return pipelineSteps.find((s) => s.name === name); }, clone() { return createPipeline(pipelineSteps.map((s) => ({ ...s })), { ...pipelineOptions }); }, }; return pipeline; } export function createStep(name, promptFn, streamFactory) { return { name, fn: (input) => ({ stream: () => streamFactory(promptFn(input)), }), }; } export function chainPipelines(...pipelines) { const allSteps = []; for (const p of pipelines) { allSteps.push(...p.steps); } return createPipeline(allSteps, { name: pipelines.map((p) => p.name).join(" -> "), }); } export async function parallelPipelines(pipelines, input, combiner) { const results = await Promise.all(pipelines.map((p) => p.run(input))); return combiner(results); } export function createBranchStep(name, condition, ifTrue, ifFalse) { const branchByContext = new WeakMap(); return { name, fn: async (input, context) => { const result = await condition(input, context); const step = result ? ifTrue : ifFalse; branchByContext.set(context, step); return step.fn(input, context); }, transform: async (result, context) => { const step = branchByContext.get(context) ?? ifTrue; if (step.transform) { return step.transform(result, context); } return result.state.content; }, }; } //# sourceMappingURL=pipeline.js.map