agentfootprint 2.11.1 → 2.11.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (67) hide show
  1. package/dist/core/Agent.js +81 -1238
  2. package/dist/core/Agent.js.map +1 -1
  3. package/dist/core/agent/AgentBuilder.js +489 -0
  4. package/dist/core/agent/AgentBuilder.js.map +1 -0
  5. package/dist/core/agent/buildAgentChart.js +227 -0
  6. package/dist/core/agent/buildAgentChart.js.map +1 -0
  7. package/dist/core/agent/buildToolRegistry.js +115 -0
  8. package/dist/core/agent/buildToolRegistry.js.map +1 -0
  9. package/dist/core/agent/stages/breakFinal.js +28 -0
  10. package/dist/core/agent/stages/breakFinal.js.map +1 -0
  11. package/dist/core/agent/stages/callLLM.js +129 -0
  12. package/dist/core/agent/stages/callLLM.js.map +1 -0
  13. package/dist/core/agent/stages/iterationStart.js +24 -0
  14. package/dist/core/agent/stages/iterationStart.js.map +1 -0
  15. package/dist/core/agent/stages/prepareFinal.js +45 -0
  16. package/dist/core/agent/stages/prepareFinal.js.map +1 -0
  17. package/dist/core/agent/stages/route.js +36 -0
  18. package/dist/core/agent/stages/route.js.map +1 -0
  19. package/dist/core/agent/stages/seed.js +95 -0
  20. package/dist/core/agent/stages/seed.js.map +1 -0
  21. package/dist/core/agent/stages/toolCalls.js +250 -0
  22. package/dist/core/agent/stages/toolCalls.js.map +1 -0
  23. package/dist/esm/core/Agent.js +83 -1239
  24. package/dist/esm/core/Agent.js.map +1 -1
  25. package/dist/esm/core/agent/AgentBuilder.js +485 -0
  26. package/dist/esm/core/agent/AgentBuilder.js.map +1 -0
  27. package/dist/esm/core/agent/buildAgentChart.js +223 -0
  28. package/dist/esm/core/agent/buildAgentChart.js.map +1 -0
  29. package/dist/esm/core/agent/buildToolRegistry.js +111 -0
  30. package/dist/esm/core/agent/buildToolRegistry.js.map +1 -0
  31. package/dist/esm/core/agent/stages/breakFinal.js +24 -0
  32. package/dist/esm/core/agent/stages/breakFinal.js.map +1 -0
  33. package/dist/esm/core/agent/stages/callLLM.js +125 -0
  34. package/dist/esm/core/agent/stages/callLLM.js.map +1 -0
  35. package/dist/esm/core/agent/stages/iterationStart.js +20 -0
  36. package/dist/esm/core/agent/stages/iterationStart.js.map +1 -0
  37. package/dist/esm/core/agent/stages/prepareFinal.js +41 -0
  38. package/dist/esm/core/agent/stages/prepareFinal.js.map +1 -0
  39. package/dist/esm/core/agent/stages/route.js +32 -0
  40. package/dist/esm/core/agent/stages/route.js.map +1 -0
  41. package/dist/esm/core/agent/stages/seed.js +91 -0
  42. package/dist/esm/core/agent/stages/seed.js.map +1 -0
  43. package/dist/esm/core/agent/stages/toolCalls.js +246 -0
  44. package/dist/esm/core/agent/stages/toolCalls.js.map +1 -0
  45. package/dist/types/core/Agent.d.ts +5 -333
  46. package/dist/types/core/Agent.d.ts.map +1 -1
  47. package/dist/types/core/agent/AgentBuilder.d.ts +348 -0
  48. package/dist/types/core/agent/AgentBuilder.d.ts.map +1 -0
  49. package/dist/types/core/agent/buildAgentChart.d.ts +74 -0
  50. package/dist/types/core/agent/buildAgentChart.d.ts.map +1 -0
  51. package/dist/types/core/agent/buildToolRegistry.d.ts +62 -0
  52. package/dist/types/core/agent/buildToolRegistry.d.ts.map +1 -0
  53. package/dist/types/core/agent/stages/breakFinal.d.ts +23 -0
  54. package/dist/types/core/agent/stages/breakFinal.d.ts.map +1 -0
  55. package/dist/types/core/agent/stages/callLLM.d.ts +54 -0
  56. package/dist/types/core/agent/stages/callLLM.d.ts.map +1 -0
  57. package/dist/types/core/agent/stages/iterationStart.d.ts +16 -0
  58. package/dist/types/core/agent/stages/iterationStart.d.ts.map +1 -0
  59. package/dist/types/core/agent/stages/prepareFinal.d.ts +20 -0
  60. package/dist/types/core/agent/stages/prepareFinal.d.ts.map +1 -0
  61. package/dist/types/core/agent/stages/route.d.ts +19 -0
  62. package/dist/types/core/agent/stages/route.d.ts.map +1 -0
  63. package/dist/types/core/agent/stages/seed.d.ts +54 -0
  64. package/dist/types/core/agent/stages/seed.d.ts.map +1 -0
  65. package/dist/types/core/agent/stages/toolCalls.d.ts +50 -0
  66. package/dist/types/core/agent/stages/toolCalls.d.ts.map +1 -0
  67. package/package.json +1 -1
@@ -0,0 +1,223 @@
1
+ /**
2
+ * buildAgentChart — assemble the agent's full footprintjs FlowChart
3
+ * from stage functions + slot subflows + memory wiring.
4
+ *
5
+ * This is the "chart composition" that used to live inline in
6
+ * `Agent.buildChart()`. Extracted for v2.11.2 so:
7
+ *
8
+ * 1. Agent.ts focuses on Agent class lifecycle (constructor, run,
9
+ * attach, getSpec) instead of chart wiring details.
10
+ * 2. The reliability gate chart (v2.11.x) wires into ONE focused
11
+ * file rather than surgically into Agent.ts's 250-line composition
12
+ * block.
13
+ * 3. The composition is independently readable + reviewable —
14
+ * consumers building custom agent shapes have a reference.
15
+ *
16
+ * Chart shape:
17
+ *
18
+ * Seed
19
+ * → [memory READ subflows for each .memory()]
20
+ * → InjectionEngine (subflow)
21
+ * → SystemPrompt (slot subflow)
22
+ * → Messages (slot subflow)
23
+ * → Tools (slot subflow)
24
+ * → CacheDecision (subflow)
25
+ * → UpdateSkillHistory
26
+ * → CacheGate (decider) → ApplyMarkers / SkipCaching
27
+ * → IterationStart
28
+ * → CallLLM
29
+ * → Route (decider) → tool-calls (pausable) / final (subflow)
30
+ * |
31
+ * ┌────── PrepareFinal ▼
32
+ * ├──── [memory WRITE subflows]
33
+ * └──── BreakFinal ($break)
34
+ * loopTo(InjectionEngine)
35
+ *
36
+ * (When v2.11.x reliability is configured, the reliability gate chart
37
+ * mounts as a subflow between IterationStart and CallLLM with a
38
+ * TranslateFailFast stage after it. Lands in the next commit.)
39
+ */
40
+ import { ArrayMergeMode } from 'footprintjs/advanced';
41
+ import { flowChart } from 'footprintjs';
42
+ import { STAGE_IDS, SUBFLOW_IDS } from '../../conventions.js';
43
+ import { memoryInjectionKey } from '../../memory/define.types.js';
44
+ import { unwrapMemoryFlowChart } from '../../memory/define.js';
45
+ import { mountMemoryRead, mountMemoryWrite } from '../../memory/wire/mountMemoryPipeline.js';
46
+ import { breakFinalStage } from './stages/breakFinal.js';
47
+ import { prepareFinalStage } from './stages/prepareFinal.js';
48
+ /**
49
+ * Build the agent's complete FlowChart from the supplied deps.
50
+ */
51
+ export function buildAgentChart(deps) {
52
+ // ── Final-branch subflow ─────────────────────────────────────
53
+ // Split so memory-write subflows can mount BETWEEN setting
54
+ // finalContent and breaking the ReAct loop. PrepareFinal captures
55
+ // the turn payload; BreakFinal terminates the loop.
56
+ let finalBranchBuilder = flowChart('PrepareFinal', prepareFinalStage, 'prepare-final', undefined, 'Capture turn payload (finalContent + newMessages)');
57
+ for (const m of deps.memories) {
58
+ if (m.write) {
59
+ finalBranchBuilder = mountMemoryWrite(finalBranchBuilder, {
60
+ pipeline: {
61
+ read: unwrapMemoryFlowChart(m.read),
62
+ write: unwrapMemoryFlowChart(m.write),
63
+ },
64
+ identityKey: 'runIdentity',
65
+ turnNumberKey: 'turnNumber',
66
+ contextTokensKey: 'contextTokensRemaining',
67
+ newMessagesKey: 'newMessages',
68
+ writeSubflowId: `sf-memory-write-${m.id}`,
69
+ });
70
+ }
71
+ }
72
+ const finalBranchChart = finalBranchBuilder
73
+ .addFunction('BreakFinal', breakFinalStage, 'break-final', 'Terminate the ReAct loop')
74
+ .build();
75
+ // ── Main chart ──────────────────────────────────────────────
76
+ // Description prefix `Agent:` is a taxonomy marker — consumers
77
+ // (Lens + FlowchartRecorder) detect Agent-primitive subflows via
78
+ // this prefix and flag them as true agent boundaries (separate
79
+ // from LLMCall subflows which use `LLMCall:` prefix).
80
+ let builder = flowChart('Seed', deps.seed, STAGE_IDS.SEED, undefined, 'Agent: ReAct loop');
81
+ // Memory READ subflows — mounted between Seed and InjectionEngine
82
+ // for TURN_START timing (default). Each memory writes to its own
83
+ // scope key (`memoryInjection_${id}`) so multiple `.memory()`
84
+ // registrations layer without colliding.
85
+ for (const m of deps.memories) {
86
+ builder = mountMemoryRead(builder, {
87
+ pipeline: {
88
+ read: unwrapMemoryFlowChart(m.read),
89
+ ...(m.write !== undefined && { write: unwrapMemoryFlowChart(m.write) }),
90
+ },
91
+ identityKey: 'runIdentity',
92
+ turnNumberKey: 'turnNumber',
93
+ contextTokensKey: 'contextTokensRemaining',
94
+ injectionKey: memoryInjectionKey(m.id),
95
+ readSubflowId: `sf-memory-read-${m.id}`,
96
+ });
97
+ }
98
+ builder = builder
99
+ // Injection Engine — evaluates every Injection's trigger once
100
+ // per iteration; writes activeInjections[] to parent scope for
101
+ // the slot subflows to consume. Skipped if no injections were
102
+ // registered (no observable difference, just one more no-op
103
+ // subflow boundary).
104
+ .addSubFlowChartNext(SUBFLOW_IDS.INJECTION_ENGINE, deps.injectionEngineSubflow, 'Injection Engine', {
105
+ inputMapper: (parent) => ({
106
+ iteration: parent.iteration,
107
+ userMessage: parent.userMessage,
108
+ history: parent.history,
109
+ lastToolResult: parent.lastToolResult,
110
+ activatedInjectionIds: parent.activatedInjectionIds ?? [],
111
+ }),
112
+ outputMapper: (sf) => ({ activeInjections: sf.activeInjections }),
113
+ // CRITICAL: footprintjs's default `applyOutputMapping`
114
+ // CONCATENATES arrays from subflow output with the parent's
115
+ // existing array values. Without `Replace`, the parent's
116
+ // `activeInjections` from iter N gets CONCATENATED with the
117
+ // subflow's iter N+1 fresh evaluation — producing
118
+ // 8 → 16 → 24 → 32 cumulative injections per turn.
119
+ arrayMerge: ArrayMergeMode.Replace,
120
+ })
121
+ .addSubFlowChartNext(SUBFLOW_IDS.SYSTEM_PROMPT, deps.systemPromptSubflow, 'System Prompt', {
122
+ inputMapper: (parent) => ({
123
+ userMessage: parent.userMessage,
124
+ iteration: parent.iteration,
125
+ activeInjections: parent.activeInjections,
126
+ }),
127
+ outputMapper: (sf) => ({ systemPromptInjections: sf.systemPromptInjections }),
128
+ arrayMerge: ArrayMergeMode.Replace,
129
+ })
130
+ .addSubFlowChartNext(SUBFLOW_IDS.MESSAGES, deps.messagesSubflow, 'Messages', {
131
+ inputMapper: (parent) => ({
132
+ messages: parent.history,
133
+ iteration: parent.iteration,
134
+ activeInjections: parent.activeInjections,
135
+ }),
136
+ outputMapper: (sf) => ({ messagesInjections: sf.messagesInjections }),
137
+ arrayMerge: ArrayMergeMode.Replace,
138
+ })
139
+ .addSubFlowChartNext(SUBFLOW_IDS.TOOLS, deps.toolsSubflow, 'Tools', {
140
+ inputMapper: (parent) => ({
141
+ iteration: parent.iteration,
142
+ activeInjections: parent.activeInjections,
143
+ // The slot subflow reads these to build the per-iteration
144
+ // ToolDispatchContext when an external `.toolProvider()` is
145
+ // configured. Without them the provider sees activeSkillId
146
+ // = undefined every iteration, breaking skillScopedTools etc.
147
+ activatedInjectionIds: parent.activatedInjectionIds,
148
+ runIdentity: parent.runIdentity,
149
+ }),
150
+ outputMapper: (sf) => ({
151
+ toolsInjections: sf.toolsInjections,
152
+ // Pass merged tool schemas (registry + injection-supplied)
153
+ // back up so callLLM uses the right list for THIS iteration.
154
+ dynamicToolSchemas: sf.toolSchemas,
155
+ }),
156
+ // Same array-concat hazard as InjectionEngine — replace, don't
157
+ // concatenate. Without Replace the deduped tool list re-acquires
158
+ // duplicates that providers reject.
159
+ arrayMerge: ArrayMergeMode.Replace,
160
+ })
161
+ // ── Cache layer (v2.6) ─────────────────────────────────────
162
+ .addSubFlowChartNext(SUBFLOW_IDS.CACHE_DECISION, deps.cacheDecisionSubflow, 'CacheDecision', {
163
+ inputMapper: (parent) => ({
164
+ activeInjections: parent.activeInjections ?? [],
165
+ iteration: parent.iteration ?? 1,
166
+ maxIterations: parent.maxIterations ?? deps.maxIterations,
167
+ userMessage: parent.userMessage ?? '',
168
+ ...(parent.lastToolResult !== undefined && {
169
+ lastToolName: parent.lastToolResult?.toolName,
170
+ }),
171
+ cumulativeInputTokens: parent.totalInputTokens ?? 0,
172
+ systemPromptCachePolicy: deps.systemPromptCachePolicy,
173
+ cachingDisabled: parent.cachingDisabled ?? false,
174
+ }),
175
+ outputMapper: (sf) => ({ cacheMarkers: sf.cacheMarkers }),
176
+ arrayMerge: ArrayMergeMode.Replace,
177
+ })
178
+ .addFunction('UpdateSkillHistory', deps.updateSkillHistoryStage, STAGE_IDS.UPDATE_SKILL_HISTORY, 'Update skill-history rolling window for CacheGate churn detection')
179
+ .addDeciderFunction('CacheGate', deps.cacheGateDecide, STAGE_IDS.CACHE_GATE, 'Gate cache-marker application: kill switch / hit-rate / skill-churn')
180
+ .addFunctionBranch(STAGE_IDS.APPLY_MARKERS, 'ApplyMarkers',
181
+ // Pass-through stage — markers stay in scope as-is.
182
+ // BuildLLMRequest (Phase 7+) reads them on the next stage.
183
+ () => undefined, 'Proceed with cache markers from CacheDecision')
184
+ .addFunctionBranch(STAGE_IDS.SKIP_CACHING, 'SkipCaching',
185
+ // Clear markers so BuildLLMRequest sees an empty list and
186
+ // makes the request unmodified.
187
+ (scope) => {
188
+ scope.cacheMarkers = [];
189
+ }, 'Skip caching this iteration')
190
+ .end()
191
+ .addFunction('IterationStart', deps.iterationStart, 'iteration-start', 'Iteration begin marker')
192
+ .addFunction('CallLLM', deps.callLLM, STAGE_IDS.CALL_LLM, 'LLM invocation')
193
+ .addDeciderFunction('Route', deps.routeDecider, SUBFLOW_IDS.ROUTE, 'ReAct routing')
194
+ .addPausableFunctionBranch('tool-calls', 'ToolCalls', deps.toolCallsHandler, 'Tool execution (pausable via pauseHere)')
195
+ .addSubFlowChartBranch('final', finalBranchChart, 'Final', {
196
+ // Pass through the read-only state the sub-chart needs;
197
+ // OMIT keys the sub-chart writes (finalContent, newMessages)
198
+ // — passing those via inputMapper would freeze them as args.
199
+ inputMapper: (parent) => {
200
+ const { finalContent: _f, newMessages: _nm, ...rest } = parent;
201
+ void _f;
202
+ void _nm;
203
+ return rest;
204
+ },
205
+ outputMapper: (sf) => ({
206
+ finalContent: sf.finalContent,
207
+ }),
208
+ // BreakFinal's $break() must reach the outer loopTo so the
209
+ // ReAct iteration terminates; without this the inner break
210
+ // only exits the sub-chart and the outer loop continues.
211
+ propagateBreak: true,
212
+ })
213
+ .setDefault('final')
214
+ .end()
215
+ // Dynamic ReAct: loop back to the InjectionEngine so EVERY iteration
216
+ // re-evaluates triggers (rule predicates, on-tool-return,
217
+ // llm-activated) against the freshest context (the just-appended
218
+ // tool result). Without this, the InjectionEngine runs ONCE per
219
+ // turn — quietly breaking the framework's "Dynamic ReAct" claim.
220
+ .loopTo(SUBFLOW_IDS.INJECTION_ENGINE);
221
+ return builder.build();
222
+ }
223
+ //# sourceMappingURL=buildAgentChart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buildAgentChart.js","sourceRoot":"","sources":["../../../../src/core/agent/buildAgentChart.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,111 @@
1
+ /**
2
+ * buildToolRegistry — pure function that composes the agent's
3
+ * augmented tool registry from three sources:
4
+ *
5
+ * 1. **Static registry** — tools registered via `.tool()`. Always
6
+ * visible to the LLM; always executable.
7
+ * 2. **`read_skill`** — auto-attached when ≥1 Skill is registered.
8
+ * Activation tool for LLM-guided Skills.
9
+ * 3. **Skill-supplied tools** (`Skill.inject.tools[]`) — visible
10
+ * only when the Skill is active (filtered by tools-slot subflow);
11
+ * MUST always be in the executor registry so when the LLM calls
12
+ * one, the tool-calls handler can dispatch.
13
+ *
14
+ * Tool-name uniqueness is enforced across all three sources at build
15
+ * time. The LLM only sees `tool.schema.name` (no ids), so names ARE
16
+ * the runtime dispatch key — collisions break the LLM's ability to
17
+ * call the right tool. Throw early instead of subtly shadowing.
18
+ *
19
+ * **Block C runtime — `autoActivate: 'currentSkill'` semantics:**
20
+ * When a skill's `defineSkill({ autoActivate: 'currentSkill' })` is
21
+ * set, its tools are EXCLUDED from the static registry. They flow
22
+ * into the LLM's tool list ONLY through `dynamicSchemas` (the
23
+ * buildToolsSlot path that reads activeInjections), which means
24
+ * they're visible ONLY on iterations after the skill is activated by
25
+ * `read_skill('id')`. Without this, the LLM sees every skill's tools
26
+ * on every iteration and the per-skill-narrowing autoActivate
27
+ * promised in `defineSkill` doesn't actually narrow anything. Skills
28
+ * WITHOUT autoActivate keep the v2.4 behavior (tools always visible)
29
+ * for back-compat.
30
+ *
31
+ * **autoActivate dispatch invariant:** autoActivate skill tools live
32
+ * OUTSIDE the LLM-visible registry (so they don't pollute the
33
+ * per-iteration tool list before the skill activates), but they MUST
34
+ * still be findable by the dispatch handler — the LLM calls them by
35
+ * name once the skill is active, and dispatch looks up by name. We
36
+ * add them to the dispatch map (`registryByName`) so `lookupTool`
37
+ * resolves correctly.
38
+ */
39
+ import { buildReadSkillTool } from '../../lib/injection-engine/skillTools.js';
40
+ /**
41
+ * Compose the augmented tool registry from the static `.tool()`
42
+ * registry + the agent's injections (skills only). Throws on tool-
43
+ * name collisions across sources.
44
+ */
45
+ export function buildToolRegistry(registry, injections) {
46
+ const skills = injections.filter((i) => i.flavor === 'skill');
47
+ // Collect skill tools, deduping by name when the SAME Tool reference
48
+ // is shared across skills. Different Tool implementations under the
49
+ // same name throws (already validated upstream by
50
+ // validateToolNameUniqueness) — we keep the runtime check as
51
+ // belt-and-suspenders.
52
+ const skillToolEntries = [];
53
+ const sharedSkillTools = new Map();
54
+ for (const skill of skills) {
55
+ const meta = skill.metadata;
56
+ const isAutoActivate = meta?.autoActivate === 'currentSkill';
57
+ const toolsFromSkill = skill.inject.tools ?? [];
58
+ for (const tool of toolsFromSkill) {
59
+ const name = tool.schema.name;
60
+ const existing = sharedSkillTools.get(name);
61
+ if (existing) {
62
+ if (existing !== tool) {
63
+ throw new Error(`Agent: tool name '${name}' is declared by multiple skills with different ` +
64
+ `Tool implementations. Skills MAY share the SAME Tool reference; they may ` +
65
+ `NOT register different functions under the same name.`);
66
+ }
67
+ continue; // dedupe — same reference already added
68
+ }
69
+ sharedSkillTools.set(name, tool);
70
+ // autoActivate skills: their tools come ONLY through dynamicSchemas
71
+ // (buildToolsSlot.ts pulls them from activeInjections.inject.tools
72
+ // when the skill is active). Don't pre-load in the static registry.
73
+ if (isAutoActivate)
74
+ continue;
75
+ skillToolEntries.push({ name, tool });
76
+ }
77
+ }
78
+ // buildReadSkillTool returns undefined when skills is empty; the length
79
+ // check below short-circuits so the non-null assertion is safe.
80
+ const readSkillEntries = skills.length > 0 ? [{ name: 'read_skill', tool: buildReadSkillTool(skills) }] : [];
81
+ const augmentedRegistry = [
82
+ ...registry,
83
+ ...readSkillEntries,
84
+ ...skillToolEntries,
85
+ ];
86
+ // Final cross-source name-uniqueness check: static .tool() vs
87
+ // read_skill vs (deduped) skill tools. Catches collisions BETWEEN
88
+ // sources (e.g., a static .tool('foo') colliding with a Skill's foo).
89
+ const seenNames = new Set();
90
+ for (const entry of augmentedRegistry) {
91
+ if (seenNames.has(entry.name)) {
92
+ throw new Error(`Agent: duplicate tool name '${entry.name}'. Tool names must be unique ` +
93
+ `across .tool() registrations and Skills' inject.tools (after deduping ` +
94
+ `same-reference shares across skills). The LLM dispatches by name; ` +
95
+ `collisions break tool routing.`);
96
+ }
97
+ seenNames.add(entry.name);
98
+ }
99
+ const registryByName = new Map(augmentedRegistry.map((e) => [e.name, e.tool]));
100
+ // autoActivate skill tools live outside augmentedRegistry but MUST
101
+ // be findable by name at dispatch time. Add them to the dispatch
102
+ // map so `lookupTool` resolves correctly when the skill activates.
103
+ for (const [name, tool] of sharedSkillTools.entries()) {
104
+ if (!registryByName.has(name)) {
105
+ registryByName.set(name, tool);
106
+ }
107
+ }
108
+ const toolSchemas = augmentedRegistry.map((e) => e.tool.schema);
109
+ return { augmentedRegistry, registryByName, toolSchemas };
110
+ }
111
+ //# sourceMappingURL=buildToolRegistry.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"buildToolRegistry.js","sourceRoot":"","sources":["../../../../src/core/agent/buildToolRegistry.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqCG;AAEH,OAAO,EAAE,kBAAkB,EAAE,MAAM,0CAA0C,CAAC;AAoB9E;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAC/B,QAAsC,EACtC,UAAgC;IAEhC,MAAM,MAAM,GAAG,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,KAAK,OAAO,CAAC,CAAC;IAE9D,qEAAqE;IACrE,oEAAoE;IACpE,kDAAkD;IAClD,6DAA6D;IAC7D,uBAAuB;IACvB,MAAM,gBAAgB,GAAwB,EAAE,CAAC;IACjD,MAAM,gBAAgB,GAAG,IAAI,GAAG,EAAgB,CAAC;IACjD,KAAK,MAAM,KAAK,IAAI,MAAM,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,KAAK,CAAC,QAAiD,CAAC;QACrE,MAAM,cAAc,GAAG,IAAI,EAAE,YAAY,KAAK,cAAc,CAAC;QAC7D,MAAM,cAAc,GAAG,KAAK,CAAC,MAAM,CAAC,KAAK,IAAI,EAAE,CAAC;QAChD,KAAK,MAAM,IAAI,IAAI,cAAc,EAAE,CAAC;YAClC,MAAM,IAAI,GAAG,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC;YAC9B,MAAM,QAAQ,GAAG,gBAAgB,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;YAC5C,IAAI,QAAQ,EAAE,CAAC;gBACb,IAAI,QAAQ,KAAM,IAAwB,EAAE,CAAC;oBAC3C,MAAM,IAAI,KAAK,CACb,qBAAqB,IAAI,kDAAkD;wBACzE,2EAA2E;wBAC3E,uDAAuD,CAC1D,CAAC;gBACJ,CAAC;gBACD,SAAS,CAAC,wCAAwC;YACpD,CAAC;YACD,gBAAgB,CAAC,GAAG,CAAC,IAAI,EAAE,IAAuB,CAAC,CAAC;YACpD,oEAAoE;YACpE,mEAAmE;YACnE,oEAAoE;YACpE,IAAI,cAAc;gBAAE,SAAS;YAC7B,gBAAgB,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QACxC,CAAC;IACH,CAAC;IAED,wEAAwE;IACxE,gEAAgE;IAChE,MAAM,gBAAgB,GACpB,MAAM,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,YAAY,EAAE,IAAI,EAAE,kBAAkB,CAAC,MAAM,CAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACvF,MAAM,iBAAiB,GAAiC;QACtD,GAAG,QAAQ;QACX,GAAG,gBAAgB;QACnB,GAAG,gBAAgB;KACpB,CAAC;IAEF,8DAA8D;IAC9D,kEAAkE;IAClE,sEAAsE;IACtE,MAAM,SAAS,GAAG,IAAI,GAAG,EAAU,CAAC;IACpC,KAAK,MAAM,KAAK,IAAI,iBAAiB,EAAE,CAAC;QACtC,IAAI,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9B,MAAM,IAAI,KAAK,CACb,+BAA+B,KAAK,CAAC,IAAI,+BAA+B;gBACtE,wEAAwE;gBACxE,oEAAoE;gBACpE,gCAAgC,CACnC,CAAC;QACJ,CAAC;QACD,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;IAC5B,CAAC;IAED,MAAM,cAAc,GAAG,IAAI,GAAG,CAC5B,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAU,CAAC,CACxD,CAAC;IACF,mEAAmE;IACnE,iEAAiE;IACjE,mEAAmE;IACnE,KAAK,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,gBAAgB,CAAC,OAAO,EAAE,EAAE,CAAC;QACtD,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;YAC9B,cAAc,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QACjC,CAAC;IACH,CAAC;IACD,MAAM,WAAW,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IAEhE,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,WAAW,EAAE,CAAC;AAC5D,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * breakFinal — terminal stage of the agent's "Final" branch subflow.
3
+ *
4
+ * Fires after the (optional) memory-write subflows have persisted the
5
+ * (user, assistant) pair. `$break()` stops execution before the outer
6
+ * loopTo can re-enter the ReAct loop, ending the iteration cleanly.
7
+ * Returns `scope.finalContent` so the parent's `outputMapper` can
8
+ * surface it as the agent's response.
9
+ *
10
+ * Mounted in the final-branch subflow (built in `buildAgentChart`) as
11
+ * the LAST stage. The parent agent chart mounts the final-branch
12
+ * subflow under the Route decider's `'final'` branch with
13
+ * `propagateBreak: true`, so this $break terminates the outer ReAct
14
+ * loop too.
15
+ */
16
+ /**
17
+ * Pure stage function — no dependencies, no closure over Agent state.
18
+ * Exported as a const, not a factory, since there's nothing to inject.
19
+ */
20
+ export const breakFinalStage = (scope) => {
21
+ scope.$break();
22
+ return scope.finalContent;
23
+ };
24
+ //# sourceMappingURL=breakFinal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"breakFinal.js","sourceRoot":"","sources":["../../../../../src/core/agent/stages/breakFinal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH;;;GAGG;AACH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,KAA6B,EAAU,EAAE;IACvE,KAAK,CAAC,MAAM,EAAE,CAAC;IACf,OAAO,KAAK,CAAC,YAAY,CAAC;AAC5B,CAAC,CAAC"}
@@ -0,0 +1,125 @@
1
+ /**
2
+ * callLLM — the LLM-invocation stage of the agent's chart.
3
+ *
4
+ * Reads the assembled prompt + messages from scope (populated by the
5
+ * upstream slot subflows: SystemPrompt, Messages, Tools, CacheDecision,
6
+ * CacheGate). Calls `provider.stream()` if available (token streaming
7
+ * with per-chunk events) else falls back to `provider.complete()`.
8
+ * Writes the response to scope (`llmLatestContent`, `llmLatestToolCalls`,
9
+ * cumulative tokens) for the downstream Route decider to read.
10
+ *
11
+ * Emits `agentfootprint.stream.llm_start` + `llm_end` brackets for
12
+ * observability adapters and per-chunk `stream.token` events during
13
+ * streaming. Emits `cost.tick` via `emitCostTick` when a `pricingTable`
14
+ * is configured.
15
+ *
16
+ * Factory signature so the chart-build-time provider/model/etc. deps
17
+ * are explicit. The `toolSchemas` value is late-bound via a getter
18
+ * because tool schema composition completes after the seed factory is
19
+ * built but before the chart actually runs.
20
+ */
21
+ import { typedEmit } from '../../../recorders/core/typedEmit.js';
22
+ import { emitCostTick } from '../../cost.js';
23
+ /**
24
+ * Build the callLLM stage function. Captures the LLM provider + model
25
+ * config + cache strategy via the deps object; everything per-iteration
26
+ * comes from scope.
27
+ */
28
+ export function buildCallLLMStage(deps) {
29
+ return async (scope) => {
30
+ const systemPromptInjections = scope.systemPromptInjections ?? [];
31
+ // `scope.messagesInjections` is read by ContextRecorder for
32
+ // observability; the LLM-wire path now reads scope.history directly.
33
+ const iteration = scope.iteration;
34
+ const systemPrompt = systemPromptInjections
35
+ .map((r) => r.rawContent ?? '')
36
+ .filter((s) => s.length > 0)
37
+ .join('\n\n');
38
+ // Read the LLM message stream from `scope.history` directly. The
39
+ // `messagesInjections` projection is for observability — it
40
+ // flattens InjectionRecords for event reporting and doesn't carry
41
+ // the full LLM-protocol shape (assistant `toolCalls[]`, etc.). For
42
+ // Anthropic's API contract we need the original LLMMessage with
43
+ // `toolCalls` intact so tool_use → tool_result correlation survives.
44
+ const messages = scope.history ?? [];
45
+ typedEmit(scope, 'agentfootprint.stream.llm_start', {
46
+ iteration,
47
+ provider: deps.provider.name,
48
+ model: deps.model,
49
+ systemPromptChars: systemPrompt.length,
50
+ messagesCount: messages.length,
51
+ toolsCount: deps.toolSchemas.length,
52
+ ...(deps.temperature !== undefined && { temperature: deps.temperature }),
53
+ });
54
+ const startMs = Date.now();
55
+ // Use dynamic schemas — registry tools + injection-supplied tools
56
+ // (Skills' `inject.tools` when their Injection is active). Falls
57
+ // back to the static schemas at startup before the tools slot has
58
+ // run for the first time.
59
+ const activeToolSchemas = scope.dynamicToolSchemas ?? deps.toolSchemas;
60
+ const baseRequest = {
61
+ ...(systemPrompt.length > 0 && { systemPrompt }),
62
+ messages,
63
+ ...(activeToolSchemas.length > 0 && { tools: activeToolSchemas }),
64
+ model: deps.model,
65
+ ...(deps.temperature !== undefined && { temperature: deps.temperature }),
66
+ ...(deps.maxTokens !== undefined && { maxTokens: deps.maxTokens }),
67
+ };
68
+ // v2.6+ — call cache strategy to attach provider-specific cache
69
+ // hints. CacheGate has already routed (apply-markers / no-markers)
70
+ // and populated scope.cacheMarkers accordingly. Strategy.prepareRequest
71
+ // is a pass-through for empty markers.
72
+ const cacheMarkers = scope.cacheMarkers ?? [];
73
+ const cachePrepared = await deps.cacheStrategy.prepareRequest(baseRequest, cacheMarkers, {
74
+ iteration,
75
+ iterationsRemaining: Math.max(0, deps.maxIterations - iteration),
76
+ recentHitRate: scope.recentHitRate,
77
+ cachingDisabled: scope.cachingDisabled ?? false,
78
+ });
79
+ const llmRequest = cachePrepared.request;
80
+ // Streaming-first: when the provider implements `stream()` we
81
+ // consume chunk-by-chunk so consumers see tokens as they arrive
82
+ // instead of waiting for the full LLM call to finish. Each
83
+ // non-terminal chunk fires `agentfootprint.stream.token`. The
84
+ // terminal chunk SHOULD carry the authoritative `LLMResponse`;
85
+ // when it doesn't (older providers, partial implementations) we
86
+ // fall back to `complete()` for the authoritative payload —
87
+ // keeping the ReAct loop deterministic.
88
+ let response;
89
+ if (deps.provider.stream) {
90
+ for await (const chunk of deps.provider.stream(llmRequest)) {
91
+ if (chunk.done) {
92
+ if (chunk.response)
93
+ response = chunk.response;
94
+ break;
95
+ }
96
+ if (chunk.content.length > 0) {
97
+ typedEmit(scope, 'agentfootprint.stream.token', {
98
+ iteration,
99
+ tokenIndex: chunk.tokenIndex,
100
+ content: chunk.content,
101
+ });
102
+ }
103
+ }
104
+ }
105
+ if (!response) {
106
+ // No `stream()` OR stream finished without a response payload.
107
+ response = await deps.provider.complete(llmRequest);
108
+ }
109
+ const durationMs = Date.now() - startMs;
110
+ scope.totalInputTokens = scope.totalInputTokens + response.usage.input;
111
+ scope.totalOutputTokens = scope.totalOutputTokens + response.usage.output;
112
+ scope.llmLatestContent = response.content;
113
+ scope.llmLatestToolCalls = response.toolCalls;
114
+ typedEmit(scope, 'agentfootprint.stream.llm_end', {
115
+ iteration,
116
+ content: response.content,
117
+ toolCallCount: response.toolCalls.length,
118
+ usage: response.usage,
119
+ stopReason: response.stopReason,
120
+ durationMs,
121
+ });
122
+ emitCostTick(scope, deps.pricingTable, deps.costBudget, deps.model, response.usage);
123
+ };
124
+ }
125
+ //# sourceMappingURL=callLLM.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"callLLM.js","sourceRoot":"","sources":["../../../../../src/core/agent/stages/callLLM.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * iterationStart — per-iteration marker stage.
3
+ *
4
+ * Emits `agentfootprint.agent.iteration_start` so observability adapters
5
+ * + recorders can bracket each ReAct iteration. Fires AFTER the slot
6
+ * subflows (SystemPrompt, Messages, Tools, CacheDecision, CacheGate)
7
+ * have produced this iteration's prompt assembly and BEFORE CallLLM.
8
+ *
9
+ * `turnIndex: 0` is intentional — the agent currently runs ONE turn per
10
+ * `agent.run()`. The turn index is reserved for future multi-turn
11
+ * orchestration; iteration index is the per-iteration counter.
12
+ */
13
+ import { typedEmit } from '../../../recorders/core/typedEmit.js';
14
+ export const iterationStartStage = (scope) => {
15
+ typedEmit(scope, 'agentfootprint.agent.iteration_start', {
16
+ turnIndex: 0,
17
+ iterIndex: scope.iteration,
18
+ });
19
+ };
20
+ //# sourceMappingURL=iterationStart.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"iterationStart.js","sourceRoot":"","sources":["../../../../../src/core/agent/stages/iterationStart.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,sCAAsC,CAAC;AAGjE,MAAM,CAAC,MAAM,mBAAmB,GAAG,CAAC,KAA6B,EAAQ,EAAE;IACzE,SAAS,CAAC,KAAK,EAAE,sCAAsC,EAAE;QACvD,SAAS,EAAE,CAAC;QACZ,SAAS,EAAE,KAAK,CAAC,SAAS;KAC3B,CAAC,CAAC;AACL,CAAC,CAAC"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * prepareFinal — first stage of the agent's "Final" branch subflow.
3
+ *
4
+ * Captures the turn payload (`finalContent` from the LLM's latest
5
+ * content; `newMessages` as the `[user, assistant]` pair the memory-
6
+ * write subflows persist) and emits the per-turn observability
7
+ * brackets (`iteration_end`, `turn_end`).
8
+ *
9
+ * Mounted as the FIRST stage of the final-branch subflow built in
10
+ * `buildAgentChart`. Subsequent memory-write subflows mount AFTER this
11
+ * stage so they have `newMessages` available; `breakFinal` is the
12
+ * terminal stage that stops the ReAct loop.
13
+ *
14
+ * Pure function — no closure over Agent class state. Imported and
15
+ * passed directly to `flowChart(...)` in buildAgentChart.
16
+ */
17
+ import { typedEmit } from '../../../recorders/core/typedEmit.js';
18
+ export const prepareFinalStage = (scope) => {
19
+ const iteration = scope.iteration;
20
+ scope.finalContent = scope.llmLatestContent;
21
+ // The turn payload memory writes persist: the user's message
22
+ // paired with the agent's final answer.
23
+ scope.newMessages = [
24
+ { role: 'user', content: scope.userMessage },
25
+ { role: 'assistant', content: scope.finalContent },
26
+ ];
27
+ typedEmit(scope, 'agentfootprint.agent.iteration_end', {
28
+ turnIndex: 0,
29
+ iterIndex: iteration,
30
+ toolCallCount: 0,
31
+ });
32
+ typedEmit(scope, 'agentfootprint.agent.turn_end', {
33
+ turnIndex: 0,
34
+ finalContent: scope.finalContent,
35
+ totalInputTokens: scope.totalInputTokens,
36
+ totalOutputTokens: scope.totalOutputTokens,
37
+ iterationCount: iteration,
38
+ durationMs: Date.now() - scope.turnStartMs,
39
+ });
40
+ };
41
+ //# sourceMappingURL=prepareFinal.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prepareFinal.js","sourceRoot":"","sources":["../../../../../src/core/agent/stages/prepareFinal.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,sCAAsC,CAAC;AAGjE,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,KAA6B,EAAQ,EAAE;IACvE,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS,CAAC;IAClC,KAAK,CAAC,YAAY,GAAG,KAAK,CAAC,gBAAgB,CAAC;IAC5C,6DAA6D;IAC7D,wCAAwC;IACxC,KAAK,CAAC,WAAW,GAAG;QAClB,EAAE,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,CAAC,WAAW,EAAE;QAC5C,EAAE,IAAI,EAAE,WAAW,EAAE,OAAO,EAAE,KAAK,CAAC,YAAY,EAAE;KACnD,CAAC;IAEF,SAAS,CAAC,KAAK,EAAE,oCAAoC,EAAE;QACrD,SAAS,EAAE,CAAC;QACZ,SAAS,EAAE,SAAS;QACpB,aAAa,EAAE,CAAC;KACjB,CAAC,CAAC;IACH,SAAS,CAAC,KAAK,EAAE,+BAA+B,EAAE;QAChD,SAAS,EAAE,CAAC;QACZ,YAAY,EAAE,KAAK,CAAC,YAAY;QAChC,gBAAgB,EAAE,KAAK,CAAC,gBAAgB;QACxC,iBAAiB,EAAE,KAAK,CAAC,iBAAiB;QAC1C,cAAc,EAAE,SAAS;QACzB,UAAU,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,WAAW;KAC3C,CAAC,CAAC;AACL,CAAC,CAAC"}
@@ -0,0 +1,32 @@
1
+ /**
2
+ * route — decider that branches the ReAct loop into 'tool-calls' or 'final'.
3
+ *
4
+ * Runs after CallLLM. If the LLM returned tool calls AND we haven't hit
5
+ * `maxIterations`, route to the tool execution branch (which loops back
6
+ * to PromptBuilder). Otherwise route to the final-branch subflow which
7
+ * persists memory writes and breaks the loop.
8
+ *
9
+ * Emits `agentfootprint.agent.route_decided` with the chosen branch +
10
+ * a human-readable rationale (visible in narrative + observability).
11
+ *
12
+ * Pure function — no closure over Agent class state. Imported and
13
+ * passed directly to `addDeciderFunction(...)` in buildAgentChart.
14
+ */
15
+ import { typedEmit } from '../../../recorders/core/typedEmit.js';
16
+ export const routeDeciderStage = (scope) => {
17
+ const toolCalls = scope.llmLatestToolCalls;
18
+ const iteration = scope.iteration;
19
+ const chosen = toolCalls.length > 0 && iteration < scope.maxIterations ? 'tool-calls' : 'final';
20
+ typedEmit(scope, 'agentfootprint.agent.route_decided', {
21
+ turnIndex: 0,
22
+ iterIndex: iteration,
23
+ chosen,
24
+ rationale: chosen === 'tool-calls'
25
+ ? `LLM requested ${toolCalls.length} tool call(s)`
26
+ : iteration >= scope.maxIterations
27
+ ? 'maxIterations reached — forcing final'
28
+ : 'LLM produced no tool calls — final answer',
29
+ });
30
+ return chosen;
31
+ };
32
+ //# sourceMappingURL=route.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.js","sourceRoot":"","sources":["../../../../../src/core/agent/stages/route.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,EAAE,SAAS,EAAE,MAAM,sCAAsC,CAAC;AAKjE,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,KAA6B,EAAe,EAAE;IAC9E,MAAM,SAAS,GAAG,KAAK,CAAC,kBAAiD,CAAC;IAC1E,MAAM,SAAS,GAAG,KAAK,CAAC,SAAmB,CAAC;IAC5C,MAAM,MAAM,GACV,SAAS,CAAC,MAAM,GAAG,CAAC,IAAI,SAAS,GAAG,KAAK,CAAC,aAAa,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC;IAEnF,SAAS,CAAC,KAAK,EAAE,oCAAoC,EAAE;QACrD,SAAS,EAAE,CAAC;QACZ,SAAS,EAAE,SAAS;QACpB,MAAM;QACN,SAAS,EACP,MAAM,KAAK,YAAY;YACrB,CAAC,CAAC,iBAAiB,SAAS,CAAC,MAAM,eAAe;YAClD,CAAC,CAAC,SAAS,IAAI,KAAK,CAAC,aAAa;gBAClC,CAAC,CAAC,uCAAuC;gBACzC,CAAC,CAAC,2CAA2C;KAClD,CAAC,CAAC;IAEH,OAAO,MAAM,CAAC;AAChB,CAAC,CAAC"}