pi-ui-extend 1.0.41 → 1.0.42
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.
- package/README.md +10 -2
- package/dist/app/app.d.ts +3 -0
- package/dist/app/app.js +26 -0
- package/dist/app/commands/command-host.d.ts +1 -0
- package/dist/app/commands/command-model-actions.js +6 -1
- package/dist/app/commands/command-registry.js +1 -1
- package/dist/app/commands/command-session-actions.js +9 -3
- package/dist/app/commands/reload-context-inventory.d.ts +11 -0
- package/dist/app/commands/reload-context-inventory.js +59 -0
- package/dist/app/extensions/extension-actions-controller.d.ts +1 -0
- package/dist/app/extensions/extension-actions-controller.js +6 -0
- package/dist/app/extensions/subagent-catalog-state.d.ts +9 -0
- package/dist/app/extensions/subagent-catalog-state.js +23 -0
- package/dist/app/rendering/editor-panels.js +10 -4
- package/dist/app/session/session-lifecycle-controller.d.ts +1 -0
- package/dist/app/session/session-lifecycle-controller.js +6 -0
- package/dist/app/session/tabs-controller.d.ts +1 -0
- package/dist/app/session/tabs-controller.js +19 -1
- package/dist/app/subagents/subagents-files.js +60 -1
- package/dist/app/subagents/subagents-model.d.ts +1 -0
- package/dist/app/subagents/subagents-model.js +18 -2
- package/dist/app/types.d.ts +5 -0
- package/dist/default-pix-config.js +10 -0
- package/dist/schemas/index.d.ts +1 -0
- package/dist/schemas/index.js +1 -0
- package/dist/schemas/pi-tools-suite-schema.d.ts +80 -58
- package/dist/schemas/pi-tools-suite-schema.js +43 -78
- package/dist/schemas/pix-schema.d.ts +7 -0
- package/dist/schemas/pix-schema.js +14 -0
- package/dist/schemas/tasks-schema.d.ts +18 -0
- package/dist/schemas/tasks-schema.js +41 -0
- package/docs/concurrency.md +6 -0
- package/docs/desktop-mvp.md +12 -1
- package/docs/desktop-task-manager.md +93 -82
- package/external/pi-tools-suite/README.md +37 -50
- package/external/pi-tools-suite/docs/browser-qa-subagent.md +19 -0
- package/external/pi-tools-suite/docs/evals.md +1 -1
- package/external/pi-tools-suite/docs/session-recovery.md +40 -14
- package/external/pi-tools-suite/docs/subagent-model-pools.md +38 -27
- package/external/pi-tools-suite/src/async-subagents/agents/frontier-review.md +23 -0
- package/external/pi-tools-suite/src/async-subagents/agents/presets.jsonc +16 -0
- package/external/pi-tools-suite/src/async-subagents/agents/research.md +5 -3
- package/external/pi-tools-suite/src/async-subagents/commands.ts +14 -70
- package/external/pi-tools-suite/src/async-subagents/core/activity.ts +33 -0
- package/external/pi-tools-suite/src/async-subagents/core/agent-catalog.ts +5 -4
- package/external/pi-tools-suite/src/async-subagents/core/agent-strategy.ts +1 -1
- package/external/pi-tools-suite/src/async-subagents/core/agents-dir.ts +8 -3
- package/external/pi-tools-suite/src/async-subagents/core/config.ts +122 -312
- package/external/pi-tools-suite/src/async-subagents/core/routing.ts +15 -2
- package/external/pi-tools-suite/src/async-subagents/core/spawn.ts +6 -2
- package/external/pi-tools-suite/src/async-subagents/core/state.ts +40 -0
- package/external/pi-tools-suite/src/async-subagents/core/types.ts +7 -0
- package/external/pi-tools-suite/src/async-subagents/index.ts +69 -5
- package/external/pi-tools-suite/src/async-subagents/lib.ts +7 -8
- package/external/pi-tools-suite/src/async-subagents/tools/spawn.ts +8 -4
- package/external/pi-tools-suite/src/async-subagents/tools/subagents.ts +3 -2
- package/external/pi-tools-suite/src/async-subagents/types.ts +1 -0
- package/external/pi-tools-suite/src/config.ts +41 -1
- package/external/pi-tools-suite/src/context-gateway/config.ts +11 -2
- package/external/pi-tools-suite/src/context-gateway/enforcement.ts +102 -0
- package/external/pi-tools-suite/src/context-gateway/index.ts +73 -19
- package/external/pi-tools-suite/src/context-gateway/storeless-capabilities.ts +3 -3
- package/external/pi-tools-suite/src/context-gateway/telemetry.ts +101 -28
- package/external/pi-tools-suite/src/context-gateway/types.ts +9 -3
- package/external/pi-tools-suite/src/context-inventory.ts +99 -0
- package/external/pi-tools-suite/src/dcp/auto-compress.ts +96 -44
- package/external/pi-tools-suite/src/dcp/commands.ts +18 -0
- package/external/pi-tools-suite/src/dcp/compress-tool.ts +170 -45
- package/external/pi-tools-suite/src/dcp/compression-blocks.ts +6 -58
- package/external/pi-tools-suite/src/dcp/compression-preview.ts +9 -0
- package/external/pi-tools-suite/src/dcp/config.ts +56 -13
- package/external/pi-tools-suite/src/dcp/prompts.ts +83 -192
- package/external/pi-tools-suite/src/dcp/protected-continuity.ts +175 -0
- package/external/pi-tools-suite/src/dcp/pruner-candidates.ts +1 -1
- package/external/pi-tools-suite/src/dcp/pruner-message-ids.ts +6 -10
- package/external/pi-tools-suite/src/dcp/pruner-tools.ts +6 -3
- package/external/pi-tools-suite/src/default-pi-tools-suite-config.ts +13 -9
- package/external/pi-tools-suite/src/index.ts +7 -1
- package/external/pi-tools-suite/src/resource-registry/index.ts +2290 -0
- package/external/pi-tools-suite/src/shell-command-policy.ts +219 -0
- package/external/pi-tools-suite/src/tool-descriptions.ts +3 -4
- package/package.json +4 -2
- package/schemas/pi-tools-suite.json +427 -280
- package/schemas/pix.json +24 -0
- package/schemas/tasks.json +132 -0
- package/skills/spec-wiki/SKILL.md +55 -0
- package/skills/spec-wiki/evals/evals.json +132 -0
- package/skills/spec-wiki/evals/files/bootstrap/architecture/rfc-007.md +14 -0
- package/skills/spec-wiki/evals/files/bootstrap/docs/how-to-pay.md +4 -0
- package/skills/spec-wiki/evals/files/bootstrap/docs/overview.md +9 -0
- package/skills/spec-wiki/evals/files/bootstrap/requirements/payment-behavior.md +17 -0
- package/skills/spec-wiki/evals/files/bootstrap/src/payments.ts +12 -0
- package/skills/spec-wiki/evals/files/bootstrap/tests/payments.test.ts +11 -0
- package/skills/spec-wiki/evals/files/focused/src/session.ts +5 -0
- package/skills/spec-wiki/evals/files/focused/tests/session.test.ts +17 -0
- package/skills/spec-wiki/evals/files/maintenance/low-signal/incoming/capture.txt +2 -0
- package/skills/spec-wiki/evals/files/maintenance/low-signal/src/capture.ts +3 -0
- package/skills/spec-wiki/evals/files/maintenance/move/docs/old-job-contract.md +18 -0
- package/skills/spec-wiki/evals/files/maintenance/move/src/job.ts +5 -0
- package/skills/spec-wiki/evals/files/maintenance/new-relation/docs/session-refresh.md +24 -0
- package/skills/spec-wiki/evals/files/maintenance/new-relation/incoming/refresh-worker.ts +7 -0
- package/skills/spec-wiki/evals/files/maintenance/new-relation/src/session.ts +7 -0
- package/skills/spec-wiki/evals/files/maintenance/no-impact/docs/auth-contract.md +17 -0
- package/skills/spec-wiki/evals/files/maintenance/no-impact/incoming/telemetry-format.ts +3 -0
- package/skills/spec-wiki/evals/files/maintenance/no-impact/src/auth.ts +3 -0
- package/skills/spec-wiki/evals/files/query/docs/how-to-run-jobs.md +4 -0
- package/skills/spec-wiki/evals/files/query/docs/spec-overview.md +9 -0
- package/skills/spec-wiki/evals/files/query/features/jobs/cancellation-contract.md +15 -0
- package/skills/spec-wiki/evals/files/query/features/jobs/retry-spec.md +6 -0
- package/skills/spec-wiki/evals/maintenance_regression.py +311 -0
- package/skills/spec-wiki/evals/retrieval-eval.md +37 -0
- package/skills/spec-wiki/evals/retrieval-evals.json +37 -0
- package/skills/spec-wiki/evals/trigger-evals.json +94 -0
- package/skills/spec-wiki/references/bootstrap.md +100 -0
- package/skills/spec-wiki/references/focused-spec.md +117 -0
- package/skills/spec-wiki/references/index-schema.md +330 -0
- package/skills/spec-wiki/references/maintenance.md +134 -0
- package/skills/spec-wiki/references/query.md +74 -0
- package/skills/spec-wiki/scripts/spec_wiki.py +2076 -0
- package/docs/desktop-markdown-media.md +0 -77
- package/external/pi-tools-suite/docs/dcp-emergency-current-turn.md +0 -102
- package/external/pi-tools-suite/src/async-subagents/async-subagents.sample.jsonc +0 -54
- package/external/pi-tools-suite/src/skill-installer/index.ts +0 -333
- package/skills/spec-lite/SKILL.md +0 -140
|
@@ -6,12 +6,15 @@ integration, decisions and the final answer. Actual savings depend on worker
|
|
|
6
6
|
quality, retries and how much work the parent repeats; the configuration is
|
|
7
7
|
not a price oracle.
|
|
8
8
|
|
|
9
|
-
##
|
|
9
|
+
## Six execution modes
|
|
10
10
|
|
|
11
|
-
- `research`: read-only evidence gathering, searches and
|
|
11
|
+
- `research`: read-only evidence gathering, searches and focused review questions.
|
|
12
12
|
- `implement`: bounded code, documentation, test and frontend changes.
|
|
13
13
|
- `verify`: run checks and interpret logs, without fixing source or tests.
|
|
14
14
|
- `browser-qa`: isolated browser workflow with assertions and visual artifacts.
|
|
15
|
+
- `frontier-review`: independent post-implementation code review on a strong
|
|
16
|
+
model; hidden when the current parent model matches the role's availability
|
|
17
|
+
gate.
|
|
15
18
|
- `oracle`: a deliberate strong second opinion, not automatic worker escalation.
|
|
16
19
|
|
|
17
20
|
Task-specific discipline belongs in the brief or `promptAppend`. A new project
|
|
@@ -35,29 +38,27 @@ thinking: medium
|
|
|
35
38
|
---
|
|
36
39
|
```
|
|
37
40
|
|
|
38
|
-
A preset contains a set of available models, not a per-agent matrix
|
|
41
|
+
A preset contains a set of available models, not a per-agent matrix. Project
|
|
42
|
+
pools live in `.pi/agents/presets.jsonc`:
|
|
39
43
|
|
|
40
44
|
```jsonc
|
|
41
45
|
{
|
|
42
|
-
"
|
|
43
|
-
"
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
"openai-codex/gpt-5.6-sol"
|
|
50
|
-
]
|
|
51
|
-
}
|
|
52
|
-
}
|
|
46
|
+
"gpt": {
|
|
47
|
+
"description": "Models available for this project",
|
|
48
|
+
"models": [
|
|
49
|
+
"openai-codex/gpt-5.6-luna",
|
|
50
|
+
"openai-codex/gpt-5.6-terra",
|
|
51
|
+
"openai-codex/gpt-5.6-sol"
|
|
52
|
+
]
|
|
53
53
|
}
|
|
54
54
|
}
|
|
55
55
|
```
|
|
56
56
|
|
|
57
57
|
The example agent selects Terra, not Luna: the agent's order wins. Sol is
|
|
58
58
|
available in the pool but absent from this worker's chain, so it cannot become
|
|
59
|
-
an automatic implementation fallback. The oracle
|
|
60
|
-
|
|
59
|
+
an automatic implementation fallback. The oracle and frontier-review can
|
|
60
|
+
declare Sol in their own chains. Model references in `models` must be exact
|
|
61
|
+
`provider/model` values, not wildcards.
|
|
61
62
|
|
|
62
63
|
The resolver intersects the agent chain with the selected pool. Runtime
|
|
63
64
|
selection then skips unregistered, unauthenticated or session-exhausted models.
|
|
@@ -83,22 +84,31 @@ Use `/subagent-preset <name>`, `AGENTS_PRESET=<name>` or
|
|
|
83
84
|
without a pool filter. The shipped names remain compatible with saved choices:
|
|
84
85
|
`cheap` is the GLM pool, `gpt` the GPT pool, and `deep` the mixed pool. The last
|
|
85
86
|
name no longer means that ordinary workers should escalate to flagship models.
|
|
87
|
+
Bundled definitions live beside the built-in agents in
|
|
88
|
+
`src/async-subagents/agents/presets.jsonc`; a project file with the same preset
|
|
89
|
+
name overrides that pool.
|
|
86
90
|
|
|
87
91
|
Old role names are not implicit aliases. `quick`, `scan`, `review`, `deep`,
|
|
88
92
|
`docs`, `frontend`, and `tests` work only when explicitly defined as ordinary
|
|
89
93
|
custom/project types. This keeps the effective catalog and accepted names exact.
|
|
90
94
|
|
|
91
|
-
|
|
92
|
-
`
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
95
|
+
Agent frontmatter can gate whether a role exists for the current parent model:
|
|
96
|
+
`forParentModels` is an optional allow-list and `notForParentModels` is an
|
|
97
|
+
optional deny-list; deny wins when both match. These fields accept model
|
|
98
|
+
patterns such as `zai/*` and affect the parent catalog, explicit role
|
|
99
|
+
validation, and automatic routing. They do not change which model the child
|
|
100
|
+
runs on; `models` / legacy model selectors still own child model selection.
|
|
96
101
|
|
|
97
|
-
Legacy
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
+
Legacy `model` plus `fallbackModels` and `modelByParent` still load when they are
|
|
103
|
+
declared in an agent Markdown file. New profile `models` replaces inherited
|
|
104
|
+
legacy selection fields. Empty `models` means no candidates, not permission to
|
|
105
|
+
inherit the parent model. Model-less project specialists must declare candidates
|
|
106
|
+
or receive an explicit model override.
|
|
107
|
+
|
|
108
|
+
The removed `asyncSubagents` section is no longer part of the public config
|
|
109
|
+
schema and is not read at runtime. Existing legacy files are left untouched but
|
|
110
|
+
have no effect. Migrate role definitions to `.pi/agents/*.md` and custom pools to
|
|
111
|
+
`.pi/agents/presets.jsonc`.
|
|
102
112
|
|
|
103
113
|
## Compact handoff
|
|
104
114
|
|
|
@@ -106,4 +116,5 @@ Give workers a scope, acceptance criteria and the evidence needed to start.
|
|
|
106
116
|
Read compact results first and inspect raw artifacts selectively. One noisy
|
|
107
117
|
sequential investigation can justify a worker; a command whose exit status is
|
|
108
118
|
sufficient usually only needs a saved log, not another LLM. Independent review
|
|
109
|
-
|
|
119
|
+
of substantive code changes uses `frontier-review` when it is present in the
|
|
120
|
+
current parent catalog; use `research` for focused evidence/review questions.
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: Independent frontier-model code review gate for substantive code changes made by a non-frontier parent. Use after implementation and targeted checks, before finalizing. Read-only review of the actual diff and surrounding code; use research for ordinary evidence gathering and oracle for architecture or high-stakes second opinions.
|
|
3
|
+
icon: eye
|
|
4
|
+
models: [openai-codex/gpt-5.6-sol, zai/glm-5.3]
|
|
5
|
+
notForParentModels: [openai-codex/gpt-5.6-sol*, zai/glm-5.3]
|
|
6
|
+
thinking: high
|
|
7
|
+
tools: [read, grep, bash]
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
# Frontier code review
|
|
11
|
+
|
|
12
|
+
Review the implementation independently. Inspect the actual diff and the
|
|
13
|
+
surrounding contracts; do not accept the implementer's summary as evidence.
|
|
14
|
+
|
|
15
|
+
Look for correctness bugs, regressions, broken invariants, unsafe edge cases,
|
|
16
|
+
missing error handling, concurrency/state mistakes, security issues, and tests
|
|
17
|
+
that fail to cover a material behavior change. Prefer a small number of
|
|
18
|
+
actionable findings over stylistic commentary or speculative rewrites.
|
|
19
|
+
|
|
20
|
+
Do not edit source or tests. Run narrow read-only checks when they materially
|
|
21
|
+
increase confidence. For each finding, give severity, rationale, and precise
|
|
22
|
+
file/line evidence. If there are no findings, say so explicitly and name any
|
|
23
|
+
important residual risk or verification gap.
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
// Presets are available-model pools. Agent candidate order still comes from
|
|
3
|
+
// each agent's Markdown frontmatter; pool order never reorders candidates.
|
|
4
|
+
"cheap": {
|
|
5
|
+
"description": "GLM pool: economical workers plus GLM-5.3 for frontier-review/oracle.",
|
|
6
|
+
"models": ["zai/glm-5-turbo", "zai/glm-5.3-flash", "zai/glm-5.3"]
|
|
7
|
+
},
|
|
8
|
+
"gpt": {
|
|
9
|
+
"description": "GPT pool: Luna/Terra workers; Sol is available to frontier-review/oracle.",
|
|
10
|
+
"models": ["openai-codex/gpt-5.6-luna", "openai-codex/gpt-5.6-terra", "openai-codex/gpt-5.6-sol"]
|
|
11
|
+
},
|
|
12
|
+
"deep": {
|
|
13
|
+
"description": "Mixed pool; workers retain economical candidate order and frontier-review/oracle use strong models.",
|
|
14
|
+
"models": ["zai/glm-5-turbo", "zai/glm-5.3-flash", "openai-codex/gpt-5.6-luna", "openai-codex/gpt-5.6-terra", "openai-codex/gpt-5.6-sol", "zai/glm-5.3"]
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: Read-only evidence gathering - search files, trace behavior, investigate hypotheses, or
|
|
2
|
+
description: Read-only evidence gathering - search files, trace behavior, investigate hypotheses, or analyze a focused review question. Return findings with paths, not raw source. Use frontier-review for the post-implementation code-review gate when available, verify for running checks, and implement for changes.
|
|
3
3
|
icon: search
|
|
4
4
|
models: [zai/glm-5-turbo, openai-codex/gpt-5.6-luna]
|
|
5
5
|
thinking: low
|
|
@@ -9,8 +9,10 @@ tools: [read, grep]
|
|
|
9
9
|
# Research
|
|
10
10
|
|
|
11
11
|
Investigate the assigned question within scope. Read and compare evidence; do
|
|
12
|
-
not edit files or invent missing facts.
|
|
13
|
-
the
|
|
12
|
+
not edit files or invent missing facts. When assigned a review question, make
|
|
13
|
+
it a fresh investigation of the relevant code, not approval based on another
|
|
14
|
+
agent's summary. The broad post-implementation review gate belongs to
|
|
15
|
+
frontier-review when that role is available.
|
|
14
16
|
|
|
15
17
|
Return the answer and supporting file:line references, distinguishing confirmed
|
|
16
18
|
findings from hypotheses. Report gaps or a concrete blocker when the available
|
|
@@ -3,15 +3,12 @@ import * as fs from "node:fs";
|
|
|
3
3
|
import * as path from "node:path";
|
|
4
4
|
import { ignoreStaleExtensionContextError } from "../context-usage.js";
|
|
5
5
|
import {
|
|
6
|
-
copySubagentConfigSample,
|
|
7
6
|
ensureSessionFileLink,
|
|
8
|
-
existingSubagentConfigFiles,
|
|
9
7
|
findSubagentSessionByFile,
|
|
10
8
|
getActiveSubagentPresetName,
|
|
11
|
-
|
|
9
|
+
getBuiltinSubagentPresetsPath,
|
|
10
|
+
getProjectSubagentPresetsPath,
|
|
12
11
|
getSessionSubagentPresetOverride,
|
|
13
|
-
getSubagentConfigInitTargetPath,
|
|
14
|
-
getSubagentConfigSamplePath,
|
|
15
12
|
getSubagentPresetSelectionPath,
|
|
16
13
|
getRunState,
|
|
17
14
|
listRunDirs,
|
|
@@ -49,7 +46,6 @@ type MessageSender = ExtensionAPI & {
|
|
|
49
46
|
};
|
|
50
47
|
|
|
51
48
|
const CLEAR_ACTIVE_PRESET_LABEL = "Use no active preset";
|
|
52
|
-
const COPY_SAMPLE_CONFIG_LABEL = "Copy sample asyncSubagents config";
|
|
53
49
|
|
|
54
50
|
export const ULTRAWORK_PROMPT = `Run ultrawork mode for the current objective.
|
|
55
51
|
|
|
@@ -192,12 +188,10 @@ async function triggerOrchestrationPrompt(
|
|
|
192
188
|
|
|
193
189
|
function registerPresetCommands(pi: ExtensionAPI): void {
|
|
194
190
|
pi.registerCommand("subagent-preset", {
|
|
195
|
-
description: "Select a sub-agent preset
|
|
191
|
+
description: "Select a sub-agent model-pool preset, or run session <name> for a process-only override",
|
|
196
192
|
getArgumentCompletions: (prefix: string) => {
|
|
197
|
-
const names =
|
|
198
|
-
|
|
199
|
-
: [];
|
|
200
|
-
return [...names, ...names.map((name) => `session ${name}`), "list", "path", "config", "init", "clear", "session", "session-clear"]
|
|
193
|
+
const names = sortedPresetNames(loadSubagentConfig(process.cwd()).presets ?? {}, getActiveSubagentPresetName());
|
|
194
|
+
return [...names, ...names.map((name) => `session ${name}`), "list", "path", "clear", "session", "session-clear"]
|
|
201
195
|
.filter((name) => name.startsWith(prefix))
|
|
202
196
|
.map((name) => ({ value: name, label: name }));
|
|
203
197
|
},
|
|
@@ -209,28 +203,19 @@ function registerPresetCommands(pi: ExtensionAPI): void {
|
|
|
209
203
|
if (name === "session-clear") return clearSessionActiveSubagentPreset(ctx);
|
|
210
204
|
if (name === "list") return listSubagentPresets(ctx);
|
|
211
205
|
if (name === "path") return showSubagentPresetPaths(ctx);
|
|
212
|
-
if (name === "config") return showSubagentPresetConfigurator(ctx);
|
|
213
|
-
if (name === "init") return initSubagentConfigSample(ctx);
|
|
214
206
|
if (name === "clear") return clearActiveSubagentPreset(ctx);
|
|
215
|
-
if (existingSubagentConfigFiles(ctx.cwd).length === 0) return ctx.ui.notify(missingSubagentConfigMessage(ctx), "warning");
|
|
216
207
|
|
|
217
208
|
const config = loadSubagentConfig(ctx.cwd);
|
|
218
209
|
const preset = config.presets?.[name];
|
|
219
|
-
if (!preset) return ctx.ui.notify(`Unknown sub-agent preset "${name}".
|
|
210
|
+
if (!preset) return ctx.ui.notify(`Unknown sub-agent preset "${name}". Run /subagent-preset list to see available pools.`, "error");
|
|
220
211
|
setActiveSubagentPreset(name);
|
|
221
212
|
notifyActiveSubagentPreset(ctx, name, preset);
|
|
222
213
|
},
|
|
223
214
|
});
|
|
224
|
-
|
|
225
|
-
pi.registerCommand("subagent-preset-config", {
|
|
226
|
-
description: "Select sub-agent presets defined in asyncSubagents config",
|
|
227
|
-
handler: async (_args: string, ctx: CommandContext) => showSubagentPresetConfigurator(ctx),
|
|
228
|
-
});
|
|
229
215
|
}
|
|
230
216
|
|
|
231
217
|
async function showSubagentPresetSelector(ctx: CommandContext): Promise<void> {
|
|
232
218
|
if (!ctx.hasUI) return ctx.ui.notify("Sub-agent preset selector requires interactive UI. Use /subagent-preset <name>.", "warning");
|
|
233
|
-
if (existingSubagentConfigFiles(ctx.cwd).length === 0) return showMissingSubagentConfigSelector(ctx);
|
|
234
219
|
|
|
235
220
|
const config = loadSubagentConfig(ctx.cwd);
|
|
236
221
|
const activePreset = getActiveSubagentPresetName();
|
|
@@ -240,12 +225,12 @@ async function showSubagentPresetSelector(ctx: CommandContext): Promise<void> {
|
|
|
240
225
|
const labels = [...presetLabels];
|
|
241
226
|
if (activePreset) labels.push(CLEAR_ACTIVE_PRESET_LABEL);
|
|
242
227
|
if (labels.length === 0) {
|
|
243
|
-
ctx.ui.notify("No sub-agent presets are
|
|
228
|
+
ctx.ui.notify("No sub-agent model-pool presets are available.", "warning");
|
|
244
229
|
showSubagentPresetPaths(ctx);
|
|
245
230
|
return;
|
|
246
231
|
}
|
|
247
232
|
const labelToName = new Map(presetLabels.map((label, index) => [label, names[index]]));
|
|
248
|
-
const selected = await ctx.ui.select(
|
|
233
|
+
const selected = await ctx.ui.select("Select active sub-agent preset", labels);
|
|
249
234
|
if (!selected) return;
|
|
250
235
|
if (selected === CLEAR_ACTIVE_PRESET_LABEL) return clearActiveSubagentPreset(ctx);
|
|
251
236
|
|
|
@@ -254,69 +239,29 @@ async function showSubagentPresetSelector(ctx: CommandContext): Promise<void> {
|
|
|
254
239
|
setActiveSubagentPreset(name);
|
|
255
240
|
notifyActiveSubagentPreset(ctx, name, presets[name]);
|
|
256
241
|
}
|
|
257
|
-
|
|
258
|
-
async function showSubagentPresetConfigurator(ctx: CommandContext): Promise<void> {
|
|
259
|
-
if (!ctx.hasUI) return ctx.ui.notify("Sub-agent preset selector requires interactive UI.", "warning");
|
|
260
|
-
return showSubagentPresetSelector(ctx);
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
async function showMissingSubagentConfigSelector(ctx: CommandContext): Promise<void> {
|
|
264
|
-
const selected = await ctx.ui.select("No asyncSubagents config found", [COPY_SAMPLE_CONFIG_LABEL]);
|
|
265
|
-
if (selected === COPY_SAMPLE_CONFIG_LABEL) initSubagentConfigSample(ctx);
|
|
266
|
-
}
|
|
267
|
-
|
|
268
242
|
function listSubagentPresets(ctx: CommandContext): void {
|
|
269
|
-
if (existingSubagentConfigFiles(ctx.cwd).length === 0) {
|
|
270
|
-
ctx.ui.notify(missingSubagentConfigMessage(ctx), "warning");
|
|
271
|
-
return;
|
|
272
|
-
}
|
|
273
243
|
const config = loadSubagentConfig(ctx.cwd);
|
|
274
244
|
const activePreset = getActiveSubagentPresetName();
|
|
275
245
|
const presets = config.presets ?? {};
|
|
276
246
|
const names = sortedPresetNames(presets, activePreset);
|
|
277
|
-
if (names.length === 0) return ctx.ui.notify("No sub-agent presets are
|
|
247
|
+
if (names.length === 0) return ctx.ui.notify("No sub-agent model-pool presets are available.", "warning");
|
|
278
248
|
ctx.ui.notify([
|
|
279
|
-
"Sub-agent presets
|
|
249
|
+
"Sub-agent model-pool presets:",
|
|
280
250
|
...names.map((name) => `- ${subagentPresetLabel(name, presets[name], activePreset)}`),
|
|
281
251
|
].join("\n"), "info");
|
|
282
252
|
}
|
|
283
253
|
|
|
284
254
|
function showSubagentPresetPaths(ctx: CommandContext): void {
|
|
285
255
|
ctx.ui.notify([
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
`Sample config: ${getSubagentConfigSamplePath()}`,
|
|
290
|
-
`Copy sample target: ${getSubagentConfigInitTargetPath(ctx.cwd)}`,
|
|
256
|
+
`Bundled presets: ${getBuiltinSubagentPresetsPath()}`,
|
|
257
|
+
`Project preset override: ${getProjectSubagentPresetsPath(ctx.cwd)}`,
|
|
258
|
+
"Project presets are defined as model pools in .pi/agents/presets.jsonc; agent behavior stays in .pi/agents/*.md.",
|
|
291
259
|
`Active selection state: ${getSubagentPresetSelectionPath()}`,
|
|
292
260
|
`Session override: ${formatSessionPresetOverride()}`,
|
|
293
261
|
"Use /subagent-preset session <name> to override only the current Pi process; use /subagent-preset session-clear to clear that runtime override.",
|
|
294
|
-
"Run /subagent-preset init to copy the bundled sample only when no config exists.",
|
|
295
262
|
].join("\n"), "info");
|
|
296
263
|
}
|
|
297
264
|
|
|
298
|
-
function initSubagentConfigSample(ctx: CommandContext): void {
|
|
299
|
-
try {
|
|
300
|
-
const result = copySubagentConfigSample(ctx.cwd);
|
|
301
|
-
if (result.copied) {
|
|
302
|
-
ctx.ui.notify(`Copied sample asyncSubagents config:\n${result.samplePath}\n→ ${result.targetPath}`, "info");
|
|
303
|
-
return;
|
|
304
|
-
}
|
|
305
|
-
ctx.ui.notify(`AsyncSubagents config already exists; not overwriting:\n${result.existingFiles.join("\n") || result.targetPath}`, "warning");
|
|
306
|
-
} catch (error) {
|
|
307
|
-
ctx.ui.notify(error instanceof Error ? error.message : String(error), "error");
|
|
308
|
-
}
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
function missingSubagentConfigMessage(ctx: CommandContext): string {
|
|
312
|
-
return [
|
|
313
|
-
"No asyncSubagents config found in pi-tools-suite config.",
|
|
314
|
-
`Sample config: ${getSubagentConfigSamplePath()}`,
|
|
315
|
-
`Copy target: ${getSubagentConfigInitTargetPath(ctx.cwd)}`,
|
|
316
|
-
"Run /subagent-preset init to copy the bundled sample into the shared config.",
|
|
317
|
-
].join("\n");
|
|
318
|
-
}
|
|
319
|
-
|
|
320
265
|
function clearActiveSubagentPreset(ctx: CommandContext): void {
|
|
321
266
|
setActiveSubagentPreset(undefined);
|
|
322
267
|
const override = getSessionSubagentPresetOverride();
|
|
@@ -327,10 +272,9 @@ function clearActiveSubagentPreset(ctx: CommandContext): void {
|
|
|
327
272
|
|
|
328
273
|
function setSessionActiveSubagentPreset(ctx: CommandContext, name: string): void {
|
|
329
274
|
if (!name) return ctx.ui.notify("Usage: /subagent-preset session <name>", "warning");
|
|
330
|
-
if (existingSubagentConfigFiles(ctx.cwd).length === 0) return ctx.ui.notify(missingSubagentConfigMessage(ctx), "warning");
|
|
331
275
|
const config = loadSubagentConfig(ctx.cwd);
|
|
332
276
|
const preset = config.presets?.[name];
|
|
333
|
-
if (!preset) return ctx.ui.notify(`Unknown sub-agent preset "${name}".
|
|
277
|
+
if (!preset) return ctx.ui.notify(`Unknown sub-agent preset "${name}". Run /subagent-preset list to see available pools.`, "error");
|
|
334
278
|
setSessionSubagentPresetOverride(name);
|
|
335
279
|
ctx.ui.notify(`Session-only sub-agent preset "${name}": ${subagentPresetDescription(preset)}\nApplies to future sub-agent spawns only until this Pi process exits or /subagent-preset session-clear is run. Saved preset selection is unchanged.`, "info");
|
|
336
280
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import type { AgentActivity, RpcEventRecord } from "./types.js";
|
|
2
|
+
import { isRecord, isoNow } from "./utils.js";
|
|
3
|
+
|
|
4
|
+
export function activityFromRpcEvent(event: RpcEventRecord, at = isoNow()): AgentActivity | undefined {
|
|
5
|
+
if (event.type === "tool_execution_start") {
|
|
6
|
+
const toolName = nonEmptyString(event.toolName);
|
|
7
|
+
return toolName ? { label: toolName, at } : undefined;
|
|
8
|
+
}
|
|
9
|
+
if ((event.type === "message_start" || event.type === "message_end") && rpcMessageRole(event) === "assistant") {
|
|
10
|
+
return { label: "Thinking", at };
|
|
11
|
+
}
|
|
12
|
+
return undefined;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
export function activityFromProgressRecord(value: unknown): AgentActivity | undefined {
|
|
16
|
+
if (!isRecord(value) || value.stage !== "rpc_event") return undefined;
|
|
17
|
+
const at = nonEmptyString(value.at);
|
|
18
|
+
if (!at) return undefined;
|
|
19
|
+
const toolName = nonEmptyString(value.toolName);
|
|
20
|
+
if (toolName) return { label: toolName, at };
|
|
21
|
+
if (value.type === "message_start" || value.type === "message_end") return { label: "Thinking", at };
|
|
22
|
+
return undefined;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
function rpcMessageRole(event: RpcEventRecord): string | undefined {
|
|
26
|
+
const directRole = nonEmptyString(event.role);
|
|
27
|
+
if (directRole) return directRole;
|
|
28
|
+
return isRecord(event.message) ? nonEmptyString(event.message.role) : undefined;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
function nonEmptyString(value: unknown): string | undefined {
|
|
32
|
+
return typeof value === "string" && value.trim() ? value.trim() : undefined;
|
|
33
|
+
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { filterSubagentConfigForParentModel, type SubagentConfig } from "./config.js";
|
|
2
2
|
import { SUBAGENT_DELEGATION_GUIDANCE } from "./agent-strategy.js";
|
|
3
3
|
|
|
4
|
-
export const SUBAGENT_TYPE_SELECTION_GUIDANCE = "Choose and set subagentType from the available catalog when a role clearly matches, preferring a matching project-local specialist. Preserve a user-requested role. Omit subagentType only when unsure or when the user explicitly requests automatic routing; the LLM router handles omissions only. Model/thinking overrides are not substitutes for choosing a role.";
|
|
4
|
+
export const SUBAGENT_TYPE_SELECTION_GUIDANCE = "Choose and set subagentType from the available catalog when a role clearly matches, preferring a matching project-local specialist. Preserve a user-requested role when it is available in the current catalog. Omit subagentType only when unsure or when the user explicitly requests automatic routing; the LLM router handles omissions only. Model/thinking overrides are not substitutes for choosing a role.";
|
|
5
5
|
|
|
6
6
|
const MAX_DESCRIPTION_CHARS = 500;
|
|
7
7
|
|
|
@@ -10,8 +10,9 @@ const MAX_DESCRIPTION_CHARS = 500;
|
|
|
10
10
|
* The config has already merged built-ins, config files, and project-local
|
|
11
11
|
* `.pi/agents/*.md`, so this stays aligned with what spawn/routing can use.
|
|
12
12
|
*/
|
|
13
|
-
export function buildSubagentCatalogPrompt(config: SubagentConfig): string | undefined {
|
|
14
|
-
const
|
|
13
|
+
export function buildSubagentCatalogPrompt(config: SubagentConfig, parentModelRef?: string): string | undefined {
|
|
14
|
+
const effectiveConfig = filterSubagentConfigForParentModel(config, parentModelRef);
|
|
15
|
+
const entries = Object.entries(effectiveConfig.types).sort(([left], [right]) => left.localeCompare(right));
|
|
15
16
|
if (entries.length === 0) return undefined;
|
|
16
17
|
|
|
17
18
|
return [
|
|
@@ -7,7 +7,7 @@ export interface AgentStrategyOptions {
|
|
|
7
7
|
}
|
|
8
8
|
|
|
9
9
|
/** Shared by the strategy, tool description and role catalog. */
|
|
10
|
-
export const SUBAGENT_DELEGATION_GUIDANCE = "Delegate bounded work when a lower-cost worker can do it or noisy intermediate evidence should stay out of the parent context; one sequential task can qualify. Keep planning, decisions, integration and the final answer in the parent. Use research for evidence/review, implement for code/docs/tests/UI changes, verify for running checks, browser-qa for browser testing. Reserve oracle for a deliberate strong independent opinion, not
|
|
10
|
+
export const SUBAGENT_DELEGATION_GUIDANCE = "Delegate bounded work when a lower-cost worker can do it or noisy intermediate evidence should stay out of the parent context; one sequential task can qualify. Keep planning, decisions, integration and the final answer in the parent. Use research for evidence/focused review questions, implement for code/docs/tests/UI changes, verify for running checks, browser-qa for browser testing. When frontier-review is present in the current role catalog and substantive code changed, use it as the independent post-implementation review gate before finalizing; it is intentionally hidden for parent models excluded by its profile. Reserve oracle for a deliberate strong independent opinion, not routine code review. Do trivial lookups/edits directly; redirect a noisy command to a log instead of spawning an LLM when no interpretation is needed.";
|
|
11
11
|
|
|
12
12
|
export function agentStrategyPrompt(options: AgentStrategyOptions = {}): string | undefined {
|
|
13
13
|
const env = options.env ?? process.env;
|
|
@@ -46,6 +46,8 @@ const KNOWN_FRONTMATTER_KEYS = new Set([
|
|
|
46
46
|
"model",
|
|
47
47
|
"fallbackModels",
|
|
48
48
|
"modelByParent",
|
|
49
|
+
"forParentModels",
|
|
50
|
+
"notForParentModels",
|
|
49
51
|
"thinking",
|
|
50
52
|
"tools",
|
|
51
53
|
"isolatedSkills",
|
|
@@ -62,6 +64,8 @@ const COMMA_SEPARATED_ARRAY_KEYS = new Set([
|
|
|
62
64
|
"tools",
|
|
63
65
|
"models",
|
|
64
66
|
"fallbackModels",
|
|
67
|
+
"forParentModels",
|
|
68
|
+
"notForParentModels",
|
|
65
69
|
"isolatedSkills",
|
|
66
70
|
"extraArgs",
|
|
67
71
|
"retryableExitCodes",
|
|
@@ -72,7 +76,7 @@ const NUMERIC_PATTERN = /^[+-]?(\d+\.?\d*|\.\d+)([eE][+-]?\d+)?$/;
|
|
|
72
76
|
|
|
73
77
|
/** Discover and parse `.pi/agents/*.md` for the project containing `cwd`. */
|
|
74
78
|
export function readProjectAgentDefinitions(cwd: string): Record<string, ProjectAgentDefinition> {
|
|
75
|
-
const dir =
|
|
79
|
+
const dir = projectAgentsDir(cwd);
|
|
76
80
|
return dir ? readAgentDefinitionsFromDir(dir) : {};
|
|
77
81
|
}
|
|
78
82
|
|
|
@@ -94,7 +98,7 @@ export function readAgentDefinitionsFromDir(dir: string): Record<string, AgentDe
|
|
|
94
98
|
* deterministic merge order.
|
|
95
99
|
*/
|
|
96
100
|
export function projectAgentDefinitionFiles(cwd: string): string[] {
|
|
97
|
-
const dir =
|
|
101
|
+
const dir = projectAgentsDir(cwd);
|
|
98
102
|
return dir ? agentDefinitionFiles(dir) : [];
|
|
99
103
|
}
|
|
100
104
|
|
|
@@ -108,7 +112,8 @@ export function agentDefinitionFiles(dir: string): string[] {
|
|
|
108
112
|
.sort();
|
|
109
113
|
}
|
|
110
114
|
|
|
111
|
-
|
|
115
|
+
/** First project `.pi/agents` directory found walking up from cwd. */
|
|
116
|
+
export function projectAgentsDir(startDir: string): string | undefined {
|
|
112
117
|
let dir = path.resolve(startDir);
|
|
113
118
|
const root = path.parse(dir).root;
|
|
114
119
|
while (true) {
|