jac-coder 0.2.7__tar.gz → 0.2.8__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.7 → jac_coder-0.2.8}/PKG-INFO +1 -2
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/api.impl.jac +12 -3
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/core/nodes.impl.jac +18 -1
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/core/nodes.jac +214 -14
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/core/walkers.impl.jac +43 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/core/walkers.jac +2 -2
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/infra/config.jac +1 -1
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/runtime/prompt.impl.jac +9 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/runtime/prompt.jac +18 -1
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/runtime/skills.impl.jac +21 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/runtime/skills.jac +3 -0
- jac_coder-0.2.8/jac_coder/runtime/struggle_report.jac +326 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/server.jac +1 -1
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/meta/delegation.impl.jac +21 -10
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/meta/delegation.jac +1 -1
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/net/preview.impl.jac +12 -2
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/net/preview.jac +1 -1
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder.egg-info/PKG-INFO +1 -2
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder.egg-info/SOURCES.txt +1 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder.egg-info/requires.txt +0 -1
- {jac_coder-0.2.7 → jac_coder-0.2.8}/pyproject.toml +1 -2
- {jac_coder-0.2.7 → jac_coder-0.2.8}/README.md +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/__init__.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/__init__.py +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/api.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/cli.impl.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/cli.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/cli_entry.py +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/core/__init__.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/infra/__init__.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/infra/config.impl.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/infra/events.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/infra/kv.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/infra/mcp_manager.impl.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/infra/mcp_manager.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/lib/__init__.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/lib/coder.impl.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/lib/coder.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/runtime/__init__.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/runtime/compaction.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/runtime/context.impl.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/runtime/context.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/runtime/cost_tracker.impl.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/runtime/cost_tracker.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/runtime/events.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/runtime/file_logger.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/runtime/memory.impl.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/runtime/memory.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/runtime/permission.impl.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/runtime/permission.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/serve_entry.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/__init__.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/git.impl.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/git.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/mcp.impl.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/mcp.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/meta/__init__.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/meta/clarify_intent.impl.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/meta/clarify_intent.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/meta/task.impl.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/meta/task.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/meta/think.impl.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/meta/think.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/meta/todo.impl.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/meta/todo.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/meta/validate.impl.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/meta/validate.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/net/__init__.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/net/web.impl.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/net/web.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/read/__init__.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/read/filesystem.impl.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/read/filesystem.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/read/jac_analyzer.impl.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/read/jac_analyzer.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/read/load_jac_skill.impl.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/read/load_jac_skill.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/read/search.impl.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/read/search.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/run/__init__.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/run/guarded.impl.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/run/guarded.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/run/jac_tools.impl.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/run/jac_tools.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/run/shell.impl.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/run/shell.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/write/__init__.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/write/checked.impl.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/tool/write/checked.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/util/__init__.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/util/banner.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/util/colors.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/util/md_render.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/util/sandbox.impl.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/util/sandbox.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/util/tool_output.impl.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder/util/tool_output.jac +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder.egg-info/dependency_links.txt +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder.egg-info/entry_points.txt +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/jac_coder.egg-info/top_level.txt +0 -0
- {jac_coder-0.2.7 → jac_coder-0.2.8}/setup.cfg +0 -0
|
@@ -1,11 +1,10 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: jac-coder
|
|
3
|
-
Version: 0.2.
|
|
3
|
+
Version: 0.2.8
|
|
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
7
|
Requires-Dist: jaclang
|
|
8
|
-
Requires-Dist: byllm
|
|
9
8
|
Requires-Dist: mcp>=1.0.0
|
|
10
9
|
Requires-Dist: jac-mcp
|
|
11
10
|
Requires-Dist: rich>=13.0
|
|
@@ -339,7 +339,7 @@ impl chat(
|
|
|
339
339
|
user_image = None;
|
|
340
340
|
if images and len(images) > 0 {
|
|
341
341
|
try {
|
|
342
|
-
import from byllm.lib { Image }
|
|
342
|
+
import from jaclang.byllm.lib { Image }
|
|
343
343
|
;
|
|
344
344
|
first_img = images[0];
|
|
345
345
|
data_url = first_img.get("data_url", "") if isinstance(first_img, dict) else str(first_img);
|
|
@@ -358,6 +358,7 @@ impl chat(
|
|
|
358
358
|
|
|
359
359
|
response_text = stream_result["content"];
|
|
360
360
|
tools_used = stream_result["tools_used"];
|
|
361
|
+
tool_records = stream_result.get("tool_records", []);
|
|
361
362
|
|
|
362
363
|
# Finalize turn — get accumulated file/error data from tool internals
|
|
363
364
|
tool_end();
|
|
@@ -421,6 +422,14 @@ impl chat(
|
|
|
421
422
|
import from jac_coder.runtime.prompt { infer_mode_hint as _infer_hint }
|
|
422
423
|
session.last_mode_hint = _infer_hint(tools_used, files_modified);
|
|
423
424
|
|
|
425
|
+
# Guaranteed end-of-turn struggle reflection (work turns only).
|
|
426
|
+
if not is_abort_requested() {
|
|
427
|
+
import from jac_coder.runtime.struggle_report { reflect_and_log }
|
|
428
|
+
reflect_and_log(
|
|
429
|
+
main_agent, tool_records, files_modified, has_errors, response_text
|
|
430
|
+
);
|
|
431
|
+
}
|
|
432
|
+
|
|
424
433
|
return {
|
|
425
434
|
"response": response_text,
|
|
426
435
|
"agent": "main",
|
|
@@ -552,8 +561,8 @@ impl api_check_local_setup(alias: str) -> dict {
|
|
|
552
561
|
model: bool = False;
|
|
553
562
|
valid_alias: bool = False;
|
|
554
563
|
try {
|
|
555
|
-
import from byllm.local_runtime { LOCAL_MODELS }
|
|
556
|
-
import from byllm.model_cache { is_downloaded }
|
|
564
|
+
import from jaclang.byllm.local_runtime { LOCAL_MODELS }
|
|
565
|
+
import from jaclang.byllm.model_cache { is_downloaded }
|
|
557
566
|
spec = LOCAL_MODELS.get(alias);
|
|
558
567
|
if spec is not None {
|
|
559
568
|
valid_alias = True;
|
|
@@ -87,10 +87,14 @@ sem MainAgent.respond = "Respond to the user's coding request.";
|
|
|
87
87
|
# ---------------------------------------------------------------------------
|
|
88
88
|
# SubAgent walkers — sem annotations and entry ability implementations
|
|
89
89
|
# ---------------------------------------------------------------------------
|
|
90
|
-
sem WorkerAgent.do_work = "Execute the delegated coding task.";
|
|
90
|
+
sem WorkerAgent.do_work = "Execute the delegated coding task as a pure implementer. When .jaccoder/ui_spec.json exists, treat it as a binding UI contract — never change style, theme, base_color, nav_pattern, or pages (those belong to UIDesignerAgent). If a mechanical implementation need arises for a component not in primitive_components (e.g. a spinner), add it to primitive_components in ui_spec.json first, then run jac add --shadcn. Never make freestyle design decisions.";
|
|
91
91
|
|
|
92
92
|
sem ExplorerAgent.do_work = "Investigate the codebase and report findings.";
|
|
93
93
|
|
|
94
|
+
sem UIDesignerAgent = "UI design authority — produces or updates .jaccoder/ui_spec.json, the living design contract for the application.";
|
|
95
|
+
sem UIDesignerAgent.do_work = "Write or update .jaccoder/ui_spec.json. Create mode (no UISpec in task): analyse project from scratch and produce a full spec. Update mode (current UISpec JSON provided in task): apply the user's change request to only the affected fields, preserve everything else.";
|
|
96
|
+
sem UIDesignerAgent.task = "Input context in one of two forms. Create: project path + directory listing + jac.toml + user request. Update: project path + current UISpec JSON + user request.";
|
|
97
|
+
|
|
94
98
|
|
|
95
99
|
"""Consume a SubAgent's by llm() stream, forward events, and return results."""
|
|
96
100
|
def _consume_subagent_stream(event_stream: Any, prefix: str, track_files: bool = False) -> dict {
|
|
@@ -134,6 +138,11 @@ def _consume_subagent_stream(event_stream: Any, prefix: str, track_files: bool =
|
|
|
134
138
|
}
|
|
135
139
|
} elif event.event_type == "steps_done" {
|
|
136
140
|
emit_event("llm_steps_done", dict(event.data));
|
|
141
|
+
} elif event.event_type == "stream_reset" {
|
|
142
|
+
# byllm retried a transient mid-stream drop; drop the partial subagent
|
|
143
|
+
# reply so the regenerated text isn't doubled.
|
|
144
|
+
content = "";
|
|
145
|
+
emit_event("llm_stream_reset", dict(event.data));
|
|
137
146
|
} elif event.event_type == "chunk" {
|
|
138
147
|
content += event.data.get("content", "");
|
|
139
148
|
} elif event.event_type == "usage" {
|
|
@@ -169,3 +178,11 @@ impl ExplorerAgent.execute with MainAgent entry {
|
|
|
169
178
|
self.result_files = [];
|
|
170
179
|
self.result_errors = list(result["errors"]);
|
|
171
180
|
}
|
|
181
|
+
|
|
182
|
+
|
|
183
|
+
impl UIDesignerAgent.execute with MainAgent entry {
|
|
184
|
+
result = _consume_subagent_stream(
|
|
185
|
+
self.do_work(task_str=self.task), "sub:designer"
|
|
186
|
+
);
|
|
187
|
+
self.result_content = str(result["content"]);
|
|
188
|
+
}
|
|
@@ -3,7 +3,7 @@ import sys;
|
|
|
3
3
|
|
|
4
4
|
import from uuid { uuid4 }
|
|
5
5
|
import from datetime { datetime }
|
|
6
|
-
import from byllm.types { IterationAction, IterationContext }
|
|
6
|
+
import from jaclang.byllm.types { IterationAction, IterationContext }
|
|
7
7
|
import from jac_coder.infra.config { llm, get_config }
|
|
8
8
|
import from jac_coder.runtime.events { is_abort_requested }
|
|
9
9
|
|
|
@@ -24,8 +24,8 @@ import from jac_coder.tool.read.jac_analyzer { analyze_project, find_symbol }
|
|
|
24
24
|
import from jac_coder.tool.net.preview { browser_open, browser_do, browser_state, browser_close, browser_validate }
|
|
25
25
|
import from jac_coder.tool.mcp { mcp_call }
|
|
26
26
|
import from jac_coder.runtime.compaction { jaccoder_compaction }
|
|
27
|
-
import from jac_coder.runtime.prompt { compose_system_prompt }
|
|
28
|
-
import from byllm.lib { Image }
|
|
27
|
+
import from jac_coder.runtime.prompt { compose_system_prompt, compose_system_prompt_filtered }
|
|
28
|
+
import from jaclang.byllm.lib { Image }
|
|
29
29
|
|
|
30
30
|
|
|
31
31
|
|
|
@@ -64,6 +64,43 @@ sem SubAgentResult.tools_used = "Tools called during execution";
|
|
|
64
64
|
sem SubAgentResult.iterations_used = "Number of ReAct iterations consumed";
|
|
65
65
|
|
|
66
66
|
|
|
67
|
+
# Controlled vocabulary for the struggle's root cause. A fixed enum (not a free
|
|
68
|
+
# string) so categories stay consistent across users and the admin portal can
|
|
69
|
+
# group/triage them. Each value maps to an improvement action: skills_gap -> write
|
|
70
|
+
# a skill doc, upstream_bug -> file a Jaseci issue, environment_issue -> fix the
|
|
71
|
+
# sandbox, etc.
|
|
72
|
+
enum StruggleCategory {
|
|
73
|
+
SKILLS_GAP = "skills_gap",
|
|
74
|
+
UPSTREAM_BUG = "upstream_bug",
|
|
75
|
+
SYNTAX_ERROR = "syntax_error",
|
|
76
|
+
FRAMEWORK_API = "framework_api",
|
|
77
|
+
ENVIRONMENT_ISSUE = "environment_issue",
|
|
78
|
+
TOOLING_LIMITATION = "tooling_limitation",
|
|
79
|
+
LOGIC_ERROR = "logic_error",
|
|
80
|
+
AMBIGUITY = "ambiguity",
|
|
81
|
+
NONE = "none"
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
obj TurnReflection {
|
|
86
|
+
has issue: str = "",
|
|
87
|
+
root_cause: str = "",
|
|
88
|
+
resolution: str = "",
|
|
89
|
+
code_before: str = "",
|
|
90
|
+
code_after: str = "",
|
|
91
|
+
smoothness: float = 0.7,
|
|
92
|
+
category: StruggleCategory = StruggleCategory.NONE;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
sem TurnReflection.issue = "The single biggest sticking point this turn and WHERE it was (file / function / component). 1-2 sentences.";
|
|
96
|
+
sem TurnReflection.root_cause = "The concrete underlying cause: the exact error, the API you misunderstood, the wrong assumption. Be specific, not generic.";
|
|
97
|
+
sem TurnReflection.resolution = "How you fixed it, in one sentence, or 'unresolved' if you did not fix it.";
|
|
98
|
+
sem TurnReflection.code_before = "The minimal broken code (just the few key lines), if it was a code problem. Empty otherwise.";
|
|
99
|
+
sem TurnReflection.code_after = "Those same lines, fixed. Empty otherwise.";
|
|
100
|
+
sem TurnReflection.smoothness = "0.0 (fought it for many iterations or left it unresolved) to 1.0 (effortless). Ground it in the effort the digest shows - a long unresolved struggle is LOW.";
|
|
101
|
+
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
|
+
|
|
103
|
+
|
|
67
104
|
obj ProjectScan {
|
|
68
105
|
has architecture: str;
|
|
69
106
|
has file_map: dict[str, str];
|
|
@@ -271,6 +308,29 @@ node MainAgent {
|
|
|
271
308
|
stream=True,
|
|
272
309
|
logging=True
|
|
273
310
|
);
|
|
311
|
+
|
|
312
|
+
"""You ARE the coding agent, reflecting on the turn you just finished, for an
|
|
313
|
+
internal quality log the user never sees. The digest below is the turn: your own
|
|
314
|
+
think reasoning, every tool call (failures and functional/app problems are
|
|
315
|
+
flagged), the code you changed, and the cost (how many calls).
|
|
316
|
+
|
|
317
|
+
Find the SINGLE most significant struggle - the one that cost the most effort or
|
|
318
|
+
stayed unresolved, NOT the tidiest one-liner. A functional bug you debugged over
|
|
319
|
+
many iterations (e.g. the app showing wrong data, a "not found" that kept failing)
|
|
320
|
+
matters far more than a quick procedural realization. Weight by effort and whether
|
|
321
|
+
it was resolved, not by how cleanly you can state it.
|
|
322
|
+
|
|
323
|
+
Then report it concretely: `issue` (what + WHERE), `root_cause` (the real
|
|
324
|
+
underlying cause), `resolution` (how you fixed it, or "unresolved"), and if it was
|
|
325
|
+
a code problem, a MINIMAL `code_before`/`code_after` (just the few key lines).
|
|
326
|
+
Set `smoothness` from the effort the digest shows: a long or unresolved struggle
|
|
327
|
+
is LOW (0.2-0.4), a smooth turn is high. Choose the `category` that best matches
|
|
328
|
+
the root cause from the allowed values. If the turn
|
|
329
|
+
really was smooth, say so briefly with high smoothness and empty code fields."""
|
|
330
|
+
def reflect_on_turn(turn_digest: str) -> TurnReflection by llm(
|
|
331
|
+
temperature=0.3,
|
|
332
|
+
max_tokens=700
|
|
333
|
+
);
|
|
274
334
|
}
|
|
275
335
|
|
|
276
336
|
|
|
@@ -288,6 +348,84 @@ def _iteration_hook(ctx: IterationContext) -> IterationAction {
|
|
|
288
348
|
}
|
|
289
349
|
|
|
290
350
|
|
|
351
|
+
glob DESIGNER_SKILLS: set[str] = {"jac-shadcn-components", "jac-shadcn-blocks"};
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
glob JACCODER_DESIGNER_SYSTEM: str = """
|
|
355
|
+
# UIDesignerAgent — UI Design Authority
|
|
356
|
+
|
|
357
|
+
Produce or update `.jaccoder/ui_spec.json` — the UI design contract. You do NOT write application code, run commands, or build anything.
|
|
358
|
+
|
|
359
|
+
## Two operating modes
|
|
360
|
+
|
|
361
|
+
### Create mode (no UISpec in task)
|
|
362
|
+
Task: project path + directory listing + jac.toml + user request. Analyse from scratch and produce a complete UISpec.
|
|
363
|
+
1. Load `jac-shadcn-blocks` skill — `### Section headers` give valid block names.
|
|
364
|
+
2. Load `jac-shadcn-components` skill — Component Selection table gives primitive names; § Theming gives valid theming values.
|
|
365
|
+
3. Write the full JSON to `<project_dir>/.jaccoder/ui_spec.json` using `write_code`.
|
|
366
|
+
|
|
367
|
+
### Update mode (current UISpec provided in task)
|
|
368
|
+
Task: project path + current UISpec JSON + user request. Update ONLY the relevant fields — preserve everything else.
|
|
369
|
+
1. Load `jac-shadcn-blocks` (if change involves pages or blocks).
|
|
370
|
+
2. Load `jac-shadcn-components` (if change involves theme, style, font, or primitive_components).
|
|
371
|
+
3. Apply only the requested changes. Write the complete JSON back (full file, not a patch).
|
|
372
|
+
|
|
373
|
+
Changes → fields: visual redesign ("more attractive", "production-level", "like Linear/Notion") → `style/theme/base_color/font/radius/menu_accent`; nav change → `nav_pattern` + page `blocks`; add/remove page → `pages[]` + `primitive_components`; component addition → `primitive_components`.
|
|
374
|
+
|
|
375
|
+
## Output — `.jaccoder/ui_spec.json`
|
|
376
|
+
Single raw JSON object (no markdown fences, no comments). All fields required.
|
|
377
|
+
|
|
378
|
+
```
|
|
379
|
+
{
|
|
380
|
+
"app_type": "landing | dashboard | saas | ecommerce | blog | portfolio | tool",
|
|
381
|
+
"auth_required": true | false,
|
|
382
|
+
"backend_required": true | false,
|
|
383
|
+
"nav_pattern": "sidebar | topnav | bottomnav | none",
|
|
384
|
+
"pages": [
|
|
385
|
+
{
|
|
386
|
+
"name": "Human-readable page name",
|
|
387
|
+
"route": "/path",
|
|
388
|
+
"blocks": ["block_name_1"],
|
|
389
|
+
"auth_protected": true | false,
|
|
390
|
+
"title": "HTML page title"
|
|
391
|
+
}
|
|
392
|
+
],
|
|
393
|
+
"primitive_components": ["button", "card"],
|
|
394
|
+
"style": "nova | vega | maia | lyra | mira",
|
|
395
|
+
"base_color": "neutral | stone | zinc | gray",
|
|
396
|
+
"theme": "rose | indigo | emerald | amber | blue | violet | teal | green",
|
|
397
|
+
"font": "figtree | inter | geist | dm-sans | roboto",
|
|
398
|
+
"radius": "default | none | small | medium | large",
|
|
399
|
+
"menu_accent": "subtle | bold",
|
|
400
|
+
"confidence": 0.0,
|
|
401
|
+
"assumption": "One sentence describing the biggest assumption made.",
|
|
402
|
+
"remove_from_template": []
|
|
403
|
+
}
|
|
404
|
+
```
|
|
405
|
+
|
|
406
|
+
Note: `theme` and `font` show the most common values — see jac-shadcn-components § Theme reference and § Font reference for the full lists with descriptions.
|
|
407
|
+
|
|
408
|
+
## Field guidance
|
|
409
|
+
|
|
410
|
+
**app_type**: match to user's domain.
|
|
411
|
+
**auth_required**: DEFAULT is `false`. Set `true` ONLY if the user's message contains explicit words like "login", "signup", "sign in", "user accounts", "authentication", or "protected pages". Do NOT infer from app type — "habit tracker", "todo app", "notes app", "dashboard" do NOT imply auth. When in doubt → `false`.
|
|
412
|
+
**backend_required**: `true` if server endpoints, a database, or per-user data needed.
|
|
413
|
+
**pages[].blocks**: exact snake_case names from jac-shadcn-blocks skill only — auth_card, app_shell_sidebar, data_table, stats_row, pricing_grid, cta_banner, empty_state, marketing_section. Do not invent names.
|
|
414
|
+
**primitive_components**: exact lowercase names from jac-shadcn-components Component Selection table — passed to `jac add --shadcn` (e.g. "button", "card", "sidebar", "badge", "table", "input", "dialog", "select", "avatar", "chart"). No custom names like "HabitCard". List primaries only — peer deps auto-resolve.
|
|
415
|
+
**style**: visual language — `nova` (neutral professional B2B), `vega` (vibrant modern consumer), `maia` (warm approachable/health), `lyra` (data-focused minimal), `mira` (creative expressive). See jac-shadcn-components § Theming.
|
|
416
|
+
**base_color**: gray palette for backgrounds/borders/muted text. NOT a hex color. `neutral` (default/most apps), `stone` (warm/organic), `zinc` (cool/technical), `gray` (mid). See jac-shadcn-components § baseColor vs theme.
|
|
417
|
+
**theme**: accent/brand color name. NOT "light"/"dark"/"system". See jac-shadcn-components § Theme reference for full list (e.g. `indigo`=enterprise, `emerald`=health/wellness, `rose`=lifestyle, `amber`=e-commerce).
|
|
418
|
+
**font**: see jac-shadcn-components § Font reference for full list and tone descriptions. Default `figtree` (warm/friendly). `inter` for professional, `geist` for technical.
|
|
419
|
+
**radius**: `default` for most apps. `none`/`small` for enterprise/data. `medium`/`large` for consumer/mobile.
|
|
420
|
+
**menu_accent**: `subtle` (muted, low distraction — Notion/GitHub style). `bold` (primary-colored — Linear/Vercel style).
|
|
421
|
+
**remove_from_template**: only files confirmed present in directory listing. Set `[]` when uncertain.
|
|
422
|
+
**confidence**: 0.0-1.0. Create mode: how well the request maps to a complete spec. Update mode: how well the changes match the user's request.
|
|
423
|
+
|
|
424
|
+
## After writing the file
|
|
425
|
+
Confirm the write succeeded. Your task is done — do not build, run commands, or write any application code.
|
|
426
|
+
""";
|
|
427
|
+
|
|
428
|
+
|
|
291
429
|
glob JACCODER_WORKER_SYSTEM: str = """
|
|
292
430
|
# WorkerAgent — Jac Coding SubAgent
|
|
293
431
|
|
|
@@ -302,20 +440,58 @@ Build breadth-first — get all files written and app running before polishing.
|
|
|
302
440
|
## UI (mandatory)
|
|
303
441
|
Build responsive, mobile-first UIs: fluid flex/grid layouts, Tailwind responsive prefixes (sm:/md:/lg:), no fixed widths that overflow small screens. A desktop-only layout that breaks on mobile is a bug. After browser_validate PASS, also check the layout at a narrow/mobile width.
|
|
304
442
|
|
|
443
|
+
## Pre-flight — PATH A setup (run BEFORE writing any code files)
|
|
444
|
+
If `.jaccoder/ui_spec.json` exists, these two commands MUST run before you write or edit any code file:
|
|
445
|
+
|
|
446
|
+
**1. Install primitives:**
|
|
447
|
+
`jac add --shadcn <primitive_components from UISpec>` — use the exact list, nothing more.
|
|
448
|
+
|
|
449
|
+
**2. Apply theme:**
|
|
450
|
+
```
|
|
451
|
+
jac retheme --style <style> --baseColor <base_color> --theme <theme> --font <font> --radius <radius> --menuAccent <menu_accent>
|
|
452
|
+
```
|
|
453
|
+
All 6 flags are required — never omit any, even when the value is the default (e.g. `--radius default`). UISpec uses snake_case; flags are camelCase (`base_color`→`--baseColor`, `menu_accent`→`--menuAccent`). This overwrites `global.css` wholesale.
|
|
454
|
+
|
|
455
|
+
Run both before touching services, components, or any other file.
|
|
456
|
+
|
|
305
457
|
## Workflow
|
|
306
458
|
1. Read .jaccoder/progress.md if it exists, update it as you go.
|
|
307
459
|
2. analyze_project(dir) for existing projects.
|
|
308
|
-
3.
|
|
309
|
-
4. **
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
- Load `jac-
|
|
318
|
-
- Load `jac-
|
|
460
|
+
3. For PATH B/C: build bottom-up — services → hooks → components → layout. For PATH A, follow steps a–d below (page-first, not service-first).
|
|
461
|
+
4. **Choose your build path:**
|
|
462
|
+
|
|
463
|
+
### PATH A — UISpec present (`.jaccoder/ui_spec.json` exists)
|
|
464
|
+
Pre-flight already done above. Then:
|
|
465
|
+
|
|
466
|
+
a) **Remove unwanted template files** listed in `remove_from_template` early, before writing new pages. Re-verify each file exists before deleting.
|
|
467
|
+
|
|
468
|
+
b) **For each page in `pages`**:
|
|
469
|
+
- Load `jac-shadcn-blocks` skill. Use the listed `blocks` in order to build the page.
|
|
470
|
+
- Load `jac-shadcn-components` for shared UI primitives.
|
|
471
|
+
- Register the route in the app router.
|
|
472
|
+
|
|
473
|
+
c) **Auth — detect and ensure** based on `auth_required`:
|
|
474
|
+
- If `true`:
|
|
475
|
+
- **Frontend check**: Does `pages/LoginPage.cl.jac` exist AND does `index.cl.jac` (or router file) contain `AuthGuard`?
|
|
476
|
+
- If MISSING: load `jac-shadcn-blocks` (use `auth_card` block) + `jac-cl-auth` skill. Build `pages/LoginPage.cl.jac` and wrap protected routes with `<AuthGuard redirect="/login">` in the router.
|
|
477
|
+
- If EXISTS: keep it.
|
|
478
|
+
- **Backend check**: Does `jac.toml` contain `[plugins.server]` OR does a `services/` dir exist?
|
|
479
|
+
- If MISSING: load `jac-sv-auth` + `jac-sv-endpoints` skills. Add `[plugins.server]` section to `jac.toml`. Create `services/appService.jac` with a minimal skeleton. Run `jac install`.
|
|
480
|
+
- If EXISTS: keep it.
|
|
481
|
+
- Note: jac-scale auto-provides `/user/login` and `/user/register` — do NOT write custom auth walkers.
|
|
482
|
+
- If `false`: delete `pages/LoginPage.cl.jac` if it exists; remove `AuthGuard` wrapper from router if present.
|
|
483
|
+
|
|
484
|
+
d) **Backend — detect and ensure** based on `backend_required` (independent of auth):
|
|
485
|
+
- If `true` and no backend present (same check as above): load `jac-sv-endpoints`, add `[plugins.server]` to `jac.toml`, create `services/appService.jac` skeleton, run `jac install`.
|
|
486
|
+
- If `false`: leave any existing backend untouched.
|
|
487
|
+
|
|
488
|
+
|
|
489
|
+
### PATH B — jac-shadcn project, no UISpec
|
|
490
|
+
Check: `components/ui/` exists OR `jac.toml` has `[jac-shadcn]`. Load `jac-shadcn-components` + `jac-shadcn-blocks` skills and build based on the task description. Apply sensible design defaults. Do NOT create or modify `styles/global.css` or `jac.toml` (pre-configured by jac-shadcn).
|
|
491
|
+
|
|
492
|
+
### PATH C — Standard project (no jac-shadcn)
|
|
493
|
+
Load `jac-cl-styling` and build with plain Tailwind. `jac.toml` needs `[plugins.client.vite]` with tailwindcss. Run `jac install` after toml changes. `styles/global.css`: `@import "tailwindcss"`. Load `jac-npm-packages` when adding third-party packages.
|
|
494
|
+
|
|
319
495
|
5. After all files: jac start --dev main.jac (background=True).
|
|
320
496
|
6. browser_validate(url) and follow its instructions.
|
|
321
497
|
""";
|
|
@@ -405,3 +581,27 @@ walker ExplorerAgent {
|
|
|
405
581
|
);
|
|
406
582
|
can execute with MainAgent entry;
|
|
407
583
|
}
|
|
584
|
+
|
|
585
|
+
|
|
586
|
+
walker UIDesignerAgent {
|
|
587
|
+
has task: str;
|
|
588
|
+
has result_content: str = "";
|
|
589
|
+
|
|
590
|
+
def do_work(task_str: str) -> str by llm(
|
|
591
|
+
system_prompt=compose_system_prompt_filtered(JACCODER_DESIGNER_SYSTEM, DESIGNER_SKILLS),
|
|
592
|
+
tools=[
|
|
593
|
+
think,
|
|
594
|
+
load_jac_skill,
|
|
595
|
+
list_files,
|
|
596
|
+
read_file,
|
|
597
|
+
write_code
|
|
598
|
+
],
|
|
599
|
+
on_iteration=_iteration_hook,
|
|
600
|
+
max_react_iterations=15,
|
|
601
|
+
temperature=0.1,
|
|
602
|
+
max_tokens=8192,
|
|
603
|
+
stream=True,
|
|
604
|
+
logging=True
|
|
605
|
+
);
|
|
606
|
+
can execute with MainAgent entry;
|
|
607
|
+
}
|
|
@@ -4,6 +4,7 @@
|
|
|
4
4
|
|
|
5
5
|
glob _PROGRESS_DIR: str = ".jaccoder";
|
|
6
6
|
glob _PROGRESS_FILE: str = "progress.md";
|
|
7
|
+
glob _UI_SPEC_FILE: str = "ui_spec.json";
|
|
7
8
|
|
|
8
9
|
|
|
9
10
|
"""Read .jaccoder/progress.md from the project directory. Returns content or empty string."""
|
|
@@ -30,6 +31,20 @@ def _read_progress(project_dir: str) -> str {
|
|
|
30
31
|
}
|
|
31
32
|
|
|
32
33
|
|
|
34
|
+
def _read_ui_spec(project_dir: str) -> str {
|
|
35
|
+
spec_path = os.path.join(project_dir, _PROGRESS_DIR, _UI_SPEC_FILE);
|
|
36
|
+
if not os.path.isfile(spec_path) {
|
|
37
|
+
return "";
|
|
38
|
+
}
|
|
39
|
+
try {
|
|
40
|
+
with open(spec_path, "r", encoding="utf-8") as f {
|
|
41
|
+
return f.read();
|
|
42
|
+
}
|
|
43
|
+
} except Exception {
|
|
44
|
+
return "";
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
|
|
33
48
|
impl ensure_main_agent() -> MainAgent {
|
|
34
49
|
agents = [root()-->][?:MainAgent];
|
|
35
50
|
if agents {
|
|
@@ -256,6 +271,15 @@ impl _consume_llm_stream(event_stream: Any) -> dict {
|
|
|
256
271
|
emit_event("llm_tool_result", dict(event.data));
|
|
257
272
|
} elif event.event_type == "steps_done" {
|
|
258
273
|
emit_event("llm_steps_done", dict(event.data));
|
|
274
|
+
} elif event.event_type == "stream_reset" {
|
|
275
|
+
# byllm retried a transient drop: discard the partial reply (so the
|
|
276
|
+
# regenerated text isn't doubled) and forward the signal to the UI.
|
|
277
|
+
if event.data.get("scope") == "answer" {
|
|
278
|
+
response_text = "";
|
|
279
|
+
} else {
|
|
280
|
+
thought_text = "";
|
|
281
|
+
}
|
|
282
|
+
emit_event("llm_stream_reset", dict(event.data));
|
|
259
283
|
} elif event.event_type == "chunk" {
|
|
260
284
|
chunk_content = event.data.get("content", "");
|
|
261
285
|
response_text += chunk_content;
|
|
@@ -319,6 +343,19 @@ impl _respond_and_persist(agent: MainAgent, ctx: interact) -> None {
|
|
|
319
343
|
);
|
|
320
344
|
}
|
|
321
345
|
|
|
346
|
+
if work_dir {
|
|
347
|
+
ui_spec_json = _read_ui_spec(work_dir);
|
|
348
|
+
if ui_spec_json {
|
|
349
|
+
prefix_parts.append(
|
|
350
|
+
"<ui-spec>\n"
|
|
351
|
+
"UISpec produced by UIDesignerAgent. "
|
|
352
|
+
"WorkerAgent MUST follow it when building or modifying pages.\n\n"
|
|
353
|
+
+ ui_spec_json
|
|
354
|
+
+ "\n</ui-spec>"
|
|
355
|
+
);
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
|
|
322
359
|
if project_summary {
|
|
323
360
|
prefix_parts.append(
|
|
324
361
|
"[INTERNAL — background context from .jaccoder/progress.md. "
|
|
@@ -431,6 +468,12 @@ impl _respond_and_persist(agent: MainAgent, ctx: interact) -> None {
|
|
|
431
468
|
emit_previewable();
|
|
432
469
|
}
|
|
433
470
|
|
|
471
|
+
# Guaranteed end-of-turn struggle reflection (work turns only).
|
|
472
|
+
if not is_abort_requested() {
|
|
473
|
+
import from jac_coder.runtime.struggle_report { reflect_and_log }
|
|
474
|
+
reflect_and_log(agent, tool_records, files_modified, has_errors, response_text);
|
|
475
|
+
}
|
|
476
|
+
|
|
434
477
|
report {
|
|
435
478
|
"response": response_text,
|
|
436
479
|
"agent": "main",
|
|
@@ -8,13 +8,13 @@ import from jac_coder.infra.config { llm, get_config }
|
|
|
8
8
|
import from jaclang.runtimelib.builtin { restspec }
|
|
9
9
|
import from jac_coder.runtime.context { build_context, ContextConfig }
|
|
10
10
|
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 byllm.types { StreamEvent }
|
|
11
|
+
import from jaclang.byllm.types { StreamEvent }
|
|
12
12
|
import from jac_coder.runtime.memory {
|
|
13
13
|
find_or_create_memory,
|
|
14
14
|
_init_memory,
|
|
15
15
|
update_memory_from_session
|
|
16
16
|
}
|
|
17
|
-
import from jac_coder.core.nodes { Session, MainAgent }
|
|
17
|
+
import from jac_coder.core.nodes { Session, MainAgent, UIDesignerAgent }
|
|
18
18
|
|
|
19
19
|
|
|
20
20
|
def ensure_main_agent() -> MainAgent;
|
|
@@ -6,6 +6,15 @@ impl compose_system_prompt(base_prompt: str) -> str {
|
|
|
6
6
|
return (prompt + "\n\n" + listing) if listing else prompt;
|
|
7
7
|
}
|
|
8
8
|
|
|
9
|
+
impl compose_system_prompt_filtered(base_prompt: str, allowed_skills: set[str]) -> str {
|
|
10
|
+
skills_block = inject_skills_listing_filtered(allowed_skills);
|
|
11
|
+
return (base_prompt + "\n\n" + skills_block) if skills_block else base_prompt;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
impl smells_like_build(message: str) -> bool {
|
|
15
|
+
return _smells_like_build(message);
|
|
16
|
+
}
|
|
17
|
+
|
|
9
18
|
# ---------------------------------------------------------------------------
|
|
10
19
|
# infer_mode_hint — classify what the agent did from ground truth
|
|
11
20
|
# ---------------------------------------------------------------------------
|
|
@@ -11,7 +11,7 @@ Signal chain per turn:
|
|
|
11
11
|
"""
|
|
12
12
|
|
|
13
13
|
import os;
|
|
14
|
-
import from jac_coder.runtime.skills { inject_skills_listing }
|
|
14
|
+
import from jac_coder.runtime.skills { inject_skills_listing, inject_skills_listing_filtered }
|
|
15
15
|
|
|
16
16
|
# ---------------------------------------------------------------------------
|
|
17
17
|
# Mode hint constants — stored as strings for graph persistence safety
|
|
@@ -53,6 +53,17 @@ You have limited iterations. Prioritize a WORKING app over a perfect one:
|
|
|
53
53
|
|
|
54
54
|
## Build Workflow
|
|
55
55
|
0. **Inspect the workspace** (per Step 0 above) — decide EXTEND vs CREATE before anything else.
|
|
56
|
+
0.5. **UIDesignerAgent — UI design authority** (UIDesignerAgent owns ALL UI design decisions):
|
|
57
|
+
|
|
58
|
+
**Condition A — `.jaccoder/ui_spec.json` does NOT exist** (first build): Run UIDesignerAgent now, before any skill loading or file writing:
|
|
59
|
+
`spawn_agent(mode='designer', task="Design UISpec for <abs_path>\n\nDirectory listing:\n<paste list_files output>\n\nProject config (jac.toml):\n<paste jac.toml content, or 'not present'>\n\nUser request: <user_message>")`
|
|
60
|
+
Pass the directory listing and jac.toml you already read — UIDesignerAgent will use them directly. Wait for it to complete, then proceed to step 1.
|
|
61
|
+
|
|
62
|
+
**Condition B — `.jaccoder/ui_spec.json` EXISTS and the request involves UI design changes**: UI design changes include: visual redesign ("more attractive", "production-level", "like X"), theme/style/font changes, navigation structure changes, adding or removing pages, layout changes. Run UIDesignerAgent in update mode:
|
|
63
|
+
`spawn_agent(mode='designer', task="Update UISpec for <abs_path>\n\nCurrent UISpec:\n<paste .jaccoder/ui_spec.json content>\n\nUser request: <user_message>")`
|
|
64
|
+
Wait for UIDesignerAgent to update `ui_spec.json`, then spawn WorkerAgent to implement the changes.
|
|
65
|
+
|
|
66
|
+
**Condition C — `.jaccoder/ui_spec.json` EXISTS and request is feature or code only**: Bug fixes, logic changes, backend features, content changes. Skip UIDesignerAgent. Proceed to step 1 and spawn WorkerAgent.
|
|
56
67
|
1. Load skills from `<jac-skills-available>` via `load_jac_skill(name)`: **always start with `jac-core-cheatsheet`**, then load the task-specific skills (fullstack + anything the task touches).
|
|
57
68
|
2. Plan briefly, then create/update `.jaccoder/progress.md` with the plan. Keep planning SHORT: make each choice ONCE and move on — never re-litigate the same decision and don't restate the plan in chat. The plan lives in progress.md, not in long prose.
|
|
58
69
|
3. Backend services (.sv.jac), then a minimal main.jac that renders a real layout (not a stub) — your live-preview shell; it grows as you wire in components.
|
|
@@ -197,3 +208,9 @@ No emojis in generated UI (headings, buttons, labels, empty states, toasts) or i
|
|
|
197
208
|
"""Build an agent's full system prompt: base persona + shared static context
|
|
198
209
|
that belongs in the cached prompt prefix (currently the skills listing)."""
|
|
199
210
|
def compose_system_prompt(base_prompt: str) -> str;
|
|
211
|
+
|
|
212
|
+
"""Like compose_system_prompt but only includes skills listed in `allowed_skills`. Used by per-agent prompts."""
|
|
213
|
+
def compose_system_prompt_filtered(base_prompt: str, allowed_skills: set[str]) -> str;
|
|
214
|
+
|
|
215
|
+
"""Public wrapper for the private _smells_like_build check."""
|
|
216
|
+
def smells_like_build(message: str) -> bool;
|
|
@@ -123,6 +123,27 @@ impl inject_skills_listing() -> str {
|
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
|
|
126
|
+
impl inject_skills_listing_filtered(allowed: set[str]) -> str {
|
|
127
|
+
reg = get_default_registry();
|
|
128
|
+
lines: list[str] = [];
|
|
129
|
+
for name in allowed {
|
|
130
|
+
if name in reg.skills {
|
|
131
|
+
meta = reg.skills[name];
|
|
132
|
+
lines.append(f"- {meta.name}: {meta.description}");
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
if not lines {
|
|
136
|
+
return "";
|
|
137
|
+
}
|
|
138
|
+
body = "\n".join(lines);
|
|
139
|
+
return (
|
|
140
|
+
"<jac-skills-available>\n"
|
|
141
|
+
+ body
|
|
142
|
+
+ "\n</jac-skills-available>"
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
|
|
146
|
+
|
|
126
147
|
# ---------------------------------------------------------------------------
|
|
127
148
|
# Private helpers
|
|
128
149
|
# ---------------------------------------------------------------------------
|
|
@@ -89,3 +89,6 @@ def get_default_registry() -> SkillRegistry;
|
|
|
89
89
|
"""Render the available-skills listing as a single system-message string.
|
|
90
90
|
Returns empty string when no skills are installed."""
|
|
91
91
|
def inject_skills_listing() -> str;
|
|
92
|
+
|
|
93
|
+
"""Render only skills whose names are in `allowed`. No cache — used for per-agent filtered prompts."""
|
|
94
|
+
def inject_skills_listing_filtered(allowed: set[str]) -> str;
|