@ai2070/l0
Version:
L0: The Missing Reliability Substrate for AI
242 lines (241 loc) • 6.52 kB
JavaScript
import { l0 } from "./runtime/l0";
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: void 0,
status: "skipped",
duration: Date.now() - stepStartTime,
startTime: stepStartTime,
endTime: Date.now()
});
continue;
}
}
try {
const l0Options = await step.fn(currentInput, context);
const executeStep = async () => {
const result2 = await l0({
...l0Options,
signal,
monitoring
});
let content = "";
for await (const event of result2.stream) {
if (event.type === "token" && event.value) {
content += event.value;
}
}
return {
...result2,
state: {
...result2.state,
content: content || result2.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: void 0,
l0Result: void 0,
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;
}
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;
}
function createStep(name, promptFn, streamFactory) {
return {
name,
fn: (input) => ({
stream: () => streamFactory(promptFn(input))
})
};
}
function chainPipelines(...pipelines) {
const allSteps = [];
for (const p of pipelines) {
allSteps.push(...p.steps);
}
return createPipeline(allSteps, {
name: pipelines.map((p) => p.name).join(" -> ")
});
}
async function parallelPipelines(pipelines, input, combiner) {
const results = await Promise.all(pipelines.map((p) => p.run(input)));
return combiner(results);
}
function createBranchStep(name, condition, ifTrue, ifFalse) {
const branchByContext = /* @__PURE__ */ 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;
}
};
}
export {
chainPipelines,
createBranchStep,
createPipeline,
createStep,
parallelPipelines,
pipe
};
//# sourceMappingURL=pipeline.js.map