agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
92 lines • 4.03 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.readCacheUsage = exports.applyCacheMarkers = exports.bedrockPromptCaching = void 0;
const bedrockModels_js_1 = require("./bedrockModels.js");
function bedrockPromptCaching(model) {
const facts = (0, bedrockModels_js_1.bedrockCacheFacts)(model);
return facts === undefined
? undefined
: {
mode: 'breakpoints',
maxBreakpoints: facts.maxBreakpoints,
reportsUsage: true,
...(!facts.tools && { fields: ['system', 'messages'] }),
};
}
exports.bedrockPromptCaching = bedrockPromptCaching;
/** Translate only valid original boundaries; a dropped message never marks a
* neighbor. Deduplicate, cap, then insert backwards so indices never shift.
* TTLs follow wire order (tools → system → messages), independent of marker
* arrival order: a long TTL after a short one is safely reduced to default.
*/
function applyCacheMarkers(body, markers, model, positions) {
const facts = (0, bedrockModels_js_1.bedrockCacheFacts)(model);
if (facts === undefined)
return;
const boundaries = new Map();
for (const marker of markers) {
if (!Number.isSafeInteger(marker.boundaryIndex) || marker.boundaryIndex < 0)
continue;
let array;
let index = marker.boundaryIndex;
let order = 0;
let identity = '';
if (marker.field === 'tools' && facts.tools) {
array = body.toolConfig?.tools;
identity = `tools:${index}`;
}
else if (marker.field === 'system') {
// The port carries one composed system string, as the Anthropic wire
// does. A system marker covers that single block, not invented pieces.
array = body.system;
index = 0;
order = 1;
identity = 'system';
}
else if (marker.field === 'messages') {
const position = positions[index];
if (position === undefined)
continue;
array = body.messages[position.message]?.content;
index = position.content;
order = position.message + 2;
identity = `message:${position.message}:${index}`;
}
if (array === undefined || index >= array.length || identity === '')
continue;
// A duplicate never upgrades a short cache request to a pricier long TTL.
const previous = boundaries.get(identity);
const long = marker.ttl === 'long' && facts.longTtl;
boundaries.set(identity, { array, index, order, long: long && (previous?.long ?? true) });
if (boundaries.size >= facts.maxBreakpoints)
break;
}
const selected = [...boundaries.values()]
.sort((a, b) => a.order - b.order || a.index - b.index)
.slice(0, facts.maxBreakpoints);
let shortSeen = false;
const points = selected.map((boundary) => {
const long = boundary.long && !shortSeen;
if (!long)
shortSeen = true;
const point = {
cachePoint: { type: 'default', ...(long && { ttl: '1h' }) },
};
return { ...boundary, point };
});
for (const { array, index, point } of points.reverse())
array.splice(index + 1, 0, point);
}
exports.applyCacheMarkers = applyCacheMarkers;
/** Present zero is measured; absent or malformed cache counters stay absent.
* inputTokens is fresh input (AWS excludes both cache reads and writes), the
* same semantics the port cache meter expects from Anthropic's adapter. */
function readCacheUsage(usage) {
const count = (value) => Number.isSafeInteger(value) && value >= 0;
return {
...(count(usage?.cacheReadInputTokens) && { cacheRead: usage?.cacheReadInputTokens }),
...(count(usage?.cacheWriteInputTokens) && { cacheWrite: usage?.cacheWriteInputTokens }),
};
}
exports.readCacheUsage = readCacheUsage;
//# sourceMappingURL=bedrockCacheWire.js.map