InvocationContext
The internal execution environment for a single agent invocation — exposes all services, session data, and lifecycle controls.
InvocationContext is the root data container for a single invocation — one call to runner.run() from start to finish. It is not in the ReadonlyContext → CallbackContext → ToolContext inheritance chain; instead, all three of those classes hold a reference to it internally. You interact with InvocationContext directly only when writing custom agent classes that extend BaseAgent or LlmAgent.
import { InvocationContext } from "@iqai/adk";What an invocation contains
A single invocation spans all agent calls from the moment the user message arrives to the moment a final response is produced. All agent calls within one invocation share the same invocationId and the same session.
Properties
Services
Services are set by the runner at startup. Optional services may be undefined — always guard before using them.
| Property | Type | Description |
|---|---|---|
sessionService | BaseSessionService | Always present. Manages session CRUD and event appending. |
artifactService | BaseArtifactService | undefined | Present if configured with .withArtifactService(...). |
memoryService | MemoryService | undefined | Present if configured with .withMemoryService(...). |
pluginManager | PluginManager | Manages registered plugins for this invocation. |
Identity and routing
| Property | Type | Description |
|---|---|---|
invocationId | string | Unique ID for this invocation, shared across all child contexts. |
branch | string | undefined | Dot-separated agent path, e.g. "orchestrator.researcher". |
appName | string | Derived from session.appName. |
userId | string | Derived from session.userId. |
Execution state
| Property | Type | Description |
|---|---|---|
agent | BaseAgent | The agent currently executing. |
session | Session | The current session with state and event history. |
userContent | Content | undefined | The original user message that started this invocation. |
endInvocation | boolean | Set to true in a callback or tool to terminate the invocation early. |
runConfig | RunConfig | undefined | Runtime configuration including maxLlmCalls. |
contextCacheConfig | ContextCacheConfig | undefined | Context caching configuration if enabled. |
Methods
createChildContext(agent)
Creates a new InvocationContext for a sub-agent. The child inherits the same invocationId, services, session, and flags. Its branch is extended with the sub-agent's name so that history isolation works correctly in parallel flows.
createChildContext(agent: BaseAgent): InvocationContextincrementLlmCallCount()
Increments the internal LLM call counter and throws LlmCallsLimitExceededError if the runConfig.maxLlmCalls limit has been reached. The framework calls this automatically before each LLM request — you only need it if you are making LLM calls manually in a custom agent.
incrementLlmCallCount(): voidCustom agent example
Most developers never touch InvocationContext directly. The scenario where you do is when writing a custom BaseAgent subclass. The runAsyncImpl method receives the context and must yield Event objects:
import { BaseAgent, InvocationContext, Event } from "@iqai/adk";
export class SummaryAgent extends BaseAgent {
protected async *runAsyncImpl(
ctx: InvocationContext,
): AsyncGenerator<Event, void, unknown> {
// Read the original user message
const userText =
ctx.userContent?.parts?.find(p => p.text)?.text ?? "(no input)";
// Optionally search memory if the service is configured
let memorySnippet = "";
if (ctx.memoryService) {
const results = await ctx.memoryService.search({
query: userText,
userId: ctx.userId,
appName: ctx.appName,
});
if (results.length > 0) {
memorySnippet = ` (related memory: ${results[0].memory.content.summary})`;
}
}
yield new Event({
invocationId: ctx.invocationId,
author: this.name,
content: {
parts: [{ text: `Summarising: "${userText}"${memorySnippet}` }],
},
});
}
}Delegating to sub-agents
When an orchestrating agent needs to hand off work, it creates a child context so the sub-agent runs with the correct branch path:
import { BaseAgent, InvocationContext, Event } from "@iqai/adk";
export class OrchestratorAgent extends BaseAgent {
constructor(private readonly researchAgent: BaseAgent) {
super({ name: "orchestrator", description: "Routes requests" });
}
protected async *runAsyncImpl(
ctx: InvocationContext,
): AsyncGenerator<Event, void, unknown> {
const userText = ctx.userContent?.parts?.find(p => p.text)?.text ?? "";
if (userText.toLowerCase().includes("research")) {
// Create a child context — same invocation ID, updated branch
const childCtx = ctx.createChildContext(this.researchAgent);
yield* this.researchAgent.runAsync(childCtx);
} else {
yield new Event({
invocationId: ctx.invocationId,
author: this.name,
content: { parts: [{ text: "I can help with research requests." }] },
});
}
}
}Terminating an invocation early
Setting endInvocation = true on the context signals every part of the framework to stop after the current step completes. A callback or tool can do this to implement hard limits or graceful shutdowns:
import { CallbackContext } from "@iqai/adk";
async function safetyCallback(ctx: CallbackContext) {
const callCount = (ctx.state["callCount"] as number) ?? 0;
if (callCount > 50) {
ctx.invocationContext.endInvocation = true;
return undefined;
}
ctx.state["callCount"] = callCount + 1;
return undefined;
}endInvocation is a shared flag — setting it in a child context also
terminates the parent, because child contexts reference the same flag object.
Next steps
📖 ReadonlyContext
The read-only view of InvocationContext used in instruction providers
🔁 CallbackContext
The callback layer — exposes invocationContext as a property
🗄️ Context Caching
Cache large prompts via contextCacheConfig on the invocation
🤖 Agents
How agents implement runAsyncImpl and receive InvocationContext