Compare commits
2 Commits
6ffb769b95
...
95cac39fcf
| Author | SHA1 | Date | |
|---|---|---|---|
| 95cac39fcf | |||
| 310ee4a266 |
@@ -17,6 +17,8 @@ Copy `config.example.json` to `config.json` and fill in credentials, or use envi
|
||||
|
||||
Key env vars: `TG_API_ID`, `TG_API_HASH`, `SESSION_DIR`, `ACCOUNTS_JSON` (JSON list) or `ACCOUNT_SESSIONS` (comma-separated session names), `AI_CONFIG` (full AI block as JSON), `BOT_CONFIG` (path to config file), `BOT_DOTENV_PATH` (path to .env).
|
||||
|
||||
`ai.image_understand.command` defaults to `["uvx", "minimax-coding-plan-mcp", "-y"]`. If `uvx` is not on PATH but `uv` is available via Python, use `["python3", "-m", "uv", "tool", "run", "minimax-coding-plan-mcp", "-y"]` instead.
|
||||
|
||||
## Architecture
|
||||
|
||||
### Boot path
|
||||
|
||||
@@ -332,9 +332,33 @@ class AIService:
|
||||
def _get_allowed_roots(self) -> tuple[Path, ...]:
|
||||
return (self.config.workspace_dir, self.config.prompt.root)
|
||||
|
||||
async def _execute_send_file(
|
||||
self,
|
||||
arguments: dict,
|
||||
ctx: "CommandContext",
|
||||
allowed_roots: tuple[Path, ...],
|
||||
) -> str:
|
||||
from app.ai.tools import _resolve_sandboxed_path
|
||||
raw_path = str(arguments.get("path", "")).strip()
|
||||
caption = arguments.get("caption") or None
|
||||
if not raw_path:
|
||||
raise ValueError("send_file: 'path' is required")
|
||||
path = _resolve_sandboxed_path(raw_path, allowed_roots)
|
||||
if not path.exists():
|
||||
raise ValueError(f"send_file: file not found: {raw_path!r}")
|
||||
if not path.is_file():
|
||||
raise ValueError(f"send_file: not a file: {raw_path!r}")
|
||||
await ctx.client.send_document(
|
||||
ctx.message.chat.id,
|
||||
document=str(path),
|
||||
caption=caption,
|
||||
)
|
||||
return f"Sent {raw_path} to chat"
|
||||
|
||||
async def _execute_tool_call(
|
||||
self,
|
||||
tool_call: Any,
|
||||
ctx: "CommandContext",
|
||||
mcp_client: MinimaxImageUnderstandClient | None,
|
||||
mcp_names: set[str],
|
||||
allowed_roots: tuple[Path, ...],
|
||||
@@ -349,7 +373,9 @@ class AIService:
|
||||
return f"Tool {name!r}: invalid JSON arguments: {exc}"
|
||||
|
||||
try:
|
||||
if name in FILE_TOOL_DISPATCH:
|
||||
if name == "send_file":
|
||||
result = await self._execute_send_file(arguments, ctx, allowed_roots)
|
||||
elif name in FILE_TOOL_DISPATCH:
|
||||
result = await FILE_TOOL_DISPATCH[name](arguments, allowed_roots)
|
||||
elif name in mcp_names and mcp_client is not None:
|
||||
result = await mcp_client.call_tool(name, arguments)
|
||||
@@ -463,7 +489,7 @@ class AIService:
|
||||
tc_name = getattr(getattr(tc, "function", None), "name", "?")
|
||||
await self._maybe_call_progress(progress, f"🛠 Calling tool: {tc_name}")
|
||||
result_text = await self._execute_tool_call(
|
||||
tc, mcp_client, mcp_names, allowed_roots, progress
|
||||
tc, ctx, mcp_client, mcp_names, allowed_roots, progress
|
||||
)
|
||||
messages.append({
|
||||
"role": "tool",
|
||||
|
||||
@@ -196,6 +196,24 @@ FILE_TOOL_DISPATCH: dict[str, ToolExecutor] = {
|
||||
}
|
||||
|
||||
FILE_TOOL_SCHEMAS: list[dict[str, Any]] = [
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
"name": "send_file",
|
||||
"description": (
|
||||
"Send a file from workspace/ or prompts/ to the current Telegram chat as a document. "
|
||||
"Use this when the user asks to receive, download, or share a file."
|
||||
),
|
||||
"parameters": {
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"path": {"type": "string", "description": "Relative file path"},
|
||||
"caption": {"type": "string", "description": "Optional caption for the file"},
|
||||
},
|
||||
"required": ["path"],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
"type": "function",
|
||||
"function": {
|
||||
|
||||
Reference in New Issue
Block a user