@bingjiang0611/rotom 0.1.24 → 0.1.26
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/THIRD_PARTY_NOTICES.md +2 -2
- package/extensions/observability/index.ts +20 -2
- package/extensions/qoder/messages.mjs +1 -1
- package/extensions/qoder/provider.mjs +14 -6
- package/extensions/qoder/transport.mjs +53 -11
- package/extensions/third-party/node_modules/.package-lock.json +6 -6
- package/extensions/third-party/node_modules/pi-subagents/README.md +17 -0
- package/extensions/third-party/node_modules/pi-subagents/agents/delegate.md +2 -0
- package/extensions/third-party/node_modules/pi-subagents/agents/oracle.md +18 -14
- package/extensions/third-party/node_modules/pi-subagents/agents/reviewer.md +5 -3
- package/extensions/third-party/node_modules/pi-subagents/docs/models.md +1 -1
- package/extensions/third-party/node_modules/pi-subagents/docs/tool-reference.md +2 -2
- package/extensions/third-party/node_modules/pi-subagents/docs/workflows.md +2 -2
- package/extensions/third-party/node_modules/pi-subagents/package.json +1 -1
- package/extensions/third-party/node_modules/pi-subagents/prompts/gather-context-and-clarify.md +1 -1
- package/extensions/third-party/node_modules/pi-subagents/prompts/parallel-research.md +4 -6
- package/extensions/third-party/node_modules/pi-subagents/skills/pi-subagents/references/constraints-and-recipes.md +8 -8
- package/extensions/third-party/node_modules/pi-subagents/skills/pi-subagents/references/execution-controls.md +5 -5
- package/extensions/third-party/node_modules/pi-subagents/skills/pi-subagents/references/prompting-and-roles.md +7 -8
- package/extensions/third-party/node_modules/pi-subagents/src/agents/agents.ts +0 -1
- package/extensions/third-party/node_modules/pi-subagents/src/extension/index.ts +9 -2
- package/extensions/third-party/node_modules/pi-subagents/src/profiles/profiles.ts +1 -2
- package/extensions/third-party/node_modules/pi-subagents/src/runs/background/async-execution.ts +81 -52
- package/extensions/third-party/node_modules/pi-subagents/src/runs/background/process-terminal.ts +13 -0
- package/extensions/third-party/node_modules/pi-subagents/src/runs/background/stale-run-reconciler.ts +7 -3
- package/extensions/third-party/node_modules/sol-pi/UPSTREAM.md +8 -3
- package/extensions/third-party/node_modules/sol-pi/package.json +1 -1
- package/extensions/third-party/node_modules/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/index.ts +6 -2
- package/extensions/third-party/node_modules/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/journal.ts +21 -0
- package/extensions/third-party/node_modules/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/provider.ts +7 -1
- package/extensions/third-party/node_modules/sol-pi/src/sol-pi/extensions/evidence-preserving-reducer/receipt.ts +79 -16
- package/extensions/third-party/package-lock.json +8 -8
- package/extensions/third-party/package.json +2 -2
- package/extensions/third-party/vendor/README.md +12 -11
- package/extensions/third-party/vendor/pi-subagents-0.52.1-rotom.10.tgz +0 -0
- package/extensions/third-party/vendor/sol-pi-0.1.0-rotom.2.tgz +0 -0
- package/package.json +10 -10
- package/runtime/pi/fork-build.json +24 -24
- package/runtime/pi/node_modules/.package-lock.json +29 -29
- package/runtime/pi/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.d.ts.map +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js +30 -7
- package/runtime/pi/node_modules/@earendil-works/pi-agent-core/dist/agent-loop.js.map +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
- package/runtime/pi/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.d.ts.map +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js +2 -1
- package/runtime/pi/node_modules/@earendil-works/pi-ai/dist/api/anthropic-messages.js.map +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-ai/dist/utils/error-body.d.ts +8 -0
- package/runtime/pi/node_modules/@earendil-works/pi-ai/dist/utils/error-body.d.ts.map +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-ai/dist/utils/error-body.js +37 -1
- package/runtime/pi/node_modules/@earendil-works/pi-ai/dist/utils/error-body.js.map +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts +6 -0
- package/runtime/pi/node_modules/@earendil-works/pi-ai/dist/utils/retry.d.ts.map +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-ai/dist/utils/retry.js +34 -0
- package/runtime/pi/node_modules/@earendil-works/pi-ai/dist/utils/retry.js.map +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-ai/package.json +3 -3
- package/runtime/pi/node_modules/@earendil-works/pi-codemode/package.json +2 -2
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/anthropic-messages-H6BRNJYC.js +6 -0
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{azure-openai-responses-KZZFKCXW.js → azure-openai-responses-45AJGMB6.js} +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/bedrock-converse-stream.js +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{chunk-2CKNKV2I.js → chunk-5MTGRVNE.js} +2 -2
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{chunk-ITZNWD4K.js → chunk-7OCND3IM.js} +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/chunk-CTEAMRDY.js +2 -0
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{chunk-3CD5ZAQX.js → chunk-ESL4WJJF.js} +11 -11
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{chunk-XQ3UQBJ2.js → chunk-MXCOAUPD.js} +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{cloudflare-workers-ai-system-one-UTBL2KOF.js → cloudflare-workers-ai-system-one-IEPXKTM7.js} +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{execute-4WILIDZF.js → execute-ULZNGRYF.js} +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{google-generative-ai-KJOKBJM3.js → google-generative-ai-KXRSXWRQ.js} +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{google-vertex-VCLZ36OB.js → google-vertex-CVLJXJIO.js} +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{llama-cpp-classify-FYN623RH.js → llama-cpp-classify-42ZH3VVO.js} +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{openai-codex-responses-ZYGHVE5B.js → openai-codex-responses-L4P7LV62.js} +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{openai-completions-BGCEXFAB.js → openai-completions-ZIOWDPDJ.js} +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{openai-decisions-WVPMQ4JD.js → openai-decisions-L7N23NC7.js} +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{openai-responses-KCCCXI3B.js → openai-responses-XT6CQ4R7.js} +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{openrouter-images-DUPG5DZO.js → openrouter-images-FQ7HEE4T.js} +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{typesafe-system-one-ZSK3RN4B.js → typesafe-system-one-IH2QHGKL.js} +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{virtual-modules-C5BH2VI2.js → virtual-modules-YSF6BJRF.js} +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/cli-runtime.js +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/index.js +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/rpc-entry.js +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.d.ts +5 -0
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.d.ts.map +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js +60 -27
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js.map +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/loader.d.ts.map +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/loader.js +5 -0
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/loader.js.map +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.d.ts.map +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.js +1 -0
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/runner.js.map +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/types.d.ts +8 -0
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/types.d.ts.map +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/types.js.map +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/status-indicator.d.ts +1 -0
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/status-indicator.d.ts.map +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/status-indicator.js +4 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/status-indicator.js.map +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.d.ts.map +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.js +37 -4
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.js.map +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/docs/extensions.md +1 -0
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/docs/json.md +6 -0
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/docs/rpc-extension-ui.md +2 -0
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/docs/settings.md +3 -1
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/package.json +7 -7
- package/runtime/pi/node_modules/@earendil-works/pi-mcp/package.json +2 -2
- package/runtime/pi/node_modules/@earendil-works/pi-telemetry/package.json +2 -2
- package/runtime/pi/node_modules/@earendil-works/pi-tui/package.json +2 -2
- package/runtime/pi/package-lock.json +37 -37
- package/runtime/pi/package.json +15 -15
- package/runtime/pi/vendor/earendil-works-pi-agent-core-1.3.0-rotom.2.tgz +0 -0
- package/runtime/pi/vendor/earendil-works-pi-ai-1.3.0-rotom.2.tgz +0 -0
- package/runtime/pi/vendor/earendil-works-pi-codemode-1.3.0-rotom.2.tgz +0 -0
- package/runtime/pi/vendor/{earendil-works-pi-coding-agent-1.3.0-rotom.1.tgz → earendil-works-pi-coding-agent-1.3.0-rotom.2.tgz} +0 -0
- package/runtime/pi/vendor/earendil-works-pi-mcp-1.3.0-rotom.2.tgz +0 -0
- package/runtime/pi/vendor/earendil-works-pi-telemetry-1.3.0-rotom.2.tgz +0 -0
- package/runtime/pi/vendor/earendil-works-pi-tui-1.3.0-rotom.2.tgz +0 -0
- package/runtime/product-config.mjs +5 -5
- package/extensions/third-party/node_modules/pi-subagents/agents/researcher.md +0 -52
- package/extensions/third-party/node_modules/pi-subagents/docs/agents.md +0 -383
- package/extensions/third-party/vendor/pi-subagents-0.52.1-rotom.7.tgz +0 -0
- package/extensions/third-party/vendor/sol-pi-0.1.0-rotom.0.tgz +0 -0
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/anthropic-messages-UIH6DSZT.js +0 -6
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/chunk-TEPMHNKQ.js +0 -2
- package/runtime/pi/vendor/earendil-works-pi-agent-core-1.3.0-rotom.1.tgz +0 -0
- package/runtime/pi/vendor/earendil-works-pi-ai-1.3.0-rotom.1.tgz +0 -0
- package/runtime/pi/vendor/earendil-works-pi-codemode-1.3.0-rotom.1.tgz +0 -0
- package/runtime/pi/vendor/earendil-works-pi-mcp-1.3.0-rotom.1.tgz +0 -0
- package/runtime/pi/vendor/earendil-works-pi-telemetry-1.3.0-rotom.1.tgz +0 -0
- package/runtime/pi/vendor/earendil-works-pi-tui-1.3.0-rotom.1.tgz +0 -0
package/THIRD_PARTY_NOTICES.md
CHANGED
|
@@ -6,13 +6,13 @@ rotom 的根产品许可证尚未确定(当前 `UNLICENSED`);此状态不
|
|
|
6
6
|
|
|
7
7
|
| Package | Version | Declared license | Distribution |
|
|
8
8
|
|---|---|---|---|
|
|
9
|
-
| `@earendil-works/pi-coding-agent`, `pi-agent-core`, `pi-ai`, `pi-tui`, `pi-telemetry`, `pi-codemode`, `pi-mcp` (all under `@earendil-works`) | `1.3.0-rotom.
|
|
9
|
+
| `@earendil-works/pi-coding-agent`, `pi-agent-core`, `pi-ai`, `pi-tui`, `pi-telemetry`, `pi-codemode`, `pi-mcp` (all under `@earendil-works`) | `1.3.0-rotom.2` | MIT | In-repository Pi fork (`packages/rotom-pi/`), built into integrity-pinned archives and installed under `runtime/pi/node_modules/` |
|
|
10
10
|
| `@injaneity/pi-computer-use` | `0.5.1-rotom.0` | MIT | Independently maintained fork (`packages/rotom-computer-use/`), included from its integrity-pinned vendor archive |
|
|
11
11
|
| `@juicesharp/rpiv-ask-user-question` | `2.6.2` | MIT | Included under `extensions/third-party/node_modules/` |
|
|
12
12
|
| `@narumitw/pi-goal` | `0.54.4-rotom.8` | MIT | Independently maintained fork (`packages/rotom-goal/`), included from its integrity-pinned vendor archive |
|
|
13
13
|
| `pi-context-view` | `0.7.1` | MIT | Included unmodified under `extensions/third-party/node_modules/` |
|
|
14
14
|
| `pi-subagents` | `0.52.1-rotom.7` | MIT | Independently maintained Subagent source, included from its integrity-pinned vendor archive |
|
|
15
|
-
| `sol-pi` (SoL-Pi, Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES) | `0.1.0-rotom.
|
|
15
|
+
| `sol-pi` (SoL-Pi, Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES) | `0.1.0-rotom.2` | MIT | Maintained import (`packages/rotom-sol-pi/`), included from its integrity-pinned vendor archive |
|
|
16
16
|
|
|
17
17
|
Each included extension retains its original `LICENSE` and package metadata; transitive dependency notices remain in their installed package directories. The modified Subagent, Computer Use, Goal and SoL-Pi archives' origin and scope are documented in `extensions/third-party/vendor/README.md` and each fork's `package/UPSTREAM.md`. Shipping the complete dependency does not enable its unselected tools, templates, or skills.
|
|
18
18
|
|
|
@@ -20,7 +20,10 @@ const QODER_TRACE_ERROR_MESSAGES = new Map([
|
|
|
20
20
|
["Qoder: upstream_error_event", "upstream_error_event"],
|
|
21
21
|
["Qoder: upstream_error_frame", "upstream_error_frame"],
|
|
22
22
|
["Qoder: request_failed", "transport_failure"],
|
|
23
|
+
["Qoder: connection_failed", "transport_failure"],
|
|
23
24
|
["Qoder: stream_failed", "transport_failure"],
|
|
25
|
+
["Qoder: invalid_tool_id", "invalid_tool_id"],
|
|
26
|
+
["Qoder: model_refusal", "model_refusal"],
|
|
24
27
|
]);
|
|
25
28
|
|
|
26
29
|
const EXACT_VERSION = /^\d+\.\d+\.\d+(?:-[0-9A-Za-z.-]+)?$/u;
|
|
@@ -34,7 +37,7 @@ const PROVIDER_ERROR_CATEGORIES: ReadonlyArray<readonly [category: string, patte
|
|
|
34
37
|
["websocket", /^WebSocket (?:error|closed)\b/u],
|
|
35
38
|
["aborted", /^This operation was aborted$/u],
|
|
36
39
|
["overloaded", /overloaded/iu],
|
|
37
|
-
["network", /^(?:fetch failed|terminated|Connection error\.)
|
|
40
|
+
["network", /^(?:fetch failed|terminated|Connection error\.)(?: \(caused by: .*\))?$|^Qoder: (?:request|stream|connection)_failed$|\b(?:ECONNRESET|ECONNREFUSED|ENOTFOUND|EAI_AGAIN)\b|socket hang up|^upstream connect error/u],
|
|
38
41
|
["auth", /^API key auth failed\b/u],
|
|
39
42
|
["provider_error", /^Codex error:|^\{"type":"error"|^Qoder: /u],
|
|
40
43
|
];
|
|
@@ -376,8 +379,23 @@ function assistantAttributes(message: any): TraceAttributes {
|
|
|
376
379
|
|
|
377
380
|
function qoderDiagnosticAttributes(value: unknown): TraceAttributes {
|
|
378
381
|
const diagnostic = record(value);
|
|
379
|
-
const allowedCodes = ["upstream_error_frame", "legacy_error", "transport_failure"];
|
|
382
|
+
const allowedCodes = ["upstream_error_frame", "legacy_error", "transport_failure", "invalid_tool_id"];
|
|
380
383
|
if (!diagnostic || !allowedCodes.includes(String(diagnostic.code))) return {};
|
|
384
|
+
if (diagnostic.code === "invalid_tool_id") {
|
|
385
|
+
// Event payloads are untrusted: persist only fixed categories and the
|
|
386
|
+
// parser's bounded wire index, never identities, arguments or prose.
|
|
387
|
+
return {
|
|
388
|
+
"pi.ai.qoder.diagnostic_code": "invalid_tool_id",
|
|
389
|
+
...(["non_string", "oversized", "changed"].includes(diagnostic.reason)
|
|
390
|
+
? { "pi.ai.qoder.tool_id_reason": diagnostic.reason } : {}),
|
|
391
|
+
...(diagnostic.reason === "changed" && ["extension", "fragment", "distinct"].includes(diagnostic.relation)
|
|
392
|
+
? { "pi.ai.qoder.tool_id_relation": diagnostic.relation } : {}),
|
|
393
|
+
...(diagnostic.reason === "changed" && typeof diagnostic.previousArgumentsComplete === "boolean"
|
|
394
|
+
? { "pi.ai.qoder.previous_arguments_complete": diagnostic.previousArgumentsComplete } : {}),
|
|
395
|
+
...(Number.isSafeInteger(diagnostic.wireIndex) && diagnostic.wireIndex >= 0 && diagnostic.wireIndex < 64
|
|
396
|
+
? { "pi.ai.qoder.tool_wire_index": diagnostic.wireIndex } : {}),
|
|
397
|
+
};
|
|
398
|
+
}
|
|
381
399
|
const status = Number.isSafeInteger(diagnostic.status) && (diagnostic.status as number) >= 0
|
|
382
400
|
? diagnostic.status as number
|
|
383
401
|
: undefined;
|
|
@@ -257,7 +257,7 @@ export function buildQoderPayload(model, context, { maxTokens, reasoningMode } =
|
|
|
257
257
|
messages: convertMessages(model, context),
|
|
258
258
|
stream: true,
|
|
259
259
|
stream_options: { include_usage: true },
|
|
260
|
-
max_tokens: maxTokens,
|
|
260
|
+
...(maxTokens !== undefined ? { max_tokens: maxTokens } : {}),
|
|
261
261
|
};
|
|
262
262
|
if (reasoningMode) payload.reasoning_effort = reasoningMode.effort;
|
|
263
263
|
const tools = context.tools ?? [];
|
|
@@ -19,8 +19,9 @@ export const MODEL = {
|
|
|
19
19
|
// "openai-completions" identity. Older sessions fail model_scope by design.
|
|
20
20
|
api: 'qoder', provider: PROVIDER_ID, baseUrl: BASE_URL,
|
|
21
21
|
reasoning: false, input: ['text'],
|
|
22
|
-
//
|
|
23
|
-
|
|
22
|
+
// Managed input window; zero means no declared output maximum in Pi.
|
|
23
|
+
// The service owns the default output budget, not a guessed adapter cap.
|
|
24
|
+
contextWindow: 32000, maxTokens: 0,
|
|
24
25
|
// Pi requires numeric prices. These placeholders are NOT zero-cost evidence.
|
|
25
26
|
cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 },
|
|
26
27
|
compat: { supportsStore: false, supportsDeveloperRole: false, supportsReasoningEffort: false, supportsStrictMode: false, maxTokensField: 'max_tokens' },
|
|
@@ -109,7 +110,7 @@ export async function createQoderProvider({ piAI, clampMaxTokens, getToken, getC
|
|
|
109
110
|
messages: transcript.messages.filter(message => message.role !== 'system'),
|
|
110
111
|
};
|
|
111
112
|
const reasoning = REASONING_MODEL_IDS.includes(model.id);
|
|
112
|
-
if (!SUPPORTED_MODEL_IDS.includes(model.id) || model.provider !== PROVIDER_ID || model.baseUrl !== BASE_URL || model.api !== MODEL.api || model.reasoning !== reasoning || !Number.isSafeInteger(model.contextWindow) || model.contextWindow < 4096 || model.contextWindow > (EXPANDED_INPUT_MODEL_IDS.includes(model.id) ? 272000 : 32000) || model.maxTokens
|
|
113
|
+
if (!SUPPORTED_MODEL_IDS.includes(model.id) || model.provider !== PROVIDER_ID || model.baseUrl !== BASE_URL || model.api !== MODEL.api || model.reasoning !== reasoning || !Number.isSafeInteger(model.contextWindow) || model.contextWindow < 4096 || model.contextWindow > (EXPANDED_INPUT_MODEL_IDS.includes(model.id) ? 272000 : 32000) || !Number.isSafeInteger(model.maxTokens) || model.maxTokens < 0) throw new QoderError('model_scope_rejected');
|
|
113
114
|
if (options.signal?.aborted) throw new QoderError('aborted');
|
|
114
115
|
// Refresh through the session's native registry before building any payload,
|
|
115
116
|
// including tool continuations and compaction. Never retry an inference.
|
|
@@ -173,8 +174,15 @@ export async function createQoderProvider({ piAI, clampMaxTokens, getToken, getC
|
|
|
173
174
|
// the agent lifecycle; only request encoding and response translation move
|
|
174
175
|
// in-house here.
|
|
175
176
|
const nativeModel = { ...model, contextWindow: input.contextWindow, input: input.images ? ['text', 'image'] : ['text'], ...(controls ? { thinkingLevelMap: thinkingMap(controls.levels), compat: { ...MODEL.compat, supportsReasoningEffort: true } } : {}) };
|
|
176
|
-
|
|
177
|
-
|
|
177
|
+
// Omit the default output limit, including for resumed models that still
|
|
178
|
+
// carry the former 4096 metadata. Explicit caller budgets (e.g. compaction)
|
|
179
|
+
// still use Pi's context headroom rather than an independent fixed ceiling.
|
|
180
|
+
let maxTokens;
|
|
181
|
+
if (options.maxTokens !== undefined) {
|
|
182
|
+
if (!Number.isSafeInteger(options.maxTokens) || options.maxTokens < 1) throw new QoderError('request_limits_rejected');
|
|
183
|
+
clampMaxTokens ??= await nativeOutputBudget();
|
|
184
|
+
maxTokens = clampMaxTokens(nativeModel, context, options.maxTokens);
|
|
185
|
+
}
|
|
178
186
|
let payload = buildQoderPayload(nativeModel, context, { maxTokens, reasoningMode });
|
|
179
187
|
// Preserve Pi's BeforeProviderRequest hook: an extension may rewrite the
|
|
180
188
|
// payload, but openQoderStream re-validates the result against the bound
|
|
@@ -186,7 +194,7 @@ export async function createQoderProvider({ piAI, clampMaxTokens, getToken, getC
|
|
|
186
194
|
// encoding and HTTP dispatch, then yields validated chunk records; a
|
|
187
195
|
// pre-stream failure rejects here and lazyStream turns it into an error
|
|
188
196
|
// event carrying the stable "Qoder: <code>" message the session-policy reads.
|
|
189
|
-
const { chunks } = await openQoderStream({ payload, getToken: requestToken, getLegacyCredential: () => requestCredential, legacyModel: entry, reasoningMode, fetchImpl, signal: options.signal, modelId: model.id, timeoutMs: reasoning ? 180000 : 60000, onDiagnostic, sessionId: options.sessionId, onMetering(data) {
|
|
197
|
+
const { chunks } = await openQoderStream({ payload, getToken: requestToken, getLegacyCredential: () => requestCredential, legacyModel: entry, reasoningMode, fetchImpl, signal: options.signal, modelId: model.id, timeoutMs: reasoning ? 180000 : 60000, onDiagnostic, sessionId: options.sessionId, onResponse: options.onResponse && (response => options.onResponse(response, model)), onMetering(data) {
|
|
190
198
|
for (const notify of [() => recordMetering?.({ ...data, fingerprint: requestCredential?.fingerprint }), () => onMetering?.(data)]) {
|
|
191
199
|
try { void Promise.resolve(notify()).catch(() => {}); } catch { /* Scoped metadata only; never retry a model request. */ }
|
|
192
200
|
}
|
|
@@ -35,9 +35,9 @@ export function inputCapabilities(entry) {
|
|
|
35
35
|
// so it is a managed budget, not the upstream limit. The maintainer aligned it
|
|
36
36
|
// with the Codex-declared 272000 to keep one compaction percentage across
|
|
37
37
|
// providers; the fixed 400K wire selector still is not an advertised capacity.
|
|
38
|
-
//
|
|
39
|
-
//
|
|
40
|
-
//
|
|
38
|
+
// Explicit output budgets retain Pi's native context headroom clamp. With
|
|
39
|
+
// no requested budget, the service decides output length; the managed input
|
|
40
|
+
// window and native compaction reserve remain unchanged.
|
|
41
41
|
return Object.freeze({ images: reviewed && entry.reportedImages === true, contextWindow: expanded ? 272000 : Math.min(32000, entry?.reportedContextWindow ?? 32000), contextLength: expanded ? 400000 : Math.min(32000, entry?.reportedContextWindow ?? 32000) });
|
|
42
42
|
}
|
|
43
43
|
// Only inline, canonical base64 in the three exercised codecs.
|
|
@@ -261,6 +261,9 @@ export async function* qoderChunks(body, { signal, toolNames = [], onDiagnostic,
|
|
|
261
261
|
if (chunk.choices.length > 1) fail('multiple_choices_unsupported');
|
|
262
262
|
const choices = chunk.choices.map(choice => {
|
|
263
263
|
if (choice.index !== undefined && choice.index !== 0) fail('invalid_choice_index');
|
|
264
|
+
// A refusal may omit delta and even precede later tool frames. Never
|
|
265
|
+
// reinterpret that explicit refusal as a malformed delta or execute tools.
|
|
266
|
+
if (choice.finish_reason === 'refusal') fail('model_refusal');
|
|
264
267
|
// Observed Sonus/Ultimate COSY frames use function_call with modern
|
|
265
268
|
// tool_calls deltas. Still require complete tools and validated EOF;
|
|
266
269
|
// never reinterpret the direct HTTP route or legacy function_call deltas.
|
|
@@ -297,11 +300,12 @@ export async function* qoderChunks(body, { signal, toolNames = [], onDiagnostic,
|
|
|
297
300
|
let index = wireIndexes.get(wireIndex);
|
|
298
301
|
if (index === undefined) { index = calls.has(wireIndex) ? freeIndex() : wireIndex; wireIndexes.set(wireIndex, index); }
|
|
299
302
|
let call = calls.get(index) ?? { id: '', name: '', arguments: '' };
|
|
300
|
-
// Observed Ultimate batches restart index 0 for each serial tool
|
|
303
|
+
// Observed Ultimate batches restart index 0 for each serial tool,
|
|
304
|
+
// including on the fixed COSY route after unwrapping its envelope.
|
|
301
305
|
// Rebase only a new full, unique identity after a complete prior call
|
|
302
306
|
// and with an explicit declared function name. Never concatenate IDs,
|
|
303
307
|
// alias a correction, or guess an interleaved/unfinished call's owner.
|
|
304
|
-
if (allowOpaqueReasoning && opaqueModelId === 'ultimate' &&
|
|
308
|
+
if (allowOpaqueReasoning && opaqueModelId === 'ultimate' && wireIndex === 0 && t.index === 0 && call.id && typeof t.id === 'string' && t.id && call.id !== t.id) {
|
|
305
309
|
let args; try { args = JSON.parse(call.arguments); } catch { /* Incomplete predecessor: reject the identity change below. */ }
|
|
306
310
|
if (record(args) && toolNames.includes(call.name) && toolNames.includes(t.function.name) && t.id.length <= 512 && !t.id.startsWith(call.id) && !call.id.startsWith(t.id) && ![...calls.values()].some(c => c.id === t.id)) {
|
|
307
311
|
index = freeIndex(); wireIndexes.set(wireIndex, index); call = { id: '', name: '', arguments: '' };
|
|
@@ -309,7 +313,23 @@ export async function* qoderChunks(body, { signal, toolNames = [], onDiagnostic,
|
|
|
309
313
|
}
|
|
310
314
|
const out = { index, type: 'function', function: {} };
|
|
311
315
|
if (t.id !== undefined && t.id !== '') {
|
|
312
|
-
if (typeof t.id !== 'string' || t.id.length > 512 || (call.id && call.id !== t.id))
|
|
316
|
+
if (typeof t.id !== 'string' || t.id.length > 512 || (call.id && call.id !== t.id)) {
|
|
317
|
+
let reason = 'changed';
|
|
318
|
+
if (typeof t.id !== 'string') reason = 'non_string';
|
|
319
|
+
else if (t.id.length > 512) reason = 'oversized';
|
|
320
|
+
const diagnostic = { code: 'invalid_tool_id', reason, wireIndex };
|
|
321
|
+
if (reason === 'changed') {
|
|
322
|
+
// Describe identity/argument structure only; never emit IDs or arguments.
|
|
323
|
+
diagnostic.relation = 'distinct';
|
|
324
|
+
if (t.id.startsWith(call.id)) diagnostic.relation = 'extension';
|
|
325
|
+
else if (call.id.startsWith(t.id) || call.id.endsWith(t.id)) diagnostic.relation = 'fragment';
|
|
326
|
+
let previousArguments;
|
|
327
|
+
try { previousArguments = JSON.parse(call.arguments); } catch { /* Partial JSON is not a complete tool argument object. */ }
|
|
328
|
+
diagnostic.previousArgumentsComplete = record(previousArguments);
|
|
329
|
+
}
|
|
330
|
+
try { void Promise.resolve(onDiagnostic?.(diagnostic)).catch(() => {}); } catch { /* Optional metadata must not replace the validation error. */ }
|
|
331
|
+
fail('invalid_tool_id');
|
|
332
|
+
}
|
|
313
333
|
call.id = out.id = t.id;
|
|
314
334
|
}
|
|
315
335
|
for (const field of ['name', 'arguments']) {
|
|
@@ -399,7 +419,22 @@ export async function* normalizeSSE(body, options) {
|
|
|
399
419
|
// stream-time failures. It never yields STREAM_DONE, so normal completion of
|
|
400
420
|
// `chunks` is itself proof of clean termination because qoderChunks fails
|
|
401
421
|
// closed on any incomplete or malformed stream ending.
|
|
402
|
-
|
|
422
|
+
// Same connect-phase rule as Pi's `connectFailureCause` (this module stays
|
|
423
|
+
// dependency-free): socket codes that only occur while connecting, or a proxy
|
|
424
|
+
// tunnel / TLS setup that failed before any request bytes were sent. undici
|
|
425
|
+
// nests these in `cause`, as an AggregateError for multi-address connects.
|
|
426
|
+
const UNSENT_CONNECT_ERROR_CODES = new Set(['ENOTFOUND', 'EAI_AGAIN', 'ECONNREFUSED', 'ENETUNREACH', 'ENETDOWN', 'EHOSTUNREACH', 'EADDRNOTAVAIL', 'UND_ERR_CONNECT_TIMEOUT']);
|
|
427
|
+
const UNSENT_CONNECT_ERROR_MESSAGE = /before secure TLS connection was established|when HTTP Tunneling/;
|
|
428
|
+
function neverSent(error) {
|
|
429
|
+
let current = error;
|
|
430
|
+
for (let depth = 0; depth < 5 && current instanceof Error; depth++) {
|
|
431
|
+
if (UNSENT_CONNECT_ERROR_CODES.has(current.code) || UNSENT_CONNECT_ERROR_MESSAGE.test(current.message)) return true;
|
|
432
|
+
current = current.cause ?? (current instanceof AggregateError ? current.errors[0] : undefined);
|
|
433
|
+
}
|
|
434
|
+
return false;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
export async function openQoderStream({ payload, getToken, getLegacyCredential, legacyModel, fetchImpl = globalThis.fetch, modelId = 'lite', sessionId = randomUUID(), timeoutMs = 60000, onDiagnostic, onMetering, onResponse, reasoningMode, signal } = {}) {
|
|
403
438
|
// Models.json, onPayload and SDK overrides must never redirect credentials.
|
|
404
439
|
const input = inputCapabilities(legacyModel?.id === modelId ? legacyModel : undefined);
|
|
405
440
|
if (signal?.aborted) fail('aborted');
|
|
@@ -450,9 +485,8 @@ export async function openQoderStream({ payload, getToken, getLegacyCredential,
|
|
|
450
485
|
payload.reasoning_effort = 'none';
|
|
451
486
|
}
|
|
452
487
|
if (payload.tools !== undefined && (!Array.isArray(payload.tools) || payload.tools.some(t => !record(t) || t.type !== 'function' || !record(t.function) || typeof t.function.name !== 'string'))) fail('request_scope_rejected');
|
|
453
|
-
const maxTokens = payload.max_tokens
|
|
454
|
-
if (!Number.isSafeInteger(maxTokens) || maxTokens < 1
|
|
455
|
-
payload.max_tokens = maxTokens;
|
|
488
|
+
const maxTokens = payload.max_tokens;
|
|
489
|
+
if (maxTokens !== undefined && (!Number.isSafeInteger(maxTokens) || maxTokens < 1)) fail('request_limits_rejected');
|
|
456
490
|
const requestId = randomUUID();
|
|
457
491
|
payload.metadata = { context: { request_id: requestId, request_set_id: requestId, session_id: sessionId, task_id: 'common', client_type: 'rotom' } };
|
|
458
492
|
const legacy = LEGACY_MODEL_IDS.includes(modelId);
|
|
@@ -491,6 +525,9 @@ export async function openQoderStream({ payload, getToken, getLegacyCredential,
|
|
|
491
525
|
if (controller.signal.aborted) { void result.body?.cancel().catch(() => {}); fail('aborted'); }
|
|
492
526
|
return result;
|
|
493
527
|
}, controller.signal);
|
|
528
|
+
// Response-header timing for observability (status only matters there); the
|
|
529
|
+
// body is untouched, so this cannot alter the stream.
|
|
530
|
+
await onResponse?.({ status: response.status, headers: Object.fromEntries(response.headers) });
|
|
494
531
|
if (!response.ok) {
|
|
495
532
|
void response.body?.cancel().catch(() => {});
|
|
496
533
|
fail(`http_${response.status}`);
|
|
@@ -502,7 +539,12 @@ export async function openQoderStream({ payload, getToken, getLegacyCredential,
|
|
|
502
539
|
if (!controller.signal.aborted) {
|
|
503
540
|
try { void Promise.resolve(onDiagnostic?.({ code: 'transport_failure', phase: 'request' })).catch(() => {}); } catch { /* Allowlisted metadata only. */ }
|
|
504
541
|
}
|
|
505
|
-
|
|
542
|
+
// Only failures that prove the request never left this machine (offline,
|
|
543
|
+
// DNS, refused/unroutable connect) become connection_failed, which Pi waits
|
|
544
|
+
// out without a retry limit. A reset after the body was sent may already be
|
|
545
|
+
// billed upstream, so it stays the generic, non-retried request_failed.
|
|
546
|
+
const unreachable = dispatchStarted && neverSent(error);
|
|
547
|
+
throw new QoderError(controller.signal.aborted ? 'aborted' : unreachable ? 'connection_failed' : 'request_failed');
|
|
506
548
|
}
|
|
507
549
|
const frames = qoderChunks(response.body, { signal: controller.signal, onDiagnostic, onCreditUsage: usage => meter.observe(usage), allowReasoning: allowReasoning && reasoningMode?.enabled !== false, allowOpaqueReasoning: OPAQUE_MODEL_IDS.includes(modelId), opaqueModelId: modelId, allowLegacyEnvelope: legacy, allowLegacyMetricsDone: ['mmodel', 'smodel', 'ultimate'].includes(modelId), toolNames: (payload.tools ?? []).map(t => t.function?.name) });
|
|
508
550
|
async function* chunks() {
|
|
@@ -131,9 +131,9 @@
|
|
|
131
131
|
}
|
|
132
132
|
},
|
|
133
133
|
"node_modules/pi-subagents": {
|
|
134
|
-
"version": "0.52.1-rotom.
|
|
135
|
-
"resolved": "file:vendor/pi-subagents-0.52.1-rotom.
|
|
136
|
-
"integrity": "sha512-
|
|
134
|
+
"version": "0.52.1-rotom.10",
|
|
135
|
+
"resolved": "file:vendor/pi-subagents-0.52.1-rotom.10.tgz",
|
|
136
|
+
"integrity": "sha512-5mXSC3zXponiWE+NP16rJ4zo1j1mHS04bbFO+fOc31RVVHA8rKvZ3nvemDOHT9qCBqINAiRcXJuhpZCNNNeoHg==",
|
|
137
137
|
"license": "MIT",
|
|
138
138
|
"dependencies": {
|
|
139
139
|
"acorn": "8.18.0",
|
|
@@ -166,9 +166,9 @@
|
|
|
166
166
|
}
|
|
167
167
|
},
|
|
168
168
|
"node_modules/sol-pi": {
|
|
169
|
-
"version": "0.1.0-rotom.
|
|
170
|
-
"resolved": "file:vendor/sol-pi-0.1.0-rotom.
|
|
171
|
-
"integrity": "sha512-
|
|
169
|
+
"version": "0.1.0-rotom.2",
|
|
170
|
+
"resolved": "file:vendor/sol-pi-0.1.0-rotom.2.tgz",
|
|
171
|
+
"integrity": "sha512-9SOaxYtxnfbnU+IByPpz8dmk95eDsGs4dvi1sq9i2g3VrGxIok0sGatlhPLhiOUgETWZyRBtRHULCm+yZiOu2g==",
|
|
172
172
|
"license": "MIT",
|
|
173
173
|
"engines": {
|
|
174
174
|
"node": ">=22.19.0"
|
|
@@ -38,6 +38,23 @@ macOS 的 mount device ID 可能在重启后重新编号。store 现在只在 Da
|
|
|
38
38
|
|
|
39
39
|
在 `.4` 的精简基础上,终态投影出错时保留已观察到的受控进程关闭证据与错误说明,将结果明确标记为 unknown,而不是推断任务成功或授权重放。本版重新归档当前源码,使后续终态修复实际进入产品;不覆盖旧 `.4` 归档,不迁移存活安装。它属于后续开发,不包含在已冻结的 rotom `0.1.17` 安装包中。
|
|
40
40
|
|
|
41
|
+
## `0.52.1-rotom.9`:父运行时退出前等待关闭证明
|
|
42
|
+
|
|
43
|
+
正常退出、reload、new/resume 或 SDK dispose 时,先暂停当前扩展运行时实际启动的异步 runner,等待真实 `close` 回调完成终态证据处理,再清理运行时。只保留当前进程中的 ChildProcess 对象,不按历史 PID 补发信号;其他运行时的任务不受影响。回收开始后拒绝新 writer,正常关闭后可由新运行时恢复原 canonical session。后台任务不再跨越其所属运行时的销毁继续执行。任务结果先于 close 回调到达时,仅在本进程仍持有该 run/runner 实例的真实观察者期间保留 pending;不会提前将其改成 observer-unavailable,也不会把观察者登记当成关闭证明。
|
|
44
|
+
|
|
45
|
+
强杀、异常 owner loss、缺失/写入失败的证据仍是 unknown,不从候选记录或 PID 消失推断历史退出;不补写旧任务的成功证明、不自动恢复旧任务。源码版本不会热更新当前安装。验证、首次失败与剩余限制见[父运行时关闭修复](../../docs/agent/subagent-parent-shutdown.md)。
|
|
46
|
+
|
|
47
|
+
## `0.52.1-rotom.10`:内置角色可在 owned scope 启动
|
|
48
|
+
|
|
49
|
+
会话复盘发现 `delegate` 在 owned scope 下 6/6 启动失败、`researcher` 1/1 失败,原因都是缺少显式 `extensions`。本版调整内置角色:
|
|
50
|
+
|
|
51
|
+
- `delegate` 声明空 `extensions` 与 `defaultContext: fresh`,工具白名单不变。
|
|
52
|
+
- `oracle`(别名 `advisor`)改为 `defaultContext: fresh`、空 `extensions`,任务由父会话写成决策简报(目标/验收、已定决策、约束、方案、相关文件、具体问题);仍只读,不再依赖 fork。
|
|
53
|
+
- `reviewer` 增加 `bash`,提示词限定只读检查(diff/log/rg、运行现有测试与类型检查),禁止写文件、Git 写操作、安装和网络;这是提示约束,不是沙箱。
|
|
54
|
+
- 删除 `researcher`:它依赖的 `web_search`/`fetch_content` 在 rotom 中不存在。需要网页检索时由父会话自行完成,或配置显式声明 web 工具与 `extensions` 的自定义 agent。
|
|
55
|
+
|
|
56
|
+
自定义 agent、显式 fork 请求与 admission 拒绝规则不变。
|
|
57
|
+
|
|
41
58
|
## 开发
|
|
42
59
|
|
|
43
60
|
在本目录运行;依赖是固定版本及本目录 lockfile,勿复制维护者 node_modules:
|
|
@@ -4,6 +4,8 @@ description: Lightweight subagent that inherits the parent model with no default
|
|
|
4
4
|
systemPromptMode: append
|
|
5
5
|
inheritProjectContext: true
|
|
6
6
|
tools: read, grep, find, ls, bash, edit, write, contact_supervisor
|
|
7
|
+
extensions:
|
|
8
|
+
defaultContext: fresh
|
|
7
9
|
inheritSkills: false
|
|
8
10
|
---
|
|
9
11
|
|
|
@@ -1,41 +1,44 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: oracle
|
|
3
3
|
aliases: advisor
|
|
4
|
-
description:
|
|
4
|
+
description: Read-only decision-consistency oracle; checks a parent-written decision brief against the code and prevents drift
|
|
5
5
|
tools: read, grep, find, ls, bash
|
|
6
|
+
extensions:
|
|
6
7
|
thinking: high
|
|
7
8
|
systemPromptMode: replace
|
|
8
9
|
inheritProjectContext: true
|
|
9
10
|
inheritSkills: false
|
|
10
|
-
defaultContext:
|
|
11
|
+
defaultContext: fresh
|
|
11
12
|
---
|
|
12
13
|
|
|
13
|
-
You are the oracle: a
|
|
14
|
+
You are the oracle: a read-only decision-consistency subagent.
|
|
14
15
|
|
|
15
|
-
Your primary job is to prevent the main agent from making hidden, conflicting, or inconsistent decisions
|
|
16
|
+
Your primary job is to prevent the main agent from making hidden, conflicting, or inconsistent decisions. You start with a fresh context: you do not see the parent conversation. The task is a decision brief written by the main agent, and it is your authoritative contract together with the code. You are not the primary executor. You do not silently become a second decision-maker.
|
|
16
17
|
|
|
17
|
-
Before you do anything else,
|
|
18
|
+
A useful brief contains: the goal and acceptance criteria, decisions already made and why, hard constraints, the current plan or proposed move, the files or documents that matter, and the specific question. Before you do anything else, restate the decisions, constraints, and open questions from the brief and verify the claims that matter against the named files and the codebase. Those decisions form your baseline contract. Preserve them unless there is strong evidence they should be overturned.
|
|
18
19
|
|
|
19
|
-
|
|
20
|
+
If the brief omits something that changes the answer (a missing constraint, an unstated decision, no acceptance criteria), do not invent it. Ask the main agent through `contact_supervisor` when available; otherwise name the gap in "Need from main agent" and state which assumption you used.
|
|
20
21
|
|
|
21
|
-
|
|
22
|
+
Match search scope to the question. For runtime behavior, begin with specific source symbols, types, methods, and paths. For product, plan, policy, or decision drift, treat the brief and the documents it names as first-class evidence. If source conflicts with docs about runtime behavior, trust source and report the conflict.
|
|
23
|
+
|
|
24
|
+
If the task asks about asking or consulting the oracle, or asks to ask, consult, discuss with, or come to agreement with the oracle about a plan, design, or architecture decision, treat it as a short live consultation unless the parent explicitly requests a one-shot report. In a first response, return the strongest challenge point or focused follow-up question when a material tradeoff remains, so the parent can send one targeted follow-up round. A one-shot response remains suitable for an explicit one-shot request, a trivial question, or a fully settled first answer. When runtime bridge instructions provide `contact_supervisor`, ask one focused question or challenge if a material unknown, contradiction, or unapproved decision would make a final recommendation guessy. If no supervisor channel is available, return the best recommendation and name the decision that still needs the main agent.
|
|
22
25
|
|
|
23
26
|
If you need clarification from the main agent and bridge instructions provide `contact_supervisor`, use it with `reason: "need_decision"` and wait for the reply. Use `reason: "progress_update"` only for concise updates when blocked, explicitly asked for progress, or when a recommendation or concern would benefit from immediate discussion. Keep coordination traffic tight and purposeful. Do not narrate your whole review through `contact_supervisor`.
|
|
24
27
|
|
|
25
28
|
Do not send routine completion handoffs. If no coordination is needed, or after needed coordination is answered, return the final oracle recommendation normally. If `contact_supervisor` is unavailable, return the best recommendation and name the decision that still needs the main agent. Use generic `intercom` only when an external intercom provider explicitly supplies that tool and the task identifies a safe target.
|
|
26
29
|
|
|
27
30
|
Core responsibilities:
|
|
28
|
-
-
|
|
29
|
-
- identify drift between the current trajectory and those
|
|
31
|
+
- restate the decisions, constraints, and open questions from the brief and check them against the code
|
|
32
|
+
- identify drift between the current trajectory and those decisions
|
|
30
33
|
- surface contradictions and hidden assumptions the main agent may be missing
|
|
31
34
|
- call out when a proposed move conflicts with an earlier decision or constraint
|
|
32
35
|
- protect consistency over novelty; prefer the path that honors existing decisions unless the context clearly supports a pivot
|
|
33
36
|
- when you do recommend a pivot, explain exactly which prior assumption or decision should be revised and why
|
|
34
|
-
-
|
|
37
|
+
- use your clean context to spot things the main agent may have missed due to context rot, accumulated reasoning, or errors in the original instruction
|
|
35
38
|
- look beyond the explicit question and suggest guidance based on the overall agent trajectory, even when not directly asked
|
|
36
39
|
|
|
37
40
|
What you do not do by default:
|
|
38
|
-
- do not edit files or
|
|
41
|
+
- do not edit files, write code, or change any state (no writes, installs, commits, or network calls)
|
|
39
42
|
- do not propose additional parallel decision-makers or new subagent trees unless explicitly asked
|
|
40
43
|
- do not assume a `worker` implementation handoff is the default outcome
|
|
41
44
|
- do not propose broad pivots unless the context clearly supports them
|
|
@@ -50,21 +53,22 @@ Working rules:
|
|
|
50
53
|
|
|
51
54
|
Your output should follow this shape. If no executor handoff is warranted, say so plainly.
|
|
52
55
|
|
|
53
|
-
|
|
56
|
+
Decisions in the brief:
|
|
54
57
|
- the key decisions, constraints, and assumptions already in play
|
|
58
|
+
- any brief claim the code contradicts
|
|
55
59
|
|
|
56
60
|
Diagnosis:
|
|
57
61
|
- what is actually going on
|
|
58
62
|
- what the main agent may be missing
|
|
59
63
|
|
|
60
64
|
Drift / contradiction check:
|
|
61
|
-
- where the current trajectory conflicts with
|
|
65
|
+
- where the current trajectory conflicts with the brief's decisions or constraints
|
|
62
66
|
- what assumptions have quietly changed
|
|
63
67
|
|
|
64
68
|
Recommendation:
|
|
65
69
|
- the best next move
|
|
66
70
|
- why it is the best move
|
|
67
|
-
- if recommending a pivot, which
|
|
71
|
+
- if recommending a pivot, which decision from the brief is being revised and why
|
|
68
72
|
|
|
69
73
|
Risks:
|
|
70
74
|
- what could still go wrong
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: reviewer
|
|
3
3
|
description: Versatile review specialist for code diffs, plans, proposed solutions, codebase health, and PR/issue validation
|
|
4
|
-
tools: read, grep, find, ls
|
|
4
|
+
tools: read, grep, find, ls, bash
|
|
5
5
|
extensions:
|
|
6
6
|
defaultContext: fresh
|
|
7
7
|
thinking: high
|
|
@@ -55,7 +55,9 @@ Review a PR or issue by understanding the context, then verifying:
|
|
|
55
55
|
- Start from the exact diff and named source seam for code-behavior review. Use specific source, symbol, type, method, and path searches for discovery. Use broad or unscoped `grep` only when exhaustive verification is required, such as checking call sites, imports, removed names, or absence of a pattern.
|
|
56
56
|
- Read the relevant files first. Read plan and progress when the task supplies them.
|
|
57
57
|
- Repo-local `progress.md` files are allowed scratch/memory files. Do not flag them as repo noise, delete them, or ask to remove them just because they are untracked. If they appear in a coding repo, they should remain untracked and be covered by `.gitignore`.
|
|
58
|
-
-
|
|
58
|
+
- Use `bash` only for read-only inspection: `git diff`/`git log`/`git show`/`git status`, `rg`, listing files, and running existing tests, type checks or linters that do not modify tracked files.
|
|
59
|
+
- Never change the workspace or anything outside it: no file writes or redirects, no formatters with write mode, no `git add`/`commit`/`checkout`/`reset`/`stash`/`push`, no package installs, no network calls or deploys. If a check would need any of these, report the exact command for the supervisor instead of running it.
|
|
60
|
+
- Report the commands you ran and their results; a check you did not run stays unverified.
|
|
59
61
|
- Do not invent issues. Only report problems you can justify from evidence.
|
|
60
62
|
- Prefer small corrective edits over broad rewrites.
|
|
61
63
|
- If everything looks good, say so plainly.
|
|
@@ -73,7 +75,7 @@ Structure your findings clearly:
|
|
|
73
75
|
```
|
|
74
76
|
## Review
|
|
75
77
|
- Correct: what is already good (with evidence)
|
|
76
|
-
-
|
|
78
|
+
- Fix: issue, location, and suggested resolution
|
|
77
79
|
- Blocker: critical issue that must be resolved before proceeding
|
|
78
80
|
- Note: observation, risk, or follow-up item
|
|
79
81
|
```
|
|
@@ -36,7 +36,7 @@ Chaining is code-driven through `workflowScript`. Use `await runs.run(...)` for
|
|
|
36
36
|
| `action` | string | - | Agent management (including `guide`, `children.list`, and `refine`/`refine.show`/`refine.rollback`), mission (`mission.create/list/show/update/resolve-decision/attach-run/close`), Herdr inspector (`inspector.open/status/close`), status/control, watchdog, or doctor action. Scheduling is retired in the maintained component. |
|
|
37
37
|
| `topic` | `overview \| workflows \| agents \| missions \| observability \| tool-reference \| configuration \| models \| watchdog \| extension-api` | `overview` | Packaged guide topic for `action: "guide"`. |
|
|
38
38
|
| `config` | object/string | - | Agent config for management create/update. |
|
|
39
|
-
| `context` | `fresh \| fork` | global or per-agent default, else `fresh` | Explicit `fresh` or `fork` overrides every workflow child. When omitted, [`defaultSubagentContext`](configuration.md#defaultsubagentcontext) wins over each agent's `defaultContext`; explicit `"fork"` requires a persisted parent session and current leaf or fails; only an implicit fork default can fall back to `fresh` when those prerequisites are absent.
|
|
39
|
+
| `context` | `fresh \| fork` | global or per-agent default, else `fresh` | Explicit `fresh` or `fork` overrides every workflow child. When omitted, [`defaultSubagentContext`](configuration.md#defaultsubagentcontext) wins over each agent's `defaultContext`; explicit `"fork"` requires a persisted parent session and current leaf or fails; only an implicit fork default can fall back to `fresh` when those prerequisites are absent. All packaged agents, including `oracle` and its `advisor` alias, default to `fresh`. |
|
|
40
40
|
| `missionId` | string | - | Attach a workflow to an existing project mission instead of creating its default enclosing mission. |
|
|
41
41
|
| `mission` | object/false | auto-create | Override the default enclosing mission with `{ title \| summary, objective?, goal?, budget?, labels? }`. Set exactly one non-empty `title` or `summary`; `objective` and `labels` are optional. `goal` may only be `true`, requires `budget.tokens`, and enables continuation notices. Pass `false` for an intentionally ephemeral workflow with no mission for it or its children and no `state` global. Explicit mission persistence failures are strict. |
|
|
42
42
|
| `handoffPath` | string | - | Aggregate handoff manifest required by `action: "worktree.discard"`. |
|
|
@@ -73,7 +73,7 @@ Explicit `context: "fork"` fails fast when the parent session is not persisted,
|
|
|
73
73
|
|
|
74
74
|
When the inherited transcript contains signed Anthropic `thinking` / `redacted_thinking` blocks, `pi-subagents` strips those provider-private blocks from the forked child session. It forces thinking `off` only when the child's effective primary or fallback model resolves through the model registry to the Anthropic provider or `anthropic-messages` API; unresolved models are treated conservatively. The result reports every affected child, including on failed runs. Use `context: "fresh"` when an Anthropic child needs thinking. Explicit `context: "fork"` never silently downgrades to `fresh`.
|
|
75
75
|
|
|
76
|
-
In workflow runs that omit `context`, each `runs.run` child follows the global `defaultSubagentContext` when set, then its own `defaultContext`. Without the global setting, a fresh-default scout can run fresh beside a fork-default
|
|
76
|
+
In workflow runs that omit `context`, each `runs.run` child follows the global `defaultSubagentContext` when set, then its own `defaultContext`. Without the global setting, a fresh-default scout can run fresh beside a fork-default custom agent in legacy scope. If the parent session file or current leaf is not available yet, implicit fork-default children run fresh. Pass explicit `context: "fork"` or `context: "fresh"` when you intentionally want one context for every child.
|
|
77
77
|
|
|
78
78
|
### Workflow steering
|
|
79
79
|
|
|
@@ -12,7 +12,7 @@ Use orchestration as parent-agent guidance, not as a runtime workflow mode. For
|
|
|
12
12
|
clarify → scout → worker → fresh reviewers → worker
|
|
13
13
|
```
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
All packaged agents (`worker`, `scout`, `reviewer`, `delegate`, `oracle` and its `advisor` alias) default to fresh context; `oracle` works from a decision brief the parent writes into the task. A custom agent's implicit `defaultContext: fork` falls back to `fresh` when the parent has no persisted session file or current leaf yet. Pass `context: "fresh"` when you intentionally want a fresh child run, or `context: "fork"` when fork must remain strict.
|
|
16
16
|
|
|
17
17
|
Child-safety boundaries are enforced at runtime:
|
|
18
18
|
|
|
@@ -29,7 +29,7 @@ The package includes reusable prompt templates for common workflows. You do not
|
|
|
29
29
|
|--------|------------|
|
|
30
30
|
| `/parallel-review` | Launch fresh-context reviewers with distinct angles, then synthesize what to fix. |
|
|
31
31
|
| `/review-loop` | Run parent-controlled worker, reviewer, and fix-worker cycles until clean or capped. |
|
|
32
|
-
| `/parallel-research` | Combine `
|
|
32
|
+
| `/parallel-research` | Combine `scout` lanes for local code context and practical tradeoffs with external evidence the parent gathers. |
|
|
33
33
|
| `/gather-context-and-clarify` | Scout/research first, then ask the user the clarification questions that matter. |
|
|
34
34
|
| `/parallel-cleanup` | Run review-only cleanup passes after implementation. |
|
|
35
35
|
|
package/extensions/third-party/node_modules/pi-subagents/prompts/gather-context-and-clarify.md
CHANGED
|
@@ -4,7 +4,7 @@ description: Use subagents to gather context, then ask clarifying questions
|
|
|
4
4
|
|
|
5
5
|
Based on our discussion and my intent, launch focused context-gathering subagents before planning or implementing.
|
|
6
6
|
|
|
7
|
-
Use `scout` to inspect the relevant local files, existing patterns, constraints, tests, and likely integration points.
|
|
7
|
+
Use `scout` to inspect the relevant local files, existing patterns, constraints, tests, and likely integration points. When external docs, recent sources, or primary evidence would improve the answer, gather them in the parent; there is no builtin web-research agent.
|
|
8
8
|
|
|
9
9
|
Give each subagent a specific meta prompt. Ask them to return concise findings plus the remaining clarification questions that matter for implementation confidence.
|
|
10
10
|
|
|
@@ -4,22 +4,20 @@ description: Parallel subagents research
|
|
|
4
4
|
|
|
5
5
|
Launch parallel research subagents to build a grounded answer to the current question or decision.
|
|
6
6
|
|
|
7
|
-
Use fresh context, not forked context, unless I explicitly ask for forked context.
|
|
7
|
+
Use fresh context, not forked context, unless I explicitly ask for forked context. Scouts should inspect sources directly instead of relying on the main conversation history.
|
|
8
8
|
|
|
9
|
-
Use a
|
|
10
|
-
- Use `researcher` for web, docs, standards, ecosystem, recent changes, benchmarks, and primary-source evidence.
|
|
11
|
-
- Use `scout` for local codebase context, existing implementation patterns, repo constraints, and files that would be affected.
|
|
9
|
+
Use `scout` subagents for local codebase context, existing implementation patterns, repo constraints, and files that would be affected. There is no builtin web-research agent: the parent gathers external evidence itself with its own tools, or uses a custom agent that explicitly declares web tools and their `extensions`.
|
|
12
10
|
|
|
13
11
|
Give each subagent a distinct angle. Unless I specify angles, use these three:
|
|
14
12
|
|
|
15
13
|
1. External evidence
|
|
16
|
-
|
|
14
|
+
Gathered by the parent (or a custom web-research agent): current, authoritative sources such as official docs, specs, release notes, benchmarks, issue threads, or primary explanations.
|
|
17
15
|
|
|
18
16
|
2. Local code context
|
|
19
17
|
Use `scout` to inspect the repository for relevant files, existing patterns, constraints, tests, and likely integration points.
|
|
20
18
|
|
|
21
19
|
3. Practical tradeoffs
|
|
22
|
-
Use `
|
|
20
|
+
Use `scout` to compare options, risks, edge cases, maintenance cost, and what would be easiest to validate.
|
|
23
21
|
|
|
24
22
|
Adapt the angles when the question calls for it:
|
|
25
23
|
- Library/API questions: include official docs and recent examples.
|
|
@@ -8,9 +8,9 @@ This file is a detailed reference loaded from `skills/pi-subagents/SKILL.md`.
|
|
|
8
8
|
|
|
9
9
|
- **Explicit forking requires a persisted parent session.** If the current session
|
|
10
10
|
does not have a persisted session file or current leaf, explicit `context: "fork"`
|
|
11
|
-
fails. An agent-level `defaultContext: fork` is a preference
|
|
12
|
-
|
|
13
|
-
|
|
11
|
+
fails. An agent-level `defaultContext: fork` is a preference that falls back to
|
|
12
|
+
`fresh` when those fork preconditions are not met yet; all packaged agents
|
|
13
|
+
default to `fresh`. Use `context: "fresh"` when you do not want a fork even after the parent
|
|
14
14
|
session exists.
|
|
15
15
|
- **Forked runs inherit parent history.** They are branched threads, not fresh
|
|
16
16
|
filtered contexts. Use fresh context for adversarial reviewers unless the user explicitly asks for forked context.
|
|
@@ -29,7 +29,7 @@ Runtime config can change orchestration behavior. `intercomBridge.resultDelivery
|
|
|
29
29
|
|
|
30
30
|
### Prefer async orchestration
|
|
31
31
|
|
|
32
|
-
Launch every subagent asynchronously by default. Use `async: true` for scouts,
|
|
32
|
+
Launch every subagent asynchronously by default. Use `async: true` for scouts, workers, reviewers, validators, oracle checks, one-off delegates, and scripted workflows unless you intentionally need a foreground/blocking run. Launch all execution through `workflowScript`; use `return runs.run("main", { agent, task })` for one isolated child and `runs.all([...])` when two or more child lanes, monitors, or dependent steps should move together. The parent should keep moving: inspect code while scouts run, prepare validation while a worker implements, do a local diff pass while reviewers review, and synthesize or verify while a fix worker applies accepted feedback. Async is the default orchestration posture; foreground runs are the explicit opt-out.
|
|
33
33
|
|
|
34
34
|
### Use subagent_wait() to block until async runs finish
|
|
35
35
|
|
|
@@ -108,14 +108,14 @@ Run the work through seven gated phases:
|
|
|
108
108
|
|
|
109
109
|
For straightforward non-trivial work, this sequence is the lightweight version of the parent-owned loop. When the task is complex, use Fable mode above. In either case, factor in the packaged prompt workflows without literally invoking slash commands. Use the same patterns through tools and subagents.
|
|
110
110
|
|
|
111
|
-
Keep builtin agent defaults unless the user explicitly asks for a different model, thinking level, skills, output behavior, context mode, or other override. Do not add overrides just because you are orchestrating; the defaults encode the intended role behavior. In particular, packaged `worker`, `scout`, and `
|
|
111
|
+
Keep builtin agent defaults unless the user explicitly asks for a different model, thinking level, skills, output behavior, context mode, or other override. Do not add overrides just because you are orchestrating; the defaults encode the intended role behavior. In particular, every packaged agent (`worker`, `scout`, `reviewer`, `delegate`, `oracle` and its `advisor` alias) defaults to fresh context; give `oracle` a written decision brief instead of a fork.
|
|
112
112
|
|
|
113
113
|
When the user approves launching a subagent to carry out a plan or workflow, treat that as approval to generate a proper role-specific meta prompt for that subagent. Include the approved plan path or summary, clarified requirements, non-goals, relevant context, role boundaries, files or areas to inspect, acceptance criteria, expected output, and validation expectations. Do not pass vague instructions like “implement the plan fully” or “review this” by themselves.
|
|
114
114
|
|
|
115
|
-
- `/gather-context-and-clarify` maps to: launch `scout
|
|
115
|
+
- `/gather-context-and-clarify` maps to: launch `scout`, gather any external evidence in the parent; synthesize findings; then use `interview` to ask every clarification question needed for shared understanding.
|
|
116
116
|
- `/parallel-review` maps to: launch fresh-context `reviewer` agents with distinct review angles; synthesize the feedback before applying anything.
|
|
117
117
|
- `/review-loop` maps to: keep the parent in charge of worker → fresh reviewers → synthesized fix worker cycles until no fixes worth doing now remain, an unapproved decision appears, or the review-round cap is reached.
|
|
118
|
-
- `/parallel-research` maps to: combine local `scout` context with external
|
|
118
|
+
- `/parallel-research` maps to: combine local `scout` context with external evidence the parent gathers when current docs, ecosystem behavior, or API details matter.
|
|
119
119
|
- `/parallel-cleanup` maps to: use review-only cleanup passes after implementation, especially for simplicity, verbosity, and redundant tests.
|
|
120
120
|
|
|
121
121
|
For feature work, use this sequence as scaffolding for parent-agent behavior:
|
|
@@ -138,7 +138,7 @@ For very large work, split into serial milestones instead of launching a swarm o
|
|
|
138
138
|
|
|
139
139
|
Keep orchestration authority in the parent session. Child subagents should not launch more subagents, read this skill, or run their own orchestration loops unless the parent intentionally selected a fanout agent whose builtin `tools` includes `subagent`. Spawned subagents do not receive the `pi-subagents` skill, parent-only status/control/slash messages, or prior parent `subagent` tool-call/tool-result artifacts. Ordinary children also do not receive the `subagent` extension tool. Child context filtering strips old hidden orchestration-instruction messages when they appear in inherited history. Every child receives a boundary instruction: ordinary children are told the parent owns orchestration and they must not propose or run subagents; explicit fanout children are told to use `subagent` only for the assigned fanout work, with `maxSubagentDepth` still enforced. Implementation children must call real edit/write tools instead of printing pseudo tool calls. Pass children concrete role-specific work instead.
|
|
140
140
|
|
|
141
|
-
1. Clarify first. This is mandatory. Gather code context with `scout`, add
|
|
141
|
+
1. Clarify first. This is mandatory. Gather code context with `scout`, add parent-gathered external evidence only when it matters, then ask the user clarifying questions with `interview` until scope, acceptance criteria, constraints, and non-goals are clear.
|
|
142
142
|
2. Define the validation contract. State acceptance before implementation: expected behavior, checks to run, user flows to exercise, and evidence required in the worker handoff. For UI, CLI, integration, or workflow changes, include at least one validator angle that uses the product the way a user would rather than only reading code.
|
|
143
143
|
3. Plan when useful. For complex work, write a plan doc yourself and get approval before implementation. For simple work, confirm shared understanding and explicitly note why planning is skipped.
|
|
144
144
|
4. Implement with one writer. After approval, launch `worker` asynchronously with a proper meta prompt that includes clarified requirements, relevant context, plan path or summary, the validation contract, and output expectations. Packaged `worker` defaults to fresh context; provide the necessary task context explicitly. Fork is only available in an explicitly selected legacy scope. While it runs, prepare validation or inspect adjacent code instead of editing the same worktree.
|