Skip to main content
Injected state lets tools receive hidden context — session ID, agent ID, previous results — without users or the LLM ever seeing those parameters in the tool schema.
from praisonaiagents import Agent, tool
from praisonaiagents.tools import Injected

@tool
def search(query: str, state=Injected()) -> str:
    """Search with hidden session context."""
    return f"Results for {query} (session={state.get(session_id)})"

agent = Agent(name="assistant", tools=[search])
agent.start("Find recent orders")
The user asks a question; hidden state is injected into the tool without appearing in the schema. The LLM sees only query in the schema. The agent automatically fills state before calling the tool.

Quick Start

1

Simplest form — bare Injected

from praisonaiagents import Agent, tool
from praisonaiagents.tools import Injected

@tool
def quick_context(query: str, state: Injected) -> str:
    """Search with session context — bare Injected defaults to dict."""
    session = state.get("session_id", "unknown")
    return f"Results for '{query}' (session: {session})"

agent = Agent(name="SearchBot", tools=[quick_context])
agent.start("Find Python tutorials")
Bare Injected behaves like Injected[dict] — excluded from the tool schema and resolved to state.to_dict().
2

Create a tool with injected state

from praisonaiagents import Agent, tool
from praisonaiagents.tools import Injected

@tool
def personalized_search(query: str, state: Injected[dict]) -> str:
    """Search with user context."""
    session = state.get("session_id", "unknown")
    return f"Results for '{query}' (session: {session})"

agent = Agent(
    name="SearchBot",
    instructions="Search for information.",
    tools=[personalized_search]
)

result = agent.start("Find Python tutorials")
The state parameter never appears in tool descriptions shown to the LLM — only query does.
3

Use AgentState for typed access

from praisonaiagents import Agent, tool
from praisonaiagents.tools import Injected
from praisonaiagents.tools.injected import AgentState

@tool
def context_aware_tool(query: str, state: Injected[AgentState]) -> str:
    """Access typed agent state fields."""
    return (
        f"Query: {query}\n"
        f"Agent: {state.agent_id}\n"
        f"Session: {state.session_id}\n"
        f"Previous results: {len(state.previous_tool_results)}"
    )

agent = Agent(
    name="ContextBot",
    instructions="Help with context-aware tasks.",
    tools=[context_aware_tool]
)

result = agent.start("What's the current context?")

How It Works

When a tool parameter is annotated with Injected, Injected[T], or bare Injected, the SDK:
  1. Strips that parameter from the schema sent to the LLM
  2. Captures the current AgentState at call time
  3. Injects the state value automatically before the tool runs
AnnotationInjected value
Injectedstate.to_dict() — same as Injected[dict]
Injected[dict]state.to_dict() — plain Python dict
Injected[AgentState]Full AgentState dataclass with all fields

Configuration Options

AgentState fields available at runtime:
FieldTypeDescription
agent_idstrName/ID of the running agent
run_idstrUnique ID for this run
session_idstrConversation session identifier
last_user_messagestr | NoneMost recent message from the user
last_agent_messagestr | NoneMost recent message from the agent
memoryAnyAgent memory object if configured
previous_tool_resultslistResults from earlier tool calls in this run
metadatadictExtra key-value context

Injected Tools TypeScript Reference

TypeScript injected state configuration

Tools Rust Reference

Rust tool configuration

Common Patterns

Multi-turn memory access in a tool:
from praisonaiagents import Agent, tool
from praisonaiagents.tools import Injected
from praisonaiagents.tools.injected import AgentState

@tool
def summarize_session(topic: str, state: Injected[AgentState]) -> str:
    """Summarize what we discussed about a topic this session."""
    history = state.previous_tool_results
    return f"Session {state.session_id}{len(history)} tool calls so far on '{topic}'"
Testing with a manual injection context:
from praisonaiagents.tools.injected import AgentState, with_injection_context

state = AgentState(agent_id="test-agent", run_id="run-001", session_id="sess-42")

with with_injection_context(state):
    result = personalized_search(query="Python")
    print(result)
Validating the tool schema has no injected params:
import inspect
from praisonaiagents.tools import Injected

sig = inspect.signature(personalized_search)
public_params = [
    name for name, param in sig.parameters.items()
    if not (hasattr(param.annotation, "__origin__") and param.annotation.__origin__ is Injected)
]
print(public_params)

Best Practices

Bare Injected and Injected[dict] both return state.to_dict(). Use Injected[AgentState] when you need memory, learn_manager, or previous_tool_results objects directly.
The LLM builds its understanding from the docstring. Documenting injected parameters confuses the model — describe only the user-facing parameters.
Direct unit tests cannot rely on an agent to set up injection context. Wrap calls with with_injection_context(state) to test tools in isolation without spinning up a full agent.
get_current_state() returns None when called outside an agent context. resolve_injected_value falls back to an empty dict. Design tools to handle empty state gracefully.

Tools

Creating and registering tools with agents

Middleware

Intercept tool calls before and after execution