@lmzhen/dsh-evolution-review 0.4.0 → 0.4.1

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/lib/index.js CHANGED
@@ -213,7 +213,7 @@ function apply(ctx, rawConfig = {}) {
213
213
  return;
214
214
  }
215
215
  if (event.type !== "turn/end") return;
216
- if (turnStarts.size >= COUNTER_SWEEP_THRESHOLD || cumulativeToolCalls.size >= COUNTER_SWEEP_THRESHOLD || completionInjected.size >= COUNTER_SWEEP_THRESHOLD || pendingCadenceReviews.size >= COUNTER_SWEEP_THRESHOLD || skipNextCadenceFire.size >= COUNTER_SWEEP_THRESHOLD || cadenceResetWarned.size >= COUNTER_SWEEP_THRESHOLD || lastTurnStart.size >= COUNTER_SWEEP_THRESHOLD) {
216
+ if (turnStarts.size >= COUNTER_SWEEP_THRESHOLD || pendingCadenceWarned.size >= COUNTER_SWEEP_THRESHOLD || cumulativeToolCalls.size >= COUNTER_SWEEP_THRESHOLD || completionInjected.size >= COUNTER_SWEEP_THRESHOLD || pendingCadenceReviews.size >= COUNTER_SWEEP_THRESHOLD || skipNextCadenceFire.size >= COUNTER_SWEEP_THRESHOLD || cadenceResetWarned.size >= COUNTER_SWEEP_THRESHOLD || lastTurnStart.size >= COUNTER_SWEEP_THRESHOLD) {
217
217
  const isAlive = (id) => ctx.agents.get(id) !== void 0;
218
218
  sweepDeadSessionEntries(turnStarts, isAlive);
219
219
  sweepDeadSessionEntries(lastTurnStart, isAlive);
@@ -1113,24 +1113,56 @@ function resultCallIdOf(event) {
1113
1113
  return null;
1114
1114
  }
1115
1115
  /**
1116
- * V10-10 (P2-11): render one `[result]` evidence line from a tool-result
1117
- * event payload. The former read (`data.output`) targeted a field that does
1118
- * not exist on the upstream rc.2 payload, so EVERY result line rendered an
1119
- * empty payload and the review subagent never saw tool output — the evidence
1120
- * chain silently starved while still spending its line budget. The payload
1121
- * text now comes from `data.message.content` tool-result blocks (inner text
1122
- * blocks joined, mirroring the user/assistant rendering above). A failure is
1123
- * marked by the payload-level `error` OR a block-level `isError`. The legacy
1124
- * pre-rc.2 shape (no `message`) is tolerated as an empty payload it never
1125
- * throws. Budget: 500 chars per line (the 12-line cap lives in
1126
- * buildReviewRequest and is unchanged).
1116
+ * V10-10 (P2-11) / A1 (audit P1-1): render one `[result]` evidence line from
1117
+ * a tool-result event payload. The former read (`data.output`) targeted a
1118
+ * field that does not exist on the rc.2 payload; the current contract covers
1119
+ * BOTH rc.2 result shapes:
1120
+ * - native `tool/result`: the outcome lives in `message.content`
1121
+ * tool-result blocks (inner text blocks joined); a failure is marked by
1122
+ * the payload-level `error` OR a block-level `isError`;
1123
+ * - PTC `tool/ptc-dispatch` settle: the outcome lives at the TOP level
1124
+ * `content` is the logged ContentBlock list and `isError` the flag; there
1125
+ * is no `message` wrapper. (Before A1 this shape rendered an empty line,
1126
+ * so every PTC session's evidence block starved while its plan prompt
1127
+ * still demanded evidence.)
1128
+ * The legacy pre-rc.2 shape (neither `message` nor a PTC settle marker) is
1129
+ * tolerated as an empty payload — it never throws. `identity`, when given, is
1130
+ * the dispatched tool's name + raw arguments, prepended so a settled dispatch
1131
+ * keeps the call identity its `[call]` line would have had. Budget: 500 chars
1132
+ * per line (the 12-line cap lives in buildReviewRequest and is unchanged).
1127
1133
  */
1128
- function renderToolResultLine(data) {
1134
+ function renderToolResultLine(data, identity) {
1129
1135
  const shape = data;
1130
- const content = shape?.message?.content;
1131
- const resultBlocks = (Array.isArray(content) ? content : []).filter((block) => block.type === "tool-result");
1132
- const output = resultBlocks.map((block) => Array.isArray(block.content) ? block.content.map((inner) => inner.type === "text" && typeof inner.text === "string" ? inner.text : "").join(" ") : typeof block.text === "string" ? block.text : "").join(" ").trim();
1133
- return `[result]${shape?.error || resultBlocks.some((block) => block.isError === true) ? " [ERROR]" : ""} ${output.slice(0, 500)}`;
1136
+ const nativeContent = shape?.message?.content;
1137
+ const resultBlocks = Array.isArray(nativeContent) ? nativeContent.filter((block) => block.type === "tool-result") : [];
1138
+ let output;
1139
+ let failed;
1140
+ if (shape?.message !== void 0) {
1141
+ output = resultBlocks.map((block) => Array.isArray(block.content) ? block.content.map((inner) => inner.type === "text" && typeof inner.text === "string" ? inner.text : "").join(" ") : typeof block.text === "string" ? block.text : "").join(" ").trim();
1142
+ failed = Boolean(shape.error) || resultBlocks.some((block) => block.isError === true);
1143
+ } else if (typeof shape?.subCallId === "string" && typeof shape.isError === "boolean") {
1144
+ output = textOfLoggedContent(shape.content);
1145
+ failed = shape.isError;
1146
+ } else {
1147
+ output = "";
1148
+ failed = false;
1149
+ }
1150
+ const head = identity === void 0 ? "" : `${identity.name} ${identity.argsRaw.slice(0, 200)} → `;
1151
+ return `[result]${failed ? " [ERROR]" : ""} ${head}${output.slice(0, 500)}`;
1152
+ }
1153
+ /** Text of a PTC settle `content` payload (the logged ContentBlock list):
1154
+ * text blocks and plain strings joined, anything else skipped. */
1155
+ function textOfLoggedContent(content) {
1156
+ if (typeof content === "string") return content.trim();
1157
+ if (!Array.isArray(content)) return "";
1158
+ return content.map((block) => {
1159
+ if (typeof block === "string") return block;
1160
+ if (block !== null && typeof block === "object") {
1161
+ const candidate = block;
1162
+ if (candidate.type === "text" && typeof candidate.text === "string") return candidate.text;
1163
+ }
1164
+ return "";
1165
+ }).join(" ").trim();
1134
1166
  }
1135
1167
  /**
1136
1168
  * PLAN S4.1 (2026-09-16, audit P2-12): text of one persisted content block,
@@ -1157,6 +1189,17 @@ function buildReviewRequest(session, kind, signal, maxMessages, maxMessageChars)
1157
1189
  }
1158
1190
  const toolLines = [];
1159
1191
  const events = session.snapshotEvents();
1192
+ const callIdentity = /* @__PURE__ */ new Map();
1193
+ const identityWindowStart = Math.max(0, events.length - 2e3);
1194
+ for (let index = events.length - 1; index >= identityWindowStart; index -= 1) {
1195
+ const event = events[index];
1196
+ const opened = readDispatchSignal(event);
1197
+ if (opened === null || callIdentity.has(opened.callId)) continue;
1198
+ callIdentity.set(opened.callId, {
1199
+ name: opened.name,
1200
+ argsRaw: typeof opened.arguments === "string" ? opened.arguments : JSON.stringify(opened.arguments ?? {})
1201
+ });
1202
+ }
1160
1203
  const openedCallIds = /* @__PURE__ */ new Set();
1161
1204
  for (let index = events.length - 1; index >= 0 && toolLines.length < 12; index -= 1) {
1162
1205
  const event = events[index];
@@ -1164,7 +1207,13 @@ function buildReviewRequest(session, kind, signal, maxMessages, maxMessageChars)
1164
1207
  if (answeredCallId !== null) {
1165
1208
  if (openedCallIds.has(answeredCallId)) continue;
1166
1209
  openedCallIds.add(answeredCallId);
1167
- toolLines.push(renderToolResultLine(event?.data));
1210
+ const rawSettle = event?.data;
1211
+ const settleData = rawSettle !== null && typeof rawSettle === "object" ? rawSettle : void 0;
1212
+ const identity = settleData !== void 0 && typeof settleData.name === "string" && settleData.name !== "" ? {
1213
+ name: settleData.name,
1214
+ argsRaw: typeof settleData.arguments === "string" ? settleData.arguments : JSON.stringify(settleData.arguments ?? {})
1215
+ } : callIdentity.get(answeredCallId);
1216
+ toolLines.push(renderToolResultLine(event?.data, identity));
1168
1217
  continue;
1169
1218
  }
1170
1219
  const opened = readDispatchSignal(event);
@@ -151,19 +151,28 @@ export declare function filterUnreadSkillOps(ops: Array<{
151
151
  name?: string;
152
152
  }>, readNames: ReadonlySet<string>): number;
153
153
  /**
154
- * V10-10 (P2-11): render one `[result]` evidence line from a tool-result
155
- * event payload. The former read (`data.output`) targeted a field that does
156
- * not exist on the upstream rc.2 payload, so EVERY result line rendered an
157
- * empty payload and the review subagent never saw tool output — the evidence
158
- * chain silently starved while still spending its line budget. The payload
159
- * text now comes from `data.message.content` tool-result blocks (inner text
160
- * blocks joined, mirroring the user/assistant rendering above). A failure is
161
- * marked by the payload-level `error` OR a block-level `isError`. The legacy
162
- * pre-rc.2 shape (no `message`) is tolerated as an empty payload it never
163
- * throws. Budget: 500 chars per line (the 12-line cap lives in
164
- * buildReviewRequest and is unchanged).
154
+ * V10-10 (P2-11) / A1 (audit P1-1): render one `[result]` evidence line from
155
+ * a tool-result event payload. The former read (`data.output`) targeted a
156
+ * field that does not exist on the rc.2 payload; the current contract covers
157
+ * BOTH rc.2 result shapes:
158
+ * - native `tool/result`: the outcome lives in `message.content`
159
+ * tool-result blocks (inner text blocks joined); a failure is marked by
160
+ * the payload-level `error` OR a block-level `isError`;
161
+ * - PTC `tool/ptc-dispatch` settle: the outcome lives at the TOP level
162
+ * `content` is the logged ContentBlock list and `isError` the flag; there
163
+ * is no `message` wrapper. (Before A1 this shape rendered an empty line,
164
+ * so every PTC session's evidence block starved while its plan prompt
165
+ * still demanded evidence.)
166
+ * The legacy pre-rc.2 shape (neither `message` nor a PTC settle marker) is
167
+ * tolerated as an empty payload — it never throws. `identity`, when given, is
168
+ * the dispatched tool's name + raw arguments, prepended so a settled dispatch
169
+ * keeps the call identity its `[call]` line would have had. Budget: 500 chars
170
+ * per line (the 12-line cap lives in buildReviewRequest and is unchanged).
165
171
  */
166
- export declare function renderToolResultLine(data: unknown): string;
172
+ export declare function renderToolResultLine(data: unknown, identity?: {
173
+ name: string;
174
+ argsRaw: string;
175
+ }): string;
167
176
  export declare function buildReviewRequest(session: Session, kind: ReviewKind, signal: {
168
177
  toolCalls: number;
169
178
  userChars: number;
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@lmzhen/dsh-evolution-review",
3
3
  "description": "Background review orchestration (community build)",
4
- "version": "0.4.0",
4
+ "version": "0.4.1",
5
5
  "publishConfig": {
6
6
  "access": "public"
7
7
  },
@@ -27,9 +27,9 @@
27
27
  "license": "MIT",
28
28
  "dependencies": {
29
29
  "@deepseek-ai/schemastery": "^3.18.1",
30
- "@lmzhen/dsh-evolution-approval": "^0.4.0",
31
- "@lmzhen/dsh-evolution-core": "^0.4.0",
32
- "@lmzhen/dsh-evolution-plan-validator": "^0.4.0"
30
+ "@lmzhen/dsh-evolution-approval": "^0.4.1",
31
+ "@lmzhen/dsh-evolution-core": "^0.4.1",
32
+ "@lmzhen/dsh-evolution-plan-validator": "^0.4.1"
33
33
  },
34
34
  "peerDependencies": {
35
35
  "@deepseek-ai/cordis": "^4.0.1",
@@ -37,8 +37,8 @@
37
37
  "@deepseek-ai/dsh-llm": "^0.1.5-rc.2",
38
38
  "@deepseek-ai/dsh-session": "^0.1.5-rc.2",
39
39
  "@deepseek-ai/dsh-tools": "^0.1.5-rc.2",
40
- "@lmzhen/dsh-evolution-state": "^0.4.0",
41
- "@lmzhen/dsh-evolution-policy": "^0.4.0"
40
+ "@lmzhen/dsh-evolution-state": "^0.4.1",
41
+ "@lmzhen/dsh-evolution-policy": "^0.4.1"
42
42
  },
43
43
  "devDependencies": {
44
44
  "@deepseek-ai/dsh-agent": "^0.1.5-rc.2",
@@ -48,10 +48,10 @@
48
48
  "@deepseek-ai/dsh-session-persistence": "^0.1.5-rc.2",
49
49
  "@deepseek-ai/dsh-session-persistence-jsonl": "^0.1.5-rc.2",
50
50
  "@deepseek-ai/dsh-tools": "^0.1.5-rc.2",
51
- "@lmzhen/dsh-evolution-approval": "^0.4.0",
52
- "@lmzhen/dsh-evolution-core": "^0.4.0",
53
- "@lmzhen/dsh-evolution-curator": "^0.4.0",
54
- "@lmzhen/dsh-evolution-plan-validator": "^0.4.0",
55
- "@lmzhen/dsh-evolution-state": "^0.4.0"
51
+ "@lmzhen/dsh-evolution-approval": "^0.4.1",
52
+ "@lmzhen/dsh-evolution-core": "^0.4.1",
53
+ "@lmzhen/dsh-evolution-curator": "^0.4.1",
54
+ "@lmzhen/dsh-evolution-plan-validator": "^0.4.1",
55
+ "@lmzhen/dsh-evolution-state": "^0.4.1"
56
56
  }
57
57
  }