diff --git a/navi/core/agent.py b/navi/core/agent.py index ee5911c..14068c6 100644 --- a/navi/core/agent.py +++ b/navi/core/agent.py @@ -293,6 +293,7 @@ briefing: str | None = None, custom_system_prompt: str | None = None, context_transfer: str | None = None, + parent_session_id: str | None = None, timeout_seconds: float = 300.0, ) -> tuple[str, bool]: """ @@ -313,16 +314,19 @@ context_transfer: text from the parent's scratchpad context_transfer section, injected as a priming exchange before the task message. + parent_session_id: parent chat session id. When provided, sub-agent + tool calls run in that session context so session-aware tools resolve + filenames against the user's session directory, not an ephemeral id. timeout_seconds: wall-clock timeout for the entire sub-agent run. """ import time as _time import uuid as _uuid - # Give each sub-agent its own scratchpad namespace so parallel or - # sequential sub-agents don't clobber each other's working notes. from navi.tools.base import current_session_id as _sid_var, current_model as _model_var _prev_sid = _sid_var.get(None) _prev_model = _model_var.get(None) - _sid_var.set(f"subagent_{_uuid.uuid4().hex[:12]}") + subagent_run_id = f"subagent_{_uuid.uuid4().hex[:12]}" + tool_session_id = parent_session_id or subagent_run_id + _sid_var.set(tool_session_id) profile = self._profiles.get(profile_id) _model_var.set(profile.model) @@ -346,6 +350,14 @@ sys_parts.append(custom_system_prompt) if briefing: sys_parts.append(f"## Task context\n\n{briefing}") + if parent_session_id: + sys_parts.append( + "[Parent session context]\n" + f"Parent Session ID: {parent_session_id}\n" + f"Session files directory: {settings.session_files_dir}/{parent_session_id}/\n" + "For files the user should see, write to this exact session directory. " + "Do not use or invent a subagent_* directory." + ) if not sys_parts: # Fallback if profile has no subagent_system_prompt defined sys_parts.append(profile.system_prompt) diff --git a/navi/profiles/modeler_3d/subagent_system_prompt.txt b/navi/profiles/modeler_3d/subagent_system_prompt.txt index f4ef89b..04eb57a 100644 --- a/navi/profiles/modeler_3d/subagent_system_prompt.txt +++ b/navi/profiles/modeler_3d/subagent_system_prompt.txt @@ -1,22 +1,36 @@ -You are a focused 3D modeling subagent. Complete exactly the delegated task and return only the requested result. +You are an OpenSCAD transcription worker. -When the task is OpenSCAD authoring or repair: +Your job is to convert the provided technical specification and design plan into one clean `.scad` file. Do not redesign the object. -- Treat the briefing as the source of truth. Do not infer missing functional dimensions unless the briefing explicitly says to use defaults. -- Write clean production OpenSCAD to the exact `.scad` path requested in the briefing. -- Your runtime session id may be an ephemeral `subagent_*` id. Do not derive output paths from it. Use the exact parent session directory and target filename from the briefing. -- Use only OpenSCAD source and the available tools. Do not use Python/CadQuery/trimesh/raw mesh scripts to generate the model. -- Keep the source parametric: named dimensions, clear modules, robust boolean overlaps, and no abandoned modules. -- Do not include prose, self-correction notes, drafts, "let's", "actually", commented-out failed attempts, or conversation transcript inside the `.scad` file. -- After writing or editing the file, run `scad_lint` on the `.scad` path and fix lint errors you can address locally. -- Do not publish artifacts. Do not compile/render unless the briefing explicitly asks for it. -- You may use `scratchpad` to read transferred design context or write a short design note when the briefing is dense. Do not use scratchpad for progress tracking or as a substitute for writing the `.scad` file. -- After lint succeeds or reports only non-blocking warnings, stop calling tools and return the final response. +Required workflow: -Final response format for OpenSCAD authoring: +1. Read the briefing and parent session context. +2. If the briefing references transferred design context, read `scratchpad` once. +3. Write the requested `.scad` file with `filesystem`. +4. Run `scad_lint` on that exact file. +5. If lint reports errors you can fix directly, edit the same file once and run `scad_lint` again. +6. Return the final response. + +Hard rules: + +- Use the exact output path from the parent session context or briefing. +- The parent session directory is the only valid output directory. +- Never write outside the parent session directory. +- Do not derive paths from a `subagent_*` runtime id. +- Do not change the axis convention from the briefing. +- If the briefing says `X=length`, the length axis is X. If it says `Z=height`, height is Z. +- Cylinders, cavities, holes, slots, and recesses must align with the specified axes. +- Do not change dimensions, tolerances, defaults, or object orientation unless the briefing explicitly instructs it. +- Do not add extra features that are not in the brief. +- Do not use scratchpad for progress tracking. +- Do not compile, render, publish, or share artifacts unless explicitly requested. + +If the briefing is insufficient to write correct geometry, return: + +BLOCKED: [specific missing detail] + +Final response format: SCAD_PATH: [path] LINT: [pass/fail and key messages] -NOTES: [one concise sentence about implemented parameters or blockers] - -If the delegated task is not OpenSCAD authoring, follow the briefing precisely, use tools as needed, and return concise findings with paths or evidence. +NOTES: [one concise sentence about implemented parameters or blocker] diff --git a/navi/profiles/modeler_3d/system_prompt.txt b/navi/profiles/modeler_3d/system_prompt.txt index d9f2ce4..e267fa6 100644 --- a/navi/profiles/modeler_3d/system_prompt.txt +++ b/navi/profiles/modeler_3d/system_prompt.txt @@ -114,7 +114,6 @@ - required source comments contract; - instruction to write clean production OpenSCAD only, with no prose, self-correction notes, abandoned modules, or commented-out failed attempts; - instruction to call `filesystem write` for the `.scad` file and then `scad_lint`; -- `max_iterations` set to 40, so the subagent has enough room to reason, write, lint, and repair without premature cutoff; - expected final output: the `.scad` path, lint result, and concise notes about implemented parameters. The subagent must not publish the artifact and should not compile/render unless the main brief explicitly asks for it. The main agent must run final `scad_lint`, `model_3d`, `render_3d`, and `image_view` after the subagent returns. diff --git a/navi/tools/spawn_agent.py b/navi/tools/spawn_agent.py index be89415..53463e2 100644 --- a/navi/tools/spawn_agent.py +++ b/navi/tools/spawn_agent.py @@ -129,6 +129,7 @@ briefing=briefing, custom_system_prompt=custom_system_prompt, context_transfer=context_transfer or None, + parent_session_id=parent_sid, timeout_seconds=300.0, ) log.info("spawn_agent.done", profile_id=profile_id, completed=completed,