@zhushanwen/pi-canvas 0.4.2 → 0.4.3
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/package.json +3 -3
- package/src/__tests__/review.test.ts +27 -3
- package/src/render.ts +4 -11
- package/src/review.ts +7 -5
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@zhushanwen/pi-canvas",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.3",
|
|
4
4
|
"description": "Problem-solving canvas toolface for pi: six deferred canvas_* tools bridging the agent to the taiji runtime CanvasService via the CANVAS_MARKER select channel (problem-solve-canvas)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "index.ts",
|
|
@@ -55,10 +55,10 @@
|
|
|
55
55
|
"vitest": "^4.1.8"
|
|
56
56
|
},
|
|
57
57
|
"dependencies": {
|
|
58
|
-
"@zhushanwen/pi-ext-guards": "0.5.0",
|
|
59
58
|
"@zhushanwen/extension-protocol": "0.23.0",
|
|
59
|
+
"@zhushanwen/pi-ext-guards": "0.5.0",
|
|
60
60
|
"@zhushanwen/pi-extension-logger": "0.6.2",
|
|
61
|
-
"@zhushanwen/subagent-core": "2.0.
|
|
61
|
+
"@zhushanwen/subagent-core": "2.0.1"
|
|
62
62
|
},
|
|
63
63
|
"scripts": {
|
|
64
64
|
"typecheck": "npx tsc --noEmit",
|
|
@@ -251,8 +251,9 @@ describe("runReviewRound(编排主体)", () => {
|
|
|
251
251
|
});
|
|
252
252
|
expect(outcome.round).toBe(1);
|
|
253
253
|
expect(capturedTask).toContain("R1 全面审查");
|
|
254
|
-
//
|
|
255
|
-
|
|
254
|
+
// 零发现轮也写回(空 entries 的 review-append):写回本身是「本轮 run 已完成」的
|
|
255
|
+
// 落盘事实(runtime lastRunRound),缺它轮次永不推进、maxRounds 预算不消耗
|
|
256
|
+
expect(append.calls).toEqual([{ canvasId: "c1", round: 1, entries: [] }]);
|
|
256
257
|
});
|
|
257
258
|
|
|
258
259
|
it("R2 run(runtime 已推进 round=2)→ 报告标 R2,scope 收窄 + 上轮处置表进 task", async () => {
|
|
@@ -281,7 +282,30 @@ describe("runReviewRound(编排主体)", () => {
|
|
|
281
282
|
expect(capturedTask).toContain("R2 复审");
|
|
282
283
|
expect(capturedTask).toContain("只审处置表");
|
|
283
284
|
expect(capturedTask).toContain("[rv-1]");
|
|
284
|
-
expect(append.calls).
|
|
285
|
+
expect(append.calls).toEqual([{ canvasId: "c1", round: 2, entries: [] }]);
|
|
286
|
+
});
|
|
287
|
+
|
|
288
|
+
it("全 dropped(reviewer 条目全畸形被丢弃)→ 同样以空 entries 写回(零发现轮 = 完成轮,事实照常落盘)", async () => {
|
|
289
|
+
const append = makeAppend();
|
|
290
|
+
const dispatch: ReviewerDispatchPort = {
|
|
291
|
+
executeAndAwait: async () => ({
|
|
292
|
+
parsedOutput: {
|
|
293
|
+
entries: [
|
|
294
|
+
{ id: "rv-x", dimension: "style", severity: "must-fix", targetId: "n1", note: "词表外维度" },
|
|
295
|
+
"not-an-object",
|
|
296
|
+
],
|
|
297
|
+
},
|
|
298
|
+
}),
|
|
299
|
+
};
|
|
300
|
+
const outcome = await runReviewRound({
|
|
301
|
+
state: makeState(),
|
|
302
|
+
dispatch,
|
|
303
|
+
appendWriteBack: append.append,
|
|
304
|
+
});
|
|
305
|
+
expect(outcome.appended).toBe(0);
|
|
306
|
+
expect(outcome.dropped).toBe(2);
|
|
307
|
+
expect(outcome.summary).toContain("写回 0 条");
|
|
308
|
+
expect(append.calls).toEqual([{ canvasId: "c1", round: 1, entries: [] }]);
|
|
285
309
|
});
|
|
286
310
|
|
|
287
311
|
it("reviewer 执行失败(error 信封)→ 显式 throw(review_dispatch_failed + 恢复动作)", async () => {
|
package/src/render.ts
CHANGED
|
@@ -5,19 +5,12 @@
|
|
|
5
5
|
*/
|
|
6
6
|
import type { Theme } from "@earendil-works/pi-coding-agent";
|
|
7
7
|
import { Text } from "@earendil-works/pi-tui";
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
/** pi toolResult 通用形状(AgentToolResult 的结构最小面,renderResult 入参收窄用)。 */
|
|
11
|
-
interface ToolResultShape { // oe-exempt:20261017:framework:details 数据形状窄 view(单实现消费,非抽象接口)
|
|
12
|
-
content: Array<{ type: string; text?: string }>;
|
|
13
|
-
details?: { summary?: unknown };
|
|
14
|
-
}
|
|
8
|
+
import { readDetailsSummary, resultContentText } from "@zhushanwen/extension-protocol";
|
|
15
9
|
|
|
16
10
|
export function renderCanvasToolResult(result: unknown, options: { expanded: boolean }, theme: Theme): Text {
|
|
17
|
-
const
|
|
18
|
-
|
|
19
|
-
if (options.expanded === false && typeof summary === "string" && summary !== "") {
|
|
11
|
+
const summary = readDetailsSummary(result);
|
|
12
|
+
if (options.expanded === false && summary !== undefined) {
|
|
20
13
|
return new Text(theme.fg("dim", summary), 0, 0);
|
|
21
14
|
}
|
|
22
|
-
return new Text(
|
|
15
|
+
return new Text(resultContentText(result), 0, 0);
|
|
23
16
|
}
|
package/src/review.ts
CHANGED
|
@@ -125,8 +125,9 @@ export function isCanvasStateReply(v: unknown): v is CanvasState {
|
|
|
125
125
|
}
|
|
126
126
|
|
|
127
127
|
/** 本轮审查轮次:run 链路的 read 发生在 review-request 之后,review.round 已是本轮
|
|
128
|
-
* 轮次(runtime 侧一轮 =
|
|
129
|
-
*
|
|
128
|
+
* 轮次(runtime 侧一轮 = 一循环:当前轮无报告写回时再发起不推进轮次——GUI 双跳的
|
|
129
|
+
* 第二跳与重发都不虚增轮次;零发现轮的写回也算完成);从未审查(read 无 review
|
|
130
|
+
* 聚合)= R1。 */
|
|
130
131
|
export function currentReviewRound(state: CanvasState): number {
|
|
131
132
|
return state.review?.round ?? 1;
|
|
132
133
|
}
|
|
@@ -218,9 +219,10 @@ export async function runReviewRound(input: {
|
|
|
218
219
|
);
|
|
219
220
|
}
|
|
220
221
|
const { entries, dropped } = collectValidEntries(input.state.canvasId, round, result.parsedOutput ?? result.content);
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
222
|
+
// 零发现轮也写回(空 entries 的 review-append):写回本身就是「本轮 run 已完成」的
|
|
223
|
+
// 落盘事实(runtime 侧落 review.lastRunRound),跳过会使零发现轮永不推进轮次、
|
|
224
|
+
// maxRounds 预算永不消耗(max-rounds 停回保护对该形态失灵)。
|
|
225
|
+
await input.appendWriteBack({ canvasId: input.state.canvasId, round, entries });
|
|
224
226
|
const parsedSummary = recordOf(result.parsedOutput)?.summary;
|
|
225
227
|
const summary =
|
|
226
228
|
(typeof parsedSummary === "string" ? parsedSummary : "") ||
|