From 02d26b0fde238e5093f77f95e9d59200aea90c84 Mon Sep 17 00:00:00 2001 From: justinmadison Date: Mon, 10 Nov 2025 11:58:54 -0800 Subject: [PATCH 1/3] update backlog and project board --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 8651061..981c3f2 100644 --- a/.gitignore +++ b/.gitignore @@ -71,3 +71,7 @@ tmp/ # Claude Code (keep project-context.md but ignore local settings) .claude/settings.local.json .claude/*.local.* + +# GitHub automation scripts (used for setup, not needed in repo) +scripts/create_github_*.bat +scripts/create_github_*.sh From c3c5a01b8bdf7155b1788c3f89ab5b554c508f36 Mon Sep 17 00:00:00 2001 From: justinmadison Date: Mon, 10 Nov 2025 11:59:22 -0800 Subject: [PATCH 2/3] update backlog and project board --- .claude/project-context.md | 2 +- CONTRIBUTING.md | 79 ++++- QUICK_START_GITHUB_CLI.md | 261 ++++++++++++++ docs/backlog_items.md | 624 ++++++++++++++++++++++++++++++++++ docs/github_cli_guide.md | 593 ++++++++++++++++++++++++++++++++ docs/github_issues.md | 678 +++++++++++++++++++++++++++++++++++++ docs/ipc_protocol.md | 568 +++++++++++++++++++++++++++++++ docs/project_board.md | 448 ++++++++++++++++++++++++ docs/team_onboarding.md | 354 +++++++++++++++++++ scenes/crafting_chain.tscn | 103 ++++++ scenes/foraging.tscn | 119 +++++++ scenes/team_capture.tscn | 94 +++++ 12 files changed, 3919 insertions(+), 4 deletions(-) create mode 100644 QUICK_START_GITHUB_CLI.md create mode 100644 docs/backlog_items.md create mode 100644 docs/github_cli_guide.md create mode 100644 docs/github_issues.md create mode 100644 docs/ipc_protocol.md create mode 100644 docs/project_board.md create mode 100644 docs/team_onboarding.md create mode 100644 scenes/crafting_chain.tscn create mode 100644 scenes/foraging.tscn create mode 100644 scenes/team_capture.tscn diff --git a/.claude/project-context.md b/.claude/project-context.md index e15a0a6..8e7b0af 100644 --- a/.claude/project-context.md +++ b/.claude/project-context.md @@ -61,7 +61,7 @@ c:\Projects\Agent Arena\ - ✅ Test scene created with working controls - ✅ Core classes verified: SimulationManager, Agent, EventBus, ToolRegistry - ✅ IPC system implemented (Godot ↔ Python via HTTP/FastAPI) -- ⏳ Next: Create actual benchmark scenes (foraging, crafting_chain, team_capture) +- ✅ Benchmark scenes created (foraging, crafting_chain, team_capture) - ⏳ Next: Set up Python environment and agent runtime - ⏳ Next: Integrate LLM backends with agent decision-making diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 871faa3..67d3b14 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -34,6 +34,27 @@ Thank you for your interest in contributing to Agent Arena! This project bridges See [docs/quickstart.md](docs/quickstart.md) for initial setup. +### Work Division Strategy + +To minimize merge conflicts and maximize parallel development: + +**C++/Godot Development**: +- `godot/**/*` - C++ GDExtension code +- `scenes/**/*.tscn` - Godot scenes +- `scripts/**/*.gd` - GDScript files +- Scene balancing and visual improvements + +**Python Development**: +- `python/**/*.py` - Agent runtime, backends, tools +- `configs/**/*.yaml` - Configuration files +- `tests/**/*.py` - Python unit tests +- LLM integration and memory systems + +**Shared** (coordinate before modifying): +- `README.md`, `docs/**/*.md` +- `.claude/project-context.md` +- `CONTRIBUTING.md` (this file) + ### Development Workflow 1. **C++ Module Changes:** @@ -57,6 +78,45 @@ See [docs/quickstart.md](docs/quickstart.md) for initial setup. - Keep examples working - Add diagrams if helpful +### Branch Strategy + +Use feature branches with descriptive names: + +```bash +# Create feature branch +git checkout -b feature/llama-cpp-backend + +# Make changes and commit +git commit -m "feat(backend): implement llama.cpp integration" + +# Push and create PR +git push origin feature/llama-cpp-backend +gh pr create --title "Add llama.cpp backend" --body "..." +``` + +**Branch naming**: +- `feature/` - New features +- `fix/` - Bug fixes +- `refactor/` - Code refactoring +- `docs/` - Documentation updates +- `test/` - Test additions + +### Daily Sync Pattern + +**Morning** (async update): +- Post what you're working on today +- Mention any blockers + +**Evening**: +- Push changes to your branch +- Tag teammates on PRs needing review +- Update issue status + +**Weekly**: +- Integration checkpoint +- Demo progress +- Plan next week's work + ## Code Standards ### Python @@ -204,9 +264,22 @@ python python/evals/run_eval.py --scene foraging --trials 1 ## Communication -- **GitHub Issues**: Bug reports, feature requests -- **GitHub Discussions**: Questions, ideas, general discussion -- **Pull Requests**: Code contributions +- **GitHub Issues**: Bug reports, feature requests, task tracking +- **GitHub Discussions**: Questions, ideas, architecture decisions +- **Pull Requests**: Code contributions and reviews +- **Discord/Slack** (if configured): Quick questions, daily standups + +### IPC Protocol Changes + +If you need to modify the Godot ↔ Python communication protocol: + +1. Update [docs/ipc_protocol.md](docs/ipc_protocol.md) +2. Implement changes on both sides (Godot C++ and Python) +3. Add integration tests +4. Notify team (breaking change) +5. Version the protocol if needed + +See [IPC Protocol Documentation](docs/ipc_protocol.md) for message format details. ## Code of Conduct diff --git a/QUICK_START_GITHUB_CLI.md b/QUICK_START_GITHUB_CLI.md new file mode 100644 index 0000000..22d7c6a --- /dev/null +++ b/QUICK_START_GITHUB_CLI.md @@ -0,0 +1,261 @@ +# Quick Start: GitHub CLI for Agent Arena + +Quick reference for using GitHub CLI to manage Agent Arena development. + +## Setup (One Time) + +```bash +# 1. Install GitHub CLI +winget install --id GitHub.cli # Windows + +# 2. Authenticate +gh auth login + +# 3. Navigate to repo +cd "c:\Projects\Agent Arena" +``` + +--- + +## Create Labels & Issues (Automated) + +**IMPORTANT: Run these scripts in order!** + +### Step 1: Create Labels First + +```bash +# Windows +scripts\create_github_labels.bat + +# Linux/Mac +bash scripts/create_github_labels.sh +``` + +This creates all the labels (backend, python, enhancement, etc.) that issues will use. + +### Step 2: Create Issues + +```bash +# Windows +scripts\create_github_issues.bat + +# Linux/Mac +bash scripts/create_github_issues.sh +``` + +This creates ~10 high-priority issues with the labels you just created. + +**Why this order?** Labels must exist before you can assign them to issues! + +--- + +## Manual Issue Creation + +### Create Issue + +```bash +gh issue create \ + --title "Your issue title" \ + --label "python,enhancement" \ + --assignee @me \ + --body "Issue description" +``` + +### Create Issue for Colleague + +```bash +gh issue create \ + --title "Setup Python environment" \ + --label "python,setup,good-first-issue" \ + --assignee colleague-github-username \ + --body "Create venv and requirements.txt" +``` + +--- + +## Project Board Management + +### Create Project Board (Web) + +1. Go to: https://github.com/JustInternetAI/AgentArena +2. Click **Projects** → **New project** +3. Choose **Board** template +4. Name: "Agent Arena Development" +5. Note the project number (shows as `#1`, `#2`, etc.) + +### Add Issue to Project + +```bash +# Replace 1 with your project number, 5 with issue number +gh project item-add 1 \ + --owner JustInternetAI \ + --url https://github.com/JustInternetAI/AgentArena/issues/5 +``` + +**PowerShell (easier)**: +```powershell +# Add issue #5 to project #1 +$url = gh issue view 5 --json url -q .url +gh project item-add 1 --owner JustInternetAI --url $url +``` + +### Add All Open Issues to Project + +**PowerShell**: +```powershell +# Add all open issues to project #1 +gh issue list --state open --json number -q '.[].number' | ForEach-Object { + $url = gh issue view $_ --json url -q .url + gh project item-add 1 --owner JustInternetAI --url $url + Write-Host "Added issue #$_" +} +``` + +**Bash**: +```bash +gh issue list --state open --json number -q '.[].number' | while read num; do + url=$(gh issue view $num --json url -q .url) + gh project item-add 1 --owner JustInternetAI --url $url + echo "Added issue #$num" +done +``` + +--- + +## Daily Workflow + +### View Your Issues + +```bash +# Issues assigned to you +gh issue list --assignee @me + +# All open issues +gh issue list --state open + +# Python-related issues +gh issue list --label "python" +``` + +### Update Issue + +```bash +# Add label +gh issue edit 5 --add-label "in-progress" + +# Assign yourself +gh issue edit 5 --assignee @me + +# Close issue +gh issue close 5 --comment "Completed in PR #10" +``` + +### Create PR + +```bash +# From current branch +gh pr create --title "Add vLLM backend" --body "Implements issue #5" + +# Draft PR +gh pr create --draft --title "WIP: vLLM backend" +``` + +--- + +## Common Commands + +| Action | Command | +|--------|---------| +| List issues | `gh issue list` | +| View issue | `gh issue view 5` | +| Create issue | `gh issue create` | +| Edit issue | `gh issue edit 5` | +| Close issue | `gh issue close 5` | +| List PRs | `gh pr list` | +| Create PR | `gh pr create` | +| View PR | `gh pr view 10` | +| Merge PR | `gh pr merge 10 --squash` | +| Open repo in browser | `gh repo view --web` | +| View project | `gh project list --owner JustInternetAI` | + +--- + +## Week 1 Quick Setup + +```bash +# 1. Create issues for colleague (Python work) +gh issue create --title "Setup Python environment" \ + --label "python,setup,good-first-issue" \ + --assignee colleague-username + +gh issue create --title "Implement BaseBackend class" \ + --label "python,backend,architecture" \ + --assignee colleague-username + +gh issue create --title "Implement FastAPI IPC server" \ + --label "python,ipc,critical" \ + --assignee colleague-username + +# 2. View created issues +gh issue list + +# 3. Create project board (via web) +# Go to: https://github.com/JustInternetAI/AgentArena/projects + +# 4. Add issues to board (PowerShell) +1..3 | ForEach-Object { + $url = gh issue view $_ --json url -q .url + gh project item-add 1 --owner JustInternetAI --url $url +} + +# 5. Done! View the board +gh project view 1 --owner JustInternetAI --web +``` + +--- + +## Tips + +1. **Use `--web` flag** to open items in browser: + ```bash + gh issue view 5 --web + gh pr view 10 --web + gh repo view --web + ``` + +2. **Use interactive mode** (prompts for input): + ```bash + gh issue create # No flags = interactive + gh pr create + ``` + +3. **Get JSON output** for scripting: + ```bash + gh issue list --json number,title,state + ``` + +4. **Reference issues in commits**: + ```bash + git commit -m "feat: add vLLM backend (#5)" + ``` + +5. **Auto-close issues with PRs**: + ```bash + gh pr create --body "Closes #5" + ``` + +--- + +## Next Steps + +✅ Install GitHub CLI +✅ Run `scripts\create_github_issues.bat` +✅ Create project board via web +✅ Add issues to board +✅ Start developing! + +**Full documentation**: See [docs/github_cli_guide.md](docs/github_cli_guide.md) + +**Backlog items**: See [docs/backlog_items.md](docs/backlog_items.md) + +**Issue templates**: See [docs/github_issues.md](docs/github_issues.md) diff --git a/docs/backlog_items.md b/docs/backlog_items.md new file mode 100644 index 0000000..20bc121 --- /dev/null +++ b/docs/backlog_items.md @@ -0,0 +1,624 @@ +# Backlog Items for Agent Arena + +This document contains backlog items organized by priority and category. Use these to populate your GitHub Project Board. + +--- + +## High Priority Backlog + +### Backend & LLM Integration + +#### B-1: vLLM Backend Integration +**Priority**: High +**Component**: Backends +**Size**: L + +Support vLLM for faster batch inference. + +**Tasks**: +- [ ] Research vLLM API and requirements +- [ ] Create `python/backends/vllm_backend.py` +- [ ] Implement BaseBackend interface +- [ ] Add config file `configs/backend/vllm.yaml` +- [ ] Add support for batch processing multiple agents +- [ ] Test with Llama-2 or Mistral models +- [ ] Document setup and usage + +**Acceptance Criteria**: +- Can load models via vLLM +- Supports batch inference (multiple agents) +- Performance better than sequential llama.cpp +- Config-driven model selection + +--- + +#### B-2: TensorRT-LLM Backend +**Priority**: Medium +**Component**: Backends +**Size**: XL + +Ultra-fast inference with TensorRT optimization. + +**Tasks**: +- [ ] Install TensorRT-LLM dependencies +- [ ] Create `python/backends/tensorrt_backend.py` +- [ ] Implement engine building/loading +- [ ] Support function calling +- [ ] Benchmark vs other backends +- [ ] Document GPU requirements + +**Acceptance Criteria**: +- <100ms inference on RTX 4090 +- Supports quantized models +- Works with Godot IPC + +--- + +#### B-3: Model Download & Management +**Priority**: High +**Component**: Tools +**Size**: M + +Automated model downloading and version management. + +**Tasks**: +- [ ] Create `python/tools/model_manager.py` +- [ ] Support Hugging Face Hub downloads +- [ ] Verify model checksums +- [ ] Cache models in `models/` directory +- [ ] CLI tool: `python -m tools.model_manager download phi-2` +- [ ] List compatible models in README + +**Acceptance Criteria**: +- Can download GGUF models from HF +- Verifies file integrity +- Shows download progress +- Lists available models + +--- + +### Memory Systems + +#### B-4: Long-Term Memory (Vector Store) +**Priority**: High +**Component**: Memory +**Size**: L + +Implement RAG-based long-term memory with FAISS. + +**Tasks**: +- [ ] Create `python/memory/long_term_memory.py` +- [ ] Integrate FAISS for vector storage +- [ ] Use sentence-transformers for embeddings +- [ ] Implement similarity search +- [ ] Support memory insertion/retrieval +- [ ] Add memory persistence (save/load) +- [ ] Create unit tests + +**Acceptance Criteria**: +- Can store episode memories +- Top-K retrieval works +- Persists across sessions +- <50ms retrieval time + +--- + +#### B-5: Episode Memory System +**Priority**: Medium +**Component**: Memory +**Size**: M + +Store and summarize episode trajectories for learning. + +**Tasks**: +- [ ] Create `python/memory/episode_memory.py` +- [ ] Store full episode trajectories +- [ ] Generate LLM-based episode summaries +- [ ] Index by success/failure +- [ ] Support episode replay +- [ ] Link to long-term memory + +**Acceptance Criteria**: +- Episodes stored with metadata +- Can retrieve similar episodes +- Summaries are coherent +- Supports filtering by metrics + +--- + +### Agent Tools + +#### B-6: Advanced Movement Tools +**Priority**: Medium +**Component**: Tools +**Size**: M + +Navigation, pathfinding, and advanced movement. + +**Tasks**: +- [ ] Implement A* pathfinding in Godot +- [ ] Add `navigate_to` tool (vs simple move_to) +- [ ] Support obstacle avoidance +- [ ] Add `follow_path` tool +- [ ] Test in complex scenes +- [ ] Update tool schemas + +**Acceptance Criteria**: +- Agents can navigate around obstacles +- Pathfinding works in all scenes +- Performance acceptable (< 10ms) + +--- + +#### B-7: Inventory Management Tools +**Priority**: Medium +**Component**: Tools +**Size**: S + +Complete inventory system for agents. + +**Tasks**: +- [ ] Implement `pickup_item` tool +- [ ] Implement `drop_item` tool +- [ ] Implement `use_item` tool +- [ ] Add inventory capacity limits +- [ ] Track item properties (durability, etc.) +- [ ] Update perception with inventory state + +**Acceptance Criteria**: +- Agents can manage inventory +- Capacity limits enforced +- Items have properties +- Works in crafting scene + +--- + +#### B-8: Communication Tools +**Priority**: Medium +**Component**: Tools +**Size**: M + +Enhanced agent-to-agent communication. + +**Tasks**: +- [ ] Implement message broadcast +- [ ] Add message history +- [ ] Support team channels +- [ ] Add `query_messages` tool +- [ ] Track message metadata (sender, timestamp) +- [ ] Test in team capture scene + +**Acceptance Criteria**: +- Agents can send/receive messages +- Messages persist in memory +- Team-based filtering works +- Demonstrates coordination + +--- + +### Benchmark Scenes + +#### B-9: Combat Arena Scene +**Priority**: Medium +**Component**: Scenes +**Size**: L + +1v1 or team-based combat benchmark. + +**Tasks**: +- [ ] Design combat mechanics +- [ ] Create scene in Godot +- [ ] Implement health/damage system +- [ ] Add weapon types +- [ ] Create combat tools (attack, defend, dodge) +- [ ] Track combat metrics +- [ ] Add GDScript logic + +**Metrics**: +- Damage dealt/taken +- Win rate +- Survival time +- Hit accuracy + +--- + +#### B-10: Navigation Maze Scene +**Priority**: Low +**Component**: Scenes +**Size**: M + +Test pathfinding and exploration. + +**Tasks**: +- [ ] Create maze layout +- [ ] Add waypoints/checkpoints +- [ ] Implement fog of war +- [ ] Track exploration metrics +- [ ] Add procedural generation (optional) + +**Metrics**: +- Time to complete +- Exploration coverage +- Backtracking count +- Path efficiency + +--- + +#### B-11: Multi-Agent Coordination Scene +**Priority**: High +**Component**: Scenes +**Size**: L + +Complex task requiring tight coordination. + +**Tasks**: +- [ ] Design coordination challenge (e.g., moving large objects) +- [ ] Implement synchronization requirements +- [ ] Add communication requirements +- [ ] Track coordination metrics +- [ ] Test with 3-5 agents + +**Metrics**: +- Task completion time +- Communication frequency +- Individual contribution +- Synchronization score + +--- + +### Evaluation & Metrics + +#### B-12: Evaluation Harness +**Priority**: High +**Component**: Evals +**Size**: L + +Automated benchmark running and metric collection. + +**Tasks**: +- [ ] Create `python/evals/eval_harness.py` +- [ ] Support running multiple trials +- [ ] Collect metrics from all scenes +- [ ] Generate reports (JSON, CSV) +- [ ] Add visualization (plots, tables) +- [ ] Support comparison across models +- [ ] CLI: `python -m evals.run --scene foraging --trials 10` + +**Acceptance Criteria**: +- Runs benchmarks automatically +- Collects all metrics +- Generates reports +- Supports multiple backends + +--- + +#### B-13: Replay System +**Priority**: Medium +**Component**: Godot/C++ +**Size**: M + +Record and replay agent episodes deterministically. + +**Tasks**: +- [ ] Implement replay recording in EventBus +- [ ] Export to MessagePack format +- [ ] Create replay loader +- [ ] Support playback in Godot +- [ ] Add replay viewer UI +- [ ] Test determinism + +**Acceptance Criteria**: +- Episodes can be recorded +- Replays are deterministic +- Can view replays in Godot +- File format documented + +--- + +### Performance & Optimization + +#### B-14: Parallel Agent Processing +**Priority**: Medium +**Component**: Python/Runtime +**Size**: M + +Process multiple agents in parallel for performance. + +**Tasks**: +- [ ] Add async/await to AgentRuntime +- [ ] Implement thread pool for LLM inference +- [ ] Batch observations for multiple agents +- [ ] Optimize IPC for bulk messages +- [ ] Benchmark performance gains + +**Acceptance Criteria**: +- Multiple agents process concurrently +- 2x+ speedup for 3+ agents +- No race conditions +- Works with all backends + +--- + +#### B-15: Response Caching +**Priority**: Low +**Component**: Backends +**Size**: S + +Cache LLM responses for identical contexts. + +**Tasks**: +- [ ] Implement cache key generation +- [ ] Add LRU cache to backends +- [ ] Support cache invalidation +- [ ] Add cache hit/miss metrics +- [ ] Make cache size configurable + +**Acceptance Criteria**: +- Identical contexts use cached responses +- Cache hit rate >30% in repetitive scenarios +- Configurable cache size +- No memory leaks + +--- + +#### B-16: Profiling & Benchmarking Tools +**Priority**: Medium +**Component**: Tools +**Size**: M + +Tools for performance analysis. + +**Tasks**: +- [ ] Add timing decorators +- [ ] Create profiling scripts +- [ ] Measure IPC latency +- [ ] Measure LLM inference time +- [ ] Generate performance reports +- [ ] Add flamegraphs + +**Acceptance Criteria**: +- Can profile Python code +- Identifies bottlenecks +- Reports are readable +- Actionable insights + +--- + +## Medium Priority Backlog + +### Documentation & Tutorials + +#### B-17: Video Tutorials +**Priority**: Low +**Component**: Documentation +**Size**: L + +Create video walkthroughs. + +**Content**: +- [ ] Installation and setup +- [ ] Creating a custom scene +- [ ] Adding a new tool +- [ ] Implementing a backend +- [ ] Running benchmarks + +--- + +#### B-18: API Reference Documentation +**Priority**: Medium +**Component**: Documentation +**Size**: M + +Auto-generated API docs. + +**Tasks**: +- [ ] Set up Sphinx for Python +- [ ] Set up Doxygen for C++ +- [ ] Auto-generate from docstrings +- [ ] Host on GitHub Pages +- [ ] Add examples to docs + +--- + +#### B-19: Cookbook & Examples +**Priority**: Medium +**Component**: Documentation +**Size**: M + +Practical examples and recipes. + +**Examples**: +- [ ] Custom tool implementation +- [ ] Memory system usage +- [ ] Multi-agent coordination +- [ ] Custom scene creation +- [ ] Backend customization + +--- + +### Testing & Quality + +#### B-20: Integration Test Suite +**Priority**: High +**Component**: Testing +**Size**: L + +Comprehensive integration tests. + +**Tests**: +- [ ] Godot ↔ Python IPC +- [ ] Full agent decision loop +- [ ] All benchmark scenes +- [ ] Memory persistence +- [ ] Tool execution +- [ ] Error handling + +--- + +#### B-21: CI/CD Pipeline +**Priority**: High +**Component**: DevOps +**Size**: L + +Automated testing and deployment. + +**Tasks**: +- [ ] Set up GitHub Actions +- [ ] Run Python tests on PR +- [ ] Build C++ module on PR +- [ ] Run integration tests +- [ ] Generate coverage reports +- [ ] Auto-deploy docs + +--- + +#### B-22: Linting & Code Quality +**Priority**: Medium +**Component**: Quality +**Size**: S + +Enforce code standards automatically. + +**Tasks**: +- [ ] Add pre-commit hooks +- [ ] Configure Black, Ruff +- [ ] Add C++ clang-format +- [ ] Run in CI/CD +- [ ] Update CONTRIBUTING.md + +--- + +### Advanced Features + +#### B-23: Multi-Modal Support (Vision) +**Priority**: Low +**Component**: Features +**Size**: XL + +Add vision encoder for visual observations. + +**Tasks**: +- [ ] Integrate CLIP or similar +- [ ] Capture screenshots from Godot +- [ ] Process images in Python +- [ ] Pass to LLM as vision input +- [ ] Test with vision-capable models + +--- + +#### B-24: RL Fine-Tuning Pipeline +**Priority**: Low +**Component**: Features +**Size**: XL + +Reinforcement learning for agent improvement. + +**Tasks**: +- [ ] Collect trajectory data +- [ ] Implement PPO/DPO +- [ ] Fine-tune on successful episodes +- [ ] Evaluate performance gains +- [ ] Document training process + +--- + +#### B-25: Distributed Simulation +**Priority**: Low +**Component**: Infrastructure +**Size**: XL + +Run multiple simulations in parallel. + +**Tasks**: +- [ ] Design distributed architecture +- [ ] Support multiple Godot instances +- [ ] Aggregate results +- [ ] Scale evaluation throughput +- [ ] Deploy on cloud (optional) + +--- + +## Low Priority / Future Ideas + +#### B-26: Web Dashboard +**Priority**: Low +**Component**: UI +**Size**: L + +Web interface for monitoring and control. + +**Features**: +- Real-time metrics +- Agent visualization +- Benchmark results +- Configuration management + +--- + +#### B-27: Custom Scene Builder +**Priority**: Low +**Component**: Tools +**Size**: XL + +GUI tool for creating benchmark scenes. + +**Features**: +- Drag-and-drop scene editor +- Resource placement +- Metric configuration +- Export to .tscn + +--- + +#### B-28: Agent Behavior Trees +**Priority**: Low +**Component**: Features +**Size**: L + +Alternative to LLM for deterministic behaviors. + +**Features**: +- Behavior tree editor +- Hybrid LLM + BT agents +- Fallback behaviors + +--- + +#### B-29: Competition Mode +**Priority**: Low +**Component**: Features +**Size**: M + +Leaderboard and agent competition. + +**Features**: +- Submit agent implementations +- Automated tournaments +- Global leaderboard +- Prize competitions (optional) + +--- + +#### B-30: Mobile Support +**Priority**: Low +**Component**: Platform +**Size**: XL + +Run benchmarks on mobile devices. + +**Tasks**: +- [ ] Android/iOS Godot export +- [ ] Optimize for mobile +- [ ] On-device LLM inference +- [ ] Touch controls + +--- + +## Total Backlog Summary + +- **High Priority**: 7 items +- **Medium Priority**: 15 items +- **Low Priority**: 8 items +- **Total**: 30 items + +**Estimated Timeline**: 6-12 months for all items with 2 developers diff --git a/docs/github_cli_guide.md b/docs/github_cli_guide.md new file mode 100644 index 0000000..dd69bdf --- /dev/null +++ b/docs/github_cli_guide.md @@ -0,0 +1,593 @@ +# GitHub CLI Guide for Agent Arena + +Complete guide to using GitHub CLI (`gh`) for creating issues, managing the project board, and coordinating development. + +## Table of Contents + +- [Installation & Setup](#installation--setup) +- [Creating Issues](#creating-issues) +- [Managing Project Board](#managing-project-board) +- [Common Workflows](#common-workflows) +- [Batch Operations](#batch-operations) + +--- + +## Installation & Setup + +### Install GitHub CLI + +**Windows**: +```powershell +# Using winget +winget install --id GitHub.cli + +# Or download from: https://cli.github.com/ +``` + +**Mac**: +```bash +brew install gh +``` + +**Linux**: +```bash +# Debian/Ubuntu +sudo apt install gh + +# Or see: https://github.com/cli/cli/blob/trunk/docs/install_linux.md +``` + +### Authenticate + +```bash +# Login to GitHub +gh auth login + +# Follow prompts: +# 1. Choose GitHub.com +# 2. Choose HTTPS +# 3. Authenticate via browser +# 4. Choose default git protocol: HTTPS + +# Verify authentication +gh auth status +``` + +### Set Default Repository + +```bash +# Navigate to repo directory +cd "c:\Projects\Agent Arena" + +# Verify you're in correct repo +gh repo view + +# Should show: JustInternetAI/AgentArena +``` + +--- + +## Creating Issues + +### Basic Issue Creation + +```bash +# Simple issue +gh issue create --title "Fix bug in foraging scene" --body "Resource collection not working" + +# Issue with labels +gh issue create \ + --title "Add vLLM backend" \ + --label "backend,enhancement,high-priority" \ + --body "Implement vLLM for faster inference" + +# Issue with assignee +gh issue create \ + --title "Setup Python environment" \ + --assignee @me \ + --label "python,setup" \ + --body "Create venv and requirements.txt" +``` + +### Issue from Template File + +Create a file with the issue body: + +**File**: `issue_templates/vllm_backend.md` +```markdown +## Description +Support vLLM for faster batch inference. + +## Tasks +- [ ] Research vLLM API +- [ ] Create backend class +- [ ] Add tests + +## Acceptance Criteria +- Works with Llama-2 +- Faster than sequential inference +``` + +Then create the issue: +```bash +gh issue create \ + --title "vLLM Backend Integration" \ + --label "backend,enhancement" \ + --body-file issue_templates/vllm_backend.md +``` + +### Interactive Issue Creation + +```bash +# Opens editor for title and body +gh issue create + +# Follow the prompts +``` + +--- + +## Managing Project Board + +### Create Project (v2) + +Projects v2 must be created via web interface currently, but you can link issues to it. + +**Via Web**: +1. Go to https://github.com/orgs/JustInternetAI/projects +2. Click **New project** +3. Choose **Board** template +4. Name: "Agent Arena Development" +5. Note the project number (e.g., #1) + +### List Projects + +```bash +# List organization projects +gh project list --owner JustInternetAI + +# Output shows project number and title +``` + +### Add Issue to Project + +```bash +# Get project number (e.g., 1) and issue URL +gh project item-add 1 \ + --owner JustInternetAI \ + --url https://github.com/JustInternetAI/AgentArena/issues/5 + +# Or use issue number +ISSUE_URL=$(gh issue view 5 --json url -q .url) +gh project item-add 1 --owner JustInternetAI --url $ISSUE_URL +``` + +**Windows PowerShell**: +```powershell +# Get issue URL +$ISSUE_URL = gh issue view 5 --json url -q .url + +# Add to project +gh project item-add 1 --owner JustInternetAI --url $ISSUE_URL +``` + +### List Project Items + +```bash +# View all items in project +gh project item-list 1 --owner JustInternetAI + +# With specific fields +gh project item-list 1 --owner JustInternetAI --format json +``` + +--- + +## Common Workflows + +### Workflow 1: Create Issue and Add to Board + +```bash +# 1. Create the issue +gh issue create \ + --title "Implement LlamaCppBackend" \ + --label "python,backend,critical" \ + --assignee @me \ + --body "Create llama.cpp backend for local LLM inference" + +# 2. Get the issue number from output (e.g., #7) + +# 3. Add to project board +ISSUE_URL=$(gh issue view 7 --json url -q .url) +gh project item-add 1 --owner JustInternetAI --url $ISSUE_URL + +# 4. Verify +gh issue view 7 +``` + +**One-liner** (PowerShell): +```powershell +$issue = gh issue create --title "Test Issue" --body "Test" --json number | ConvertFrom-Json +$url = gh issue view $issue.number --json url -q .url +gh project item-add 1 --owner JustInternetAI --url $url +``` + +### Workflow 2: Bulk Create Issues from List + +Create a file with issue data: + +**File**: `backlog.csv` +```csv +title,labels,priority,body +vLLM Backend,backend;enhancement,high,Implement vLLM for batch inference +Long-Term Memory,memory;enhancement,high,Add FAISS vector store +Evaluation Harness,evals;critical,high,Automated benchmark running +``` + +**Script** (`scripts/bulk_create_issues.sh`): +```bash +#!/bin/bash +while IFS=, read -r title labels priority body +do + gh issue create \ + --title "$title" \ + --label "$labels" \ + --body "$body\n\nPriority: $priority" +done < backlog.csv +``` + +Run it: +```bash +bash scripts/bulk_create_issues.sh +``` + +### Workflow 3: Update Issue Labels + +```bash +# Add labels +gh issue edit 5 --add-label "good-first-issue" + +# Remove labels +gh issue edit 5 --remove-label "wontfix" + +# Replace all labels +gh issue edit 5 --label "backend,python,high-priority" +``` + +### Workflow 4: Assign Issues + +```bash +# Assign to yourself +gh issue edit 5 --assignee @me + +# Assign to specific user +gh issue edit 5 --assignee colleague-username + +# Assign multiple people +gh issue edit 5 --assignee user1,user2 +``` + +### Workflow 5: Close Issue with Comment + +```bash +# Close issue +gh issue close 5 + +# Close with comment +gh issue close 5 --comment "Fixed in PR #12" +``` + +--- + +## Batch Operations + +### Create All Backlog Issues + +Use the provided script: + +**Windows**: +```bash +# Run the batch script +scripts\create_github_issues.bat +``` + +**Linux/Mac**: +```bash +# Make executable +chmod +x scripts/create_github_issues.sh + +# Run +bash scripts/create_github_issues.sh +``` + +### Add All Issues to Project + +```bash +# Get all open issues +gh issue list --state open --limit 100 --json number -q '.[].number' > issues.txt + +# Add each to project (PowerShell) +Get-Content issues.txt | ForEach-Object { + $url = gh issue view $_ --json url -q .url + gh project item-add 1 --owner JustInternetAI --url $url + Write-Host "Added issue #$_ to project" +} +``` + +**Bash version**: +```bash +# Get all open issues +gh issue list --state open --limit 100 --json number -q '.[].number' | while read num; do + url=$(gh issue view $num --json url -q .url) + gh project item-add 1 --owner JustInternetAI --url $url + echo "Added issue #$num to project" +done +``` + +--- + +## Useful Commands Reference + +### Issues + +```bash +# List all issues +gh issue list + +# List with filters +gh issue list --label "python" --state open +gh issue list --assignee @me +gh issue list --author colleague-username + +# View issue details +gh issue view 5 +gh issue view 5 --web # Open in browser + +# Comment on issue +gh issue comment 5 --body "Working on this now" + +# Search issues +gh issue list --search "backend" +``` + +### Pull Requests + +```bash +# Create PR from current branch +gh pr create --title "Add vLLM backend" --body "Implements vLLM integration" + +# Create draft PR +gh pr create --draft --title "WIP: vLLM backend" + +# List PRs +gh pr list +gh pr list --author @me + +# View PR +gh pr view 10 +gh pr view 10 --web + +# Check PR status +gh pr status + +# Merge PR +gh pr merge 10 --squash + +# Close PR +gh pr close 10 +``` + +### Repository + +```bash +# View repo info +gh repo view + +# Clone repo +gh repo clone JustInternetAI/AgentArena + +# Fork repo +gh repo fork + +# View in browser +gh repo view --web +``` + +--- + +## Project Management Automation + +### Script: Add New Issues to Project Automatically + +**File**: `.github/workflows/add-to-project.yml` +```yaml +name: Add to Project Board + +on: + issues: + types: [opened] + +jobs: + add-to-project: + runs-on: ubuntu-latest + steps: + - name: Add issue to project + uses: actions/add-to-project@v0.5.0 + with: + project-url: https://github.com/orgs/JustInternetAI/projects/1 + github-token: ${{ secrets.ADD_TO_PROJECT_TOKEN }} +``` + +This automatically adds new issues to your project board! + +--- + +## Tips & Tricks + +### 1. Create Aliases + +Add to `.bashrc` or PowerShell profile: + +```bash +# Bash aliases +alias ghic='gh issue create' +alias ghil='gh issue list' +alias ghiv='gh issue view' +alias ghpc='gh pr create' +alias ghpl='gh pr list' +``` + +**PowerShell**: +```powershell +# Add to $PROFILE +function ghic { gh issue create $args } +function ghil { gh issue list $args } +function ghiv { gh issue view $args } +``` + +### 2. Use JSON Output for Scripting + +```bash +# Get issue data as JSON +gh issue view 5 --json number,title,state,labels + +# Parse with jq +gh issue list --json number,title,state | jq '.[] | select(.state == "OPEN")' +``` + +### 3. Quick Issue Templates + +Create template files in `issue_templates/`: + +```bash +# Python issue template +cat > issue_templates/python.md << 'EOF' +## Description +[Describe the Python component] + +## Tasks +- [ ] Implementation +- [ ] Tests +- [ ] Documentation + +## Component +Python +EOF + +# Use it +gh issue create --body-file issue_templates/python.md --title "New Python Feature" +``` + +### 4. Link Issues and PRs + +```bash +# Reference issue in PR +gh pr create --title "Fix #5: Add vLLM backend" + +# Close issue when PR merges (in PR description) +gh pr create --body "Closes #5\n\nImplements vLLM backend" +``` + +### 5. Use Issue Numbers in Commits + +```bash +git commit -m "feat(backend): add vLLM support (#5)" + +# GitHub automatically links the commit to issue #5 +``` + +--- + +## Complete Example: Week 1 Setup + +Here's a complete workflow for Week 1: + +```bash +# 1. Authenticate +gh auth login + +# 2. Navigate to repo +cd "c:\Projects\Agent Arena" + +# 3. Create issues for Week 1 +gh issue create \ + --title "Setup Python environment and requirements.txt" \ + --label "python,setup,good-first-issue" \ + --assignee colleague-username \ + --body-file docs/issue_bodies/issue_1.md + +gh issue create \ + --title "Implement BaseBackend abstract class" \ + --label "python,backend,architecture" \ + --assignee colleague-username \ + --body-file docs/issue_bodies/issue_2.md + +gh issue create \ + --title "Implement FastAPI IPC server" \ + --label "python,ipc,critical" \ + --assignee colleague-username \ + --body-file docs/issue_bodies/issue_3.md + +# 4. View created issues +gh issue list --assignee colleague-username + +# 5. Add to project board (assuming project #1) +for i in {1..3}; do + url=$(gh issue view $i --json url -q .url) + gh project item-add 1 --owner JustInternetAI --url $url + echo "Added issue #$i to project" +done + +# 6. View project +gh project view 1 --owner JustInternetAI --web +``` + +--- + +## Troubleshooting + +### Error: "Resource not accessible by personal access token" + +**Solution**: Create a Personal Access Token with `project` scope: +1. Go to https://github.com/settings/tokens +2. Generate new token (classic) +3. Check `project` and `repo` scopes +4. Copy token +5. Use: `gh auth login --with-token < token.txt` + +### Error: "Project not found" + +**Solution**: Use the correct project number: +```bash +# List all projects +gh project list --owner JustInternetAI + +# Note the correct number +``` + +### Issues Not Showing in Project + +**Solution**: Manually add via web or use correct project URL: +```bash +gh project item-add \ + --owner JustInternetAI \ + --url https://github.com/JustInternetAI/AgentArena/issues/ +``` + +--- + +## Resources + +- [GitHub CLI Manual](https://cli.github.com/manual/) +- [GitHub CLI Reference](https://cli.github.com/manual/gh) +- [GitHub Projects Docs](https://docs.github.com/en/issues/planning-and-tracking-with-projects) +- [GitHub CLI Issues](https://github.com/cli/cli/issues) + +--- + +**Next Steps**: +1. Install and authenticate GitHub CLI +2. Run `scripts/create_github_issues.bat` (Windows) or `.sh` (Linux/Mac) +3. Create project board via web interface +4. Add issues to board using commands above +5. Start developing! diff --git a/docs/github_issues.md b/docs/github_issues.md new file mode 100644 index 0000000..e82d814 --- /dev/null +++ b/docs/github_issues.md @@ -0,0 +1,678 @@ +# GitHub Issues for Agent Arena + +This document contains pre-written GitHub issues that can be created for dividing work. Copy the markdown below each issue into GitHub's issue creation form. + +--- + +## Python Environment & Setup Issues + +### Issue 1: Setup Python Environment and Requirements + +**Title**: Setup Python environment and requirements.txt + +**Labels**: `python`, `setup`, `good-first-issue` + +**Assignee**: Your colleague + +**Body**: +```markdown +## Description +Set up the Python development environment for the Agent Arena project, including virtual environment and dependency management. + +## Tasks +- [ ] Create Python virtual environment in `python/venv/` +- [ ] Create `python/requirements.txt` with initial dependencies +- [ ] Add `.gitignore` entry for `python/venv/` +- [ ] Document setup steps in `docs/python_development.md` +- [ ] Test installation on fresh environment + +## Dependencies +```txt +fastapi>=0.100.0 +uvicorn>=0.23.0 +pydantic>=2.0.0 +requests>=2.31.0 +pytest>=7.4.0 +hydra-core>=1.3.0 +omegaconf>=2.3.0 +numpy>=1.24.0 +``` + +## Acceptance Criteria +- Virtual environment can be created and activated +- `pip install -r requirements.txt` completes without errors +- Documentation includes setup instructions for Windows, Linux, macOS +- CI/CD can install dependencies (future) + +## References +- [Python Development Docs](../docs/python_development.md) (to be created) +- [Architecture](../docs/architecture.md) +``` + +--- + +### Issue 2: Implement BaseBackend Abstract Class + +**Title**: Implement BaseBackend abstract class for LLM backends + +**Labels**: `python`, `architecture`, `backend` + +**Assignee**: Your colleague + +**Body**: +```markdown +## Description +Create the abstract base class that all LLM backends will inherit from. This establishes the interface contract for different inference engines (llama.cpp, vLLM, TensorRT-LLM). + +## Tasks +- [ ] Create `python/backends/base_backend.py` +- [ ] Define abstract methods: `generate()`, `generate_with_tools()`, `is_available()`, `unload()` +- [ ] Add type hints and docstrings +- [ ] Create unit tests in `tests/test_base_backend.py` +- [ ] Add example mock backend for testing + +## Implementation Details + +```python +from abc import ABC, abstractmethod +from typing import List, Dict, Any, Optional + +class BaseBackend(ABC): + """Abstract base class for LLM inference backends.""" + + def __init__(self, config: Dict[str, Any]): + """Initialize backend with configuration.""" + self.config = config + + @abstractmethod + def generate(self, prompt: str, max_tokens: int = 512, + temperature: float = 0.7) -> str: + """Generate text from a prompt.""" + pass + + @abstractmethod + def generate_with_tools(self, prompt: str, tools: List[Dict], + **kwargs) -> Dict[str, Any]: + """Generate with tool/function calling support.""" + pass + + @abstractmethod + def is_available(self) -> bool: + """Check if backend is ready for inference.""" + pass + + @abstractmethod + def unload(self): + """Unload model and free resources.""" + pass +``` + +## Acceptance Criteria +- BaseBackend class is abstract and cannot be instantiated +- All required methods are defined with proper type hints +- Docstrings follow Google or NumPy style +- Unit tests achieve >80% coverage +- Mock backend can be used for testing without real LLM + +## References +- [Architecture - Backend Module](../docs/architecture.md#backends) +``` + +--- + +### Issue 3: Implement FastAPI IPC Server + +**Title**: Implement FastAPI IPC server for Godot-Python communication + +**Labels**: `python`, `ipc`, `critical` + +**Assignee**: Your colleague + +**Body**: +```markdown +## Description +Create the FastAPI server that receives perception data from Godot and returns agent actions. + +## Tasks +- [ ] Create `python/run_ipc_server.py` +- [ ] Implement `/tick` POST endpoint +- [ ] Implement `/health` GET endpoint +- [ ] Implement `/echo` POST endpoint for testing +- [ ] Add Pydantic models for request/response validation +- [ ] Add error handling and logging +- [ ] Support multiple agents in single request +- [ ] Add CLI arguments (--host, --port, --workers, --debug) +- [ ] Create integration test with mock Godot client + +## Implementation Guide + +```python +from fastapi import FastAPI, HTTPException +from pydantic import BaseModel +from typing import List, Dict, Any +import uvicorn + +app = FastAPI(title="Agent Arena IPC Server") + +class AgentObservation(BaseModel): + agent_id: str + observations: Dict[str, Any] + +class PerceptionRequest(BaseModel): + tick: int + timestamp: float + agents: List[AgentObservation] + +class ActionResponse(BaseModel): + tick: int + actions: List[Dict[str, Any]] + +@app.post("/tick", response_model=ActionResponse) +async def process_tick(request: PerceptionRequest): + # Process agent observations + # Generate actions using agent runtime + # Return actions + pass + +@app.get("/health") +async def health_check(): + return {"status": "ok"} + +if __name__ == "__main__": + uvicorn.run(app, host="127.0.0.1", port=5000) +``` + +## Acceptance Criteria +- Server starts successfully on port 5000 +- `/health` endpoint returns 200 OK +- `/tick` endpoint accepts valid perception data +- Response matches ActionResponse schema +- Invalid requests return proper HTTP error codes +- Server logs all requests when --debug flag is used +- Can handle 60+ requests/second (simulation tick rate) + +## References +- [IPC Protocol Documentation](../docs/ipc_protocol.md) +- [Architecture - Communication Protocol](../docs/architecture.md#communication-protocol) +``` + +--- + +## Agent Runtime Issues + +### Issue 4: Implement AgentRuntime Class + +**Title**: Implement AgentRuntime for managing agent lifecycle + +**Labels**: `python`, `agent`, `core` + +**Assignee**: Your colleague + +**Body**: +```markdown +## Description +Create the main agent runtime class that manages multiple agents, coordinates their perception-reasoning-action loops, and interfaces with LLM backends. + +## Tasks +- [ ] Create `python/agent_runtime/agent_runtime.py` +- [ ] Implement agent registration and management +- [ ] Add async execution support for multiple agents +- [ ] Integrate with BaseBackend for decision-making +- [ ] Add memory system integration hooks +- [ ] Implement tool dispatcher integration +- [ ] Add basic logging and metrics +- [ ] Create unit tests + +## Key Methods + +```python +class AgentRuntime: + def __init__(self, backend: BaseBackend, config: Dict[str, Any]): + self.backend = backend + self.agents = {} + + def register_agent(self, agent_id: str, agent_config: Dict): + """Register a new agent.""" + + async def process_observations(self, observations: List[Dict]) -> List[Dict]: + """Process observations for all agents and return actions.""" + + def get_agent_memory(self, agent_id: str) -> Any: + """Get agent's memory state.""" + + def reset_agent(self, agent_id: str): + """Reset agent state.""" +``` + +## Acceptance Criteria +- Can manage multiple agents simultaneously +- Processes observations and returns actions asynchronously +- Integrates with backend for LLM inference +- Handles agent registration and deregistration +- Includes error handling for individual agent failures +- Unit tests cover all major methods + +## References +- [Architecture - Agent Runtime](../docs/architecture.md#2-python-agent-runtime) +``` + +--- + +### Issue 5: Implement Short-Term Memory System + +**Title**: Implement short-term memory (scratchpad) for agents + +**Labels**: `python`, `memory`, `agent` + +**Assignee**: Your colleague + +**Body**: +```markdown +## Description +Create a short-term memory system that stores recent observations for each agent using a FIFO queue with configurable capacity. + +## Tasks +- [ ] Create `python/memory/short_term_memory.py` +- [ ] Implement FIFO queue with max capacity +- [ ] Add priority-based eviction (optional) +- [ ] Support serialization/deserialization +- [ ] Add memory retrieval with filtering +- [ ] Create unit tests +- [ ] Add configuration via Hydra config + +## Implementation + +```python +from collections import deque +from typing import List, Dict, Any, Optional + +class ShortTermMemory: + """FIFO queue for recent agent observations.""" + + def __init__(self, capacity: int = 10): + self.capacity = capacity + self.memory = deque(maxlen=capacity) + + def add(self, observation: Dict[str, Any]): + """Add observation to memory.""" + self.memory.append(observation) + + def get_recent(self, n: int = 5) -> List[Dict[str, Any]]: + """Get n most recent observations.""" + return list(self.memory)[-n:] + + def clear(self): + """Clear all memories.""" + self.memory.clear() + + def to_context_string(self) -> str: + """Convert memories to LLM context string.""" + pass +``` + +## Acceptance Criteria +- FIFO queue respects capacity limit +- Old memories are evicted when capacity is reached +- Can retrieve N most recent observations +- Supports clearing memory +- Can serialize memory state for replay +- Unit tests verify FIFO behavior + +## References +- [Architecture - Memory System](../docs/architecture.md#memory-system) +``` + +--- + +### Issue 6: Implement Tool Dispatcher + +**Title**: Implement ToolDispatcher for agent tool execution + +**Labels**: `python`, `tools`, `agent` + +**Assignee**: Your colleague + +**Body**: +```markdown +## Description +Create the tool dispatcher that registers available tools, validates tool calls from LLM, and formats them for execution in Godot. + +## Tasks +- [ ] Create `python/agent_runtime/tool_dispatcher.py` +- [ ] Implement tool registration with JSON schemas +- [ ] Add tool call validation against schemas +- [ ] Support dynamic tool discovery +- [ ] Parse LLM output for tool calls (JSON, function calling) +- [ ] Create unit tests +- [ ] Add example tools (movement, collection) + +## Implementation + +```python +from typing import Dict, List, Any, Callable +import json + +class ToolDispatcher: + """Manages tool registration and execution.""" + + def __init__(self): + self.tools = {} + + def register_tool(self, name: str, schema: Dict[str, Any], + handler: Optional[Callable] = None): + """Register a tool with its schema.""" + self.tools[name] = { + "schema": schema, + "handler": handler + } + + def get_tool_schemas(self) -> List[Dict[str, Any]]: + """Get all tool schemas for LLM context.""" + return [tool["schema"] for tool in self.tools.values()] + + def validate_tool_call(self, tool_name: str, params: Dict) -> bool: + """Validate tool call parameters against schema.""" + pass + + def parse_tool_call(self, llm_output: str) -> Dict[str, Any]: + """Parse tool call from LLM output.""" + pass +``` + +## Acceptance Criteria +- Can register tools with JSON schemas +- Validates parameters against schema +- Parses tool calls from LLM output (JSON format) +- Returns properly formatted action for Godot +- Handles invalid tool calls gracefully +- Unit tests cover all parsing scenarios + +## References +- [IPC Protocol - Available Tools](../docs/ipc_protocol.md#3-available-tools) +- [Architecture - Tool System](../docs/architecture.md#extensibility) +``` + +--- + +### Issue 7: Implement LlamaCppBackend + +**Title**: Implement llama.cpp backend for local LLM inference + +**Labels**: `python`, `backend`, `llm` + +**Assignee**: Your colleague + +**Body**: +```markdown +## Description +Create a backend implementation for llama.cpp to enable local LLM inference with GGUF models. + +## Tasks +- [ ] Create `python/backends/llama_cpp_backend.py` +- [ ] Install llama-cpp-python dependency +- [ ] Implement all BaseBackend abstract methods +- [ ] Add model loading/unloading +- [ ] Support function calling / tool use +- [ ] Add configurable inference parameters (temp, top_p, etc.) +- [ ] Create config file `configs/backend/llama_cpp.yaml` +- [ ] Add integration tests with small model +- [ ] Document model download and setup + +## Dependencies + +Add to `requirements.txt`: +``` +llama-cpp-python>=0.2.0 +``` + +## Configuration + +`configs/backend/llama_cpp.yaml`: +```yaml +backend: + type: llama_cpp + model_path: models/phi-2.Q4_K_M.gguf + n_ctx: 2048 + n_threads: 4 + n_gpu_layers: 0 + temperature: 0.7 + top_p: 0.9 + max_tokens: 512 +``` + +## Acceptance Criteria +- Can load GGUF models successfully +- Generates coherent text from prompts +- Supports function/tool calling +- Handles model loading errors gracefully +- Can unload model to free memory +- Integration test runs with small model (~1GB) + +## References +- [llama-cpp-python docs](https://github.com/abetlen/llama-cpp-python) +- [Architecture - Backends](../docs/architecture.md#backends) +``` + +--- + +## Testing & Integration Issues + +### Issue 8: Create Python Unit Test Suite + +**Title**: Create comprehensive Python unit test suite + +**Labels**: `python`, `testing`, `quality` + +**Assignee**: Your colleague + +**Body**: +```markdown +## Description +Set up pytest-based unit testing infrastructure for the Python codebase. + +## Tasks +- [ ] Create `tests/` directory structure +- [ ] Set up pytest configuration (`pytest.ini`) +- [ ] Create fixtures for common test data +- [ ] Add tests for BaseBackend +- [ ] Add tests for AgentRuntime +- [ ] Add tests for ToolDispatcher +- [ ] Add tests for ShortTermMemory +- [ ] Add tests for IPC server +- [ ] Set up coverage reporting +- [ ] Document testing practices + +## Directory Structure + +``` +tests/ +├── __init__.py +├── conftest.py # Shared fixtures +├── test_backends/ +│ ├── test_base_backend.py +│ └── test_llama_cpp_backend.py +├── test_agent_runtime/ +│ ├── test_agent_runtime.py +│ └── test_tool_dispatcher.py +├── test_memory/ +│ └── test_short_term_memory.py +└── test_ipc/ + └── test_ipc_server.py +``` + +## pytest.ini + +```ini +[pytest] +testpaths = tests +python_files = test_*.py +python_classes = Test* +python_functions = test_* +addopts = + --verbose + --cov=python + --cov-report=html + --cov-report=term +``` + +## Acceptance Criteria +- All tests pass with `pytest` +- Code coverage > 80% +- Tests run in CI/CD pipeline (future) +- Mock objects used where appropriate +- Documentation includes testing guide + +## References +- [pytest documentation](https://docs.pytest.org/) +``` + +--- + +### Issue 9: Create End-to-End Integration Test + +**Title**: Create end-to-end integration test (Godot + Python) + +**Labels**: `integration`, `testing`, `critical` + +**Assignee**: Both (collaborative) + +**Body**: +```markdown +## Description +Create an integration test that verifies the full pipeline: Godot sends perception → Python processes → Returns action → Godot executes. + +## Tasks +- [ ] Create test script that starts IPC server +- [ ] Create minimal Godot test scene +- [ ] Send mock perception data from Godot +- [ ] Verify Python receives and processes it +- [ ] Verify action is returned and executed +- [ ] Test all three benchmark scenes +- [ ] Document integration testing process +- [ ] Add to CI/CD (future) + +## Test Scenarios + +1. **Basic IPC**: Send perception, receive action +2. **Movement**: Agent moves to target position +3. **Collection**: Agent collects resource +4. **Crafting**: Agent crafts item at station +5. **Team Capture**: Multiple agents coordinate +6. **Error Handling**: Invalid tool call, LLM timeout + +## Acceptance Criteria +- Full perception → action → execution loop works +- All benchmark scenes work end-to-end +- Error cases handled gracefully +- Documentation includes troubleshooting guide +- Can run without manual intervention + +## References +- [IPC Protocol](../docs/ipc_protocol.md) +- [Testing Guide](../TESTING.md) +``` + +--- + +## Documentation Issues + +### Issue 10: Create Python Development Documentation + +**Title**: Create Python development documentation + +**Labels**: `documentation`, `python` + +**Assignee**: Your colleague + +**Body**: +```markdown +## Description +Create comprehensive documentation for Python development on Agent Arena. + +## Tasks +- [ ] Create `docs/python_development.md` +- [ ] Document environment setup +- [ ] Document project structure +- [ ] Add backend development guide +- [ ] Add tool creation guide +- [ ] Add memory system guide +- [ ] Include code examples +- [ ] Add troubleshooting section + +## Sections + +1. **Setup**: venv, dependencies, IDE configuration +2. **Project Structure**: Explanation of `python/` directory +3. **Adding a Backend**: Step-by-step guide +4. **Creating Tools**: How to add new agent tools +5. **Memory Systems**: Short-term, long-term, episode +6. **Testing**: Running tests, writing tests +7. **Debugging**: Common issues and solutions +8. **Code Style**: Formatting, linting, type hints + +## Acceptance Criteria +- New developer can set up Python environment from docs +- All major components are documented +- Includes working code examples +- Covers common pitfalls and solutions + +## References +- [Architecture](../docs/architecture.md) +- [IPC Protocol](../docs/ipc_protocol.md) +``` + +--- + +## Quick Create Commands + +To create these issues quickly, use the GitHub CLI: + +```bash +# Make sure you're in the repo directory +cd "c:\Projects\Agent Arena" + +# Create all issues at once (copy/paste each block) + +# Issue 1 +gh issue create --title "Setup Python environment and requirements.txt" \ + --label "python,setup,good-first-issue" \ + --body-file docs/issue_bodies/issue_1.md + +# Issue 2 +gh issue create --title "Implement BaseBackend abstract class for LLM backends" \ + --label "python,architecture,backend" \ + --body-file docs/issue_bodies/issue_2.md + +# ... etc for all issues +``` + +Or create them manually via GitHub web interface and copy the markdown body from each section above. + +--- + +## Issue Assignment Strategy + +**Week 1 Focus** (Your colleague): +- Issue 1: Setup Python environment +- Issue 2: BaseBackend +- Issue 3: FastAPI IPC server + +**Week 2 Focus** (Your colleague): +- Issue 4: AgentRuntime +- Issue 5: Short-term memory +- Issue 6: Tool dispatcher + +**Week 3 Focus** (Your colleague): +- Issue 7: LlamaCppBackend +- Issue 8: Unit tests + +**Week 4 Focus** (Collaborative): +- Issue 9: Integration testing +- Issue 10: Documentation + +**Your Focus** (Parallel): +- Debug benchmark scenes +- Implement tool execution in Godot +- Add collision detection +- Improve visuals +- Refine IPC client diff --git a/docs/ipc_protocol.md b/docs/ipc_protocol.md new file mode 100644 index 0000000..f7ed545 --- /dev/null +++ b/docs/ipc_protocol.md @@ -0,0 +1,568 @@ +# IPC Protocol Documentation + +## Overview + +Agent Arena uses HTTP/JSON for communication between the Godot simulation (C++/GDScript) and the Python agent runtime. This document defines the message format and protocol for both directions. + +## Architecture + +``` +┌─────────────────┐ ┌──────────────────┐ +│ Godot Engine │ │ Python Runtime │ +│ (Simulation) │ │ (Agent Brain) │ +├─────────────────┤ ├──────────────────┤ +│ │ Perception Data │ │ +│ IPCClient │───────────────────>│ FastAPI Server │ +│ │ │ │ +│ ToolRegistry │<───────────────────│ AgentRuntime │ +│ │ Action Commands │ │ +└─────────────────┘ └──────────────────┘ +``` + +## Connection Setup + +### Server (Python) +- **Protocol**: HTTP/1.1 +- **Default Host**: `127.0.0.1` +- **Default Port**: `5000` +- **Framework**: FastAPI +- **Startup**: `python python/run_ipc_server.py` + +### Client (Godot) +- **Node Type**: `IPCClient` (C++ GDExtension) +- **Methods**: `connect_to_server()`, `send_tick_request()`, `get_tick_response()` +- **Default URL**: `http://127.0.0.1:5000` + +## Message Format + +All messages use JSON encoding with UTF-8. + +--- + +## 1. Perception Messages (Godot → Python) + +Sent every simulation tick to provide agents with observations about the world. + +### Endpoint +``` +POST /tick +``` + +### Request Format + +```json +{ + "tick": 1234, + "timestamp": 1234567890.123, + "agents": [ + { + "agent_id": "foraging_agent_001", + "observations": { + "position": [10.5, 0.0, 5.2], + "rotation": [0.0, 90.0, 0.0], + "velocity": [1.0, 0.0, 0.5], + "health": 100.0, + "inventory": { + "berries": 3, + "wood": 2, + "stone": 1 + }, + "visible_entities": [ + { + "entity_id": "berry_001", + "type": "resource", + "resource_type": "berry", + "position": [12.0, 0.5, 6.0], + "distance": 2.1 + }, + { + "entity_id": "fire_hazard_002", + "type": "hazard", + "hazard_type": "fire", + "position": [7.0, 0.5, -3.0], + "distance": 9.8 + } + ], + "nearby_agents": [ + { + "agent_id": "blue_agent_002", + "team": "blue", + "position": [8.0, 1.0, 7.0], + "distance": 3.5 + } + ], + "scene_specific": { + "foraging": { + "resources_collected": 6, + "resources_remaining": 1, + "damage_taken": 15.0 + }, + "crafting": { + "available_stations": [ + { + "name": "Furnace", + "type": "furnace", + "position": [0.0, 0.5, -5.0], + "distance": 12.3 + } + ], + "recipes": { + "iron_ingot": { + "inputs": {"iron_ore": 1, "coal": 1}, + "station": "Furnace", + "time": 3.0 + } + } + }, + "team_capture": { + "team": "blue", + "team_score": 45, + "enemy_score": 38, + "objectives": [ + { + "name": "CapturePointA", + "owner": "blue", + "capturing_team": null, + "capture_progress": 0.0, + "position": [-15.0, 0.5, -15.0], + "distance": 8.2 + } + ] + } + } + } + } + ] +} +``` + +### Field Descriptions + +| Field | Type | Description | +|-------|------|-------------| +| `tick` | integer | Current simulation tick number | +| `timestamp` | float | Unix timestamp in seconds | +| `agents` | array | List of agent observations | +| `agent_id` | string | Unique identifier for the agent | +| `observations` | object | Agent's perception data | +| `position` | [float, float, float] | Agent position (x, y, z) | +| `rotation` | [float, float, float] | Agent rotation in degrees (pitch, yaw, roll) | +| `velocity` | [float, float, float] | Current velocity vector | +| `health` | float | Agent's health (0-100) | +| `inventory` | object | Dict of item_name: quantity | +| `visible_entities` | array | Entities within perception range | +| `nearby_agents` | array | Other agents within communication range | +| `scene_specific` | object | Benchmark-specific data | + +--- + +## 2. Action Messages (Python → Godot) + +Response containing agent action decisions. + +### Response Format + +```json +{ + "tick": 1234, + "actions": [ + { + "agent_id": "foraging_agent_001", + "action": { + "tool": "move_to", + "params": { + "target_x": 12.0, + "target_y": 0.0, + "target_z": 6.0, + "speed": 1.5 + } + }, + "reasoning": "Moving towards berry at (12, 0, 6) to collect resources" + }, + { + "agent_id": "blue_agent_001", + "action": { + "tool": "capture_point", + "params": { + "point_name": "CapturePointC" + } + }, + "reasoning": "Capturing neutral objective to gain team points" + } + ] +} +``` + +### Field Descriptions + +| Field | Type | Description | +|-------|------|-------------| +| `tick` | integer | Must match the request tick | +| `actions` | array | List of agent actions | +| `agent_id` | string | Agent that performs this action | +| `action` | object | Action specification | +| `tool` | string | Name of the tool to execute | +| `params` | object | Tool-specific parameters | +| `reasoning` | string | (Optional) LLM's reasoning for debugging | + +--- + +## 3. Available Tools + +Tools are registered in the `ToolRegistry` and available to agents. Each tool has a JSON schema defining its parameters. + +### Movement Tools + +#### `move_to` +Move the agent to a target position. + +```json +{ + "tool": "move_to", + "params": { + "target_x": 15.0, + "target_y": 0.0, + "target_z": 8.0, + "speed": 1.5 + } +} +``` + +**Parameters**: +- `target_x` (float): Target X coordinate +- `target_y` (float): Target Y coordinate +- `target_z` (float): Target Z coordinate +- `speed` (float, optional): Movement speed multiplier (default: 1.0) + +#### `rotate_to` +Rotate the agent to face a direction. + +```json +{ + "tool": "rotate_to", + "params": { + "yaw": 90.0 + } +} +``` + +**Parameters**: +- `yaw` (float): Target rotation in degrees + +### Collection Tools + +#### `collect` +Collect a nearby resource. + +```json +{ + "tool": "collect", + "params": { + "resource_name": "Berry1" + } +} +``` + +**Parameters**: +- `resource_name` (string): Name of the resource to collect + +### Crafting Tools + +#### `craft` +Craft an item at a crafting station. + +```json +{ + "tool": "craft", + "params": { + "item_name": "iron_ingot", + "station_name": "Furnace" + } +} +``` + +**Parameters**: +- `item_name` (string): Name of item to craft (must match recipe) +- `station_name` (string): Name of crafting station + +### Query Tools + +#### `query_world` +Get information about nearby entities. + +```json +{ + "tool": "query_world", + "params": { + "radius": 10.0 + } +} +``` + +**Parameters**: +- `radius` (float): Search radius in meters + +#### `query_inventory` +Check current inventory contents. + +```json +{ + "tool": "query_inventory", + "params": {} +} +``` + +**Parameters**: None + +#### `query_recipes` +Get available crafting recipes. + +```json +{ + "tool": "query_recipes", + "params": {} +} +``` + +**Parameters**: None + +### Communication Tools (Team Capture) + +#### `send_message` +Send a message to nearby teammates. + +```json +{ + "tool": "send_message", + "params": { + "message": "Capturing point C, need backup!", + "target_agent": "blue_agent_002" + } +} +``` + +**Parameters**: +- `message` (string): Message content +- `target_agent` (string, optional): Specific agent ID or "all" for broadcast + +#### `capture_point` +Attempt to capture an objective. + +```json +{ + "tool": "capture_point", + "params": { + "point_name": "CapturePointC" + } +} +``` + +**Parameters**: +- `point_name` (string): Name of the capture point + +--- + +## 4. Error Handling + +### Error Response Format + +If an error occurs, the Python server returns an error response: + +```json +{ + "tick": 1234, + "error": { + "code": "TOOL_EXECUTION_FAILED", + "message": "Agent foraging_agent_001 attempted invalid action: tool 'invalid_tool' not registered", + "agent_id": "foraging_agent_001" + }, + "actions": [] +} +``` + +### Error Codes + +| Code | Description | +|------|-------------| +| `TOOL_NOT_FOUND` | Requested tool not registered | +| `INVALID_PARAMETERS` | Tool parameters don't match schema | +| `AGENT_NOT_FOUND` | Agent ID doesn't exist | +| `LLM_TIMEOUT` | LLM failed to respond in time | +| `PARSING_ERROR` | Failed to parse LLM output | +| `TOOL_EXECUTION_FAILED` | Tool execution failed in Godot | + +--- + +## 5. Timing & Performance + +### Recommended Timing +- **Tick Rate**: 60 ticks/second (16.67ms per tick) +- **IPC Latency Budget**: < 5ms per request +- **LLM Response Time**: 100-1000ms (run async, queue actions) + +### Async Pattern (Recommended) + +For LLM backends with high latency: + +1. **Godot**: Send perception data (non-blocking) +2. **Python**: Queue perception, return previous action or "wait" +3. **Python**: Process LLM inference async in background +4. **Python**: Cache action for next tick +5. **Godot**: Use cached action on subsequent tick + +### Example Async Response + +```json +{ + "tick": 1234, + "actions": [ + { + "agent_id": "foraging_agent_001", + "action": { + "tool": "wait", + "params": {} + }, + "processing": true + } + ] +} +``` + +--- + +## 6. Testing & Debugging + +### Test Endpoints + +#### Health Check +``` +GET /health +``` + +**Response**: +```json +{ + "status": "ok", + "backend": "llama_cpp", + "agents_active": 3, + "uptime_seconds": 1234.5 +} +``` + +#### Echo Test +``` +POST /echo +``` + +**Request**: Any JSON +**Response**: Same JSON echoed back + +### Debug Logging + +Enable verbose IPC logging: + +**Godot** ([scripts/foraging.gd:112](scripts/foraging.gd#L112)): +```gdscript +# In _on_tick_advanced() +print("[IPC] Sending perception: ", perception_data) +``` + +**Python**: +```python +# In run_ipc_server.py +import logging +logging.basicConfig(level=logging.DEBUG) +``` + +### Mock Testing + +**Test Python without Godot**: +```python +# tests/test_ipc.py +import requests + +perception = { + "tick": 1, + "agents": [{...}] +} + +response = requests.post("http://127.0.0.1:5000/tick", json=perception) +print(response.json()) +``` + +**Test Godot without Python**: +Use the IPC test scene: [scenes/test_IPC.tscn](scenes/test_IPC.tscn) + +--- + +## 7. Future Enhancements + +### Planned Features +- **WebSocket support**: For lower latency bidirectional streaming +- **Compression**: MessagePack or protobuf for binary encoding +- **Batch processing**: Multiple ticks in single request +- **State synchronization**: Full world state snapshots +- **Replay streaming**: Send recorded events for analysis + +### Protocol Versioning + +Include version in all messages: + +```json +{ + "protocol_version": "0.1.0", + "tick": 1234, + ... +} +``` + +--- + +## 8. Schema Validation + +### Python Side (FastAPI) + +Use Pydantic models for validation: + +```python +from pydantic import BaseModel +from typing import List, Dict, Any + +class AgentObservation(BaseModel): + agent_id: str + observations: Dict[str, Any] + +class PerceptionRequest(BaseModel): + tick: int + timestamp: float + agents: List[AgentObservation] + +class ActionResponse(BaseModel): + tick: int + actions: List[Dict[str, Any]] +``` + +### Godot Side + +Validate in GDScript before sending: + +```gdscript +func validate_perception(data: Dictionary) -> bool: + return data.has("tick") and data.has("agents") +``` + +--- + +## Reference Implementation + +See: +- **Godot**: [scripts/tests/ipc_test.gd](scripts/tests/ipc_test.gd) +- **Python**: `python/run_ipc_server.py` +- **C++ IPCClient**: `godot/src/agent_arena.cpp` + +--- + +## Contact & Support + +Questions about the IPC protocol? Open an issue on GitHub: +https://github.com/JustInternetAI/AgentArena/issues diff --git a/docs/project_board.md b/docs/project_board.md new file mode 100644 index 0000000..0780e6d --- /dev/null +++ b/docs/project_board.md @@ -0,0 +1,448 @@ +# Agent Arena Project Board Structure + +This document describes the recommended GitHub Project Board setup for managing Agent Arena development. + +## Overview + +We use a **Kanban-style project board** to track issues, pull requests, and overall project progress. This provides visibility into what's being worked on and helps coordinate between team members. + +## Creating the Project Board + +### Via GitHub CLI + +```bash +cd "c:\Projects\Agent Arena" + +# Create project (v2) +gh project create --title "Agent Arena Development" --owner JustInternetAI + +# Note: GitHub Projects v2 uses a different CLI - use web interface for full setup +``` + +### Via GitHub Web Interface + +1. Go to https://github.com/JustInternetAI/AgentArena +2. Click **Projects** tab +3. Click **New project** +4. Choose **Board** template +5. Name: "Agent Arena Development" +6. Click **Create** + +## Board Columns + +### 1. Backlog +**Purpose**: Unprioritized ideas and future work + +**Contains**: +- Feature ideas not yet planned +- Low-priority bug fixes +- Future enhancements +- "Nice to have" items + +**Move to "Todo" when**: Item is prioritized for current sprint/milestone + +--- + +### 2. Todo +**Purpose**: Prioritized work ready to be started + +**Contains**: +- Issues assigned to upcoming work +- Prioritized bug fixes +- Planned features for current milestone +- Dependencies resolved + +**Move to "In Progress" when**: Someone starts working on it + +--- + +### 3. In Progress +**Purpose**: Work currently being done + +**Contains**: +- Issues actively being worked on +- PRs in draft or development +- Items with assignee actively coding + +**Move to "Review" when**: PR is created and ready for review + +**Limit**: Each person should have max 2-3 items here (avoid context switching) + +--- + +### 4. Review +**Purpose**: Code review and testing + +**Contains**: +- PRs awaiting code review +- Items needing testing +- Documentation needing review + +**Move to "Done" when**: PR is approved and merged + +**Move back to "In Progress" if**: Changes requested + +--- + +### 5. Done +**Purpose**: Completed work in current sprint + +**Contains**: +- Merged PRs +- Closed issues +- Completed milestones + +**Archive**: Clear monthly or per release + +--- + +## Custom Fields + +Add these custom fields to track additional metadata: + +### Priority +- **Type**: Single select +- **Options**: + - 🔴 Critical + - 🟠 High + - 🟡 Medium + - 🟢 Low + +### Component +- **Type**: Single select +- **Options**: + - Godot/C++ + - Python/Runtime + - Backends + - Memory + - Tools + - Scenes + - Documentation + - Testing + - IPC + +### Size +- **Type**: Single select +- **Options**: + - XS (< 2 hours) + - S (< 1 day) + - M (1-3 days) + - L (3-5 days) + - XL (> 1 week) + +### Sprint +- **Type**: Iteration +- **Duration**: 1 week +- **Use**: Track weekly work cycles + +## Automation Rules + +Set up GitHub Actions workflows to automate board movement: + +### Auto-move to "In Progress" +**Trigger**: Issue assigned or PR opened in draft +**Action**: Move to "In Progress" column + +### Auto-move to "Review" +**Trigger**: PR marked ready for review +**Action**: Move to "Review" column + +### Auto-move to "Done" +**Trigger**: PR merged or issue closed +**Action**: Move to "Done" column + +### Example Workflow + +Create `.github/workflows/project-automation.yml`: + +```yaml +name: Project Board Automation + +on: + issues: + types: [assigned, closed] + pull_request: + types: [opened, ready_for_review, closed] + +jobs: + update_board: + runs-on: ubuntu-latest + steps: + - name: Move assigned issues to In Progress + if: github.event.action == 'assigned' + uses: alex-page/github-project-automation-plus@v0.9.0 + with: + project: Agent Arena Development + column: In Progress + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Move PRs to Review + if: github.event.action == 'ready_for_review' + uses: alex-page/github-project-automation-plus@v0.9.0 + with: + project: Agent Arena Development + column: Review + repo-token: ${{ secrets.GITHUB_TOKEN }} + + - name: Move merged PRs to Done + if: github.event.pull_request.merged == true + uses: alex-page/github-project-automation-plus@v0.9.0 + with: + project: Agent Arena Development + column: Done + repo-token: ${{ secrets.GITHUB_TOKEN }} +``` + +## Initial Board Population + +### Week 1 Issues (Your Colleague - Python) + +**Backlog → Todo**: +1. Setup Python environment and requirements.txt (#1) +2. Implement BaseBackend abstract class (#2) +3. Implement FastAPI IPC server (#3) + +**Priority**: 🔴 Critical +**Component**: Python/Runtime +**Size**: S-M + +### Week 2 Issues (Your Colleague - Python) + +**Todo**: +4. Implement AgentRuntime class (#4) +5. Implement short-term memory system (#5) +6. Implement ToolDispatcher (#6) + +**Priority**: 🟠 High +**Component**: Python/Runtime, Memory, Tools +**Size**: M + +### Week 1-2 Issues (You - Godot/C++) + +**Todo**: +- Debug foraging scene collision detection +- Implement move_to tool execution in C++ +- Add visual improvements to benchmark scenes +- Fix resource collection radius detection + +**Priority**: 🟠 High +**Component**: Godot/C++, Scenes +**Size**: S-M + +### Week 3 Issues (Your Colleague - Python) + +**Todo**: +7. Implement LlamaCppBackend (#7) +8. Create Python unit test suite (#8) + +**Priority**: 🟡 Medium +**Component**: Backends, Testing +**Size**: M-L + +### Week 4 Issues (Both - Integration) + +**Todo**: +9. Create end-to-end integration test (#9) +10. Create Python development documentation (#10) + +**Priority**: 🟠 High +**Component**: Testing, Documentation +**Size**: M + +## Board Views + +Create multiple views for different perspectives: + +### 1. Default Board View (Kanban) +Shows all columns with cards + +### 2. Python Work View +**Filter**: `Component:Python/Runtime OR Component:Backends OR Component:Memory OR Component:Tools` +**Group by**: Status + +### 3. Godot Work View +**Filter**: `Component:Godot/C++ OR Component:Scenes` +**Group by**: Status + +### 4. Sprint View +**Filter**: `Sprint:Current` +**Group by**: Assignee +**Sort by**: Priority + +### 5. Priority View +**Group by**: Priority +**Sort by**: Size + +## Milestones + +Create milestones to track larger goals: + +### Milestone 1: Basic IPC Working +**Due**: Week 2 +**Issues**: +- #1 Python environment +- #2 BaseBackend +- #3 FastAPI IPC server +- Godot IPC client testing + +**Success criteria**: +- Godot can send perception data +- Python receives and returns action +- Integration test passes + +--- + +### Milestone 2: Agent Runtime Complete +**Due**: Week 3 +**Issues**: +- #4 AgentRuntime +- #5 Short-term memory +- #6 ToolDispatcher +- #8 Unit tests + +**Success criteria**: +- Agent can process observations +- Memory system working +- Tools can be called +- >80% test coverage + +--- + +### Milestone 3: LLM Integration +**Due**: Week 4 +**Issues**: +- #7 LlamaCppBackend +- Integration testing +- Documentation + +**Success criteria**: +- Real LLM can control agent +- Foraging scene works end-to-end +- Performance acceptable (< 1s per action) + +--- + +### Milestone 4: All Scenes Working +**Due**: Week 5-6 +**Issues**: +- Crafting chain scene complete +- Team capture scene complete +- Evaluation harness +- Metrics collection + +**Success criteria**: +- All 3 scenes functional +- Metrics tracked correctly +- Ready for benchmarking + +--- + +## Daily/Weekly Practices + +### Daily (Async) + +Each team member posts in GitHub Discussions or comments: + +``` +Status Update - 2025-11-11 + +Yesterday: Implemented LlamaCppBackend model loading +Today: Working on function calling integration +Blockers: Need clarification on tool schema format + +Board: Moved #7 to In Progress +``` + +### Weekly Sync + +**Monday**: +- Review board +- Prioritize Todo column +- Assign issues for the week +- Update milestone progress + +**Friday**: +- Demo completed work +- Move Done items to archive +- Retrospective: What went well? What to improve? +- Plan next week + +## Board Maintenance + +### Weekly +- Archive "Done" items older than 1 week +- Update issue priorities +- Reassign stale issues +- Close duplicate issues + +### Monthly +- Review backlog and close outdated items +- Update custom fields if needed +- Check milestone progress +- Adjust sprint duration if needed + +## Example Board State + +Here's what the board might look like in Week 2: + +``` +┌─────────────┬──────────────┬──────────────┬──────────────┬──────────────┐ +│ Backlog │ Todo │ In Progress │ Review │ Done │ +├─────────────┼──────────────┼──────────────┼──────────────┼──────────────┤ +│ #11 vLLM │ #4 Runtime │ #2 Backend │ #3 IPC PR │ #1 Python │ +│ backend │ (High,M) │ (Critical) │ (Review) │ env ✓ │ +│ │ │ @colleague │ │ │ +│ #12 Vision │ #5 Memory │ Scene debug │ │ │ +│ encoder │ (High,M) │ (High,S) │ │ │ +│ │ @colleague │ @you │ │ │ +│ #13 RL │ │ │ │ │ +│ training │ #6 Tools │ │ │ │ +│ │ (High,M) │ │ │ │ +│ │ │ │ │ │ +└─────────────┴──────────────┴──────────────┴──────────────┴──────────────┘ +``` + +## Tips for Effective Board Use + +1. **Keep it updated**: Move cards as work progresses +2. **Limit WIP**: Don't have too many items in "In Progress" +3. **Add details**: Comment on cards with progress updates +4. **Link PRs**: Link PRs to issues for automatic tracking +5. **Use labels**: Tag issues with component/priority +6. **Regular grooming**: Review and update board weekly +7. **Celebrate done**: Acknowledge completed work! + +## Integration with Issues + +When creating issues (see [github_issues.md](github_issues.md)), add them directly to the project: + +```bash +# Create issue and add to project +gh issue create \ + --title "Setup Python environment" \ + --label "python,setup,good-first-issue" \ + --project "Agent Arena Development" \ + --body "..." +``` + +Or use the web interface and select the project when creating the issue. + +## Resources + +- [GitHub Projects Documentation](https://docs.github.com/en/issues/planning-and-tracking-with-projects) +- [GitHub Projects Best Practices](https://github.com/features/issues) +- [Project Automation](https://docs.github.com/en/issues/planning-and-tracking-with-projects/automating-your-project) + +## Questions? + +Open a discussion on GitHub or ask in your team's communication channel. + +--- + +**Next Steps**: +1. Create the project board via GitHub web interface +2. Add the 5 columns (Backlog, Todo, In Progress, Review, Done) +3. Add custom fields (Priority, Component, Size, Sprint) +4. Populate with issues from [github_issues.md](github_issues.md) +5. Set up automation rules +6. Start using it! diff --git a/docs/team_onboarding.md b/docs/team_onboarding.md new file mode 100644 index 0000000..0cfab97 --- /dev/null +++ b/docs/team_onboarding.md @@ -0,0 +1,354 @@ +# Team Onboarding Guide + +Welcome to Agent Arena development! This guide will help you get started working collaboratively on the project. + +## Quick Links + +- 📋 [IPC Protocol Documentation](ipc_protocol.md) - Communication format between Godot and Python +- 🎯 [GitHub Issues List](github_issues.md) - Pre-written issues ready to assign +- 🤝 [Contributing Guidelines](../CONTRIBUTING.md) - Development workflow and standards +- 📊 [Project Board Setup](project_board.md) - Kanban board structure and usage + +## Getting Started Checklist + +### For Your Colleague (Python Focus) + +- [ ] Clone the repository: `git clone https://github.com/JustInternetAI/AgentArena.git` +- [ ] Read [architecture.md](architecture.md) to understand the system +- [ ] Read [ipc_protocol.md](ipc_protocol.md) for the communication contract +- [ ] Set up Python environment (see Issue #1 in [github_issues.md](github_issues.md)) +- [ ] Create feature branch: `git checkout -b feature/python-setup` +- [ ] Review assigned issues on the project board +- [ ] Join communication channels (Discord/Slack if configured) + +### For You (Godot Focus) + +- [ ] Continue debugging benchmark scenes +- [ ] Implement tool execution in C++ (move_to, collect, etc.) +- [ ] Add collision detection for resources/hazards +- [ ] Improve scene visuals (materials, particles) +- [ ] Test IPC client with mock Python responses + +## Work Division + +### Python/Agent Runtime (Your Colleague) +**Primary Ownership**: +- `python/**/*.py` - All Python code +- `configs/**/*.yaml` - Configuration files +- `tests/**/*.py` - Python unit tests +- `requirements.txt` - Dependencies + +**Key Tasks**: +1. Setup Python environment (Week 1) +2. Implement BaseBackend and IPC server (Week 1) +3. Implement AgentRuntime, Memory, Tools (Week 2) +4. Add LlamaCppBackend (Week 3) +5. Create unit tests and documentation (Week 3-4) + +**Start with**: Issues #1, #2, #3 from [github_issues.md](github_issues.md) + +--- + +### Godot/Simulation (You) +**Primary Ownership**: +- `godot/**/*` - C++ GDExtension code +- `scenes/**/*.tscn` - Godot scenes +- `scripts/**/*.gd` - GDScript files +- Scene balancing and visuals + +**Key Tasks**: +1. Debug and refine benchmark scenes (Week 1-2) +2. Implement tool execution in C++ (Week 1-2) +3. Add collision detection and physics (Week 2) +4. Visual improvements (Week 2-3) +5. IPC client testing and refinement (Week 3) + +**Focus areas**: Foraging, Crafting Chain, Team Capture scenes + +--- + +### Shared/Integration (Both) +**Coordinate before modifying**: +- `docs/**/*.md` - Documentation +- `README.md` - Project overview +- `.claude/project-context.md` - Project context +- Integration testing + +**Collaborative work**: +- Week 4: End-to-end integration testing +- IPC protocol refinements +- Performance optimization + +## Communication Plan + +### Daily Updates (Async) + +Post brief updates in your team channel: + +**Format**: +``` +📅 [Date] +✅ Yesterday: [What you completed] +🔄 Today: [What you're working on] +🚫 Blockers: [Any issues/questions] +``` + +**Example**: +``` +📅 2025-11-11 +✅ Yesterday: Implemented BaseBackend abstract class +🔄 Today: Working on FastAPI IPC server +🚫 Blockers: Need clarification on action response format +``` + +### Weekly Sync + +**Every Monday** (30 mins): +- Review project board +- Demo progress from last week +- Discuss blockers +- Assign issues for current week +- Update milestones + +**Every Friday** (15 mins): +- Quick retrospective +- Celebrate wins +- Note improvements for next week + +### Pull Request Protocol + +1. **Create PR early** (can be draft) +2. **Tag relevant person** for review +3. **Respond to feedback** within 24 hours +4. **Merge** once approved + +**Review SLA**: 24-48 hours for PR review + +## Integration Checkpoints + +### Week 1 Checkpoint: Basic IPC +**Goal**: Godot and Python can communicate + +**Success Criteria**: +- [ ] Python IPC server running +- [ ] Godot can send perception data +- [ ] Python returns action response +- [ ] No errors in communication + +**Test**: Run [scenes/test_IPC.tscn](../scenes/test_IPC.tscn) + +--- + +### Week 2 Checkpoint: Agent Runtime +**Goal**: Agent can process observations + +**Success Criteria**: +- [ ] AgentRuntime processes observations +- [ ] Short-term memory stores recent data +- [ ] ToolDispatcher validates tool calls +- [ ] Unit tests pass (>80% coverage) + +**Test**: Send mock perception, verify memory and tool parsing + +--- + +### Week 3 Checkpoint: LLM Integration +**Goal**: Real LLM controls agent + +**Success Criteria**: +- [ ] LlamaCppBackend loads model +- [ ] LLM generates valid tool calls +- [ ] Foraging scene works end-to-end +- [ ] Performance acceptable (<1s per action) + +**Test**: Agent collects resources in foraging scene using LLM decisions + +--- + +### Week 4 Checkpoint: All Scenes +**Goal**: All benchmarks functional + +**Success Criteria**: +- [ ] Foraging scene complete ✓ +- [ ] Crafting chain scene complete +- [ ] Team capture scene complete +- [ ] Metrics tracked correctly +- [ ] Documentation updated + +**Test**: Run all three scenes with LLM agents, collect metrics + +## Troubleshooting + +### IPC Connection Issues + +**Problem**: Python server not responding + +**Check**: +1. Is server running? `python python/run_ipc_server.py` +2. Correct port? Default is 5000 +3. Firewall blocking? Check Windows Firewall +4. Check server logs for errors + +**Solution**: See [ipc_protocol.md - Testing & Debugging](ipc_protocol.md#6-testing--debugging) + +--- + +### Merge Conflicts + +**Problem**: Can't merge due to conflicts + +**Solution**: +```bash +# Update main +git checkout main +git pull origin main + +# Rebase your branch +git checkout your-branch +git rebase main + +# Resolve conflicts in editor +# Then continue rebase +git add . +git rebase --continue + +# Force push (with lease for safety) +git push origin your-branch --force-with-lease +``` + +--- + +### Python Import Errors + +**Problem**: Module not found when running Python code + +**Solution**: +```bash +# Make sure venv is activated +cd python +venv\Scripts\activate # Windows +source venv/bin/activate # Linux/Mac + +# Reinstall dependencies +pip install -r requirements.txt + +# Add python directory to PYTHONPATH if needed +export PYTHONPATH="${PYTHONPATH}:${PWD}" +``` + +--- + +### Godot Extension Not Loading + +**Problem**: C++ extension not showing in Godot + +**Solution**: +1. Rebuild extension: + ```bash + cd godot/build + cmake --build . --config Debug + ``` +2. Check DLL is in `bin/windows/` +3. Verify `agent_arena.gdextension` paths are correct +4. Restart Godot editor +5. Check Godot console for error messages + +## Resources + +### Documentation +- [Architecture Overview](architecture.md) +- [IPC Protocol](ipc_protocol.md) +- [Quickstart Guide](quickstart.md) +- [Testing Guide](../TESTING.md) + +### External Resources +- [Godot Documentation](https://docs.godotengine.org/) +- [FastAPI Documentation](https://fastapi.tiangolo.com/) +- [llama-cpp-python](https://github.com/abetlen/llama-cpp-python) +- [Hydra Configuration](https://hydra.cc/) + +### GitHub +- [Repository](https://github.com/JustInternetAI/AgentArena) +- [Issues](https://github.com/JustInternetAI/AgentArena/issues) +- [Pull Requests](https://github.com/JustInternetAI/AgentArena/pulls) +- [Discussions](https://github.com/JustInternetAI/AgentArena/discussions) + +## First Week Action Items + +### Your Colleague's Week 1 + +**Monday-Tuesday**: +- [ ] Read architecture.md and ipc_protocol.md +- [ ] Setup development environment +- [ ] Create Issue #1 branch +- [ ] Complete Python environment setup +- [ ] Create PR for requirements.txt + +**Wednesday-Thursday**: +- [ ] Implement BaseBackend (Issue #2) +- [ ] Write unit tests +- [ ] Create PR + +**Friday**: +- [ ] Implement FastAPI IPC server (Issue #3) +- [ ] Test with mock Godot client +- [ ] Demo in weekly sync + +--- + +### Your Week 1 + +**Monday-Tuesday**: +- [ ] Debug foraging scene collision detection +- [ ] Fix resource collection radius +- [ ] Test hazard damage system + +**Wednesday-Thursday**: +- [ ] Implement move_to tool in C++ +- [ ] Add pathfinding basics +- [ ] Test tool execution + +**Friday**: +- [ ] Visual improvements (colors, shapes) +- [ ] Test IPC with colleague's server +- [ ] Demo in weekly sync + +## Questions? + +- **Technical questions**: Open GitHub Discussion +- **Bugs**: Create GitHub Issue +- **Urgent blockers**: Direct message +- **General chat**: Team channel + +## Next Steps + +1. **Review all 4 documents**: + - [ipc_protocol.md](ipc_protocol.md) + - [github_issues.md](github_issues.md) + - [CONTRIBUTING.md](../CONTRIBUTING.md) + - [project_board.md](project_board.md) + +2. **Set up GitHub Project Board**: + - Create board via web interface + - Add columns and custom fields + - Populate with issues + +3. **Create initial issues**: + - Copy from [github_issues.md](github_issues.md) + - Assign to appropriate person + - Add to project board + +4. **Schedule first sync**: + - Pick a recurring time + - Add to calendars + - Set up call link + +5. **Start developing**! + - Create feature branches + - Make commits + - Push regularly + - Open PRs + +--- + +**Welcome aboard! Let's build something amazing together! 🚀🤖** diff --git a/scenes/crafting_chain.tscn b/scenes/crafting_chain.tscn new file mode 100644 index 0000000..a9cc07b --- /dev/null +++ b/scenes/crafting_chain.tscn @@ -0,0 +1,103 @@ +[gd_scene load_steps=3 format=3 uid="uid://crafting_chain_scene"] + +[ext_resource type="Script" path="res://scripts/crafting_chain.gd" id="1_crafting"] + +[sub_resource type="BoxMesh" id="BoxMesh_ground"] +size = Vector3(40, 0.5, 40) + +[node name="CraftingChainScene" type="Node3D"] +script = ExtResource("1_crafting") + +[node name="SimulationManager" type="SimulationManager" parent="."] + +[node name="EventBus" type="EventBus" parent="."] + +[node name="ToolRegistry" type="ToolRegistry" parent="."] + +[node name="Environment" type="Node3D" parent="."] + +[node name="Ground" type="MeshInstance3D" parent="Environment"] +mesh = SubResource("BoxMesh_ground") +skeleton = NodePath("../..") + +[node name="DirectionalLight3D" type="DirectionalLight3D" parent="Environment"] +transform = Transform3D(1, 0, 0, 0, 0.707107, 0.707107, 0, -0.707107, 0.707107, 0, 10, 10) +shadow_enabled = true + +[node name="BaseResources" type="Node3D" parent="."] + +[node name="IronOre1" type="Area3D" parent="BaseResources"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -10, 0.5, -10) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="BaseResources/IronOre1"] +mesh = SubResource("BoxMesh_ground") + +[node name="IronOre2" type="Area3D" parent="BaseResources"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -12, 0.5, -8) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="BaseResources/IronOre2"] +mesh = SubResource("BoxMesh_ground") + +[node name="Wood1" type="Area3D" parent="BaseResources"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -8, 0.5, -12) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="BaseResources/Wood1"] +mesh = SubResource("BoxMesh_ground") + +[node name="Wood2" type="Area3D" parent="BaseResources"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -10, 0.5, -14) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="BaseResources/Wood2"] +mesh = SubResource("BoxMesh_ground") + +[node name="Coal1" type="Area3D" parent="BaseResources"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 10, 0.5, -10) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="BaseResources/Coal1"] +mesh = SubResource("BoxMesh_ground") + +[node name="Coal2" type="Area3D" parent="BaseResources"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 12, 0.5, -12) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="BaseResources/Coal2"] +mesh = SubResource("BoxMesh_ground") + +[node name="CraftingStations" type="Node3D" parent="."] + +[node name="Furnace" type="Area3D" parent="CraftingStations"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, -5) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="CraftingStations/Furnace"] +mesh = SubResource("BoxMesh_ground") + +[node name="Anvil" type="Area3D" parent="CraftingStations"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="CraftingStations/Anvil"] +mesh = SubResource("BoxMesh_ground") + +[node name="Workbench" type="Area3D" parent="CraftingStations"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 5) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="CraftingStations/Workbench"] +mesh = SubResource("BoxMesh_ground") + +[node name="Agents" type="Node3D" parent="."] + +[node name="Agent1" type="Agent" parent="Agents"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 10) + +[node name="Camera3D" type="Camera3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 0.707107, 0.707107, 0, -0.707107, 0.707107, 0, 20, 20) +current = true + +[node name="UI" type="CanvasLayer" parent="."] + +[node name="MetricsLabel" type="Label" parent="UI"] +offset_right = 500.0 +offset_bottom = 200.0 +text = "Crafting Chain Benchmark +Items Crafted: 0 +Recipe Efficiency: 0% +Resource Waste: 0 +Crafting Time: 0s" diff --git a/scenes/foraging.tscn b/scenes/foraging.tscn new file mode 100644 index 0000000..1186f09 --- /dev/null +++ b/scenes/foraging.tscn @@ -0,0 +1,119 @@ +[gd_scene load_steps=3 format=3 uid="uid://foraging_scene"] + +[ext_resource type="Script" path="res://scripts/foraging.gd" id="1_foraging"] + +[sub_resource type="BoxMesh" id="BoxMesh_ground"] +size = Vector3(50, 0.5, 50) + +[node name="ForagingScene" type="Node3D"] +script = ExtResource("1_foraging") + +[node name="SimulationManager" type="SimulationManager" parent="."] + +[node name="EventBus" type="EventBus" parent="."] + +[node name="ToolRegistry" type="ToolRegistry" parent="."] + +[node name="Environment" type="Node3D" parent="."] + +[node name="Ground" type="MeshInstance3D" parent="Environment"] +mesh = SubResource("BoxMesh_ground") +skeleton = NodePath("../..") + +[node name="DirectionalLight3D" type="DirectionalLight3D" parent="Environment"] +transform = Transform3D(1, 0, 0, 0, 0.707107, 0.707107, 0, -0.707107, 0.707107, 0, 10, 10) +shadow_enabled = true + +[node name="Resources" type="Node3D" parent="."] + +[node name="Berry1" type="Area3D" parent="Resources"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 5, 0.5, 5) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="Resources/Berry1"] +mesh = SubResource("BoxMesh_ground") +skeleton = NodePath("../../..") + +[node name="Berry2" type="Area3D" parent="Resources"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -8, 0.5, 3) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="Resources/Berry2"] +mesh = SubResource("BoxMesh_ground") +skeleton = NodePath("../../..") + +[node name="Berry3" type="Area3D" parent="Resources"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 10, 0.5, -7) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="Resources/Berry3"] +mesh = SubResource("BoxMesh_ground") +skeleton = NodePath("../../..") + +[node name="Wood1" type="Area3D" parent="Resources"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -5, 0.5, -5) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="Resources/Wood1"] +mesh = SubResource("BoxMesh_ground") +skeleton = NodePath("../../..") + +[node name="Wood2" type="Area3D" parent="Resources"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 12, 0.5, 8) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="Resources/Wood2"] +mesh = SubResource("BoxMesh_ground") +skeleton = NodePath("../../..") + +[node name="Stone1" type="Area3D" parent="Resources"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 10) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="Resources/Stone1"] +mesh = SubResource("BoxMesh_ground") +skeleton = NodePath("../../..") + +[node name="Stone2" type="Area3D" parent="Resources"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -10, 0.5, -8) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="Resources/Stone2"] +mesh = SubResource("BoxMesh_ground") +skeleton = NodePath("../../..") + +[node name="Hazards" type="Node3D" parent="."] + +[node name="Fire1" type="Area3D" parent="Hazards"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 7, 0.5, -3) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="Hazards/Fire1"] +mesh = SubResource("BoxMesh_ground") +skeleton = NodePath("../../..") + +[node name="Fire2" type="Area3D" parent="Hazards"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3, 0.5, 7) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="Hazards/Fire2"] +mesh = SubResource("BoxMesh_ground") +skeleton = NodePath("../../..") + +[node name="Pit1" type="Area3D" parent="Hazards"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, -12) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="Hazards/Pit1"] +mesh = SubResource("BoxMesh_ground") +skeleton = NodePath("../../..") + +[node name="Agents" type="Node3D" parent="."] + +[node name="Agent1" type="Agent" parent="Agents"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0) + +[node name="Camera3D" type="Camera3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 0.707107, 0.707107, 0, -0.707107, 0.707107, 0, 20, 20) +current = true + +[node name="UI" type="CanvasLayer" parent="."] + +[node name="MetricsLabel" type="Label" parent="UI"] +offset_right = 400.0 +offset_bottom = 150.0 +text = "Foraging Benchmark +Resources Collected: 0 +Damage Taken: 0 +Distance Traveled: 0 +Time Elapsed: 0s" diff --git a/scenes/team_capture.tscn b/scenes/team_capture.tscn new file mode 100644 index 0000000..1e0b57c --- /dev/null +++ b/scenes/team_capture.tscn @@ -0,0 +1,94 @@ +[gd_scene load_steps=3 format=3 uid="uid://team_capture_scene"] + +[ext_resource type="Script" path="res://scripts/team_capture.gd" id="1_team_capture"] + +[sub_resource type="BoxMesh" id="BoxMesh_ground"] +size = Vector3(60, 0.5, 60) + +[node name="TeamCaptureScene" type="Node3D"] +script = ExtResource("1_team_capture") + +[node name="SimulationManager" type="SimulationManager" parent="."] + +[node name="EventBus" type="EventBus" parent="."] + +[node name="ToolRegistry" type="ToolRegistry" parent="."] + +[node name="Environment" type="Node3D" parent="."] + +[node name="Ground" type="MeshInstance3D" parent="Environment"] +mesh = SubResource("BoxMesh_ground") +skeleton = NodePath("../..") + +[node name="DirectionalLight3D" type="DirectionalLight3D" parent="Environment"] +transform = Transform3D(1, 0, 0, 0, 0.707107, 0.707107, 0, -0.707107, 0.707107, 0, 15, 15) +shadow_enabled = true + +[node name="CapturePoints" type="Node3D" parent="."] + +[node name="CapturePointA" type="Area3D" parent="CapturePoints"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -15, 0.5, -15) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="CapturePoints/CapturePointA"] +mesh = SubResource("BoxMesh_ground") + +[node name="CapturePointB" type="Area3D" parent="CapturePoints"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 15, 0.5, -15) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="CapturePoints/CapturePointB"] +mesh = SubResource("BoxMesh_ground") + +[node name="CapturePointC" type="Area3D" parent="CapturePoints"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.5, 0) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="CapturePoints/CapturePointC"] +mesh = SubResource("BoxMesh_ground") + +[node name="CapturePointD" type="Area3D" parent="CapturePoints"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -15, 0.5, 15) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="CapturePoints/CapturePointD"] +mesh = SubResource("BoxMesh_ground") + +[node name="CapturePointE" type="Area3D" parent="CapturePoints"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 15, 0.5, 15) + +[node name="MeshInstance3D" type="MeshInstance3D" parent="CapturePoints/CapturePointE"] +mesh = SubResource("BoxMesh_ground") + +[node name="TeamBlue" type="Node3D" parent="."] + +[node name="BlueAgent1" type="Agent" parent="TeamBlue"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -20, 1, -20) + +[node name="BlueAgent2" type="Agent" parent="TeamBlue"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -22, 1, -18) + +[node name="BlueAgent3" type="Agent" parent="TeamBlue"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -18, 1, -22) + +[node name="TeamRed" type="Node3D" parent="."] + +[node name="RedAgent1" type="Agent" parent="TeamRed"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 20, 1, 20) + +[node name="RedAgent2" type="Agent" parent="TeamRed"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 22, 1, 18) + +[node name="RedAgent3" type="Agent" parent="TeamRed"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 18, 1, 22) + +[node name="Camera3D" type="Camera3D" parent="."] +transform = Transform3D(1, 0, 0, 0, 0.707107, 0.707107, 0, -0.707107, 0.707107, 0, 30, 30) +current = true + +[node name="UI" type="CanvasLayer" parent="."] + +[node name="MetricsLabel" type="Label" parent="UI"] +offset_right = 500.0 +offset_bottom = 250.0 +text = "Team Capture Benchmark +Objectives Captured: 0/5 +Team Blue Score: 0 +Team Red Score: 0 +Time Elapsed: 0s" From 360da245adac400d54b5a764767037eb83873c03 Mon Sep 17 00:00:00 2001 From: justinmadison Date: Mon, 10 Nov 2025 12:45:59 -0800 Subject: [PATCH 3/3] Add scripts directory and configure godot-cpp as submodul --- .gitmodules | 3 + external/godot-cpp | 1 + scripts | 1 - scripts/README.md | 106 ++++++ scripts/crafting_chain.gd | 548 +++++++++++++++++++++++++++ scripts/crafting_chain.gd.uid | 1 + scripts/foraging.gd | 397 +++++++++++++++++++ scripts/foraging.gd.uid | 1 + scripts/init_github.bat | 94 +++++ scripts/init_github.sh | 108 ++++++ scripts/setup.bat | 111 ++++++ scripts/setup.sh | 104 +++++ scripts/setup_godot_cpp.bat | 30 ++ scripts/setup_godot_cpp.sh | 29 ++ scripts/team_capture.gd | 569 ++++++++++++++++++++++++++++ scripts/team_capture.gd.uid | 1 + scripts/test_arena.gd | 121 ++++++ scripts/test_arena.gd.uid | 1 + scripts/tests/ipc_test.gd | 113 ++++++ scripts/tests/ipc_test.gd.uid | 1 + scripts/tests/test_extension.gd | 36 ++ scripts/tests/test_extension.gd.uid | 1 + 22 files changed, 2376 insertions(+), 1 deletion(-) create mode 100644 .gitmodules create mode 160000 external/godot-cpp delete mode 160000 scripts create mode 100644 scripts/README.md create mode 100644 scripts/crafting_chain.gd create mode 100644 scripts/crafting_chain.gd.uid create mode 100644 scripts/foraging.gd create mode 100644 scripts/foraging.gd.uid create mode 100644 scripts/init_github.bat create mode 100644 scripts/init_github.sh create mode 100644 scripts/setup.bat create mode 100644 scripts/setup.sh create mode 100644 scripts/setup_godot_cpp.bat create mode 100644 scripts/setup_godot_cpp.sh create mode 100644 scripts/team_capture.gd create mode 100644 scripts/team_capture.gd.uid create mode 100644 scripts/test_arena.gd create mode 100644 scripts/test_arena.gd.uid create mode 100644 scripts/tests/ipc_test.gd create mode 100644 scripts/tests/ipc_test.gd.uid create mode 100644 scripts/tests/test_extension.gd create mode 100644 scripts/tests/test_extension.gd.uid diff --git a/.gitmodules b/.gitmodules new file mode 100644 index 0000000..a102094 --- /dev/null +++ b/.gitmodules @@ -0,0 +1,3 @@ +[submodule "external/godot-cpp"] + path = external/godot-cpp + url = https://github.com/godotengine/godot-cpp.git diff --git a/external/godot-cpp b/external/godot-cpp new file mode 160000 index 0000000..e83fd09 --- /dev/null +++ b/external/godot-cpp @@ -0,0 +1 @@ +Subproject commit e83fd0904c13356ed1d4c3d09f8bb9132bdc6b77 diff --git a/scripts b/scripts deleted file mode 160000 index 751d1ca..0000000 --- a/scripts +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 751d1caccfb77de5d9d14b2311a908322f4fdbfa diff --git a/scripts/README.md b/scripts/README.md new file mode 100644 index 0000000..c2ea5a8 --- /dev/null +++ b/scripts/README.md @@ -0,0 +1,106 @@ +# Scripts Directory + +This directory contains GDScript files and GitHub automation scripts for the Agent Arena project. + +## GitHub Setup Scripts (*.bat / *.sh) + +Scripts for creating GitHub labels and issues. + +### Quick Start + +Run these scripts **in order**: + +#### Step 1: Create Labels First + +```bash +scripts\create_github_labels.bat +``` + +This creates all necessary labels (backend, python, enhancement, high-priority, etc.). + +**Note**: Labels must exist before you can assign them to issues! + +#### Step 2: Create Issues + +```bash +scripts\create_github_issues.bat +``` + +This creates the initial backlog issues with proper labels. + +See [GitHub CLI Guide](../docs/github_cli_guide.md) for more details. + +--- + +## GDScript Files + +All GDScript files for the Godot simulation. + +## Organization + +``` +scripts/ +├── tests/ # Test and diagnostic scripts +│ ├── test_extension.gd # Tests that all GDExtension classes load correctly +│ └── ipc_test.gd # Tests IPC communication between Godot and Python +└── test_arena.gd # Main test arena scene script +``` + +## Running Scripts + +### Test Scripts + +**Test Extension Loading:** +``` +1. Open scripts/tests/test_extension.gd in Godot +2. Press F6 (Run Current Scene) +3. Check console for results +``` + +**Test IPC Communication:** +``` +1. Start Python IPC server: + cd python + python run_ipc_server.py + +2. Open scripts/tests/ipc_test.gd in Godot +3. Press F6 (Run Current Scene) +4. Watch both consoles for communication +``` + +## Best Practices + +### File Naming +- Use `snake_case` for script filenames +- Test scripts should start with `test_` +- Keep scripts focused on single responsibilities + +### Directory Structure +- **Root scripts**: Main game/simulation scripts +- **tests/**: Diagnostic and test scripts +- **ui/**: UI-related scripts (to be added) +- **gameplay/**: Gameplay mechanics (to be added) + +### Script Organization +- Scene-specific scripts go in `scripts/` and reference `.tscn` files in `scenes/` +- Keep `.gd` scripts separate from `.tscn` scene files for better version control +- Reusable components should be in their own files + +## Creating New Scripts + +When creating a new script: +1. Decide if it's a test, UI, or gameplay script +2. Create it in the appropriate subdirectory +3. Use clear, descriptive names +4. Add documentation comments at the top + +Example: +```gdscript +# scripts/ui/main_menu.gd +# Main menu UI controller +# Handles menu navigation and settings + +extends Control + +# ... implementation +``` diff --git a/scripts/crafting_chain.gd b/scripts/crafting_chain.gd new file mode 100644 index 0000000..84f126c --- /dev/null +++ b/scripts/crafting_chain.gd @@ -0,0 +1,548 @@ +extends Node3D + +## Crafting Chain Benchmark Scene +## Goal: Craft complex items from base resources using crafting stations +## Metrics: Items crafted, recipe efficiency, resource waste, crafting time + +@onready var simulation_manager = $SimulationManager +@onready var event_bus = $EventBus +@onready var tool_registry = $ToolRegistry +@onready var agent = $Agents/Agent1 +@onready var metrics_label = $UI/MetricsLabel + +# Scene configuration +const COLLECTION_RADIUS = 2.0 +const CRAFTING_RADIUS = 2.5 +const TARGET_ITEM = "iron_sword" # Final item to craft + +# Crafting recipes +const RECIPES = { + "iron_ingot": { + "inputs": {"iron_ore": 1, "coal": 1}, + "station": "Furnace", + "time": 3.0 + }, + "iron_rod": { + "inputs": {"iron_ingot": 1}, + "station": "Anvil", + "time": 2.0 + }, + "wooden_handle": { + "inputs": {"wood": 2}, + "station": "Workbench", + "time": 2.0 + }, + "iron_sword": { + "inputs": {"iron_rod": 1, "wooden_handle": 1}, + "station": "Anvil", + "time": 4.0 + } +} + +# Metrics +var items_crafted = {} # Dict of item_name: count +var total_items_crafted = 0 +var resources_collected = 0 +var resources_used = 0 +var resources_wasted = 0 +var crafting_attempts = 0 +var successful_crafts = 0 +var start_time = 0.0 +var total_crafting_time = 0.0 +var scene_completed = false + +# Inventory +var agent_inventory = {} + +# Scene elements +var base_resources = [] +var crafting_stations = [] +var current_craft = null # Current crafting operation + +func _ready(): + print("Crafting Chain Benchmark Scene Ready!") + + # Verify C++ nodes + if simulation_manager == null or agent == null: + push_error("GDExtension nodes not found!") + return + + # Initialize agent + agent.agent_id = "crafting_agent_001" + + # Connect signals + simulation_manager.simulation_started.connect(_on_simulation_started) + simulation_manager.simulation_stopped.connect(_on_simulation_stopped) + simulation_manager.tick_advanced.connect(_on_tick_advanced) + agent.action_decided.connect(_on_agent_action_decided) + + # Register tools + _register_tools() + + # Initialize scene + _initialize_scene() + + print("Base resources: ", base_resources.size()) + print("Crafting stations: ", crafting_stations.size()) + print("Recipes available: ", RECIPES.keys()) + +func _register_tools(): + """Register available tools for the agent""" + if tool_registry == null: + return + + # Movement + tool_registry.register_tool("move_to", { + "name": "move_to", + "description": "Move to a target position", + "parameters": { + "target_x": {"type": "float"}, + "target_y": {"type": "float"}, + "target_z": {"type": "float"} + } + }) + + # Collection + tool_registry.register_tool("collect", { + "name": "collect", + "description": "Collect a nearby resource", + "parameters": { + "resource_name": {"type": "string"} + } + }) + + # Crafting + tool_registry.register_tool("craft", { + "name": "craft", + "description": "Craft an item at a nearby station", + "parameters": { + "item_name": {"type": "string"}, + "station_name": {"type": "string"} + } + }) + + # Query + tool_registry.register_tool("query_inventory", { + "name": "query_inventory", + "description": "Check current inventory", + "parameters": {} + }) + + tool_registry.register_tool("query_recipes", { + "name": "query_recipes", + "description": "Get available crafting recipes", + "parameters": {} + }) + +func _initialize_scene(): + """Initialize resources and stations""" + base_resources.clear() + crafting_stations.clear() + agent_inventory.clear() + items_crafted.clear() + + # Collect base resources + var resources_node = $BaseResources + for child in resources_node.get_children(): + if child is Area3D: + base_resources.append({ + "name": child.name, + "position": child.global_position, + "type": _get_resource_type(child.name), + "collected": false, + "node": child + }) + + # Collect crafting stations + var stations_node = $CraftingStations + for child in stations_node.get_children(): + if child is Area3D: + crafting_stations.append({ + "name": child.name, + "position": child.global_position, + "type": child.name.to_lower(), + "node": child + }) + +func _get_resource_type(resource_name: String) -> String: + """Extract resource type from name""" + if "IronOre" in resource_name: + return "iron_ore" + elif "Wood" in resource_name: + return "wood" + elif "Coal" in resource_name: + return "coal" + return "unknown" + +func _process(_delta): + _update_metrics_ui() + + # Update crafting progress + if current_craft != null: + _update_crafting() + +func _input(event): + if simulation_manager == null: + return + + if event is InputEventKey and event.pressed: + if event.keycode == KEY_SPACE: + if simulation_manager.is_running: + simulation_manager.stop_simulation() + else: + simulation_manager.start_simulation() + elif event.keycode == KEY_R: + _reset_scene() + elif event.keycode == KEY_S: + simulation_manager.step_simulation() + elif event.keycode == KEY_I: + _print_inventory() + +func _on_simulation_started(): + print("✓ Crafting chain benchmark started!") + start_time = Time.get_ticks_msec() / 1000.0 + scene_completed = false + +func _on_simulation_stopped(): + print("✓ Crafting chain benchmark stopped!") + _print_final_metrics() + +func _on_tick_advanced(tick: int): + # Check for resource collection + _check_resource_collection() + + # Send perception to agent + _send_perception_to_agent() + + # Check completion + if agent_inventory.get(TARGET_ITEM, 0) > 0: + _complete_scene() + +func _check_resource_collection(): + """Auto-collect nearby resources""" + var agent_pos = agent.global_position + + for resource in base_resources: + if resource.collected: + continue + + var dist = agent_pos.distance_to(resource.position) + if dist <= COLLECTION_RADIUS: + _collect_resource(resource) + +func _collect_resource(resource: Dictionary): + """Collect a resource and add to inventory""" + if resource.collected: + return + + resource.collected = true + resources_collected += 1 + + # Add to inventory + var item_type = resource.type + agent_inventory[item_type] = agent_inventory.get(item_type, 0) + 1 + + # Hide the node + if resource.node != null: + resource.node.visible = false + + # Record event + if event_bus != null: + event_bus.emit_event({ + "type": "resource_collected", + "resource_name": resource.name, + "resource_type": resource.type, + "tick": simulation_manager.current_tick + }) + + print("✓ Collected %s (Inventory: %s)" % [resource.name, str(agent_inventory)]) + +func craft_item(item_name: String, station_name: String) -> bool: + """Attempt to craft an item""" + crafting_attempts += 1 + + # Check if recipe exists + if not RECIPES.has(item_name): + print("✗ Unknown recipe: %s" % item_name) + return false + + var recipe = RECIPES[item_name] + + # Check if at correct station + var agent_pos = agent.global_position + var at_station = false + for station in crafting_stations: + if station.name.to_lower() == station_name.to_lower(): + var dist = agent_pos.distance_to(station.position) + if dist <= CRAFTING_RADIUS: + at_station = true + break + + if not at_station: + print("✗ Not at correct crafting station: %s" % station_name) + return false + + # Check if correct station type + if recipe.station.to_lower() != station_name.to_lower(): + print("✗ Wrong station. Need %s, at %s" % [recipe.station, station_name]) + return false + + # Check if we have required materials + for input_item in recipe.inputs.keys(): + var required_amount = recipe.inputs[input_item] + var current_amount = agent_inventory.get(input_item, 0) + if current_amount < required_amount: + print("✗ Missing materials for %s. Need %d %s, have %d" % + [item_name, required_amount, input_item, current_amount]) + return false + + # Start crafting + current_craft = { + "item_name": item_name, + "recipe": recipe, + "start_time": Time.get_ticks_msec() / 1000.0, + "duration": recipe.time + } + + # Consume materials + for input_item in recipe.inputs.keys(): + var amount = recipe.inputs[input_item] + agent_inventory[input_item] -= amount + resources_used += amount + + print("⚙ Crafting %s at %s (%.1fs)..." % [item_name, station_name, recipe.time]) + return true + +func _update_crafting(): + """Update current crafting operation""" + if current_craft == null: + return + + var elapsed = (Time.get_ticks_msec() / 1000.0) - current_craft.start_time + if elapsed >= current_craft.duration: + _complete_craft() + +func _complete_craft(): + """Complete the current craft""" + if current_craft == null: + return + + var item_name = current_craft.item_name + + # Add crafted item to inventory + agent_inventory[item_name] = agent_inventory.get(item_name, 0) + 1 + + # Update metrics + items_crafted[item_name] = items_crafted.get(item_name, 0) + 1 + total_items_crafted += 1 + successful_crafts += 1 + total_crafting_time += current_craft.duration + + # Record event + if event_bus != null: + event_bus.emit_event({ + "type": "item_crafted", + "item_name": item_name, + "tick": simulation_manager.current_tick + }) + + print("✓ Crafted %s! (Inventory: %s)" % [item_name, str(agent_inventory)]) + + current_craft = null + +func _send_perception_to_agent(): + """Send world observations to agent""" + var agent_pos = agent.global_position + + # Find nearby resources + var nearby_resources = [] + for resource in base_resources: + if not resource.collected: + var dist = agent_pos.distance_to(resource.position) + nearby_resources.append({ + "name": resource.name, + "type": resource.type, + "position": resource.position, + "distance": dist + }) + + # Find nearby stations + var nearby_stations = [] + for station in crafting_stations: + var dist = agent_pos.distance_to(station.position) + nearby_stations.append({ + "name": station.name, + "type": station.type, + "position": station.position, + "distance": dist + }) + + # Build observation + var observations = { + "position": agent_pos, + "inventory": agent_inventory.duplicate(), + "nearby_resources": nearby_resources, + "nearby_stations": nearby_stations, + "recipes": RECIPES, + "target_item": TARGET_ITEM, + "crafting": current_craft != null, + "tick": simulation_manager.current_tick + } + + agent.perceive(observations) + +func _on_agent_action_decided(action): + """Handle agent action""" + if action is Dictionary and action.has("tool"): + var tool_name = action.tool + var params = action.get("params", {}) + + if tool_name == "craft": + craft_item(params.get("item_name", ""), params.get("station_name", "")) + +func _complete_scene(): + """Complete the benchmark""" + if scene_completed: + return + + scene_completed = true + simulation_manager.stop_simulation() + + print("\n" + "=".repeat(50)) + print("✓ CRAFTING CHAIN BENCHMARK COMPLETED!") + _print_final_metrics() + print("=".repeat(50)) + +func _print_final_metrics(): + """Print final benchmark metrics""" + var elapsed_time = (Time.get_ticks_msec() / 1000.0) - start_time + + print("\nFinal Metrics:") + print(" Items Crafted:") + for item_name in items_crafted.keys(): + print(" - %s: %d" % [item_name, items_crafted[item_name]]) + print(" Total Items: %d" % total_items_crafted) + print(" Crafting Attempts: %d" % crafting_attempts) + print(" Successful Crafts: %d" % successful_crafts) + print(" Recipe Efficiency: %.1f%%" % _calculate_recipe_efficiency()) + print(" Resources Collected: %d" % resources_collected) + print(" Resources Used: %d" % resources_used) + print(" Resources Wasted: %d" % _calculate_waste()) + print(" Total Crafting Time: %.2f seconds" % total_crafting_time) + print(" Total Time: %.2f seconds" % elapsed_time) + print(" Efficiency Score: %.2f" % _calculate_efficiency_score()) + +func _calculate_recipe_efficiency() -> float: + """Calculate recipe efficiency (successful crafts / attempts)""" + if crafting_attempts == 0: + return 0.0 + return (float(successful_crafts) / float(crafting_attempts)) * 100.0 + +func _calculate_waste() -> int: + """Calculate wasted resources""" + # Wasted = collected - used - remaining in inventory + var remaining = 0 + for item in agent_inventory.values(): + remaining += item + return resources_collected - resources_used - remaining + +func _calculate_efficiency_score() -> float: + """Calculate overall efficiency score""" + var efficiency = 0.0 + + # Did we craft the target item? + if agent_inventory.get(TARGET_ITEM, 0) > 0: + efficiency += 50.0 + + # Recipe efficiency bonus + efficiency += _calculate_recipe_efficiency() * 0.3 + + # Waste penalty + var waste = _calculate_waste() + efficiency -= waste * 5.0 + + return max(efficiency, 0.0) + +func _update_metrics_ui(): + """Update metrics display""" + if metrics_label == null: + return + + var elapsed_time = 0.0 + if simulation_manager.is_running: + elapsed_time = (Time.get_ticks_msec() / 1000.0) - start_time + + var status = "RUNNING" if simulation_manager.is_running else "STOPPED" + if scene_completed: + status = "COMPLETED" + + var crafting_status = "Idle" + if current_craft != null: + crafting_status = "Crafting %s..." % current_craft.item_name + + metrics_label.text = "Crafting Chain Benchmark [%s] +Tick: %d +Items Crafted: %d +Recipe Efficiency: %.1f%% +Resources Used: %d / %d +Resource Waste: %d +Crafting Time: %.2f s +Status: %s +Target: %s + +Inventory: %s + +Press SPACE to start/stop +Press R to reset +Press I to print inventory" % [ + status, + simulation_manager.current_tick, + total_items_crafted, + _calculate_recipe_efficiency(), + resources_used, + resources_collected, + _calculate_waste(), + total_crafting_time, + crafting_status, + TARGET_ITEM, + str(agent_inventory) + ] + +func _print_inventory(): + """Print current inventory""" + print("\nCurrent Inventory:") + for item in agent_inventory.keys(): + print(" - %s: %d" % [item, agent_inventory[item]]) + +func _reset_scene(): + """Reset the scene""" + print("Resetting crafting chain scene...") + + simulation_manager.reset_simulation() + + # Reset metrics + items_crafted.clear() + total_items_crafted = 0 + resources_collected = 0 + resources_used = 0 + resources_wasted = 0 + crafting_attempts = 0 + successful_crafts = 0 + start_time = 0.0 + total_crafting_time = 0.0 + scene_completed = false + current_craft = null + + # Reset inventory + agent_inventory.clear() + + # Reset agent position + agent.global_position = Vector3(0, 1, 10) + + # Reset resources + for resource in base_resources: + resource.collected = false + if resource.node != null: + resource.node.visible = true + + print("✓ Scene reset!") diff --git a/scripts/crafting_chain.gd.uid b/scripts/crafting_chain.gd.uid new file mode 100644 index 0000000..93a10d3 --- /dev/null +++ b/scripts/crafting_chain.gd.uid @@ -0,0 +1 @@ +uid://b5jfvj0m2vh0m diff --git a/scripts/foraging.gd b/scripts/foraging.gd new file mode 100644 index 0000000..8f010d4 --- /dev/null +++ b/scripts/foraging.gd @@ -0,0 +1,397 @@ +extends Node3D + +## Foraging Benchmark Scene +## Goal: Collect resources (berries, wood, stone) while avoiding hazards (fire, pits) +## Metrics: Resources collected, damage taken, distance traveled, time to completion + +@onready var simulation_manager = $SimulationManager +@onready var event_bus = $EventBus +@onready var tool_registry = $ToolRegistry +@onready var agent = $Agents/Agent1 +@onready var metrics_label = $UI/MetricsLabel + +# Scene configuration +const MAX_RESOURCES = 7 # Total resources to collect +const FIRE_DAMAGE = 10.0 +const PIT_DAMAGE = 25.0 +const COLLECTION_RADIUS = 2.0 +const HAZARD_RADIUS = 1.5 + +# Metrics +var resources_collected = 0 +var damage_taken = 0.0 +var distance_traveled = 0.0 +var start_time = 0.0 +var last_position = Vector3.ZERO +var scene_completed = false + +# Resource tracking +var active_resources = [] +var active_hazards = [] + +func _ready(): + print("Foraging Benchmark Scene Ready!") + + # Verify C++ nodes are loaded + if simulation_manager == null or agent == null: + push_error("GDExtension nodes not found! Extension may not be loaded.") + return + + # Initialize agent + agent.agent_id = "foraging_agent_001" + last_position = agent.global_position + + # Connect simulation signals + simulation_manager.simulation_started.connect(_on_simulation_started) + simulation_manager.simulation_stopped.connect(_on_simulation_stopped) + simulation_manager.tick_advanced.connect(_on_tick_advanced) + + # Connect agent signals + agent.action_decided.connect(_on_agent_action_decided) + agent.perception_received.connect(_on_agent_perception_received) + + # Register tools + _register_tools() + + # Initialize resources and hazards + _initialize_scene() + + print("Resources available: ", active_resources.size()) + print("Hazards: ", active_hazards.size()) + +func _register_tools(): + """Register available tools for the agent""" + if tool_registry == null: + return + + # Movement tool + var move_schema = { + "name": "move_to", + "description": "Move the agent to a target position", + "parameters": { + "target_x": {"type": "float", "description": "Target X coordinate"}, + "target_y": {"type": "float", "description": "Target Y coordinate"}, + "target_z": {"type": "float", "description": "Target Z coordinate"} + } + } + tool_registry.register_tool("move_to", move_schema) + + # Collection tool + var collect_schema = { + "name": "collect", + "description": "Collect a nearby resource", + "parameters": { + "resource_name": {"type": "string", "description": "Name of resource to collect"} + } + } + tool_registry.register_tool("collect", collect_schema) + + # Query tool + var query_schema = { + "name": "query_world", + "description": "Get information about nearby entities", + "parameters": { + "radius": {"type": "float", "description": "Search radius"} + } + } + tool_registry.register_tool("query_world", query_schema) + +func _initialize_scene(): + """Initialize resource and hazard tracking""" + active_resources.clear() + active_hazards.clear() + + # Collect all resources + var resources_node = $Resources + for child in resources_node.get_children(): + if child is Area3D: + active_resources.append({ + "name": child.name, + "position": child.global_position, + "type": _get_resource_type(child.name), + "collected": false, + "node": child + }) + + # Collect all hazards + var hazards_node = $Hazards + for child in hazards_node.get_children(): + if child is Area3D: + active_hazards.append({ + "name": child.name, + "position": child.global_position, + "type": _get_hazard_type(child.name), + "damage": FIRE_DAMAGE if "Fire" in child.name else PIT_DAMAGE, + "node": child + }) + +func _get_resource_type(resource_name: String) -> String: + """Extract resource type from name""" + if "Berry" in resource_name: + return "berry" + elif "Wood" in resource_name: + return "wood" + elif "Stone" in resource_name: + return "stone" + return "unknown" + +func _get_hazard_type(hazard_name: String) -> String: + """Extract hazard type from name""" + if "Fire" in hazard_name: + return "fire" + elif "Pit" in hazard_name: + return "pit" + return "unknown" + +func _process(_delta): + _update_metrics_ui() + +func _input(event): + if simulation_manager == null: + return + + # Control simulation with keyboard + if event is InputEventKey and event.pressed: + if event.keycode == KEY_SPACE: + if simulation_manager.is_running: + simulation_manager.stop_simulation() + else: + simulation_manager.start_simulation() + elif event.keycode == KEY_R: + _reset_scene() + elif event.keycode == KEY_S: + simulation_manager.step_simulation() + +func _on_simulation_started(): + print("✓ Foraging benchmark started!") + start_time = Time.get_ticks_msec() / 1000.0 + scene_completed = false + +func _on_simulation_stopped(): + print("✓ Foraging benchmark stopped!") + _print_final_metrics() + +func _on_tick_advanced(tick: int): + # Update distance traveled + var current_position = agent.global_position + distance_traveled += last_position.distance_to(current_position) + last_position = current_position + + # Check for resource collection + _check_resource_collection() + + # Check for hazard damage + _check_hazard_damage() + + # Send perception to agent + _send_perception_to_agent() + + # Check completion + if resources_collected >= MAX_RESOURCES: + _complete_scene() + +func _check_resource_collection(): + """Check if agent is near any uncollected resources""" + var agent_pos = agent.global_position + + for resource in active_resources: + if resource.collected: + continue + + var dist = agent_pos.distance_to(resource.position) + if dist <= COLLECTION_RADIUS: + _collect_resource(resource) + +func _collect_resource(resource: Dictionary): + """Collect a resource and update metrics""" + if resource.collected: + return + + resource.collected = true + resources_collected += 1 + + # Hide the resource node + if resource.node != null: + resource.node.visible = false + + # Record event + if event_bus != null: + event_bus.emit_event({ + "type": "resource_collected", + "resource_name": resource.name, + "resource_type": resource.type, + "position": resource.position, + "tick": simulation_manager.current_tick + }) + + print("✓ Collected %s (%d/%d)" % [resource.name, resources_collected, MAX_RESOURCES]) + +func _check_hazard_damage(): + """Check if agent is near any hazards and apply damage""" + var agent_pos = agent.global_position + + for hazard in active_hazards: + var dist = agent_pos.distance_to(hazard.position) + if dist <= HAZARD_RADIUS: + _apply_hazard_damage(hazard) + +func _apply_hazard_damage(hazard: Dictionary): + """Apply damage from a hazard""" + damage_taken += hazard.damage + + # Record event + if event_bus != null: + event_bus.emit_event({ + "type": "hazard_damage", + "hazard_name": hazard.name, + "hazard_type": hazard.type, + "damage": hazard.damage, + "position": hazard.position, + "tick": simulation_manager.current_tick + }) + + print("⚠ Took %d damage from %s! Total damage: %d" % [hazard.damage, hazard.name, damage_taken]) + +func _send_perception_to_agent(): + """Send world observations to the agent""" + var agent_pos = agent.global_position + + # Find nearby entities + var nearby_resources = [] + for resource in active_resources: + if not resource.collected: + var dist = agent_pos.distance_to(resource.position) + nearby_resources.append({ + "name": resource.name, + "type": resource.type, + "position": resource.position, + "distance": dist + }) + + var nearby_hazards = [] + for hazard in active_hazards: + var dist = agent_pos.distance_to(hazard.position) + nearby_hazards.append({ + "name": hazard.name, + "type": hazard.type, + "position": hazard.position, + "distance": dist + }) + + # Build observation dictionary + var observations = { + "position": agent_pos, + "resources_collected": resources_collected, + "resources_remaining": MAX_RESOURCES - resources_collected, + "damage_taken": damage_taken, + "nearby_resources": nearby_resources, + "nearby_hazards": nearby_hazards, + "tick": simulation_manager.current_tick + } + + # Send to agent + agent.perceive(observations) + +func _on_agent_action_decided(action): + """Handle agent's action decision""" + print("Agent decided: ", action) + +func _on_agent_perception_received(observations): + """Handle agent receiving perception""" + pass # Perception already handled in _send_perception_to_agent + +func _complete_scene(): + """Complete the benchmark scene""" + if scene_completed: + return + + scene_completed = true + simulation_manager.stop_simulation() + + print("\n" + "=".repeat(50)) + print("✓ FORAGING BENCHMARK COMPLETED!") + _print_final_metrics() + print("=".repeat(50)) + +func _print_final_metrics(): + """Print final benchmark metrics""" + var elapsed_time = (Time.get_ticks_msec() / 1000.0) - start_time + + print("\nFinal Metrics:") + print(" Resources Collected: %d/%d" % [resources_collected, MAX_RESOURCES]) + print(" Damage Taken: %.1f" % damage_taken) + print(" Distance Traveled: %.2f meters" % distance_traveled) + print(" Time Elapsed: %.2f seconds" % elapsed_time) + print(" Efficiency Score: %.2f" % _calculate_efficiency_score()) + +func _calculate_efficiency_score() -> float: + """Calculate overall efficiency score""" + if resources_collected == 0: + return 0.0 + + # Score based on: resources collected, minimal damage, efficient pathing + var resource_score = float(resources_collected) / float(MAX_RESOURCES) * 100.0 + var damage_penalty = min(damage_taken, 100.0) # Cap penalty at 100 + var efficiency = resource_score - damage_penalty + + return max(efficiency, 0.0) + +func _update_metrics_ui(): + """Update the metrics display""" + if metrics_label == null: + return + + var elapsed_time = 0.0 + if simulation_manager.is_running: + elapsed_time = (Time.get_ticks_msec() / 1000.0) - start_time + + var status = "RUNNING" if simulation_manager.is_running else "STOPPED" + if scene_completed: + status = "COMPLETED" + + metrics_label.text = "Foraging Benchmark [%s] +Tick: %d +Resources Collected: %d/%d +Damage Taken: %.1f +Distance Traveled: %.2f m +Time Elapsed: %.2f s +Efficiency Score: %.1f + +Press SPACE to start/stop +Press R to reset +Press S to step" % [ + status, + simulation_manager.current_tick, + resources_collected, + MAX_RESOURCES, + damage_taken, + distance_traveled, + elapsed_time, + _calculate_efficiency_score() + ] + +func _reset_scene(): + """Reset the scene to initial state""" + print("Resetting foraging scene...") + + simulation_manager.reset_simulation() + + # Reset metrics + resources_collected = 0 + damage_taken = 0.0 + distance_traveled = 0.0 + start_time = 0.0 + scene_completed = false + + # Reset agent position + agent.global_position = Vector3.ZERO + agent.global_position.y = 1.0 + last_position = agent.global_position + + # Reset resources + for resource in active_resources: + resource.collected = false + if resource.node != null: + resource.node.visible = true + + print("✓ Scene reset!") diff --git a/scripts/foraging.gd.uid b/scripts/foraging.gd.uid new file mode 100644 index 0000000..1a07bd5 --- /dev/null +++ b/scripts/foraging.gd.uid @@ -0,0 +1 @@ +uid://cuvvv5nbixqy8 diff --git a/scripts/init_github.bat b/scripts/init_github.bat new file mode 100644 index 0000000..aa218b3 --- /dev/null +++ b/scripts/init_github.bat @@ -0,0 +1,94 @@ +@echo off +REM Initialize Git repository and push to GitHub (Windows) + +setlocal EnableDelayedExpansion + +echo ========================================== +echo Agent Arena - GitHub Initialization +echo ========================================== +echo. + +set "REPO_URL=https://github.com/JustInternetAI/AgentArena.git" + +REM Check if git is installed +where git >nul 2>nul +if %ERRORLEVEL% NEQ 0 ( + echo Error: git is not installed + exit /b 1 +) + +REM Initialize repository if not already done +if not exist ".git" ( + echo Initializing git repository... + git init + echo [OK] Git repository initialized +) else ( + echo [OK] Git repository already initialized +) + +REM Configure git user +echo. +echo Configuring git user... +set /p GIT_NAME="Enter your name (e.g., Justin Madison): " +set /p GIT_EMAIL="Enter your email: " + +git config user.name "%GIT_NAME%" +git config user.email "%GIT_EMAIL%" +echo [OK] Git user configured + +REM Add remote if not exists +git remote | findstr /C:"origin" >nul +if %ERRORLEVEL% NEQ 0 ( + echo. + echo Adding remote origin... + git remote add origin "%REPO_URL%" + echo [OK] Remote added: %REPO_URL% +) else ( + echo [OK] Remote 'origin' already exists +) + +REM Show status +echo. +echo ========================================== +echo Repository Status: +echo ========================================== +git status + +REM Ask to commit and push +echo. +set /p CONFIRM="Ready to commit and push? (y/n): " +if /i "%CONFIRM%"=="y" ( + echo. + echo Adding files... + git add . + + echo Creating commit... + git commit -m "Initial commit: Agent Arena framework - Godot C++ GDExtension module with core simulation classes - Python agent runtime with LLM backend support - Tool system (world query, movement, inventory) - Memory infrastructure (short-term and RAG) - Comprehensive documentation and setup guides - Apache 2.0 license with founder attribution - GitHub workflows and issue templates Founded by Andrew Madison and Justin Madison Maintained by JustInternetAI" + + echo. + echo Pushing to GitHub... + git branch -M main + git push -u origin main + + echo. + echo ========================================== + echo [OK] Repository pushed to GitHub! + echo ========================================== + echo. + echo Next steps: + echo 1. Visit: https://github.com/JustInternetAI/AgentArena + echo 2. Configure repository settings (topics, about, etc.^) + echo 3. Review and merge any dependabot PRs + echo 4. Create your first release (v0.1.0^) + echo. + echo See GITHUB_SETUP.md for detailed configuration instructions +) else ( + echo. + echo Skipped. When ready, run: + echo git add . + echo git commit -m "Initial commit" + echo git push -u origin main +) + +echo. +pause diff --git a/scripts/init_github.sh b/scripts/init_github.sh new file mode 100644 index 0000000..4b64352 --- /dev/null +++ b/scripts/init_github.sh @@ -0,0 +1,108 @@ +#!/bin/bash +# Initialize Git repository and push to GitHub + +set -e + +echo "==========================================" +echo " Agent Arena - GitHub Initialization" +echo "==========================================" +echo "" + +REPO_URL="https://github.com/JustInternetAI/AgentArena.git" + +# Check if git is installed +if ! command -v git &> /dev/null; then + echo "Error: git is not installed" + exit 1 +fi + +# Initialize repository if not already done +if [ ! -d ".git" ]; then + echo "Initializing git repository..." + git init + echo "✓ Git repository initialized" +else + echo "✓ Git repository already initialized" +fi + +# Configure git user (update with your details) +echo "" +echo "Configuring git user..." +read -p "Enter your name (e.g., Justin Madison): " GIT_NAME +read -p "Enter your email: " GIT_EMAIL + +git config user.name "$GIT_NAME" +git config user.email "$GIT_EMAIL" +echo "✓ Git user configured" + +# Add remote if not exists +if ! git remote | grep -q origin; then + echo "" + echo "Adding remote origin..." + git remote add origin "$REPO_URL" + echo "✓ Remote added: $REPO_URL" +else + echo "✓ Remote 'origin' already exists" +fi + +# Create .gitignore if it doesn't exist +if [ ! -f ".gitignore" ]; then + echo "" + echo "Warning: .gitignore not found" +fi + +# Show status +echo "" +echo "==========================================" +echo "Repository Status:" +echo "==========================================" +git status + +# Ask to commit and push +echo "" +read -p "Ready to commit and push? (y/n): " -n 1 -r +echo +if [[ $REPLY =~ ^[Yy]$ ]]; then + echo "" + echo "Adding files..." + git add . + + echo "Creating commit..." + git commit -m "Initial commit: Agent Arena framework + +- Godot C++ GDExtension module with core simulation classes +- Python agent runtime with LLM backend support +- Tool system (world query, movement, inventory) +- Memory infrastructure (short-term and RAG) +- Comprehensive documentation and setup guides +- Apache 2.0 license with founder attribution +- GitHub workflows and issue templates + +Founded by Andrew Madison and Justin Madison +Maintained by JustInternetAI +" || echo "Note: Commit may have failed if no changes" + + echo "" + echo "Pushing to GitHub..." + git branch -M main + git push -u origin main + + echo "" + echo "==========================================" + echo "✓ Repository pushed to GitHub!" + echo "==========================================" + echo "" + echo "Next steps:" + echo "1. Visit: https://github.com/JustInternetAI/AgentArena" + echo "2. Configure repository settings (topics, about, etc.)" + echo "3. Review and merge any dependabot PRs" + echo "4. Create your first release (v0.1.0)" + echo "" + echo "See GITHUB_SETUP.md for detailed configuration instructions" +else + echo "" + echo "Skipped. When ready, run:" + echo " git add ." + echo " git commit -m 'Initial commit'" + echo " git push -u origin main" +fi diff --git a/scripts/setup.bat b/scripts/setup.bat new file mode 100644 index 0000000..6c9d6f8 --- /dev/null +++ b/scripts/setup.bat @@ -0,0 +1,111 @@ +@echo off +REM Complete setup script for Agent Arena on Windows + +setlocal EnableDelayedExpansion + +echo ======================================== +echo Agent Arena Setup Script +echo ======================================== +echo. + +set "SCRIPT_DIR=%~dp0" +set "PROJECT_ROOT=%SCRIPT_DIR%.." + +REM Check prerequisites +echo Checking prerequisites... + +where git >nul 2>nul +if %ERRORLEVEL% NEQ 0 ( + echo Error: git is not installed + exit /b 1 +) + +where python >nul 2>nul +if %ERRORLEVEL% NEQ 0 ( + echo Error: python is not installed + exit /b 1 +) + +where cmake >nul 2>nul +if %ERRORLEVEL% NEQ 0 ( + echo Error: cmake is not installed + exit /b 1 +) + +echo [OK] All prerequisites found +echo. + +REM Setup godot-cpp +echo Setting up godot-cpp... +call "%SCRIPT_DIR%\setup_godot_cpp.bat" +echo [OK] godot-cpp setup complete +echo. + +REM Build C++ module +echo Building C++ module... +cd /d "%PROJECT_ROOT%\godot" + +if not exist "build" mkdir build +cd build + +cmake .. -DCMAKE_BUILD_TYPE=Release +cmake --build . --config Release + +if %ERRORLEVEL% NEQ 0 ( + echo Error: Build failed + exit /b 1 +) + +echo [OK] C++ module built +echo. + +REM Setup Python environment +echo Setting up Python environment... +cd /d "%PROJECT_ROOT%\python" + +if not exist "venv" ( + python -m venv venv +) + +call venv\Scripts\activate.bat + +python -m pip install --upgrade pip +pip install -r requirements.txt + +if %ERRORLEVEL% NEQ 0 ( + echo Error: Python setup failed + exit /b 1 +) + +echo [OK] Python environment ready +echo. + +REM Create necessary directories +echo Creating project directories... +if not exist "%PROJECT_ROOT%\logs" mkdir "%PROJECT_ROOT%\logs" +if not exist "%PROJECT_ROOT%\replays" mkdir "%PROJECT_ROOT%\replays" +if not exist "%PROJECT_ROOT%\metrics" mkdir "%PROJECT_ROOT%\metrics" +if not exist "%PROJECT_ROOT%\models" mkdir "%PROJECT_ROOT%\models" + +echo [OK] Directories created +echo. + +REM Run tests +echo Running tests... +cd /d "%PROJECT_ROOT%\tests" +pytest -v +echo. + +echo ======================================== +echo Setup complete! +echo ======================================== +echo. +echo Next steps: +echo 1. Download a model to models/ directory +echo 2. Update configs/backend/llama_cpp.yaml with model path +echo 3. Open the project in Godot 4 +echo 4. Run: python python\test_agent.py +echo. +echo See docs/quickstart.md for detailed instructions +echo. +pause diff --git a/scripts/setup.sh b/scripts/setup.sh new file mode 100644 index 0000000..dd9c963 --- /dev/null +++ b/scripts/setup.sh @@ -0,0 +1,104 @@ +#!/bin/bash +# Complete setup script for Agent Arena + +set -e + +echo "========================================" +echo " Agent Arena Setup Script" +echo "========================================" +echo "" + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" + +# Colors for output +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +NC='\033[0m' # No Color + +# Check prerequisites +echo -e "${YELLOW}Checking prerequisites...${NC}" + +if ! command -v git &> /dev/null; then + echo -e "${RED}Error: git is not installed${NC}" + exit 1 +fi + +if ! command -v python3 &> /dev/null; then + echo -e "${RED}Error: python3 is not installed${NC}" + exit 1 +fi + +if ! command -v cmake &> /dev/null; then + echo -e "${RED}Error: cmake is not installed${NC}" + exit 1 +fi + +echo -e "${GREEN}✓ All prerequisites found${NC}" +echo "" + +# Setup godot-cpp +echo -e "${YELLOW}Setting up godot-cpp...${NC}" +"$SCRIPT_DIR/setup_godot_cpp.sh" +echo -e "${GREEN}✓ godot-cpp setup complete${NC}" +echo "" + +# Build C++ module +echo -e "${YELLOW}Building C++ module...${NC}" +cd "$PROJECT_ROOT/godot" + +if [ ! -d "build" ]; then + mkdir build +fi + +cd build +cmake .. -DCMAKE_BUILD_TYPE=Release +cmake --build . --config Release + +echo -e "${GREEN}✓ C++ module built${NC}" +echo "" + +# Setup Python environment +echo -e "${YELLOW}Setting up Python environment...${NC}" +cd "$PROJECT_ROOT/python" + +if [ ! -d "venv" ]; then + python3 -m venv venv +fi + +source venv/bin/activate + +pip install --upgrade pip +pip install -r requirements.txt + +echo -e "${GREEN}✓ Python environment ready${NC}" +echo "" + +# Create necessary directories +echo -e "${YELLOW}Creating project directories...${NC}" +mkdir -p "$PROJECT_ROOT/logs" +mkdir -p "$PROJECT_ROOT/replays" +mkdir -p "$PROJECT_ROOT/metrics" +mkdir -p "$PROJECT_ROOT/models" + +echo -e "${GREEN}✓ Directories created${NC}" +echo "" + +# Run tests +echo -e "${YELLOW}Running tests...${NC}" +cd "$PROJECT_ROOT/tests" +pytest -v || echo -e "${YELLOW}Warning: Some tests failed${NC}" +echo "" + +echo "========================================" +echo -e "${GREEN}Setup complete!${NC}" +echo "========================================" +echo "" +echo "Next steps:" +echo "1. Download a model to models/ directory" +echo "2. Update configs/backend/llama_cpp.yaml with model path" +echo "3. Open the project in Godot 4" +echo "4. Run: python python/test_agent.py" +echo "" +echo "See docs/quickstart.md for detailed instructions" diff --git a/scripts/setup_godot_cpp.bat b/scripts/setup_godot_cpp.bat new file mode 100644 index 0000000..7bdfcbc --- /dev/null +++ b/scripts/setup_godot_cpp.bat @@ -0,0 +1,30 @@ +@echo off +REM Setup script for godot-cpp dependency on Windows + +setlocal EnableDelayedExpansion + +set "SCRIPT_DIR=%~dp0" +set "PROJECT_ROOT=%SCRIPT_DIR%.." +set "EXTERNAL_DIR=%PROJECT_ROOT%\external" + +echo Setting up godot-cpp... + +REM Create external directory +if not exist "%EXTERNAL_DIR%" mkdir "%EXTERNAL_DIR%" + +REM Clone godot-cpp if not present +if not exist "%EXTERNAL_DIR%\godot-cpp" ( + echo Cloning godot-cpp... + git clone --recursive https://github.com/godotengine/godot-cpp.git "%EXTERNAL_DIR%\godot-cpp" + cd /d "%EXTERNAL_DIR%\godot-cpp" + git checkout 4.2 + git submodule update --init --recursive +) else ( + echo godot-cpp already exists, updating... + cd /d "%EXTERNAL_DIR%\godot-cpp" + git pull + git submodule update --init --recursive +) + +echo godot-cpp setup complete! +pause diff --git a/scripts/setup_godot_cpp.sh b/scripts/setup_godot_cpp.sh new file mode 100644 index 0000000..ccda8e4 --- /dev/null +++ b/scripts/setup_godot_cpp.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# Setup script for godot-cpp dependency + +set -e + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +PROJECT_ROOT="$(dirname "$SCRIPT_DIR")" +EXTERNAL_DIR="$PROJECT_ROOT/external" + +echo "Setting up godot-cpp..." + +# Create external directory +mkdir -p "$EXTERNAL_DIR" + +# Clone godot-cpp if not present +if [ ! -d "$EXTERNAL_DIR/godot-cpp" ]; then + echo "Cloning godot-cpp..." + git clone --recursive https://github.com/godotengine/godot-cpp.git "$EXTERNAL_DIR/godot-cpp" + cd "$EXTERNAL_DIR/godot-cpp" + git checkout 4.2 # Use Godot 4.2 compatible version + git submodule update --init --recursive +else + echo "godot-cpp already exists, updating..." + cd "$EXTERNAL_DIR/godot-cpp" + git pull + git submodule update --init --recursive +fi + +echo "godot-cpp setup complete!" diff --git a/scripts/team_capture.gd b/scripts/team_capture.gd new file mode 100644 index 0000000..cf5ac7d --- /dev/null +++ b/scripts/team_capture.gd @@ -0,0 +1,569 @@ +extends Node3D + +## Team Capture Benchmark Scene +## Goal: Multi-agent teams compete to capture and hold objectives +## Metrics: Objectives captured, team coordination, individual contribution, win rate + +@onready var simulation_manager = $SimulationManager +@onready var event_bus = $EventBus +@onready var tool_registry = $ToolRegistry +@onready var metrics_label = $UI/MetricsLabel + +# Scene configuration +const CAPTURE_RADIUS = 3.0 +const CAPTURE_TIME = 5.0 # Seconds to capture +const POINTS_PER_CAPTURE = 10 +const POINTS_PER_HOLD_TICK = 1 +const MAX_POINTS = 100 +const COMMUNICATION_RADIUS = 15.0 + +# Teams +var blue_team = [] +var red_team = [] + +# Capture points +var capture_points = [] + +# Metrics +var blue_score = 0 +var red_score = 0 +var objectives_captured = {"blue": 0, "red": 0} +var total_captures = 0 +var team_blue_contributions = {} +var team_red_contributions = {} +var start_time = 0.0 +var scene_completed = false +var winning_team = "" + +func _ready(): + print("Team Capture Benchmark Scene Ready!") + + # Verify C++ nodes + if simulation_manager == null: + push_error("GDExtension nodes not found!") + return + + # Connect simulation signals + simulation_manager.simulation_started.connect(_on_simulation_started) + simulation_manager.simulation_stopped.connect(_on_simulation_stopped) + simulation_manager.tick_advanced.connect(_on_tick_advanced) + + # Register tools + _register_tools() + + # Initialize teams and capture points + _initialize_scene() + + print("Blue team agents: ", blue_team.size()) + print("Red team agents: ", red_team.size()) + print("Capture points: ", capture_points.size()) + +func _register_tools(): + """Register available tools for agents""" + if tool_registry == null: + return + + # Movement + tool_registry.register_tool("move_to", { + "name": "move_to", + "description": "Move to a target position", + "parameters": { + "target_x": {"type": "float"}, + "target_y": {"type": "float"}, + "target_z": {"type": "float"} + } + }) + + # Capture + tool_registry.register_tool("capture_point", { + "name": "capture_point", + "description": "Attempt to capture a nearby point", + "parameters": { + "point_name": {"type": "string"} + } + }) + + # Communication + tool_registry.register_tool("send_message", { + "name": "send_message", + "description": "Send a message to nearby teammates", + "parameters": { + "message": {"type": "string"}, + "target_agent": {"type": "string"} + } + }) + + # Query + tool_registry.register_tool("query_team", { + "name": "query_team", + "description": "Get information about teammates", + "parameters": {} + }) + + tool_registry.register_tool("query_objectives", { + "name": "query_objectives", + "description": "Get status of capture points", + "parameters": {} + }) + +func _initialize_scene(): + """Initialize teams and capture points""" + blue_team.clear() + red_team.clear() + capture_points.clear() + team_blue_contributions.clear() + team_red_contributions.clear() + + # Initialize Blue Team + var blue_team_node = $TeamBlue + for child in blue_team_node.get_children(): + if child.get_class() == "Agent": + child.agent_id = "blue_%s" % child.name + blue_team.append({ + "agent": child, + "id": child.agent_id, + "position": child.global_position, + "team": "blue" + }) + team_blue_contributions[child.agent_id] = { + "captures": 0, + "assists": 0, + "messages_sent": 0 + } + # Connect agent signals + child.action_decided.connect(_on_agent_action_decided.bind(child.agent_id)) + + # Initialize Red Team + var red_team_node = $TeamRed + for child in red_team_node.get_children(): + if child.get_class() == "Agent": + child.agent_id = "red_%s" % child.name + red_team.append({ + "agent": child, + "id": child.agent_id, + "position": child.global_position, + "team": "red" + }) + team_red_contributions[child.agent_id] = { + "captures": 0, + "assists": 0, + "messages_sent": 0 + } + # Connect agent signals + child.action_decided.connect(_on_agent_action_decided.bind(child.agent_id)) + + # Initialize Capture Points + var points_node = $CapturePoints + for child in points_node.get_children(): + if child is Area3D: + capture_points.append({ + "name": child.name, + "position": child.global_position, + "owner": "neutral", + "capture_progress": 0.0, + "capturing_team": null, + "agents_present": [], + "node": child + }) + +func _process(_delta): + _update_metrics_ui() + +func _input(event): + if simulation_manager == null: + return + + if event is InputEventKey and event.pressed: + if event.keycode == KEY_SPACE: + if simulation_manager.is_running: + simulation_manager.stop_simulation() + else: + simulation_manager.start_simulation() + elif event.keycode == KEY_R: + _reset_scene() + elif event.keycode == KEY_S: + simulation_manager.step_simulation() + elif event.keycode == KEY_M: + _print_detailed_metrics() + +func _on_simulation_started(): + print("✓ Team capture benchmark started!") + start_time = Time.get_ticks_msec() / 1000.0 + scene_completed = false + +func _on_simulation_stopped(): + print("✓ Team capture benchmark stopped!") + _print_final_metrics() + +func _on_tick_advanced(tick: int): + # Update agent positions + _update_agent_positions() + + # Update capture point status + _update_capture_points(1.0 / 60.0) # Assuming 60 ticks per second + + # Award points for holding objectives + _award_holding_points() + + # Send perception to all agents + _send_perception_to_agents() + + # Check win condition + if blue_score >= MAX_POINTS or red_score >= MAX_POINTS: + _complete_scene() + +func _update_agent_positions(): + """Update stored agent positions""" + for agent_data in blue_team: + agent_data.position = agent_data.agent.global_position + + for agent_data in red_team: + agent_data.position = agent_data.agent.global_position + +func _update_capture_points(delta: float): + """Update capture progress for all points""" + for point in capture_points: + # Find agents at this point + point.agents_present.clear() + var blue_count = 0 + var red_count = 0 + + for agent_data in blue_team: + var dist = agent_data.position.distance_to(point.position) + if dist <= CAPTURE_RADIUS: + point.agents_present.append(agent_data) + blue_count += 1 + + for agent_data in red_team: + var dist = agent_data.position.distance_to(point.position) + if dist <= CAPTURE_RADIUS: + point.agents_present.append(agent_data) + red_count += 1 + + # Determine capturing team + var dominant_team = null + if blue_count > red_count: + dominant_team = "blue" + elif red_count > blue_count: + dominant_team = "red" + + # Update capture progress + if dominant_team != null and point.owner != dominant_team: + # Capturing + if point.capturing_team != dominant_team: + point.capturing_team = dominant_team + point.capture_progress = 0.0 + + point.capture_progress += delta + if point.capture_progress >= CAPTURE_TIME: + _capture_point(point, dominant_team) + else: + # Reset progress if contested or no one present + point.capturing_team = null + point.capture_progress = 0.0 + +func _capture_point(point: Dictionary, team: String): + """Capture a point for a team""" + var previous_owner = point.owner + point.owner = team + point.capture_progress = 0.0 + point.capturing_team = null + + # Award points + if team == "blue": + blue_score += POINTS_PER_CAPTURE + objectives_captured.blue += 1 + else: + red_score += POINTS_PER_CAPTURE + objectives_captured.red += 1 + + total_captures += 1 + + # Award contributions to agents present + for agent_data in point.agents_present: + if agent_data.team == team: + var contributions = team_blue_contributions if team == "blue" else team_red_contributions + contributions[agent_data.id].captures += 1 + + # Record event + if event_bus != null: + event_bus.emit_event({ + "type": "point_captured", + "point_name": point.name, + "team": team, + "previous_owner": previous_owner, + "tick": simulation_manager.current_tick + }) + + print("✓ %s team captured %s! (Score: Blue %d, Red %d)" % + [team.capitalize(), point.name, blue_score, red_score]) + +func _award_holding_points(): + """Award points for holding capture points""" + for point in capture_points: + if point.owner == "blue": + blue_score += POINTS_PER_HOLD_TICK + elif point.owner == "red": + red_score += POINTS_PER_HOLD_TICK + +func _send_perception_to_agents(): + """Send observations to all agents""" + # Blue team perception + for agent_data in blue_team: + var obs = _build_agent_observation(agent_data, blue_team, red_team) + agent_data.agent.perceive(obs) + + # Red team perception + for agent_data in red_team: + var obs = _build_agent_observation(agent_data, red_team, blue_team) + agent_data.agent.perceive(obs) + +func _build_agent_observation(agent_data: Dictionary, allies: Array, enemies: Array) -> Dictionary: + """Build observation for an agent""" + var agent_pos = agent_data.position + + # Find nearby allies + var nearby_allies = [] + for ally in allies: + if ally.id == agent_data.id: + continue + var dist = agent_pos.distance_to(ally.position) + if dist <= COMMUNICATION_RADIUS: + nearby_allies.append({ + "id": ally.id, + "position": ally.position, + "distance": dist + }) + + # Find visible enemies (simplified - just distance check) + var nearby_enemies = [] + for enemy in enemies: + var dist = agent_pos.distance_to(enemy.position) + if dist <= 20.0: # Vision range + nearby_enemies.append({ + "id": enemy.id, + "position": enemy.position, + "distance": dist + }) + + # Capture point status + var objectives = [] + for point in capture_points: + var dist = agent_pos.distance_to(point.position) + objectives.append({ + "name": point.name, + "position": point.position, + "owner": point.owner, + "capturing_team": point.capturing_team, + "capture_progress": point.capture_progress, + "distance": dist + }) + + return { + "agent_id": agent_data.id, + "team": agent_data.team, + "position": agent_pos, + "team_score": blue_score if agent_data.team == "blue" else red_score, + "enemy_score": red_score if agent_data.team == "blue" else blue_score, + "nearby_allies": nearby_allies, + "nearby_enemies": nearby_enemies, + "objectives": objectives, + "tick": simulation_manager.current_tick + } + +func _on_agent_action_decided(action, agent_id: String): + """Handle agent action decisions""" + # Actions are handled through the tool system + # This is just for logging/debugging + pass + +func _complete_scene(): + """Complete the benchmark""" + if scene_completed: + return + + scene_completed = true + simulation_manager.stop_simulation() + + # Determine winner + if blue_score > red_score: + winning_team = "Blue" + elif red_score > blue_score: + winning_team = "Red" + else: + winning_team = "Draw" + + print("\n" + "=".repeat(50)) + print("✓ TEAM CAPTURE BENCHMARK COMPLETED!") + print("Winner: %s Team!" % winning_team) + _print_final_metrics() + print("=".repeat(50)) + +func _print_final_metrics(): + """Print final benchmark metrics""" + var elapsed_time = (Time.get_ticks_msec() / 1000.0) - start_time + + print("\nFinal Metrics:") + print(" Final Score: Blue %d - Red %d" % [blue_score, red_score]) + print(" Objectives Captured: Blue %d - Red %d" % [objectives_captured.blue, objectives_captured.red]) + print(" Total Captures: %d" % total_captures) + print(" Time Elapsed: %.2f seconds" % elapsed_time) + print(" Winner: %s" % winning_team) + print("\nTeam Blue Contributions:") + for agent_id in team_blue_contributions.keys(): + var contrib = team_blue_contributions[agent_id] + print(" %s - Captures: %d, Assists: %d" % [agent_id, contrib.captures, contrib.assists]) + print("\nTeam Red Contributions:") + for agent_id in team_red_contributions.keys(): + var contrib = team_red_contributions[agent_id] + print(" %s - Captures: %d, Assists: %d" % [agent_id, contrib.captures, contrib.assists]) + print(" Team Coordination Score: %.2f" % _calculate_coordination_score()) + +func _calculate_coordination_score() -> float: + """Calculate team coordination metric""" + # Measure how evenly distributed contributions are + # Perfect coordination = equal contributions from all agents + if total_captures == 0: + return 0.0 + + var blue_variance = _calculate_contribution_variance(team_blue_contributions) + var red_variance = _calculate_contribution_variance(team_red_contributions) + + # Lower variance = better coordination + var avg_variance = (blue_variance + red_variance) / 2.0 + return max(100.0 - avg_variance * 10.0, 0.0) + +func _calculate_contribution_variance(contributions: Dictionary) -> float: + """Calculate variance in contributions""" + if contributions.size() == 0: + return 0.0 + + var values = [] + for agent_id in contributions.keys(): + values.append(contributions[agent_id].captures) + + var mean = 0.0 + for val in values: + mean += val + mean /= values.size() + + var variance = 0.0 + for val in values: + variance += pow(val - mean, 2) + variance /= values.size() + + return variance + +func _print_detailed_metrics(): + """Print detailed metrics during simulation""" + print("\n--- Current Status ---") + print("Score: Blue %d - Red %d" % [blue_score, red_score]) + print("Capture Points:") + for point in capture_points: + var status = point.owner + if point.capturing_team != null: + status = "%s (capturing: %s %.1f%%)" % [ + point.owner, + point.capturing_team, + (point.capture_progress / CAPTURE_TIME) * 100.0 + ] + print(" %s: %s (%d agents)" % [point.name, status, point.agents_present.size()]) + +func _update_metrics_ui(): + """Update metrics display""" + if metrics_label == null: + return + + var elapsed_time = 0.0 + if simulation_manager.is_running: + elapsed_time = (Time.get_ticks_msec() / 1000.0) - start_time + + var status = "RUNNING" if simulation_manager.is_running else "STOPPED" + if scene_completed: + status = "COMPLETED - %s WINS!" % winning_team.to_upper() + + # Count controlled objectives + var blue_controlled = 0 + var red_controlled = 0 + for point in capture_points: + if point.owner == "blue": + blue_controlled += 1 + elif point.owner == "red": + red_controlled += 1 + + metrics_label.text = "Team Capture Benchmark [%s] +Tick: %d + +SCORE: + Blue Team: %d + Red Team: %d + +OBJECTIVES: + Blue Controlled: %d + Red Controlled: %d + Total Captures: Blue %d, Red %d + +TIME: %.2f s + +Press SPACE to start/stop +Press R to reset +Press M for detailed metrics" % [ + status, + simulation_manager.current_tick, + blue_score, + red_score, + blue_controlled, + red_controlled, + objectives_captured.blue, + objectives_captured.red, + elapsed_time + ] + +func _reset_scene(): + """Reset the scene""" + print("Resetting team capture scene...") + + simulation_manager.reset_simulation() + + # Reset metrics + blue_score = 0 + red_score = 0 + objectives_captured = {"blue": 0, "red": 0} + total_captures = 0 + start_time = 0.0 + scene_completed = false + winning_team = "" + + # Reset contributions + for agent_id in team_blue_contributions.keys(): + team_blue_contributions[agent_id] = { + "captures": 0, + "assists": 0, + "messages_sent": 0 + } + for agent_id in team_red_contributions.keys(): + team_red_contributions[agent_id] = { + "captures": 0, + "assists": 0, + "messages_sent": 0 + } + + # Reset capture points + for point in capture_points: + point.owner = "neutral" + point.capture_progress = 0.0 + point.capturing_team = null + point.agents_present.clear() + + # Reset agent positions + var blue_spawn_positions = [Vector3(-20, 1, -20), Vector3(-22, 1, -18), Vector3(-18, 1, -22)] + for i in range(blue_team.size()): + if i < blue_spawn_positions.size(): + blue_team[i].agent.global_position = blue_spawn_positions[i] + + var red_spawn_positions = [Vector3(20, 1, 20), Vector3(22, 1, 18), Vector3(18, 1, 22)] + for i in range(red_team.size()): + if i < red_spawn_positions.size(): + red_team[i].agent.global_position = red_spawn_positions[i] + + print("✓ Scene reset!") diff --git a/scripts/team_capture.gd.uid b/scripts/team_capture.gd.uid new file mode 100644 index 0000000..bb99bb8 --- /dev/null +++ b/scripts/team_capture.gd.uid @@ -0,0 +1 @@ +uid://bleomj5dy008u diff --git a/scripts/test_arena.gd b/scripts/test_arena.gd new file mode 100644 index 0000000..6879a43 --- /dev/null +++ b/scripts/test_arena.gd @@ -0,0 +1,121 @@ +extends Node + +@onready var simulation_manager = $SimulationManager +@onready var agent = $Agent +@onready var label = $UI/Label + +var tick_count = 0 + +func _ready(): + print("Test Arena Ready!") + print("SimulationManager: ", simulation_manager) + print("Agent: ", agent) + + # Check if nodes are available + if simulation_manager == null: + push_error("SimulationManager node not found! The GDExtension may not be loaded properly.") + print("ERROR: Make sure the extension is built and the .gdextension file is configured correctly.") + return + + if agent == null: + push_error("Agent node not found! The GDExtension may not be loaded properly.") + return + + # Connect simulation signals + simulation_manager.simulation_started.connect(_on_simulation_started) + simulation_manager.simulation_stopped.connect(_on_simulation_stopped) + simulation_manager.tick_advanced.connect(_on_tick_advanced) + + # Connect agent signals + agent.action_decided.connect(_on_agent_action_decided) + agent.perception_received.connect(_on_agent_perception_received) + + # Set up agent + agent.agent_id = "test_agent_001" + print("Agent ID: ", agent.agent_id) + +func _input(event): + if simulation_manager == null: + return + + if event is InputEventKey and event.pressed: + if event.keycode == KEY_SPACE: + if simulation_manager.is_running: + simulation_manager.stop_simulation() + else: + simulation_manager.start_simulation() + elif event.keycode == KEY_R: + simulation_manager.reset_simulation() + elif event.keycode == KEY_S: + simulation_manager.step_simulation() + elif event.keycode == KEY_T: + test_agent() + +func _process(_delta): + if simulation_manager == null or agent == null: + label.text = "Agent Arena Test Scene (ERROR) +Extension not loaded! +Check console for errors." + return + + if simulation_manager.is_running: + label.text = "Agent Arena Test Scene (RUNNING) +Tick: %d +Agent ID: %s +Press SPACE to stop +Press S to step +Press R to reset +Press T to test agent" % [simulation_manager.current_tick, agent.agent_id] + else: + label.text = "Agent Arena Test Scene (STOPPED) +Tick: %d +Agent ID: %s +Press SPACE to start +Press S to step +Press R to reset +Press T to test agent" % [simulation_manager.current_tick, agent.agent_id] + +func test_agent(): + if agent == null: + push_error("Cannot test agent - agent is null") + return + + print("Testing agent functions...") + + # Test perception + var obs = { + "position": Vector3(10, 0, 5), + "health": 100, + "nearby_objects": ["tree", "rock", "water"] + } + agent.perceive(obs) + + # Test decision + var action = agent.decide_action() + print("Agent decided action: ", action) + + # Test memory + agent.store_memory("test_key", "test_value") + var retrieved = agent.retrieve_memory("test_key") + print("Retrieved memory: ", retrieved) + + # Test tool call + var tool_result = agent.call_tool("move", {"direction": "north", "distance": 5}) + print("Tool result: ", tool_result) + +func _on_simulation_started(): + print("✓ Simulation started!") + +func _on_simulation_stopped(): + print("✓ Simulation stopped!") + +func _on_tick_advanced(tick): + tick_count += 1 + if tick_count % 60 == 0: # Print every 60 ticks (1 second) + print("Tick: ", tick) + +func _on_agent_action_decided(action): + print("Agent action: ", action) + +func _on_agent_perception_received(observations): + print("Agent perceived: ", observations) diff --git a/scripts/test_arena.gd.uid b/scripts/test_arena.gd.uid new file mode 100644 index 0000000..3d60d17 --- /dev/null +++ b/scripts/test_arena.gd.uid @@ -0,0 +1 @@ +uid://dosf7di72b72k diff --git a/scripts/tests/ipc_test.gd b/scripts/tests/ipc_test.gd new file mode 100644 index 0000000..3f54c7a --- /dev/null +++ b/scripts/tests/ipc_test.gd @@ -0,0 +1,113 @@ +extends Node + +# Test script to demonstrate IPC communication between Godot and Python + +var simulation_manager: SimulationManager +var ipc_client: IPCClient +var agent: Agent +var tick_count: int = 0 + +func _ready(): + print("=== IPC Test Starting ===") + + # Create simulation manager + simulation_manager = SimulationManager.new() + simulation_manager.name = "SimulationManager" + add_child(simulation_manager) + + # Create IPC client + ipc_client = IPCClient.new() + ipc_client.name = "IPCClient" + ipc_client.server_url = "http://127.0.0.1:5000" + add_child(ipc_client) + + # Create test agent + agent = Agent.new() + agent.name = "TestAgent" + agent.agent_id = "agent_001" + add_child(agent) + + # Connect signals + ipc_client.response_received.connect(_on_response_received) + ipc_client.connection_failed.connect(_on_connection_failed) + simulation_manager.tick_advanced.connect(_on_tick_advanced) + + # Wait a frame for nodes to initialize + await get_tree().process_frame + + # Connect to Python server + print("Connecting to IPC server...") + ipc_client.connect_to_server("http://127.0.0.1:5000") + + # Wait for connection + await get_tree().create_timer(1.0).timeout + + if ipc_client.is_server_connected(): + print("Connected to IPC server!") + start_test() + else: + print("Failed to connect. Make sure Python IPC server is running:") + print(" cd python && python run_ipc_server.py") + +func start_test(): + print("Starting test simulation...") + simulation_manager.start_simulation() + + # Run for 10 ticks + for i in range(10): + await get_tree().create_timer(0.5).timeout + simulation_manager.step_simulation() + +func _on_tick_advanced(tick: int): + print("\n--- Tick ", tick, " ---") + + # Create perception data for agent + var perceptions = [] + var perception = { + "agent_id": agent.agent_id, + "tick": tick, + "position": [randf() * 10.0, 0.0, randf() * 10.0], + "rotation": [0.0, randf() * 360.0, 0.0], + "velocity": [0.0, 0.0, 0.0], + "visible_entities": [], + "inventory": [], + "health": 100.0, + "energy": 100.0, + "custom_data": {} + } + perceptions.append(perception) + + # Send tick request to Python + print("Sending tick request to Python...") + ipc_client.send_tick_request(tick, perceptions) + +func _on_response_received(response: Dictionary): + print("Received response from Python:") + print(" Tick: ", response.get("tick", -1)) + print(" Actions: ", response.get("actions", [])) + print(" Metrics: ", response.get("metrics", {})) + + # Execute actions + var actions = response.get("actions", []) + for action in actions: + var agent_id = action.get("agent_id", "") + var tool = action.get("tool", "") + var params = action.get("params", {}) + var reasoning = action.get("reasoning", "") + + print(" Agent ", agent_id, " action: ", tool) + if reasoning: + print(" Reasoning: ", reasoning) + + tick_count += 1 + if tick_count >= 10: + print("\n=== Test Complete ===") + simulation_manager.stop_simulation() + get_tree().quit() + +func _on_connection_failed(error: String): + print("Connection failed: ", error) + print("\nMake sure the Python IPC server is running:") + print(" cd python") + print(" python run_ipc_server.py") + get_tree().quit() diff --git a/scripts/tests/ipc_test.gd.uid b/scripts/tests/ipc_test.gd.uid new file mode 100644 index 0000000..a304530 --- /dev/null +++ b/scripts/tests/ipc_test.gd.uid @@ -0,0 +1 @@ +uid://7hsfpv21qbe8 diff --git a/scripts/tests/test_extension.gd b/scripts/tests/test_extension.gd new file mode 100644 index 0000000..f65b9df --- /dev/null +++ b/scripts/tests/test_extension.gd @@ -0,0 +1,36 @@ +extends Node + +# Simple test to verify GDExtension classes are available + +func _ready(): + print("=== Testing GDExtension Classes ===") + + # Test each class + var tests = [ + ["SimulationManager", SimulationManager], + ["EventBus", EventBus], + ["Agent", Agent], + ["ToolRegistry", ToolRegistry], + ["IPCClient", IPCClient] + ] + + var all_passed = true + for test_item in tests: + var test_name = test_item[0] + var type = test_item[1] + + var instance = type.new() + if instance: + print(" ✓ ", test_name, " - OK") + # RefCounted objects are automatically freed, don't call free() + else: + print(" ✗ ", test_name, " - FAILED") + all_passed = false + + print("=== Test Complete ===") + if all_passed: + print("All classes loaded successfully!") + else: + print("Some classes failed to load - rebuild may be needed") + + get_tree().quit() diff --git a/scripts/tests/test_extension.gd.uid b/scripts/tests/test_extension.gd.uid new file mode 100644 index 0000000..73b2ca8 --- /dev/null +++ b/scripts/tests/test_extension.gd.uid @@ -0,0 +1 @@ +uid://c4ohlhvnjq2vd