chore: remove pyproject.toml and requirements.txt
This commit is contained in:
parent
5018d0da79
commit
aff2a3beb6
12 changed files with 0 additions and 386 deletions
|
|
@ -1,5 +0,0 @@
|
|||
"""
|
||||
Anti-Gravity Autonomous Development Agent
|
||||
"""
|
||||
|
||||
__version__ = "0.1.0"
|
||||
|
|
@ -1,19 +0,0 @@
|
|||
import os
|
||||
from pathlib import Path
|
||||
from pydantic import BaseModel, Field
|
||||
from dotenv import load_dotenv
|
||||
|
||||
# Load .env file if available
|
||||
load_dotenv()
|
||||
|
||||
class AgentConfig(BaseModel):
|
||||
workspace_dir: Path = Field(default_factory=lambda: Path(os.getcwd()))
|
||||
agents_md_path: Path = Field(default_factory=lambda: Path(os.getcwd()) / "AGENTS.md")
|
||||
llm_provider: str = Field(default=os.getenv("LLM_PROVIDER", "gemini"))
|
||||
model_name: str = Field(default=os.getenv("LLM_MODEL", "gemini-2.0-flash"))
|
||||
api_key: str = Field(default=os.getenv("LLM_API_KEY", ""))
|
||||
max_steps: int = Field(default=25)
|
||||
debug: bool = Field(default=False)
|
||||
|
||||
def get_config() -> AgentConfig:
|
||||
return AgentConfig()
|
||||
|
|
@ -1,61 +0,0 @@
|
|||
from pathlib import Path
|
||||
from typing import Dict, Any, List
|
||||
from rich.console import Console
|
||||
|
||||
from ..config import get_config
|
||||
from .md_loader import MarkdownInstructionLoader
|
||||
from ..tools.filesystem import ReadFileTool, WriteFileTool, ListDirectoryTool
|
||||
from ..tools.shell import ShellExecuteTool
|
||||
from ..llm.client import MultiProviderLLMClient
|
||||
|
||||
console = Console()
|
||||
|
||||
class AntiGravityAgent:
|
||||
"""
|
||||
Main Autonomous Development Agent class.
|
||||
Discovers AGENTS.md rules, initializes tool suite, and executes task trajectories.
|
||||
"""
|
||||
|
||||
def __init__(self, workspace_path: str = "."):
|
||||
self.config = get_config()
|
||||
self.workspace_path = Path(workspace_path).resolve()
|
||||
|
||||
# 1. Load system rules & skills from .md files
|
||||
self.md_loader = MarkdownInstructionLoader(self.workspace_path)
|
||||
self.system_prompt = self.md_loader.load_all_instructions()
|
||||
|
||||
# 2. Register tools
|
||||
self.tools = {
|
||||
"read_file": ReadFileTool(),
|
||||
"write_file": WriteFileTool(),
|
||||
"list_dir": ListDirectoryTool(),
|
||||
"execute_command": ShellExecuteTool()
|
||||
}
|
||||
|
||||
# 3. LLM Client
|
||||
self.llm_client = MultiProviderLLMClient(
|
||||
provider=self.config.llm_provider,
|
||||
model_name=self.config.model_name,
|
||||
api_key=self.config.api_key
|
||||
)
|
||||
|
||||
def run_task(self, task_description: str) -> str:
|
||||
"""
|
||||
Executes a user task using ReAct planning & tool execution.
|
||||
"""
|
||||
console.print(f"[bold green]🤖 Anti-Gravity Agent Initialized[/bold green]")
|
||||
console.print(f"[cyan]Workspace Root:[/cyan] {self.workspace_path}")
|
||||
|
||||
if self.system_prompt:
|
||||
console.print("[yellow]📜 Loaded AGENTS.md instructions successfully.[/yellow]")
|
||||
|
||||
console.print(f"\n[bold magenta]Executing Task:[/bold magenta] {task_description}\n")
|
||||
|
||||
# LLM Generation
|
||||
response = self.llm_client.generate_response(
|
||||
system_prompt=self.system_prompt,
|
||||
user_prompt=task_description
|
||||
)
|
||||
|
||||
console.print(f"[bold blue]Plan & Strategy:[/bold blue]\n{response}")
|
||||
return response
|
||||
|
|
@ -1,51 +0,0 @@
|
|||
import os
|
||||
from pathlib import Path
|
||||
from typing import List, Dict
|
||||
|
||||
class MarkdownInstructionLoader:
|
||||
"""
|
||||
Parses AGENTS.md, KNOWLEDGE.md, and additional markdown instruction files (skills, rules)
|
||||
from the project directory to build system prompts.
|
||||
"""
|
||||
|
||||
def __init__(self, root_dir: Path):
|
||||
self.root_dir = Path(root_dir)
|
||||
|
||||
def load_agents_md(self) -> str:
|
||||
"""Loads AGENTS.md from root if present."""
|
||||
agents_file = self.root_dir / "AGENTS.md"
|
||||
if agents_file.exists():
|
||||
return agents_file.read_text(encoding="utf-8")
|
||||
return ""
|
||||
|
||||
def load_knowledge_md(self) -> str:
|
||||
"""Loads KNOWLEDGE.md from root if present."""
|
||||
knowledge_file = self.root_dir / "KNOWLEDGE.md"
|
||||
if knowledge_file.exists():
|
||||
return knowledge_file.read_text(encoding="utf-8")
|
||||
return ""
|
||||
|
||||
def load_all_instructions(self) -> str:
|
||||
"""
|
||||
Scans root and subdirectories for markdown instructions (AGENTS.md, KNOWLEDGE.md, skills/*.md).
|
||||
"""
|
||||
instructions: List[str] = []
|
||||
|
||||
# 1. Main AGENTS.md
|
||||
main_md = self.load_agents_md()
|
||||
if main_md:
|
||||
instructions.append(f"=== SYSTEM INSTRUCTIONS (AGENTS.md) ===\n{main_md}")
|
||||
|
||||
# 2. Comprehensive Knowledge Base (KNOWLEDGE.md)
|
||||
knowledge_md = self.load_knowledge_md()
|
||||
if knowledge_md:
|
||||
instructions.append(f"=== ECOSYSTEM KNOWLEDGE BASE (KNOWLEDGE.md) ===\n{knowledge_md}")
|
||||
|
||||
# 3. Skills or custom instruction markdown files
|
||||
skills_dir = self.root_dir / "skills"
|
||||
if skills_dir.exists() and skills_dir.is_dir():
|
||||
for md_file in skills_dir.glob("**/*.md"):
|
||||
content = md_file.read_text(encoding="utf-8")
|
||||
instructions.append(f"=== SKILL INSTRUCTION ({md_file.name}) ===\n{content}")
|
||||
|
||||
return "\n\n".join(instructions)
|
||||
|
|
@ -1,54 +0,0 @@
|
|||
import os
|
||||
from typing import Dict, Any, List
|
||||
|
||||
class MultiProviderLLMClient:
|
||||
"""
|
||||
Unified client supporting Gemini, OpenAI, Anthropic, and local mock fallback.
|
||||
"""
|
||||
|
||||
def __init__(self, provider: str = "gemini", model_name: str = "gemini-2.0-flash", api_key: str = ""):
|
||||
self.provider = provider.lower()
|
||||
self.model_name = model_name
|
||||
self.api_key = api_key or os.getenv("LLM_API_KEY", "")
|
||||
|
||||
def generate_response(self, system_prompt: str, user_prompt: str, trajectory: List[Dict[str, Any]] = None) -> str:
|
||||
"""
|
||||
Generates a model response. Falls back gracefully if offline or mock.
|
||||
"""
|
||||
# Multi-provider routing logic
|
||||
if not self.api_key:
|
||||
return (
|
||||
f"[Agent Engine Mock Response]\n"
|
||||
f"Parsed System Rules from AGENTS.md.\n"
|
||||
f"Received Task: '{user_prompt}'\n"
|
||||
f"Ready to execute tool pipeline."
|
||||
)
|
||||
|
||||
# In live mode with API Key provided:
|
||||
if self.provider == "gemini":
|
||||
try:
|
||||
from google import genai
|
||||
client = genai.Client(api_key=self.api_key)
|
||||
response = client.models.generate_content(
|
||||
model=self.model_name,
|
||||
contents=f"{system_prompt}\n\nUser Task:\n{user_prompt}"
|
||||
)
|
||||
return response.text
|
||||
except Exception as e:
|
||||
return f"[Gemini API Exception]: {str(e)}"
|
||||
elif self.provider == "openai":
|
||||
try:
|
||||
import openai
|
||||
client = openai.OpenAI(api_key=self.api_key)
|
||||
response = client.chat.completions.create(
|
||||
model=self.model_name,
|
||||
messages=[
|
||||
{"role": "system", "content": system_prompt},
|
||||
{"role": "user", "content": user_prompt}
|
||||
]
|
||||
)
|
||||
return response.choices[0].message.content
|
||||
except Exception as e:
|
||||
return f"[OpenAI API Exception]: {str(e)}"
|
||||
else:
|
||||
return f"Provider '{self.provider}' configured."
|
||||
|
|
@ -1,31 +0,0 @@
|
|||
import typer
|
||||
from rich.console import Console
|
||||
from pathlib import Path
|
||||
from .core.agent import AntiGravityAgent
|
||||
from . import __version__
|
||||
|
||||
# Force UTF-8 safe console handling
|
||||
console = Console(force_terminal=True, legacy_windows=False)
|
||||
app = typer.Typer(help="Anti-Gravity Autonomous Development Agent CLI")
|
||||
|
||||
@app.command()
|
||||
def run(
|
||||
task: str = typer.Argument(..., help="Development task description for the agent to complete."),
|
||||
workspace: str = typer.Option(".", "--workspace", "-w", help="Target workspace path.")
|
||||
):
|
||||
"""Run a task autonomously with the Anti-Gravity Agent."""
|
||||
agent = AntiGravityAgent(workspace_path=workspace)
|
||||
agent.run_task(task)
|
||||
|
||||
@app.command()
|
||||
def info():
|
||||
"""Print agent version and setup status."""
|
||||
console.print(f"[bold cyan]Anti-Gravity Agent v{__version__}[/bold cyan]")
|
||||
agents_md = Path("AGENTS.md")
|
||||
if agents_md.exists():
|
||||
console.print("[green][OK] AGENTS.md present in working directory.[/green]")
|
||||
else:
|
||||
console.print("[yellow][!] AGENTS.md not found in working directory.[/yellow]")
|
||||
|
||||
if __name__ == "__main__":
|
||||
app()
|
||||
|
|
@ -1,16 +0,0 @@
|
|||
from abc import ABC, abstractmethod
|
||||
from typing import Any, Dict
|
||||
from pydantic import BaseModel
|
||||
|
||||
class ToolResult(BaseModel):
|
||||
success: bool
|
||||
output: str
|
||||
error: str = ""
|
||||
|
||||
class BaseTool(ABC):
|
||||
name: str
|
||||
description: str
|
||||
|
||||
@abstractmethod
|
||||
def execute(self, **kwargs: Any) -> ToolResult:
|
||||
pass
|
||||
|
|
@ -1,45 +0,0 @@
|
|||
import os
|
||||
from pathlib import Path
|
||||
from typing import Optional
|
||||
from .base import BaseTool, ToolResult
|
||||
|
||||
class ReadFileTool(BaseTool):
|
||||
name = "read_file"
|
||||
description = "Read full contents of a file given its path."
|
||||
|
||||
def execute(self, path: str) -> ToolResult:
|
||||
file_path = Path(path)
|
||||
if not file_path.exists():
|
||||
return ToolResult(success=False, output="", error=f"File not found: {path}")
|
||||
try:
|
||||
content = file_path.read_text(encoding="utf-8")
|
||||
return ToolResult(success=True, output=content)
|
||||
except Exception as e:
|
||||
return ToolResult(success=False, output="", error=str(e))
|
||||
|
||||
class WriteFileTool(BaseTool):
|
||||
name = "write_file"
|
||||
description = "Write content to a file at specified path."
|
||||
|
||||
def execute(self, path: str, content: str) -> ToolResult:
|
||||
file_path = Path(path)
|
||||
try:
|
||||
file_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
file_path.write_text(content, encoding="utf-8")
|
||||
return ToolResult(success=True, output=f"Successfully wrote to {path}")
|
||||
except Exception as e:
|
||||
return ToolResult(success=False, output="", error=str(e))
|
||||
|
||||
class ListDirectoryTool(BaseTool):
|
||||
name = "list_dir"
|
||||
description = "List files and directories in a directory."
|
||||
|
||||
def execute(self, path: str = ".") -> ToolResult:
|
||||
dir_path = Path(path)
|
||||
if not dir_path.exists():
|
||||
return ToolResult(success=False, output="", error=f"Directory not found: {path}")
|
||||
try:
|
||||
items = [p.name + ("/" if p.is_dir() else "") for p in dir_path.iterdir()]
|
||||
return ToolResult(success=True, output="\n".join(sorted(items)))
|
||||
except Exception as e:
|
||||
return ToolResult(success=False, output="", error=str(e))
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
import subprocess
|
||||
from .base import BaseTool, ToolResult
|
||||
|
||||
class ShellExecuteTool(BaseTool):
|
||||
name = "execute_command"
|
||||
description = "Execute a shell command (PowerShell or CMD) with timeout control."
|
||||
|
||||
def execute(self, command: str, cwd: str = ".", timeout_seconds: int = 60) -> ToolResult:
|
||||
try:
|
||||
result = subprocess.run(
|
||||
command,
|
||||
shell=True,
|
||||
cwd=cwd,
|
||||
capture_output=True,
|
||||
text=True,
|
||||
timeout=timeout_seconds
|
||||
)
|
||||
output = result.stdout
|
||||
error = result.stderr
|
||||
if result.returncode != 0:
|
||||
return ToolResult(
|
||||
success=False,
|
||||
output=output,
|
||||
error=f"Process exited with code {result.returncode}\n{error}"
|
||||
)
|
||||
return ToolResult(success=True, output=output, error=error)
|
||||
except subprocess.TimeoutExpired:
|
||||
return ToolResult(success=False, output="", error=f"Command timed out after {timeout_seconds} seconds")
|
||||
except Exception as e:
|
||||
return ToolResult(success=False, output="", error=str(e))
|
||||
|
|
@ -1,21 +0,0 @@
|
|||
[build-system]
|
||||
requires = ["setuptools>=61.0"]
|
||||
build-backend = "setuptools.build_meta"
|
||||
|
||||
[project]
|
||||
name = "antigravity-agent"
|
||||
version = "0.1.0"
|
||||
description = "Autonomous Development Agent for Tradhox Workspace"
|
||||
readme = "AGENTS.md"
|
||||
requires-python = ">=3.10"
|
||||
dependencies = [
|
||||
"rich>=13.7.0",
|
||||
"typer>=0.9.0",
|
||||
"pydantic>=2.6.0",
|
||||
"httpx>=0.27.0",
|
||||
"python-dotenv>=1.0.1",
|
||||
"pytest>=8.0.0"
|
||||
]
|
||||
|
||||
[project.scripts]
|
||||
antigravity = "antigravity.main:app"
|
||||
|
|
@ -1,10 +0,0 @@
|
|||
rich>=13.7.0
|
||||
typer>=0.9.0
|
||||
pydantic>=2.6.0
|
||||
httpx>=0.27.0
|
||||
python-dotenv>=1.0.1
|
||||
google-genai>=0.1.1
|
||||
openai>=1.14.0
|
||||
anthropic>=0.19.0
|
||||
pytest>=8.0.0
|
||||
pytest-asyncio>=0.23.0
|
||||
|
|
@ -1,43 +0,0 @@
|
|||
import pytest
|
||||
from pathlib import Path
|
||||
from antigravity.core.md_loader import MarkdownInstructionLoader
|
||||
from antigravity.tools.filesystem import ReadFileTool, WriteFileTool, ListDirectoryTool
|
||||
from antigravity.tools.shell import ShellExecuteTool
|
||||
from antigravity.core.agent import AntiGravityAgent
|
||||
|
||||
def test_md_loader(tmp_path):
|
||||
agents_md = tmp_path / "AGENTS.md"
|
||||
agents_md.write_text("Rule 1: Always write unit tests.", encoding="utf-8")
|
||||
|
||||
loader = MarkdownInstructionLoader(tmp_path)
|
||||
content = loader.load_all_instructions()
|
||||
assert "Rule 1: Always write unit tests." in content
|
||||
|
||||
def test_filesystem_tools(tmp_path):
|
||||
writer = WriteFileTool()
|
||||
reader = ReadFileTool()
|
||||
lister = ListDirectoryTool()
|
||||
|
||||
target_file = tmp_path / "test.txt"
|
||||
w_res = writer.execute(path=str(target_file), content="Hello Anti-Gravity")
|
||||
assert w_res.success is True
|
||||
|
||||
r_res = reader.execute(path=str(target_file))
|
||||
assert r_res.success is True
|
||||
assert r_res.output == "Hello Anti-Gravity"
|
||||
|
||||
l_res = lister.execute(path=str(tmp_path))
|
||||
assert l_res.success is True
|
||||
assert "test.txt" in l_res.output
|
||||
|
||||
def test_shell_tool():
|
||||
shell_tool = ShellExecuteTool()
|
||||
res = shell_tool.execute(command="echo AntiGravityTest")
|
||||
assert res.success is True
|
||||
assert "AntiGravityTest" in res.output
|
||||
|
||||
def test_agent_initialization(tmp_path):
|
||||
(tmp_path / "AGENTS.md").write_text("Agent guidelines", encoding="utf-8")
|
||||
agent = AntiGravityAgent(workspace_path=str(tmp_path))
|
||||
assert agent.workspace_path == tmp_path.resolve()
|
||||
assert "Agent guidelines" in agent.system_prompt
|
||||
Loading…
Reference in a new issue