cmte
Version:
Design by Committee™ except it's just you and LLMs
147 lines (138 loc) • 3.97 kB
JavaScript
import logger from "../../utils/logger.js";
/**
* Resolves references to task outputs using explicit path syntax
*/
export class TaskOutputResolver {
constructor(config = {}) {
this.outputs = new Map();
this.config = {
strict: true,
...config
};
}
/**
* Register an output for a task
*/
registerTaskOutput(phase, taskPath, output, iterations) {
const phaseOutput = this.outputs.get(phase) || {
name: phase,
outputs: {},
iterations: {}
};
// Always register the base output
phaseOutput.outputs[taskPath] = output;
// Register iteration outputs if provided
if (iterations) {
Object.entries(iterations).forEach(([iterationKey, value]) => {
phaseOutput.iterations = phaseOutput.iterations || {};
phaseOutput.iterations[iterationKey] = {
name: `${phase}[${iterationKey}]`,
outputs: {
[taskPath]: value
}
};
});
}
this.outputs.set(phase, phaseOutput);
logger.debug(`Registered output for task ${taskPath} in phase ${phase}`, {
output
});
}
/**
* Parse a reference string into a TaskOutputReference
* Format: $phase.set['iteration'].subset['iteration'].task['iteration']
*/
parseReference(ref) {
// Match the basic structure
const basicMatch = ref.match(/^\$([^.]+)\.([^.[\]]+)(?:\['([^']+)'\])?(?:\.([^.[\]]+)(?:\['([^']+)'\])?)?\.([^.[\]]+)(?:\['([^']+)'\])?$/);
if (!basicMatch) {
return null;
}
const [, phase, set, setIter, subset, subsetIter, task, taskIter] = basicMatch;
const reference = {
phase,
set,
task
};
if (subset) {
reference.subset = subset;
}
if (setIter || subsetIter || taskIter) {
reference.iterations = {};
if (setIter) reference.iterations.set = setIter;
if (subsetIter) reference.iterations.subset = subsetIter;
if (taskIter) reference.iterations.task = taskIter;
}
return reference;
}
/**
* Build a task path from a reference
*/
buildTaskPath(ref) {
const parts = [ref.set];
if (ref.subset) parts.push(ref.subset);
parts.push(ref.task);
return parts.join('.');
}
/**
* Resolve a reference to a task's output
*/
resolveReference(ref) {
// Parse the reference
const reference = this.parseReference(ref);
if (!reference) {
return {
value: '',
success: false,
error: `Invalid reference format: ${ref}`
};
}
// Get the phase output
const phaseOutput = this.outputs.get(reference.phase);
if (!phaseOutput) {
return {
value: '',
success: false,
error: `Phase not found: ${reference.phase}`
};
}
const taskPath = this.buildTaskPath(reference);
// Handle iterations if specified
if (reference.iterations) {
// Find the most specific iteration that matches
const iterationKeys = Object.entries(reference.iterations).map(([level, value]) => `${level}:${value}`).join('.');
if (!phaseOutput.iterations?.[iterationKeys]) {
return {
value: '',
success: false,
error: `No output found for iterations ${iterationKeys} in phase ${reference.phase}`
};
}
const output = phaseOutput.iterations[iterationKeys].outputs[taskPath];
if (!output) {
return {
value: '',
success: false,
error: `Task ${taskPath} not found in iterations ${iterationKeys} of phase ${reference.phase}`
};
}
return {
value: output,
success: true
};
}
// Handle direct task reference
const output = phaseOutput.outputs[taskPath];
if (!output) {
return {
value: '',
success: false,
error: `Task ${taskPath} not found in phase ${reference.phase}`
};
}
return {
value: output,
success: true
};
}
}