-
Notifications
You must be signed in to change notification settings - Fork 120
Description
Summary
AgentKit networks exhibit unexpected behavior when embedded in Inngest functions containing other step.run() calls. Network execution state resets multiple times during a single network.run(), causing agents to execute redundantly and router decisions to be unreliable.
Observed Behavior
Single Network Run, Multiple Execution Cycles
Despite calling network.run() only once, we observe multiple execution cycles with reset state:
2025-07-11T22:15:49.838Z [AgentService] [info]: 🔂 [ilyu1xlir] Running network ← Single network.run()
[AgentKit DEBUG] INITIAL - Calling router with _counter: 0, results.length: 0
[AgentKit DEBUG] EXECUTING AGENT: VideoPlanningAgent (counter before: 0)
[AgentKit DEBUG] AGENT RUN STARTED: VideoPlanningAgent
// No AGENT RUN FINISHED - execution interrupted
[AgentKit DEBUG] INITIAL - Calling router with _counter: 0, results.length: 0 ← State reset
[AgentKit DEBUG] EXECUTING AGENT: VideoPlanningAgent (counter before: 0) ← Agent runs again
[AgentKit DEBUG] AGENT RUN STARTED: VideoPlanningAgent
[AgentKit DEBUG] AGENT RUN FINISHED: VideoPlanningAgent
[AgentKit DEBUG] AGENT COMPLETED: VideoPlanningAgent (counter after: 1)
[AgentKit DEBUG] INITIAL - Calling router with _counter: 0, results.length: 0 ← State reset again
[AgentKit DEBUG] EXECUTING AGENT: VideoPlanningAgent (counter before: 0) ← Agent runs again
Multiple Router Invocations
Both function routers and routing agent onRoute handlers are called multiple times:
Function Router:
🔂 Called 0 times
🎯 Routing to planning agent for initial strategy
🔂 Called 0 times ← Called again with same callCount
🎯 Routing to planning agent for initial strategy
Routing Agent onRoute:
2025-07-11T22:15:55.376Z [VideoBuilderRouter] [debug]: onRoute handler called with result
2025-07-11T22:15:58.518Z [VideoBuilderRouter] [debug]: onRoute handler called with result
// ↑ Same result object processed multiple times
Reproduction Setup
Following the official multi-tenancy pattern with additional Inngest steps:
export const userPromptProcessing = inngest.createFunction(
{ id: 'user-prompt-processing', retries: 0 },
{ event: UserInteractionEvents.UserMessage },
async ({ event, step, logger }) => {
// Multiple Inngest steps before network
const working = await step.run('create-working-interaction', async () => {
// ... database operations
});
const state = await step.run('generate-state', async () => {
// ... state generation
});
// Network execution - this is where issues occur
const networkResult = await videoBuilderNetwork.run(userPrompt, { state });
// Additional steps after...
}
);Router Implementation
// Function router
export const videoBuilderRouter: Network.Router.FnRouter<CreativeAgentState> = ({
input, network, stack, callCount, lastResult
}) => {
if (callCount === 0) {
return videoPlanningAgent;
}
return videoBuilderRoutingAgent;
};
// Routing agent with onRoute
export const videoBuilderRoutingAgent = createRoutingAgent<CreativeAgentState>({
name: 'VideoBuilderRouter',
tools: [routeToAgent, completeNetwork],
lifecycle: {
onRoute: ({ result, agent, network }) => {
const tool = result.toolCalls[0];
if (tool?.content?.data?.nextAgent) {
return [tool.content.data.nextAgent];
}
return undefined;
},
},
});Debug Method
Added logging to Agent Kit's compiled source to track execution flow:
Router Calls (in getNextAgents method):
console.log(`[AgentKit DEBUG] ${debugSource} - Calling router with _counter: ${this._counter}, results.length: ${this.state.results.length}`);
Agent Execution (in network execution loop):
console.log(`[AgentKit DEBUG] EXECUTING AGENT: ${agent.name} (counter before: ${this._counter})`);
console.log(`[AgentKit DEBUG] AGENT COMPLETED: ${agent.name} (counter after: ${this._counter})`);
Agent Run Method (in Agent.run):
console.log(`[AgentKit DEBUG] AGENT RUN STARTED: ${this.name}`);
// ... at end of method
console.log(`[AgentKit DEBUG] AGENT RUN FINISHED: ${this.name}`);
Questions and Observations
- Why does network state (_counter, results.length) reset to initial values multiple times during a single network run?
- What causes the interruption between AGENT RUN STARTED and AGENT RUN FINISHED?
- Is this related to how Agent Kit's internal step.ai.infer() calls interact with the parent Inngest function's step context?
- Should network execution be atomic, or is this multi-cycle behavior intended?
- Why do both function routers and routing agent onRoute handlers exhibit the same replay behavior?
Root Cause Analysis
Based on investigation, the issue stems from Agent Kit's execution model not being replay-aware when used within Inngest's step-based functions:
- Each step.ai.infer() call triggers Inngest replay - Agent Kit makes internal step.ai.infer() calls that cause the parent Inngest function to replay from the beginning
- Agent Kit state doesn't persist across step boundaries - While user state persists, Agent Kit's internal execution state (_counter, results.length) resets on each replay
- Network execution becomes replay-driven rather than linear - Instead of a single execution flow, the network runs multiple partial executions that get replayed and continued
Evidence from debugging:
[STATE CHECK] callCount: 0, results.length: 0, state.data keys: chapterId,inngestEventId,interaction,ownerId,projectId,workingInteractionId,_dedupeCache, has _dedupeCache: true
- User state data persists (all keys present including custom _dedupeCache)
- But Agent Kit execution state resets (callCount: 0, results.length: 0) on each replay
Impact on Applications
- Performance degradation from redundant agent executions
- Increased LLM API costs from duplicate calls
- Unreliable router logic due to inconsistent callCount values
- Complex debugging due to interleaved execution logs
- Potential state corruption if agents have side effects
- Logging noise from duplicate router calls and lifecycle events
- Difficulty with replay-aware logging - Standard loggers don't deduplicate across Inngest replays
Environment Details
- Agent Kit Version: 0.8.0
- Integration Pattern: Multi-tenancy following official documentation
- Inngest Context: Network embedded in function with multiple other steps
- Occurrence: Only when network.run() called within Inngest function containing other step.run() calls
- Simple Pattern: Issue does not occur with standalone network execution (just network.run() alone)
Additional Notes
- Network eventually completes successfully despite multiple execution cycles
- The pattern follows official Agent Kit documentation for multi-tenancy
- Issue appears to be specific to the interaction between Agent Kit's execution model and Inngest's step-based replay system