agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
96 lines • 3.71 kB
JavaScript
import { retireReplayHistory } from '../thinking/replayHistory.js';
/**
* The leaf still chooses whether anything may be omitted. A retry or fallback
* must remember that choice before its next attempt, even when the first wire
* fails after preparation. Never adopt the whole prepared request: resolved
* models, cache hints and other wire-local adjustments belong to that leaf.
*/
export function replayAttempts(request, hooks) {
let current = request;
const reported = new Map();
function response(answer) {
if (reported.size === 0 && !answer.replayOmissions?.length)
return answer;
const total = new Map(reported);
const existing = answer.replayOmissions ?? [];
remember(total, existing);
const omissions = [...total.values()];
if (omissions.length === existing.length &&
omissions.every((item, index) => omissionKey(item) === omissionKey(existing[index])))
return answer;
return { ...answer, replayOmissions: omissions };
}
function chunk(item) {
if (!item.done || item.response === undefined)
return item;
const answer = response(item.response);
return answer === item.response ? item : { ...item, response: answer };
}
function result(item) {
if (item.done)
return item;
const value = chunk(item.value);
return value === item.value ? item : { ...item, value };
}
return {
get request() {
return current;
},
/** The reliability loop explicitly owns feedback and other request changes. */
replaceRequest(next) {
current = next;
},
response,
chunk,
/** Preserve the underlying iterator's cancellation/throw protocol. */
iterator(inner) {
const close = inner.return?.bind(inner);
const raise = inner.throw?.bind(inner);
return {
next: async (...args) => result(await inner.next(...args)),
...(close && {
return: async (...args) => result(await close(...args)),
}),
...(raise && {
throw: async (...args) => result(await raise(...args)),
}),
};
},
hooks: {
...hooks,
onReplayPrepared(preparation) {
const messages = retireReplayHistory(current.messages, preparation);
hooks?.onReplayPrepared?.(preparation);
// A failed durable write must be attempted again, not hidden by a
// local omission that lets the next leaf bypass that failed hook.
if (messages !== current.messages)
current = { ...current, messages };
remember(reported, preparation.omissions);
},
},
};
}
/** All declared metadata fields identify one report; no model content is copied. */
function omissionKey(item) {
return JSON.stringify([
item.messageIndex,
item.blockIndex,
item.reason,
item.replayId ?? null,
item.messageFingerprint,
]);
}
function remember(target, items) {
for (const item of items) {
const key = omissionKey(item);
if (!target.has(key))
target.set(key, {
messageIndex: item.messageIndex,
blockIndex: item.blockIndex,
reason: item.reason,
...(item.replayId !== undefined && { replayId: item.replayId }),
messageFingerprint: item.messageFingerprint,
});
}
}
//# sourceMappingURL=replayAttempt.js.map