Injected State

Pass agent context into tools automatically without exposing it in the tool's public schema

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.

python
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.

Diagram

Agent State

Injected param

User call: query only

Tool

Result

The LLM sees only query in the schema. The agent automatically fills state before calling the tool.

Quick Start

  1. Simplest form — bare Injected
    python
    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
    python
    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
    python
    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

Diagram
ToolSchemaAgentUserToolSchemaAgentUser“Search for X”Get tool schema{query: string} (no state field)Build injection contextcall(query=”X”, state=AgentState(…))resultformatted response

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_message`str \None`Most recent message from the user
last_agent_message`str \None`Most 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:

python
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:

python
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:

python
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

Prefer bare Injected or Injected[dict] for simple access

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.

Never add injected params to tool docstrings

The LLM builds its understanding from the docstring. Documenting injected parameters confuses the model — describe only the user-facing parameters.

Use with_injection_context in tests

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.

Keep injected parameters optional-safe

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.


Related