feat: backend orkestrasyonunu ve arac entegrasyonlarini genislet

This commit is contained in:
2026-03-22 04:45:43 +03:00
parent d07bc365f5
commit 5f4c19a18d
25 changed files with 3750 additions and 82 deletions

View File

@@ -6,16 +6,100 @@ from app.tools.base import Tool
class FilesTool(Tool):
name = "files"
description = "Read and write files within allowed paths."
description = "Read, list, and write files within the workspace."
def __init__(self, workspace_root: Path) -> None:
self.workspace_root = workspace_root.resolve()
def parameters_schema(self) -> dict[str, Any]:
return {
"type": "object",
"properties": {
"action": {
"type": "string",
"enum": ["read", "list", "write"],
"description": "Use read to read a file, list to list a directory, or write to create/update a file.",
},
"path": {
"type": "string",
"description": "Absolute or relative path inside the workspace.",
},
"content": {
"type": "string",
"description": "File content for write operations.",
},
},
"required": ["action", "path"],
"additionalProperties": False,
}
async def run(self, payload: dict[str, Any]) -> dict[str, Any]:
action = str(payload.get("action", "read")).strip()
path = Path(str(payload.get("path", "")).strip()).expanduser()
raw_path = str(payload.get("path", "")).strip()
path = self._resolve_path(raw_path)
if action == "read":
if not path.exists():
return {"tool": self.name, "status": "error", "message": f"Path not found: {path}"}
if path.is_dir():
return {"tool": self.name, "status": "error", "message": f"Path is a directory: {path}"}
content = path.read_text(encoding="utf-8", errors="replace")
return {
"tool": self.name,
"status": "ok",
"action": action,
"path": str(path),
"content": content[:12000],
"truncated": len(content) > 12000,
}
if action == "list":
if not path.exists():
return {"tool": self.name, "status": "error", "message": f"Path not found: {path}"}
if not path.is_dir():
return {"tool": self.name, "status": "error", "message": f"Path is not a directory: {path}"}
entries = []
for child in sorted(path.iterdir(), key=lambda item: item.name.lower())[:200]:
entries.append(
{
"name": child.name,
"type": "dir" if child.is_dir() else "file",
}
)
return {
"tool": self.name,
"status": "ok",
"action": action,
"path": str(path),
"entries": entries,
"truncated": len(entries) >= 200,
}
if action == "write":
content = str(payload.get("content", ""))
path.parent.mkdir(parents=True, exist_ok=True)
path.write_text(content, encoding="utf-8")
return {
"tool": self.name,
"status": "ok",
"action": action,
"path": str(path),
"bytes_written": len(content.encode("utf-8")),
}
return {
"tool": self.name,
"status": "stub",
"action": action,
"path": str(path),
"message": "File integration is not wired yet.",
"status": "error",
"message": f"Unsupported action: {action}. Allowed actions are read, list, and write.",
}
def _resolve_path(self, raw_path: str) -> Path:
candidate = Path(raw_path).expanduser()
if not candidate.is_absolute():
candidate = (self.workspace_root / candidate).resolve()
else:
candidate = candidate.resolve()
if self.workspace_root not in candidate.parents and candidate != self.workspace_root:
raise ValueError(f"Path is outside the workspace: {candidate}")
return candidate