Skip to main content

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:

  • RequestContext
  • RequestContextBuilder

During execution, the SDK attaches request context through the framework's native carrier:

FrameworkOfficial framework patternSDK carrier
PydanticAITools use RunContext and read runtime dependencies from ctx.depsdeps
LangChainTools use ToolRuntime and read runtime values from runtime.contextcontext
LangGraphNodes use Runtime and read run-scoped values from runtime.contextcontext

The SDK also fills in missing values automatically when it can, such as:

  • agent_id
  • thread_id
  • framework

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:

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:

FieldPurpose
request_idUnique ID for one execution
agent_idAgent ID used for the run
thread_idConversation thread ID
frameworkActive framework, for example pydantic_ai, langchain, or langgraph
created_atTimestamp when context was created
metadataCustom metadata such as source, tenant, region, or correlation ID
user_idUser identifier for trace attribution
session_idSession identifier for grouping traces
tagsTags 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(...)
tip

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_id
  • thread_id
  • framework
  • 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, and tags from RequestContext are 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

NeedPut it in
User prompt or questionagent.run("...")
Request ID, user ID, session ID, tenant, tagsRequestContext
App runtime dependencies such as region or user profiledeps or context
LangGraph workflow values that change during executionLangGraph state
Static configuration such as credentials or endpointsEnvironment/configuration, not RequestContext