Add OpenAI tool-calling agentic loop with file tools and MiniMax MCP integration
- AIService.generate() now runs an agentic loop: sends tools to the API, handles tool_calls responses, executes tools, appends results, and repeats until a text response (up to tool_max_rounds, default 10) - New app/ai/tools.py: six sandboxed file tools (write/read/create/modify/delete/list), OpenAI JSON schemas, path sandbox validator, and MCP→OpenAI schema converter - Paths are sandboxed to workspace/ (project root) and prompts/ai/; traversal blocked - MinimaxImageUnderstandClient gains list_tools() and call_tool() methods; MCP tool schemas are lazily fetched once per session and forwarded to the AI as callable tools - AIConfig gains workspace_dir (Path, default workspace/) and tool_max_rounds (int, default 10) - MCP client opened lazily only when an MCP tool is actually called during a loop Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -71,6 +71,8 @@ class AIConfig:
|
||||
image_understand: AIImageUnderstandConfig | None = None
|
||||
providers: dict[str, AIProviderConfig] = field(default_factory=dict)
|
||||
models: dict[str, AIModelConfig] = field(default_factory=dict)
|
||||
workspace_dir: Path = field(default_factory=lambda: Path("workspace"))
|
||||
tool_max_rounds: int = 10
|
||||
|
||||
|
||||
@dataclass(slots=True)
|
||||
@@ -289,6 +291,15 @@ def _parse_ai_config(raw_ai: Any, *, root: Path) -> AIConfig | None:
|
||||
f"ai.models.{alias}.provider references unknown provider: {model_config.provider}"
|
||||
)
|
||||
|
||||
workspace_dir_raw = raw_ai.get("workspace_dir", "workspace")
|
||||
workspace_dir = Path(str(workspace_dir_raw)).expanduser()
|
||||
if not workspace_dir.is_absolute():
|
||||
workspace_dir = (root / workspace_dir).resolve()
|
||||
|
||||
tool_max_rounds = _parse_int(raw_ai.get("tool_max_rounds", 10), field_name="ai.tool_max_rounds")
|
||||
if tool_max_rounds < 1:
|
||||
raise ValueError("ai.tool_max_rounds must be >= 1")
|
||||
|
||||
return AIConfig(
|
||||
default_model=default_model,
|
||||
context_messages=context_messages,
|
||||
@@ -296,6 +307,8 @@ def _parse_ai_config(raw_ai: Any, *, root: Path) -> AIConfig | None:
|
||||
image_understand=image_understand,
|
||||
providers=providers,
|
||||
models=models,
|
||||
workspace_dir=workspace_dir,
|
||||
tool_max_rounds=tool_max_rounds,
|
||||
)
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user