From ea0449f5b7a26af8aa6646852ca99f57a551c06b Mon Sep 17 00:00:00 2001 From: BChain Date: Mon, 27 Apr 2026 14:14:20 +0100 Subject: [PATCH 1/3] refactor(agents): specialize all agents for Python (Dash, Flask, FastAPI, ClickHouse) - Updated system prompts in `source.ts`, `codegen.ts`, `test.ts`, and `review.ts` to align with Python-specific expertise. - Enhanced `TestAgent` to detect Python projects (`requirements.txt`, `pyproject.toml`) and default to `pytest`. - Expanded prompts with detailed framework-specific behaviors and best practices. - Improved output formats for Python code and test files. --- .wolf/anatomy.md | 10 +-- .wolf/buglog.json | 96 ++++++++++++++++++++++++ .wolf/cerebrum.md | 3 + .wolf/hooks/_session.json | 77 ++++++++++++++++++- .wolf/memory.md | 9 +++ .wolf/token-ledger.json | 153 ++++++++++++++++++++++++++++++++++++-- src/agents/codegen.ts | 12 ++- src/agents/review.ts | 17 +++-- src/agents/source.ts | 61 ++++++++++----- src/agents/test.ts | 38 ++++++---- 10 files changed, 416 insertions(+), 60 deletions(-) diff --git a/.wolf/anatomy.md b/.wolf/anatomy.md index 54c9d17..ffd2b2f 100644 --- a/.wolf/anatomy.md +++ b/.wolf/anatomy.md @@ -1,6 +1,6 @@ # anatomy.md -> Auto-maintained by OpenWolf. Last scanned: 2026-04-27T09:27:38.664Z +> Auto-maintained by OpenWolf. Last scanned: 2026-04-27T13:11:28.059Z > Files: 145 tracked | Anatomy hits: 0 | Misses: 0 ## ../../../../../../../../home/brown/.claude/plans/ @@ -186,11 +186,11 @@ ## src/agents/ -- `codegen.ts` — CodeGen Agent — generates new code from a natural language spec and file context. (~1739 tok) -- `review.ts` — Review Agent — performs code review, identifies bugs, suggests improvements. (~1914 tok) +- `codegen.ts` — CodeGen Agent — generates new code from a natural language spec and file context. (~1990 tok) +- `review.ts` — Review Agent — performs code review, identifies bugs, suggests improvements. (~2244 tok) - `source.test.ts` — Agent source registry: each AgentType maps to the right embedded source (~404 tok) -- `source.ts` — Agent source code registry — returns the TypeScript source for each agent type. (~3610 tok) -- `test.ts` — Test Agent — writes and validates unit/integration tests. (~1898 tok) +- `source.ts` — Agent source code registry — returns the TypeScript source for each agent type. (~4536 tok) +- `test.ts` — Test Agent — writes and validates unit/integration tests. (~2197 tok) ## src/bindings/ diff --git a/.wolf/buglog.json b/.wolf/buglog.json index b5bcbda..7e8d7b5 100644 --- a/.wolf/buglog.json +++ b/.wolf/buglog.json @@ -51,6 +51,102 @@ "related_bugs": [], "occurrences": 1, "last_seen": "2026-04-27T09:27:38.697Z" + }, + { + "id": "bug-004", + "timestamp": "2026-04-27T13:10:04.224Z", + "error_message": "Function not marked async", + "file": "src/agents/source.ts", + "root_cause": "Function uses await but wasn't declared async", + "fix": "Added async modifier", + "tags": [ + "auto-detected", + "async-fix", + "ts" + ], + "related_bugs": [], + "occurrences": 2, + "last_seen": "2026-04-27T13:10:33.516Z" + }, + { + "id": "bug-005", + "timestamp": "2026-04-27T13:10:20.750Z", + "error_message": "Null/undefined access in ", + "file": "src/agents/source.ts", + "root_cause": "Property access on potentially null/undefined value", + "fix": "Added null safety (optional chaining or null check)", + "tags": [ + "auto-detected", + "null-safety", + "ts" + ], + "related_bugs": [], + "occurrences": 1, + "last_seen": "2026-04-27T13:10:20.750Z" + }, + { + "id": "bug-006", + "timestamp": "2026-04-27T13:10:47.486Z", + "error_message": "Function not marked async", + "file": "src/agents/codegen.ts", + "root_cause": "Function uses await but wasn't declared async", + "fix": "Added async modifier", + "tags": [ + "auto-detected", + "async-fix", + "ts" + ], + "related_bugs": [], + "occurrences": 1, + "last_seen": "2026-04-27T13:10:47.486Z" + }, + { + "id": "bug-007", + "timestamp": "2026-04-27T13:10:55.677Z", + "error_message": "Null/undefined access in ", + "file": "src/agents/test.ts", + "root_cause": "Property access on potentially null/undefined value", + "fix": "Added null safety (optional chaining or null check)", + "tags": [ + "auto-detected", + "null-safety", + "ts" + ], + "related_bugs": [], + "occurrences": 1, + "last_seen": "2026-04-27T13:10:55.677Z" + }, + { + "id": "bug-008", + "timestamp": "2026-04-27T13:11:05.864Z", + "error_message": "Significant refactor of ", + "file": "src/agents/test.ts", + "root_cause": "8 lines replaced/restructured", + "fix": "Rewrote 15→17 lines (8 removed)", + "tags": [ + "auto-detected", + "refactor", + "ts" + ], + "related_bugs": [], + "occurrences": 1, + "last_seen": "2026-04-27T13:11:05.864Z" + }, + { + "id": "bug-009", + "timestamp": "2026-04-27T13:11:28.094Z", + "error_message": "Missing await", + "file": "src/agents/review.ts", + "root_cause": "Async call without await — returned Promise instead of value", + "fix": "Added await to async call", + "tags": [ + "auto-detected", + "async-fix", + "ts" + ], + "related_bugs": [], + "occurrences": 1, + "last_seen": "2026-04-27T13:11:28.094Z" } ] } \ No newline at end of file diff --git a/.wolf/cerebrum.md b/.wolf/cerebrum.md index aef30d1..4e09979 100644 --- a/.wolf/cerebrum.md +++ b/.wolf/cerebrum.md @@ -12,6 +12,9 @@ - **Project:** agent-orchestrator - **Description:** AI Agent Orchestration Platform on Cloudflare Dynamic Workers +- **Agent domain expertise:** All agents (CodeGen, Test, Review) are configured for Python + Plotly Dash + Flask + FastAPI + ClickHouse. System prompts updated in both `src/agents/source.ts` (runtime embedded strings) and the individual reference `.ts` files. +- **Two places to update agent prompts:** `source.ts` contains the actual runtime embedded source (escaped backticks as `\\\``). The individual `codegen.ts`, `test.ts`, `review.ts` files are typed reference implementations — both must be kept in sync. +- **Test framework detection:** TestAgent checks for `requirements.txt` / `pyproject.toml` first (→ pytest), then falls back to `package.json` (→ vitest/jest/mocha). Default is now `pytest`. ## Do-Not-Repeat diff --git a/.wolf/hooks/_session.json b/.wolf/hooks/_session.json index afefca6..3ecbdad 100644 --- a/.wolf/hooks/_session.json +++ b/.wolf/hooks/_session.json @@ -21,6 +21,31 @@ "count": 1, "tokens": 231, "first_read": "2026-04-27T09:25:05.130Z" + }, + "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/source.ts": { + "count": 1, + "tokens": 3610, + "first_read": "2026-04-27T13:08:13.357Z" + }, + "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/types.ts": { + "count": 1, + "tokens": 1708, + "first_read": "2026-04-27T13:08:25.705Z" + }, + "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/codegen.ts": { + "count": 1, + "tokens": 1739, + "first_read": "2026-04-27T13:09:17.229Z" + }, + "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/test.ts": { + "count": 1, + "tokens": 1898, + "first_read": "2026-04-27T13:09:17.614Z" + }, + "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/review.ts": { + "count": 1, + "tokens": 1914, + "first_read": "2026-04-27T13:09:17.862Z" } }, "files_written": [ @@ -65,6 +90,48 @@ "action": "edit", "tokens": 10, "at": "2026-04-27T09:27:38.685Z" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/source.ts", + "action": "edit", + "tokens": 406, + "at": "2026-04-27T13:10:04.212Z" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/source.ts", + "action": "edit", + "tokens": 592, + "at": "2026-04-27T13:10:20.735Z" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/source.ts", + "action": "edit", + "tokens": 498, + "at": "2026-04-27T13:10:33.500Z" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/codegen.ts", + "action": "edit", + "tokens": 378, + "at": "2026-04-27T13:10:47.474Z" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/test.ts", + "action": "edit", + "tokens": 240, + "at": "2026-04-27T13:10:55.665Z" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/test.ts", + "action": "edit", + "tokens": 364, + "at": "2026-04-27T13:11:05.852Z" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/review.ts", + "action": "edit", + "tokens": 450, + "at": "2026-04-27T13:11:28.081Z" } ], "edit_counts": { @@ -72,11 +139,15 @@ "examples/task-ui/.dockerignore": 1, "examples/task-ui/vite.config.ts": 1, "docker-compose.dev.yml": 2, - "Dockerfile": 2 + "Dockerfile": 2, + "src/agents/source.ts": 3, + "src/agents/codegen.ts": 1, + "src/agents/test.ts": 2, + "src/agents/review.ts": 1 }, - "anatomy_hits": 4, + "anatomy_hits": 9, "anatomy_misses": 0, "repeated_reads_warned": 2, "cerebrum_warnings": 0, - "stop_count": 4 + "stop_count": 5 } \ No newline at end of file diff --git a/.wolf/memory.md b/.wolf/memory.md index 923d002..2c78218 100644 --- a/.wolf/memory.md +++ b/.wolf/memory.md @@ -53,3 +53,12 @@ | 10:27 | Edited Dockerfile | "/sbin/tini" → "/usr/bin/tini" | ~10 | | 10:30 | Session end: 7 writes across 4 files (Dockerfile, .dockerignore, vite.config.ts, docker-compose.dev.yml) | 4 reads | ~1784 tok | | 10:30 | Session end: 7 writes across 4 files (Dockerfile, .dockerignore, vite.config.ts, docker-compose.dev.yml) | 4 reads | ~1784 tok | +| 14:10 | Edited src/agents/source.ts | expanded (+6 lines) | ~406 | +| 14:10 | Edited src/agents/source.ts | added 1 condition(s) | ~592 | +| 14:10 | Edited src/agents/source.ts | 9→12 lines | ~498 | +| 14:10 | Edited src/agents/codegen.ts | expanded (+6 lines) | ~378 | +| 14:10 | Edited src/agents/test.ts | added 1 condition(s) | ~240 | +| 14:11 | Edited src/agents/test.ts | 15→17 lines | ~364 | +| 14:11 | Edited src/agents/review.ts | 8→11 lines | ~450 | +| 14:12 | Configured all agents as Python/Dash/Flask/FastAPI/ClickHouse experts | src/agents/source.ts, codegen.ts, test.ts, review.ts | Updated system prompts in runtime embedded source + reference implementations; pytest detection added | ~400 | +| 14:13 | Session end: 14 writes across 8 files (Dockerfile, .dockerignore, vite.config.ts, docker-compose.dev.yml, source.ts) | 9 reads | ~15581 tok | diff --git a/.wolf/token-ledger.json b/.wolf/token-ledger.json index 4282f18..f7335fb 100644 --- a/.wolf/token-ledger.json +++ b/.wolf/token-ledger.json @@ -2,14 +2,14 @@ "version": 1, "created_at": "2026-04-23T20:26:46.638Z", "lifetime": { - "total_tokens_estimated": 168780, - "total_reads": 36, - "total_writes": 126, + "total_tokens_estimated": 184361, + "total_reads": 45, + "total_writes": 140, "total_sessions": 2, - "anatomy_hits": 30, + "anatomy_hits": 39, "anatomy_misses": 0, - "repeated_reads_blocked": 5, - "estimated_savings_vs_bare_cli": 8354 + "repeated_reads_blocked": 7, + "estimated_savings_vs_bare_cli": 11098 }, "sessions": [ { @@ -1026,6 +1026,147 @@ "repeated_reads_blocked": 2, "anatomy_lookups": 4 } + }, + { + "id": "session-2026-04-26-2002", + "started": "2026-04-26T19:02:51.922Z", + "ended": "2026-04-27T13:13:05.272Z", + "reads": [ + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/docker-compose.dev.yml", + "tokens_estimated": 466, + "was_repeated": true, + "anatomy_had_description": false + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/examples/task-ui/vite.config.ts", + "tokens_estimated": 172, + "was_repeated": false, + "anatomy_had_description": false + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/Dockerfile", + "tokens_estimated": 478, + "was_repeated": true, + "anatomy_had_description": false + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/docker-compose.yml", + "tokens_estimated": 231, + "was_repeated": false, + "anatomy_had_description": false + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/source.ts", + "tokens_estimated": 3610, + "was_repeated": false, + "anatomy_had_description": false + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/types.ts", + "tokens_estimated": 1708, + "was_repeated": false, + "anatomy_had_description": false + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/codegen.ts", + "tokens_estimated": 1739, + "was_repeated": false, + "anatomy_had_description": false + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/test.ts", + "tokens_estimated": 1898, + "was_repeated": false, + "anatomy_had_description": false + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/review.ts", + "tokens_estimated": 1914, + "was_repeated": false, + "anatomy_had_description": false + } + ], + "writes": [ + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/examples/task-ui/Dockerfile", + "tokens_estimated": 48, + "action": "create" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/examples/task-ui/.dockerignore", + "tokens_estimated": 7, + "action": "create" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/examples/task-ui/vite.config.ts", + "tokens_estimated": 13, + "action": "edit" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/docker-compose.dev.yml", + "tokens_estimated": 94, + "action": "edit" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/docker-compose.dev.yml", + "tokens_estimated": 219, + "action": "edit" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/Dockerfile", + "tokens_estimated": 46, + "action": "edit" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/Dockerfile", + "tokens_estimated": 10, + "action": "edit" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/source.ts", + "tokens_estimated": 406, + "action": "edit" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/source.ts", + "tokens_estimated": 592, + "action": "edit" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/source.ts", + "tokens_estimated": 498, + "action": "edit" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/codegen.ts", + "tokens_estimated": 378, + "action": "edit" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/test.ts", + "tokens_estimated": 240, + "action": "edit" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/test.ts", + "tokens_estimated": 364, + "action": "edit" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/review.ts", + "tokens_estimated": 450, + "action": "edit" + } + ], + "totals": { + "input_tokens_estimated": 12216, + "output_tokens_estimated": 3365, + "reads_count": 9, + "writes_count": 14, + "repeated_reads_blocked": 2, + "anatomy_lookups": 9 + } } ], "daemon_usage": [], diff --git a/src/agents/codegen.ts b/src/agents/codegen.ts index 6b4e7f3..3bc53b8 100644 --- a/src/agents/codegen.ts +++ b/src/agents/codegen.ts @@ -70,10 +70,16 @@ export class CodeGenAgent extends WorkerEntrypoint { const relatedSymbols = await this.gatherContext(targetFiles); const systemPrompt = [ - "You are an expert software engineer. Generate production-quality code.", + "You are an expert Python engineer specializing in Plotly Dash, Flask, FastAPI, and ClickHouse.", + "Generate production-quality Python code following PEP 8, with full type hints and async patterns where appropriate.", + "Stack expertise:", + "- Plotly Dash: layout components (dcc, html, dbc), callbacks with Input/Output/State, clientside callbacks, multi-page apps, DataTable, dcc.Store, pattern-matching callbacks", + "- Flask: application factory pattern, blueprints, SQLAlchemy ORM, Flask-Login, Jinja2 templates, request/response lifecycle, Flask-CORS", + "- FastAPI: path operations, Pydantic v2 models, dependency injection, async/await, middleware, background tasks, OpenAPI docs, HTTPException", + "- ClickHouse: SQL dialect, MergeTree/ReplacingMergeTree/AggregatingMergeTree engines, clickhouse-connect or aiochclient async client, batch inserts, materialized views, parametrized queries to prevent injection", "Return ONLY code blocks with file paths. Format each file as:", - "```filepath:path/to/file.ts", - "// code here", + "```filepath:path/to/file.py", + "# code here", "```", "Do not explain the code unless asked. Follow existing conventions exactly.", conventions ? `\nProject conventions:\n${conventions}` : "", diff --git a/src/agents/review.ts b/src/agents/review.ts index 858537a..deebaf2 100644 --- a/src/agents/review.ts +++ b/src/agents/review.ts @@ -75,13 +75,16 @@ export class ReviewAgent extends WorkerEntrypoint { const pastFeedback = await this.env.MEMORY.get("review-patterns"); const systemPrompt = [ - "You are a senior code reviewer. Analyze the code for:", - "1. Bugs and logic errors", - "2. Security vulnerabilities (injection, auth issues, data exposure)", - "3. Performance problems (N+1 queries, unnecessary allocations, blocking ops)", - "4. Code quality (naming, structure, duplication, complexity)", - "5. Missing error handling", - "6. Type safety issues", + "You are a senior Python code reviewer specializing in Plotly Dash, Flask, FastAPI, and ClickHouse. Analyze the code for:", + "1. Bugs and logic errors — Python-specific: mutable default arguments, late-binding closures, incorrect async/await, missing await on coroutines", + "2. Security vulnerabilities — ClickHouse SQL injection (require parametrized queries), missing FastAPI/Flask input validation, exposed secrets, CORS misconfiguration, missing authentication", + "3. Performance problems — N+1 queries, missing ClickHouse batch inserts, synchronous IO in async FastAPI routes, Dash callbacks triggering on every input unnecessarily", + "4. Dash-specific issues — callback Input/Output/State mismatches, missing prevent_initial_call, circular callback dependencies, missing allow_duplicate, improper dcc.Store usage", + "5. FastAPI issues — missing response_model, untyped path/query params, blocking calls in async routes, missing HTTPException, improper dependency lifetimes", + "6. ClickHouse issues — wrong engine selection, missing ORDER BY in MergeTree, inefficient aggregations, non-parametrized queries, missing TTL policies", + "7. Flask issues — missing application factory pattern, unmanaged db.session, unhandled exceptions as 500s, missing CSRF protection", + "8. Code quality — PEP 8 compliance, type hint coverage, snake_case naming, excessive complexity, code duplication", + "9. Missing error handling — uncaught exceptions, missing HTTP status codes, no logging on failure paths", "", "Return your review as a JSON array of comments:", '```json', diff --git a/src/agents/source.ts b/src/agents/source.ts index 7caa9e3..70eed76 100644 --- a/src/agents/source.ts +++ b/src/agents/source.ts @@ -48,10 +48,16 @@ export class CodeGenAgent extends WorkerEntrypoint { const conventions = await this.env.MEMORY?.get?.("coding-conventions").catch(() => null); const systemPrompt = [ - "You are an expert software engineer. Generate production-quality code.", + "You are an expert Python engineer specializing in Plotly Dash, Flask, FastAPI, and ClickHouse.", + "Generate production-quality Python code following PEP 8, with full type hints and async patterns where appropriate.", + "Stack expertise:", + "- Plotly Dash: layout components (dcc, html, dbc), callbacks with Input/Output/State, clientside callbacks, multi-page apps, DataTable, dcc.Store, pattern-matching callbacks", + "- Flask: application factory pattern, blueprints, SQLAlchemy ORM, Flask-Login, Jinja2 templates, request/response lifecycle, Flask-CORS", + "- FastAPI: path operations, Pydantic v2 models, dependency injection, async/await, middleware, background tasks, OpenAPI docs, HTTPException", + "- ClickHouse: SQL dialect, MergeTree/ReplacingMergeTree/AggregatingMergeTree engines, clickhouse-connect or aiochclient async client, batch inserts, materialized views, parametrized queries to prevent injection", "Return ONLY code blocks with file paths. Format each file as:", - "\\\`\\\`\\\`filepath:path/to/file.ts", - "// code here", + "\\\`\\\`\\\`filepath:path/to/file.py", + "# code here", "\\\`\\\`\\\`", "Do not explain the code unless asked. Follow existing conventions exactly.", conventions ? "\\nProject conventions:\\n" + conventions : "", @@ -152,23 +158,35 @@ export class TestAgent extends WorkerEntrypoint { } const conventions = await this.env.MEMORY?.get?.("test-conventions").catch(() => null); - let testFramework = "vitest"; + let testFramework = "pytest"; try { - const pkg = await this.env.FS.read("package.json"); - const parsed = JSON.parse(pkg); - const deps = { ...parsed.dependencies, ...parsed.devDependencies }; - if (deps.vitest) testFramework = "vitest"; - else if (deps.jest) testFramework = "jest"; - else if (deps.mocha) testFramework = "mocha"; + const requirements = await this.env.FS.read("requirements.txt").catch(() => null); + const pyproject = await this.env.FS.read("pyproject.toml").catch(() => null); + if (requirements !== null || pyproject !== null) { + testFramework = "pytest"; + } else { + const pkg = await this.env.FS.read("package.json"); + const parsed = JSON.parse(pkg); + const deps = { ...parsed.dependencies, ...parsed.devDependencies }; + if (deps.vitest) testFramework = "vitest"; + else if (deps.jest) testFramework = "jest"; + else if (deps.mocha) testFramework = "mocha"; + } } catch (e) {} const systemPrompt = [ - "You are an expert test engineer. Write comprehensive, well-structured tests.", + "You are an expert Python test engineer specializing in pytest, pytest-asyncio, and framework-specific testing patterns.", "Test framework: " + testFramework, + "Stack-specific testing patterns:", + "- FastAPI: use TestClient (sync) or httpx.AsyncClient with ASGITransport (async); parametrize endpoint tests; use pytest fixtures for app/client", + "- Flask: use app.test_client() with app_context fixture; test blueprints independently; mock external services", + "- Dash: use dash.testing.composite DashComposite with pytest-dash; Selenium-based callback integration tests", + "- ClickHouse: mock clickhouse_connect.get_client() with unittest.mock.patch; use pytest fixtures for connection setup/teardown", "Return ONLY code blocks with file paths. Format each file as:", - "\\\`\\\`\\\`filepath:path/to/file.test.ts", - "// test code here", + "\\\`\\\`\\\`filepath:tests/test_file.py", + "# test code here", "\\\`\\\`\\\`", + "Follow pytest conventions: fixtures in conftest.py, test_ prefix, assert statements (not unittest-style).", "Write tests that cover happy paths, edge cases, error handling, and input validation.", "Ensure tests are independent, deterministic, and fast.", conventions ? "\\nTest conventions:\\n" + conventions : "", @@ -270,13 +288,16 @@ export class ReviewAgent extends WorkerEntrypoint { const pastFeedback = await this.env.MEMORY?.get?.("review-patterns").catch(() => null); const systemPrompt = [ - "You are a senior code reviewer. Analyze the code for:", - "1. Bugs and logic errors", - "2. Security vulnerabilities", - "3. Performance problems", - "4. Code quality (naming, structure, duplication, complexity)", - "5. Missing error handling", - "6. Type safety issues", + "You are a senior Python code reviewer specializing in Plotly Dash, Flask, FastAPI, and ClickHouse. Analyze the code for:", + "1. Bugs and logic errors — Python-specific: mutable default arguments, late-binding closures, incorrect async/await, missing await on coroutines", + "2. Security vulnerabilities — ClickHouse SQL injection (require parametrized queries), missing FastAPI/Flask input validation, exposed secrets, CORS misconfiguration, missing authentication", + "3. Performance problems — N+1 queries, missing ClickHouse batch inserts, synchronous IO in async FastAPI routes, Dash callbacks triggering on every input change unnecessarily", + "4. Dash-specific issues — callback Input/Output/State mismatches, missing prevent_initial_call, circular callback dependencies, missing allow_duplicate, improper use of dcc.Store", + "5. FastAPI issues — missing response_model, untyped path/query params, blocking calls in async routes, missing HTTPException handling, improper dependency lifetimes", + "6. ClickHouse issues — wrong engine selection, missing ORDER BY in MergeTree, inefficient GROUP BY/aggregations, not using parametrized queries, missing TTL policies", + "7. Flask issues — missing application factory pattern, raw db.session without context management, unhandled exceptions bubbling as 500s, missing CSRF protection", + "8. Code quality — PEP 8 compliance, type hint coverage, naming conventions (snake_case), excessive complexity, code duplication", + "9. Missing error handling — uncaught exceptions, missing HTTP status codes, no logging on failure paths", "", "Return your review as a JSON array of comments:", "\\\`\\\`\\\`json", diff --git a/src/agents/test.ts b/src/agents/test.ts index 77aca84..aea490b 100644 --- a/src/agents/test.ts +++ b/src/agents/test.ts @@ -69,17 +69,19 @@ export class TestAgent extends WorkerEntrypoint { const conventions = await this.env.MEMORY.get("test-conventions"); const systemPrompt = [ - "You are an expert test engineer. Write comprehensive, well-structured tests.", + "You are an expert Python test engineer specializing in pytest, pytest-asyncio, and framework-specific testing patterns.", `Test framework: ${testFramework}`, + "Stack-specific testing patterns:", + "- FastAPI: use TestClient (sync) or httpx.AsyncClient with ASGITransport (async); parametrize endpoint tests; use pytest fixtures for app/client", + "- Flask: use app.test_client() with app_context fixture; test blueprints independently; mock external services", + "- Dash: use dash.testing.composite DashComposite with pytest-dash; Selenium-based callback integration tests", + "- ClickHouse: mock clickhouse_connect.get_client() with unittest.mock.patch; use pytest fixtures for connection setup/teardown", "Return ONLY code blocks with file paths. Format each file as:", - "```filepath:path/to/file.test.ts", - "// test code here", + "```filepath:tests/test_file.py", + "# test code here", "```", - "Write tests that cover:", - "- Happy path cases", - "- Edge cases and boundary conditions", - "- Error handling paths", - "- Input validation", + "Follow pytest conventions: fixtures in conftest.py, test_ prefix, assert statements (not unittest-style).", + "Write tests that cover happy paths, edge cases, error handling, and input validation.", "Ensure tests are independent, deterministic, and fast.", conventions ? `\nTest conventions:\n${conventions}` : "", ].join("\n"); @@ -170,20 +172,24 @@ export class TestAgent extends WorkerEntrypoint { } private async detectTestFramework(): Promise { + // Python projects take priority — check for requirements.txt or pyproject.toml + try { + const requirements = await this.env.FS.read("requirements.txt").catch(() => null); + const pyproject = await this.env.FS.read("pyproject.toml").catch(() => null); + if (requirements !== null || pyproject !== null) return "pytest"; + } catch { /* continue */ } + + // Fall back to JS framework detection try { const pkg = await this.env.FS.read("package.json"); const parsed = JSON.parse(pkg); - const allDeps = { - ...parsed.dependencies, - ...parsed.devDependencies, - }; + const allDeps = { ...parsed.dependencies, ...parsed.devDependencies }; if (allDeps.vitest) return "vitest"; if (allDeps.jest) return "jest"; if (allDeps.mocha) return "mocha"; - } catch { - // No package.json - } - return "vitest"; + } catch { /* no package.json */ } + + return "pytest"; } } From d2a09e3aa3ef15ce7c999ff0b3f79b4f62f18ca3 Mon Sep 17 00:00:00 2001 From: BChain Date: Mon, 27 Apr 2026 14:23:14 +0100 Subject: [PATCH 2/3] docs: add `WALKTHROUGH.md` for Task UI usage - Introduced a comprehensive 12-step guide on adding a filterable DataTable to a Dash app. - Covers task creation, reviewing agent outputs, approval workflows, PR generation, and follow-up testing. - Includes troubleshooting tips and cost insights for usage tracking. --- .wolf/anatomy.md | 5 +- .wolf/hooks/_session.json | 43 ++++- .wolf/memory.md | 3 + .wolf/token-ledger.json | 194 +++++++++++++++++++- WALKTHROUGH.md | 372 ++++++++++++++++++++++++++++++++++++++ 5 files changed, 606 insertions(+), 11 deletions(-) create mode 100644 WALKTHROUGH.md diff --git a/.wolf/anatomy.md b/.wolf/anatomy.md index ffd2b2f..ba1fb63 100644 --- a/.wolf/anatomy.md +++ b/.wolf/anatomy.md @@ -1,7 +1,7 @@ # anatomy.md -> Auto-maintained by OpenWolf. Last scanned: 2026-04-27T13:11:28.059Z -> Files: 145 tracked | Anatomy hits: 0 | Misses: 0 +> Auto-maintained by OpenWolf. Last scanned: 2026-04-27T13:19:12.118Z +> Files: 146 tracked | Anatomy hits: 0 | Misses: 0 ## ../../../../../../../../home/brown/.claude/plans/ @@ -25,6 +25,7 @@ - `README.md` — Project documentation (~2817 tok) - `tsconfig.json` — TypeScript configuration (~142 tok) - `tsconfig.test.json` — /*.ts", (~140 tok) +- `WALKTHROUGH.md` — Walkthrough: Adding a DataTable Feature to a Plotly Dash App (~3316 tok) - `wrangler.jsonc` (~392 tok) ## .claude/ diff --git a/.wolf/hooks/_session.json b/.wolf/hooks/_session.json index 3ecbdad..332e0ac 100644 --- a/.wolf/hooks/_session.json +++ b/.wolf/hooks/_session.json @@ -46,6 +46,36 @@ "count": 1, "tokens": 1914, "first_read": "2026-04-27T13:09:17.862Z" + }, + "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/examples/task-ui/src/pages/HomePage.tsx": { + "count": 1, + "tokens": 1542, + "first_read": "2026-04-27T13:17:23.773Z" + }, + "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/examples/task-ui/src/components/TaskForm.tsx": { + "count": 1, + "tokens": 4520, + "first_read": "2026-04-27T13:17:24.343Z" + }, + "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/examples/task-ui/src/pages/TaskPage.tsx": { + "count": 1, + "tokens": 2387, + "first_read": "2026-04-27T13:17:30.514Z" + }, + "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/examples/task-ui/src/components/TaskCard.tsx": { + "count": 1, + "tokens": 2006, + "first_read": "2026-04-27T13:17:30.963Z" + }, + "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/examples/task-ui/src/components/ReviewPanel.tsx": { + "count": 1, + "tokens": 2447, + "first_read": "2026-04-27T13:17:35.397Z" + }, + "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/examples/task-ui/src/components/UsageSidebar.tsx": { + "count": 1, + "tokens": 1122, + "first_read": "2026-04-27T13:17:36.003Z" } }, "files_written": [ @@ -132,6 +162,12 @@ "action": "edit", "tokens": 450, "at": "2026-04-27T13:11:28.081Z" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/WALKTHROUGH.md", + "action": "create", + "tokens": 3790, + "at": "2026-04-27T13:19:12.138Z" } ], "edit_counts": { @@ -143,11 +179,12 @@ "src/agents/source.ts": 3, "src/agents/codegen.ts": 1, "src/agents/test.ts": 2, - "src/agents/review.ts": 1 + "src/agents/review.ts": 1, + "WALKTHROUGH.md": 1 }, - "anatomy_hits": 9, + "anatomy_hits": 15, "anatomy_misses": 0, "repeated_reads_warned": 2, "cerebrum_warnings": 0, - "stop_count": 5 + "stop_count": 6 } \ No newline at end of file diff --git a/.wolf/memory.md b/.wolf/memory.md index 2c78218..f93ec17 100644 --- a/.wolf/memory.md +++ b/.wolf/memory.md @@ -62,3 +62,6 @@ | 14:11 | Edited src/agents/review.ts | 8→11 lines | ~450 | | 14:12 | Configured all agents as Python/Dash/Flask/FastAPI/ClickHouse experts | src/agents/source.ts, codegen.ts, test.ts, review.ts | Updated system prompts in runtime embedded source + reference implementations; pytest detection added | ~400 | | 14:13 | Session end: 14 writes across 8 files (Dockerfile, .dockerignore, vite.config.ts, docker-compose.dev.yml, source.ts) | 9 reads | ~15581 tok | +| 14:19 | Created WALKTHROUGH.md | — | ~3538 | +| 14:21 | Created WALKTHROUGH.md — end-to-end Task UI guide for adding Dash DataTable feature | WALKTHROUGH.md | 12-step guide covering form fields, live logs, review panel, approve/revise/reject, test agent follow-up, usage sidebar | ~300 | +| 14:21 | Session end: 15 writes across 9 files (Dockerfile, .dockerignore, vite.config.ts, docker-compose.dev.yml, source.ts) | 15 reads | ~33395 tok | diff --git a/.wolf/token-ledger.json b/.wolf/token-ledger.json index f7335fb..78c3a31 100644 --- a/.wolf/token-ledger.json +++ b/.wolf/token-ledger.json @@ -2,14 +2,14 @@ "version": 1, "created_at": "2026-04-23T20:26:46.638Z", "lifetime": { - "total_tokens_estimated": 184361, - "total_reads": 45, - "total_writes": 140, + "total_tokens_estimated": 217756, + "total_reads": 60, + "total_writes": 155, "total_sessions": 2, - "anatomy_hits": 39, + "anatomy_hits": 54, "anatomy_misses": 0, - "repeated_reads_blocked": 7, - "estimated_savings_vs_bare_cli": 11098 + "repeated_reads_blocked": 9, + "estimated_savings_vs_bare_cli": 15042 }, "sessions": [ { @@ -1167,6 +1167,188 @@ "repeated_reads_blocked": 2, "anatomy_lookups": 9 } + }, + { + "id": "session-2026-04-26-2002", + "started": "2026-04-26T19:02:51.922Z", + "ended": "2026-04-27T13:21:51.798Z", + "reads": [ + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/docker-compose.dev.yml", + "tokens_estimated": 466, + "was_repeated": true, + "anatomy_had_description": false + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/examples/task-ui/vite.config.ts", + "tokens_estimated": 172, + "was_repeated": false, + "anatomy_had_description": false + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/Dockerfile", + "tokens_estimated": 478, + "was_repeated": true, + "anatomy_had_description": false + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/docker-compose.yml", + "tokens_estimated": 231, + "was_repeated": false, + "anatomy_had_description": false + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/source.ts", + "tokens_estimated": 3610, + "was_repeated": false, + "anatomy_had_description": false + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/types.ts", + "tokens_estimated": 1708, + "was_repeated": false, + "anatomy_had_description": false + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/codegen.ts", + "tokens_estimated": 1739, + "was_repeated": false, + "anatomy_had_description": false + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/test.ts", + "tokens_estimated": 1898, + "was_repeated": false, + "anatomy_had_description": false + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/review.ts", + "tokens_estimated": 1914, + "was_repeated": false, + "anatomy_had_description": false + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/examples/task-ui/src/pages/HomePage.tsx", + "tokens_estimated": 1542, + "was_repeated": false, + "anatomy_had_description": false + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/examples/task-ui/src/components/TaskForm.tsx", + "tokens_estimated": 4520, + "was_repeated": false, + "anatomy_had_description": false + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/examples/task-ui/src/pages/TaskPage.tsx", + "tokens_estimated": 2387, + "was_repeated": false, + "anatomy_had_description": false + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/examples/task-ui/src/components/TaskCard.tsx", + "tokens_estimated": 2006, + "was_repeated": false, + "anatomy_had_description": false + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/examples/task-ui/src/components/ReviewPanel.tsx", + "tokens_estimated": 2447, + "was_repeated": false, + "anatomy_had_description": false + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/examples/task-ui/src/components/UsageSidebar.tsx", + "tokens_estimated": 1122, + "was_repeated": false, + "anatomy_had_description": false + } + ], + "writes": [ + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/examples/task-ui/Dockerfile", + "tokens_estimated": 48, + "action": "create" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/examples/task-ui/.dockerignore", + "tokens_estimated": 7, + "action": "create" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/examples/task-ui/vite.config.ts", + "tokens_estimated": 13, + "action": "edit" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/docker-compose.dev.yml", + "tokens_estimated": 94, + "action": "edit" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/docker-compose.dev.yml", + "tokens_estimated": 219, + "action": "edit" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/Dockerfile", + "tokens_estimated": 46, + "action": "edit" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/Dockerfile", + "tokens_estimated": 10, + "action": "edit" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/source.ts", + "tokens_estimated": 406, + "action": "edit" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/source.ts", + "tokens_estimated": 592, + "action": "edit" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/source.ts", + "tokens_estimated": 498, + "action": "edit" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/codegen.ts", + "tokens_estimated": 378, + "action": "edit" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/test.ts", + "tokens_estimated": 240, + "action": "edit" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/test.ts", + "tokens_estimated": 364, + "action": "edit" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/review.ts", + "tokens_estimated": 450, + "action": "edit" + }, + { + "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/WALKTHROUGH.md", + "tokens_estimated": 3790, + "action": "create" + } + ], + "totals": { + "input_tokens_estimated": 26240, + "output_tokens_estimated": 7155, + "reads_count": 15, + "writes_count": 15, + "repeated_reads_blocked": 2, + "anatomy_lookups": 15 + } } ], "daemon_usage": [], diff --git a/WALKTHROUGH.md b/WALKTHROUGH.md new file mode 100644 index 0000000..b54c306 --- /dev/null +++ b/WALKTHROUGH.md @@ -0,0 +1,372 @@ +# Walkthrough: Adding a DataTable Feature to a Plotly Dash App + +This guide walks through the complete end-to-end flow of using the Task UI to instruct +the Dynamic Workers agents to build a new filterable, sortable DataTable component in +your Plotly Dash application — from filling in the form to approving the finished code. + +--- + +## Prerequisites + +Make sure both containers are running before you start: + +```bash +docker compose -f docker-compose.yml -f docker-compose.dev.yml up --build +``` + +Verify: +- Orchestrator: `curl http://localhost:8787/health` → `{"status":"healthy",...}` +- Task UI: open `http://localhost:5173` in your browser + +--- + +## Overview of the flow + +``` +Fill form → Submit → Agent runs (live logs) → Review panel → Approve → PR created + ↓ + Request Revision → Agent retries +``` + +Each step is covered below in order. + +--- + +## Step 1 — Open the Task UI + +Navigate to `http://localhost:5173`. + +You will see a two-column layout: +- **Left panel** — the New Task form +- **Right panel** — Recent Tasks list and the Usage sidebar + +The form always defaults to `codegen` agent type, which is exactly what you need to +generate new Dash code. + +--- + +## Step 2 — Write the task description + +Click into the **Description** textarea (top of the left panel) and describe exactly +what you want the agent to build. Be specific — the more detail you give, the less +revision you will need later. + +**Example description for this walkthrough:** + +``` +Add a DataTable to the sales dashboard page that displays data from the ClickHouse +`sales_events` table. Requirements: +- Use dash_ag_grid (AgGrid) component, not the legacy dash_table.DataTable +- Columns: event_id, product_name, region, quantity, unit_price, total_value, event_ts +- Server-side pagination: 100 rows per page, controlled by dcc.Store('pagination-state') +- Column filters: text filter on product_name and region, number filter on quantity/unit_price +- Sorting: single-column sort, passes sort model back to ClickHouse ORDER BY clause +- The ClickHouse query must use parametrized queries via clickhouse_connect +- Loading state: show dcc.Loading spinner while data fetches +- Place the component in pages/sales.py and the ClickHouse query helper in data/sales_queries.py +``` + +> The description field requires a minimum of 10 characters and the form will show a +> validation error if it is left too short. + +--- + +## Step 3 — Select the Agent Type + +The **Agent Type** dropdown is directly below the description. Leave it set to +**`codegen`** for this task. + +The subtitle below the dropdown will read: +> *Generate new code from a natural language specification* + +Available agent types for reference: + +| Type | Use it when you want to… | +|---|---| +| `codegen` | Generate new code from a description | +| `test` | Write pytest tests for existing code | +| `review` | Review code for bugs and security issues | +| `refactor` | Restructure code without changing behaviour | +| `debug` | Diagnose and fix a failing test or runtime error | +| `dependency` | Update or audit Python package dependencies | + +--- + +## Step 4 — Fill in the Repository section + +The **Repository** fieldset tells the agent where to read and write code. All four +fields are required. + +| Field | Example value | Notes | +|---|---|---| +| **Owner** | `myorg` | Your GitHub user or organisation name | +| **Repository** | `dash-sales-dashboard` | Exact repo name — no URL, no `.git` | +| **Working Branch** | `agent/datatable-feature` | Auto-filled with `agent/task-`. You can rename it. The agent commits to this branch. | +| **Base Branch** | `main` | The branch the PR will be opened against when you approve | + +> The working branch is created in your repo automatically when the agent first +> commits. You do not need to create it manually. + +--- + +## Step 5 — Add file context (optional but strongly recommended) + +The **Files** section lets you paste existing code so the agent can match your +project's conventions and avoid writing code that clashes with what already exists. + +Click **+ Add File** to add each file. You will see two fields per entry: +- **File path** — relative path in your repo (e.g. `pages/sales.py`) +- **Content** — paste the current file contents here + +For the DataTable task, add these files as context: + +### File 1 — existing sales page +``` +File path: pages/sales.py +Content: +``` + +### File 2 — ClickHouse connection helper +``` +File path: data/db.py +Content: +``` + +### File 3 — app entry point (so the agent knows your layout structure) +``` +File path: app.py +Content: +``` + +### File 4 — requirements.txt (so the agent knows which packages are installed) +``` +File path: requirements.txt +Content: +``` + +> If you do not add file context, the agent will still generate code — it just will +> not know your existing variable names, import paths, or callback patterns, and you +> may need a revision round. Adding context produces better first-pass results. + +To remove a file entry, click the **✕** button on the right side of its row. + +--- + +## Step 6 — Advanced Config (optional) + +Click **Advanced Config** to expand the accordion. Leave everything at defaults for +most tasks. You may want to change: + +| Setting | When to change it | +|---|---| +| **Provider** | Switch from Anthropic to OpenAI if you prefer GPT-4o for this task | +| **Model** | Pin to a specific model version, e.g. `claude-opus-4-20250514` for maximum quality | +| **Max Tokens** | Increase to `16384` if the agent is generating many large files and getting cut off | +| **Max Retries** | Increase from `3` if your repo has flaky network and jobs sometimes fail transiently | +| **Temperature** | Drag toward 0 (Precise) for code tasks — deterministic output is almost always what you want | + +--- + +## Step 7 — Submit the task + +Click **Submit Task** at the bottom of the form. + +The button will show **Submitting…** briefly while the orchestrator accepts the task. +Once accepted, the UI automatically navigates to the **Task Detail page** for that task +(`/tasks/`). + +You will also see the task appear in the **Recent Tasks** list on the right panel so +you can return to it from the home page later. + +--- + +## Step 8 — Watch the Task Detail page + +The Task Detail page (`http://localhost:5173/tasks/`) has three panels: + +### Task Card (top-left) + +Shows the current status with a colour-coded badge: + +| Badge colour | Status | Meaning | +|---|---|---| +| Blue (pulsing) | `running` | Agent is actively generating code | +| Grey | `pending` / `assigned` | Queued, not started yet | +| Yellow | `review` | Agent finished — your approval is needed | +| Green | `completed` | Approved and PR created | +| Red | `failed` | Agent hit an unrecoverable error | + +The card also shows: +- The repo and working branch name +- Subtask list with per-subtask `✓` / `✗` / `○` indicators +- Token count and estimated cost once the agent finishes + +### Live Logs (top-right) + +A terminal-style streaming panel that shows real-time log output from the agent +while it is running. You will see lines like: + +``` +[codegen] Starting: Add a DataTable to the sales dashboard page... +[codegen] File pages/sales.py not found, will create new +[codegen] Wrote pages/sales.py (3,241 bytes) +[codegen] Wrote data/sales_queries.py (1,187 bytes) +[codegen] Complete in 14,302ms, commit: a3f9e12 +``` + +The connected indicator (green dot) shows the WebSocket is live. Once the task +reaches a terminal status (`completed`, `failed`, `review`) the stream stops and +the indicator shows *Task is no longer active — streaming stopped*. + +### Agent Results (bottom, after task finishes) + +A list of all subtask results, each showing: +- Agent type badge (`codegen`, `test`, etc.) +- Success/failure indicator +- Files written (clickable chip list) +- Token count and cost for that subtask + +--- + +## Step 9 — Human review + +When the agent finishes generating code, the task status changes to `review` and a +yellow **Human Review Required** panel appears below the logs. + +The review panel shows: + +### Files changed +A list of every file the agent wrote, e.g.: +``` +pages/sales.py +data/sales_queries.py +``` + +### Review comments +If a review agent ran as a subtask, its findings are listed here by severity: +- **Red** — `error`: bugs, security issues (e.g. non-parametrized ClickHouse query) +- **Yellow** — `warning`: performance issues (e.g. missing `prevent_initial_call`) +- **Grey** — `info`: style suggestions + +### Diff viewer +A syntax-highlighted git diff of every change the agent made, so you can see exactly +what was added or modified without leaving the browser. + +### Making your decision + +You have three options: + +#### Approve +Click **Approve** then **Confirm approve**. + +The orchestrator merges the working branch and opens a pull request against your base +branch. A **View PR on GitHub →** link appears immediately. The task status turns +green (`completed`). + +#### Request Revision +Click **Request Revision**, then type your feedback in the text box that appears, then +click **Confirm revise**. + +**Example revision feedback:** +``` +The DataTable is missing the dcc.Loading wrapper — add it around the AgGrid component. +Also the ClickHouse query in sales_queries.py is missing the LIMIT clause for pagination. +``` + +The agent will re-run with your feedback injected into its prompt and produce an +updated diff. The task returns to `running` and then `review` again. You can +iterate as many times as you need. + +#### Reject +Click **Reject**, enter a reason, then click **Confirm reject**. + +The task moves to `failed` with your rejection reason recorded. No PR is created. +Submit a new task if you want to try again with a different description. + +--- + +## Step 10 — Follow-up: run the Test agent + +After approving the DataTable implementation, submit a second task to generate tests +for it. Go back to the home page (`← Home` in the top-left) and fill in a new task: + +| Field | Value | +|---|---| +| **Description** | `Write pytest tests for the new AgGrid DataTable in pages/sales.py and data/sales_queries.py. Test the ClickHouse query builder with mocked clickhouse_connect, and test the Dash callbacks using TestClient.` | +| **Agent Type** | `test` | +| **Owner / Repo / Branches** | Same as before | +| **Files** | Add `pages/sales.py` and `data/sales_queries.py` from the branch the agent just wrote | + +The test agent automatically detects `requirements.txt` in the file context and sets +the framework to **pytest**. It will generate a `conftest.py` with fixtures and +`tests/test_sales_datatable.py` with mocked ClickHouse calls. + +--- + +## Step 11 — Look up a past task by ID + +If you lose track of a task, use the **Look up task by ID** input in the top-right +of the home page. Paste the full task ID (or the first 8 characters) and click **Go** +to jump directly to its detail page. + +Task IDs are shown on every task card. You can click the short ID on any card to copy +it to your clipboard. + +--- + +## Step 12 — Monitor costs in the Usage sidebar + +The **Usage** sidebar on the home page shows aggregate token consumption and estimated +cost across all tasks. Use the time filter buttons — **Today**, **7 days**, **All time** +— to scope the view. The sidebar refreshes every 30 seconds automatically. + +A typical DataTable `codegen` task costs approximately: +- ~3,000–6,000 input tokens (your description + file context) +- ~2,000–4,000 output tokens (generated code) +- ~$0.02–$0.08 estimated at Anthropic Sonnet pricing + +--- + +## Quick reference: full field values for this walkthrough + +| Field | Value used in this example | +|---|---| +| Description | *See Step 2* | +| Agent Type | `codegen` | +| Owner | `myorg` | +| Repository | `dash-sales-dashboard` | +| Working Branch | `agent/datatable-feature` | +| Base Branch | `main` | +| Files | `pages/sales.py`, `data/db.py`, `app.py`, `requirements.txt` | +| Provider | Default (Anthropic) | +| Model | Default (`claude-sonnet-4-20250514`) | +| Temperature | 0 (Precise) | + +--- + +## Troubleshooting + +**The form shows a validation error on Description** +The description must be at least 10 characters. Expand your description — more detail +also produces better output. + +**Task stays in `pending` for more than 30 seconds** +Check that the orchestrator container is still running: +```bash +docker compose -f docker-compose.yml -f docker-compose.dev.yml ps +curl http://localhost:8787/health +``` + +**Task fails immediately with an ENOENT or auth error** +Check your `.dev.vars` file. The agent needs `GITHUB_PAT` with `repo` scope to read +and write to your repository, and `ANTHROPIC_API_KEY` or `OPENAI_API_KEY` to call +the LLM. + +**Log stream shows "clickhouse_connect not found"** +The agent generates code for packages it expects to be installed. If `clickhouse_connect` +is not in your `requirements.txt`, add it as a file entry in the Files section so the +agent knows to import from the correct package or to add it to requirements. + +**Review panel does not appear** +Hard-refresh the page (`Ctrl+Shift+R`). The task must be in `review` status for the +panel to render — check the status badge on the TaskCard. From 7802d84cf71ebffdeb36b9f160983fced2e5c0c6 Mon Sep 17 00:00:00 2001 From: David Brown Date: Tue, 28 Apr 2026 11:39:43 +0100 Subject: [PATCH 3/3] chore: update session data and token ledger - Updated session information in `_session.json` to reflect the latest session on 2026-04-28. - Added new session entries in `token-ledger.json`, increasing total tokens estimated and reads. - Enhanced `settings.local.json` with an additional Bash command for listing files. - Expanded `memory.md` to include new session logs for better tracking of actions. --- .claude/settings.local.json | 3 +- .wolf/hooks/_session.json | 195 +++--------------------------------- .wolf/memory.md | 10 ++ .wolf/token-ledger.json | 68 +++++++++++-- 4 files changed, 88 insertions(+), 188 deletions(-) diff --git a/.claude/settings.local.json b/.claude/settings.local.json index dc8b5da..2d91e44 100644 --- a/.claude/settings.local.json +++ b/.claude/settings.local.json @@ -12,7 +12,8 @@ "Bash(pkill -f \"wrangler\" 2>/dev/null; pkill -f \"vite\" 2>/dev/null; pkill -f \"npm run dev\" 2>/dev/null; echo \"killed\")", "Bash(pkill -f \"wrangler\" 2>/dev/null || true; pkill -f \"vite\" 2>/dev/null || true; echo \"processes cleared\")", "Bash(docker compose:*)", - "Bash(docker run:*)" + "Bash(docker run:*)", + "Bash(ls:*)" ] } } diff --git a/.wolf/hooks/_session.json b/.wolf/hooks/_session.json index 332e0ac..c132ffa 100644 --- a/.wolf/hooks/_session.json +++ b/.wolf/hooks/_session.json @@ -1,190 +1,23 @@ { - "session_id": "session-2026-04-26-2002", - "started": "2026-04-26T19:02:51.922Z", + "session_id": "session-2026-04-28-1135", + "started": "2026-04-28T10:35:11.822Z", "files_read": { - "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/docker-compose.dev.yml": { - "count": 2, - "tokens": 466, - "first_read": "2026-04-26T19:03:05.318Z" - }, - "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/examples/task-ui/vite.config.ts": { - "count": 1, - "tokens": 172, - "first_read": "2026-04-26T19:03:05.974Z" - }, - "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/Dockerfile": { - "count": 2, - "tokens": 478, - "first_read": "2026-04-27T07:51:53.686Z" - }, - "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/docker-compose.yml": { - "count": 1, - "tokens": 231, - "first_read": "2026-04-27T09:25:05.130Z" - }, - "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/source.ts": { - "count": 1, - "tokens": 3610, - "first_read": "2026-04-27T13:08:13.357Z" - }, - "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/types.ts": { - "count": 1, - "tokens": 1708, - "first_read": "2026-04-27T13:08:25.705Z" - }, - "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/codegen.ts": { - "count": 1, - "tokens": 1739, - "first_read": "2026-04-27T13:09:17.229Z" - }, - "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/test.ts": { - "count": 1, - "tokens": 1898, - "first_read": "2026-04-27T13:09:17.614Z" - }, - "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/review.ts": { - "count": 1, - "tokens": 1914, - "first_read": "2026-04-27T13:09:17.862Z" - }, - "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/examples/task-ui/src/pages/HomePage.tsx": { - "count": 1, - "tokens": 1542, - "first_read": "2026-04-27T13:17:23.773Z" - }, - "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/examples/task-ui/src/components/TaskForm.tsx": { - "count": 1, - "tokens": 4520, - "first_read": "2026-04-27T13:17:24.343Z" - }, - "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/examples/task-ui/src/pages/TaskPage.tsx": { - "count": 1, - "tokens": 2387, - "first_read": "2026-04-27T13:17:30.514Z" - }, - "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/examples/task-ui/src/components/TaskCard.tsx": { - "count": 1, - "tokens": 2006, - "first_read": "2026-04-27T13:17:30.963Z" - }, - "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/examples/task-ui/src/components/ReviewPanel.tsx": { + "/Users/davidbrown/Documents/GitHub/dynamic-workers/docker-compose.dev.yml": { "count": 1, - "tokens": 2447, - "first_read": "2026-04-27T13:17:35.397Z" - }, - "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/examples/task-ui/src/components/UsageSidebar.tsx": { - "count": 1, - "tokens": 1122, - "first_read": "2026-04-27T13:17:36.003Z" - } - }, - "files_written": [ - { - "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/examples/task-ui/Dockerfile", - "action": "create", - "tokens": 48, - "at": "2026-04-26T19:03:09.208Z" - }, - { - "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/examples/task-ui/.dockerignore", - "action": "create", - "tokens": 7, - "at": "2026-04-26T19:03:10.030Z" - }, - { - "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/examples/task-ui/vite.config.ts", - "action": "edit", - "tokens": 13, - "at": "2026-04-26T19:03:11.573Z" - }, - { - "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/docker-compose.dev.yml", - "action": "edit", - "tokens": 94, - "at": "2026-04-26T19:03:14.108Z" - }, - { - "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/docker-compose.dev.yml", - "action": "edit", - "tokens": 219, - "at": "2026-04-27T07:52:40.801Z" - }, - { - "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/Dockerfile", - "action": "edit", - "tokens": 46, - "at": "2026-04-27T09:25:57.511Z" - }, - { - "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/Dockerfile", - "action": "edit", - "tokens": 10, - "at": "2026-04-27T09:27:38.685Z" - }, - { - "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/source.ts", - "action": "edit", - "tokens": 406, - "at": "2026-04-27T13:10:04.212Z" - }, - { - "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/source.ts", - "action": "edit", - "tokens": 592, - "at": "2026-04-27T13:10:20.735Z" - }, - { - "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/source.ts", - "action": "edit", "tokens": 498, - "at": "2026-04-27T13:10:33.500Z" + "first_read": "2026-04-28T10:35:47.958Z" }, - { - "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/codegen.ts", - "action": "edit", - "tokens": 378, - "at": "2026-04-27T13:10:47.474Z" - }, - { - "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/test.ts", - "action": "edit", - "tokens": 240, - "at": "2026-04-27T13:10:55.665Z" - }, - { - "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/test.ts", - "action": "edit", - "tokens": 364, - "at": "2026-04-27T13:11:05.852Z" - }, - { - "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/src/agents/review.ts", - "action": "edit", - "tokens": 450, - "at": "2026-04-27T13:11:28.081Z" - }, - { - "file": "/mnt/c/Users/brown/OneDrive/Documents/GitHub/dynamic-workers/WALKTHROUGH.md", - "action": "create", - "tokens": 3790, - "at": "2026-04-27T13:19:12.138Z" + "/Users/davidbrown/Documents/GitHub/dynamic-workers/.env.example": { + "count": 1, + "tokens": 0, + "first_read": "2026-04-28T10:36:11.277Z" } - ], - "edit_counts": { - "examples/task-ui/Dockerfile": 1, - "examples/task-ui/.dockerignore": 1, - "examples/task-ui/vite.config.ts": 1, - "docker-compose.dev.yml": 2, - "Dockerfile": 2, - "src/agents/source.ts": 3, - "src/agents/codegen.ts": 1, - "src/agents/test.ts": 2, - "src/agents/review.ts": 1, - "WALKTHROUGH.md": 1 }, - "anatomy_hits": 15, - "anatomy_misses": 0, - "repeated_reads_warned": 2, + "files_written": [], + "edit_counts": {}, + "anatomy_hits": 1, + "anatomy_misses": 1, + "repeated_reads_warned": 0, "cerebrum_warnings": 0, - "stop_count": 6 + "stop_count": 2 } \ No newline at end of file diff --git a/.wolf/memory.md b/.wolf/memory.md index f93ec17..730591f 100644 --- a/.wolf/memory.md +++ b/.wolf/memory.md @@ -65,3 +65,13 @@ | 14:19 | Created WALKTHROUGH.md | — | ~3538 | | 14:21 | Created WALKTHROUGH.md — end-to-end Task UI guide for adding Dash DataTable feature | WALKTHROUGH.md | 12-step guide covering form fields, live logs, review panel, approve/revise/reject, test agent follow-up, usage sidebar | ~300 | | 14:21 | Session end: 15 writes across 9 files (Dockerfile, .dockerignore, vite.config.ts, docker-compose.dev.yml, source.ts) | 15 reads | ~33395 tok | + +## Session: 2026-04-28 11:24 + +| Time | Action | File(s) | Outcome | ~Tokens | +|------|--------|---------|---------|--------| + +## Session: 2026-04-28 11:35 + +| Time | Action | File(s) | Outcome | ~Tokens | +|------|--------|---------|---------|--------| diff --git a/.wolf/token-ledger.json b/.wolf/token-ledger.json index 78c3a31..171a630 100644 --- a/.wolf/token-ledger.json +++ b/.wolf/token-ledger.json @@ -2,14 +2,14 @@ "version": 1, "created_at": "2026-04-23T20:26:46.638Z", "lifetime": { - "total_tokens_estimated": 217756, - "total_reads": 60, + "total_tokens_estimated": 218752, + "total_reads": 64, "total_writes": 155, - "total_sessions": 2, - "anatomy_hits": 54, - "anatomy_misses": 0, + "total_sessions": 4, + "anatomy_hits": 56, + "anatomy_misses": 2, "repeated_reads_blocked": 9, - "estimated_savings_vs_bare_cli": 15042 + "estimated_savings_vs_bare_cli": 15442 }, "sessions": [ { @@ -1349,6 +1349,62 @@ "repeated_reads_blocked": 2, "anatomy_lookups": 15 } + }, + { + "id": "session-2026-04-28-1135", + "started": "2026-04-28T10:35:11.822Z", + "ended": "2026-04-28T10:36:20.276Z", + "reads": [ + { + "file": "/Users/davidbrown/Documents/GitHub/dynamic-workers/docker-compose.dev.yml", + "tokens_estimated": 498, + "was_repeated": false, + "anatomy_had_description": false + }, + { + "file": "/Users/davidbrown/Documents/GitHub/dynamic-workers/.env.example", + "tokens_estimated": 0, + "was_repeated": false, + "anatomy_had_description": false + } + ], + "writes": [], + "totals": { + "input_tokens_estimated": 498, + "output_tokens_estimated": 0, + "reads_count": 2, + "writes_count": 0, + "repeated_reads_blocked": 0, + "anatomy_lookups": 1 + } + }, + { + "id": "session-2026-04-28-1135", + "started": "2026-04-28T10:35:11.822Z", + "ended": "2026-04-28T10:36:42.615Z", + "reads": [ + { + "file": "/Users/davidbrown/Documents/GitHub/dynamic-workers/docker-compose.dev.yml", + "tokens_estimated": 498, + "was_repeated": false, + "anatomy_had_description": false + }, + { + "file": "/Users/davidbrown/Documents/GitHub/dynamic-workers/.env.example", + "tokens_estimated": 0, + "was_repeated": false, + "anatomy_had_description": false + } + ], + "writes": [], + "totals": { + "input_tokens_estimated": 498, + "output_tokens_estimated": 0, + "reads_count": 2, + "writes_count": 0, + "repeated_reads_blocked": 0, + "anatomy_lookups": 1 + } } ], "daemon_usage": [],