fix(skill): dispatch Pi's semantic subagents as pi-subagents' delegate

The Pi skill rendered the shared agent-tool-disk dispatch, which tells the
host to use subagent_type="general-purpose". pi-subagents has no agent by
that name and rejects it as unknown, so semantic extraction never started
(#4494). Step B3's re-run hints named the same agent.

Pi now gets its own dispatch fragment that sends one builtin `delegate`
agent per chunk; delegate has read, bash, edit and write. The two B3 hints
are core slots filled per dispatch variant, so every other host renders
byte-identical output.
This commit is contained in:
berce committed 2026-10-16 18:08:26 +03:00
1 parent 10130e79ed
commit a0b3a053a5
7 files changed
+57 -27

No files matched your search

+6 -12
View File
@@ -265,19 +265,13 @@ Only dispatch subagents for files listed in `graphify-out/.graphify_uncached.txt
Load files from `graphify-out/.graphify_uncached.txt`. Split into chunks of 20-25 files each. Each image gets its own chunk (vision needs separate context). When splitting, group files from the same directory together so related artifacts land in the same chunk and cross-file relationships are more likely to be extracted.
**Step B2 - Dispatch ALL subagents in a single message**
**Step B2 - Dispatch ALL subagents in a single message (Pi)**
Call the Agent tool multiple times IN THE SAME RESPONSE - one call per chunk. This is the only way they run in parallel. If you make one Agent call, wait, then make another, you are doing it sequentially and defeating the purpose.
> **Pi platform:** Dispatch through the `subagent` tool of the pi-subagents extension (`pi install npm:pi-subagents`), not a Claude Code Agent tool.
**IMPORTANT - subagent type:** Always use `subagent_type="general-purpose"`. Do NOT use `Explore` - it is read-only and cannot write chunk files to disk, which silently drops extraction results. General-purpose has Write and Bash access which the subagent needs.
Dispatch one `delegate` subagent per chunk, all of them in parallel in a single run. If you start one chunk, wait for it, then start the next, you are doing it sequentially and defeating the purpose.
Concrete example for 3 chunks:
```
[Agent tool call 1: files 1-15, subagent_type="general-purpose"]
[Agent tool call 2: files 16-30, subagent_type="general-purpose"]
[Agent tool call 3: files 31-45, subagent_type="general-purpose"]
```
All three in one message. Not three separate messages.
**IMPORTANT - agent:** Always use the builtin `delegate` agent. It has `read`, `bash`, `edit` and `write`, which the subagent needs to write its chunk file.
Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH).
@@ -296,10 +290,10 @@ See `references/extraction-spec.md` for the exact subagent prompt (JSON schema,
Wait for all subagents. For each result:
- Check that `graphify-out/.graphify_chunk_NN.json` exists on disk — this is the success signal
- If the file exists and contains valid JSON with `nodes` and `edges`, include it and save to cache
- If the file is missing, the subagent was likely dispatched as read-only (Explore type) — print a warning: "chunk N missing from disk — subagent may have been read-only. Re-run with general-purpose agent." Do not silently skip.
- If the file is missing, the subagent was likely dispatched as read-only (Explore type) — print a warning: "chunk N missing from disk — subagent may have been read-only. Re-run with the `delegate` agent." Do not silently skip.
- If a subagent failed or returned invalid JSON, print a warning and skip that chunk - do not abort
If more than half the chunks failed or are missing, stop and tell the user to re-run and ensure `subagent_type="general-purpose"` is used.
If more than half the chunks failed or are missing, stop and tell the user to re-run and ensure the `delegate` agent is used.
Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run:
```bash
+14
View File
@@ -546,6 +546,7 @@ def test_dispatch_variants_are_host_specific():
"amp": "Task(description=",
"trae": "Task(description=",
"vscode": "paste each response back",
"pi": "`delegate` agent",
}
for key, marker in expect.items():
core, _ = _platform_artifacts(key)
@@ -553,6 +554,19 @@ def test_dispatch_variants_are_host_specific():
assert marker.lower() in b2.lower(), f"[{key}] dispatch slot missing {marker!r}"
def test_pi_never_names_the_claude_general_purpose_agent():
"""pi-subagents rejects `general-purpose` as an unknown agent (#4494), so
neither Pi's dispatch nor its Step B3 re-run hints may name it; claude keeps
its own wording."""
pi, _ = _platform_artifacts("pi")
assert "general-purpose" not in pi
assert "Re-run with the `delegate` agent." in pi
assert "ensure the `delegate` agent is used." in pi
claude, _ = _platform_artifacts("claude")
assert "Re-run with general-purpose agent." in claude
assert 'ensure `subagent_type="general-purpose"` is used.' in claude
def test_compact_extraction_hosts_use_the_compact_spec():
"""kiro, pi, claw use the compact extraction body; the rest use verbose."""
for key in ("kiro", "pi", "claw"):
+6 -12
View File
@@ -265,19 +265,13 @@ Only dispatch subagents for files listed in `graphify-out/.graphify_uncached.txt
Load files from `graphify-out/.graphify_uncached.txt`. Split into chunks of 20-25 files each. Each image gets its own chunk (vision needs separate context). When splitting, group files from the same directory together so related artifacts land in the same chunk and cross-file relationships are more likely to be extracted.
**Step B2 - Dispatch ALL subagents in a single message**
**Step B2 - Dispatch ALL subagents in a single message (Pi)**
Call the Agent tool multiple times IN THE SAME RESPONSE - one call per chunk. This is the only way they run in parallel. If you make one Agent call, wait, then make another, you are doing it sequentially and defeating the purpose.
> **Pi platform:** Dispatch through the `subagent` tool of the pi-subagents extension (`pi install npm:pi-subagents`), not a Claude Code Agent tool.
**IMPORTANT - subagent type:** Always use `subagent_type="general-purpose"`. Do NOT use `Explore` - it is read-only and cannot write chunk files to disk, which silently drops extraction results. General-purpose has Write and Bash access which the subagent needs.
Dispatch one `delegate` subagent per chunk, all of them in parallel in a single run. If you start one chunk, wait for it, then start the next, you are doing it sequentially and defeating the purpose.
Concrete example for 3 chunks:
```
[Agent tool call 1: files 1-15, subagent_type="general-purpose"]
[Agent tool call 2: files 16-30, subagent_type="general-purpose"]
[Agent tool call 3: files 31-45, subagent_type="general-purpose"]
```
All three in one message. Not three separate messages.
**IMPORTANT - agent:** Always use the builtin `delegate` agent. It has `read`, `bash`, `edit` and `write`, which the subagent needs to write its chunk file.
Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH).
@@ -296,10 +290,10 @@ See `references/extraction-spec.md` for the exact subagent prompt (JSON schema,
Wait for all subagents. For each result:
- Check that `graphify-out/.graphify_chunk_NN.json` exists on disk — this is the success signal
- If the file exists and contains valid JSON with `nodes` and `edges`, include it and save to cache
- If the file is missing, the subagent was likely dispatched as read-only (Explore type) — print a warning: "chunk N missing from disk — subagent may have been read-only. Re-run with general-purpose agent." Do not silently skip.
- If the file is missing, the subagent was likely dispatched as read-only (Explore type) — print a warning: "chunk N missing from disk — subagent may have been read-only. Re-run with the `delegate` agent." Do not silently skip.
- If a subagent failed or returned invalid JSON, print a warning and skip that chunk - do not abort
If more than half the chunks failed or are missing, stop and tell the user to re-run and ensure `subagent_type="general-purpose"` is used.
If more than half the chunks failed or are missing, stop and tell the user to re-run and ensure the `delegate` agent is used.
Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run:
```bash
+2 -2
View File
@@ -225,10 +225,10 @@ Load files from `graphify-out/.graphify_uncached.txt`. Split into chunks of 20-2
Wait for all subagents. For each result:
- Check that `graphify-out/.graphify_chunk_NN.json` exists on disk — this is the success signal
- If the file exists and contains valid JSON with `nodes` and `edges`, include it and save to cache
- If the file is missing, the subagent was likely dispatched as read-only (Explore type) — print a warning: "chunk N missing from disk — subagent may have been read-only. Re-run with general-purpose agent." Do not silently skip.
- If the file is missing, the subagent was likely dispatched as read-only (Explore type) — print a warning: "chunk N missing from disk — subagent may have been read-only. Re-run with @@WRITER_AGENT@@." Do not silently skip.
- If a subagent failed or returned invalid JSON, print a warning and skip that chunk - do not abort
If more than half the chunks failed or are missing, stop and tell the user to re-run and ensure `subagent_type="general-purpose"` is used.
If more than half the chunks failed or are missing, stop and tell the user to re-run and ensure @@WRITER_AGENT_ARG@@ is used.
Merge all chunk files into `.graphify_semantic_new.json`. **After each Agent call completes, read the real token counts from the Agent tool result's `usage` field and write them back into the chunk JSON before merging** — the chunk JSON itself always has placeholder zeros. Then run:
```bash
@@ -0,0 +1,19 @@
**Step B2 - Dispatch ALL subagents in a single message (Pi)**
> **Pi platform:** Dispatch through the `subagent` tool of the pi-subagents extension (`pi install npm:pi-subagents`), not a Claude Code Agent tool.
Dispatch one `delegate` subagent per chunk, all of them in parallel in a single run. If you start one chunk, wait for it, then start the next, you are doing it sequentially and defeating the purpose.
**IMPORTANT - agent:** Always use the builtin `delegate` agent. It has `read`, `bash`, `edit` and `write`, which the subagent needs to write its chunk file.
Each subagent receives this exact prompt (substitute FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH).
CHUNK_PATH must be an **absolute** path — derive it before dispatching:
```bash
PROJECT_ROOT=$(pwd) # cwd — where Part C globs graphify-out/ (NOT .graphify_root/scan dir, #1392)
# Then for chunk N: CHUNK_PATH="${PROJECT_ROOT}/graphify-out/.graphify_chunk_0N.json"
```
Subagent prompt template:
See `references/extraction-spec.md` for the exact subagent prompt (JSON schema, node-ID rules, confidence rubric, frontmatter, hyperedge, and vision rules). Load it only here, only when at least one chunk holds a doc, paper, or image; a pure-code corpus has skipped Part B and never reads it. Pass each subagent that prompt verbatim with FILE_LIST, CHUNK_NUM, TOTAL_CHUNKS, DEEP_MODE, and CHUNK_PATH substituted, and have it write the result to CHUNK_PATH.
+9
View File
@@ -537,6 +537,12 @@ def _core_to_powershell(body: str) -> str:
return translated
# Step B3's re-run hints name the agent that can write chunk files. A dispatch
# variant whose host has no `general-purpose` agent names its own (#4494).
_DEFAULT_WRITER_AGENT = ("general-purpose agent", '`subagent_type="general-purpose"`')
_WRITER_AGENT = {"pi-subagents": ("the `delegate` agent", "the `delegate` agent")}
def _render_core(platform: Platform) -> str:
"""Fill the shared core template's per-platform slots for this platform.
@@ -553,6 +559,7 @@ def _render_core(platform: Platform) -> str:
interp_guard = _read_fragment(f"shell/interpreter-guard-{platform.shell}.md").rstrip("\n")
dispatch = _read_fragment(f"dispatch/{platform.dispatch}.md").rstrip("\n")
query_stub = _read_fragment(_QUERY_STUB).rstrip("\n")
writer_agent, writer_agent_arg = _WRITER_AGENT.get(platform.dispatch, _DEFAULT_WRITER_AGENT)
if platform.extra_sections:
extra = "".join(
@@ -567,6 +574,8 @@ def _render_core(platform: Platform) -> str:
.replace("@@INSTALL@@", install)
.replace("@@INTERP_GUARD@@", interp_guard)
.replace("@@DISPATCH@@", dispatch)
.replace("@@WRITER_AGENT@@", writer_agent)
.replace("@@WRITER_AGENT_ARG@@", writer_agent_arg)
.replace("@@QUERY_STUB@@", query_stub)
.replace("@@HOOKS_TARGET@@", platform.hooks_target)
.replace("@@EXTRA@@", extra)
+1 -1
View File
@@ -175,7 +175,7 @@ core = "core"
skill_dst = "graphify/skill-pi.md"
refs_dst = "graphify/skills/pi/references"
description = "Use for any question about a codebase, its architecture, file relationships, or project content — especially when graphify-out/ exists, where the question should be treated as a graphify query first. Turns any input (code, docs, papers, images, videos) into a persistent knowledge graph with god nodes, community detection, and query/path/explain tools."
dispatch = "agent-tool-disk"
dispatch = "pi-subagents"
extraction = "compact"
[platform.vscode]