@bingjiang0611/rotom 0.1.25 → 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 +1 -1
- 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 +1 -0
- 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 +1 -0
- 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 -12
- 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 +3 -3
- package/runtime/pi/fork-build.json +9 -9
- package/runtime/pi/node_modules/.package-lock.json +7 -7
- package/runtime/pi/node_modules/@earendil-works/pi-agent-core/package.json +1 -1
- 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 +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-codemode/package.json +1 -1
- 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-6NUCYK64.js → chunk-ESL4WJJF.js} +9 -9
- package/runtime/pi/node_modules/@earendil-works/pi-coding-agent/dist/bundle/chunks/{chunk-DSV77X2M.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-INPREDLP.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 +56 -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/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/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 +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-mcp/package.json +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
- package/runtime/pi/node_modules/@earendil-works/pi-tui/package.json +1 -1
- package/runtime/pi/package-lock.json +7 -7
- 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.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 +4 -4
- 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.1.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
|
@@ -48,7 +48,7 @@ subagent({
|
|
|
48
48
|
|
|
49
49
|
```typescript
|
|
50
50
|
subagent({
|
|
51
|
-
workflowScript: `return runs.run("
|
|
51
|
+
workflowScript: `return runs.run("continue-thread", { agent: "delegate", task: "Continue the investigation from the current conversation state.", context: "fork" })`
|
|
52
52
|
})
|
|
53
53
|
```
|
|
54
54
|
|
|
@@ -86,7 +86,7 @@ Completed workflow children from this parent session stay addressable as retaine
|
|
|
86
86
|
|
|
87
87
|
### Async/background
|
|
88
88
|
|
|
89
|
-
Prefer async mode for every subagent launch. Set `async: true` no matter the task unless the parent must block until completion. This applies to scouts,
|
|
89
|
+
Prefer async mode for every subagent launch. Set `async: true` no matter the task unless the parent must block until completion. This applies to scouts, workers, reviewers, validators, oracle checks, one-off delegates, final review gates, backlog gates, and scripted workflows. Keep the write path single-threaded even when the run is async.
|
|
90
90
|
|
|
91
91
|
Use `async:false` only when the parent must block until completion. Async mode still shows progress. Do not use `async:false` because a task is short, because it is the last gate, because no other work is ready, because the user asked to finish the overall job, or because blocking is convenient.
|
|
92
92
|
|
|
@@ -358,7 +358,7 @@ worktree, first confirm dependencies were linked, installed, or provisioned by
|
|
|
358
358
|
|
|
359
359
|
### Oracle consultation loop
|
|
360
360
|
|
|
361
|
-
For plan, design, or architecture advice that asks to ask, consult, discuss with, or come to agreement with `oracle`, start with one
|
|
361
|
+
For plan, design, or architecture advice that asks to ask, consult, discuss with, or come to agreement with `oracle`, start with one fresh oracle run whose task is a decision brief: goal and acceptance criteria, decisions already made and why, hard constraints, the proposed move, the files that matter, and the specific question. Read its result. If it challenges the direction or leaves a material tradeoff, resume that same completed child once with a focused follow-up, then synthesize the parent decision. `resume` returns a new run id, but continues the same oracle session. Do not force a second round for an explicit one-shot request, a trivial question, or a fully settled first answer.
|
|
362
362
|
|
|
363
363
|
```typescript
|
|
364
364
|
const first = await runs.run("oracle-consult", { agent: "oracle", task: "Review this plan and identify the strongest unresolved tradeoff." });
|
|
@@ -368,14 +368,14 @@ const final = await runs.run("oracle-consult-follow-up", { resume: first.runId,
|
|
|
368
368
|
The parent remains the final decision-maker. Oracle advice does not approve a direction or start implementation.
|
|
369
369
|
|
|
370
370
|
The intended oracle loop is:
|
|
371
|
-
1. the main agent
|
|
371
|
+
1. the main agent writes a decision brief and launches `oracle` with fresh context
|
|
372
372
|
2. `oracle` reviews direction, drift, assumptions, and risks
|
|
373
373
|
3. `oracle` can coordinate back through `contact_supervisor` when the bridge injects it
|
|
374
374
|
4. the main agent decides what direction to approve
|
|
375
375
|
5. only then should `worker` implement
|
|
376
376
|
|
|
377
377
|
```typescript
|
|
378
|
-
// Advisory review
|
|
378
|
+
// Advisory review from a parent-written decision brief. Oracle defaults to fresh context.
|
|
379
379
|
subagent({
|
|
380
380
|
workflowScript: `return runs.run("oracle-check", { agent: "oracle", task: "Review my current direction, challenge assumptions, and propose the best next move." })`
|
|
381
381
|
})
|
|
@@ -9,7 +9,7 @@ Parent extensions may register a session-scoped, out-of-band ceiling through `pi
|
|
|
9
9
|
## When to Use
|
|
10
10
|
|
|
11
11
|
- **Complex work orchestration**: use Fable mode as the default parent-agent loop for complex work. Complex means the task has multiple moving parts, unclear acceptance, cross-cutting code, meaningful user-visible impact, expensive or irreversible validation, broad review surface, or the user asks for orchestration. Lightweight one-off delegation can stay lightweight.
|
|
12
|
-
- **Advisory review**: use fresh-context `reviewer` agents for adversarial code review, or
|
|
12
|
+
- **Advisory review**: use fresh-context `reviewer` agents for adversarial code review, or give `oracle` a written decision brief when prior decisions and drift matter
|
|
13
13
|
- **Implementation handoff**: have `oracle` advise, then `worker` implement only after an approved direction
|
|
14
14
|
- **Recon and planning**: use `scout`, then write a plan when needed
|
|
15
15
|
- **Parallel exploration**: run multiple non-conflicting tasks concurrently
|
|
@@ -41,7 +41,7 @@ you are guiding a human through an interactive flow.
|
|
|
41
41
|
Packaged prompt shortcuts are also available for repeatable workflows. Treat them as reusable orchestration recipes, not just human slash commands. When the user asks for one of these shapes, or when the workflow clearly fits, apply the same pattern directly with `subagent(...)` and other tools:
|
|
42
42
|
- `/parallel-review` — fresh-context reviewers with distinct review angles, then synthesis
|
|
43
43
|
- `/review-loop` — parent-orchestrated worker, fresh-reviewer, and fix-worker cycles until clean or capped
|
|
44
|
-
- `/parallel-research` — combine
|
|
44
|
+
- `/parallel-research` — combine parallel `scout` lanes for local code context with external evidence the parent gathers
|
|
45
45
|
- `/gather-context-and-clarify` — scout/research first, then ask the user clarifying questions with `interview`
|
|
46
46
|
- `/parallel-cleanup` — two fresh-context reviewers (deslop + verbosity passes) for an adversarial cleanup review of the current diff
|
|
47
47
|
|
|
@@ -87,13 +87,13 @@ As a conservative orchestration policy, do not pass `turnBudget` or a hard `tool
|
|
|
87
87
|
|
|
88
88
|
### Parallel research technique
|
|
89
89
|
|
|
90
|
-
Use this when the question needs both external evidence and local implications.
|
|
90
|
+
Use this when the question needs both external evidence and local implications. The parent gathers official docs, specs, ecosystem behavior, recent changes, benchmarks, and primary sources itself (there is no builtin web-research agent) and uses `scout` for repository files, patterns, constraints, tests, and likely integration points. Give each child a distinct angle: external evidence, local code context, and practical tradeoffs. Ask for source links or file ranges, confidence level, gaps, and decision implications. Do not ask these children to edit unless implementation was explicitly requested.
|
|
91
91
|
|
|
92
92
|
|
|
93
93
|
|
|
94
94
|
### Gather-context-and-clarify technique
|
|
95
95
|
|
|
96
|
-
Use this at the start of non-trivial work. Launch `scout` for local context and
|
|
96
|
+
Use this at the start of non-trivial work. Launch `scout` for local context, and gather external docs, recent sources, ecosystem context, or primary evidence in the parent only when they would materially improve understanding. Ask children for concise findings plus remaining clarification questions. Then synthesize what is known and use `interview` to ask the unresolved questions needed for shared understanding before planning or implementing.
|
|
97
97
|
|
|
98
98
|
### Parallel cleanup technique
|
|
99
99
|
|
|
@@ -157,10 +157,9 @@ and user/project agents override builtins with the same name.
|
|
|
157
157
|
|-------|---------|-------|------------------------|
|
|
158
158
|
| `scout` | Fast codebase recon | inherits default | Writes `context.md` handoff material |
|
|
159
159
|
| `worker` | Implementation and approved oracle handoffs | inherits default | Single-writer implementation with decision escalation |
|
|
160
|
-
| `reviewer` | Review specialist | inherits default |
|
|
161
|
-
| `researcher` | Web research brief generator | inherits default | Writes `research.md` |
|
|
160
|
+
| `reviewer` | Review specialist | inherits default | Review-only; `bash` limited by prompt to read-only inspection and existing checks |
|
|
162
161
|
| `delegate` | Lightweight generic delegate | inherits default | No fixed output; generic delegated work |
|
|
163
|
-
| `oracle` | Decision-consistency advisory review | inherits default |
|
|
162
|
+
| `oracle` | Decision-consistency advisory review | inherits default | Read-only; fresh context from a parent-written decision brief |
|
|
164
163
|
| `advisor` | Claude Code-compatible alias for `oracle` | inherits default | Same advisory role as `oracle` |
|
|
165
164
|
|
|
166
165
|
Builtin `worker` and `delegate` use strict tool allowlists and do not inherit ambient parent extension tools. To give a child an extension tool, name it in `tools` and load its provider via `extensions`, a path-like `tools` entry, or `subagentOnlyExtensions`. Custom agents without an `extensions` field follow `subagents.defaultExtensions` when set.
|
|
@@ -206,7 +205,7 @@ A strong subagent prompt usually includes:
|
|
|
206
205
|
|
|
207
206
|
Give each role useful discovery anchors. Name source roots, filenames, symbols, types, methods, and paths for scouts. Give workers context files, plans, task paths, and named source seams before asking them to search. Give reviewers changed files, contracts, and any exhaustive-verification target. Tell oracle whether current source behavior, product/policy documents, plans, or inherited decisions are the evidence that matters.
|
|
208
207
|
|
|
209
|
-
Avoid carrying over old prompt habits that over-specify every step. Use `must`, `always`, and `never` for real invariants; for judgment calls, give decision rules. For example, tell a reviewer to inspect the staged diff directly and report only evidence-backed findings, rather than prescribing every file or command.
|
|
208
|
+
Avoid carrying over old prompt habits that over-specify every step. Use `must`, `always`, and `never` for real invariants; for judgment calls, give decision rules. For example, tell a reviewer to inspect the staged diff directly and report only evidence-backed findings, rather than prescribing every file or command.
|
|
210
209
|
|
|
211
210
|
For implementation handoffs, name the approved scope and success criteria more clearly than the process. Good prompts say what to change, what not to change, where the evidence lives, how to validate, and when to escalate. They should not ask the child to create another subagent plan or continue the parent conversation.
|
|
212
211
|
|
|
@@ -47,6 +47,7 @@ import { resolveWaitToolConfig } from "../runs/background/subagent-wait.ts";
|
|
|
47
47
|
import { registerWaitTool } from "../runs/background/wait-tool.ts";
|
|
48
48
|
import { createWaitSubscriptionManager } from "../runs/background/wait-subscriptions.ts";
|
|
49
49
|
import { drainOutstandingWork } from "../runs/background/auto-drain.ts";
|
|
50
|
+
import { asyncRunnerDrain } from "../runs/background/async-execution.ts";
|
|
50
51
|
import registerSubagentNotify, { parseSubagentNotifyContent, type SubagentNotifyDetails } from "../runs/background/notify.ts";
|
|
51
52
|
import { formatSteeringNotice, handleSubagentSteeringNotice, SUBAGENT_STEERING_MESSAGE_TYPE, type SubagentSteeringMessageDetails } from "./steering-notices.ts";
|
|
52
53
|
import { SUBAGENT_CHILD_ENV, SUBAGENT_PARENT_SESSION_ENV } from "../runs/shared/pi-args.ts";
|
|
@@ -950,7 +951,13 @@ export default function registerSubagentExtension(pi: ExtensionAPI): void {
|
|
|
950
951
|
});
|
|
951
952
|
|
|
952
953
|
pi.on("session_shutdown", async () => {
|
|
953
|
-
|
|
954
|
-
|
|
954
|
+
try {
|
|
955
|
+
// Quit, reload and replacement retire this runtime's authority. Persist
|
|
956
|
+
// child close evidence before disposing the original observers.
|
|
957
|
+
await asyncRunnerDrain(pi).drain();
|
|
958
|
+
} finally {
|
|
959
|
+
runtimeEntry.cleanup();
|
|
960
|
+
await herdrStatusBridge.flush();
|
|
961
|
+
}
|
|
955
962
|
});
|
|
956
963
|
}
|
|
@@ -261,7 +261,7 @@ function qualityTierToRoleTier(quality: QualityTier, cost: CostTier): Recommende
|
|
|
261
261
|
|
|
262
262
|
function agentsForRoleTier(roleTier: RecommendedRoleTier): BuiltinAgentName[] {
|
|
263
263
|
if (roleTier === "cheap") return ["scout", "delegate"];
|
|
264
|
-
if (roleTier === "medium") return ["
|
|
264
|
+
if (roleTier === "medium") return ["reviewer"];
|
|
265
265
|
return ["worker", "reviewer", "oracle"];
|
|
266
266
|
}
|
|
267
267
|
|
|
@@ -407,7 +407,6 @@ function buildProfileFile(kind: ProfileKind, models: { cheap: string; medium: st
|
|
|
407
407
|
agentOverrides: {
|
|
408
408
|
scout: { model: models.cheap },
|
|
409
409
|
delegate: { model: models.cheap },
|
|
410
|
-
researcher: { model: models.medium },
|
|
411
410
|
worker: { model: models.strong },
|
|
412
411
|
reviewer: { model: models.strong },
|
|
413
412
|
oracle: { model: models.strong },
|
package/extensions/third-party/node_modules/pi-subagents/src/runs/background/async-execution.ts
CHANGED
|
@@ -67,7 +67,9 @@ import { validateToolBudgetConfig } from "../shared/tool-budget.ts";
|
|
|
67
67
|
import { usageBudgetState } from "../shared/usage-budget.ts";
|
|
68
68
|
import type { ImportedAsyncRoot } from "./chain-root-attachment.ts";
|
|
69
69
|
import type { SessionLeaseRequest } from "../shared/session-lease.ts";
|
|
70
|
-
import { finalizeProcessTerminal, readProcessTerminal } from "./process-terminal.ts";
|
|
70
|
+
import { finalizeProcessTerminal, readProcessTerminal, registerRunnerCloseObserver } from "./process-terminal.ts";
|
|
71
|
+
import { createRunnerDrain } from "./runner-drain.ts";
|
|
72
|
+
|
|
71
73
|
import type { ActiveAsyncCapacityHandle } from "./active-async-capacity.ts";
|
|
72
74
|
import { assertExecutionStoreScope, scopedSessionRoot, assertScopedSessionPath } from "../../shared/execution-store.ts";
|
|
73
75
|
import { OWNED_EXECUTION_SCOPE, type OwnedExecutionRequest, type OwnedWorkflowParent } from "./owned-execution.ts";
|
|
@@ -76,6 +78,17 @@ import { assertAgentAllowedByCapabilityCeiling, decodeSubagentCapabilityCeiling,
|
|
|
76
78
|
import { agentDefinitionDigest, launchBindingDigest } from "../../shared/launch-contract.ts";
|
|
77
79
|
import { resolvePermissionRules, type PermissionConfig } from "../shared/permissions.ts";
|
|
78
80
|
|
|
81
|
+
// Each runtime owns live ChildProcess handles, never historical PIDs.
|
|
82
|
+
const runtimeRunnerDrains = new WeakMap<object, ReturnType<typeof createRunnerDrain>>();
|
|
83
|
+
export function asyncRunnerDrain(owner: object): ReturnType<typeof createRunnerDrain> {
|
|
84
|
+
let drain = runtimeRunnerDrains.get(owner);
|
|
85
|
+
if (!drain) {
|
|
86
|
+
drain = createRunnerDrain();
|
|
87
|
+
runtimeRunnerDrains.set(owner, drain);
|
|
88
|
+
}
|
|
89
|
+
return drain;
|
|
90
|
+
}
|
|
91
|
+
|
|
79
92
|
const require = createRequire(import.meta.url);
|
|
80
93
|
const piPackageRoot = resolvePiPackageRoot();
|
|
81
94
|
|
|
@@ -487,7 +500,8 @@ interface SpawnRunnerResult {
|
|
|
487
500
|
startupDidNotProceed?: boolean;
|
|
488
501
|
}
|
|
489
502
|
|
|
490
|
-
function spawnRunner(cfg: object, suffix: string, cwd: string, onProcessTerminal?: (proof: unknown) => void): SpawnRunnerResult {
|
|
503
|
+
function spawnRunner(cfg: object, suffix: string, cwd: string, drain: ReturnType<typeof createRunnerDrain>, onProcessTerminal?: (proof: unknown) => void): SpawnRunnerResult {
|
|
504
|
+
drain.assertOpen();
|
|
491
505
|
if (!jitiCliPath) {
|
|
492
506
|
return { error: "upstream jiti for TypeScript execution could not be found; ensure package dependencies are installed" };
|
|
493
507
|
}
|
|
@@ -546,62 +560,75 @@ function spawnRunner(cfg: object, suffix: string, cwd: string, onProcessTerminal
|
|
|
546
560
|
proc.on("error", (error) => {
|
|
547
561
|
console.error(`[pi-subagents] async spawn failed: ${error.message}`);
|
|
548
562
|
});
|
|
563
|
+
const releaseCloseObserver = typeof launchAsyncDir === "string" && typeof launchRunId === "string"
|
|
564
|
+
? registerRunnerCloseObserver(launchAsyncDir, launchRunId, runnerProcessInstanceId) : undefined;
|
|
565
|
+
const observedClose = drain.track(() => {
|
|
566
|
+
// Awaiting a Promise alone cannot keep Node alive after RPC stdin closes.
|
|
567
|
+
proc.ref();
|
|
568
|
+
if (proc.exitCode === null && proc.signalCode === null) proc.kill("SIGTERM");
|
|
569
|
+
});
|
|
549
570
|
proc.once("close", (exitCode, signal) => {
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
let status: import("../../shared/types.ts").AsyncStatus;
|
|
571
|
+
try {
|
|
572
|
+
const launch = launchConfig as { asyncDir?: unknown; id?: unknown; nestedRoute?: NestedRouteInfo; nestedSelf?: { parentRunId: string; parentStepIndex?: number; depth: number; path?: Array<{ runId: string; stepIndex?: number; agent?: string }> } };
|
|
573
|
+
const asyncDir = launch.asyncDir;
|
|
574
|
+
const runId = launch.id;
|
|
575
|
+
if (typeof asyncDir !== "string" || typeof runId !== "string") return;
|
|
576
|
+
finalizeProcessTerminal(asyncDir, runId, {
|
|
577
|
+
processInstanceId: runnerProcessInstanceId,
|
|
578
|
+
closeObservedAt: Date.now(),
|
|
579
|
+
exitCode,
|
|
580
|
+
signal,
|
|
581
|
+
});
|
|
582
|
+
const persisted = readProcessTerminal(asyncDir, { runId, runnerProcessInstanceId });
|
|
583
|
+
if (!persisted) return;
|
|
584
|
+
if (launch.nestedRoute && launch.nestedSelf) {
|
|
565
585
|
try {
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
child: nestedSummaryFromAsyncStatus(status, asyncDir, {
|
|
584
|
-
id: runId,
|
|
586
|
+
let status: import("../../shared/types.ts").AsyncStatus;
|
|
587
|
+
try {
|
|
588
|
+
status = JSON.parse(fs.readFileSync(path.join(asyncDir, "status.json"), "utf-8")) as import("../../shared/types.ts").AsyncStatus;
|
|
589
|
+
status.processTerminal = persisted;
|
|
590
|
+
} catch {
|
|
591
|
+
status = {
|
|
592
|
+
runId,
|
|
593
|
+
mode: "single",
|
|
594
|
+
state: persisted.state === "observed" ? "complete" : "failed",
|
|
595
|
+
startedAt: persisted.observedAt ?? Date.now(),
|
|
596
|
+
lastUpdate: Date.now(),
|
|
597
|
+
processTerminal: persisted,
|
|
598
|
+
};
|
|
599
|
+
}
|
|
600
|
+
writeNestedEvent(launch.nestedRoute, {
|
|
601
|
+
type: "subagent.nested.completed",
|
|
602
|
+
ts: Date.now(),
|
|
585
603
|
parentRunId: launch.nestedSelf.parentRunId,
|
|
586
604
|
parentStepIndex: launch.nestedSelf.parentStepIndex,
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
605
|
+
child: nestedSummaryFromAsyncStatus(status, asyncDir, {
|
|
606
|
+
id: runId,
|
|
607
|
+
parentRunId: launch.nestedSelf.parentRunId,
|
|
608
|
+
parentStepIndex: launch.nestedSelf.parentStepIndex,
|
|
609
|
+
depth: launch.nestedSelf.depth,
|
|
610
|
+
path: launch.nestedSelf.path,
|
|
611
|
+
mode: status.mode,
|
|
612
|
+
ts: Date.now(),
|
|
613
|
+
}),
|
|
614
|
+
});
|
|
615
|
+
} catch (error) {
|
|
616
|
+
console.error("Failed to emit final nested process-terminal status:", error);
|
|
617
|
+
}
|
|
618
|
+
}
|
|
619
|
+
try {
|
|
620
|
+
onProcessTerminal?.(persisted);
|
|
593
621
|
} catch (error) {
|
|
594
|
-
|
|
622
|
+
// The close proof is already durable. Reload/disposal can retire the
|
|
623
|
+
// originating Pi API before this late advisory wake; never redirect it
|
|
624
|
+
// to a new session or claim a receipt. Recovery must read the record.
|
|
625
|
+
if (!(error instanceof Error)
|
|
626
|
+
|| !/extension ctx is stale|stale after session replacement or reload/i.test(error.message)) throw error;
|
|
595
627
|
}
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
// The close proof is already durable. Reload/disposal can retire the
|
|
601
|
-
// originating Pi API before this late advisory wake; never redirect it
|
|
602
|
-
// to a new session or claim a receipt. Recovery must read the record.
|
|
603
|
-
if (!(error instanceof Error)
|
|
604
|
-
|| !/extension ctx is stale|stale after session replacement or reload/i.test(error.message)) throw error;
|
|
628
|
+
} finally {
|
|
629
|
+
// Finalization (including honest unknown) precedes runtime teardown.
|
|
630
|
+
releaseCloseObserver?.();
|
|
631
|
+
observedClose();
|
|
605
632
|
}
|
|
606
633
|
});
|
|
607
634
|
if (typeof proc.pid !== "number") {
|
|
@@ -1202,6 +1229,7 @@ export function executeAsyncChain(
|
|
|
1202
1229
|
},
|
|
1203
1230
|
id,
|
|
1204
1231
|
runnerCwd,
|
|
1232
|
+
asyncRunnerDrain(ctx.pi),
|
|
1205
1233
|
(proof) => ctx.pi.events.emit(SUBAGENT_PROCESS_TERMINAL_EVENT, proof),
|
|
1206
1234
|
);
|
|
1207
1235
|
} catch (error) {
|
|
@@ -1684,6 +1712,7 @@ export function executeAsyncSingle(
|
|
|
1684
1712
|
},
|
|
1685
1713
|
id,
|
|
1686
1714
|
runnerCwd,
|
|
1715
|
+
asyncRunnerDrain(ctx.pi),
|
|
1687
1716
|
(proof) => ctx.pi.events.emit(SUBAGENT_PROCESS_TERMINAL_EVENT, proof),
|
|
1688
1717
|
);
|
|
1689
1718
|
} catch (error) {
|
package/extensions/third-party/node_modules/pi-subagents/src/runs/background/process-terminal.ts
CHANGED
|
@@ -13,6 +13,19 @@ import { canonicalSessionId, inspectSessionLease } from "../shared/session-lease
|
|
|
13
13
|
import { releaseActiveRunIndex } from "./active-run-index.ts";
|
|
14
14
|
import { validOwnedExecution, projectOwnedClosure, type OwnedExecutionV2 } from "./owned-execution.ts";
|
|
15
15
|
|
|
16
|
+
// Process-local liveness of the original observer, not evidence of exit. A new
|
|
17
|
+
// parent cannot reconstruct this registration from disk or a numeric PID.
|
|
18
|
+
const runnerCloseObservers = new Set<string>();
|
|
19
|
+
const observerKey = (asyncDir: string, runId: string, instanceId: string) => JSON.stringify([path.resolve(asyncDir), runId, instanceId]);
|
|
20
|
+
export function registerRunnerCloseObserver(asyncDir: string, runId: string, instanceId: string): () => void {
|
|
21
|
+
const key = observerKey(asyncDir, runId, instanceId);
|
|
22
|
+
runnerCloseObservers.add(key);
|
|
23
|
+
return () => { runnerCloseObservers.delete(key); };
|
|
24
|
+
}
|
|
25
|
+
export function hasRunnerCloseObserver(asyncDir: string, runId: string, instanceId: string): boolean {
|
|
26
|
+
return runnerCloseObservers.has(observerKey(asyncDir, runId, instanceId));
|
|
27
|
+
}
|
|
28
|
+
|
|
16
29
|
export interface ProcessTerminalCandidate {
|
|
17
30
|
version: 1;
|
|
18
31
|
runId: string;
|
package/extensions/third-party/node_modules/pi-subagents/src/runs/background/stale-run-reconciler.ts
CHANGED
|
@@ -7,6 +7,7 @@ import { readStatus } from "../../shared/utils.ts";
|
|
|
7
7
|
import { DIRS, type AsyncParallelGroupStatus, type AsyncStatus, type NestedRunSummary, type SubagentRunMode } from "../../shared/types.ts";
|
|
8
8
|
import { resolveEffectiveThinking } from "../../shared/model-info.ts";
|
|
9
9
|
import { normalizeParallelGroups } from "./parallel-groups.ts";
|
|
10
|
+
import { hasRunnerCloseObserver } from "./process-terminal.ts";
|
|
10
11
|
import { nestedSummaryFromAsyncStatus, projectNestedEvents, resolveNestedAsyncDir, writeNestedEvent, type NestedRoute } from "../shared/nested-events.ts";
|
|
11
12
|
|
|
12
13
|
export type PidLiveness = "alive" | "dead" | "unknown";
|
|
@@ -141,7 +142,7 @@ function childState(overallState: ResultRepairData["state"], child: ResultChildO
|
|
|
141
142
|
return overallState;
|
|
142
143
|
}
|
|
143
144
|
|
|
144
|
-
function terminalStatusFromResult(status: AsyncStatus, resultPath: string, now: number): AsyncStatus | undefined {
|
|
145
|
+
function terminalStatusFromResult(status: AsyncStatus, resultPath: string, now: number, asyncDir: string): AsyncStatus | undefined {
|
|
145
146
|
const repair = readResultRepairData(resultPath);
|
|
146
147
|
if (!repair) return undefined;
|
|
147
148
|
const steps = (status.steps ?? []).map((step, index) => {
|
|
@@ -168,7 +169,10 @@ function terminalStatusFromResult(status: AsyncStatus, resultPath: string, now:
|
|
|
168
169
|
const terminalStatus: AsyncStatus = {
|
|
169
170
|
...status,
|
|
170
171
|
state: repair.state,
|
|
171
|
-
...(status.lifecycleArtifactVersion === 3 && (!status.processTerminal || status.processTerminal.state === "pending")
|
|
172
|
+
...(status.lifecycleArtifactVersion === 3 && (!status.processTerminal || status.processTerminal.state === "pending")
|
|
173
|
+
// A result can precede the launching parent's native close callback.
|
|
174
|
+
// Retain pending for that actual observer; this never proves exit.
|
|
175
|
+
&& !(status.processTerminal?.state === "pending" && hasRunnerCloseObserver(asyncDir, status.runId, status.processTerminal.runnerProcessInstanceId)) ? {
|
|
172
176
|
processTerminal: { version: 1 as const, state: "unknown" as const, runId: status.runId, runnerProcessInstanceId: "observer-unavailable", reason: "observer-unavailable" as const },
|
|
173
177
|
} : {}),
|
|
174
178
|
...(repair.state === "stopped" ? { stopped: true } : {}),
|
|
@@ -379,7 +383,7 @@ export function reconcileAsyncRun(asyncDir: string, options: ReconcileAsyncRunOp
|
|
|
379
383
|
: regularFileExists(resultPath) ? resultPath : undefined;
|
|
380
384
|
if (existingResultPath) {
|
|
381
385
|
const terminalStatus = effectiveStatus.state === "running" || effectiveStatus.state === "queued"
|
|
382
|
-
? terminalStatusFromResult(effectiveStatus, existingResultPath, now)
|
|
386
|
+
? terminalStatusFromResult(effectiveStatus, existingResultPath, now, asyncDir)
|
|
383
387
|
: undefined;
|
|
384
388
|
if (terminalStatus) {
|
|
385
389
|
writeAtomicJson(path.join(asyncDir, "status.json"), terminalStatus);
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
## rotom changes
|
|
15
15
|
|
|
16
16
|
- `0.1.0-rotom.1`: the Evidence-Preserving Reducer records each returned reducer response (applied or rejected) as a Pi `usage` entry of kind `sol_pi_reducer`, attributed to the reducer provider/model with the provider-reported usage unchanged. Pi's footer, session stats, usage breakdown and Goal budgets then include the reducer spend. It uses `pi.appendUsage`, which the rotom Pi fork exposes from `1.3.0-rotom.2`; on Pi releases without it (upstream Pi) only the SoL-Pi journal entry is written, as before. Calls that throw before a response (timeout, unavailable model, missing auth) record no usage. Files: `evidence-preserving-reducer/{provider,journal,index}.ts`, `tests/helpers.ts`, `tests/evidence-preserving-reducer.test.ts`.
|
|
17
|
+
- `0.1.0-rotom.2`: an `unverifiable-quote` fallback journal entry now carries a `quoteDiagnostic` for the first rejected evidence item: `cause` (`invalid-kind`, `not-a-string`, `empty`, `too-long` or `not-in-source`), its index and the evidence count, the quote length and SHA-256, and for `not-in-source` the longest leading part found in the log with its line, plus whether the quote would match after removing ANSI escapes or collapsing whitespace. It never stores quote or log text. Acceptance is unchanged: a receipt is still rejected unless every quote appears byte for byte. Files: `evidence-preserving-reducer/{receipt,index}.ts`, `tests/evidence-preserving-reducer.test.ts`.
|
|
17
18
|
|
|
18
19
|
## How rotom uses it
|
|
19
20
|
|
|
@@ -30,9 +30,30 @@ export interface ValidatedReceipt {
|
|
|
30
30
|
readonly evidence: readonly VerifiedEvidence[];
|
|
31
31
|
}
|
|
32
32
|
|
|
33
|
+
export type QuoteRejection = "invalid-kind" | "not-a-string" | "empty" | "too-long" | "not-in-source";
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Why one evidence item was rejected, without its text: the journal may only
|
|
37
|
+
* hold digests, sizes and line numbers, never log or model content.
|
|
38
|
+
*/
|
|
39
|
+
export interface QuoteDiagnostic {
|
|
40
|
+
readonly cause: QuoteRejection;
|
|
41
|
+
readonly evidenceIndex: number;
|
|
42
|
+
readonly evidenceCount: number;
|
|
43
|
+
readonly quoteChars?: number;
|
|
44
|
+
readonly quoteSha256?: string;
|
|
45
|
+
/** Longest leading part of the quote found in the log, and its line. */
|
|
46
|
+
readonly matchedPrefixChars?: number;
|
|
47
|
+
readonly matchedPrefixLine?: number;
|
|
48
|
+
/** Whether the quote would match after removing ANSI escapes from the log. */
|
|
49
|
+
readonly matchesWithoutAnsi?: boolean;
|
|
50
|
+
/** Whether the quote would match after collapsing whitespace runs in both. */
|
|
51
|
+
readonly matchesWithCollapsedWhitespace?: boolean;
|
|
52
|
+
}
|
|
53
|
+
|
|
33
54
|
export type ReceiptValidation =
|
|
34
55
|
| { readonly ok: true; readonly value: ValidatedReceipt }
|
|
35
|
-
| { readonly ok: false; readonly reason: string };
|
|
56
|
+
| { readonly ok: false; readonly reason: string; readonly quoteDiagnostic?: QuoteDiagnostic };
|
|
36
57
|
|
|
37
58
|
export function reducerInstructions(): string {
|
|
38
59
|
return [
|
|
@@ -74,6 +95,50 @@ function lineNumberOf(body: string, quote: string): number | undefined {
|
|
|
74
95
|
return line;
|
|
75
96
|
}
|
|
76
97
|
|
|
98
|
+
const ALLOWED_KINDS = new Set<EvidenceKind>(["fatal", "failure", "warning", "target", "summary"]);
|
|
99
|
+
const ANSI_ESCAPE = /\u001b\[[0-9;?]*[ -/]*[@-~]/gu;
|
|
100
|
+
|
|
101
|
+
function collapseWhitespace(value: string): string {
|
|
102
|
+
return value.replace(/\s+/gu, " ").trim();
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
function quoteRejection(kind: unknown, quote: unknown, body: string): QuoteRejection | undefined {
|
|
106
|
+
if (typeof kind !== "string" || !ALLOWED_KINDS.has(kind as EvidenceKind)) return "invalid-kind";
|
|
107
|
+
if (typeof quote !== "string") return "not-a-string";
|
|
108
|
+
if (quote.length < 1) return "empty";
|
|
109
|
+
if (quote.length > MAX_QUOTE_CHARS) return "too-long";
|
|
110
|
+
if (!body.includes(quote)) return "not-in-source";
|
|
111
|
+
return undefined;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
function quoteDiagnostic(
|
|
115
|
+
cause: QuoteRejection,
|
|
116
|
+
quote: unknown,
|
|
117
|
+
body: string,
|
|
118
|
+
evidenceIndex: number,
|
|
119
|
+
evidenceCount: number,
|
|
120
|
+
): QuoteDiagnostic {
|
|
121
|
+
const base = { cause, evidenceIndex, evidenceCount };
|
|
122
|
+
if (typeof quote !== "string") return base;
|
|
123
|
+
const sized = { ...base, quoteChars: quote.length, quoteSha256: sha256(quote) };
|
|
124
|
+
if (cause !== "not-in-source") return sized;
|
|
125
|
+
// Prefix presence is monotonic, so a binary search finds the longest one.
|
|
126
|
+
let found = 0;
|
|
127
|
+
let missing = quote.length;
|
|
128
|
+
while (missing - found > 1) {
|
|
129
|
+
const middle = Math.floor((found + missing) / 2);
|
|
130
|
+
if (body.includes(quote.slice(0, middle))) found = middle;
|
|
131
|
+
else missing = middle;
|
|
132
|
+
}
|
|
133
|
+
return {
|
|
134
|
+
...sized,
|
|
135
|
+
matchedPrefixChars: found,
|
|
136
|
+
matchedPrefixLine: found > 0 ? lineNumberOf(body, quote.slice(0, found)) : undefined,
|
|
137
|
+
matchesWithoutAnsi: body.replace(ANSI_ESCAPE, "").includes(quote),
|
|
138
|
+
matchesWithCollapsedWhitespace: collapseWhitespace(body).includes(collapseWhitespace(quote)),
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
|
|
77
142
|
/**
|
|
78
143
|
* Accept a receipt only when every claim in it can be checked against the
|
|
79
144
|
* archived log: right schema, right source hash, status that matches the
|
|
@@ -104,31 +169,29 @@ export function validateReceipt(
|
|
|
104
169
|
) {
|
|
105
170
|
return { ok: false, reason: "schema-mismatch" };
|
|
106
171
|
}
|
|
107
|
-
const allowedKinds = new Set<EvidenceKind>(["fatal", "failure", "warning", "target", "summary"]);
|
|
108
172
|
const evidence: VerifiedEvidence[] = [];
|
|
109
173
|
const seen = new Set<string>();
|
|
110
|
-
for (const item of evidenceValue) {
|
|
174
|
+
for (const [index, item] of evidenceValue.entries()) {
|
|
111
175
|
const kind = recordValue(item, "kind");
|
|
112
176
|
const quote = recordValue(item, "quote");
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
) {
|
|
121
|
-
return { ok: false, reason: "unverifiable-quote" };
|
|
177
|
+
const rejection = quoteRejection(kind, quote, body);
|
|
178
|
+
if (rejection !== undefined) {
|
|
179
|
+
return {
|
|
180
|
+
ok: false,
|
|
181
|
+
reason: "unverifiable-quote",
|
|
182
|
+
quoteDiagnostic: quoteDiagnostic(rejection, quote, body, index, evidenceValue.length),
|
|
183
|
+
};
|
|
122
184
|
}
|
|
123
185
|
const evidenceKind = kind as EvidenceKind;
|
|
124
|
-
const
|
|
186
|
+
const evidenceQuote = quote as string;
|
|
187
|
+
const key = `${evidenceKind}\0${evidenceQuote}`;
|
|
125
188
|
if (seen.has(key)) continue;
|
|
126
189
|
seen.add(key);
|
|
127
190
|
evidence.push({
|
|
128
191
|
kind: evidenceKind,
|
|
129
|
-
line: lineNumberOf(body,
|
|
130
|
-
quote,
|
|
131
|
-
quoteSha256: sha256(
|
|
192
|
+
line: lineNumberOf(body, evidenceQuote),
|
|
193
|
+
quote: evidenceQuote,
|
|
194
|
+
quoteSha256: sha256(evidenceQuote),
|
|
132
195
|
});
|
|
133
196
|
}
|
|
134
197
|
// A failing log that reads as a failure must carry failure evidence, or the
|
|
@@ -10,8 +10,8 @@
|
|
|
10
10
|
"@juicesharp/rpiv-ask-user-question": "2.6.2",
|
|
11
11
|
"@narumitw/pi-goal": "0.54.4-rotom.8",
|
|
12
12
|
"pi-context-view": "0.7.1",
|
|
13
|
-
"pi-subagents": "0.52.1-rotom.
|
|
14
|
-
"sol-pi": "0.1.0-rotom.
|
|
13
|
+
"pi-subagents": "0.52.1-rotom.10",
|
|
14
|
+
"sol-pi": "0.1.0-rotom.2"
|
|
15
15
|
}
|
|
16
16
|
},
|
|
17
17
|
"node_modules/@injaneity/pi-computer-use": {
|
|
@@ -142,9 +142,9 @@
|
|
|
142
142
|
}
|
|
143
143
|
},
|
|
144
144
|
"node_modules/pi-subagents": {
|
|
145
|
-
"version": "0.52.1-rotom.
|
|
146
|
-
"resolved": "file:vendor/pi-subagents-0.52.1-rotom.
|
|
147
|
-
"integrity": "sha512-
|
|
145
|
+
"version": "0.52.1-rotom.10",
|
|
146
|
+
"resolved": "file:vendor/pi-subagents-0.52.1-rotom.10.tgz",
|
|
147
|
+
"integrity": "sha512-5mXSC3zXponiWE+NP16rJ4zo1j1mHS04bbFO+fOc31RVVHA8rKvZ3nvemDOHT9qCBqINAiRcXJuhpZCNNNeoHg==",
|
|
148
148
|
"license": "MIT",
|
|
149
149
|
"dependencies": {
|
|
150
150
|
"acorn": "8.18.0",
|
|
@@ -177,9 +177,9 @@
|
|
|
177
177
|
}
|
|
178
178
|
},
|
|
179
179
|
"node_modules/sol-pi": {
|
|
180
|
-
"version": "0.1.0-rotom.
|
|
181
|
-
"resolved": "file:vendor/sol-pi-0.1.0-rotom.
|
|
182
|
-
"integrity": "sha512-
|
|
180
|
+
"version": "0.1.0-rotom.2",
|
|
181
|
+
"resolved": "file:vendor/sol-pi-0.1.0-rotom.2.tgz",
|
|
182
|
+
"integrity": "sha512-9SOaxYtxnfbnU+IByPpz8dmk95eDsGs4dvi1sq9i2g3VrGxIok0sGatlhPLhiOUgETWZyRBtRHULCm+yZiOu2g==",
|
|
183
183
|
"license": "MIT",
|
|
184
184
|
"engines": {
|
|
185
185
|
"node": ">=22.19.0"
|