agentfootprint 2.14.5 → 3.1.0
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.
- package/README.md +1 -1
- package/dist/cache/CacheDecisionSubflow.js +13 -16
- package/dist/cache/CacheDecisionSubflow.js.map +1 -1
- package/dist/cache/CacheGateDecider.js +18 -3
- package/dist/cache/CacheGateDecider.js.map +1 -1
- package/dist/cache/cacheRecorder.js +12 -3
- package/dist/cache/cacheRecorder.js.map +1 -1
- package/dist/conventions.js +155 -4
- package/dist/conventions.js.map +1 -1
- package/dist/core/Agent.js +115 -32
- package/dist/core/Agent.js.map +1 -1
- package/dist/core/LLMCall.js +213 -41
- package/dist/core/LLMCall.js.map +1 -1
- package/dist/core/RunnerBase.js +187 -0
- package/dist/core/RunnerBase.js.map +1 -1
- package/dist/core/agent/buildAgentChart.js +127 -48
- package/dist/core/agent/buildAgentChart.js.map +1 -1
- package/dist/core/agent/buildAgentMessageApiChart.js +201 -0
- package/dist/core/agent/buildAgentMessageApiChart.js.map +1 -0
- package/dist/core/agent/buildCacheSubflow.js +62 -0
- package/dist/core/agent/buildCacheSubflow.js.map +1 -0
- package/dist/core/agent/buildDynamicAgentChart.js +364 -0
- package/dist/core/agent/buildDynamicAgentChart.js.map +1 -0
- package/dist/core/agent/buildMessageApiChart.js +154 -0
- package/dist/core/agent/buildMessageApiChart.js.map +1 -0
- package/dist/core/agent/stages/callLLM.js +11 -0
- package/dist/core/agent/stages/callLLM.js.map +1 -1
- package/dist/core/agent/stages/reliabilityExecution.js +64 -9
- package/dist/core/agent/stages/reliabilityExecution.js.map +1 -1
- package/dist/core/humanizeLLMError.js +66 -0
- package/dist/core/humanizeLLMError.js.map +1 -0
- package/dist/core/runner.js +4 -3
- package/dist/core/runner.js.map +1 -1
- package/dist/core/slots/buildMessagesSlot.js +2 -2
- package/dist/core/slots/buildMessagesSlot.js.map +1 -1
- package/dist/core/slots/buildSystemPromptSlot.js +1 -1
- package/dist/core/slots/buildSystemPromptSlot.js.map +1 -1
- package/dist/core/slots/buildThinkingSubflow.js +1 -1
- package/dist/core/slots/buildThinkingSubflow.js.map +1 -1
- package/dist/core/slots/buildToolsSlot.js +3 -1
- package/dist/core/slots/buildToolsSlot.js.map +1 -1
- package/dist/core/translator.js +32 -0
- package/dist/core/translator.js.map +1 -0
- package/dist/core-flow/Conditional.js +72 -10
- package/dist/core-flow/Conditional.js.map +1 -1
- package/dist/core-flow/Loop.js +59 -16
- package/dist/core-flow/Loop.js.map +1 -1
- package/dist/core-flow/Parallel.js +239 -92
- package/dist/core-flow/Parallel.js.map +1 -1
- package/dist/core-flow/Sequence.js +50 -8
- package/dist/core-flow/Sequence.js.map +1 -1
- package/dist/esm/cache/CacheDecisionSubflow.js +11 -15
- package/dist/esm/cache/CacheDecisionSubflow.js.map +1 -1
- package/dist/esm/cache/CacheGateDecider.js +18 -3
- package/dist/esm/cache/CacheGateDecider.js.map +1 -1
- package/dist/esm/cache/cacheRecorder.js +12 -3
- package/dist/esm/cache/cacheRecorder.js.map +1 -1
- package/dist/esm/conventions.js +151 -3
- package/dist/esm/conventions.js.map +1 -1
- package/dist/esm/core/Agent.js +116 -33
- package/dist/esm/core/Agent.js.map +1 -1
- package/dist/esm/core/LLMCall.js +213 -41
- package/dist/esm/core/LLMCall.js.map +1 -1
- package/dist/esm/core/RunnerBase.js +187 -0
- package/dist/esm/core/RunnerBase.js.map +1 -1
- package/dist/esm/core/agent/buildAgentChart.js +128 -49
- package/dist/esm/core/agent/buildAgentChart.js.map +1 -1
- package/dist/esm/core/agent/buildAgentMessageApiChart.js +197 -0
- package/dist/esm/core/agent/buildAgentMessageApiChart.js.map +1 -0
- package/dist/esm/core/agent/buildCacheSubflow.js +58 -0
- package/dist/esm/core/agent/buildCacheSubflow.js.map +1 -0
- package/dist/esm/core/agent/buildDynamicAgentChart.js +360 -0
- package/dist/esm/core/agent/buildDynamicAgentChart.js.map +1 -0
- package/dist/esm/core/agent/buildMessageApiChart.js +150 -0
- package/dist/esm/core/agent/buildMessageApiChart.js.map +1 -0
- package/dist/esm/core/agent/stages/callLLM.js +11 -0
- package/dist/esm/core/agent/stages/callLLM.js.map +1 -1
- package/dist/esm/core/agent/stages/reliabilityExecution.js +64 -9
- package/dist/esm/core/agent/stages/reliabilityExecution.js.map +1 -1
- package/dist/esm/core/humanizeLLMError.js +61 -0
- package/dist/esm/core/humanizeLLMError.js.map +1 -0
- package/dist/esm/core/runner.js +4 -3
- package/dist/esm/core/runner.js.map +1 -1
- package/dist/esm/core/slots/buildMessagesSlot.js +2 -2
- package/dist/esm/core/slots/buildMessagesSlot.js.map +1 -1
- package/dist/esm/core/slots/buildSystemPromptSlot.js +1 -1
- package/dist/esm/core/slots/buildSystemPromptSlot.js.map +1 -1
- package/dist/esm/core/slots/buildThinkingSubflow.js +1 -1
- package/dist/esm/core/slots/buildThinkingSubflow.js.map +1 -1
- package/dist/esm/core/slots/buildToolsSlot.js +3 -1
- package/dist/esm/core/slots/buildToolsSlot.js.map +1 -1
- package/dist/esm/core/translator.js +31 -0
- package/dist/esm/core/translator.js.map +1 -0
- package/dist/esm/core-flow/Conditional.js +72 -10
- package/dist/esm/core-flow/Conditional.js.map +1 -1
- package/dist/esm/core-flow/Loop.js +59 -16
- package/dist/esm/core-flow/Loop.js.map +1 -1
- package/dist/esm/core-flow/Parallel.js +240 -93
- package/dist/esm/core-flow/Parallel.js.map +1 -1
- package/dist/esm/core-flow/Sequence.js +50 -8
- package/dist/esm/core-flow/Sequence.js.map +1 -1
- package/dist/esm/events/registry.js +10 -0
- package/dist/esm/events/registry.js.map +1 -1
- package/dist/esm/index.js +22 -1
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/lib/injection-engine/buildInjectionEngineSubflow.js +16 -9
- package/dist/esm/lib/injection-engine/buildInjectionEngineSubflow.js.map +1 -1
- package/dist/esm/memory/causal/snapshotPipeline.js +6 -2
- package/dist/esm/memory/causal/snapshotPipeline.js.map +1 -1
- package/dist/esm/memory/pipeline/auto.js +2 -2
- package/dist/esm/memory/pipeline/auto.js.map +1 -1
- package/dist/esm/memory/pipeline/default.js +4 -2
- package/dist/esm/memory/pipeline/default.js.map +1 -1
- package/dist/esm/memory/pipeline/ephemeral.js +3 -1
- package/dist/esm/memory/pipeline/ephemeral.js.map +1 -1
- package/dist/esm/memory/pipeline/fact.js +4 -2
- package/dist/esm/memory/pipeline/fact.js.map +1 -1
- package/dist/esm/memory/pipeline/narrative.js +4 -2
- package/dist/esm/memory/pipeline/narrative.js.map +1 -1
- package/dist/esm/memory/pipeline/semantic.js +2 -2
- package/dist/esm/memory/pipeline/semantic.js.map +1 -1
- package/dist/esm/observe.js +1 -1
- package/dist/esm/observe.js.map +1 -1
- package/dist/esm/patterns/MapReduce.js +5 -5
- package/dist/esm/patterns/MapReduce.js.map +1 -1
- package/dist/esm/patterns/Swarm.js +1 -1
- package/dist/esm/patterns/Swarm.js.map +1 -1
- package/dist/esm/recorders/core/ContextEvaluatedRecorder.js +31 -0
- package/dist/esm/recorders/core/ContextEvaluatedRecorder.js.map +1 -0
- package/dist/esm/recorders/core/ContextRecorder.js +12 -14
- package/dist/esm/recorders/core/ContextRecorder.js.map +1 -1
- package/dist/esm/recorders/core/ErrorBridge.js +59 -0
- package/dist/esm/recorders/core/ErrorBridge.js.map +1 -0
- package/dist/esm/recorders/core/ReliabilityRecorder.js +29 -0
- package/dist/esm/recorders/core/ReliabilityRecorder.js.map +1 -0
- package/dist/esm/recorders/observability/BoundaryRecorder.js +338 -36
- package/dist/esm/recorders/observability/BoundaryRecorder.js.map +1 -1
- package/dist/esm/recorders/observability/FlowchartRecorder.js +10 -0
- package/dist/esm/recorders/observability/FlowchartRecorder.js.map +1 -1
- package/dist/esm/recorders/observability/LiveStateRecorder.js +120 -21
- package/dist/esm/recorders/observability/LiveStateRecorder.js.map +1 -1
- package/dist/esm/recorders/observability/RunStepRecorder.js +652 -0
- package/dist/esm/recorders/observability/RunStepRecorder.js.map +1 -0
- package/dist/esm/recorders/observability/commentary/commentaryTemplates.js +1 -0
- package/dist/esm/recorders/observability/commentary/commentaryTemplates.js.map +1 -1
- package/dist/esm/recorders/observability/internal/ActorArrowClassifier.js +34 -0
- package/dist/esm/recorders/observability/internal/ActorArrowClassifier.js.map +1 -0
- package/dist/esm/recorders/observability/internal/CandidateAnswerBuffer.js +32 -0
- package/dist/esm/recorders/observability/internal/CandidateAnswerBuffer.js.map +1 -0
- package/dist/esm/recorders/observability/internal/ForkTracker.js +84 -0
- package/dist/esm/recorders/observability/internal/ForkTracker.js.map +1 -0
- package/dist/esm/recorders/observability/internal/RootInferrer.js +114 -0
- package/dist/esm/recorders/observability/internal/RootInferrer.js.map +1 -0
- package/dist/esm/recorders/observability/internal/SequenceSiblingTracker.js +31 -0
- package/dist/esm/recorders/observability/internal/SequenceSiblingTracker.js.map +1 -0
- package/dist/esm/recorders/observability/observeRunId.js +21 -0
- package/dist/esm/recorders/observability/observeRunId.js.map +1 -0
- package/dist/esm/reliability/buildReliabilityGateChart.js +11 -5
- package/dist/esm/reliability/buildReliabilityGateChart.js.map +1 -1
- package/dist/events/registry.js +10 -0
- package/dist/events/registry.js.map +1 -1
- package/dist/index.js +30 -3
- package/dist/index.js.map +1 -1
- package/dist/lib/injection-engine/buildInjectionEngineSubflow.js +16 -9
- package/dist/lib/injection-engine/buildInjectionEngineSubflow.js.map +1 -1
- package/dist/memory/causal/snapshotPipeline.js +6 -2
- package/dist/memory/causal/snapshotPipeline.js.map +1 -1
- package/dist/memory/pipeline/auto.js +2 -2
- package/dist/memory/pipeline/auto.js.map +1 -1
- package/dist/memory/pipeline/default.js +4 -2
- package/dist/memory/pipeline/default.js.map +1 -1
- package/dist/memory/pipeline/ephemeral.js +3 -1
- package/dist/memory/pipeline/ephemeral.js.map +1 -1
- package/dist/memory/pipeline/fact.js +4 -2
- package/dist/memory/pipeline/fact.js.map +1 -1
- package/dist/memory/pipeline/narrative.js +4 -2
- package/dist/memory/pipeline/narrative.js.map +1 -1
- package/dist/memory/pipeline/semantic.js +2 -2
- package/dist/memory/pipeline/semantic.js.map +1 -1
- package/dist/observe.js +1 -1
- package/dist/observe.js.map +1 -1
- package/dist/patterns/MapReduce.js +5 -5
- package/dist/patterns/MapReduce.js.map +1 -1
- package/dist/patterns/Swarm.js +1 -1
- package/dist/patterns/Swarm.js.map +1 -1
- package/dist/recorders/core/ContextEvaluatedRecorder.js +35 -0
- package/dist/recorders/core/ContextEvaluatedRecorder.js.map +1 -0
- package/dist/recorders/core/ContextRecorder.js +11 -13
- package/dist/recorders/core/ContextRecorder.js.map +1 -1
- package/dist/recorders/core/ErrorBridge.js +64 -0
- package/dist/recorders/core/ErrorBridge.js.map +1 -0
- package/dist/recorders/core/ReliabilityRecorder.js +33 -0
- package/dist/recorders/core/ReliabilityRecorder.js.map +1 -0
- package/dist/recorders/observability/BoundaryRecorder.js +337 -35
- package/dist/recorders/observability/BoundaryRecorder.js.map +1 -1
- package/dist/recorders/observability/FlowchartRecorder.js +10 -0
- package/dist/recorders/observability/FlowchartRecorder.js.map +1 -1
- package/dist/recorders/observability/LiveStateRecorder.js +119 -20
- package/dist/recorders/observability/LiveStateRecorder.js.map +1 -1
- package/dist/recorders/observability/RunStepRecorder.js +658 -0
- package/dist/recorders/observability/RunStepRecorder.js.map +1 -0
- package/dist/recorders/observability/commentary/commentaryTemplates.js +1 -0
- package/dist/recorders/observability/commentary/commentaryTemplates.js.map +1 -1
- package/dist/recorders/observability/internal/ActorArrowClassifier.js +38 -0
- package/dist/recorders/observability/internal/ActorArrowClassifier.js.map +1 -0
- package/dist/recorders/observability/internal/CandidateAnswerBuffer.js +36 -0
- package/dist/recorders/observability/internal/CandidateAnswerBuffer.js.map +1 -0
- package/dist/recorders/observability/internal/ForkTracker.js +88 -0
- package/dist/recorders/observability/internal/ForkTracker.js.map +1 -0
- package/dist/recorders/observability/internal/RootInferrer.js +118 -0
- package/dist/recorders/observability/internal/RootInferrer.js.map +1 -0
- package/dist/recorders/observability/internal/SequenceSiblingTracker.js +35 -0
- package/dist/recorders/observability/internal/SequenceSiblingTracker.js.map +1 -0
- package/dist/recorders/observability/observeRunId.js +25 -0
- package/dist/recorders/observability/observeRunId.js.map +1 -0
- package/dist/reliability/buildReliabilityGateChart.js +11 -5
- package/dist/reliability/buildReliabilityGateChart.js.map +1 -1
- package/dist/types/cache/CacheDecisionSubflow.d.ts +7 -10
- package/dist/types/cache/CacheDecisionSubflow.d.ts.map +1 -1
- package/dist/types/cache/CacheGateDecider.d.ts +16 -2
- package/dist/types/cache/CacheGateDecider.d.ts.map +1 -1
- package/dist/types/cache/cacheRecorder.d.ts.map +1 -1
- package/dist/types/conventions.d.ts +101 -1
- package/dist/types/conventions.d.ts.map +1 -1
- package/dist/types/core/Agent.d.ts +28 -18
- package/dist/types/core/Agent.d.ts.map +1 -1
- package/dist/types/core/LLMCall.d.ts +73 -11
- package/dist/types/core/LLMCall.d.ts.map +1 -1
- package/dist/types/core/RunnerBase.d.ts +136 -4
- package/dist/types/core/RunnerBase.d.ts.map +1 -1
- package/dist/types/core/agent/buildAgentChart.d.ts +38 -19
- package/dist/types/core/agent/buildAgentChart.d.ts.map +1 -1
- package/dist/types/core/agent/buildAgentMessageApiChart.d.ts +41 -0
- package/dist/types/core/agent/buildAgentMessageApiChart.d.ts.map +1 -0
- package/dist/types/core/agent/buildCacheSubflow.d.ts +36 -0
- package/dist/types/core/agent/buildCacheSubflow.d.ts.map +1 -0
- package/dist/types/core/agent/buildDynamicAgentChart.d.ts +57 -0
- package/dist/types/core/agent/buildDynamicAgentChart.d.ts.map +1 -0
- package/dist/types/core/agent/buildMessageApiChart.d.ts +48 -0
- package/dist/types/core/agent/buildMessageApiChart.d.ts.map +1 -0
- package/dist/types/core/agent/stages/callLLM.d.ts.map +1 -1
- package/dist/types/core/agent/stages/reliabilityExecution.d.ts.map +1 -1
- package/dist/types/core/agent/types.d.ts +96 -0
- package/dist/types/core/agent/types.d.ts.map +1 -1
- package/dist/types/core/humanizeLLMError.d.ts +24 -0
- package/dist/types/core/humanizeLLMError.d.ts.map +1 -0
- package/dist/types/core/runner.d.ts +51 -5
- package/dist/types/core/runner.d.ts.map +1 -1
- package/dist/types/core/slots/buildMessagesSlot.d.ts.map +1 -1
- package/dist/types/core/slots/buildSystemPromptSlot.d.ts.map +1 -1
- package/dist/types/core/slots/buildThinkingSubflow.d.ts.map +1 -1
- package/dist/types/core/slots/buildToolsSlot.d.ts.map +1 -1
- package/dist/types/core/translator.d.ts +95 -0
- package/dist/types/core/translator.d.ts.map +1 -0
- package/dist/types/core-flow/Conditional.d.ts +48 -4
- package/dist/types/core-flow/Conditional.d.ts.map +1 -1
- package/dist/types/core-flow/Loop.d.ts +42 -3
- package/dist/types/core-flow/Loop.d.ts.map +1 -1
- package/dist/types/core-flow/Parallel.d.ts +99 -4
- package/dist/types/core-flow/Parallel.d.ts.map +1 -1
- package/dist/types/core-flow/Sequence.d.ts +49 -3
- package/dist/types/core-flow/Sequence.d.ts.map +1 -1
- package/dist/types/events/payloads.d.ts +99 -1
- package/dist/types/events/payloads.d.ts.map +1 -1
- package/dist/types/events/registry.d.ts +11 -1
- package/dist/types/events/registry.d.ts.map +1 -1
- package/dist/types/index.d.ts +8 -3
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/lib/injection-engine/buildInjectionEngineSubflow.d.ts.map +1 -1
- package/dist/types/memory/causal/snapshotPipeline.d.ts.map +1 -1
- package/dist/types/memory/pipeline/auto.d.ts.map +1 -1
- package/dist/types/memory/pipeline/default.d.ts.map +1 -1
- package/dist/types/memory/pipeline/ephemeral.d.ts.map +1 -1
- package/dist/types/memory/pipeline/fact.d.ts.map +1 -1
- package/dist/types/memory/pipeline/narrative.d.ts.map +1 -1
- package/dist/types/memory/pipeline/semantic.d.ts.map +1 -1
- package/dist/types/observe.d.ts +2 -2
- package/dist/types/observe.d.ts.map +1 -1
- package/dist/types/recorders/core/ContextEvaluatedRecorder.d.ts +24 -0
- package/dist/types/recorders/core/ContextEvaluatedRecorder.d.ts.map +1 -0
- package/dist/types/recorders/core/ContextRecorder.d.ts +0 -2
- package/dist/types/recorders/core/ContextRecorder.d.ts.map +1 -1
- package/dist/types/recorders/core/ErrorBridge.d.ts +39 -0
- package/dist/types/recorders/core/ErrorBridge.d.ts.map +1 -0
- package/dist/types/recorders/core/ReliabilityRecorder.d.ts +25 -0
- package/dist/types/recorders/core/ReliabilityRecorder.d.ts.map +1 -0
- package/dist/types/recorders/observability/BoundaryRecorder.d.ts +167 -6
- package/dist/types/recorders/observability/BoundaryRecorder.d.ts.map +1 -1
- package/dist/types/recorders/observability/FlowchartRecorder.d.ts.map +1 -1
- package/dist/types/recorders/observability/LiveStateRecorder.d.ts +42 -6
- package/dist/types/recorders/observability/LiveStateRecorder.d.ts.map +1 -1
- package/dist/types/recorders/observability/RunStepRecorder.d.ts +232 -0
- package/dist/types/recorders/observability/RunStepRecorder.d.ts.map +1 -0
- package/dist/types/recorders/observability/commentary/commentaryTemplates.d.ts.map +1 -1
- package/dist/types/recorders/observability/internal/ActorArrowClassifier.d.ts +26 -0
- package/dist/types/recorders/observability/internal/ActorArrowClassifier.d.ts.map +1 -0
- package/dist/types/recorders/observability/internal/CandidateAnswerBuffer.d.ts +29 -0
- package/dist/types/recorders/observability/internal/CandidateAnswerBuffer.d.ts.map +1 -0
- package/dist/types/recorders/observability/internal/ForkTracker.d.ts +61 -0
- package/dist/types/recorders/observability/internal/ForkTracker.d.ts.map +1 -0
- package/dist/types/recorders/observability/internal/RootInferrer.d.ts +52 -0
- package/dist/types/recorders/observability/internal/RootInferrer.d.ts.map +1 -0
- package/dist/types/recorders/observability/internal/SequenceSiblingTracker.d.ts +25 -0
- package/dist/types/recorders/observability/internal/SequenceSiblingTracker.d.ts.map +1 -0
- package/dist/types/recorders/observability/observeRunId.d.ts +37 -0
- package/dist/types/recorders/observability/observeRunId.d.ts.map +1 -0
- package/dist/types/reliability/buildReliabilityGateChart.d.ts.map +1 -1
- package/package.json +6 -5
- package/dist/core/agent/stages/iterationStart.js +0 -24
- package/dist/core/agent/stages/iterationStart.js.map +0 -1
- package/dist/esm/core/agent/stages/iterationStart.js +0 -20
- package/dist/esm/core/agent/stages/iterationStart.js.map +0 -1
- package/dist/types/core/agent/stages/iterationStart.d.ts +0 -16
- package/dist/types/core/agent/stages/iterationStart.d.ts.map +0 -1
|
@@ -75,8 +75,9 @@
|
|
|
75
75
|
* }
|
|
76
76
|
* ```
|
|
77
77
|
*/
|
|
78
|
-
import { ROOT_RUNTIME_STAGE_ID, ROOT_SUBFLOW_ID,
|
|
78
|
+
import { ROOT_RUNTIME_STAGE_ID, ROOT_SUBFLOW_ID, SequenceStore, CommitRangeIndex, } from 'footprintjs/trace';
|
|
79
79
|
import { SUBFLOW_IDS, STAGE_IDS, slotFromSubflowId } from '../../conventions.js';
|
|
80
|
+
import { createRunIdObserver } from './observeRunId.js';
|
|
80
81
|
/** Closed set of routing/wrapper subflow IDs that are pure plumbing.
|
|
81
82
|
* Slot subflows (`sf-system-prompt` / `sf-messages` / `sf-tools`) are
|
|
82
83
|
* NOT in this set — they're real context-engineering moments.
|
|
@@ -90,15 +91,21 @@ import { SUBFLOW_IDS, STAGE_IDS, slotFromSubflowId } from '../../conventions.js'
|
|
|
90
91
|
const AGENT_INTERNAL_LOCAL_IDS = new Set([
|
|
91
92
|
// Subflow ids (`sf-*`)
|
|
92
93
|
SUBFLOW_IDS.INJECTION_ENGINE, // collects activeInjections; pure plumbing
|
|
94
|
+
SUBFLOW_IDS.LLM_CALL, // LLMCall's inner invocation wrapper — the meaningful step is the call-llm stage INSIDE; the wrapper itself is a chart-shape container
|
|
93
95
|
SUBFLOW_IDS.ROUTE,
|
|
94
96
|
SUBFLOW_IDS.TOOL_CALLS,
|
|
95
97
|
SUBFLOW_IDS.FINAL,
|
|
96
98
|
SUBFLOW_IDS.MERGE,
|
|
99
|
+
SUBFLOW_IDS.CACHE, // v2.14 — per-turn cache decision wrapper; pure plumbing
|
|
97
100
|
SUBFLOW_IDS.CACHE_DECISION, // v2.6 — emits cacheMarkers; not a user step
|
|
98
101
|
SUBFLOW_IDS.THINKING, // v2.14 — normalize result lands on parent LLM step
|
|
99
102
|
// Decider stage ids (the same set is used to filter `decision.branch`
|
|
100
103
|
// events whose deciding stage is plumbing rather than user-facing).
|
|
101
104
|
STAGE_IDS.CACHE_GATE, // v2.6 — apply-markers / no-markers routing; plumbing
|
|
105
|
+
// LLMCall outer wrapper stage + post-invocation marker — pure chart
|
|
106
|
+
// shape, not user-meaningful steps.
|
|
107
|
+
STAGE_IDS.CLIENT,
|
|
108
|
+
STAGE_IDS.EXTRACT_FINAL,
|
|
102
109
|
]);
|
|
103
110
|
// Constructed as a set on a separate line so we can extend with the
|
|
104
111
|
// thinking-handler inner-subflow ids below without the literal set
|
|
@@ -124,6 +131,53 @@ function isAgentInternalId(localId) {
|
|
|
124
131
|
}
|
|
125
132
|
return false;
|
|
126
133
|
}
|
|
134
|
+
function toBoundaryLabel(e) {
|
|
135
|
+
if (e.type === 'subflow.entry') {
|
|
136
|
+
return {
|
|
137
|
+
type: 'subflow.entry',
|
|
138
|
+
runtimeStageId: e.runtimeStageId,
|
|
139
|
+
subflowPath: e.subflowPath,
|
|
140
|
+
depth: e.depth,
|
|
141
|
+
ts: e.ts,
|
|
142
|
+
subflowId: e.subflowId,
|
|
143
|
+
localSubflowId: e.localSubflowId,
|
|
144
|
+
subflowName: e.subflowName,
|
|
145
|
+
...(e.description !== undefined ? { description: e.description } : {}),
|
|
146
|
+
...(e.primitiveKind !== undefined ? { primitiveKind: e.primitiveKind } : {}),
|
|
147
|
+
...(e.slotKind !== undefined ? { slotKind: e.slotKind } : {}),
|
|
148
|
+
isAgentInternal: e.isAgentInternal,
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
return {
|
|
152
|
+
type: 'run.entry',
|
|
153
|
+
runtimeStageId: e.runtimeStageId,
|
|
154
|
+
subflowPath: e.subflowPath,
|
|
155
|
+
depth: e.depth,
|
|
156
|
+
ts: e.ts,
|
|
157
|
+
};
|
|
158
|
+
}
|
|
159
|
+
/** Build a BoundaryRangeLabel for the open side of a composition pair. */
|
|
160
|
+
function toCompositionBoundaryLabel(e) {
|
|
161
|
+
return {
|
|
162
|
+
type: 'composition.start',
|
|
163
|
+
runtimeStageId: e.runtimeStageId,
|
|
164
|
+
subflowPath: e.subflowPath,
|
|
165
|
+
depth: e.depth,
|
|
166
|
+
ts: e.ts,
|
|
167
|
+
compositionKind: e.kind,
|
|
168
|
+
compositionName: e.name,
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
/** Clamp `getCommitCount()` returns to a safe non-negative integer.
|
|
172
|
+
* Defensive against malformed injections returning NaN/Infinity/negatives
|
|
173
|
+
* (security panel review YELLOW #2). */
|
|
174
|
+
function sanitizeCommitCount(n) {
|
|
175
|
+
if (!Number.isFinite(n))
|
|
176
|
+
return 0;
|
|
177
|
+
if (n < 0)
|
|
178
|
+
return 0;
|
|
179
|
+
return n;
|
|
180
|
+
}
|
|
127
181
|
let _counter = 0;
|
|
128
182
|
/** Factory — matches the `inOutRecorder()` / `topologyRecorder()` style. */
|
|
129
183
|
export function boundaryRecorder(options = {}) {
|
|
@@ -134,12 +188,35 @@ export function boundaryRecorder(options = {}) {
|
|
|
134
188
|
* attach to the executor's FlowRecorder channel; exposes `subscribe()`
|
|
135
189
|
* to wire to the agentfootprint typed-event dispatcher.
|
|
136
190
|
*
|
|
137
|
-
*
|
|
138
|
-
*
|
|
139
|
-
*
|
|
191
|
+
* v5: composes a `SequenceStore<DomainEvent>` (storage) instead of
|
|
192
|
+
* extending the deprecated `SequenceRecorder<T>` base. Time-travel
|
|
193
|
+
* utilities (`getEntryRanges`, `accumulate`) are accessed through the
|
|
194
|
+
* store via the public read API on this class.
|
|
140
195
|
*/
|
|
141
|
-
export class BoundaryRecorder
|
|
196
|
+
export class BoundaryRecorder {
|
|
142
197
|
id;
|
|
198
|
+
/** Composition: storage shelf. */
|
|
199
|
+
store = new SequenceStore();
|
|
200
|
+
/**
|
|
201
|
+
* Phase 5 Layer 2 — interval index over commit indices, populated
|
|
202
|
+
* live as boundary entry/exit pairs fire. Consumers (Lens) read
|
|
203
|
+
* `enclosing(commitIdx)` for breadcrumbs and `overlapping(slice)`
|
|
204
|
+
* for time-range queries. Empty when `getCommitCount` is not
|
|
205
|
+
* injected. See `docs/design/boundary-commit-ranges.md`.
|
|
206
|
+
*/
|
|
207
|
+
boundaryIndex = new CommitRangeIndex();
|
|
208
|
+
/** Open-range tokens keyed by `runtimeStageId` so the matching exit
|
|
209
|
+
* can close the correct range. Pure side-table; cleared on runId
|
|
210
|
+
* reset. Not exposed externally. */
|
|
211
|
+
openTokens = new Map();
|
|
212
|
+
/** Live commit-count accessor injected by the runner. Sanitized
|
|
213
|
+
* (NaN/Infinity/negative → 0) before use. */
|
|
214
|
+
getCommitCount;
|
|
215
|
+
/** True when `getCommitCount` was explicitly injected. In LEGACY
|
|
216
|
+
* MODE (false), `boundaryIndex` is intentionally NOT populated —
|
|
217
|
+
* zero-width [0,0] ranges would mislead consumers querying the
|
|
218
|
+
* index. Multi-panel review flagged this footgun. */
|
|
219
|
+
hasCommitTracking;
|
|
143
220
|
/**
|
|
144
221
|
* Tracks whether the most recent `llm.end` had toolCalls. Used to
|
|
145
222
|
* classify the NEXT `llm.start` as `'tool→llm'` (vs `'user→llm'` if
|
|
@@ -147,50 +224,184 @@ export class BoundaryRecorder extends SequenceRecorder {
|
|
|
147
224
|
* `llm.start` event after the classification is applied.
|
|
148
225
|
*/
|
|
149
226
|
prevLLMEndHadTools = false;
|
|
227
|
+
/**
|
|
228
|
+
* Run-boundary observer — fires resetForNewRun() when
|
|
229
|
+
* traversalContext.runId changes between events AND no boundary is
|
|
230
|
+
* currently open. The "no open boundary" gate distinguishes:
|
|
231
|
+
*
|
|
232
|
+
* - **Legitimate new run** — consumer reuses one recorder across
|
|
233
|
+
* sequential `executor.run()` calls. All prior boundaries closed
|
|
234
|
+
* before the second run began; openTokens is empty when the new
|
|
235
|
+
* runId arrives → safe to wipe state so the second run doesn't
|
|
236
|
+
* alias with the first.
|
|
237
|
+
* - **Composition sub-run** — primitives like `LLMCall`, `Sequence`,
|
|
238
|
+
* and `Parallel` internally spawn their own `FlowChartExecutor`
|
|
239
|
+
* instances. Each sub-executor mints a NEW runId. When that
|
|
240
|
+
* sub-executor fires events on the SHARED recorder, the recorder
|
|
241
|
+
* is still inside the parent run — `openTokens` is non-empty.
|
|
242
|
+
* Resetting here would wipe the parent's boundary index mid-run
|
|
243
|
+
* (the bug Layer 4 surfaced in agentfootprint-lens fanout).
|
|
244
|
+
*
|
|
245
|
+
* The `openTokens.size === 0` check is the cleanest semantic signal:
|
|
246
|
+
* if nothing is in-flight, a runId change means "the consumer started
|
|
247
|
+
* fresh"; if something is open, the new runId is from a sub-executor
|
|
248
|
+
* nested inside the still-ongoing parent.
|
|
249
|
+
*/
|
|
250
|
+
runIdGuard = createRunIdObserver(() => {
|
|
251
|
+
if (this.openTokens.size > 0) {
|
|
252
|
+
// Inside an active run — new runId is from a composition sub-
|
|
253
|
+
// executor (LLMCall / Sequence / Parallel). Do NOT reset.
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
this.store.clear();
|
|
257
|
+
this.boundaryIndex.clear();
|
|
258
|
+
this.openTokens.clear();
|
|
259
|
+
this.prevLLMEndHadTools = false;
|
|
260
|
+
});
|
|
150
261
|
constructor(options = {}) {
|
|
151
|
-
super();
|
|
152
262
|
this.id = options.id ?? `boundary-${++_counter}`;
|
|
263
|
+
this.hasCommitTracking = options.getCommitCount !== undefined;
|
|
264
|
+
const raw = options.getCommitCount;
|
|
265
|
+
this.getCommitCount = raw === undefined ? () => 0 : () => sanitizeCommitCount(raw());
|
|
153
266
|
}
|
|
267
|
+
/**
|
|
268
|
+
* Reset all transient state.
|
|
269
|
+
*
|
|
270
|
+
* **Composition-safe gate (Phase 5 Layer 4):** if `openTokens.size > 0`
|
|
271
|
+
* the call is a no-op. Rationale: `FlowChartExecutor.run()` calls
|
|
272
|
+
* `r.clear?.()` on every attached recorder during its pre-run loop.
|
|
273
|
+
* When agentfootprint composition primitives (LLMCall, Sequence,
|
|
274
|
+
* Parallel, etc.) propagate the parent's recorders to nested
|
|
275
|
+
* sub-executors, EACH sub-executor's pre-run clear loop calls
|
|
276
|
+
* `clear()` on the SHARED parent recorder mid-run — wiping live
|
|
277
|
+
* parent state. The `openTokens.size > 0` check distinguishes:
|
|
278
|
+
*
|
|
279
|
+
* - **Legitimate reset** — consumer or executor calls `clear()`
|
|
280
|
+
* when no boundary is in-flight (`openTokens` empty). Safe to
|
|
281
|
+
* wipe; the recorder is idle.
|
|
282
|
+
* - **Composition wipe** — sub-executor's pre-run clear fires
|
|
283
|
+
* while the parent has open boundaries (`openTokens` non-empty).
|
|
284
|
+
* Skip the wipe; the parent's state must be preserved.
|
|
285
|
+
*
|
|
286
|
+
* If a consumer needs to forcibly wipe state even with open tokens
|
|
287
|
+
* (e.g., manual recovery after a crashed run), pair `clear()` with
|
|
288
|
+
* an explicit `forceClear()` (TODO — add when the use case shows up;
|
|
289
|
+
* today the recorder lifecycle pattern is "one recorder per logical
|
|
290
|
+
* run" so leaked tokens shouldn't occur).
|
|
291
|
+
*/
|
|
154
292
|
clear() {
|
|
155
|
-
|
|
293
|
+
if (this.openTokens.size > 0) {
|
|
294
|
+
// Mid-run wipe attempt — almost certainly a sub-executor's
|
|
295
|
+
// pre-run clear via composition propagation. Skip.
|
|
296
|
+
return;
|
|
297
|
+
}
|
|
298
|
+
this.store.clear();
|
|
299
|
+
this.boundaryIndex.clear();
|
|
300
|
+
this.openTokens.clear();
|
|
156
301
|
this.prevLLMEndHadTools = false;
|
|
302
|
+
this.runIdGuard.reset();
|
|
303
|
+
}
|
|
304
|
+
observeRunId(runId) {
|
|
305
|
+
this.runIdGuard.observe(runId);
|
|
157
306
|
}
|
|
158
307
|
// ── FlowRecorder hooks (footprintjs side) ───────────────────────────
|
|
159
308
|
onRunStart(event) {
|
|
160
|
-
this.
|
|
309
|
+
this.observeRunId(event.traversalContext?.runId);
|
|
310
|
+
const commitIdxBefore = this.getCommitCount();
|
|
311
|
+
const e = buildRunEvent('run.entry', event.payload, commitIdxBefore);
|
|
312
|
+
// Open range BEFORE the store push so a failed push doesn't leak
|
|
313
|
+
// an unclosed range (DS+logic panel review). The label is the
|
|
314
|
+
// stripped projection (no payload) — security-panel YELLOW #1.
|
|
315
|
+
if (this.hasCommitTracking) {
|
|
316
|
+
const token = this.boundaryIndex.open(toBoundaryLabel(e), commitIdxBefore);
|
|
317
|
+
this.openTokens.set(e.runtimeStageId, token);
|
|
318
|
+
}
|
|
319
|
+
this.store.push(e);
|
|
161
320
|
}
|
|
162
321
|
onRunEnd(event) {
|
|
163
|
-
this.
|
|
322
|
+
this.observeRunId(event.traversalContext?.runId);
|
|
323
|
+
const commitIdxBefore = this.getCommitCount();
|
|
324
|
+
const e = buildRunEvent('run.exit', event.payload, commitIdxBefore);
|
|
325
|
+
// Close the range BEFORE store.push so a failed push doesn't
|
|
326
|
+
// leak a permanently-open range. The range is the canonical
|
|
327
|
+
// truth; the store entry is downstream telemetry.
|
|
328
|
+
if (this.hasCommitTracking) {
|
|
329
|
+
const token = this.openTokens.get(e.runtimeStageId);
|
|
330
|
+
if (token) {
|
|
331
|
+
this.boundaryIndex.close(token, commitIdxBefore);
|
|
332
|
+
this.openTokens.delete(e.runtimeStageId);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
this.store.push(e);
|
|
336
|
+
}
|
|
337
|
+
onRunFailed(event) {
|
|
338
|
+
this.observeRunId(event.traversalContext?.runId);
|
|
339
|
+
const commitIdxBefore = this.getCommitCount();
|
|
340
|
+
// A failed run still TERMINATES — close the root range (mirror
|
|
341
|
+
// onRunEnd) so consumers get a terminal "Run · failed" boundary
|
|
342
|
+
// position instead of a slider that stops mid-call. The error rides
|
|
343
|
+
// as the exit payload so the WHY is reachable at that boundary.
|
|
344
|
+
const e = buildRunEvent('run.exit', { error: event.structuredError.message }, commitIdxBefore);
|
|
345
|
+
if (this.hasCommitTracking) {
|
|
346
|
+
const token = this.openTokens.get(e.runtimeStageId);
|
|
347
|
+
if (token) {
|
|
348
|
+
this.boundaryIndex.close(token, commitIdxBefore);
|
|
349
|
+
this.openTokens.delete(e.runtimeStageId);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
this.store.push(e);
|
|
164
353
|
}
|
|
165
354
|
onSubflowEntry(event) {
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
355
|
+
this.observeRunId(event.traversalContext?.runId);
|
|
356
|
+
const commitIdxBefore = this.getCommitCount();
|
|
357
|
+
const e = buildSubflowEvent(event, 'subflow.entry', commitIdxBefore);
|
|
358
|
+
if (!e)
|
|
359
|
+
return;
|
|
360
|
+
if (this.hasCommitTracking) {
|
|
361
|
+
const token = this.boundaryIndex.open(toBoundaryLabel(e), commitIdxBefore);
|
|
362
|
+
this.openTokens.set(e.runtimeStageId, token);
|
|
363
|
+
}
|
|
364
|
+
this.store.push(e);
|
|
169
365
|
}
|
|
170
366
|
onSubflowExit(event) {
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
367
|
+
this.observeRunId(event.traversalContext?.runId);
|
|
368
|
+
const commitIdxBefore = this.getCommitCount();
|
|
369
|
+
const e = buildSubflowEvent(event, 'subflow.exit', commitIdxBefore);
|
|
370
|
+
if (!e)
|
|
371
|
+
return;
|
|
372
|
+
if (this.hasCommitTracking) {
|
|
373
|
+
const token = this.openTokens.get(e.runtimeStageId);
|
|
374
|
+
if (token) {
|
|
375
|
+
this.boundaryIndex.close(token, commitIdxBefore);
|
|
376
|
+
this.openTokens.delete(e.runtimeStageId);
|
|
377
|
+
}
|
|
378
|
+
}
|
|
379
|
+
this.store.push(e);
|
|
174
380
|
}
|
|
175
381
|
onFork(event) {
|
|
382
|
+
this.observeRunId(event.traversalContext?.runId);
|
|
176
383
|
const ts = Date.now();
|
|
177
384
|
const ctx = event.traversalContext;
|
|
178
385
|
const runtimeStageId = ctx?.runtimeStageId ?? '';
|
|
179
386
|
const segments = ctx?.subflowPath ? ctx.subflowPath.split('/').filter(Boolean) : [];
|
|
180
387
|
const subflowPath = [ROOT_SUBFLOW_ID, ...segments];
|
|
388
|
+
const commitIdxBefore = this.getCommitCount();
|
|
181
389
|
for (const childName of event.children) {
|
|
182
|
-
this.
|
|
390
|
+
this.store.push({
|
|
183
391
|
type: 'fork.branch',
|
|
184
392
|
runtimeStageId,
|
|
185
393
|
subflowPath,
|
|
186
394
|
depth: subflowPath.length - 1,
|
|
187
395
|
ts,
|
|
396
|
+
commitIdxBefore,
|
|
397
|
+
commitIdxAfter: commitIdxBefore,
|
|
188
398
|
parentSubflowId: event.parent,
|
|
189
399
|
childName,
|
|
190
400
|
});
|
|
191
401
|
}
|
|
192
402
|
}
|
|
193
403
|
onDecision(event) {
|
|
404
|
+
this.observeRunId(event.traversalContext?.runId);
|
|
194
405
|
const ctx = event.traversalContext;
|
|
195
406
|
// Agent-internal decisions (Route picking tool-calls / final) are
|
|
196
407
|
// identified by the deciding stage's stableId matching one of the
|
|
@@ -204,12 +415,15 @@ export class BoundaryRecorder extends SequenceRecorder {
|
|
|
204
415
|
? stageId.slice(stageId.lastIndexOf('/') + 1)
|
|
205
416
|
: stageId;
|
|
206
417
|
const isAgentInternal = isAgentInternalId(localStageId);
|
|
207
|
-
this.
|
|
418
|
+
const commitIdxBefore = this.getCommitCount();
|
|
419
|
+
this.store.push({
|
|
208
420
|
type: 'decision.branch',
|
|
209
421
|
runtimeStageId: ctx?.runtimeStageId ?? '',
|
|
210
422
|
subflowPath: pathFromCtx(ctx?.subflowPath),
|
|
211
423
|
depth: ctxDepth(ctx?.subflowPath),
|
|
212
424
|
ts: Date.now(),
|
|
425
|
+
commitIdxBefore,
|
|
426
|
+
commitIdxAfter: commitIdxBefore,
|
|
213
427
|
decider: event.decider,
|
|
214
428
|
chosen: event.chosen,
|
|
215
429
|
...(event.rationale ? { rationale: event.rationale } : {}),
|
|
@@ -217,13 +431,17 @@ export class BoundaryRecorder extends SequenceRecorder {
|
|
|
217
431
|
});
|
|
218
432
|
}
|
|
219
433
|
onLoop(event) {
|
|
434
|
+
this.observeRunId(event.traversalContext?.runId);
|
|
220
435
|
const ctx = event.traversalContext;
|
|
221
|
-
this.
|
|
436
|
+
const commitIdxBefore = this.getCommitCount();
|
|
437
|
+
this.store.push({
|
|
222
438
|
type: 'loop.iteration',
|
|
223
439
|
runtimeStageId: ctx?.runtimeStageId ?? '',
|
|
224
440
|
subflowPath: pathFromCtx(ctx?.subflowPath),
|
|
225
441
|
depth: ctxDepth(ctx?.subflowPath),
|
|
226
442
|
ts: Date.now(),
|
|
443
|
+
commitIdxBefore,
|
|
444
|
+
commitIdxAfter: commitIdxBefore,
|
|
227
445
|
target: event.target,
|
|
228
446
|
iteration: event.iteration,
|
|
229
447
|
});
|
|
@@ -241,11 +459,22 @@ export class BoundaryRecorder extends SequenceRecorder {
|
|
|
241
459
|
return dispatcher.on('*', (event) => this.ingestTypedEvent(event));
|
|
242
460
|
}
|
|
243
461
|
ingestTypedEvent(event) {
|
|
462
|
+
// NOTE: deliberately does NOT call observeRunId(event.meta.runId).
|
|
463
|
+
// The agentfootprint dispatcher's runId is generated by a DIFFERENT
|
|
464
|
+
// generator than footprintjs's traversalContext.runId. Mixing them
|
|
465
|
+
// would toggle lastRunId on every event and trigger a false reset.
|
|
466
|
+
// Run-boundary detection happens reliably via the FlowRecorder hooks
|
|
467
|
+
// (onRunStart fires FIRST in any new run, before any typed event).
|
|
244
468
|
const meta = event.meta;
|
|
245
469
|
const runtimeStageId = meta.runtimeStageId ?? '';
|
|
246
470
|
const subflowPath = [ROOT_SUBFLOW_ID, ...(meta.subflowPath ?? [])];
|
|
247
471
|
const depth = subflowPath.length - 1;
|
|
248
472
|
const ts = meta.wallClockMs;
|
|
473
|
+
// Phase 5 Layer 2: stamp commit index on every typed event for
|
|
474
|
+
// consumers that want to join domain events with the commit log
|
|
475
|
+
// (e.g., "which LLM call happened during this commit slice?").
|
|
476
|
+
// Typed events don't write to scope themselves, so before === after.
|
|
477
|
+
const commitIdxBefore = this.getCommitCount();
|
|
249
478
|
switch (event.type) {
|
|
250
479
|
case 'agentfootprint.stream.llm_start': {
|
|
251
480
|
const p = event.payload;
|
|
@@ -257,12 +486,14 @@ export class BoundaryRecorder extends SequenceRecorder {
|
|
|
257
486
|
? 'tool→llm'
|
|
258
487
|
: 'user→llm';
|
|
259
488
|
this.prevLLMEndHadTools = false;
|
|
260
|
-
this.
|
|
489
|
+
this.store.push({
|
|
261
490
|
type: 'llm.start',
|
|
262
491
|
runtimeStageId,
|
|
263
492
|
subflowPath,
|
|
264
493
|
depth,
|
|
265
494
|
ts,
|
|
495
|
+
commitIdxBefore,
|
|
496
|
+
commitIdxAfter: commitIdxBefore,
|
|
266
497
|
model: p.model,
|
|
267
498
|
provider: p.provider,
|
|
268
499
|
...(p.systemPromptChars !== undefined ? { systemPromptChars: p.systemPromptChars } : {}),
|
|
@@ -279,12 +510,14 @@ export class BoundaryRecorder extends SequenceRecorder {
|
|
|
279
510
|
// terminal call (toolCallCount === 0) leaves the flag false so
|
|
280
511
|
// a hypothetical follow-up call would correctly be 'user→llm'.
|
|
281
512
|
this.prevLLMEndHadTools = p.toolCallCount > 0;
|
|
282
|
-
this.
|
|
513
|
+
this.store.push({
|
|
283
514
|
type: 'llm.end',
|
|
284
515
|
runtimeStageId,
|
|
285
516
|
subflowPath,
|
|
286
517
|
depth,
|
|
287
518
|
ts,
|
|
519
|
+
commitIdxBefore,
|
|
520
|
+
commitIdxAfter: commitIdxBefore,
|
|
288
521
|
content: p.content,
|
|
289
522
|
toolCallCount: p.toolCallCount,
|
|
290
523
|
usage: { input: p.usage.input, output: p.usage.output },
|
|
@@ -295,12 +528,14 @@ export class BoundaryRecorder extends SequenceRecorder {
|
|
|
295
528
|
}
|
|
296
529
|
case 'agentfootprint.stream.tool_start': {
|
|
297
530
|
const p = event.payload;
|
|
298
|
-
this.
|
|
531
|
+
this.store.push({
|
|
299
532
|
type: 'tool.start',
|
|
300
533
|
runtimeStageId,
|
|
301
534
|
subflowPath,
|
|
302
535
|
depth,
|
|
303
536
|
ts,
|
|
537
|
+
commitIdxBefore,
|
|
538
|
+
commitIdxAfter: commitIdxBefore,
|
|
304
539
|
toolName: p.toolName,
|
|
305
540
|
toolCallId: p.toolCallId,
|
|
306
541
|
...(p.args !== undefined ? { args: p.args } : {}),
|
|
@@ -309,12 +544,14 @@ export class BoundaryRecorder extends SequenceRecorder {
|
|
|
309
544
|
}
|
|
310
545
|
case 'agentfootprint.stream.tool_end': {
|
|
311
546
|
const p = event.payload;
|
|
312
|
-
this.
|
|
547
|
+
this.store.push({
|
|
313
548
|
type: 'tool.end',
|
|
314
549
|
runtimeStageId,
|
|
315
550
|
subflowPath,
|
|
316
551
|
depth,
|
|
317
552
|
ts,
|
|
553
|
+
commitIdxBefore,
|
|
554
|
+
commitIdxAfter: commitIdxBefore,
|
|
318
555
|
toolCallId: p.toolCallId,
|
|
319
556
|
...(p.result !== undefined ? { result: p.result } : {}),
|
|
320
557
|
...(p.durationMs !== undefined ? { durationMs: p.durationMs } : {}),
|
|
@@ -324,12 +561,14 @@ export class BoundaryRecorder extends SequenceRecorder {
|
|
|
324
561
|
}
|
|
325
562
|
case 'agentfootprint.context.injected': {
|
|
326
563
|
const p = event.payload;
|
|
327
|
-
this.
|
|
564
|
+
this.store.push({
|
|
328
565
|
type: 'context.injected',
|
|
329
566
|
runtimeStageId,
|
|
330
567
|
subflowPath,
|
|
331
568
|
depth,
|
|
332
569
|
ts,
|
|
570
|
+
commitIdxBefore,
|
|
571
|
+
commitIdxAfter: commitIdxBefore,
|
|
333
572
|
slot: p.slot,
|
|
334
573
|
source: p.source ?? 'unknown',
|
|
335
574
|
...(p.sourceId ? { sourceId: p.sourceId } : {}),
|
|
@@ -347,23 +586,82 @@ export class BoundaryRecorder extends SequenceRecorder {
|
|
|
347
586
|
});
|
|
348
587
|
break;
|
|
349
588
|
}
|
|
589
|
+
case 'agentfootprint.composition.enter': {
|
|
590
|
+
// Open a boundary range for the composition. The MATCHING KEY
|
|
591
|
+
// for open/close is `payload.id` (the composition's stable id),
|
|
592
|
+
// NOT `meta.runtimeStageId`. Reason: the composition's enter
|
|
593
|
+
// event fires from a different stage (entry hook) than its
|
|
594
|
+
// exit event (merge / exit hook) — different `meta.runtimeStageId`s.
|
|
595
|
+
// The composition's `id` is the only field that's the same on
|
|
596
|
+
// both. The boundary range's runtimeStageId (used as the Lens
|
|
597
|
+
// group identity) is the ENTER event's `meta.runtimeStageId`
|
|
598
|
+
// (the entry stage's id) — that's the "fork moment."
|
|
599
|
+
const p = event.payload;
|
|
600
|
+
const e = {
|
|
601
|
+
type: 'composition.start',
|
|
602
|
+
runtimeStageId,
|
|
603
|
+
subflowPath,
|
|
604
|
+
depth,
|
|
605
|
+
ts,
|
|
606
|
+
commitIdxBefore,
|
|
607
|
+
commitIdxAfter: commitIdxBefore,
|
|
608
|
+
kind: p.kind,
|
|
609
|
+
compositionId: p.id,
|
|
610
|
+
name: p.name,
|
|
611
|
+
};
|
|
612
|
+
if (this.hasCommitTracking) {
|
|
613
|
+
const token = this.boundaryIndex.open(toCompositionBoundaryLabel(e), commitIdxBefore);
|
|
614
|
+
this.openTokens.set(`composition:${p.id}`, token);
|
|
615
|
+
}
|
|
616
|
+
this.store.push(e);
|
|
617
|
+
break;
|
|
618
|
+
}
|
|
619
|
+
case 'agentfootprint.composition.exit': {
|
|
620
|
+
// Close the matching composition range. Keyed by `payload.id`
|
|
621
|
+
// — see the enter handler for why this differs from
|
|
622
|
+
// meta.runtimeStageId.
|
|
623
|
+
const p = event.payload;
|
|
624
|
+
const e = {
|
|
625
|
+
type: 'composition.end',
|
|
626
|
+
runtimeStageId,
|
|
627
|
+
subflowPath,
|
|
628
|
+
depth,
|
|
629
|
+
ts,
|
|
630
|
+
commitIdxBefore,
|
|
631
|
+
commitIdxAfter: commitIdxBefore,
|
|
632
|
+
kind: p.kind,
|
|
633
|
+
compositionId: p.id,
|
|
634
|
+
name: p.name ?? '',
|
|
635
|
+
status: p.status,
|
|
636
|
+
durationMs: p.durationMs,
|
|
637
|
+
};
|
|
638
|
+
if (this.hasCommitTracking) {
|
|
639
|
+
const key = `composition:${p.id}`;
|
|
640
|
+
const token = this.openTokens.get(key);
|
|
641
|
+
if (token) {
|
|
642
|
+
this.boundaryIndex.close(token, commitIdxBefore);
|
|
643
|
+
this.openTokens.delete(key);
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
this.store.push(e);
|
|
647
|
+
break;
|
|
648
|
+
}
|
|
350
649
|
default:
|
|
351
|
-
// Other typed events (
|
|
352
|
-
//
|
|
353
|
-
//
|
|
354
|
-
// (agent.turn_*) that downstream selectors derive on demand.
|
|
650
|
+
// Other typed events (agent.*, eval.*, etc.) are not mapped to
|
|
651
|
+
// DomainEvent for now — they're higher-level summaries that
|
|
652
|
+
// downstream selectors derive on demand.
|
|
355
653
|
break;
|
|
356
654
|
}
|
|
357
655
|
}
|
|
358
656
|
// ── Read API ────────────────────────────────────────────────────────
|
|
359
657
|
/** All events in capture order (the canonical projection). */
|
|
360
658
|
getEvents() {
|
|
361
|
-
return this.
|
|
659
|
+
return this.store.getAll();
|
|
362
660
|
}
|
|
363
661
|
/** Type-narrowed lookup: all events of one kind. */
|
|
364
662
|
getEventsByType(type) {
|
|
365
663
|
const out = [];
|
|
366
|
-
for (const e of this.
|
|
664
|
+
for (const e of this.store.getAll()) {
|
|
367
665
|
if (e.type === type)
|
|
368
666
|
out.push(e);
|
|
369
667
|
}
|
|
@@ -373,7 +671,7 @@ export class BoundaryRecorder extends SequenceRecorder {
|
|
|
373
671
|
/** All boundary events (run + subflow, entry + exit interleaved). */
|
|
374
672
|
getBoundaries() {
|
|
375
673
|
const out = [];
|
|
376
|
-
for (const e of this.
|
|
674
|
+
for (const e of this.store.getAll()) {
|
|
377
675
|
if (e.type === 'run.entry' ||
|
|
378
676
|
e.type === 'run.exit' ||
|
|
379
677
|
e.type === 'subflow.entry' ||
|
|
@@ -393,7 +691,7 @@ export class BoundaryRecorder extends SequenceRecorder {
|
|
|
393
691
|
}
|
|
394
692
|
/** Entry/exit pair for one chart execution by `runtimeStageId`. */
|
|
395
693
|
getBoundary(runtimeStageId) {
|
|
396
|
-
const matches = this.
|
|
694
|
+
const matches = this.store.getByKey(runtimeStageId);
|
|
397
695
|
let entry;
|
|
398
696
|
let exit;
|
|
399
697
|
for (const e of matches) {
|
|
@@ -420,7 +718,7 @@ export class BoundaryRecorder extends SequenceRecorder {
|
|
|
420
718
|
const systemPrompt = [];
|
|
421
719
|
const messages = [];
|
|
422
720
|
const tools = [];
|
|
423
|
-
for (const e of this.
|
|
721
|
+
for (const e of this.store.getAll()) {
|
|
424
722
|
if (e.type !== 'subflow.entry' && e.type !== 'subflow.exit')
|
|
425
723
|
continue;
|
|
426
724
|
if (e.slotKind === 'system-prompt')
|
|
@@ -459,7 +757,7 @@ export class BoundaryRecorder extends SequenceRecorder {
|
|
|
459
757
|
* matches `runtimeStageId`.
|
|
460
758
|
*/
|
|
461
759
|
aggregateForBoundary(runtimeStageId) {
|
|
462
|
-
const events = this.
|
|
760
|
+
const events = this.store.getAll();
|
|
463
761
|
let entry;
|
|
464
762
|
let exit;
|
|
465
763
|
for (const e of events) {
|
|
@@ -484,7 +782,7 @@ export class BoundaryRecorder extends SequenceRecorder {
|
|
|
484
782
|
* not user-facing rollup units.
|
|
485
783
|
*/
|
|
486
784
|
aggregateAllBoundaries() {
|
|
487
|
-
const events = this.
|
|
785
|
+
const events = this.store.getAll();
|
|
488
786
|
const out = [];
|
|
489
787
|
// Index exits by runtimeStageId for O(1) pair-up.
|
|
490
788
|
const exitByRid = new Map();
|
|
@@ -513,18 +811,20 @@ export class BoundaryRecorder extends SequenceRecorder {
|
|
|
513
811
|
}
|
|
514
812
|
}
|
|
515
813
|
// ── Internal helpers ─────────────────────────────────────────────────
|
|
516
|
-
function buildRunEvent(type, payload) {
|
|
814
|
+
function buildRunEvent(type, payload, commitIdxBefore) {
|
|
517
815
|
return {
|
|
518
816
|
type,
|
|
519
817
|
runtimeStageId: ROOT_RUNTIME_STAGE_ID,
|
|
520
818
|
subflowPath: [ROOT_SUBFLOW_ID],
|
|
521
819
|
depth: 0,
|
|
522
820
|
ts: Date.now(),
|
|
821
|
+
commitIdxBefore,
|
|
822
|
+
commitIdxAfter: commitIdxBefore,
|
|
523
823
|
payload,
|
|
524
824
|
isRoot: true,
|
|
525
825
|
};
|
|
526
826
|
}
|
|
527
|
-
function buildSubflowEvent(event, type) {
|
|
827
|
+
function buildSubflowEvent(event, type, commitIdxBefore) {
|
|
528
828
|
const subflowId = event.subflowId;
|
|
529
829
|
if (!subflowId)
|
|
530
830
|
return undefined;
|
|
@@ -545,6 +845,8 @@ function buildSubflowEvent(event, type) {
|
|
|
545
845
|
subflowPath,
|
|
546
846
|
depth,
|
|
547
847
|
ts: Date.now(),
|
|
848
|
+
commitIdxBefore,
|
|
849
|
+
commitIdxAfter: commitIdxBefore,
|
|
548
850
|
subflowId,
|
|
549
851
|
localSubflowId,
|
|
550
852
|
subflowName: event.name,
|