jac-coder 0.2.8__tar.gz → 0.2.9__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.8 → jac_coder-0.2.9}/PKG-INFO +5 -2
- {jac_coder-0.2.8 → jac_coder-0.2.9}/README.md +1 -3
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/api.impl.jac +0 -61
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/api.jac +1 -9
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/cli.jac +2 -7
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/core/nodes.impl.jac +0 -62
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/core/nodes.jac +1 -46
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/core/walkers.impl.jac +0 -1
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/core/walkers.jac +1 -9
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/infra/config.jac +0 -1
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/infra/events.jac +15 -3
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/infra/kv.jac +10 -1
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/infra/mcp_manager.jac +0 -1
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/lib/coder.impl.jac +1 -1
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/lib/coder.jac +1 -1
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/runtime/context.impl.jac +2 -2
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/runtime/cost_tracker.impl.jac +0 -2
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/runtime/file_logger.jac +0 -6
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/runtime/permission.impl.jac +1 -2
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/runtime/prompt.impl.jac +0 -4
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/runtime/prompt.jac +0 -2
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/runtime/skills.jac +0 -3
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/__init__.jac +0 -1
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/git.impl.jac +0 -2
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/meta/delegation.impl.jac +0 -3
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/meta/delegation.jac +1 -1
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/read/filesystem.impl.jac +0 -2
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/read/filesystem.jac +0 -1
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/read/jac_analyzer.impl.jac +0 -108
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/read/jac_analyzer.jac +0 -4
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/run/shell.jac +0 -1
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/write/checked.impl.jac +0 -3
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/util/tool_output.impl.jac +0 -2
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder.egg-info/PKG-INFO +5 -2
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder.egg-info/SOURCES.txt +0 -6
- jac_coder-0.2.9/jac_coder.egg-info/requires.txt +8 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/pyproject.toml +5 -2
- jac_coder-0.2.8/jac_coder/runtime/memory.impl.jac +0 -247
- jac_coder-0.2.8/jac_coder/runtime/memory.jac +0 -21
- jac_coder-0.2.8/jac_coder/tool/meta/task.impl.jac +0 -12
- jac_coder-0.2.8/jac_coder/tool/meta/task.jac +0 -9
- jac_coder-0.2.8/jac_coder/tool/meta/validate.impl.jac +0 -254
- jac_coder-0.2.8/jac_coder/tool/meta/validate.jac +0 -11
- jac_coder-0.2.8/jac_coder.egg-info/requires.txt +0 -5
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/__init__.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/__init__.py +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/cli.impl.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/cli_entry.py +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/core/__init__.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/infra/__init__.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/infra/config.impl.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/infra/mcp_manager.impl.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/lib/__init__.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/runtime/__init__.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/runtime/compaction.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/runtime/context.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/runtime/cost_tracker.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/runtime/events.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/runtime/permission.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/runtime/skills.impl.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/runtime/struggle_report.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/serve_entry.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/server.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/git.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/mcp.impl.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/mcp.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/meta/__init__.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/meta/clarify_intent.impl.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/meta/clarify_intent.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/meta/think.impl.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/meta/think.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/meta/todo.impl.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/meta/todo.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/net/__init__.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/net/preview.impl.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/net/preview.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/net/web.impl.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/net/web.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/read/__init__.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/read/load_jac_skill.impl.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/read/load_jac_skill.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/read/search.impl.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/read/search.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/run/__init__.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/run/guarded.impl.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/run/guarded.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/run/jac_tools.impl.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/run/jac_tools.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/run/shell.impl.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/write/__init__.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/tool/write/checked.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/util/__init__.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/util/banner.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/util/colors.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/util/md_render.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/util/sandbox.impl.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/util/sandbox.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder/util/tool_output.jac +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder.egg-info/dependency_links.txt +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder.egg-info/entry_points.txt +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/jac_coder.egg-info/top_level.txt +0 -0
- {jac_coder-0.2.8 → jac_coder-0.2.9}/setup.cfg +0 -0
|
@@ -1,10 +1,13 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jac-coder
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.9
|
|
4
4
|
Summary: AI coding agent backend for Jac, powered by jac-byllm
|
|
5
5
|
Requires-Python: >=3.12
|
|
6
6
|
Requires-Dist: python-dotenv>=1.0.0
|
|
7
|
-
Requires-Dist: jaclang
|
|
8
7
|
Requires-Dist: mcp>=1.0.0
|
|
9
8
|
Requires-Dist: jac-mcp
|
|
10
9
|
Requires-Dist: rich>=13.0
|
|
10
|
+
Requires-Dist: litellm<=1.82.6,>=1.70.0
|
|
11
|
+
Requires-Dist: httpx>=0.27.0
|
|
12
|
+
Requires-Dist: loguru<0.8.0,>=0.7.2
|
|
13
|
+
Requires-Dist: pillow<13.0.0,>=12.0.0
|
|
@@ -64,7 +64,6 @@ Root → Session → MainAgent
|
|
|
64
64
|
- **WorkerAgent (walker)** — in-process SubAgent with 14 tools (can write/edit/run). For known changes.
|
|
65
65
|
- **ExplorerAgent (walker)** — in-process SubAgent with 10 tools (read-only + web search). For root-cause investigation.
|
|
66
66
|
- **Session (node)** — persistent chat state, history, active files, errors, mode hint.
|
|
67
|
-
- **ProjectMemory (node)** — AST-derived codebase knowledge (nodes, walkers, edges, imports). Backed by `.jaccoder/progress.md` as primary source of truth.
|
|
68
67
|
- **McpRegistry (node)** — persisted MCP server configs.
|
|
69
68
|
|
|
70
69
|
See [docs/ARCHITECTURE.md](docs/ARCHITECTURE.md) for the full picture.
|
|
@@ -130,7 +129,7 @@ jac-code/
|
|
|
130
129
|
│ ├── api.jac # Public API — the only module external apps import
|
|
131
130
|
│ ├── server.jac # JSON-RPC stdio server for the VS Code extension
|
|
132
131
|
│ ├── core/
|
|
133
|
-
│ │ ├── nodes.jac # MainAgent, WorkerAgent, ExplorerAgent, Session
|
|
132
|
+
│ │ ├── nodes.jac # MainAgent, WorkerAgent, ExplorerAgent, Session
|
|
134
133
|
│ │ └── walkers.jac # interact, new_session, list_sessions, etc.
|
|
135
134
|
│ ├── lib/
|
|
136
135
|
│ │ └── coder.jac # JacCoder library-mode class (stateless + service modes)
|
|
@@ -140,7 +139,6 @@ jac-code/
|
|
|
140
139
|
│ ├── runtime/
|
|
141
140
|
│ │ ├── context.jac # Tiered compaction with LLM-summary fallback
|
|
142
141
|
│ │ ├── events.jac # Event bus, doom-loop detection, abort signal
|
|
143
|
-
│ │ ├── memory.jac # AST-first ProjectMemory (LLM fallback)
|
|
144
142
|
│ │ ├── permission.jac # Permission rule engine (allow / ask / deny)
|
|
145
143
|
│ │ ├── prompt.jac # Mode-aware dynamic prompt assembly
|
|
146
144
|
│ │ ├── skills.jac # SKILL.md registry + listing injection
|
|
@@ -197,7 +197,6 @@ impl chat(
|
|
|
197
197
|
return {"error": "Session is stale after a server update. Please close this session and open a new one.", "agent": "error"};
|
|
198
198
|
}
|
|
199
199
|
|
|
200
|
-
# Override directory if provided
|
|
201
200
|
if directory {
|
|
202
201
|
session.directory = directory;
|
|
203
202
|
}
|
|
@@ -230,7 +229,6 @@ impl chat(
|
|
|
230
229
|
# whether to auto-allow, prompt, or deny write/edit/bash operations.
|
|
231
230
|
_set_chat_session(session_id, edit_mode);
|
|
232
231
|
|
|
233
|
-
# Setup
|
|
234
232
|
clear_abort();
|
|
235
233
|
reset_steps();
|
|
236
234
|
start_turn();
|
|
@@ -242,7 +240,6 @@ impl chat(
|
|
|
242
240
|
}
|
|
243
241
|
|
|
244
242
|
try {
|
|
245
|
-
# Memory initialization
|
|
246
243
|
_ensure_memory(session, work_dir);
|
|
247
244
|
|
|
248
245
|
session.updated_at = datetime.now().isoformat();
|
|
@@ -367,7 +364,6 @@ impl chat(
|
|
|
367
364
|
files_modified = summary.get("files_modified", []);
|
|
368
365
|
has_errors = summary.get("errors", 0) > 0;
|
|
369
366
|
|
|
370
|
-
# Update session state
|
|
371
367
|
if files_modified {
|
|
372
368
|
for f in files_modified {
|
|
373
369
|
if f not in session.active_files {
|
|
@@ -483,63 +479,6 @@ def _ensure_memory(session: Session, work_dir: str) -> None {
|
|
|
483
479
|
}
|
|
484
480
|
|
|
485
481
|
|
|
486
|
-
def _post_process(session: Session, response_obj: Any) -> None {
|
|
487
|
-
# Track files
|
|
488
|
-
if response_obj.files_modified {
|
|
489
|
-
for f in response_obj.files_modified {
|
|
490
|
-
if f not in session.active_files {
|
|
491
|
-
session.active_files.append(f);
|
|
492
|
-
}
|
|
493
|
-
}
|
|
494
|
-
if len(session.active_files) > 10 {
|
|
495
|
-
session.active_files = session.active_files[-10:];
|
|
496
|
-
}
|
|
497
|
-
}
|
|
498
|
-
|
|
499
|
-
# Track errors
|
|
500
|
-
if response_obj.has_errors {
|
|
501
|
-
files_str = ", ".join(response_obj.files_modified)
|
|
502
|
-
if response_obj.files_modified
|
|
503
|
-
else "unknown";
|
|
504
|
-
session.pending_errors = [f"Errors in previous turn (files: {files_str})"];
|
|
505
|
-
} else {
|
|
506
|
-
session.pending_errors = [];
|
|
507
|
-
}
|
|
508
|
-
|
|
509
|
-
# Refresh project_summary from progress.md (agent may have updated it).
|
|
510
|
-
if session.directory {
|
|
511
|
-
progress_path = os.path.join(session.directory, ".jaccoder", "progress.md");
|
|
512
|
-
if os.path.isfile(progress_path) {
|
|
513
|
-
try {
|
|
514
|
-
with open(progress_path, "r", encoding="utf-8") as f {
|
|
515
|
-
pc = f.read();
|
|
516
|
-
}
|
|
517
|
-
if len(pc) > 4000 {
|
|
518
|
-
pc = pc[:4000] + "\n\n[... truncated]";
|
|
519
|
-
}
|
|
520
|
-
session.project_summary = pc;
|
|
521
|
-
} except Exception { }
|
|
522
|
-
}
|
|
523
|
-
}
|
|
524
|
-
|
|
525
|
-
# Persist response
|
|
526
|
-
record: dict = {
|
|
527
|
-
"role": "assistant",
|
|
528
|
-
"content": response_obj.content,
|
|
529
|
-
"agent": "main"
|
|
530
|
-
};
|
|
531
|
-
if response_obj.tools_used {
|
|
532
|
-
record["tools_used"] = response_obj.tools_used;
|
|
533
|
-
}
|
|
534
|
-
if response_obj.files_modified {
|
|
535
|
-
record["files_modified"] = response_obj.files_modified;
|
|
536
|
-
}
|
|
537
|
-
session.chat_history.append(record);
|
|
538
|
-
session.last_agent = "main";
|
|
539
|
-
session.updated_at = datetime.now().isoformat();
|
|
540
|
-
}
|
|
541
|
-
|
|
542
|
-
|
|
543
482
|
# ---------------------------------------------------------------------------
|
|
544
483
|
# Model management API
|
|
545
484
|
# ---------------------------------------------------------------------------
|
|
@@ -11,8 +11,7 @@ import from jac_coder.infra.config {
|
|
|
11
11
|
}
|
|
12
12
|
import from jac_coder.util.tool_output { tool_end }
|
|
13
13
|
import from jac_coder.runtime.permission { permission_engine }
|
|
14
|
-
import from jac_coder.util.sandbox { set_sandbox_root
|
|
15
|
-
import from jac_coder.runtime.context { build_context, ContextConfig }
|
|
14
|
+
import from jac_coder.util.sandbox { set_sandbox_root }
|
|
16
15
|
import from jac_coder.core.walkers {
|
|
17
16
|
new_session,
|
|
18
17
|
ensure_main_agent,
|
|
@@ -28,11 +27,6 @@ import from jac_coder.infra.mcp_manager {
|
|
|
28
27
|
mcp_get_tools,
|
|
29
28
|
mcp_register_builtin
|
|
30
29
|
}
|
|
31
|
-
import from jac_coder.runtime.memory {
|
|
32
|
-
find_or_create_memory,
|
|
33
|
-
_init_memory,
|
|
34
|
-
update_memory_from_session
|
|
35
|
-
}
|
|
36
30
|
import from jac_coder.core.nodes { Session, MainAgent }
|
|
37
31
|
import from jac_coder.runtime.cost_tracker {
|
|
38
32
|
get_summary as _ct_get_summary,
|
|
@@ -41,7 +35,6 @@ import from jac_coder.runtime.cost_tracker {
|
|
|
41
35
|
import from jac_coder.tool.run.guarded {
|
|
42
36
|
_set_chat_session,
|
|
43
37
|
_clear_chat_session,
|
|
44
|
-
_chat_contexts,
|
|
45
38
|
_clarification_events,
|
|
46
39
|
_clarification_decisions,
|
|
47
40
|
_CLRFY_KEY_PREFIX
|
|
@@ -52,7 +45,6 @@ import from jac_coder.runtime.events {
|
|
|
52
45
|
reset_steps,
|
|
53
46
|
start_turn,
|
|
54
47
|
emit_turn_summary,
|
|
55
|
-
emit_event,
|
|
56
48
|
is_abort_requested,
|
|
57
49
|
clear_abort
|
|
58
50
|
}
|
|
@@ -2,19 +2,15 @@
|
|
|
2
2
|
|
|
3
3
|
import os;
|
|
4
4
|
import sys;
|
|
5
|
-
import from datetime { datetime }
|
|
6
5
|
import from jac_coder.core.nodes { Session, MainAgent }
|
|
7
6
|
import from jac_coder.core.walkers {
|
|
8
7
|
new_session,
|
|
9
|
-
list_sessions,
|
|
10
|
-
get_session,
|
|
11
|
-
close_session,
|
|
12
8
|
interact,
|
|
13
9
|
ensure_main_agent
|
|
14
10
|
}
|
|
15
|
-
import from jac_coder.infra.config {
|
|
11
|
+
import from jac_coder.infra.config { model_name, get_config, set_model, get_model }
|
|
16
12
|
import from jac_coder.runtime.permission { permission_engine }
|
|
17
|
-
import from jac_coder.runtime.events { register_event_callback
|
|
13
|
+
import from jac_coder.runtime.events { register_event_callback }
|
|
18
14
|
import from jac_coder.runtime.file_logger { init_file_logger, file_log_event, close_file_logger }
|
|
19
15
|
import from jac_coder.tool.meta.todo { get_todos }
|
|
20
16
|
import from jac_coder.util.colors {
|
|
@@ -26,7 +22,6 @@ import from jac_coder.util.colors {
|
|
|
26
22
|
GREEN,
|
|
27
23
|
YELLOW,
|
|
28
24
|
RED,
|
|
29
|
-
MAGENTA,
|
|
30
25
|
WHITE,
|
|
31
26
|
AGENT_COLORS
|
|
32
27
|
}
|
|
@@ -14,68 +14,6 @@ impl Session.postinit{
|
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
|
|
17
|
-
# ---------------------------------------------------------------------------
|
|
18
|
-
# ProjectMemory
|
|
19
|
-
# ---------------------------------------------------------------------------
|
|
20
|
-
sem ProjectMemory.profile_project = """Analyze a Jac project and extract structured memory.
|
|
21
|
-
Given the file tree and key file contents, return:
|
|
22
|
-
- architecture: 1-2 sentences describing the project purpose, tech stack, and node/walker structure
|
|
23
|
-
- file_map: dict mapping up to 15 important file paths (relative) to 1-line descriptions of their role
|
|
24
|
-
- conventions: list of coding conventions observed (naming style, file organization, patterns)
|
|
25
|
-
Be concise and factual. This context will help future coding sessions start smart.""";
|
|
26
|
-
|
|
27
|
-
sem ProjectMemory.collect_learnings = """Extract learnings from a completed coding session.
|
|
28
|
-
Given the files modified and a session summary, return only NEW information:
|
|
29
|
-
- new_files: dict of newly created or significantly changed file paths to 1-line descriptions
|
|
30
|
-
- new_conventions: new coding patterns or conventions established (empty list if none)
|
|
31
|
-
- new_decisions: architectural or design decisions made (empty list if none)
|
|
32
|
-
- known_issues: bugs or issues discovered but not yet fixed (empty list if none)
|
|
33
|
-
Be selective — only include genuinely new information.""";
|
|
34
|
-
|
|
35
|
-
sem ProjectScan.architecture = "1-2 sentences: project purpose, tech stack, and overall node/walker structure";
|
|
36
|
-
sem ProjectScan.file_map = "dict mapping relative file paths to 1-line role descriptions (max 15 files)";
|
|
37
|
-
sem ProjectScan.conventions = "list of coding conventions: naming style, file organization, patterns used";
|
|
38
|
-
|
|
39
|
-
sem SessionLearnings.new_files = "dict of new/modified file paths to 1-line descriptions of their content";
|
|
40
|
-
sem SessionLearnings.new_conventions = "new coding conventions established this session (empty list if none)";
|
|
41
|
-
sem SessionLearnings.new_decisions = "architectural decisions made this session (empty list if none)";
|
|
42
|
-
sem SessionLearnings.known_issues = "bugs or issues discovered but not yet fixed (empty list if none)";
|
|
43
|
-
|
|
44
|
-
impl ProjectMemory.summarize() -> str {
|
|
45
|
-
parts = [];
|
|
46
|
-
if self.architecture {
|
|
47
|
-
parts.append("Architecture: " + self.architecture);
|
|
48
|
-
}
|
|
49
|
-
if self.node_details {
|
|
50
|
-
parts.append(self.node_details);
|
|
51
|
-
}
|
|
52
|
-
if self.walker_details {
|
|
53
|
-
parts.append(self.walker_details);
|
|
54
|
-
}
|
|
55
|
-
if self.graph_topology {
|
|
56
|
-
parts.append("Graph: " + self.graph_topology);
|
|
57
|
-
}
|
|
58
|
-
if self.import_map {
|
|
59
|
-
parts.append(self.import_map);
|
|
60
|
-
}
|
|
61
|
-
if self.file_map {
|
|
62
|
-
items = list(self.file_map.items())[:10];
|
|
63
|
-
file_lines = [f" {k}: {v}" for (k, v) in items];
|
|
64
|
-
parts.append("Key files:\n" + "\n".join(file_lines));
|
|
65
|
-
}
|
|
66
|
-
if self.conventions {
|
|
67
|
-
parts.append("Conventions: " + ", ".join(self.conventions[:5]));
|
|
68
|
-
}
|
|
69
|
-
if self.past_decisions {
|
|
70
|
-
parts.append("Past decisions: " + "; ".join(self.past_decisions[:3]));
|
|
71
|
-
}
|
|
72
|
-
if self.known_issues {
|
|
73
|
-
parts.append("Known issues: " + "; ".join(self.known_issues[:3]));
|
|
74
|
-
}
|
|
75
|
-
return "\n".join(parts);
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
|
|
79
17
|
# ---------------------------------------------------------------------------
|
|
80
18
|
# MainAgent — the orchestrator
|
|
81
19
|
# ---------------------------------------------------------------------------
|
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
import os;
|
|
2
1
|
import sys;
|
|
3
2
|
|
|
4
3
|
import from uuid { uuid4 }
|
|
@@ -12,7 +11,7 @@ import from jac_coder.tool.meta.think { think }
|
|
|
12
11
|
import from jac_coder.tool.meta.delegation { spawn_agent, set_iter_count }
|
|
13
12
|
import from jac_coder.tool.meta.todo { update_todos }
|
|
14
13
|
import from jac_coder.tool.read.load_jac_skill { load_jac_skill }
|
|
15
|
-
import from jac_coder.tool.meta.clarify_intent { clarify_intent
|
|
14
|
+
import from jac_coder.tool.meta.clarify_intent { clarify_intent }
|
|
16
15
|
import from jac_coder.tool.net.web { web_fetch, web_search }
|
|
17
16
|
import from jac_coder.tool.run.guarded { run_command }
|
|
18
17
|
import from jac_coder.tool.run.jac_tools { jac_check, jac_run }
|
|
@@ -101,21 +100,6 @@ sem TurnReflection.smoothness = "0.0 (fought it for many iterations or left it u
|
|
|
101
100
|
sem TurnReflection.category = "Pick the ONE category that best fits the struggle's root cause. skills_gap: you lacked the right Jac pattern and the skills/docs did not cover it. upstream_bug: a real bug or limitation in Jac/Jaseci/jac-cloud itself, not your own mistake. syntax_error: Jac or cl.jac syntax you got wrong. framework_api: you misunderstood a Jac/jac-cloud API or concept (persistence, walkers, nodes/edges, routing, auth). environment_issue: sandbox, deployment, install, or server/tooling environment problem. tooling_limitation: a JacCoder tool itself fell short (edit match failed, browser, etc.). logic_error: your own application logic/reasoning bug. ambiguity: the user request was unclear or underspecified. none: no significant struggle this turn.";
|
|
102
101
|
|
|
103
102
|
|
|
104
|
-
obj ProjectScan {
|
|
105
|
-
has architecture: str;
|
|
106
|
-
has file_map: dict[str, str];
|
|
107
|
-
has conventions: list[str];
|
|
108
|
-
}
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
obj SessionLearnings {
|
|
112
|
-
has new_files: dict[str, str];
|
|
113
|
-
has new_conventions: list[str];
|
|
114
|
-
has new_decisions: list[str];
|
|
115
|
-
has known_issues: list[str];
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
|
|
119
103
|
# ---------------------------------------------------------------------------
|
|
120
104
|
# McpRegistry — persists MCP server configs in the graph
|
|
121
105
|
# ---------------------------------------------------------------------------
|
|
@@ -134,35 +118,6 @@ node UserPermissionRules {
|
|
|
134
118
|
}
|
|
135
119
|
|
|
136
120
|
|
|
137
|
-
# ---------------------------------------------------------------------------
|
|
138
|
-
# ProjectMemory — persists codebase knowledge across sessions
|
|
139
|
-
# ---------------------------------------------------------------------------
|
|
140
|
-
node ProjectMemory {
|
|
141
|
-
has project_dir: str = "",
|
|
142
|
-
architecture: str = "",
|
|
143
|
-
file_map: dict[str, str] = {},
|
|
144
|
-
conventions: list[str] = [],
|
|
145
|
-
past_decisions: list[str] = [],
|
|
146
|
-
known_issues: list[str] = [],
|
|
147
|
-
graph_topology: str = "",
|
|
148
|
-
node_details: str = "",
|
|
149
|
-
walker_details: str = "",
|
|
150
|
-
import_map: str = "",
|
|
151
|
-
scan_attempted: bool = False,
|
|
152
|
-
last_updated: str = "";
|
|
153
|
-
|
|
154
|
-
def profile_project(file_tree: str, key_files: str) -> ProjectScan by llm(
|
|
155
|
-
temperature=0.1
|
|
156
|
-
);
|
|
157
|
-
|
|
158
|
-
def collect_learnings(
|
|
159
|
-
files_modified: list[str], session_summary: str
|
|
160
|
-
) -> SessionLearnings by llm(temperature=0.1);
|
|
161
|
-
|
|
162
|
-
def summarize() -> str;
|
|
163
|
-
}
|
|
164
|
-
|
|
165
|
-
|
|
166
121
|
# ---------------------------------------------------------------------------
|
|
167
122
|
# Session — persistent chat state
|
|
168
123
|
# ---------------------------------------------------------------------------
|
|
@@ -168,7 +168,6 @@ impl interact.enter_session with Session entry {
|
|
|
168
168
|
here.updated_at = datetime.now().isoformat();
|
|
169
169
|
self.chat_history = here.chat_history;
|
|
170
170
|
|
|
171
|
-
# Visit MainAgent
|
|
172
171
|
visit [-->][?:MainAgent] else {
|
|
173
172
|
agent = ensure_main_agent();
|
|
174
173
|
here ++> agent;
|
|
@@ -3,17 +3,9 @@ import os;
|
|
|
3
3
|
import from http { HTTPMethod }
|
|
4
4
|
import from datetime { datetime }
|
|
5
5
|
import from jac_coder.util.tool_output { tool_end }
|
|
6
|
-
import from jac_coder.
|
|
7
|
-
import from jac_coder.infra.config { llm, get_config }
|
|
6
|
+
import from jac_coder.infra.config { get_config }
|
|
8
7
|
import from jaclang.runtimelib.builtin { restspec }
|
|
9
|
-
import from jac_coder.runtime.context { build_context, ContextConfig }
|
|
10
8
|
import from jac_coder.runtime.events { reset_steps, start_turn, emit_turn_summary, emit_event, clear_abort, is_abort_requested, emit_phase_change, emit_previewable }
|
|
11
|
-
import from jaclang.byllm.types { StreamEvent }
|
|
12
|
-
import from jac_coder.runtime.memory {
|
|
13
|
-
find_or_create_memory,
|
|
14
|
-
_init_memory,
|
|
15
|
-
update_memory_from_session
|
|
16
|
-
}
|
|
17
9
|
import from jac_coder.core.nodes { Session, MainAgent, UIDesignerAgent }
|
|
18
10
|
|
|
19
11
|
|
|
@@ -66,9 +66,21 @@ def _try_init() -> None {
|
|
|
66
66
|
}
|
|
67
67
|
_broker_init_done = True;
|
|
68
68
|
try {
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
69
|
+
# jac-scale was folded into core jaclang (jaseci#7034), so the runtime
|
|
70
|
+
# module is `jaclang.scale.*`. Prefer that; fall back to the standalone
|
|
71
|
+
# `jac_scale.*` for pre-fold binaries. Without this, the import fails on a
|
|
72
|
+
# folded runtime ("No module named 'jac_scale'"), the broker never wires,
|
|
73
|
+
# and a stream_events() call that load-balances onto a peer pod raises
|
|
74
|
+
# "run_id not found" (run_turn registered the run on a different replica).
|
|
75
|
+
try {
|
|
76
|
+
import jaclang.scale.events.publisher as _pm;
|
|
77
|
+
import from jaclang.scale.events.publisher { publish as _pub }
|
|
78
|
+
import from jaclang.scale.events.broker { Event as _Ev }
|
|
79
|
+
} except Exception {
|
|
80
|
+
import jac_scale.events.publisher as _pm;
|
|
81
|
+
import from jac_scale.events.publisher { publish as _pub }
|
|
82
|
+
import from jac_scale.events.broker { Event as _Ev }
|
|
83
|
+
}
|
|
72
84
|
_pub_mod = _pm;
|
|
73
85
|
_publish_fn = _pub;
|
|
74
86
|
_Event = _Ev;
|
|
@@ -42,7 +42,16 @@ def _try_init() -> None {
|
|
|
42
42
|
}
|
|
43
43
|
_kv_init_done = True;
|
|
44
44
|
try {
|
|
45
|
-
|
|
45
|
+
# jac-scale folded into core jaclang (jaseci#7034): kvstore now lives
|
|
46
|
+
# at jaclang.scale.persistence.lib. Prefer it; fall back to the
|
|
47
|
+
# standalone jac_scale.lib for pre-fold binaries. Without this the
|
|
48
|
+
# cross-pod KV cache silently disables on a folded runtime
|
|
49
|
+
# ("No module named 'jac_scale'").
|
|
50
|
+
try {
|
|
51
|
+
import from jaclang.scale.persistence.lib { kvstore }
|
|
52
|
+
} except Exception {
|
|
53
|
+
import from jac_scale.lib { kvstore }
|
|
54
|
+
}
|
|
46
55
|
_kv = kvstore(db_name="jac_coder", db_type="redis");
|
|
47
56
|
} except Exception as e {
|
|
48
57
|
# Redis not configured — common in CLI/stdio mode and local dev.
|
|
@@ -11,7 +11,7 @@ import logging;
|
|
|
11
11
|
import from uuid { uuid4 }
|
|
12
12
|
import from queue { Queue, Empty }
|
|
13
13
|
import from datetime { datetime, timezone }
|
|
14
|
-
import from typing { Any,
|
|
14
|
+
import from typing { Any, Callable }
|
|
15
15
|
|
|
16
16
|
import from jac_coder.core.nodes { Session, Run }
|
|
17
17
|
import from jac_coder.api {
|
|
@@ -14,7 +14,7 @@ import logging;
|
|
|
14
14
|
import from uuid { uuid4 }
|
|
15
15
|
import from queue { Queue, Empty }
|
|
16
16
|
import from datetime { datetime, timezone }
|
|
17
|
-
import from typing { Any
|
|
17
|
+
import from typing { Any }
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
glob _logger: logging.Logger = logging.getLogger("jac_coder.lib");
|
|
@@ -10,8 +10,8 @@ def _build_prefix(
|
|
|
10
10
|
) -> list[dict] {
|
|
11
11
|
parts = [];
|
|
12
12
|
if project_summary {
|
|
13
|
-
# project_summary comes from .jaccoder/progress.md
|
|
14
|
-
#
|
|
13
|
+
# project_summary comes from .jaccoder/progress.md — the agent's
|
|
14
|
+
# persistent knowledge of the project state.
|
|
15
15
|
is_progress_file = project_summary.lstrip().startswith("#");
|
|
16
16
|
label = "Project progress (.jaccoder/progress.md)" if is_progress_file else "Project context";
|
|
17
17
|
parts.append(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{project_summary}");
|
|
@@ -27,13 +27,11 @@ impl record_usage(usage_data: dict, agent: str = "main") -> None {
|
|
|
27
27
|
),
|
|
28
28
|
"total_tokens": int(call.get("total_tokens", 0) or 0)
|
|
29
29
|
};
|
|
30
|
-
# Calculate total if not provided
|
|
31
30
|
if not call_record["total_tokens"] {
|
|
32
31
|
call_record["total_tokens"] = call_record["input_tokens"] + call_record["output_tokens"];
|
|
33
32
|
}
|
|
34
33
|
state["calls"].append(call_record);
|
|
35
34
|
|
|
36
|
-
# Accumulate into running totals from this call
|
|
37
35
|
state["totals"]["input_tokens"] += call_record["input_tokens"];
|
|
38
36
|
state["totals"]["output_tokens"] += call_record["output_tokens"];
|
|
39
37
|
state["totals"]["cached_tokens"] += call_record["cached_tokens"];
|
|
@@ -21,12 +21,6 @@ glob _log_turn_cost: dict = {}; # float accumulator per session_id
|
|
|
21
21
|
glob _log_lock: threading.Lock = threading.Lock();
|
|
22
22
|
|
|
23
23
|
|
|
24
|
-
"""True when JACCODER_LOG=1 is set and logger is initialized."""
|
|
25
|
-
def is_logging_enabled() -> bool {
|
|
26
|
-
return bool(_log_file_handle);
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
|
|
30
24
|
"""Initialize the file logger. No-op if JACCODER_LOG is not set.
|
|
31
25
|
|
|
32
26
|
Call once at startup. Safe to call multiple times — only initializes once.
|
|
@@ -11,10 +11,6 @@ impl compose_system_prompt_filtered(base_prompt: str, allowed_skills: set[str])
|
|
|
11
11
|
return (base_prompt + "\n\n" + skills_block) if skills_block else base_prompt;
|
|
12
12
|
}
|
|
13
13
|
|
|
14
|
-
impl smells_like_build(message: str) -> bool {
|
|
15
|
-
return _smells_like_build(message);
|
|
16
|
-
}
|
|
17
|
-
|
|
18
14
|
# ---------------------------------------------------------------------------
|
|
19
15
|
# infer_mode_hint — classify what the agent did from ground truth
|
|
20
16
|
# ---------------------------------------------------------------------------
|
|
@@ -212,5 +212,3 @@ def compose_system_prompt(base_prompt: str) -> str;
|
|
|
212
212
|
"""Like compose_system_prompt but only includes skills listed in `allowed_skills`. Used by per-agent prompts."""
|
|
213
213
|
def compose_system_prompt_filtered(base_prompt: str, allowed_skills: set[str]) -> str;
|
|
214
214
|
|
|
215
|
-
"""Public wrapper for the private _smells_like_build check."""
|
|
216
|
-
def smells_like_build(message: str) -> bool;
|
|
@@ -7,7 +7,6 @@ import from jac_coder.tool.net.web { web_fetch, web_search }
|
|
|
7
7
|
import from jac_coder.tool.read.search { grep_search, find_files }
|
|
8
8
|
import from jac_coder.tool.meta.todo { update_todos, get_todos }
|
|
9
9
|
import from jac_coder.tool.run.jac_tools { jac_check, jac_run }
|
|
10
|
-
import from jac_coder.tool.meta.validate { validate_project }
|
|
11
10
|
import from jac_coder.tool.git { git_status, git_diff, git_commit, git_log }
|
|
12
11
|
import from jac_coder.tool.write.checked { write_code, edit_code, delete_code }
|
|
13
12
|
import from jac_coder.tool.run.guarded { write_file_guarded, edit_file_guarded, delete_file_guarded, run_command }
|
|
@@ -64,7 +64,6 @@ impl git_commit(message: str, files: list[str] = [], directory: str = "") -> str
|
|
|
64
64
|
return "Error: commit message is required.";
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
-
# Stage files
|
|
68
67
|
if files {
|
|
69
68
|
for fp in files {
|
|
70
69
|
(_, err, code) = _run_git(["add", fp], directory);
|
|
@@ -81,7 +80,6 @@ impl git_commit(message: str, files: list[str] = [], directory: str = "") -> str
|
|
|
81
80
|
}
|
|
82
81
|
}
|
|
83
82
|
|
|
84
|
-
# Commit
|
|
85
83
|
(out, err, code) = _run_git(["commit", "-m", message], directory);
|
|
86
84
|
if code != 0 {
|
|
87
85
|
if "nothing to commit" in (out + err) {
|
|
@@ -109,7 +109,6 @@ impl spawn_agent(task: str, mode: str = "worker") -> str {
|
|
|
109
109
|
return "Error: Iteration budget exhausted. Cannot spawn more SubAgents.";
|
|
110
110
|
}
|
|
111
111
|
|
|
112
|
-
# Enrich task with session context
|
|
113
112
|
project_ctx = get_project_summary_for_subagent();
|
|
114
113
|
recent_work = get_recent_results_summary();
|
|
115
114
|
clarification_ctx = _get_clarification_context();
|
|
@@ -161,7 +160,6 @@ impl spawn_agent(task: str, mode: str = "worker") -> str {
|
|
|
161
160
|
has_errs = len(errs) > 0;
|
|
162
161
|
iters_used = getattr(_tl, "iter_count", len(used_tools));
|
|
163
162
|
|
|
164
|
-
# Track budget and state
|
|
165
163
|
consume_budget(iters_used);
|
|
166
164
|
for fp in fmod {
|
|
167
165
|
track_file(fp);
|
|
@@ -181,7 +179,6 @@ impl spawn_agent(task: str, mode: str = "worker") -> str {
|
|
|
181
179
|
}
|
|
182
180
|
);
|
|
183
181
|
|
|
184
|
-
# Build result string
|
|
185
182
|
result_parts: list = [];
|
|
186
183
|
if content {
|
|
187
184
|
result_parts.append(content);
|
|
@@ -2,7 +2,7 @@ import threading;
|
|
|
2
2
|
|
|
3
3
|
import from jac_coder.infra.config { get_config }
|
|
4
4
|
import from jac_coder.util.tool_output { tool_status, tool_end }
|
|
5
|
-
import from jac_coder.runtime.events { track_file, track_error
|
|
5
|
+
import from jac_coder.runtime.events { track_file, track_error }
|
|
6
6
|
|
|
7
7
|
|
|
8
8
|
glob _tl: Any = threading.local();
|
|
@@ -683,7 +683,6 @@ impl write_file(file_path: str, content: str) -> str {
|
|
|
683
683
|
fix_count = len(auto_fixes);
|
|
684
684
|
result_msg = f"OK: {short_name} ({line_count} lines" + (f", {fix_count} auto-fixes" if fix_count else "") + ")";
|
|
685
685
|
|
|
686
|
-
# Write succeeded
|
|
687
686
|
tool_end(f"-> {line_count} lines");
|
|
688
687
|
|
|
689
688
|
# Stage 2: Compiler validation (separate step so errors show on "Check", not "Write")
|
|
@@ -779,7 +778,6 @@ impl edit_file(
|
|
|
779
778
|
fix_count = len(auto_fixes);
|
|
780
779
|
result_msg = f"OK: {short_name} ({replacements} edit" + ("s" if replacements > 1 else "") + (f", {fix_count} auto-fixes" if fix_count else "") + ")";
|
|
781
780
|
|
|
782
|
-
# Edit succeeded
|
|
783
781
|
tool_end(f"-> {replacements} edit(s)");
|
|
784
782
|
|
|
785
783
|
# Stage 2: Compiler validation (separate step)
|