Request Context
RequestContext is a small metadata object for one agent execution.
Use it when you want to pass request-level information such as request ID, user ID, session ID, tags, tenant, source system, or correlation metadata through an agent run.
It helps you answer questions like:
- Which request triggered this agent run?
- Which user or session should this trace belong to?
- Which tenant, product, or source system did this request come from?
- How can tools or graph nodes access request metadata without custom plumbing?
Mental Model
Think of RequestContext as run-scoped metadata.
It is not the user prompt. It is not long-lived configuration. It is not business state that changes inside the workflow.
It is metadata attached to a single execution:
User request
|
v
RequestContext
|-- request_id
|-- user_id
|-- session_id
|-- tags
|-- metadata
v
agent.run(...) / agent.stream(...) / agent.resume(...)
The SDK uses this context for traceability and makes it available to the active framework.
What the SDK Provides
The SDK exposes:
RequestContextRequestContextBuilder
During execution, the SDK attaches request context through the framework's native carrier:
| Framework | Official framework pattern | SDK carrier |
|---|---|---|
| PydanticAI | Tools use RunContext and read runtime dependencies from ctx.deps | deps |
| LangChain | Tools use ToolRuntime and read runtime values from runtime.context | context |
| LangGraph | Nodes use Runtime and read run-scoped values from runtime.context | context |
The SDK also fills in missing values automatically when it can, such as:
agent_idthread_idframework
If user_id, session_id, or tags are set on RequestContext, the SDK automatically propagates them to Langfuse traces.
Official Framework Patterns
The SDK follows the native context pattern of each supported framework:
- PydanticAI tools use
RunContextto access dependencies. See PydanticAI Function Tools. - LangChain tools use runtime context through
ToolRuntime. See LangChain runtime and tool context. - LangGraph nodes use runtime context through
Runtimeandcontext_schema. See LangGraph concepts.
The CAIP Agents SDK adds RequestContext on top of these native patterns so your application gets one consistent request metadata model across all frameworks.
RequestContext Fields
RequestContext supports these fields:
| Field | Purpose |
|---|---|
request_id | Unique ID for one execution |
agent_id | Agent ID used for the run |
thread_id | Conversation thread ID |
framework | Active framework, for example pydantic_ai, langchain, or langgraph |
created_at | Timestamp when context was created |
metadata | Custom metadata such as source, tenant, region, or correlation ID |
user_id | User identifier for trace attribution |
session_id | Session identifier for grouping traces |
tags | Tags for filtering and debugging traces |
Build a RequestContext
Use RequestContextBuilder instead of manually creating dictionaries.
from caip_agents_sdk import RequestContextBuilder
request_context = (
RequestContextBuilder()
.with_request_id("req-2026-07-01-001")
.with_metadata({"source": "agents-foundry-docs"})
.add_metadata("tenant", "demo")
.with_user_id("user-123")
.with_session_id("session-456")
.with_tags(["quickstart", "test"])
.build()
)
Common builder methods:
with_request_id(...)with_agent_id(...)with_thread_id(...)with_framework(...)with_metadata(...)add_metadata(...)with_user_id(...)with_session_id(...)with_tags(...)add_tag(...)
You do not need to set agent_id, thread_id, or framework manually for most runs. The SDK can infer and backfill them during execution.
PydanticAI Usage
PydanticAI's official tool pattern uses RunContext. Tools that need runtime dependencies receive ctx: RunContext[...] and read values from ctx.deps.
In the SDK, put request_context inside your dependency object and pass it with deps=....
Define Dependencies
from dataclasses import dataclass
from typing import Optional
from caip_agents_sdk import RequestContext
@dataclass
class AppDeps:
user_id: str
region: str
request_context: Optional[RequestContext] = None
Run with Request Context
deps = AppDeps(
user_id="u-123",
region="eu-central-1",
request_context=request_context,
)
result = await agent.run(
"Summarize the latest deployment risks",
deps=deps,
)
Access It Inside a Tool
from caip_agents_sdk import RunContext
@agent.tool
def trace_request(ctx: RunContext[AppDeps]) -> str:
rc = ctx.deps.request_context
request_id = rc.request_id if rc else ""
framework = rc.framework if rc else ""
return (
f"user_id={ctx.deps.user_id}, "
f"request_id={request_id}, "
f"framework={framework}"
)
LangChain Usage
LangChain's official runtime pattern lets tools receive ToolRuntime and read runtime values from runtime.context.
In the SDK, put request_context inside your context object and pass it with context=....
Define Context
from dataclasses import dataclass
from typing import Optional
from caip_agents_sdk import RequestContext
@dataclass
class AppContext:
user_id: str
region: str
request_context: Optional[RequestContext] = None
Run with Request Context
context = AppContext(
user_id="u-123",
region="eu-central-1",
request_context=request_context,
)
result = await agent.run(
"Summarize the latest deployment risks",
context=context,
)
Access It Inside a Tool
from caip_agents_sdk import ToolRuntime
@agent.tool
def trace_request(runtime: ToolRuntime[AppContext]) -> str:
rc = runtime.context.request_context
request_id = rc.request_id if rc else ""
framework = rc.framework if rc else ""
return (
f"user_id={runtime.context.user_id}, "
f"request_id={request_id}, "
f"framework={framework}"
)
LangGraph Usage
LangGraph's official pattern separates state from runtime context.
- Use state for workflow data that changes as the graph runs, such as messages, route, or intermediate outputs.
- Use runtime context for run-scoped values that should be available to nodes but should not become graph state, such as user ID, region, tenant, request ID, trace tags, or source system.
In the SDK, pass LangGraph runtime context with context=....
Define Context and State
from dataclasses import dataclass
from typing import Optional
from caip_agents_sdk import MessagesState, RequestContext
@dataclass
class AppContext:
user_id: str
region: str
request_context: Optional[RequestContext] = None
class SupportState(MessagesState):
route: str
Use Runtime Context in a Node
from langgraph.runtime import Runtime
async def router_node(state: SupportState, runtime: Runtime[AppContext]):
rc = runtime.context.request_context
request_id = rc.request_id if rc else ""
user_id = runtime.context.user_id
print(f"Handling request_id={request_id} for user_id={user_id}")
return {"route": "general"}
Add the Context Schema to the Graph
from caip_agents_sdk import START, END, StateGraph
def build_support_graph(llm, tools):
builder = StateGraph(SupportState, context_schema=AppContext)
builder.add_node("router", router_node)
builder.add_edge(START, "router")
builder.add_edge("router", END)
return builder.compile()
Run with Request Context
context = AppContext(
user_id="u-123",
region="eu-central-1",
request_context=request_context,
)
result = await agent.run(
"Customer C001 needs billing help",
context=context,
)
Resume with the Same Context
If your LangGraph workflow uses checkpointing or human-in-the-loop, keep passing the same context when you resume.
result = await agent.run(
"Customer wants manager escalation",
context=context,
)
if result.is_interrupted():
resumed = await agent.resume(
"approve",
context=context,
)
What Happens If You Do Not Provide RequestContext?
You can still pass your normal dependency or context object without setting request_context.
context = AppContext(
user_id="u-123",
region="eu-central-1",
)
result = await agent.run(
"Summarize this request",
context=context,
)
If request_context is missing, the SDK creates one automatically and attaches it to the carrier object when possible.
The generated context includes inferred values such as:
agent_idthread_idframework- generated
request_id
How Context Merging Works
The SDK merges explicit and inferred context in a predictable way:
- Values you provide take precedence.
- Missing values are backfilled from runtime information.
- Metadata is merged, with your metadata taking precedence.
user_id,session_id, andtagsfromRequestContextare propagated to Langfuse automatically.
This lets you provide only the fields you care about while still getting a complete context during execution.
Quick Decision Guide
| Need | Put it in |
|---|---|
| User prompt or question | agent.run("...") |
| Request ID, user ID, session ID, tenant, tags | RequestContext |
| App runtime dependencies such as region or user profile | deps or context |
| LangGraph workflow values that change during execution | LangGraph state |
| Static configuration such as credentials or endpoints | Environment/configuration, not RequestContext |