jac-coder 0.2.0__tar.gz → 0.2.2__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {jac_coder-0.2.0 → jac_coder-0.2.2}/PKG-INFO +1 -1
- jac_coder-0.2.2/README.md +160 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/api.impl.jac +76 -77
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/api.jac +1 -6
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/core/nodes.impl.jac +12 -1
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/core/nodes.jac +26 -18
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/core/walkers.impl.jac +51 -45
- jac_coder-0.2.2/jac_coder/infra/kv.jac +111 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/infra/mcp_manager.impl.jac +56 -31
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/infra/mcp_manager.jac +7 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/lib/coder.impl.jac +91 -11
- jac_coder-0.2.2/jac_coder/runtime/cost_tracker.impl.jac +229 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/runtime/cost_tracker.jac +12 -12
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/runtime/events.jac +69 -5
- jac_coder-0.2.2/jac_coder/runtime/permission.impl.jac +171 -0
- jac_coder-0.2.2/jac_coder/runtime/permission.jac +55 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/runtime/prompt.jac +35 -14
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/runtime/skills.impl.jac +33 -9
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/runtime/skills.jac +7 -2
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/server.jac +44 -11
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/skills/ROADMAP.md +1 -1
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/skills/jac-cl-components/SKILL.md +4 -1
- jac_coder-0.2.2/jac_coder/skills/jac-cl-styling/SKILL.md +49 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/skills/jac-core-cheatsheet/SKILL.md +3 -1
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/skills/jac-fullstack-patterns/SKILL.md +4 -2
- jac_coder-0.2.2/jac_coder/skills/jac-npm-packages/SKILL.md +94 -0
- jac_coder-0.2.2/jac_coder/skills/jac-scaffold/SKILL.md +70 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/__init__.jac +0 -1
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/git.impl.jac +15 -14
- jac_coder-0.2.2/jac_coder/tool/git.jac +34 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/meta/delegation.impl.jac +6 -1
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/meta/delegation.jac +1 -0
- jac_coder-0.2.2/jac_coder/tool/meta/think.impl.jac +19 -0
- jac_coder-0.2.2/jac_coder/tool/meta/think.jac +9 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/read/filesystem.impl.jac +15 -11
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/run/guarded.impl.jac +32 -2
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/run/guarded.jac +4 -1
- jac_coder-0.2.2/jac_coder/tool/run/shell.impl.jac +206 -0
- jac_coder-0.2.2/jac_coder/tool/run/shell.jac +23 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/write/checked.impl.jac +3 -5
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder.egg-info/PKG-INFO +1 -1
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder.egg-info/SOURCES.txt +4 -11
- {jac_coder-0.2.0 → jac_coder-0.2.2}/pyproject.toml +1 -1
- jac_coder-0.2.0/README.md +0 -141
- jac_coder-0.2.0/jac_coder/runtime/cost_tracker.impl.jac +0 -134
- jac_coder-0.2.0/jac_coder/runtime/permission.impl.jac +0 -62
- jac_coder-0.2.0/jac_coder/runtime/permission.jac +0 -19
- jac_coder-0.2.0/jac_coder/skills/jac-scaffold/SKILL.md +0 -50
- jac_coder-0.2.0/jac_coder/tool/git.jac +0 -18
- jac_coder-0.2.0/jac_coder/tool/meta/think.impl.jac +0 -4
- jac_coder-0.2.0/jac_coder/tool/meta/think.jac +0 -5
- jac_coder-0.2.0/jac_coder/tool/run/shell.impl.jac +0 -152
- jac_coder-0.2.0/jac_coder/tool/run/shell.jac +0 -13
- jac_coder-0.2.0/jac_coder/tool/write/scaffold.impl.jac +0 -236
- jac_coder-0.2.0/jac_coder/tool/write/scaffold.jac +0 -12
- jac_coder-0.2.0/tests/test_context.py +0 -53
- jac_coder-0.2.0/tests/test_events.py +0 -40
- jac_coder-0.2.0/tests/test_graph.py +0 -33
- jac_coder-0.2.0/tests/test_interact.py +0 -40
- jac_coder-0.2.0/tests/test_jaccoder.py +0 -72
- jac_coder-0.2.0/tests/test_memory.py +0 -53
- jac_coder-0.2.0/tests/test_selfcorrect.py +0 -72
- jac_coder-0.2.0/tests/test_tools.py +0 -45
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/__init__.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/__init__.py +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/cli_entry.py +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/core/__init__.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/core/walkers.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/infra/__init__.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/infra/config.impl.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/infra/config.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/lib/__init__.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/lib/coder.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/runtime/__init__.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/runtime/context.impl.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/runtime/context.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/runtime/memory.impl.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/runtime/memory.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/runtime/prompt.impl.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/serve_entry.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/skills/jac-by-llm/SKILL.md +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/skills/jac-cl-auth/SKILL.md +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/skills/jac-cl-organization/SKILL.md +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/skills/jac-cl-routing/SKILL.md +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/skills/jac-has-fields/SKILL.md +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/skills/jac-impl-files/SKILL.md +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/skills/jac-node-edge-patterns/SKILL.md +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/skills/jac-sv-auth/SKILL.md +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/skills/jac-sv-endpoints/SKILL.md +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/skills/jac-sv-persistence/SKILL.md +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/skills/jac-types/SKILL.md +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/skills/jac-walker-patterns/SKILL.md +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/mcp.impl.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/mcp.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/meta/__init__.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/meta/question.impl.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/meta/question.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/meta/task.impl.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/meta/task.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/meta/todo.impl.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/meta/todo.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/meta/validate.impl.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/meta/validate.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/net/__init__.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/net/preview.impl.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/net/preview.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/net/web.impl.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/net/web.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/read/__init__.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/read/filesystem.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/read/jac_analyzer.impl.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/read/jac_analyzer.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/read/load_jac_skill.impl.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/read/load_jac_skill.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/read/search.impl.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/read/search.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/run/__init__.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/run/jac_tools.impl.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/run/jac_tools.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/write/__init__.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/tool/write/checked.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/util/__init__.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/util/colors.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/util/sandbox.impl.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/util/sandbox.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/util/tool_output.impl.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder/util/tool_output.jac +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder.egg-info/dependency_links.txt +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder.egg-info/entry_points.txt +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder.egg-info/requires.txt +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/jac_coder.egg-info/top_level.txt +0 -0
- {jac_coder-0.2.0 → jac_coder-0.2.2}/setup.cfg +0 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# JacCoder
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
AI coding agent for the Jaseci stack, built entirely in [Jac](https://github.com/jaseci-labs/jaseci) using Object-Spatial Programming. Features an orchestrator-worker architecture with compiler-level Jac Intelligence, self-correcting code writes, and in-process SubAgent delegation.
|
|
6
|
+
|
|
7
|
+
## Architecture
|
|
8
|
+
|
|
9
|
+

|
|
10
|
+
|
|
11
|
+
## Features
|
|
12
|
+
|
|
13
|
+
- **Orchestrator-Worker Architecture** — MainAgent (27 tools) handles tasks directly or delegates to focused WorkerAgent / ExplorerAgent walkers
|
|
14
|
+
- **Jac Intelligence** — compiler-level AST analysis via jaclang (`analyze_project`, `find_symbol`)
|
|
15
|
+
- **Skills System** — Claude-Code-compatible `SKILL.md` directories, lazy-loaded so the LLM gets authoritative Jac syntax instead of stale training data
|
|
16
|
+
- **Self-Correcting Writes** — automatic JS-to-Jac sanitization, in-process syntax check, and `.jac-server.log` error monitoring on every write
|
|
17
|
+
- **Browser Validation Loop** — `browser_validate` shells out to agent-browser with cross-turn FAIL escalation (1st: hint → 2nd: warning → 3rd+: mandatory bisect)
|
|
18
|
+
- **In-Process SubAgents** — walkers, not subprocesses; share event stream + cost tracker + graph context
|
|
19
|
+
- **MCP Integration** — built-in `jac-mcp` plus user-added stdio/http/sse servers, configs persisted in the graph
|
|
20
|
+
- **Multi-Provider LLM** — 100+ models via [byllm](https://github.com/jaseci-labs/byllm); per-session model + API-key override is thread-local (no `os.environ` mutation)
|
|
21
|
+
- **Public API** — clean interface for CLI, VS Code extension, JacBuilder, library mode
|
|
22
|
+
- **Context Management** — smart tiered compaction with LLM-summary fallback; mode-aware dynamic prompt assembly
|
|
23
|
+
|
|
24
|
+
## Prerequisites
|
|
25
|
+
|
|
26
|
+
- Python 3.12+
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
pip install jac-coder
|
|
30
|
+
# or for development:
|
|
31
|
+
pip install -e .
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Dependencies (auto-installed): `jaclang`, `byllm`, `mcp>=1.0.0`, `jac-mcp`, `python-dotenv`.
|
|
35
|
+
|
|
36
|
+
## Quick Start
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
# Set API key
|
|
40
|
+
export OPENAI_API_KEY="sk-..."
|
|
41
|
+
|
|
42
|
+
# Interactive REPL
|
|
43
|
+
jac cli.jac
|
|
44
|
+
|
|
45
|
+
# Single prompt (non-interactive)
|
|
46
|
+
jac cli.jac run "build a hello world jac app at /tmp/myapp"
|
|
47
|
+
|
|
48
|
+
# Resume a session
|
|
49
|
+
jac cli.jac session <id-prefix>
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
## Architecture
|
|
53
|
+
|
|
54
|
+
```
|
|
55
|
+
Root → Session → MainAgent
|
|
56
|
+
├── handles simple tasks directly (read, search, edit, git, browser)
|
|
57
|
+
└── spawn_agent() → WorkerAgent (write+run) or ExplorerAgent (read-only)
|
|
58
|
+
└── walker runs in-process, returns result to MainAgent
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
- **MainAgent (node)** — orchestrator with 27 tools. Handles simple tasks directly, delegates complex work via `spawn_agent`. `max_react_iterations=80`.
|
|
62
|
+
- **WorkerAgent (walker)** — in-process SubAgent with 14 tools (can write/edit/run). For known changes.
|
|
63
|
+
- **ExplorerAgent (walker)** — in-process SubAgent with 10 tools (read-only + web search). For root-cause investigation.
|
|
64
|
+
- **Session (node)** — persistent chat state, history, active files, errors, mode hint.
|
|
65
|
+
- **ProjectMemory (node)** — AST-derived codebase knowledge (nodes, walkers, edges, imports). Backed by `.jaccoder/progress.md` as primary source of truth.
|
|
66
|
+
- **McpRegistry (node)** — persisted MCP server configs.
|
|
67
|
+
|
|
68
|
+
See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for the full picture.
|
|
69
|
+
|
|
70
|
+
## Tools
|
|
71
|
+
|
|
72
|
+
MainAgent has 27 tools, grouped by domain:
|
|
73
|
+
|
|
74
|
+
| Group | Tool | Description |
|
|
75
|
+
|-------|------|-------------|
|
|
76
|
+
| Reason | `think` | Explicit reasoning step (loop-guarded) |
|
|
77
|
+
| Read | `read_file` | Read files with line numbers and pagination |
|
|
78
|
+
| Read | `list_files` | List directory contents |
|
|
79
|
+
| Read | `grep_search` | Regex search across files |
|
|
80
|
+
| Read | `find_files` | Find files by glob pattern |
|
|
81
|
+
| Read | `analyze_project` | Full AST analysis (nodes, walkers, edges, imports) |
|
|
82
|
+
| Read | `find_symbol` | Find symbol definition, fields, usages, exact import |
|
|
83
|
+
| Read | `load_jac_skill` | Load full body of a Jac skill by name |
|
|
84
|
+
| Write | `write_code` | Write file — anti-pattern blocking, auto sanitize, syntax check |
|
|
85
|
+
| Write | `edit_code` | Find-and-replace with the same self-correcting pipeline |
|
|
86
|
+
| Run | `run_command` | Execute shell commands (permission-guarded, auto-detects servers → background) |
|
|
87
|
+
| Run | `jac_run` | Run `.jac` files |
|
|
88
|
+
| Git | `git_status`, `git_diff`, `git_log`, `git_commit` | First-class git ops (`git_commit` is the only sanctioned way to commit) |
|
|
89
|
+
| Web | `web_fetch`, `web_search` | HTTP fetch + DuckDuckGo search |
|
|
90
|
+
| Browser | `browser_open`, `browser_do`, `browser_state`, `browser_validate`, `browser_close` | Visual QA via agent-browser; `browser_validate` is the primary pass/fail check |
|
|
91
|
+
| Delegate | `spawn_agent` | In-process WorkerAgent / ExplorerAgent walker |
|
|
92
|
+
| Interact | `ask_question`, `update_todos` | User prompt + multi-step task tracking |
|
|
93
|
+
| MCP | `mcp_call` | Call any tool from a connected MCP server |
|
|
94
|
+
|
|
95
|
+
## Public API
|
|
96
|
+
|
|
97
|
+
External apps import only from `jac_coder.api`:
|
|
98
|
+
|
|
99
|
+
```python
|
|
100
|
+
from jac_coder.api import initialize, create_session, chat, close_session
|
|
101
|
+
|
|
102
|
+
initialize("web")
|
|
103
|
+
session = create_session("/path/to/project", title="My App")
|
|
104
|
+
result = chat(session["session_id"], "build a calculator")
|
|
105
|
+
print(result["response"])
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
## Configuration
|
|
109
|
+
|
|
110
|
+
Config sources (highest priority first):
|
|
111
|
+
|
|
112
|
+
1. Environment: `MODEL`, `TEMPERATURE`, `MAX_TOKENS`, `MAX_REACT_ITERATIONS`
|
|
113
|
+
2. Project: `./jaccoder.json`
|
|
114
|
+
3. Global: `~/.jaccoder/config.json`
|
|
115
|
+
|
|
116
|
+
## Testing
|
|
117
|
+
|
|
118
|
+
```bash
|
|
119
|
+
python -m pytest tests/ -v # 10 unit suites
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
## Project Structure
|
|
123
|
+
|
|
124
|
+
```
|
|
125
|
+
jac-code/
|
|
126
|
+
├── cli.jac # CLI entry point (REPL + subcommands)
|
|
127
|
+
├── jac_coder/ # Core package
|
|
128
|
+
│ ├── api.jac # Public API — the only module external apps import
|
|
129
|
+
│ ├── server.jac # JSON-RPC stdio server for the VS Code extension
|
|
130
|
+
│ ├── core/
|
|
131
|
+
│ │ ├── nodes.jac # MainAgent, WorkerAgent, ExplorerAgent, Session, ProjectMemory
|
|
132
|
+
│ │ └── walkers.jac # interact, new_session, list_sessions, etc.
|
|
133
|
+
│ ├── lib/
|
|
134
|
+
│ │ └── coder.jac # JacCoder library-mode class (stateless + service modes)
|
|
135
|
+
│ ├── infra/
|
|
136
|
+
│ │ ├── config.jac # Multi-source config + SessionAwareModel (thread-local LLM override)
|
|
137
|
+
│ │ └── mcp_manager.jac # MCP server registry (graph-persisted)
|
|
138
|
+
│ ├── runtime/
|
|
139
|
+
│ │ ├── context.jac # Tiered compaction with LLM-summary fallback
|
|
140
|
+
│ │ ├── events.jac # Event bus, doom-loop detection, abort signal
|
|
141
|
+
│ │ ├── memory.jac # AST-first ProjectMemory (LLM fallback)
|
|
142
|
+
│ │ ├── permission.jac # Permission rule engine (allow / ask / deny)
|
|
143
|
+
│ │ ├── prompt.jac # Mode-aware dynamic prompt assembly
|
|
144
|
+
│ │ ├── skills.jac # SKILL.md registry + listing injection
|
|
145
|
+
│ │ └── cost_tracker.jac # Opt-in token + USD cost tracking
|
|
146
|
+
│ ├── tool/ # 28 tools organized by domain
|
|
147
|
+
│ │ ├── meta/ # think, spawn_agent, update_todos, ask_question, validate
|
|
148
|
+
│ │ ├── read/ # filesystem, search, jac_analyzer, load_jac_skill
|
|
149
|
+
│ │ ├── write/ # checked (write_code/edit_code), scaffold
|
|
150
|
+
│ │ ├── run/ # shell, guarded, jac_tools
|
|
151
|
+
│ │ ├── net/ # web, preview (browser_*)
|
|
152
|
+
│ │ ├── git.jac # git_status, git_diff, git_log, git_commit
|
|
153
|
+
│ │ └── mcp.jac # mcp_call
|
|
154
|
+
│ └── skills/ # Bundled SKILL.md directories (Claude-Code-compatible)
|
|
155
|
+
├── tests/ # 10 unit suites (pytest wrappers + check_*.jac)
|
|
156
|
+
├── vscode-jac-coder/ # VS Code extension (TypeScript)
|
|
157
|
+
└── docs/ # ARCHITECTURE, ROADMAP, PROGRESS, LIBRARY_MODE
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
<img width="2661" height="1091" alt="image" src="https://github.com/user-attachments/assets/a314087f-ae94-4c8b-8899-1e4ff3eb465c" />
|
|
@@ -107,9 +107,6 @@ impl create_session(directory: str, title: str = "", agent: str = "main") -> dic
|
|
|
107
107
|
return {"error": "Failed to create session"};
|
|
108
108
|
}
|
|
109
109
|
|
|
110
|
-
# Store in registry so background threads can find it
|
|
111
|
-
_session_registry[session_id] = session_obj;
|
|
112
|
-
|
|
113
110
|
return {"session_id": session_id, "title": session_title, "status": "created"};
|
|
114
111
|
}
|
|
115
112
|
|
|
@@ -166,7 +163,6 @@ impl close_session(session_id: str) -> dict {
|
|
|
166
163
|
}
|
|
167
164
|
matches[0].status = "closed";
|
|
168
165
|
matches[0].updated_at = datetime.now().isoformat();
|
|
169
|
-
_session_registry.pop(session_id, None);
|
|
170
166
|
return {"status": "closed", "id": matches[0].id};
|
|
171
167
|
}
|
|
172
168
|
|
|
@@ -185,15 +181,9 @@ impl chat(
|
|
|
185
181
|
edit_mode: str = "auto",
|
|
186
182
|
env_overrides: dict = {}
|
|
187
183
|
) -> dict {
|
|
188
|
-
# Find session —
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
matches = [root()-->][?:Session][?id==session_id];
|
|
192
|
-
if matches {
|
|
193
|
-
session = matches[0];
|
|
194
|
-
_session_registry[session_id] = session;
|
|
195
|
-
}
|
|
196
|
-
}
|
|
184
|
+
# Find session — query the graph directly. The graph is shared across pods
|
|
185
|
+
# via MongoDB persistence, so this works in single-pod and multi-pod alike.
|
|
186
|
+
session = _find_session(session_id);
|
|
197
187
|
if not session {
|
|
198
188
|
return {"error": "Session not found", "agent": "error"};
|
|
199
189
|
}
|
|
@@ -203,7 +193,6 @@ impl chat(
|
|
|
203
193
|
try {
|
|
204
194
|
_ = session.id;
|
|
205
195
|
} except Exception {
|
|
206
|
-
_session_registry.pop(session_id, None);
|
|
207
196
|
return {"error": "Session is stale after a server update. Please close this session and open a new one.", "agent": "error"};
|
|
208
197
|
}
|
|
209
198
|
|
|
@@ -220,8 +209,12 @@ impl chat(
|
|
|
220
209
|
if env_overrides {
|
|
221
210
|
import from jac_coder.infra.config { set_session_llm }
|
|
222
211
|
import logging as _chatlog;
|
|
223
|
-
_api_key = str(env_overrides.get("OPENAI_API_KEY", env_overrides.get("ANTHROPIC_API_KEY", "")));
|
|
224
212
|
_model_name = str(env_overrides.get("MODEL", ""));
|
|
213
|
+
if _model_name.startswith("claude-") {
|
|
214
|
+
_api_key = str(env_overrides.get("ANTHROPIC_API_KEY", ""));
|
|
215
|
+
} else {
|
|
216
|
+
_api_key = str(env_overrides.get("OPENAI_API_KEY", env_overrides.get("ANTHROPIC_API_KEY", "")));
|
|
217
|
+
}
|
|
225
218
|
_chatlog.getLogger("jac_coder.api").info(f"env_overrides received: model={_model_name} has_key={bool(_api_key)}");
|
|
226
219
|
if _api_key or _model_name {
|
|
227
220
|
import from jac_coder.infra.config { llm as _current_llm }
|
|
@@ -251,13 +244,6 @@ impl chat(
|
|
|
251
244
|
# Memory initialization
|
|
252
245
|
_ensure_memory(session, work_dir);
|
|
253
246
|
|
|
254
|
-
# Add user message
|
|
255
|
-
user_msg_record: dict = {"role": "user", "content": message};
|
|
256
|
-
if images and len(images) > 0 {
|
|
257
|
-
user_msg_record["has_images"] = True;
|
|
258
|
-
user_msg_record["image_count"] = len(images);
|
|
259
|
-
}
|
|
260
|
-
session.chat_history.append(user_msg_record);
|
|
261
247
|
session.updated_at = datetime.now().isoformat();
|
|
262
248
|
|
|
263
249
|
# Get MainAgent — always resolve fresh (cached refs go stale in jac start)
|
|
@@ -267,15 +253,33 @@ impl chat(
|
|
|
267
253
|
config = get_config();
|
|
268
254
|
_init_spawn_budget(config.max_react_iterations * 3);
|
|
269
255
|
|
|
270
|
-
#
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
256
|
+
# Per-turn context gets folded into the user message; we can't add
|
|
257
|
+
# role=system dicts to session.chat_history without them persisting stale.
|
|
258
|
+
prefix_parts: list[str] = [];
|
|
259
|
+
|
|
260
|
+
if session.project_summary {
|
|
261
|
+
is_progress_file = session.project_summary.lstrip().startswith("#");
|
|
262
|
+
label = (
|
|
263
|
+
"Project progress (.jaccoder/progress.md)"
|
|
264
|
+
if is_progress_file
|
|
265
|
+
else "Project context"
|
|
266
|
+
);
|
|
267
|
+
prefix_parts.append(
|
|
268
|
+
f"[INTERNAL — do NOT present this to the user unless they ask about the project. This is your background knowledge for making informed decisions.]\n{label}:\n{session.project_summary}"
|
|
269
|
+
);
|
|
270
|
+
}
|
|
271
|
+
if session.active_files {
|
|
272
|
+
prefix_parts.append("Active files: " + ", ".join(session.active_files));
|
|
273
|
+
}
|
|
274
|
+
if session.pending_errors {
|
|
275
|
+
prefix_parts.append("Pending errors:\n" + "\n".join(session.pending_errors));
|
|
276
|
+
}
|
|
277
|
+
|
|
278
|
+
mcp_msg = _get_mcp_context_msg();
|
|
279
|
+
if mcp_msg {
|
|
280
|
+
prefix_parts.append(str(mcp_msg.get("content", "")));
|
|
281
|
+
}
|
|
277
282
|
|
|
278
|
-
# Inject mode-aware workflow modules (dynamic prompt assembly)
|
|
279
283
|
import from jac_coder.runtime.prompt { select_prompt_modules as _select_modules }
|
|
280
284
|
workflow_modules = _select_modules(
|
|
281
285
|
last_mode_hint=session.last_mode_hint,
|
|
@@ -284,20 +288,28 @@ impl chat(
|
|
|
284
288
|
chat_history=session.chat_history
|
|
285
289
|
);
|
|
286
290
|
if workflow_modules {
|
|
287
|
-
|
|
291
|
+
prefix_parts.append(workflow_modules);
|
|
288
292
|
}
|
|
289
293
|
|
|
290
|
-
# Inject agent_context if provided (e.g. from JacBuilder)
|
|
291
294
|
if agent_context {
|
|
292
|
-
|
|
295
|
+
prefix_parts.append(agent_context);
|
|
293
296
|
}
|
|
294
297
|
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
298
|
+
if edit_mode == "plan" {
|
|
299
|
+
prefix_parts.append(
|
|
300
|
+
"You are in PLAN MODE. Your task is to produce a detailed, step-by-step plan "
|
|
301
|
+
"for the user's request. Do NOT write, edit, or run any files. "
|
|
302
|
+
"Describe every file you would create or modify, what changes you would make, "
|
|
303
|
+
"and why. The user will review your plan and click 'Execute Plan' to apply it."
|
|
304
|
+
);
|
|
299
305
|
}
|
|
300
306
|
|
|
307
|
+
composed_message = (
|
|
308
|
+
"\n\n---\n\n".join(prefix_parts) + "\n\n---\n\n" + message
|
|
309
|
+
if prefix_parts
|
|
310
|
+
else message
|
|
311
|
+
);
|
|
312
|
+
|
|
301
313
|
# Early exit if already aborted before LLM starts
|
|
302
314
|
if is_abort_requested() {
|
|
303
315
|
tool_end();
|
|
@@ -313,24 +325,6 @@ impl chat(
|
|
|
313
325
|
};
|
|
314
326
|
}
|
|
315
327
|
|
|
316
|
-
# Plan mode — inject instruction to write a plan only, no file writes.
|
|
317
|
-
# The UI will show "Execute Plan" when done; execution reruns with edit_mode="auto".
|
|
318
|
-
if edit_mode == "plan" {
|
|
319
|
-
plan_msg: dict = {
|
|
320
|
-
"role": "system",
|
|
321
|
-
"content": (
|
|
322
|
-
"You are in PLAN MODE. Your task is to produce a detailed, step-by-step plan "
|
|
323
|
-
"for the user's request. Do NOT write, edit, or run any files. "
|
|
324
|
-
"Describe every file you would create or modify, what changes you would make, "
|
|
325
|
-
"and why. The user will review your plan and click 'Execute Plan' to apply it."
|
|
326
|
-
)
|
|
327
|
-
};
|
|
328
|
-
ctx_with_plan: list[dict] = [plan_msg];
|
|
329
|
-
ctx_with_plan.extend(ctx_history);
|
|
330
|
-
ctx_history = ctx_with_plan;
|
|
331
|
-
}
|
|
332
|
-
|
|
333
|
-
# Call MainAgent — returns StreamEvent generator with logging enabled
|
|
334
328
|
# If user attached images, convert to byllm Image object and pass as user_image
|
|
335
329
|
user_image = None;
|
|
336
330
|
if images and len(images) > 0 {
|
|
@@ -346,7 +340,10 @@ impl chat(
|
|
|
346
340
|
sys.stderr.write(f"[api] Failed to create Image from user attachment: {img_err}\n");
|
|
347
341
|
}
|
|
348
342
|
}
|
|
349
|
-
|
|
343
|
+
|
|
344
|
+
main_agent._conv = session.chat_history;
|
|
345
|
+
|
|
346
|
+
event_stream = main_agent.respond(message=composed_message, user_image=user_image);
|
|
350
347
|
stream_result = _consume_llm_stream(event_stream);
|
|
351
348
|
|
|
352
349
|
response_text = stream_result["content"];
|
|
@@ -386,16 +383,22 @@ impl chat(
|
|
|
386
383
|
}
|
|
387
384
|
}
|
|
388
385
|
|
|
389
|
-
#
|
|
386
|
+
# byLLM already appended the assistant/tool turns; patch UI metadata
|
|
387
|
+
# onto the trailing assistant entry. Skip if aborted.
|
|
390
388
|
if not is_abort_requested() {
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
389
|
+
for idx in range(len(session.chat_history) - 1, -1, -1) {
|
|
390
|
+
message_entry = session.chat_history[idx];
|
|
391
|
+
if message_entry.get("role") == "assistant" and "agent" not in message_entry {
|
|
392
|
+
message_entry["agent"] = "main";
|
|
393
|
+
if tools_used {
|
|
394
|
+
message_entry["tools_used"] = tools_used;
|
|
395
|
+
}
|
|
396
|
+
if files_modified {
|
|
397
|
+
message_entry["files_modified"] = files_modified;
|
|
398
|
+
}
|
|
399
|
+
break;
|
|
400
|
+
}
|
|
397
401
|
}
|
|
398
|
-
session.chat_history.append(record);
|
|
399
402
|
}
|
|
400
403
|
session.last_agent = "main";
|
|
401
404
|
session.updated_at = datetime.now().isoformat();
|
|
@@ -557,7 +560,7 @@ impl api_mcp_list() -> list {
|
|
|
557
560
|
|
|
558
561
|
|
|
559
562
|
impl abort_session(session_id: str) -> None {
|
|
560
|
-
session =
|
|
563
|
+
session = _find_session(session_id);
|
|
561
564
|
if session {
|
|
562
565
|
session.chat_history.append({
|
|
563
566
|
"role": "assistant",
|
|
@@ -567,9 +570,14 @@ impl abort_session(session_id: str) -> None {
|
|
|
567
570
|
}
|
|
568
571
|
|
|
569
572
|
|
|
570
|
-
|
|
573
|
+
"""Build MCP tools context message for the LLM system prompt.
|
|
571
574
|
|
|
572
|
-
|
|
575
|
+
Rebuilt every turn — no module-level cache. The previous in-process cache
|
|
576
|
+
(`_mcp_ctx_cache`) was keyed on `frozenset(tool_names)`, so descriptions or
|
|
577
|
+
inputSchemas could change on another pod without invalidating the cache,
|
|
578
|
+
causing stale system prompts. Rebuild cost is ~50us of string formatting,
|
|
579
|
+
dominated by the LLM call that follows.
|
|
580
|
+
"""
|
|
573
581
|
def _get_mcp_context_msg() -> dict | None {
|
|
574
582
|
try {
|
|
575
583
|
mcp_tools = mcp_get_tools();
|
|
@@ -579,12 +587,6 @@ def _get_mcp_context_msg() -> dict | None {
|
|
|
579
587
|
if not mcp_tools {
|
|
580
588
|
return None;
|
|
581
589
|
}
|
|
582
|
-
# Check if tools changed since last call
|
|
583
|
-
current_names = frozenset(f"{t['server']}::{t['name']}" for t in mcp_tools);
|
|
584
|
-
if _mcp_ctx_cache.get("tool_names") == current_names {
|
|
585
|
-
return _mcp_ctx_cache.get("msg");
|
|
586
|
-
}
|
|
587
|
-
# Rebuild
|
|
588
590
|
lines: list = [
|
|
589
591
|
"Available MCP tools — call via mcp_call(server_name, tool_name, arguments_json):",
|
|
590
592
|
"Check each tool's inputSchema for required arguments before calling."
|
|
@@ -600,10 +602,7 @@ def _get_mcp_context_msg() -> dict | None {
|
|
|
600
602
|
}
|
|
601
603
|
lines.append(f" - server={t['server']} tool={t['name']} {t['description']}{schema_hint}");
|
|
602
604
|
}
|
|
603
|
-
|
|
604
|
-
_mcp_ctx_cache["msg"] = msg;
|
|
605
|
-
_mcp_ctx_cache["tool_names"] = current_names;
|
|
606
|
-
return msg;
|
|
605
|
+
return {"role": "system", "content": "\n".join(lines)};
|
|
607
606
|
}
|
|
608
607
|
|
|
609
608
|
|
|
@@ -13,7 +13,7 @@ import from jac_coder.util.tool_output { tool_end }
|
|
|
13
13
|
import from jac_coder.runtime.permission { permission_engine }
|
|
14
14
|
import from jac_coder.util.sandbox { set_sandbox_root, set_browser_exec }
|
|
15
15
|
import from jac_coder.runtime.context { build_context, ContextConfig }
|
|
16
|
-
import from jac_coder.core.walkers { new_session, ensure_main_agent, _consume_llm_stream }
|
|
16
|
+
import from jac_coder.core.walkers { new_session, ensure_main_agent, _consume_llm_stream, _find_session }
|
|
17
17
|
import from jac_coder.infra.mcp_manager {
|
|
18
18
|
mcp_add_server,
|
|
19
19
|
mcp_disconnect_server,
|
|
@@ -43,11 +43,6 @@ import from jac_coder.runtime.events {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
|
|
46
|
-
# Thread-safe session registry — graph root() is per-request in jac-cloud,
|
|
47
|
-
# so background threads can't find sessions via [root()-->]. This dict
|
|
48
|
-
# is module-level and accessible from any thread.
|
|
49
|
-
glob _session_registry: dict = {};
|
|
50
|
-
|
|
51
46
|
"""Initialize jac-coder."""
|
|
52
47
|
def initialize(mode: str = "web") -> None;
|
|
53
48
|
|
|
@@ -106,7 +106,17 @@ Respond to what the user is asking RIGHT NOW. Don't recap. Concise by default, d
|
|
|
106
106
|
|
|
107
107
|
## Delegation
|
|
108
108
|
- Simple (1-2 files, questions, git): handle directly.
|
|
109
|
-
- Multi-file or
|
|
109
|
+
- Multi-file, investigation, or complex: spawn_agent().
|
|
110
|
+
|
|
111
|
+
SubAgent cannot see this conversation. Every task string must be fully self-contained.
|
|
112
|
+
|
|
113
|
+
Before spawning worker: use think + read_file + grep_search until you know the exact change needed. Task string must include: file path:line, function/node name, exact problem, what NOT to touch.
|
|
114
|
+
Good: `Fix delegation.impl.jac:112 — has_errs hardcoded False, extract from result.errors. Don't touch above line 108.`
|
|
115
|
+
Bad: `Fix the error tracking bug` / `Based on what you found, fix it`
|
|
116
|
+
|
|
117
|
+
Mode: `explorer` = root cause unknown → investigate first, then YOU synthesize findings and spawn `worker`. `worker` = exact file and line known → implement directly.
|
|
118
|
+
|
|
119
|
+
Never delegate understanding. Task strings must prove you already know what to change.
|
|
110
120
|
""";
|
|
111
121
|
|
|
112
122
|
|
|
@@ -118,6 +128,7 @@ sem WorkerAgent.do_work = """
|
|
|
118
128
|
|
|
119
129
|
Expert Jac coder executing a delegated task. Never edit `.jac/` (compiled output).
|
|
120
130
|
|
|
131
|
+
|
|
121
132
|
## Iteration Budget
|
|
122
133
|
Build breadth-first — get all files written and app running before polishing. If a component fails after 2 fix attempts, write a minimal working version and move on. Never spend 10+ iterations on one file.
|
|
123
134
|
|
|
@@ -9,11 +9,10 @@ import from jac_coder.runtime.events { is_abort_requested }
|
|
|
9
9
|
|
|
10
10
|
# MainAgent tools — full orchestrator set
|
|
11
11
|
import from jac_coder.tool.meta.think { think }
|
|
12
|
-
import from jac_coder.tool.meta.delegation { spawn_agent }
|
|
12
|
+
import from jac_coder.tool.meta.delegation { spawn_agent, set_iter_count }
|
|
13
13
|
import from jac_coder.tool.meta.todo { update_todos }
|
|
14
14
|
import from jac_coder.tool.read.load_jac_skill { load_jac_skill }
|
|
15
15
|
import from jac_coder.tool.meta.question { ask_question }
|
|
16
|
-
import from jac_coder.tool.write.scaffold { scaffold_project }
|
|
17
16
|
import from jac_coder.tool.net.web { web_fetch, web_search }
|
|
18
17
|
import from jac_coder.tool.run.guarded { run_command }
|
|
19
18
|
import from jac_coder.tool.run.jac_tools { jac_check, jac_run }
|
|
@@ -83,6 +82,16 @@ obj SessionLearnings {
|
|
|
83
82
|
# ---------------------------------------------------------------------------
|
|
84
83
|
node McpRegistry {
|
|
85
84
|
has servers: dict[str, dict] = {};
|
|
85
|
+
has disconnected_servers: list[str] = [];
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
|
|
89
|
+
# ---------------------------------------------------------------------------
|
|
90
|
+
# UserPermissionRules — persists per-user "always allow" decisions in the graph
|
|
91
|
+
# so they are visible across pods (B3 / horizontal scaling).
|
|
92
|
+
node UserPermissionRules {
|
|
93
|
+
has user_id: str = "",
|
|
94
|
+
always_allowed: dict[str, list[str]] = {};
|
|
86
95
|
}
|
|
87
96
|
|
|
88
97
|
|
|
@@ -146,7 +155,10 @@ node Session {
|
|
|
146
155
|
# MainAgent — the orchestrator node
|
|
147
156
|
# ---------------------------------------------------------------------------
|
|
148
157
|
node MainAgent {
|
|
149
|
-
|
|
158
|
+
# Bound to Session.chat_history by the walker before each call.
|
|
159
|
+
has _conv: list[dict] = [];
|
|
160
|
+
|
|
161
|
+
def respond(message: str, user_image: Image | None = None) -> str by llm(
|
|
150
162
|
tools=[
|
|
151
163
|
# Think — explicit reasoning before acting or delegating
|
|
152
164
|
think,
|
|
@@ -163,7 +175,6 @@ node MainAgent {
|
|
|
163
175
|
write_code,
|
|
164
176
|
run_command,
|
|
165
177
|
jac_run,
|
|
166
|
-
scaffold_project,
|
|
167
178
|
# Git — first-class version control
|
|
168
179
|
git_status,
|
|
169
180
|
git_diff,
|
|
@@ -186,6 +197,7 @@ node MainAgent {
|
|
|
186
197
|
# MCP — call tools from connected MCP servers
|
|
187
198
|
mcp_call
|
|
188
199
|
],
|
|
200
|
+
conversation=self._conv,
|
|
189
201
|
on_iteration=_iteration_hook,
|
|
190
202
|
max_react_iterations=80,
|
|
191
203
|
temperature=0.2,
|
|
@@ -200,8 +212,9 @@ node MainAgent {
|
|
|
200
212
|
# SubAgent walkers — spawned on MainAgent node for task delegation
|
|
201
213
|
# ---------------------------------------------------------------------------
|
|
202
214
|
|
|
203
|
-
"""on_iteration callback — checks abort flag
|
|
215
|
+
"""on_iteration callback — checks abort flag and tracks real iteration count."""
|
|
204
216
|
def _iteration_hook(ctx: IterationContext) -> IterationAction {
|
|
217
|
+
set_iter_count(ctx.iteration);
|
|
205
218
|
if is_abort_requested() {
|
|
206
219
|
return IterationAction.ABORT;
|
|
207
220
|
}
|
|
@@ -217,6 +230,9 @@ walker WorkerAgent {
|
|
|
217
230
|
|
|
218
231
|
def do_work(task_str: str) -> str by llm(
|
|
219
232
|
tools=[
|
|
233
|
+
# Reason
|
|
234
|
+
think,
|
|
235
|
+
# Understand
|
|
220
236
|
load_jac_skill,
|
|
221
237
|
analyze_project,
|
|
222
238
|
find_symbol,
|
|
@@ -224,26 +240,18 @@ walker WorkerAgent {
|
|
|
224
240
|
list_files,
|
|
225
241
|
grep_search,
|
|
226
242
|
find_files,
|
|
243
|
+
# Act
|
|
227
244
|
write_code,
|
|
228
245
|
edit_code,
|
|
229
246
|
run_command,
|
|
230
247
|
jac_run,
|
|
231
|
-
|
|
248
|
+
# Git — status only, workers don't commit
|
|
232
249
|
git_status,
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
git_log,
|
|
236
|
-
web_fetch,
|
|
237
|
-
web_search,
|
|
238
|
-
browser_open,
|
|
239
|
-
browser_do,
|
|
240
|
-
browser_state,
|
|
241
|
-
browser_close,
|
|
242
|
-
browser_validate,
|
|
243
|
-
mcp_call
|
|
250
|
+
# Validate
|
|
251
|
+
browser_validate
|
|
244
252
|
],
|
|
245
253
|
on_iteration=_iteration_hook,
|
|
246
|
-
max_react_iterations=
|
|
254
|
+
max_react_iterations=30,
|
|
247
255
|
temperature=0.2,
|
|
248
256
|
max_tokens=8192,
|
|
249
257
|
stream=True,
|