@@ -10,95 +10,165 @@ alwaysApply: true
1010
1111### BaseAgent (`sgr_agent_core/base_agent.py`)
1212- Parent class for all agents
13- - Implements two -phase execution cycle: Reasoning → Action
13+ - Implements three -phase execution cycle: Reasoning → Select Action → Action
1414- Manages agent context, conversation history, and streaming
1515- Must be subclassed to implement `_reasoning_phase()`, `_select_action_phase()`, `_action_phase()`
1616- Automatically registered in `AgentRegistry` via `AgentRegistryMixin`
17+ - Key attributes:
18+ - `id`: Unique agent identifier (format: `{def_name or name}_{uuid}`)
19+ - `name`: Agent class name
20+ - `task_messages`: Initial task messages in OpenAI format
21+ - `config`: AgentConfig instance with all settings
22+ - `openai_client`: AsyncOpenAI client for LLM API
23+ - `toolkit`: List of tool classes available to agent
24+ - `_context`: AgentContext instance with execution state
25+ - `conversation`: List of messages in OpenAI format for LLM context
26+ - `streaming_generator`: OpenAIStreamingGenerator for streaming responses
27+ - `logger`: Logger instance for agent logging
28+ - `log`: List of execution logs
29+ - `creation_time`: Datetime when agent was created
30+ - Key methods:
31+ - `execute()`: Main execution loop (called externally)
32+ - `_execution_step()`: Single step of execution cycle (can be overridden)
33+ - `_prepare_context()`: Prepare conversation context (can be overridden)
34+ - `_prepare_tools()`: Prepare available tools (can be overridden)
35+ - `provide_clarification()`: Receive clarification from external source
36+ - `_log_reasoning()`: Log reasoning phase results
37+ - `_log_tool_execution()`: Log tool execution results
38+ - `_save_agent_log()`: Save execution log to file
1739
1840### BaseTool (`sgr_agent_core/base_tool.py`)
19- - Parent class for all tools
20- - Must be a Pydantic model
21- - Must implement `__call__(context, config)` method
22- - Returns string or JSON string
41+ - Parent class for all tools (Pydantic `BaseModel`)
42+ - Class variables: `tool_name` (ClassVar[str]), `description` (ClassVar[str])
43+ - Must implement `__call__(context: AgentContext , config: AgentConfig, **kwargs) -> str`
44+ - Returns string or JSON string from `__call__()`
2345- Automatically registered in `ToolRegistry` via `ToolRegistryMixin`
46+ - `tool_name` defaults to class name (lowercase) if not set
47+ - `description` defaults to class docstring if not set
2448
2549### MCPBaseTool (`sgr_agent_core/base_tool.py`)
26- - Base class for MCP-integrated tools
27- - Handles MCP client calls
28- - Converts MCP responses to tool format
50+ - Base class for MCP-integrated tools (inherits from `BaseTool`)
51+ - Class variable: `_client` (ClassVar[Client | None]) - MCP client instance
52+ - `__call__()`: Calls MCP tool via `fastmcp.Client.call_tool()`
53+ - Converts MCP responses to JSON string
54+ - Respects `mcp_context_limit` from `ExecutionConfig`
55+ - Handles errors gracefully (returns error message as string)
2956
3057## Configuration Modules
3158
3259### GlobalConfig (`sgr_agent_core/agent_config.py`)
3360- Singleton pattern for global configuration
34- - Loads from YAML files (`config.yaml`, `agents.yaml`)
35- - Provides default values for all agent settings
61+ - All calls to `GlobalConfig()` return the same instance
62+ - Loads from YAML files via `from_yaml()` method
63+ - Loads from environment variables via `pydantic-settings` (prefix `SGR__`)
64+ - Contains: `llm`, `search`, `execution`, `prompts`, `mcp`, `agents`, `tools`
65+ - `agents`: Dictionary of `AgentDefinition` instances by name
66+ - `tools`: Dictionary of tool definitions by name
67+ - `definitions_from_yaml()`: Loads agent definitions from YAML (merges with existing)
3668
3769### AgentDefinition (`sgr_agent_core/agent_definition.py`)
3870- Definition template for creating agents
39- - Contains: name, base_class, tools, llm, prompts, execution, search, mcp configs
40- - Supports YAML loading
41- - Validates required fields
71+ - Inherits from `AgentConfig` (has all config fields)
72+ - Additional fields: `name`, `base_class`, `tools`
73+ - `base_class`: Can be class, ImportString (e.g., `"sgr_agent_core.agents.SGRAgent"`), or registry name
74+ - `tools`: List of tool names (strings) or tool classes
75+ - Supports YAML loading via `GlobalConfig.definitions_from_yaml()`
76+ - Validates import strings point to existing files
77+ - Automatically merges with `GlobalConfig` defaults
4278
4379### AgentConfig (`sgr_agent_core/agent_definition.py`)
4480- Runtime configuration for agent instance
45- - Combines: LLMConfig, SearchConfig, ExecutionConfig, PromptsConfig, MCPConfig
46- - Supports hierarchical inheritance from GlobalConfig
81+ - Combines: `LLMConfig`, `SearchConfig`, `ExecutionConfig`, `PromptsConfig`, `MCPConfig`
82+ - Supports hierarchical inheritance from `GlobalConfig`
83+ - Uses `extra="allow"` to support custom fields for agent-specific parameters
4784
4885## Factory and Services
4986
5087### AgentFactory (`sgr_agent_core/agent_factory.py`)
51- - Creates agent instances from AgentDefinition
52- - Resolves agent classes from AgentRegistry
53- - Resolves tools from ToolRegistry
54- - Builds MCP tools via MCP2ToolConverter
55- - Creates OpenAI client with proxy support
88+ - Creates agent instances from `AgentDefinition`
89+ - Resolves agent classes from `AgentRegistry` (by name or ImportString)
90+ - Resolves tools from `ToolRegistry` or `config.tools` section
91+ - Tool resolution order:
92+ 1. Tools defined in `config.tools` section
93+ 2. Tools in `ToolRegistry` by name (snake_case or PascalCase)
94+ 3. Auto-conversion snake_case → PascalCase for backward compatibility
95+ - Builds MCP tools via `MCP2ToolConverter`
96+ - Creates OpenAI client with proxy support via `httpx.AsyncClient`
97+ - `get_definitions_list()`: Returns all agent definitions from `GlobalConfig`
5698
5799### AgentRegistry (`sgr_agent_core/services/registry.py`)
58- - Centralized registry for agent classes
59- - Automatic registration via `AgentRegistryMixin`
100+ - Registry for agent classes (subclass of `Registry[BaseAgent]`)
101+ - Automatic registration via `AgentRegistryMixin` in `BaseAgent.__init_subclass__()`
102+ - Registers by class name (lowercase) and `name` attribute
60103- Supports lookup by name (case-insensitive)
61104
62105### ToolRegistry (`sgr_agent_core/services/registry.py`)
63- - Centralized registry for tool classes
64- - Automatic registration via `ToolRegistryMixin`
106+ - Registry for tool classes (subclass of `Registry[BaseTool]`)
107+ - Automatic registration via `ToolRegistryMixin` in `BaseTool.__init_subclass__()`
108+ - Registers by class name (lowercase) and `tool_name` attribute
65109- Supports lookup by name (case-insensitive)
66110
67111### PromptLoader (`sgr_agent_core/services/prompt_loader.py`)
68- - Loads and formats prompts from files or strings
69- - Generates system prompts with tool descriptions
70- - Formats initial user requests and clarification responses
112+ - Static class for loading and formatting prompts
113+ - `get_system_prompt()`: Formats system prompt with available tools list
114+ - `get_initial_user_request()`: Formats initial user request with current date
115+ - `get_clarification_template()`: Formats clarification response template
116+ - Uses templates from `PromptsConfig` (files or strings)
117+ - Supports placeholders: `{available_tools}`, `{current_date}`
71118
72119### MCP2ToolConverter (`sgr_agent_core/services/mcp_service.py`)
73- - Converts MCP server tools to BaseTool instances
74- - Handles MCP client initialization
75- - Builds tools from MCP configuration
120+ - Converts MCP server tools to `BaseTool` instances
121+ - `build_tools_from_mcp()`: Async method to build tools from MCP config
122+ - Uses `fastmcp.Client` to connect to MCP servers
123+ - Uses `jambo.SchemaConverter` to convert JSON schemas to Pydantic models
124+ - Creates dynamic tool classes inheriting from `MCPBaseTool`
125+ - Tool names converted to CamelCase (e.g., `web_search` → `MCPWebSearch`)
76126
77127## Agent Implementations
78128
79129### SGRAgent (`sgr_agent_core/agents/sgr_agent.py`)
80- - Uses Structured Output approach
81- - Creates dynamic JSON schema for tools
82- - LLM returns reasoning + tool schema in one call
83- - Extracts tool directly from reasoning result
130+ - Uses Structured Output approach with `response_format`
131+ - Uses `NextStepToolsBuilder` to create dynamic union tool type
132+ - `_prepare_tools()` returns `Type[NextStepToolStub]` for structured output
133+ - `_reasoning_phase()` uses `response_format` to get `NextStepToolStub` with selected tool
134+ - `_select_action_phase()` extracts tool from `reasoning.function` field
135+ - LLM returns reasoning + tool selection in one structured call
136+ - Best for models with strong structured output support
84137
85138### ToolCallingAgent (`sgr_agent_core/agents/tool_calling_agent.py`)
86- - Uses native Function Calling
87- - No explicit reasoning phase
88- - Uses `tool_choice="required"` for tool selection
89- - Best for advanced LLM models
139+ - Uses native Function Calling approach
140+ - `_reasoning_phase()` returns `None` (no explicit reasoning)
141+ - `_select_action_phase()` uses `tool_choice="required"` to force tool selection
142+ - LLM directly selects and calls tool via function calling
143+ - No structured reasoning output
144+ - Best for advanced LLM models with strong function calling support
90145
91146### SGRToolCallingAgent (`sgr_agent_core/agents/sgr_tool_calling_agent.py`)
92- - Hybrid approach: SGR + Function Calling
93- - Uses ReasoningTool for explicit reasoning
94- - Uses Function Calling for tool selection
95- - Best balance for most tasks
147+ - Hybrid approach: SGR reasoning + Function Calling for tools
148+ - `_reasoning_phase()` uses Function Calling to get `ReasoningTool` result
149+ - Executes `ReasoningTool` to get structured reasoning output
150+ - `_select_action_phase()` uses Function Calling with `tool_choice="required"` for tool selection
151+ - Handles edge case: if LLM returns text instead of tool call, creates `FinalAnswerTool`
152+ - Best balance for most tasks - combines structured reasoning with flexible tool selection
96153
97154## Tools
98155
156+ ### NextStepToolsBuilder (`sgr_agent_core/next_step_tool.py`)
157+ - Builder for creating dynamic union tool types
158+ - `build_NextStepTools()`: Creates `NextStepToolStub` subclass with union of available tools
159+ - Uses discriminated union pattern with `tool_name_discriminator` field
160+ - Enables structured output with dynamic tool selection
161+ - Used by `SGRAgent` for tool selection
162+
163+ ### NextStepToolStub (`sgr_agent_core/next_step_tool.py`)
164+ - Stub class for `NextStepTools` created by `NextStepToolsBuilder`
165+ - Inherits from `ReasoningTool` and contains `function` field with union of tools
166+ - Used in structured output to select tool for next step
167+
99168### ReasoningTool (`sgr_agent_core/tools/reasoning_tool.py`)
100169- Provides structured reasoning output
101170- Contains: reasoning_steps, current_situation, plan_status, enough_data, remaining_steps, task_completed
171+ - Base class for `NextStepToolStub`
102172
103173### ClarificationTool (`sgr_agent_core/tools/clarification_tool.py`)
104174- Requests clarification from user
@@ -137,21 +207,41 @@ alwaysApply: true
137207
138208## Server and API
139209
210+ ### Server Settings (`sgr_agent_core/server/settings.py`)
211+ - Server configuration (host, port, etc.)
212+ - Used by FastAPI application
213+
214+ ### Server Models (`sgr_agent_core/server/models.py`)
215+ - Pydantic models for API requests/responses
216+ - `ChatCompletionRequest`: OpenAI-compatible request model
217+ - `MessagesList`: Root model for message lists with base64 truncation
218+ - `AgentStateResponse`: Agent state response model
219+ - `ClarificationRequest`: Clarification request model
220+ - `HealthResponse`: Health check response
221+
140222### FastAPI Application (`sgr_agent_core/server/app.py`)
141223- Main FastAPI application
142- - Configures CORS, middleware
143- - Registers endpoints
224+ - Configures CORS, middleware, logging
225+ - Registers API router from `endpoints.py`
226+ - Uses `server/settings.py` for configuration
144227
145228### API Endpoints (`sgr_agent_core/server/endpoints.py`)
146- - `/v1/chat/completions` - OpenAI-compatible chat endpoint
147- - `/v1/agents/{agent_id}/state` - Get agent state
148- - `/v1/agents/{agent_id}/clarification` - Provide clarification
149- - `/v1/agents` - List available agents
229+ - `/v1/chat/completions` - OpenAI-compatible chat endpoint (streaming only)
230+ - Creates agent from `AgentDefinition` by model name
231+ - Supports clarification requests via agent ID in model field
232+ - Returns streaming response via `OpenAIStreamingGenerator`
233+ - `/v1/models` - List available agent definitions (OpenAI-compatible)
234+ - `/agents/{agent_id}/state` - Get agent state (GET)
235+ - `/agents/{agent_id}/provide_clarification` - Provide clarification (POST)
236+ - `/agents` - List all active agents (GET)
237+ - `/health` - Health check endpoint
150238
151239### Streaming (`sgr_agent_core/stream.py`)
152- - OpenAIStreamingGenerator for streaming responses
153- - Formats events in OpenAI-compatible format
240+ - ` OpenAIStreamingGenerator` for streaming responses
241+ - Formats events in OpenAI-compatible Server-Sent Events (SSE) format
154242- Handles tool calls and content chunks
243+ - Provides async iterator via `stream()` method
244+ - Methods: `add_chunk()`, `add_tool_call()`, `add_chunk_from_str()`, `finish()`
155245
156246## General Rules for All Modules
157247
0 commit comments