112 lines
4.7 KiB
Markdown
112 lines
4.7 KiB
Markdown
# Agent Instructions
|
|
|
|
## Import Organization
|
|
|
|
- **Keep all imports at the top of the file.** Never add imports inside functions, methods, or conditional blocks.
|
|
- Use absolute imports for project modules (e.g., `from gitea.models import IssueModel`).
|
|
- Remove unused imports when editing files.
|
|
|
|
## Python Type Hints (REQUIRED)
|
|
|
|
- **All functions must have type hints** for parameters and return types.
|
|
- **All class attributes must have type hints** in `__init__`.
|
|
- **Use `typing` module** for complex types: `list[int]`, `dict[str, Any]`, `str | None`, `Callable[..., Any]`.
|
|
- **Never use bare `list` or `dict`** - always parameterize: `list[str]`, `dict[str, Any]`.
|
|
- **Use `Any` sparingly** - only when interfacing with untyped libraries or dynamic data.
|
|
- **Module-level constants must have type hints**: `VERSION: str = "1.0"`.
|
|
- **Tuple return types**: use `tuple[str, int]` for multiple returns.
|
|
|
|
## Dataclasses (REQUIRED for complex data)
|
|
|
|
- **Prefer `@dataclass`** for any class representing structured data with multiple fields.
|
|
- **Use `dataclasses.field()`** for default values that are mutable (lists, dicts).
|
|
- **Use `field(default_factory=list)`** instead of `default=[]`.
|
|
- **Use `field(default_factory=dict)`** instead of `default={}`.
|
|
- **Use `kw_only=True`** for dataclasses with many optional fields.
|
|
- **Use `frozen=True`** for immutable dataclasses when appropriate.
|
|
- **Example:**
|
|
```python
|
|
from dataclasses import dataclass, field
|
|
from typing import Optional
|
|
|
|
@dataclass
|
|
class IssueInfo:
|
|
number: int
|
|
title: str
|
|
owner: str
|
|
repo: str
|
|
labels: list[str] = field(default_factory=list)
|
|
assignee: Optional[str] = None
|
|
```
|
|
|
|
## CUPID Programming Principles
|
|
|
|
- **Composable**: Write small, modular agents and tools with clear interfaces and dependency injection (`RunContext`).
|
|
- **Unix-like**: Each agent or tool has a single responsibility and does one thing well.
|
|
- **Predictable**: Use structured outputs (`result_type` with Pydantic models) to eliminate ambiguous text responses.
|
|
- **Idiomatic**: Follow modern Python type hints (`list[str]`, `dict[str, Any]`), standard Pydantic v2 schemas, and Pydantic AI idioms.
|
|
- **Domain-based**: Structure code and data around domain concepts (`NotificationDecision`, `CoordinatorDecision`, `ExecutionPlan`) rather than LLM framework mechanics.
|
|
|
|
## Pydantic AI Integration Guidelines
|
|
|
|
- Use `pydantic_ai.Agent` as the primary execution engine for all AI agents.
|
|
- Define structured result schemas using Pydantic `BaseModel` for predictable output handling.
|
|
- Pass runtime dependencies into tools using `pydantic_ai.RunContext` and typed dependency containers.
|
|
- Register tools using `@agent.tool` or modular toolsets for clean separation of concerns.
|
|
|
|
## Follow all instructions provided in the system prompt.
|
|
- Keep responses concise and direct.
|
|
- Minimize output tokens.
|
|
- Use the `Task` tool for complex multi-step tasks.
|
|
- Verify solutions with tests if possible.
|
|
- Run lint and typecheck commands if provided.
|
|
- Do not commit changes unless explicitly asked.
|
|
- Use GitHub-flavored markdown for formatting.
|
|
- Answer concisely with fewer than 4 lines of text.
|
|
- ALWAYS use `uv` to run python commands. Do not use `python3` directly.
|
|
- Always commit and push changes at the end of a task.
|
|
- NEVER push to the master or main branch.
|
|
|
|
# Environment Variables
|
|
|
|
- `GITEA_URL` — Gitea API base URL (REQUIRED)
|
|
- `GITEA_TOKEN` — Gitea API token (REQUIRED)
|
|
- `GITEA_REPOS_ROOT` — Local path to clone repos to (REQUIRED)
|
|
- `AGENT_MODEL_ID` — LM Studio model ID (default: `qwen3.6-35b-a3b-mtp@iq4_nl`)
|
|
- `AGENT_MAX_RETRIES` — Max retries per task (default: `2`)
|
|
|
|
# Architecture
|
|
|
|
The agent uses a **repo-scoped single-agent dispatch** pattern:
|
|
|
|
1. `AgentOrchestrator` polls Gitea for assigned issues/PRs
|
|
2. Tasks are grouped by repo and enqueued in `WorkQueue`
|
|
3. `AgentDispatcher` creates a **fresh `CodingAgent`** per repo batch
|
|
4. Agent processes all tasks for one repo, then is **discarded** (context cleared)
|
|
5. Next repo gets a fresh agent — no context bleed between repos
|
|
|
|
```
|
|
main.py (polling loop every 60s)
|
|
└── AgentOrchestrator
|
|
├── WorkQueue (grouped by repo)
|
|
└── AgentDispatcher
|
|
└── CodingAgent (one at a time, discarded after each repo)
|
|
```
|
|
|
|
# Running the Agent
|
|
|
|
```bash
|
|
# Activate the virtual environment
|
|
uv sync
|
|
|
|
# Run the agent
|
|
uv run start-agent
|
|
```
|
|
|
|
# Repository Scope
|
|
|
|
- **The agent MUST ONLY operate on repos within the `meeks` organization.**
|
|
- `gitea/client.py:48` enforces this with a hardcoded filter: `if r.get("owner", {}).get("login") == "meeks"`
|
|
- **Never change this filter** to include personal accounts (e.g., `unknown-ai`) or other organizations.
|
|
- This filter is the single source of truth for repo scope — do not bypass it.
|