feat: initialize Anti-Gravity autonomous agent project with markdown knowledge base
This commit is contained in:
commit
5018d0da79
15 changed files with 547 additions and 0 deletions
12
.gitignore
vendored
Normal file
12
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
__pycache__/
|
||||
*.pyc
|
||||
*.pyo
|
||||
*.pyd
|
||||
.pytest_cache/
|
||||
.env
|
||||
venv/
|
||||
.venv/
|
||||
dist/
|
||||
build/
|
||||
*.egg-info/
|
||||
.DS_Store
|
||||
36
AGENTS.md
Normal file
36
AGENTS.md
Normal file
|
|
@ -0,0 +1,36 @@
|
|||
# Anti-Gravity Autonomous Development Agent - System Instructions
|
||||
|
||||
You are **Anti-Gravity**, an autonomous AI development agent designed to execute full-stack development, debugging, testing, and deployment tasks for the entire Tradhox ecosystem.
|
||||
|
||||
## Environment & Managed Workspace
|
||||
- **Agent Location**: `d:/Tradhox_workspace/Agents`
|
||||
- **Frontend App**: `d:/Tradhox_workspace/supplier_central_frontend` (React 19, TypeScript, Vite, TailwindCSS v4, Bulma CSS) -> AWS S3 / CloudFront
|
||||
- **Backend Core**: `d:/Tradhox_workspace/seller_central_backend` (Python 3.14, Django 6.1, DRF, Gunicorn, PostgreSQL/SQLite) -> AWS EC2 (`seller-central-backend.service`)
|
||||
- **Logistics & Shipping Service**: `d:/Tradhox_workspace/shippingservice` (Django microservice for EKart & SFX integrations, Webhooks, AWB Label rendering) -> Daemon (`shippingservice-beta.service`)
|
||||
|
||||
## Core Guidelines & Execution Standards
|
||||
|
||||
### 1. Code Quality & Architecture
|
||||
- Maintain strict type safety in TypeScript (`.ts`/`.tsx`) and clean Python signatures (`mypy`/type hints).
|
||||
- Follow RESTful standards across Django REST Framework endpoints.
|
||||
- Keep carrier API integrations decoupled in `shippingservice` (`sfx_client.py`, `ekart/client.py`).
|
||||
- Do not swallow errors or use dummy fallback values silently; always trace exceptions to their root cause.
|
||||
|
||||
### 2. Verification Rules
|
||||
- **Frontend Verification**: Run `npm run build` and `tsc --noEmit` to verify zero build or type errors.
|
||||
- **Backend & Shipping Service Verification**: Run `python manage.py test` or `pytest` to ensure all tests pass cleanly.
|
||||
|
||||
### 3. Ecosystem Architecture Map
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
User([Supplier UI]) --> S3[AWS S3 / CloudFront]
|
||||
S3 --> Frontend[supplier_central_frontend\nReact 19 + TS + Vite]
|
||||
Frontend -- REST / JWT --> Backend[seller_central_backend\nDjango 6.1 DRF]
|
||||
Backend -- Logistics API --> ShippingService[shippingservice\nDjango + EKart + SFX Client]
|
||||
ShippingService --> Carriers[EKart / SFX Carriers]
|
||||
```
|
||||
|
||||
### 4. Tool Usage Policy
|
||||
- Ask for user confirmation before running destructive shell commands or deleting files.
|
||||
- Log execution steps cleanly in terminal output using `rich`.
|
||||
113
KNOWLEDGE.md
Normal file
113
KNOWLEDGE.md
Normal file
|
|
@ -0,0 +1,113 @@
|
|||
# Tradhox Ecosystem - Comprehensive Technical Knowledge Base
|
||||
|
||||
This document contains full technical specifications, data models, API endpoints, microservices, and deployment configurations for the Tradhox Platform.
|
||||
|
||||
---
|
||||
|
||||
## 🏛️ Ecosystem Overview
|
||||
|
||||
```mermaid
|
||||
graph TD
|
||||
UI([Supplier Browser]) --> S3[AWS S3 / CloudFront\n(supplier_central_frontend)]
|
||||
S3 --> ReactApp[React 19 + TypeScript + Vite]
|
||||
ReactApp -- REST / JWT --> EC2[AWS EC2 Server\n(seller_central_backend)]
|
||||
EC2 --> Backend[Django 6.1 DRF Core]
|
||||
Backend -- Logistics API --> ShippingService[shippingservice\nDjango Microservice]
|
||||
ShippingService --> EKart[EKart Carrier Client]
|
||||
ShippingService --> SFX[SFX Carrier Client]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## 1. 🖥️ Frontend: `supplier_central_frontend`
|
||||
|
||||
- **Directory**: `d:/Tradhox_workspace/supplier_central_frontend`
|
||||
- **Tech Stack**: React 19, TypeScript, Vite, TailwindCSS v4, Bulma CSS, Lucide React, FontAwesome.
|
||||
- **Hosting**: AWS S3 Static Hosting / CloudFront CDN.
|
||||
|
||||
### Key Pages & Routing
|
||||
- **Public Routes**:
|
||||
- `LandingPage.tsx` - Homepage & feature highlights.
|
||||
- `HowItWorksPage.tsx` - Supplier workflow guide.
|
||||
- `PricingPage.tsx` - Pricing tiers & fee structure.
|
||||
- `OnboardingPage.tsx` - Supplier registration & KYC verification wizard.
|
||||
- `LoginPage.tsx` & `ResetPasswordPage.tsx` - Auth flows.
|
||||
- **Dashboard Routes**:
|
||||
- `OverviewPage.tsx` - Real-time metrics & business analytics.
|
||||
- `AddProductPage.tsx` - Single product catalog ingestion.
|
||||
- `BulkUploadPage.tsx` - Batch CSV product import with validation.
|
||||
- `InventoryPage.tsx` - Stock levels & price adjustments.
|
||||
- `OrdersPage.tsx` & Order Views - Order acceptance, rescheduling, damage reporting.
|
||||
- `PayoutsPage.tsx` - Wallet balance & withdrawal requests.
|
||||
- `ReturnsTrackerPage.tsx` - Reverse shipment tracking & Quality Check (QC).
|
||||
- `ShippingLabelsPage.tsx` & `LabelPreviewPage.tsx` - Thermal AWB label preview & batch printing.
|
||||
- `StorefrontPage.tsx` & `SettingsPage.tsx` - Seller brand settings.
|
||||
|
||||
### API Client Layer (`src/services/api.ts`)
|
||||
- Configured with `BASE_URL` pointing to EC2 backend.
|
||||
- Manages JWT Bearer token authentication via `getAuthHeaders()`.
|
||||
|
||||
---
|
||||
|
||||
## 2. ⚙️ Backend Core: `seller_central_backend`
|
||||
|
||||
- **Directory**: `d:/Tradhox_workspace/seller_central_backend`
|
||||
- **Tech Stack**: Python 3.14, Django 6.1, DRF, SimpleJWT, Gunicorn, PostgreSQL/SQLite, Boto3.
|
||||
- **Daemon**: `seller-central-backend.service` on AWS EC2.
|
||||
|
||||
### Core Endpoints & Functionality
|
||||
- **Auth & KYC**:
|
||||
- `POST /api/auth/register/` & `POST /api/auth/login/`
|
||||
- `POST /api/auth/send-whatsapp/` & `POST /api/auth/send-email-otp/`
|
||||
- `POST /api/profile/kyc/verify-pan/` & `POST /api/profile/kyc/upload-eaadhaar/`
|
||||
- `POST /api/profile/submit-gstin/`
|
||||
- **Catalog Management**:
|
||||
- `GET/POST /api/products/` (DRF `ProductViewSet`)
|
||||
- `POST /api/products/bulk-upload/` (CSV parsing & product seeding)
|
||||
- `POST /api/profile/presigned-url/` (AWS S3 image upload signatures)
|
||||
- **Order Lifecycle**:
|
||||
- `GET /api/orders/`
|
||||
- `POST /api/orders/:id/accept/` & `POST /api/orders/:id/reject/`
|
||||
- `POST /api/orders/:id/create_pickup/`
|
||||
- `GET /api/orders/:id/track/`
|
||||
- `GET /api/orders/:id/print_label/`
|
||||
- **Wallet**:
|
||||
- `GET /api/wallet/` & `POST /api/wallet/withdraw/`
|
||||
|
||||
---
|
||||
|
||||
## 3. 🚚 Shipping & Logistics Microservice: `shippingservice`
|
||||
|
||||
- **Directory**: `d:/Tradhox_workspace/shippingservice`
|
||||
- **Tech Stack**: Django 5.x, Gunicorn, Requests, WhiteNoise.
|
||||
- **Daemon**: `shippingservice-beta.service` on EC2.
|
||||
|
||||
### Carrier Integrations
|
||||
- **EKart Integration (`ekart/`)**:
|
||||
- `ekart/client.py`: API wrapper for EKart parcel booking, tracking, and cancellation.
|
||||
- `ekart/views.py`: Dashboard & status views.
|
||||
- **SFX Integration (`shipping/`)**:
|
||||
- `shipping/sfx_client.py`: API client for SFX forward & reverse logistics.
|
||||
- `shipping/views.py`: Forward pickup creation, reverse return pickup, Quality Check (QC) updates.
|
||||
- Webhooks handling (`templates/shipping/webhooks.html`).
|
||||
- Print Label template rendering (`templates/shipping/print_label.html`).
|
||||
|
||||
---
|
||||
|
||||
## 🛠️ Verification & Build Commands
|
||||
|
||||
### Frontend Verification
|
||||
```powershell
|
||||
cd d:/Tradhox_workspace/supplier_central_frontend
|
||||
npm run build
|
||||
npm run lint
|
||||
```
|
||||
|
||||
### Backend & Shipping Service Verification
|
||||
```powershell
|
||||
cd d:/Tradhox_workspace/seller_central_backend
|
||||
python manage.py test
|
||||
|
||||
cd d:/Tradhox_workspace/shippingservice
|
||||
python manage.py test
|
||||
```
|
||||
5
antigravity/__init__.py
Normal file
5
antigravity/__init__.py
Normal file
|
|
@ -0,0 +1,5 @@
|
|||
"""
|
||||
Anti-Gravity Autonomous Development Agent
|
||||
"""
|
||||
|
||||
__version__ = "0.1.0"
|
||||
19
antigravity/config.py
Normal file
19
antigravity/config.py
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
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()
|
||||
61
antigravity/core/agent.py
Normal file
61
antigravity/core/agent.py
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
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
|
||||
51
antigravity/core/md_loader.py
Normal file
51
antigravity/core/md_loader.py
Normal file
|
|
@ -0,0 +1,51 @@
|
|||
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)
|
||||
54
antigravity/llm/client.py
Normal file
54
antigravity/llm/client.py
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
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."
|
||||
31
antigravity/main.py
Normal file
31
antigravity/main.py
Normal file
|
|
@ -0,0 +1,31 @@
|
|||
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()
|
||||
16
antigravity/tools/base.py
Normal file
16
antigravity/tools/base.py
Normal file
|
|
@ -0,0 +1,16 @@
|
|||
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
|
||||
45
antigravity/tools/filesystem.py
Normal file
45
antigravity/tools/filesystem.py
Normal file
|
|
@ -0,0 +1,45 @@
|
|||
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))
|
||||
30
antigravity/tools/shell.py
Normal file
30
antigravity/tools/shell.py
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
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))
|
||||
21
pyproject.toml
Normal file
21
pyproject.toml
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
[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"
|
||||
10
requirements.txt
Normal file
10
requirements.txt
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
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
|
||||
43
tests/test_agent.py
Normal file
43
tests/test_agent.py
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
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