agentfootprint
Version:
The explainable agent framework — backtrack a wrong answer to the exact context that caused it (evidence, not guesses). Built on footprintjs.
63 lines • 3.43 kB
JavaScript
;
/**
* buildCacheSubflow — the per-turn prompt-cache decision, as ONE subflow.
*
* Collapses the cache machinery into a single `sf-cache` boundary so the
* agent chart reads cleanly (one "Cache" box you can drill into) while the
* execution tree stays honest:
*
* decideCacheMarkers → CacheGate (decider) → ApplyMarkers / SkipCaching
*
* Layering (see src/cache/types.ts):
* - This subflow is the provider-AGNOSTIC DECISION layer — it only computes
* and gates provider-neutral `CacheMarker[]`. It knows nothing about any
* provider.
* - The provider-SPECIFIC MECHANISM (Anthropic `cache_control`, OpenAI
* automatic, …) is the attached provider's `CacheStrategy`, selected by
* the provider's declared `promptCaching` (`cacheStrategyFor`), applied
* later when the request is built.
*
* Why `UpdateSkillHistory` is NOT in here: the `skillHistory` rolling window
* must persist across loop iterations. Keeping `UpdateSkillHistory` in the
* main loop (just before this subflow) lets `skillHistory` live in the parent
* scope without round-tripping through this subflow's in/out mappers — the
* subflow stays pure (reads the turn's state, writes only `cacheMarkers`).
*
* Deps-free: every input (`activeInjections`, `iteration`, `skillHistory`,
* `recentHitRate`, `systemPromptCachePolicy`, …) is supplied by the PARENT's
* `inputMapper` at the mount site; the output is just `cacheMarkers`.
*/
Object.defineProperty(exports, "__esModule", { value: true });
exports.buildCacheSubflow = void 0;
const footprintjs_1 = require("footprintjs");
const CacheDecisionSubflow_js_1 = require("../../cache/CacheDecisionSubflow.js");
const CacheGateDecider_js_1 = require("../../cache/CacheGateDecider.js");
const conventions_js_1 = require("../../lib/conventions.js");
/**
* Build the `sf-cache` subflow chart. Called by `buildAgentChart` and
* `buildDynamicAgentChart` and mounted via `addSubFlowChartNext(
* SUBFLOW_IDS.CACHE, buildCacheSubflow(), 'Cache', { inputMapper,
* outputMapper, arrayMerge: Replace })`.
*/
function buildCacheSubflow(options = {}) {
return (0, footprintjs_1.flowChart)('CacheDecision',
// Root stage = the cache-decision function (a chart cannot start with a
// nested subflow). Exported from CacheDecisionSubflow.ts and reused here —
// the cache decision is the root of sf-cache, no logic duplication.
(0, CacheDecisionSubflow_js_1.cacheDecisionStage)(options), 'decide-cache-markers', {
description: 'CacheDecision: walk activeInjections, evaluate cache directives, emit CacheMarker[]',
})
.addDeciderFunction('CacheGate', CacheGateDecider_js_1.cacheGateDecide, conventions_js_1.STAGE_IDS.CACHE_GATE, 'Gate cache-marker application: kill switch / hit-rate / skill-churn')
.addFunctionBranch(conventions_js_1.STAGE_IDS.APPLY_MARKERS, 'ApplyMarkers',
// Pass-through — markers stay in scope; the request build reads them.
() => undefined, 'Proceed with cache markers from CacheDecision')
.addFunctionBranch(conventions_js_1.STAGE_IDS.SKIP_CACHING, 'SkipCaching',
// Clear markers so the request is built unmodified this iteration.
(scope) => {
scope.cacheMarkers = [];
}, 'Skip caching this iteration')
.end()
.build();
}
exports.buildCacheSubflow = buildCacheSubflow;
//# sourceMappingURL=buildCacheSubflow.js.map