@cueloop/schema 0.1.0-alpha.14 → 0.1.0-alpha.16
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 +1 -1
- package/src/feedback.test.ts +19 -0
- package/src/feedback.ts +7 -5
- package/src/types.ts +16 -0
package/package.json
CHANGED
package/src/feedback.test.ts
CHANGED
|
@@ -98,6 +98,25 @@ describe("renderFeedback", () => {
|
|
|
98
98
|
expect(out).toContain("_No edits or annotations._");
|
|
99
99
|
});
|
|
100
100
|
|
|
101
|
+
test("agent notes never come back as feedback items", () => {
|
|
102
|
+
const note = ann({
|
|
103
|
+
kind: "note",
|
|
104
|
+
anchor: { quote: "src/a.ts", prefix: "", suffix: "" },
|
|
105
|
+
body: "The agent's own explanation of the change.",
|
|
106
|
+
});
|
|
107
|
+
const noteOnly = renderFeedback({ verdictKind: "approve", summary: "", artifactContent: PLAN, annotations: [note] });
|
|
108
|
+
expect(noteOnly).toContain("_No edits or annotations._");
|
|
109
|
+
expect(noteOnly).not.toContain("The agent's own explanation of the change.");
|
|
110
|
+
const mixed = renderFeedback({
|
|
111
|
+
verdictKind: "request_changes",
|
|
112
|
+
summary: "",
|
|
113
|
+
artifactContent: PLAN,
|
|
114
|
+
annotations: [note, ann({ anchor: { quote: "one JSON document", prefix: "written as ", suffix: " per session." } })],
|
|
115
|
+
});
|
|
116
|
+
expect(mixed).toContain("## Annotations (1)");
|
|
117
|
+
expect(mixed).not.toContain("The agent's own explanation of the change.");
|
|
118
|
+
});
|
|
119
|
+
|
|
101
120
|
test("anchors resolve against the working copy when present", () => {
|
|
102
121
|
// annotation made on text that only exists in the edited copy
|
|
103
122
|
const working = PLAN.replace("## Storage", "## Persistence");
|
package/src/feedback.ts
CHANGED
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* first, then every annotation is addressed, located by quoted text.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import type
|
|
8
|
+
import { isAgentNote, type Annotation, type ReviewSession, type VerdictKind } from "./types";
|
|
9
9
|
import { parseBlocks, sectionOf } from "./markdown";
|
|
10
10
|
import { resolveAnchor } from "./anchor";
|
|
11
11
|
import { unifiedDiffText } from "./diff";
|
|
@@ -26,6 +26,8 @@ const quoteLines = (s: string) => "> " + s.replace(/\n/g, "\n> ");
|
|
|
26
26
|
|
|
27
27
|
export function renderFeedback(input: FeedbackInput): string {
|
|
28
28
|
const path = input.planPath ?? "plan.md";
|
|
29
|
+
// agent notes are the submitter's own context - never echoed back as feedback
|
|
30
|
+
const annotations = input.annotations.filter((annotation) => !isAgentNote(annotation));
|
|
29
31
|
const blocks = parseBlocks(input.workingCopy ?? input.artifactContent);
|
|
30
32
|
const lines: string[] = [];
|
|
31
33
|
lines.push("# Review: " + input.verdictKind.replace("_", " "));
|
|
@@ -49,12 +51,12 @@ export function renderFeedback(input: FeedbackInput): string {
|
|
|
49
51
|
lines.push("");
|
|
50
52
|
}
|
|
51
53
|
|
|
52
|
-
if (
|
|
53
|
-
lines.push(`## Annotations (${
|
|
54
|
+
if (annotations.length) {
|
|
55
|
+
lines.push(`## Annotations (${annotations.length})`);
|
|
54
56
|
lines.push("");
|
|
55
57
|
lines.push(`Address every item. Locate each one in ${path} by its quoted text.`);
|
|
56
58
|
lines.push("");
|
|
57
|
-
|
|
59
|
+
annotations.forEach((a, i) => {
|
|
58
60
|
const res = resolveAnchor(a.anchor, blocks);
|
|
59
61
|
const sec = res ? sectionOf(blocks, res.blockIndex) : "";
|
|
60
62
|
const loc = sec ? ` (§ ${sec})` : "";
|
|
@@ -77,7 +79,7 @@ export function renderFeedback(input: FeedbackInput): string {
|
|
|
77
79
|
});
|
|
78
80
|
}
|
|
79
81
|
|
|
80
|
-
if (!diff && !
|
|
82
|
+
if (!diff && !annotations.length) {
|
|
81
83
|
lines.push("_No edits or annotations._");
|
|
82
84
|
lines.push("");
|
|
83
85
|
}
|
package/src/types.ts
CHANGED
|
@@ -54,6 +54,16 @@ export interface Anchor {
|
|
|
54
54
|
/** The annotation kind set is open (map #2); these are the built-ins. */
|
|
55
55
|
export type AnnotationKind = "comment" | "suggestion" | (string & {});
|
|
56
56
|
|
|
57
|
+
/**
|
|
58
|
+
* Agent-authored context, not reviewer feedback: the guided walk's per-file
|
|
59
|
+
* notes (kind "note", anchored by the file path). Excluded from the feedback
|
|
60
|
+
* document and the reviewer's pending counts - an agent must never receive
|
|
61
|
+
* its own notes back as items to address.
|
|
62
|
+
*/
|
|
63
|
+
export function isAgentNote(annotation: Pick<Annotation, "kind">): boolean {
|
|
64
|
+
return annotation.kind === "note";
|
|
65
|
+
}
|
|
66
|
+
|
|
57
67
|
export interface Annotation {
|
|
58
68
|
id: string;
|
|
59
69
|
kind: AnnotationKind;
|
|
@@ -97,6 +107,12 @@ export interface ReviewSession {
|
|
|
97
107
|
* Undefined = no direct edits.
|
|
98
108
|
*/
|
|
99
109
|
workingCopy?: string;
|
|
110
|
+
/**
|
|
111
|
+
* File paths the reviewer marked viewed during the guided walk (diff
|
|
112
|
+
* sessions). Persisting with the session means a resumed review keeps its
|
|
113
|
+
* progress. Undefined = the walk never started.
|
|
114
|
+
*/
|
|
115
|
+
viewedPaths?: string[];
|
|
100
116
|
verdict: Verdict | null;
|
|
101
117
|
status: SessionStatus;
|
|
102
118
|
createdAt: string;
|