oridecon-ai-agents provides an agent system with pluggable reasoning strategies, tool registration, and an executor protocol. Agents think, act, and observe using strategies like ReAct or Plan-and-Execute, with tool access governed by a registry.
For full configuration details, see the oridecon-ai-agents package docs.
1. The Contracts
Section titled “1. The Contracts”All agents, tools, and executors implement protocols from oridecon.contracts.ai. The executor drives the reasoning loop, and the tool registry manages tool lifecycle:
from typing import Any, Protocol, runtime_checkablefrom oridecon.result import Resultfrom oridecon.contracts.ai import AgentError, ToolError, AgentResponse
class ToolProtocol(Protocol): @property def name(self) -> str: ... @property def description(self) -> str: ... @property def parameters_schema(self) -> dict[str, Any]: ... async def execute(self, **kwargs: Any) -> Any: ...
class AgentExecutorProtocol(Protocol): async def run( self, agent: AgentProtocol, message: str, session_id: str | None = None, user_id: str | None = None, **kwargs: Any, ) -> Result[AgentResponse, AgentError]: ...
async def astream( self, agent: AgentProtocol, message: str, session_id: str | None = None, user_id: str | None = None, **kwargs: Any, ) -> Any: ...
class ToolRegistryProtocol(Protocol): def register(self, tool: ToolProtocol, module_class: type | None = None) -> None: ... def get(self, name: str) -> ToolProtocol | None: ... def list_tools(self) -> list[ToolProtocol]: ... async def execute(self, name: str, **kwargs: Any) -> Result[Any, ToolError]: ...Your services depend on these protocols — never on concrete implementations:
graph LR
Svc[Your Service] -- uses --> Ex[AgentExecutorProtocol]
Ex -- drives --> Strat[StrategyProtocol]
Ex -- manages --> Reg[ToolRegistryProtocol]
Reg -- contains --> Tool[ToolProtocol]
2. Configuration
Section titled “2. Configuration”Add the AgentsModule via the application:
from oridecon import Applicationfrom oridecon.ai.agents import AgentsModulefrom oridecon.ai.agents import AgentConfig
app = Application(name="my-app")app.add_module(AgentsModule.configure(AgentConfig(max_iterations=10)))ai_agents: enabled: true max_iterations: 10 default_temperature: 0.7 default_max_tokens: 2048 tool_max_retries: 3 enable_tracing: true enable_metrics: true3. Defining Tools
Section titled “3. Defining Tools”Use the @tool decorator to convert an async function into an agent tool:
from oridecon.ai.agents import tool
@tool(name="lookup_order", description="Look up an order by its ID")async def lookup_order(order_id: str) -> dict: return {"order_id": order_id, "status": "shipped"}The decorator generates a JSON Schema from the function’s type hints and wraps it in a FunctionTool. For tools with more complex behavior, subclass AbstractTool:
from oridecon.ai.agents import AbstractTool
class WeatherTool(AbstractTool): @property def name(self) -> str: return "get_weather"
@property def description(self) -> str: return "Get current weather for a location"
@property def parameters_schema(self) -> dict[str, Any]: return { "type": "object", "properties": { "location": {"type": "string", "description": "City or region"} }, "required": ["location"], }
async def execute(self, location: str) -> dict: return {"temperature": 22, "conditions": "sunny"}4. Creating an Agent
Section titled “4. Creating an Agent”AgentBuilder freezes name, prompt, tools, and strategy into an AgentProtocol. That is what examples/support-agent ships.
from oridecon.ai.agents import AgentBuilder, toolfrom oridecon.contracts.ai.agents import AgentProtocol
@tool(description="Look up an order by ID and return status.")async def lookup_order(order_id: str) -> dict: return {"found": True, "order_id": order_id, "status": "shipped"}
def build_support_agent() -> AgentProtocol: return ( AgentBuilder("support-agent") .with_system_prompt("Use tools. Never invent order state.") .with_tools(lookup_order) .with_strategy("react") .build() )A facade can wrap the executor so callers get Result[AgentResponse, AgentError] from ask() — see the same example’s SupportAgent. AgentBase is still available if you prefer a subclass with a tools property.
5. Running an Agent
Section titled “5. Running an Agent”Bind LLMClientProtocol in a provider (required before AgentsModule boots). Resolve AgentExecutorProtocol and call run(agent=..., message=...):
from oridecon import Applicationfrom oridecon.ai.agents import AgentsModule, AgentConfigfrom oridecon.contracts.ai.agents import AgentExecutorProtocol
async def main() -> None: async with Application.boot( modules=[AgentsModule.configure(AgentConfig(max_iterations=5))], ) as app: executor = await app.container.resolve(AgentExecutorProtocol) agent = build_support_agent()
result = await executor.run(agent=agent, message="Where is order 123?") if result.is_ok(): response = result.unwrap() print(f"Answer: {response.message}") print(f"Steps: {len(response.steps)}") print(f"Tokens: {response.total_tokens}") else: error = result.unwrap_err() print(f"Agent failed: {error}")6. Strategies
Section titled “6. Strategies”Agents use a reasoning strategy to drive execution. The framework ships with several built-in strategies registered in AgentStrategyRegistry:
| Strategy | Description |
|---|---|
ReActStrategy | Reason → Act → Observe (default) |
FunctionCallingStrategy | Native LLM function-calling |
PlanAndExecuteStrategy | Plan then execute steps |
ReflexionStrategy | Self-critique and refine |
SupervisorStrategy is also available for multi-agent delegation, though it is not registered in the default registry.
Switch strategies or register custom ones with the @strategy decorator:
from oridecon.ai.agents import strategy
@strategy(name="custom")class CustomStrategy: async def execute( self, message: str, tools: list, history: list[dict[str, Any]], llm: Any, **kwargs: Any, ) -> Any: # Custom reasoning loop ...7. Multi-Agent Support
Section titled “7. Multi-Agent Support”Enable multi-agent orchestration to let agents delegate tasks to peer agents:
from oridecon.ai.agents import AgentsModule
app.add_module(AgentsModule.configure( AgentConfig(max_iterations=10), enable_multi_agent=True,))When enabled, agents can use AgentAsToolAdapter to expose other agents as callable tools, enabling supervisor-led delegation and crew-based workflows.
8. Testing
Section titled “8. Testing”Use AgentsModule.stub() for isolated tests without an LLM backend:
from oridecon import Applicationfrom oridecon.ai.agents import AgentsModulefrom oridecon.contracts.ai import AgentExecutorProtocol
async def test_agent_resolves() -> None: async with Application.boot(modules=[AgentsModule.stub()]) as app: executor = await app.container.resolve(AgentExecutorProtocol) assert executor is not NoneThe stub registers no-op implementations that satisfy the protocols without external dependencies.
Next Steps
Section titled “Next Steps”- Dependency Injection — binding protocols
- AI Memory — episodic and semantic recall
- AI Skills — composable skills for agents
- AI Sessions — session management
- AI RAG — retrieval-augmented generation
oridecon-ai-agentspackage — crews, delegation, streaming