@expert-council/pi-package 0.4.0
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/LICENSE +21 -0
- package/README.md +505 -0
- package/dist/extension.d.ts +7 -0
- package/dist/extension.d.ts.map +1 -0
- package/dist/extension.js +372 -0
- package/dist/extension.js.map +1 -0
- package/package.json +27 -0
- package/skills/expert-council/SKILL.md +28 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Labiey
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,505 @@
|
|
|
1
|
+
# Expert Council
|
|
2
|
+
|
|
3
|
+
[English](README.md) | [简体中文](README.zh-CN.md)
|
|
4
|
+
|
|
5
|
+
Expert Council is a local, multi-model, cost-aware expert orchestration system for Pi and MCP hosts such as Codex. It discovers the models connected through Pi's registered LLM APIs and coding plans, combines runtime metadata with user-defined billing policy, capability profiles, and local reliability data, dynamically assembles a small semantic expert team, executes bounded tasks through Pi, and returns compact structured results to the Main Agent.
|
|
6
|
+
|
|
7
|
+
> ⚠️ **Codex plugin not yet released**: the Codex plugin has not completed functional testing. Its installation and usage documentation is temporarily withheld from this version and is expected to ship with the next official release. For now, use Expert Council through the native Pi Package, the CLI, or the generic MCP Server.
|
|
8
|
+
|
|
9
|
+
Key advantages:
|
|
10
|
+
|
|
11
|
+
| Advantage | Description |
|
|
12
|
+
|---|---|
|
|
13
|
+
| Cost savings | Makes flexible use of subscribed plans and LLM APIs, automatically matching the most suitable model to each task's difficulty |
|
|
14
|
+
| Speed | Runs multiple suitable models concurrently, accelerating repository exploration and context compression |
|
|
15
|
+
| Safer | Assigns different read-only/writable permissions per expert; writable experts commit into an isolated Git worktree that the Main Agent reviews before integration |
|
|
16
|
+
| Context savings | The Main Agent no longer carries long tool-call-heavy context; it receives summarized, structured results from experts |
|
|
17
|
+
|
|
18
|
+
In practice, the theoretically strongest model is not automatically the best executor. A model with stable tool calls, reliable shell behavior, and low marginal cost can deliver more real task value than a stronger but less dependable one. We recommend configuring a cost-effective, execution-strong model as the Main Agent; when a complex problem appears, Expert Council can dispatch strong-reasoning models for review or planning.
|
|
19
|
+
|
|
20
|
+
## Current status
|
|
21
|
+
|
|
22
|
+
The current release (0.4.0) includes:
|
|
23
|
+
|
|
24
|
+
- A host-independent Core: configuration validation, model normalization, billing policy, profile layering, role scoring, task classification, dynamic team sizing, retry/escalation, and telemetry aggregation.
|
|
25
|
+
- An execution runtime built on Pi's current `ModelRuntime` and `createAgentSession` APIs.
|
|
26
|
+
- Hard tool allowlists and installed-Skill filtering for every expert session.
|
|
27
|
+
- Isolated Git worktrees for writable experts.
|
|
28
|
+
- A JSON-capable CLI.
|
|
29
|
+
- An MCP Server with nine asynchronous semantic tools, event-driven completion waits, an acceptance-feedback loop, and explicit worktree cleanup.
|
|
30
|
+
- A native Pi Package.
|
|
31
|
+
- Runtime availability markers: when a call fails with dead-model evidence, the model is recorded into the persisted assessment and hard-rejected by later council building, delegation, and escalation; markers expire and are retried automatically after 24 hours.
|
|
32
|
+
- Provider session error surfacing: upstream denials such as `403 AccessDenied` are no longer swallowed; they return to the Main Agent with the real diagnostic and the correct failure class.
|
|
33
|
+
- Cross-process shared model assessment: with multiple instances running in parallel, availability markers become visible to each other without a restart.
|
|
34
|
+
- A Codex plugin with the shared Skill and a bundled stdio MCP Server (functional testing incomplete; not yet officially released).
|
|
35
|
+
- Deterministic automated tests that never consume model quota.
|
|
36
|
+
|
|
37
|
+
## Architecture
|
|
38
|
+
|
|
39
|
+
```text
|
|
40
|
+
Codex or Pi Main Agent
|
|
41
|
+
|
|
|
42
|
+
| semantic tools / shared Skill
|
|
43
|
+
v
|
|
44
|
+
Expert Council Core
|
|
45
|
+
- resource and model normalization
|
|
46
|
+
- billing and capability profiles
|
|
47
|
+
- deterministic routing
|
|
48
|
+
- roles and team sizing
|
|
49
|
+
- retry and escalation
|
|
50
|
+
- telemetry aggregation
|
|
51
|
+
|
|
|
52
|
+
v
|
|
53
|
+
Pi Runtime
|
|
54
|
+
- callable model discovery
|
|
55
|
+
- hard tool allowlists
|
|
56
|
+
- installed-Skill filtering
|
|
57
|
+
- bounded expert sessions
|
|
58
|
+
- workspace isolation
|
|
59
|
+
/ | \
|
|
60
|
+
CLI Pi Package MCP Server
|
|
61
|
+
|
|
|
62
|
+
Codex plugin
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
TypeScript project references enforce that dependencies flow only in these directions:
|
|
66
|
+
|
|
67
|
+
```text
|
|
68
|
+
core <- pi-runtime <- cli
|
|
69
|
+
<- mcp-server <- codex-integration
|
|
70
|
+
<- pi-package
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Core does not import Pi, Codex, MCP transport, filesystem, shell, or process APIs. The CLI, MCP Server, and host distributions all use the same service and routing logic.
|
|
74
|
+
|
|
75
|
+
## Quick start
|
|
76
|
+
|
|
77
|
+
Requirements:
|
|
78
|
+
|
|
79
|
+
- Node.js 22.19 or later.
|
|
80
|
+
- npm 11 or a compatible version.
|
|
81
|
+
- Pi installed and configured with at least one usable model.
|
|
82
|
+
- When writable experts need worktree isolation, the Git repository must have at least one commit.
|
|
83
|
+
|
|
84
|
+
### Install the Pi Package (available after the npm release)
|
|
85
|
+
|
|
86
|
+
<!-- Placeholder: complete install/upgrade instructions will be added once @expert-council/pi-package is published to npm. -->
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
pi install npm:@expert-council/pi-package
|
|
90
|
+
pi update npm:@expert-council/pi-package
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
The current version is not yet published to npm; build from source and install locally for now (see "Native Pi Package" below):
|
|
94
|
+
|
|
95
|
+
```bash
|
|
96
|
+
npm install
|
|
97
|
+
npm run build
|
|
98
|
+
npm test
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
Discover models without calling any of them:
|
|
102
|
+
|
|
103
|
+
```bash
|
|
104
|
+
node packages/cli/dist/bin.js models --json
|
|
105
|
+
node packages/cli/dist/bin.js inspect --json
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Assemble an expert team without executing any expert:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
node packages/cli/dist/bin.js build "fix the device hot-swap race condition" --max-experts 4 --json
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
Delegate only when you are sure actual Pi models should be called:
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
node packages/cli/dist/bin.js delegate architecture-oracle "analyze the concurrent invocation path" --workspace /path/to/repo --json
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Zero configuration uses conservative capability defaults, marks unverifiable billing types as `unknown`, and refuses non-isolated writes. It never guesses that an API is free and never infers model quality from a model name.
|
|
121
|
+
|
|
122
|
+
## Model discovery
|
|
123
|
+
|
|
124
|
+
`PiExpertRuntime` calls Pi's `ModelRuntime.getAvailable()` instead of using a hardcoded catalog. A model that merely exists in a registry or user profile is not routed to; only models Pi reports as currently callable are used.
|
|
125
|
+
|
|
126
|
+
The runtime normalizes:
|
|
127
|
+
|
|
128
|
+
- provider and model ID;
|
|
129
|
+
- display name;
|
|
130
|
+
- reasoning support and the reasoning-level map exposed by Pi;
|
|
131
|
+
- context and maximum output windows;
|
|
132
|
+
- input modalities;
|
|
133
|
+
- published API price fields;
|
|
134
|
+
- safe compatibility metadata.
|
|
135
|
+
|
|
136
|
+
The runtime resolves a locally installed compatible Pi SDK first, then an explicit `PI_CODING_AGENT_MODULE` directory, then a compatible global npm Pi installation. If all fail, it returns an actionable diagnostic instead of fabricating a model list.
|
|
137
|
+
|
|
138
|
+
Pi builds this inventory once per session, and provider catalogs can keep stale model names, so `listAvailableModels()` may include a model the upstream can no longer serve. Routing treats such a model as callable until a real attempt fails; this is why failures with dead-model evidence mark the model unavailable in the persisted model assessment (see the routing section below). Markers expire after 24 hours, and a recovered model is retried automatically.
|
|
139
|
+
|
|
140
|
+
## Configuration
|
|
141
|
+
|
|
142
|
+
Specify a configuration file through the `EXPERT_COUNCIL_CONFIG` environment variable or the CLI's `--config PATH` flag. Start from [`config/examples/balanced.example.json`](config/examples/balanced.example.json).
|
|
143
|
+
|
|
144
|
+
Profile precedence:
|
|
145
|
+
|
|
146
|
+
```text
|
|
147
|
+
built-in conservative defaults
|
|
148
|
+
< user configuration or optional presets
|
|
149
|
+
< current-task runtime overrides
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Objective runtime metadata is merged separately. Local outcome data influences routing only after at least three samples accumulate, and the adjustment is bounded by `routing.localLearningMaxAdjustment`. Explicit user configuration always wins.
|
|
153
|
+
|
|
154
|
+
### Billing policy
|
|
155
|
+
|
|
156
|
+
Supported billing types:
|
|
157
|
+
|
|
158
|
+
```text
|
|
159
|
+
subscription metered quota free unknown
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
Marginal cost and usage preference are two independent fields because published token prices cannot express subscription plans, fixed quotas, local inference, or promotional credits. The Pi Runtime adapter classifies runtime-reported subscription access or named Token Plan catalogs as `subscription`; otherwise a provider whose Pi model catalog exposes non-zero prices is `metered`, and providers without reliable evidence stay `unknown`. `expert_inspect` returns the inference source, and explicit user configuration always has the highest priority. Models within the same metered provider are still compared on specific prices through `routing.apiPriceWeight` (default `0.35`); an all-zero price table is treated as "not provided", never guessed to be free.
|
|
163
|
+
|
|
164
|
+
```json
|
|
165
|
+
{
|
|
166
|
+
"billing": {
|
|
167
|
+
"providers": {
|
|
168
|
+
"subscription-provider": {
|
|
169
|
+
"billingType": "subscription",
|
|
170
|
+
"marginalCostClass": "very-low",
|
|
171
|
+
"usagePreference": "consume-first"
|
|
172
|
+
},
|
|
173
|
+
"scarce-provider": {
|
|
174
|
+
"billingType": "quota",
|
|
175
|
+
"marginalCostClass": "scarce",
|
|
176
|
+
"usagePreference": "escalation-only"
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
```
|
|
182
|
+
|
|
183
|
+
`config/examples/` provides:
|
|
184
|
+
|
|
185
|
+
- `balanced.example.json`: conservative defaults for zero configuration.
|
|
186
|
+
- `subscription-heavy.example.json`: prioritize subscription capacity, protect scarce quota.
|
|
187
|
+
- `metered-quality.example.json`: separate economical from high-quality metered APIs.
|
|
188
|
+
- `qwen-glm.example.json`: explicitly labeled as a hypothetical user preference, not an objective benchmark.
|
|
189
|
+
|
|
190
|
+
### Capability profiles
|
|
191
|
+
|
|
192
|
+
Models can receive user scores from 0 to 10 on these dimensions:
|
|
193
|
+
|
|
194
|
+
```text
|
|
195
|
+
reasoning planning architecture coding debugging review longContext
|
|
196
|
+
toolReliability bashReliability autonomousExecution speed
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
Model keys must use the exact `provider/model` returned by `models --json`. Newly discovered models without local profiles receive conservative defaults; stale configuration for unavailable models only produces warnings and never crashes routing.
|
|
200
|
+
|
|
201
|
+
### Main Agent capability audit and first-council preference
|
|
202
|
+
|
|
203
|
+
Users do not need to maintain per-model usage priorities. After the Main Agent decides a task deserves a council, if this is the first council in a new conversation and the user has not expressed a preference, it should ask once:
|
|
204
|
+
|
|
205
|
+
```text
|
|
206
|
+
price first (economy)
|
|
207
|
+
balance price, time, and success rate (balanced)
|
|
208
|
+
speed first (speed)
|
|
209
|
+
```
|
|
210
|
+
|
|
211
|
+
The Pi Package records the choice in the current Pi session's hidden extension state; later councils in that conversation reuse it automatically unless the user changes it. `economy` boosts cost weights, `speed` boosts the audited speed dimension, and `balanced` uses normal role weights. The legacy `quality` API value remains compatible but is not offered as a default prompt option.
|
|
212
|
+
|
|
213
|
+
Model capabilities are audited by the Main Agent rather than hand-ranked by users. `expert_inspect` returns a mandatory assessment gate: if there is no audit yet, the audit is older than 30 days, the callable model set changed, or the user explicitly requests a re-audit, the Main Agent must research every callable model listed by the gate using the host's own web tools; `expert_build` will not assemble a council until then. The Main Agent submits a complete `modelAssessment` whose ISO timestamp must come from the host's real clock, whose sources are consolidated into 1–12 URLs, and which contains 0–10 capability dimensions plus verifiable provider access/billing evidence. Future-dated timestamps are reported separately and can be corrected without repeating the web research. If the gate reports the saved assessment is still `current`, the host should omit `modelAssessment` when calling `expert_build`; incomplete, stale, or future-dated replacement snapshots cannot displace a current one. The assessment is stored once per user data directory and reused across conversations and workspaces as long as the callable model set remains compatible; ordinary plan and execution state saves never overwrite the global assessment from a stale in-memory snapshot, and only an explicitly submitted assessment that passes the gate replaces the stored scores. Explicit user billing configuration always outranks the Main Agent's judgment; unverifiable billing stays `unknown`.
|
|
214
|
+
|
|
215
|
+
Cross-check rather than trust a single leaderboard: the [Artificial Analysis Data API](https://artificialanalysis.ai/data-api/docs) provides coding, agentic, price, throughput, and latency data; [LiveBench](https://livebench.ai/) covers coding and agentic coding; [Arena](https://arena.ai/leaderboard/text) reflects human preference; provider documentation verifies versions, context, tools, and access method. [OpenRouter Rankings](https://openrouter.ai/rankings?category=programming) mostly reflect real-world usage and are only an adoption signal, not proof of model quality. When the gate demands an audit and the host has no web tools, the Main Agent must state the limitation and stop instead of silently using unaudited defaults; Expert Council never auto-installs plugins, Skills, or third-party executables.
|
|
216
|
+
|
|
217
|
+
### Role weights
|
|
218
|
+
|
|
219
|
+
Every semantic role has normalized default weights. Implementation Worker emphasizes tool reliability, coding, autonomous execution, and shell reliability; Architecture Oracle emphasizes architecture, planning, long context, and review.
|
|
220
|
+
|
|
221
|
+
```json
|
|
222
|
+
{
|
|
223
|
+
"routing": {
|
|
224
|
+
"roleWeights": {
|
|
225
|
+
"implementation-worker": {
|
|
226
|
+
"toolReliability": 0.4,
|
|
227
|
+
"coding": 0.3,
|
|
228
|
+
"costEfficiency": 0.1
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
```
|
|
234
|
+
|
|
235
|
+
Weights are re-normalized automatically. `costPolicy: economy` boosts the cost factor, `speed` boosts speed and reduces cost, and the legacy `quality` reduces cost; none of them bypass safety or compatibility hard constraints.
|
|
236
|
+
|
|
237
|
+
## Semantic roles and team sizing
|
|
238
|
+
|
|
239
|
+
Roles are defined by task semantics and never bound to a model name:
|
|
240
|
+
|
|
241
|
+
| Role | Default permissions | Purpose |
|
|
242
|
+
|---|---|---|
|
|
243
|
+
| Planner | read-only | Task decomposition, dependencies, and risks |
|
|
244
|
+
| Scout | read-only | Repository exploration and context compression |
|
|
245
|
+
| Architecture Oracle | read-only | Hard cross-file reasoning and second opinions |
|
|
246
|
+
| Implementation Worker | writable | Bounded code changes and focused testing |
|
|
247
|
+
| Debugger | writable | Reproduce, isolate, fix, and verify |
|
|
248
|
+
| Reviewer | read-only | Regressions, edge cases, and design review |
|
|
249
|
+
| Verifier | read-only | Check reported tests, diffs, and acceptance criteria |
|
|
250
|
+
|
|
251
|
+
Tiny tasks use one Worker; normal tasks use Worker plus Verifier; complex features use Planner, Worker, Reviewer, and Verifier; complex debugging uses Scout, Debugger, Oracle, and Verifier. `maxExperts` caps team size, and the Main Agent is never duplicated as a redundant `lead` expert.
|
|
252
|
+
|
|
253
|
+
Task classification and all scoring math are deterministic. Hosts can inspect the selected model, alternatives, scores, and concise reasons before delegating. Council assembly also applies configurable diversity penalties; Reviewers prefer a different provider and inferred model family from earlier members when economical, but role fit and hard constraints still dominate.
|
|
254
|
+
|
|
255
|
+
## Routing pipeline
|
|
256
|
+
|
|
257
|
+
```text
|
|
258
|
+
discover currently callable candidate models
|
|
259
|
+
-> apply hard constraints
|
|
260
|
+
-> merge capability and profile layers
|
|
261
|
+
-> score role fit and effective cost
|
|
262
|
+
-> conservatively apply local outcome adjustments
|
|
263
|
+
-> rank with stable tie-breaking
|
|
264
|
+
-> return selection, alternatives, and reasons
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
Hard constraints reject unavailable or disabled models, incompatible roles, insufficient tool reliability, insufficient context, mutation without runtime support, `escalation-only` resources on routine tasks, and models carrying an active runtime availability marker.
|
|
268
|
+
|
|
269
|
+
Pi caches its model inventory per session and provider catalogs can keep stale model names, so a council could otherwise be assembled around a model the upstream can no longer serve. When a delegated attempt fails as `provider_error` with dead-model evidence (for example `model_not_found`, unknown or discontinued models, or the runtime's own availability pre-check), the service records a `modelAvailability` marker into the persisted shared model assessment (`EXPERT_COUNCIL_DATA_DIR`, i.e. `%LOCALAPPDATA%/ExpertCouncil/model-assessment.json` on Windows) through an atomic read-modify-write that never reverts a newer snapshot written by another running Pi/Codex instance. The affected `expert_result` names the model in `executionMetadata.unavailableModels` and `risks`, `expert_inspect` warns about active markers, and later `expert_build`, delegation, and escalation hard-reject marked models. Markers are conservative local evidence: they expire after 24 hours, survive freshly submitted audits, and an explicit `modelOverrides["provider/model"].overrideUnavailableMarker: true` re-enables a model. Transient provider failures such as rate limits or authentication errors never create markers. When no saved assessment exists yet, the marker cannot be persisted, but the failure is still reported to the Main Agent and recorded in local telemetry.
|
|
270
|
+
|
|
271
|
+
Reasoning levels are optional and model-specific. A configured role preference applies only when Pi exposes it for the selected model; otherwise Pi keeps or clamps to the model's supported default.
|
|
272
|
+
|
|
273
|
+
## Skills and least privilege
|
|
274
|
+
|
|
275
|
+
The canonical platform-neutral host guidance is [`shared/skills/expert-council/SKILL.md`](shared/skills/expert-council/SKILL.md). The build composes it with the small host overlays under `shared/skills/expert-council/hosts/` into separate Pi and Codex `SKILL.md` artifacts without duplicating the shared workflow. The Pi artifact only describes completion `steer`/`followUp` behavior and never exposes `expert_wait`; only the Codex artifact describes the bounded `expert_wait` flow. Shared role prompts live in `packages/core/src/roles/prompts/` and are copied as package assets rather than rewritten per host.
|
|
276
|
+
|
|
277
|
+
Read-only roles never receive `edit`, `write`, `bash`, or `powershell`, even if a caller tries to include them. Pi sessions use a real `tools` allowlist, which is stronger than prompt-only guidance. Until a dedicated non-mutating command runner exists, tasks that need shell-driven testing belong to writable roles in isolated worktrees.
|
|
278
|
+
|
|
279
|
+
Only installed, enabled Pi Skills required by the role are activated. User-scope Skills are trusted by default; project and temporary Skills are excluded unless their exact name is listed in `security.trustedSkills`. Every expert resource loader disables extensions, prompt templates, themes, and project context files, and Pi SDK versions that cannot enforce these policies are rejected. Expert Council never downloads or installs Skills or executable extensions.
|
|
280
|
+
|
|
281
|
+
Expert prompts require: read before editing, verify paths, prefer targeted edits, diagnose failures before changing approach, use finite non-interactive commands, inspect results, never delegate recursively, and return compact JSON instead of private reasoning.
|
|
282
|
+
|
|
283
|
+
## Retry and escalation
|
|
284
|
+
|
|
285
|
+
Failure types are normalized to:
|
|
286
|
+
|
|
287
|
+
```text
|
|
288
|
+
tool_call_error reasoning_failure test_failure timeout provider_error
|
|
289
|
+
missing_context permission_error unknown
|
|
290
|
+
```
|
|
291
|
+
|
|
292
|
+
By default, the first correctable tool, context, or test failure receives at most one retry with a changed approach. Repeated relevant failures or provider errors switch to the next eligible, untried model. Attempt and escalation budgets are separately capped; with no candidates or exhausted budget, an unresolved state returns to the Main Agent.
|
|
293
|
+
|
|
294
|
+
There are no infinite loops, and the same failed action is never repeated blindly by policy.
|
|
295
|
+
|
|
296
|
+
## Structured results and context efficiency
|
|
297
|
+
|
|
298
|
+
Expert results contain status, role, model, summary, changed files, tests, findings, risks, recommended next action, failure type, the approximate usage Pi exposes, and bounded execution metadata. The system prefers the expert's own structured failure type and deterministically classifies test, provider, tool, and context failures; unparseable non-JSON output is marked `reasoning_failure`. Private reasoning is never requested or stored, and whole source files are never copied back into the Main Agent's context.
|
|
299
|
+
|
|
300
|
+
## Workspace safety
|
|
301
|
+
|
|
302
|
+
The system never assumes that Codex's own sandbox contains the external Pi process. The Pi Runtime uses an independent boundary:
|
|
303
|
+
|
|
304
|
+
1. Canonicalize the requested workspace path.
|
|
305
|
+
2. Require the path to fall under allowed roots.
|
|
306
|
+
3. Create a detached worktree from the repository's current `HEAD` inside a current-user-private directory under the system temp directory.
|
|
307
|
+
4. Give the Worker write tools inside that worktree.
|
|
308
|
+
5. Return the worktree path and changed-file list.
|
|
309
|
+
6. The Codex or Pi Main Agent inspects, integrates, and finally accepts.
|
|
310
|
+
7. After accepting or rejecting, call `expert_cleanup`. One call removes every worktree created for that execution ID through retries or escalations and returns all removed paths. Unclaimed worktrees are pruned automatically after `security.worktreeRetentionMs` (24 hours by default), and Git metadata is pruned alongside.
|
|
311
|
+
|
|
312
|
+
Non-Git workspaces refuse writes by default. If in-place mutation is truly required, it must be explicitly enabled:
|
|
313
|
+
|
|
314
|
+
```json
|
|
315
|
+
{
|
|
316
|
+
"security": {
|
|
317
|
+
"workspaceStrategy": "bounded-in-place",
|
|
318
|
+
"allowInPlaceMutations": true,
|
|
319
|
+
"allowedWorkspaceRoots": ["/absolute/path/to/project"]
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
```
|
|
323
|
+
|
|
324
|
+
Read [`SECURITY.md`](SECURITY.md) before enabling.
|
|
325
|
+
|
|
326
|
+
## Telemetry and local learning
|
|
327
|
+
|
|
328
|
+
The default user data root is `%LOCALAPPDATA%\ExpertCouncil` on Windows, `$XDG_STATE_HOME/expert-council` or `~/.local/state/expert-council` on Linux, and `~/Library/Application Support/ExpertCouncil` on macOS. The shared `telemetry.jsonl` stores opaque execution outcomes so real reliability can be reused across conversations and workspaces; feedback for the same execution overwrites earlier samples and never double-counts. The shared `model-assessment.json` stores the latest explicit capability and billing scores plus runtime-learned model availability markers. `EXPERT_COUNCIL_DATA_DIR`, `EXPERT_COUNCIL_TELEMETRY`, `EXPERT_COUNCIL_MODEL_ASSESSMENT`, and `EXPERT_COUNCIL_STATE` override locations.
|
|
329
|
+
|
|
330
|
+
It never records prompts, source content, credentials, API keys, secrets, or reasoning. Aggregate metrics include per-role success rate, first-pass rate, tool error rate, retry rate, verification pass rate, and average attempts. Expert Council has no remote analytics endpoint.
|
|
331
|
+
|
|
332
|
+
Plans, execution state, and completed structured results remain workspace-scoped in `workspaces/<workspace hash>/state.json`. They survive process restarts; a task still running at restart is closed as an explicit interrupted failure. Legacy in-project `.expert-council` and `%USERPROFILE%\.expert-council` directories are not deleted automatically.
|
|
333
|
+
|
|
334
|
+
## CLI
|
|
335
|
+
|
|
336
|
+
The CLI uses exactly the same Core and Pi Runtime as MCP and the Pi Package:
|
|
337
|
+
|
|
338
|
+
```text
|
|
339
|
+
expert-council models
|
|
340
|
+
expert-council inspect
|
|
341
|
+
expert-council build <task>
|
|
342
|
+
expert-council delegate <role> <task>
|
|
343
|
+
expert-council feedback <execution-id> --verification passed|failed
|
|
344
|
+
expert-council cleanup <execution-id>
|
|
345
|
+
expert-council status
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
Common flags:
|
|
349
|
+
|
|
350
|
+
- `--json`: machine-readable output.
|
|
351
|
+
- `--cwd`: project workspace.
|
|
352
|
+
- `--config`: user policy file.
|
|
353
|
+
- `--telemetry`: custom local telemetry path.
|
|
354
|
+
- `--state`: custom path for persisted plans, executions, and results.
|
|
355
|
+
- `--timeout-ms`: expert execution timeout.
|
|
356
|
+
|
|
357
|
+
## MCP Server
|
|
358
|
+
|
|
359
|
+
The MCP surface is deliberately limited to nine semantic tools:
|
|
360
|
+
|
|
361
|
+
- `expert_inspect`
|
|
362
|
+
- `expert_build`
|
|
363
|
+
- `expert_delegate`
|
|
364
|
+
- `expert_wait`
|
|
365
|
+
- `expert_result`
|
|
366
|
+
- `expert_feedback`
|
|
367
|
+
- `expert_cleanup`
|
|
368
|
+
- `expert_escalate`
|
|
369
|
+
- `expert_status`
|
|
370
|
+
|
|
371
|
+
`expert_inspect` and `expert_build` return compact host-facing views by default. Pass `detail: "full"` only when exact model metadata, alternatives, scores, tools, or Skills are genuinely required.
|
|
372
|
+
|
|
373
|
+
`expert_delegate` starts background work and immediately returns execution IDs; the original single-assignment parameters remain compatible. The Main Agent should set an explicit `timeoutMs` per assignment based on expected difficulty instead of relying on the runtime's ten-minute fallback. When two or more independent tasks exist, dispatch the entire batch before continuing other Main Agent work:
|
|
374
|
+
|
|
375
|
+
```json
|
|
376
|
+
{
|
|
377
|
+
"assignments": [
|
|
378
|
+
{ "role": "scout", "task": "locate relevant files", "taskDescription": "repo mapping", "timeoutMs": 300000 },
|
|
379
|
+
{ "role": "reviewer", "task": "review boundary design", "taskDescription": "boundary review", "timeoutMs": 600000 }
|
|
380
|
+
]
|
|
381
|
+
}
|
|
382
|
+
```
|
|
383
|
+
|
|
384
|
+
`assignments` must be an actual JSON array, never a string containing JSON. The native Pi adapter offers bounded compatibility parsing for models that occasionally stringify the array, but normal callers should emit real arrays.
|
|
385
|
+
|
|
386
|
+
The optional `taskDescription` is a short host-facing label for identifying the task; it is not part of the expert's actual task content. After dispatching, the Main Agent should continue all independently completable work; when nothing useful remains, call `expert_wait` once with up to eight execution IDs, usually `mode: "all"` (use `"any"` when any early result unblocks progress), and a `timeoutMs` sized to the estimated remaining difficulty. Waiting is driven by execution-promise completion events rather than polling; blocking the current MCP call is expected behavior, and no main-model tokens are consumed while waiting.
|
|
387
|
+
|
|
388
|
+
```json
|
|
389
|
+
{
|
|
390
|
+
"executionIds": ["exec_a", "exec_b"],
|
|
391
|
+
"mode": "all",
|
|
392
|
+
"timeoutMs": 900000
|
|
393
|
+
}
|
|
394
|
+
```
|
|
395
|
+
|
|
396
|
+
`expert_wait` returns only completion state and task IDs; fetch the formal feedback with `expert_result` and call `expert_feedback` after the Main Agent's acceptance. `expert_wait.timeoutMs` bounds only that wait and never extends each expert's own execution deadline. Every potentially blocking Expert Council, Bash, PowerShell, or other MCP call must still carry an explicit finite timeout sized to the operation; remaining synchronous Expert Council operations are protected by an independent 30-second in-server cap. `expert_status` returns a bounded per-attempt history. The native Pi Package uses proactive completion notifications and therefore does not expose `expert_wait`.
|
|
397
|
+
|
|
398
|
+
Start the stdio server directly:
|
|
399
|
+
|
|
400
|
+
```bash
|
|
401
|
+
node packages/mcp-server/dist/bin.js
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
Supported environment variables:
|
|
405
|
+
|
|
406
|
+
- `EXPERT_COUNCIL_WORKSPACE`: default allowed workspace.
|
|
407
|
+
- `EXPERT_COUNCIL_CONFIG`: user JSON configuration.
|
|
408
|
+
- `EXPERT_COUNCIL_TELEMETRY`: local telemetry JSONL path.
|
|
409
|
+
- `EXPERT_COUNCIL_STATE`: persisted plans, executions, and results state path.
|
|
410
|
+
- `EXPERT_COUNCIL_MCP_TIMEOUT_MS`: bounded timeout for synchronous MCP operations, 30000 ms by default.
|
|
411
|
+
- `PI_CODING_AGENT_MODULE`: explicit Pi package directory when automatic resolution fails.
|
|
412
|
+
|
|
413
|
+
Environment overrides and CLI path flags are trusted operator inputs. In particular, `PI_CODING_AGENT_MODULE` loads executable code, while config, workspace, telemetry, and state paths select local files; never accept them from an untrusted repository, task text, or model output.
|
|
414
|
+
|
|
415
|
+
## Native Pi Package
|
|
416
|
+
|
|
417
|
+
Build and install the local candidate from the repository root. Even on Windows, use forward slashes whenever a command may pass through Pi's Bash-compatible shell; an unquoted `.\packages\pi-package` loses its backslashes before reaching Pi.
|
|
418
|
+
|
|
419
|
+
```bash
|
|
420
|
+
npm run build
|
|
421
|
+
pi install "./packages/pi-package"
|
|
422
|
+
pi list
|
|
423
|
+
pi --verbose
|
|
424
|
+
```
|
|
425
|
+
|
|
426
|
+
`pi list` should show the configured source and its resolved absolute package directory. A newly started verbose Pi session should list `dist/extension.js`, the `expert-council` Skill, and the eight semantic tools without `expert_wait`. Running Pi processes do not hot-reload a rebuilt or removed package.
|
|
427
|
+
|
|
428
|
+
Or load it for one run without persisting:
|
|
429
|
+
|
|
430
|
+
```bash
|
|
431
|
+
pi --verbose -e "./packages/pi-package"
|
|
432
|
+
```
|
|
433
|
+
|
|
434
|
+
A zero-cost load check simply asks Pi to call `expert_inspect`. A real orchestration check should, in a new conversation, build one read-only council, batch two independent read-only assignments at once, confirm that `expert_delegate` immediately returns execution IDs, then accept each completion with `expert_result` and `expert_feedback`. When testing a writable expert, also confirm that one `expert_cleanup` call reports every retry worktree for the execution in `workspaces` and that `git worktree list` afterwards contains only the main checkout.
|
|
435
|
+
|
|
436
|
+
Before removing a persistent installation, exit every Pi process that loaded the package, then run from the same repository root:
|
|
437
|
+
|
|
438
|
+
```bash
|
|
439
|
+
pi remove "./packages/pi-package"
|
|
440
|
+
pi list
|
|
441
|
+
```
|
|
442
|
+
|
|
443
|
+
If the working directory changed, pass the resolved absolute path instead. PowerShell example:
|
|
444
|
+
|
|
445
|
+
```powershell
|
|
446
|
+
$ecPiPackage = (Resolve-Path "./packages/pi-package").Path
|
|
447
|
+
pi remove "$ecPiPackage"
|
|
448
|
+
pi list
|
|
449
|
+
```
|
|
450
|
+
|
|
451
|
+
If removal runs through Pi's Bash-compatible shell, use the forward-slash absolute path printed by `pi list`, for example `pi remove "C:/path/to/ExpertCouncil/packages/pi-package"`. Do not copy the indented relative source shown by `pi list` unless the command is resolved from the same settings-directory context.
|
|
452
|
+
|
|
453
|
+
Pi loads `dist/extension.js` and the synchronized `expert-council` Skill through the package manifest's `pi.extensions` and `pi.skills`. The extension registers the eight semantic tools; because native Pi already provides completion `steer`/`followUp`, the MCP-only `expert_wait` is omitted. It contains no second routing implementation.
|
|
454
|
+
|
|
455
|
+
Pi delegation is non-blocking; a single call can start up to eight independent background assignments before returning. When an expert finishes, the extension sends compact JSON containing the completed `executionId` and, only when supplied at dispatch, the `taskDescription`; it never carries feedback directly. Notifications use `steer` while the Main Agent is working and a `triggerTurn` `followUp` when it is idle. The Main Agent then calls `expert_result` for the structured feedback. Dispatch the entire ready batch before ending the turn, and avoid polling or silently waiting afterwards.
|
|
456
|
+
|
|
457
|
+
## Testing
|
|
458
|
+
|
|
459
|
+
```bash
|
|
460
|
+
npm test
|
|
461
|
+
npm run typecheck
|
|
462
|
+
npm run build
|
|
463
|
+
npm run pack:check
|
|
464
|
+
npm run validate
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
`npm run validate` builds first so a fresh clone has the workspace package entries generated before testing. Tests cover model normalization, published prices versus real policy billing, worker reliability, oracle scoring, reviewer diversity, hard constraints, unknown and missing models, team sizing, retries with per-attempt diagnostics, structured failure classification, escalation, retry limits, role permissions, compact host output, configuration validation, telemetry privacy/feedback/usage aggregation, Core host independence, mocked Pi discovery and execution, CLI JSON, MCP schemas, real Pi 0.84.4 extension loading/wrapping and async batch notifications, Pi extension registration, and real Git worktree isolation.
|
|
468
|
+
|
|
469
|
+
Ordinary tests only use the mock runtime and never call paid models. A real read-only Pi execution requires both an explicit model and an explicit cost acknowledgement:
|
|
470
|
+
|
|
471
|
+
```powershell
|
|
472
|
+
$env:EXPERT_COUNCIL_LIVE_MODEL = "provider/model"
|
|
473
|
+
$env:EXPERT_COUNCIL_LIVE_CONFIRM = "YES"
|
|
474
|
+
npm run smoke:live:pi
|
|
475
|
+
```
|
|
476
|
+
|
|
477
|
+
Ordinary validation flows never execute that script.
|
|
478
|
+
|
|
479
|
+
## Publishing
|
|
480
|
+
|
|
481
|
+
Run `npm run validate` first, inspect every `npm pack --dry-run` file list, then publish in dependency order:
|
|
482
|
+
|
|
483
|
+
```text
|
|
484
|
+
@expert-council/core
|
|
485
|
+
@expert-council/pi-runtime
|
|
486
|
+
@expert-council/cli
|
|
487
|
+
@expert-council/mcp-server
|
|
488
|
+
@expert-council/pi-package
|
|
489
|
+
```
|
|
490
|
+
|
|
491
|
+
## Known limitations
|
|
492
|
+
|
|
493
|
+
- Pi's API moves quickly. The current release was verified against the local 0.84.4 SDK; the runtime checks required SDK, model-runtime, resource-loader, and session methods and lists any missing contract explicitly on incompatibility.
|
|
494
|
+
- Pi has no unified real billing-type API. Runtime subscription signals and named Token Plans take priority; otherwise non-zero catalog prices are treated as metered, and providers without reliable evidence stay `unknown` until an audit or explicit user configuration confirms them.
|
|
495
|
+
- Expert Council does not infer subjective coding quality from model names, nor does it download benchmark presets automatically.
|
|
496
|
+
- Detached worktrees start from the committed `HEAD` and do not copy uncommitted changes from the main workspace. This is deliberate isolation; the runtime detects a dirty source workspace and surfaces the deviation through runtime limitations and mutation-council warnings before delegation.
|
|
497
|
+
- Worktree changes are returned for Main Agent review and are never auto-merged or applied; call `expert_cleanup` after acceptance or rejection, or they will be cleaned up automatically after the retention window.
|
|
498
|
+
- Writes to non-Git workspaces require explicit in-place mutation authorization.
|
|
499
|
+
- In-flight model calls do not resume after a server restart; persisted state closes them as explicit interrupted failures while preserving plans and completed results.
|
|
500
|
+
- Codex's own sandbox does not automatically contain the external Pi runtime, so Expert Council uses separate allowed roots and worktree boundaries.
|
|
501
|
+
- Expert Council contains no arbitrary third-party package installation, recursive expert trees, graphical interface, remote control plane, or remote telemetry.
|
|
502
|
+
|
|
503
|
+
## License
|
|
504
|
+
|
|
505
|
+
MIT; see [`LICENSE`](LICENSE).
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type ExpertCouncil } from "@expert-council/core";
|
|
2
|
+
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
3
|
+
export interface ExpertCouncilExtensionDependencies {
|
|
4
|
+
councilFor?: (cwd: string) => Promise<ExpertCouncil>;
|
|
5
|
+
}
|
|
6
|
+
export default function expertCouncilExtension(pi: ExtensionAPI, dependencies?: ExpertCouncilExtensionDependencies): void;
|
|
7
|
+
//# sourceMappingURL=extension.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.d.ts","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,aAAa,EAInB,MAAM,sBAAsB,CAAC;AAE9B,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,iCAAiC,CAAC;AAgGpE,MAAM,WAAW,kCAAkC;IACjD,UAAU,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;CACtD;AAED,MAAM,CAAC,OAAO,UAAU,sBAAsB,CAC5C,EAAE,EAAE,YAAY,EAChB,YAAY,GAAE,kCAAuC,QAkStD"}
|
|
@@ -0,0 +1,372 @@
|
|
|
1
|
+
import { evaluateModelAssessment, MODEL_ASSESSMENT_JSON_SCHEMA, presentCouncilPlan, presentResourceInventory, resolveModelAssessment, } from "@expert-council/core";
|
|
2
|
+
import { createExpertCouncil } from "@expert-council/pi-runtime";
|
|
3
|
+
import { Type } from "typebox";
|
|
4
|
+
const councils = new Map();
|
|
5
|
+
function councilFor(cwd) {
|
|
6
|
+
const existing = councils.get(cwd);
|
|
7
|
+
if (existing)
|
|
8
|
+
return existing;
|
|
9
|
+
const created = createExpertCouncil({ cwd });
|
|
10
|
+
councils.set(cwd, created);
|
|
11
|
+
return created;
|
|
12
|
+
}
|
|
13
|
+
function output(value) {
|
|
14
|
+
return { content: [{ type: "text", text: JSON.stringify(value) }], details: undefined };
|
|
15
|
+
}
|
|
16
|
+
const Role = Type.Union([
|
|
17
|
+
Type.Literal("planner"),
|
|
18
|
+
Type.Literal("scout"),
|
|
19
|
+
Type.Literal("architecture-oracle"),
|
|
20
|
+
Type.Literal("implementation-worker"),
|
|
21
|
+
Type.Literal("debugger"),
|
|
22
|
+
Type.Literal("reviewer"),
|
|
23
|
+
Type.Literal("verifier"),
|
|
24
|
+
]);
|
|
25
|
+
const Failure = Type.Union([
|
|
26
|
+
Type.Literal("tool_call_error"),
|
|
27
|
+
Type.Literal("reasoning_failure"),
|
|
28
|
+
Type.Literal("test_failure"),
|
|
29
|
+
Type.Literal("timeout"),
|
|
30
|
+
Type.Literal("provider_error"),
|
|
31
|
+
Type.Literal("missing_context"),
|
|
32
|
+
Type.Literal("permission_error"),
|
|
33
|
+
Type.Literal("unknown"),
|
|
34
|
+
]);
|
|
35
|
+
const Detail = Type.Optional(Type.Union([Type.Literal("compact"), Type.Literal("full")]));
|
|
36
|
+
const CostPolicySchema = Type.Union([
|
|
37
|
+
Type.Literal("economy"),
|
|
38
|
+
Type.Literal("balanced"),
|
|
39
|
+
Type.Literal("speed"),
|
|
40
|
+
Type.Literal("quality"),
|
|
41
|
+
]);
|
|
42
|
+
const ModelAssessment = Type.Unsafe(MODEL_ASSESSMENT_JSON_SCHEMA);
|
|
43
|
+
const TaskText = Type.String({ minLength: 1, maxLength: 100_000, pattern: "^[^\\x00]+$" });
|
|
44
|
+
const WorkspacePath = Type.String({ minLength: 1, maxLength: 32_768, pattern: "^[^\\x00]+$" });
|
|
45
|
+
const ExecutionIdentifier = Type.String({ minLength: 1, maxLength: 200, pattern: "^[a-zA-Z0-9_-]+$" });
|
|
46
|
+
const ASSEMBLY_PREFERENCE_ENTRY = "expert-council-assembly-preference";
|
|
47
|
+
function parseStringifiedAssignments(value) {
|
|
48
|
+
if (typeof value !== "string" || value.length > 1_000_000)
|
|
49
|
+
return value;
|
|
50
|
+
try {
|
|
51
|
+
return JSON.parse(value);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
return value;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function omitEmptyModelAssessment(args) {
|
|
58
|
+
if (!args || typeof args !== "object" || Array.isArray(args))
|
|
59
|
+
return args;
|
|
60
|
+
const candidate = args;
|
|
61
|
+
const assessment = candidate.modelAssessment;
|
|
62
|
+
if (!assessment || typeof assessment !== "object" || Array.isArray(assessment))
|
|
63
|
+
return args;
|
|
64
|
+
const models = assessment.models;
|
|
65
|
+
if (!models || typeof models !== "object" || Array.isArray(models) || Object.keys(models).length > 0)
|
|
66
|
+
return args;
|
|
67
|
+
const { modelAssessment: _ignored, ...rest } = candidate;
|
|
68
|
+
return rest;
|
|
69
|
+
}
|
|
70
|
+
function sessionAssemblyPreference(ctx) {
|
|
71
|
+
const entries = ctx.sessionManager?.getBranch?.() ?? [];
|
|
72
|
+
for (let index = entries.length - 1; index >= 0; index -= 1) {
|
|
73
|
+
const entry = entries[index];
|
|
74
|
+
if (entry.type !== "custom" || entry.customType !== ASSEMBLY_PREFERENCE_ENTRY)
|
|
75
|
+
continue;
|
|
76
|
+
const policy = entry.data?.costPolicy;
|
|
77
|
+
if (["economy", "balanced", "speed", "quality"].includes(String(policy)))
|
|
78
|
+
return policy;
|
|
79
|
+
}
|
|
80
|
+
return undefined;
|
|
81
|
+
}
|
|
82
|
+
const DelegationAssignment = Type.Object({
|
|
83
|
+
role: Role,
|
|
84
|
+
task: TaskText,
|
|
85
|
+
taskDescription: Type.Optional(Type.String({
|
|
86
|
+
minLength: 1,
|
|
87
|
+
maxLength: 500,
|
|
88
|
+
description: "Optional concise host-facing label included in the completion notification.",
|
|
89
|
+
})),
|
|
90
|
+
councilId: Type.Optional(ExecutionIdentifier),
|
|
91
|
+
workspace: Type.Optional(WorkspacePath),
|
|
92
|
+
timeoutMs: Type.Optional(Type.Integer({ minimum: 1000, maximum: 3600000 })),
|
|
93
|
+
});
|
|
94
|
+
export default function expertCouncilExtension(pi, dependencies = {}) {
|
|
95
|
+
const getCouncil = dependencies.councilFor ?? councilFor;
|
|
96
|
+
pi.registerTool({
|
|
97
|
+
name: "expert_inspect",
|
|
98
|
+
label: "Expert Inspect",
|
|
99
|
+
description: "Inspect a compact summary of callable Pi resources. Request full detail only when exact model metadata is required.",
|
|
100
|
+
parameters: Type.Object({ detail: Detail }),
|
|
101
|
+
async execute(_id, params, signal, _update, ctx) {
|
|
102
|
+
signal?.throwIfAborted();
|
|
103
|
+
const inventory = await (await getCouncil(ctx.cwd)).inspectResources();
|
|
104
|
+
return output(presentResourceInventory(inventory, params.detail));
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
pi.registerTool({
|
|
108
|
+
name: "expert_build",
|
|
109
|
+
label: "Expert Build",
|
|
110
|
+
description: "Build a small deterministic expert council. A current complete model assessment is mandatory; the first council in a Pi conversation also requires a user-selected economy, balanced, or speed preference.",
|
|
111
|
+
promptGuidelines: [
|
|
112
|
+
"Before the first council in a conversation, ask the user once to choose economy (lowest effective cost), balanced (cost/time/success), or speed (fastest completion), unless their request already states the choice. Never choose that first preference silently.",
|
|
113
|
+
"After the first council, omit costPolicy to reuse the session preference. Supply it again only when the user explicitly changes preference.",
|
|
114
|
+
"When the model-assessment gate reports missing, stale, or inventory-changed, do not build or delegate. Use an already available web/research tool for researchModels only, preserve saved scores for other requiredModels entries, then retry once with a complete dated, sourced modelAssessment. Never install a web tool or third-party package automatically.",
|
|
115
|
+
"Use the actual host clock for modelAssessment.asOf and 1 to 12 consolidated source URLs. If the gate reports future-dated, keep the existing evidence and scores, correct only the timestamp, and do not browse again.",
|
|
116
|
+
"When expert_inspect reports modelAssessment.status='current', omit modelAssessment from expert_build and reuse the saved snapshot. Never send an empty or reconstructed assessment.",
|
|
117
|
+
],
|
|
118
|
+
parameters: Type.Object({
|
|
119
|
+
task: TaskText,
|
|
120
|
+
maxExperts: Type.Optional(Type.Integer({ minimum: 1, maximum: 8 })),
|
|
121
|
+
costPolicy: Type.Optional(CostPolicySchema),
|
|
122
|
+
minimumContextWindow: Type.Optional(Type.Integer({ minimum: 1 })),
|
|
123
|
+
modelAssessment: Type.Optional(ModelAssessment),
|
|
124
|
+
detail: Detail,
|
|
125
|
+
}),
|
|
126
|
+
prepareArguments(args) {
|
|
127
|
+
return omitEmptyModelAssessment(args);
|
|
128
|
+
},
|
|
129
|
+
async execute(_id, params, signal, _update, ctx) {
|
|
130
|
+
signal?.throwIfAborted();
|
|
131
|
+
const previousPreference = sessionAssemblyPreference(ctx);
|
|
132
|
+
const requestedPreference = params.costPolicy;
|
|
133
|
+
if (!previousPreference && !requestedPreference) {
|
|
134
|
+
return output({
|
|
135
|
+
status: "preference-required",
|
|
136
|
+
question: "这是本对话第一次组建专家委员会。请选择组建方式:价格优先、综合价格/时间/成功率,或速度优先。",
|
|
137
|
+
choices: [
|
|
138
|
+
{ costPolicy: "economy", label: "价格优先", description: "优先最低有效边际成本。" },
|
|
139
|
+
{ costPolicy: "balanced", label: "综合平衡", description: "平衡价格、完成时间与成功率。" },
|
|
140
|
+
{ costPolicy: "speed", label: "速度优先", description: "优先最快完成。" },
|
|
141
|
+
],
|
|
142
|
+
});
|
|
143
|
+
}
|
|
144
|
+
const costPolicy = requestedPreference ?? previousPreference;
|
|
145
|
+
if (requestedPreference && requestedPreference !== previousPreference) {
|
|
146
|
+
pi.appendEntry(ASSEMBLY_PREFERENCE_ENTRY, { costPolicy: requestedPreference, recordedAt: new Date().toISOString() });
|
|
147
|
+
}
|
|
148
|
+
const council = await getCouncil(ctx.cwd);
|
|
149
|
+
const inventory = await council.inspectResources();
|
|
150
|
+
const assessment = resolveModelAssessment(inventory.models, inventory.modelAssessment, params.modelAssessment);
|
|
151
|
+
if (assessment.status.status === "required") {
|
|
152
|
+
return output({
|
|
153
|
+
...assessment.status,
|
|
154
|
+
assessmentStatus: assessment.status.status,
|
|
155
|
+
status: "model-assessment-required",
|
|
156
|
+
providerBilling: inventory.billing,
|
|
157
|
+
billingSources: inventory.billingSources,
|
|
158
|
+
warning: "expert_build did not assemble a council. Complete the required web audit, then retry once with modelAssessment.",
|
|
159
|
+
});
|
|
160
|
+
}
|
|
161
|
+
const plan = await council.buildCouncil({
|
|
162
|
+
task: params.task,
|
|
163
|
+
...(assessment.source === "submitted" && assessment.assessment
|
|
164
|
+
? { modelAssessment: assessment.assessment }
|
|
165
|
+
: {}),
|
|
166
|
+
...(params.maxExperts !== undefined || params.costPolicy !== undefined || params.minimumContextWindow !== undefined ? {
|
|
167
|
+
constraints: {
|
|
168
|
+
...(params.maxExperts ? { maxExperts: params.maxExperts } : {}),
|
|
169
|
+
costPolicy,
|
|
170
|
+
...(params.minimumContextWindow ? { minimumContextWindow: params.minimumContextWindow } : {}),
|
|
171
|
+
},
|
|
172
|
+
} : { constraints: { costPolicy } }),
|
|
173
|
+
});
|
|
174
|
+
return output({
|
|
175
|
+
...presentCouncilPlan({
|
|
176
|
+
...plan,
|
|
177
|
+
warnings: [
|
|
178
|
+
...plan.warnings,
|
|
179
|
+
...(assessment.ignoredSubmittedAssessment
|
|
180
|
+
? ["Ignored an incomplete, stale, or future-dated submitted modelAssessment and reused the current saved assessment."]
|
|
181
|
+
: []),
|
|
182
|
+
],
|
|
183
|
+
}, params.detail),
|
|
184
|
+
assemblyPreference: {
|
|
185
|
+
costPolicy,
|
|
186
|
+
source: requestedPreference ? "user-selected" : "reused-from-session",
|
|
187
|
+
},
|
|
188
|
+
});
|
|
189
|
+
},
|
|
190
|
+
});
|
|
191
|
+
pi.registerTool({
|
|
192
|
+
name: "expert_delegate",
|
|
193
|
+
label: "Expert Delegate",
|
|
194
|
+
description: "Start one or up to eight bounded semantic expert assignments in the background and immediately return execution IDs.",
|
|
195
|
+
promptGuidelines: [
|
|
196
|
+
"Dispatch every independent assignment selected for the current batch before ending the turn; prefer the assignments array when two or more tasks are ready.",
|
|
197
|
+
"Pass assignments as a real JSON array, never as a quoted or stringified JSON value.",
|
|
198
|
+
"After expert_delegate reports that a task has completed, call expert_result with its executionId before using the feedback.",
|
|
199
|
+
"After verifying the completed result, call expert_feedback with the same executionId and verification outcome so local routing can learn.",
|
|
200
|
+
"Native Pi completion notifications wake the Main Agent automatically; after dispatching background work, stop the turn instead of polling or silently waiting when no other useful work remains.",
|
|
201
|
+
],
|
|
202
|
+
parameters: Type.Object({
|
|
203
|
+
role: Type.Optional(Role),
|
|
204
|
+
task: Type.Optional(TaskText),
|
|
205
|
+
taskDescription: Type.Optional(Type.String({
|
|
206
|
+
minLength: 1,
|
|
207
|
+
maxLength: 500,
|
|
208
|
+
description: "Optional concise host-facing label included in the completion notification.",
|
|
209
|
+
})),
|
|
210
|
+
councilId: Type.Optional(ExecutionIdentifier),
|
|
211
|
+
workspace: Type.Optional(WorkspacePath),
|
|
212
|
+
timeoutMs: Type.Optional(Type.Integer({ minimum: 1000, maximum: 3600000 })),
|
|
213
|
+
assignments: Type.Optional(Type.Array(DelegationAssignment, { minItems: 1, maxItems: 8 })),
|
|
214
|
+
}, { additionalProperties: false }),
|
|
215
|
+
prepareArguments(args) {
|
|
216
|
+
if (!args || typeof args !== "object" || Array.isArray(args))
|
|
217
|
+
return args;
|
|
218
|
+
const candidate = args;
|
|
219
|
+
return { ...candidate, assignments: parseStringifiedAssignments(candidate.assignments) };
|
|
220
|
+
},
|
|
221
|
+
async execute(_id, params, signal, _update, ctx) {
|
|
222
|
+
signal?.throwIfAborted();
|
|
223
|
+
const council = await getCouncil(ctx.cwd);
|
|
224
|
+
const rawAssignments = parseStringifiedAssignments(params.assignments);
|
|
225
|
+
if (rawAssignments !== undefined && !Array.isArray(rawAssignments)) {
|
|
226
|
+
throw new Error("expert_delegate assignments must be a JSON array, not a string or object.");
|
|
227
|
+
}
|
|
228
|
+
const batch = Array.isArray(rawAssignments);
|
|
229
|
+
if (batch && (params.role !== undefined || params.task !== undefined)) {
|
|
230
|
+
throw new Error("expert_delegate accepts either assignments or a single role/task pair, not both.");
|
|
231
|
+
}
|
|
232
|
+
if (!batch && (!params.role || !params.task)) {
|
|
233
|
+
throw new Error("expert_delegate requires a non-empty assignments array or both role and task for one assignment.");
|
|
234
|
+
}
|
|
235
|
+
const inventory = await council.inspectResources();
|
|
236
|
+
const assessmentStatus = evaluateModelAssessment(inventory.models, inventory.modelAssessment);
|
|
237
|
+
if (assessmentStatus.status === "required") {
|
|
238
|
+
return output({
|
|
239
|
+
...assessmentStatus,
|
|
240
|
+
assessmentStatus: assessmentStatus.status,
|
|
241
|
+
status: "model-assessment-required",
|
|
242
|
+
providerBilling: inventory.billing,
|
|
243
|
+
billingSources: inventory.billingSources,
|
|
244
|
+
warning: "expert_delegate did not start any execution. Complete the required web audit through expert_build first.",
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
const requestedAssignments = batch ? rawAssignments : [{
|
|
248
|
+
role: params.role,
|
|
249
|
+
task: params.task,
|
|
250
|
+
...(params.taskDescription ? { taskDescription: params.taskDescription } : {}),
|
|
251
|
+
...(params.councilId ? { councilId: params.councilId } : {}),
|
|
252
|
+
...(params.workspace ? { workspace: params.workspace } : {}),
|
|
253
|
+
...(params.timeoutMs ? { timeoutMs: params.timeoutMs } : {}),
|
|
254
|
+
}];
|
|
255
|
+
const assignments = requestedAssignments.map((assignment) => ({
|
|
256
|
+
role: assignment.role,
|
|
257
|
+
task: assignment.task,
|
|
258
|
+
...(assignment.taskDescription ? { taskDescription: assignment.taskDescription } : {}),
|
|
259
|
+
...(assignment.councilId ? { councilId: assignment.councilId } : {}),
|
|
260
|
+
...(assignment.workspace ? { workspace: assignment.workspace } : {}),
|
|
261
|
+
...(assignment.timeoutMs ? { timeoutMs: assignment.timeoutMs } : {}),
|
|
262
|
+
}));
|
|
263
|
+
const receipts = assignments.map((assignment) => {
|
|
264
|
+
const handle = council.startDelegation(assignment);
|
|
265
|
+
void handle.result.then(() => {
|
|
266
|
+
try {
|
|
267
|
+
const delivery = ctx.isIdle() ? "followUp" : "steer";
|
|
268
|
+
const notification = {
|
|
269
|
+
executionId: handle.executionId,
|
|
270
|
+
...(assignment.taskDescription ? { taskDescription: assignment.taskDescription } : {}),
|
|
271
|
+
};
|
|
272
|
+
pi.sendMessage({
|
|
273
|
+
customType: "expert-council-completed",
|
|
274
|
+
content: JSON.stringify(notification),
|
|
275
|
+
display: true,
|
|
276
|
+
details: notification,
|
|
277
|
+
}, { deliverAs: delivery, triggerTurn: true });
|
|
278
|
+
}
|
|
279
|
+
catch {
|
|
280
|
+
// The originating Pi session may have been replaced or shut down.
|
|
281
|
+
// The result remains available through expert_result in the council service.
|
|
282
|
+
}
|
|
283
|
+
});
|
|
284
|
+
return {
|
|
285
|
+
executionId: handle.executionId,
|
|
286
|
+
role: assignment.role,
|
|
287
|
+
...(assignment.taskDescription ? { taskDescription: assignment.taskDescription } : {}),
|
|
288
|
+
status: "running",
|
|
289
|
+
};
|
|
290
|
+
});
|
|
291
|
+
return output(batch
|
|
292
|
+
? { status: "running", executions: receipts }
|
|
293
|
+
: { executionId: receipts[0].executionId, status: "running" });
|
|
294
|
+
},
|
|
295
|
+
});
|
|
296
|
+
pi.registerTool({
|
|
297
|
+
name: "expert_result",
|
|
298
|
+
label: "Expert Result",
|
|
299
|
+
description: "Retrieve completed expert feedback by execution ID, or report that the task is still running or unknown.",
|
|
300
|
+
parameters: Type.Object({
|
|
301
|
+
executionId: ExecutionIdentifier,
|
|
302
|
+
}),
|
|
303
|
+
async execute(_id, params, signal, _update, ctx) {
|
|
304
|
+
signal?.throwIfAborted();
|
|
305
|
+
return output(await (await getCouncil(ctx.cwd)).getResult(params.executionId));
|
|
306
|
+
},
|
|
307
|
+
});
|
|
308
|
+
pi.registerTool({
|
|
309
|
+
name: "expert_feedback",
|
|
310
|
+
label: "Expert Feedback",
|
|
311
|
+
description: "Record whether Main Agent verification accepted a completed expert result for local routing telemetry.",
|
|
312
|
+
parameters: Type.Object({
|
|
313
|
+
executionId: ExecutionIdentifier,
|
|
314
|
+
verificationPassed: Type.Boolean(),
|
|
315
|
+
}),
|
|
316
|
+
async execute(_id, params, signal, _update, ctx) {
|
|
317
|
+
signal?.throwIfAborted();
|
|
318
|
+
return output(await (await getCouncil(ctx.cwd)).recordFeedback(params));
|
|
319
|
+
},
|
|
320
|
+
});
|
|
321
|
+
pi.registerTool({
|
|
322
|
+
name: "expert_cleanup",
|
|
323
|
+
label: "Expert Cleanup",
|
|
324
|
+
description: "Remove every retry/escalation worktree for an execution after its result has been integrated or rejected.",
|
|
325
|
+
parameters: Type.Object({
|
|
326
|
+
executionId: ExecutionIdentifier,
|
|
327
|
+
}),
|
|
328
|
+
async execute(_id, params, signal, _update, ctx) {
|
|
329
|
+
signal?.throwIfAborted();
|
|
330
|
+
return output(await (await getCouncil(ctx.cwd)).cleanup(params.executionId));
|
|
331
|
+
},
|
|
332
|
+
});
|
|
333
|
+
pi.registerTool({
|
|
334
|
+
name: "expert_escalate",
|
|
335
|
+
label: "Expert Escalate",
|
|
336
|
+
description: "Choose a corrected retry, alternative model, or bounded stop from failure evidence.",
|
|
337
|
+
parameters: Type.Object({
|
|
338
|
+
role: Role,
|
|
339
|
+
task: TaskText,
|
|
340
|
+
currentModel: Type.String({ minLength: 3, maxLength: 500, pattern: "^[^\\x00]+$" }),
|
|
341
|
+
previousFailures: Type.Array(Type.Object({
|
|
342
|
+
model: Type.String({ minLength: 1, maxLength: 500, pattern: "^[^\\x00]+$" }),
|
|
343
|
+
type: Failure,
|
|
344
|
+
summary: Type.String({ minLength: 1, maxLength: 2000, pattern: "^[^\\x00]+$" }),
|
|
345
|
+
}), { minItems: 1, maxItems: 8 }),
|
|
346
|
+
}),
|
|
347
|
+
async execute(_id, params, signal, _update, ctx) {
|
|
348
|
+
signal?.throwIfAborted();
|
|
349
|
+
return output(await (await getCouncil(ctx.cwd)).escalate({
|
|
350
|
+
role: params.role,
|
|
351
|
+
task: params.task,
|
|
352
|
+
currentModel: params.currentModel,
|
|
353
|
+
previousFailures: params.previousFailures.map((failure) => ({
|
|
354
|
+
model: failure.model,
|
|
355
|
+
type: failure.type,
|
|
356
|
+
summary: failure.summary,
|
|
357
|
+
})),
|
|
358
|
+
}));
|
|
359
|
+
},
|
|
360
|
+
});
|
|
361
|
+
pi.registerTool({
|
|
362
|
+
name: "expert_status",
|
|
363
|
+
label: "Expert Status",
|
|
364
|
+
description: "Return compact council plans, execution states, and local aggregate outcomes.",
|
|
365
|
+
parameters: Type.Object({}),
|
|
366
|
+
async execute(_id, _params, signal, _update, ctx) {
|
|
367
|
+
signal?.throwIfAborted();
|
|
368
|
+
return output(await (await getCouncil(ctx.cwd)).getStatus());
|
|
369
|
+
},
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
//# sourceMappingURL=extension.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"extension.js","sourceRoot":"","sources":["../src/extension.ts"],"names":[],"mappings":"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"}
|
package/package.json
ADDED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@expert-council/pi-package",
|
|
3
|
+
"version": "0.4.0",
|
|
4
|
+
"description": "Native Pi package exposing Expert Council tools and host guidance",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/extension.js",
|
|
7
|
+
"types": "./dist/extension.d.ts",
|
|
8
|
+
"files": ["dist", "skills", "README.md", "LICENSE"],
|
|
9
|
+
"license": "MIT",
|
|
10
|
+
"repository": { "type": "git", "url": "git+https://github.com/Labiey/expert-council-router.git", "directory": "packages/pi-package" },
|
|
11
|
+
"homepage": "https://github.com/Labiey/expert-council-router#readme",
|
|
12
|
+
"bugs": { "url": "https://github.com/Labiey/expert-council-router/issues" },
|
|
13
|
+
"keywords": ["pi-package", "multi-model", "orchestration"],
|
|
14
|
+
"publishConfig": { "access": "public" },
|
|
15
|
+
"pi": {
|
|
16
|
+
"extensions": ["./dist/extension.js"],
|
|
17
|
+
"skills": ["./skills"]
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@expert-council/core": "0.4.0",
|
|
21
|
+
"@expert-council/pi-runtime": "0.4.0"
|
|
22
|
+
},
|
|
23
|
+
"peerDependencies": {
|
|
24
|
+
"@earendil-works/pi-coding-agent": ">=0.84.0 <1",
|
|
25
|
+
"typebox": "^1.3.7"
|
|
26
|
+
}
|
|
27
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: expert-council
|
|
3
|
+
description: Use a cost-aware Pi expert council for substantial bounded investigation, implementation, debugging, review, or verification when delegation is likely to save meaningful context, execution effort, or scarce-model quota. Do not use for trivial work.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Expert Council
|
|
7
|
+
|
|
8
|
+
Use Expert Council only when delegation is likely to save significant context, execution effort, or effective cost.
|
|
9
|
+
|
|
10
|
+
1. For a substantial host task, call `expert_inspect` before the first `expert_build`. Treat its `modelAssessment.status` as a protocol gate. Compact output includes the exact required model keys when an audit is required; request `detail: "full"` only for additional metadata.
|
|
11
|
+
2. Before building the first council in a new conversation, establish exactly one assembly preference. If the user has not already stated one, ask whether to optimize for `economy` (lowest effective marginal cost), `balanced` (cost, completion time, and success probability), or `speed` (fastest completion). Stop and wait for the answer. Reuse that choice for later councils in the same conversation; ask again only if the user changes it. The native Pi tool enforces this fallback and stores the choice in session state.
|
|
12
|
+
3. The Main Agent, not the user, assesses which models fit each role. If `modelAssessment.status` is `required`, do not call `expert_build` or `expert_delegate` yet. Use an already available network research tool to cross-check current evidence only for keys in `researchModels`. Preserve saved scores for the remaining `requiredModels` entries. If no network research tool is available, stop and tell the user that the mandatory audit cannot be completed; never silently fall back to unaudited defaults. Never install a browser, Skill, plugin, or executable package automatically.
|
|
13
|
+
4. For the mandatory audit, consider only models returned by `expert_inspect`. Prefer current primary or first-party evidence: Artificial Analysis for coding/agentic scores, price, throughput, and latency; LiveBench for coding and agentic coding; Arena for human preference; provider documentation for model/version/runtime and access-method facts. Treat OpenRouter usage rankings only as adoption evidence, not proof of quality. Triangulate into 1–12 consolidated source URLs, read the actual host clock for `asOf` (never synthesize a future timestamp), normalize only supported capability dimensions to 0–10, merge researched entries with saved entries to cover every `requiredModels` key, and include verified provider billing/access classifications when known; leave them `unknown` rather than guessing. Do not infer personal billing from published per-token prices. Pass the complete result as `modelAssessment` to `expert_build`. If the gate reports `future-dated`, retain the same evidence and scores, correct only `asOf`, and do not browse again. When `modelAssessment.status` is `current`, omit `modelAssessment` from `expert_build` so the saved snapshot is reused; do not send an empty or reconstructed table and do not browse again unless the user requests a re-audit.
|
|
14
|
+
5. Call `expert_build` only after the assessment gate is current, with the task and established cost policy. If the tool still returns `model-assessment-required`, follow its instructions and retry once after completing the audit; do not repeatedly call it unchanged. Let deterministic routing combine the Main Agent assessment, objective Pi metadata, billing policy when known, and locally observed reliability. Do not make the user rank individual models manually and do not assume a newer or more popular model is automatically best for every role.
|
|
15
|
+
6. Delegate bounded semantic assignments by role with `expert_delegate`. It starts background work and immediately returns execution IDs. Set an explicit finite `timeoutMs` for every assignment according to task difficulty instead of relying on the runtime fallback: normally 2–5 minutes for focused read-only work, 10–20 minutes for ordinary implementation/debugging, and at most 30–60 minutes for justified long-running work. When two or more independent assignments are ready, send them together in `assignments` as a real JSON array, never a quoted/stringified JSON value, so the entire batch is dispatched before the host turn ends. Add a short `taskDescription` when recognizing a task later would help.
|
|
16
|
+
7. After dispatching the complete batch, continue any independent Main Agent work. Follow the host-specific completion workflow appended by the distribution; do not poll repeatedly or spend model tokens on an idle loop.
|
|
17
|
+
8. When the host reports a completed `executionId`, call `expert_result` with that exact ID before using the feedback. Prefer read-only investigation before mutation, retain architecture and final acceptance in the Main Agent, and never create a redundant lead expert when the host Main Agent already owns that role.
|
|
18
|
+
9. Verify important results, then call `expert_feedback` so local routing can learn. Inspect isolated worktree changes before integration and call `expert_cleanup` after integrating or rejecting them. Do not delegate trivial work or allow recursive expert delegation.
|
|
19
|
+
10. Use `expert_escalate` only with structured failure evidence. Escalate scarce or expensive models only when corrected retry or economical alternatives are insufficient.
|
|
20
|
+
11. For any provided tool call that may block, use an explicit finite timeout chosen from task difficulty when its schema supports one. A host-level ceiling is only a safety envelope, not the operation's execution budget. Use a bounded operation or the safest available host limit when no per-call timeout exists.
|
|
21
|
+
|
|
22
|
+
Do not request private reasoning. Use summaries, changed files, tests, findings, risks, and recommended next actions.
|
|
23
|
+
|
|
24
|
+
## Native Pi completion behavior
|
|
25
|
+
|
|
26
|
+
After dispatching the complete batch and finishing independent work, end the current turn normally. Native Pi delivers a compact completion notification using `steer` while the Main Agent is working or `followUp` when it is idle, so do not poll or remain in a silent wait. Retrieve each reported execution with `expert_result`.
|
|
27
|
+
|
|
28
|
+
Choose `expert_delegate.timeoutMs` for every assignment from its expected difficulty. Give potentially blocking Pi shell operations their own finite, difficulty-based timeout whenever the tool supports one.
|