@pellux/goodvibes-sdk 0.33.18 → 0.33.20

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.
@@ -3,7 +3,7 @@
3
3
  "product": {
4
4
  "id": "goodvibes",
5
5
  "surface": "operator",
6
- "version": "0.33.18"
6
+ "version": "0.33.20"
7
7
  },
8
8
  "auth": {
9
9
  "modes": [
@@ -1 +1 @@
1
- {"version":3,"file":"completion-report.d.ts","sourceRoot":"","sources":["../../../src/platform/agents/completion-report.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"completion-report.d.ts","sourceRoot":"","sources":["../../../src/platform/agents/completion-report.ts"],"names":[],"mappings":"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"}
@@ -10,16 +10,46 @@ function isWellFormedConstraint(c) {
10
10
  typeof obj['text'] === 'string' && obj['text'].length > 0 &&
11
11
  obj['source'] === 'prompt');
12
12
  }
13
- /** Returns true if a ConstraintFinding entry is well-formed. */
14
- function isWellFormedConstraintFinding(f) {
13
+ function evidenceToString(evidence) {
14
+ if (typeof evidence === 'string') {
15
+ const trimmed = evidence.trim();
16
+ return trimmed.length > 0 ? trimmed : null;
17
+ }
18
+ if (typeof evidence === 'number' || typeof evidence === 'boolean') {
19
+ return String(evidence);
20
+ }
21
+ if (Array.isArray(evidence) || (typeof evidence === 'object' && evidence !== null)) {
22
+ try {
23
+ const serialized = JSON.stringify(evidence);
24
+ return serialized.length > 0 && serialized !== 'null' ? serialized : null;
25
+ }
26
+ catch {
27
+ return null;
28
+ }
29
+ }
30
+ return null;
31
+ }
32
+ /** Normalizes a ConstraintFinding entry, tolerating common model evidence shapes. */
33
+ function normalizeConstraintFinding(f) {
15
34
  if (typeof f !== 'object' || f === null)
16
- return false;
35
+ return null;
17
36
  const obj = f;
18
37
  const severity = obj['severity'];
19
- return (typeof obj['constraintId'] === 'string' && obj['constraintId'].length > 0 &&
20
- typeof obj['satisfied'] === 'boolean' &&
21
- typeof obj['evidence'] === 'string' && obj['evidence'].length > 0 &&
22
- (severity === undefined || severity === 'critical' || severity === 'major' || severity === 'minor'));
38
+ const evidence = evidenceToString(obj['evidence']);
39
+ if (typeof obj['constraintId'] !== 'string' || obj['constraintId'].length === 0 ||
40
+ typeof obj['satisfied'] !== 'boolean' ||
41
+ evidence === null) {
42
+ return null;
43
+ }
44
+ const finding = {
45
+ constraintId: obj['constraintId'],
46
+ satisfied: obj['satisfied'],
47
+ evidence,
48
+ };
49
+ if (severity === 'critical' || severity === 'major' || severity === 'minor') {
50
+ finding.severity = severity;
51
+ }
52
+ return finding;
23
53
  }
24
54
  function filterWellFormed(raw, guard) {
25
55
  if (raw === undefined)
@@ -38,6 +68,24 @@ function filterWellFormed(raw, guard) {
38
68
  }
39
69
  return { items, dropped, malformedContainer: false };
40
70
  }
71
+ function normalizeConstraintFindingList(raw) {
72
+ if (raw === undefined)
73
+ return { items: [], dropped: 0, malformedContainer: false };
74
+ if (!Array.isArray(raw))
75
+ return { items: [], dropped: 0, malformedContainer: true };
76
+ const items = [];
77
+ let dropped = 0;
78
+ for (const item of raw) {
79
+ const normalized = normalizeConstraintFinding(item);
80
+ if (normalized) {
81
+ items.push(normalized);
82
+ }
83
+ else {
84
+ dropped += 1;
85
+ }
86
+ }
87
+ return { items, dropped, malformedContainer: false };
88
+ }
41
89
  function appendEngineerIssue(report, issue) {
42
90
  const existing = Array.isArray(report['issues'])
43
91
  ? report['issues'].filter((item) => typeof item === 'string')
@@ -136,13 +184,13 @@ function applyConstraintDefaults(parsed) {
136
184
  }
137
185
  }
138
186
  if (next['archetype'] === 'reviewer') {
139
- const normalized = filterWellFormed(next['constraintFindings'], isWellFormedConstraintFinding);
187
+ const normalized = normalizeConstraintFindingList(next['constraintFindings']);
140
188
  next['constraintFindings'] = normalized.items;
141
189
  if (normalized.malformedContainer) {
142
- appendReviewerIssue(next, 'Malformed constraintFindings field ignored: expected an array.');
190
+ appendReviewerIssue(next, 'Malformed constraintFindings field ignored: expected an array of {constraintId:string,satisfied:boolean,evidence:string,severity?:critical|major|minor}.');
143
191
  }
144
192
  else if (normalized.dropped > 0) {
145
- appendReviewerIssue(next, `Malformed constraintFindings ignored: ${normalized.dropped} entr${normalized.dropped === 1 ? 'y' : 'ies'}.`);
193
+ appendReviewerIssue(next, `Malformed constraintFindings ignored: ${normalized.dropped} entr${normalized.dropped === 1 ? 'y' : 'ies'}; expected {constraintId:string,satisfied:boolean,evidence:string,severity?:critical|major|minor}.`);
146
194
  }
147
195
  }
148
196
  return next;
@@ -1 +1 @@
1
- {"version":3,"file":"wrfc-prompt-addenda.d.ts","sourceRoot":"","sources":["../../../src/platform/agents/wrfc-prompt-addenda.ts"],"names":[],"mappings":"AAAA,qFAAqF;AAerF,wBAAgB,+BAA+B,IAAI,MAAM,CAiCxD;AAGD;;;;;;;GAOG;AACH,wBAAgB,+BAA+B,IAAI,MAAM,CAqBxD;AAGD;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,IAAI,MAAM,CAgBrD"}
1
+ {"version":3,"file":"wrfc-prompt-addenda.d.ts","sourceRoot":"","sources":["../../../src/platform/agents/wrfc-prompt-addenda.ts"],"names":[],"mappings":"AAAA,qFAAqF;AAerF,wBAAgB,+BAA+B,IAAI,MAAM,CAiCxD;AAGD;;;;;;;GAOG;AACH,wBAAgB,+BAA+B,IAAI,MAAM,CAuCxD;AAGD;;;;;;;;GAQG;AACH,wBAAgB,4BAA4B,IAAI,MAAM,CAgBrD"}
@@ -67,6 +67,24 @@ The engineer's \`EngineerReport.constraints\` is the authoritative list of user-
67
67
  2. Cite concrete evidence — a file and line, a diff observation, or a test behavior. "Looks fine" is not evidence.
68
68
  3. Emit a \`constraintFindings[]\` entry referencing \`constraintId\`.
69
69
 
70
+ **Exact JSON shape required:**
71
+ \`\`\`json
72
+ {
73
+ "constraintFindings": [
74
+ {
75
+ "constraintId": "c1",
76
+ "satisfied": true,
77
+ "evidence": "Concrete proof as a single string.",
78
+ "severity": "major"
79
+ }
80
+ ]
81
+ }
82
+ \`\`\`
83
+
84
+ - \`constraintId\`, \`satisfied\`, and \`evidence\` are required.
85
+ - \`evidence\` must be a non-empty string, not an object or array.
86
+ - \`severity\` is optional and only valid as \`"critical"\`, \`"major"\`, or \`"minor"\`.
87
+
70
88
  **Severity rules for unsatisfied constraints**:
71
89
  - A violated hard limit (size, perf target, explicitly forbidden API) → **critical**.
72
90
  - A violated explicit user rule (style rules, naming conventions, required features) → **major**.
@@ -1,11 +1,15 @@
1
1
  import type { CompletionReport, Constraint, ConstraintFinding, ReviewerReport } from './completion-report.js';
2
2
  import type { QualityGateResult } from './wrfc-types.js';
3
+ type ReviewableCompletionReport = CompletionReport & {
4
+ reviewableOutput?: string | undefined;
5
+ };
3
6
  export declare function extractScoreFromText(text: string): number | null;
4
7
  export declare function extractPassedFromText(text: string, score: number, threshold: number): boolean;
5
8
  export declare function extractIssuesFromText(text: string): ReviewerReport['issues'];
6
- export declare function parseEngineerCompletionReport(rawOutput: string, _template?: string): CompletionReport;
9
+ export declare function parseEngineerCompletionReport(rawOutput: string, _template?: string): ReviewableCompletionReport;
7
10
  export declare function parseReviewerCompletionReport(chainId: string, rawOutput: string, threshold: number): ReviewerReport;
8
- export declare function buildReviewTask(chainId: string, originalTask: string, report: CompletionReport, threshold: number, constraints?: Constraint[]): string;
11
+ export declare function buildReviewTask(chainId: string, originalTask: string, report: ReviewableCompletionReport, threshold: number, constraints?: Constraint[]): string;
9
12
  export declare function buildFixTask(chainId: string, originalTask: string, review: ReviewerReport, threshold: number, fixAttempts: number, constraints?: Constraint[], constraintFindings?: ConstraintFinding[]): string;
10
13
  export declare function buildGateFailureTask(chainId: string, task: string, failedGates: readonly QualityGateResult[], constraints?: readonly Constraint[]): string;
14
+ export {};
11
15
  //# sourceMappingURL=wrfc-reporting.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"wrfc-reporting.d.ts","sourceRoot":"","sources":["../../../src/platform/agents/wrfc-reporting.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,iBAAiB,EAAkB,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAG9H,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAOzD,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAuBhE;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAK7F;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAAC,QAAQ,CAAC,CAa5E;AAED,wBAAgB,6BAA6B,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,gBAAgB,CAiBrG;AAED,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,cAAc,CA6BhB;AAID,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,gBAAgB,EACxB,SAAS,EAAE,MAAM,EACjB,WAAW,GAAE,UAAU,EAAO,GAC7B,MAAM,CAkDR;AA0FD,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,WAAW,GAAE,UAAU,EAAO,EAC9B,kBAAkB,GAAE,iBAAiB,EAAO,GAC3C,MAAM,CA6DR;AAED,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,SAAS,iBAAiB,EAAE,EACzC,WAAW,GAAE,SAAS,UAAU,EAAO,GACtC,MAAM,CAuCR"}
1
+ {"version":3,"file":"wrfc-reporting.d.ts","sourceRoot":"","sources":["../../../src/platform/agents/wrfc-reporting.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,UAAU,EAAE,iBAAiB,EAAkB,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAG9H,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AAQzD,KAAK,0BAA0B,GAAG,gBAAgB,GAAG;IACnD,gBAAgB,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACvC,CAAC;AAEF,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAuBhE;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAK7F;AAED,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,MAAM,GAAG,cAAc,CAAC,QAAQ,CAAC,CAa5E;AAED,wBAAgB,6BAA6B,CAAC,SAAS,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,0BAA0B,CAkB/G;AAED,wBAAgB,6BAA6B,CAC3C,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,MAAM,GAChB,cAAc,CA6BhB;AAID,wBAAgB,eAAe,CAC7B,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,0BAA0B,EAClC,SAAS,EAAE,MAAM,EACjB,WAAW,GAAE,UAAU,EAAO,GAC7B,MAAM,CAuDR;AAiGD,wBAAgB,YAAY,CAC1B,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,MAAM,EAAE,cAAc,EACtB,SAAS,EAAE,MAAM,EACjB,WAAW,EAAE,MAAM,EACnB,WAAW,GAAE,UAAU,EAAO,EAC9B,kBAAkB,GAAE,iBAAiB,EAAO,GAC3C,MAAM,CA6DR;AAED,wBAAgB,oBAAoB,CAClC,OAAO,EAAE,MAAM,EACf,IAAI,EAAE,MAAM,EACZ,WAAW,EAAE,SAAS,iBAAiB,EAAE,EACzC,WAAW,GAAE,SAAS,UAAU,EAAO,GACtC,MAAM,CAuCR"}
@@ -4,6 +4,7 @@ import { logger } from '../utils/logger.js';
4
4
  const REVIEW_BRIEF_ITEM_LIMIT = 6;
5
5
  const REVIEW_BRIEF_FILE_LIMIT = 8;
6
6
  const REVIEW_BRIEF_TEXT_LIMIT = 220;
7
+ const REVIEWABLE_OUTPUT_LIMIT = 16_000;
7
8
  export function extractScoreFromText(text) {
8
9
  const scorePattern = /\*{0,2}(?:overall\s+)?score\s*:?\s*\*{0,2}\s*(\d+(?:\.\d+)?)\s*\/\s*10/i;
9
10
  const matchScore = text.match(scorePattern);
@@ -54,11 +55,12 @@ export function extractIssuesFromText(text) {
54
55
  export function parseEngineerCompletionReport(rawOutput, _template) {
55
56
  const report = parseCompletionReport(rawOutput);
56
57
  if (report)
57
- return report;
58
+ return { ...report, reviewableOutput: rawOutput };
58
59
  return {
59
60
  version: 1,
60
61
  archetype: 'engineer',
61
62
  summary: rawOutput.slice(0, 500) || '(no output)',
63
+ reviewableOutput: rawOutput,
62
64
  gatheredContext: [],
63
65
  plannedActions: [],
64
66
  appliedChanges: [],
@@ -110,14 +112,18 @@ export function buildReviewTask(chainId, originalTask, report, threshold, constr
110
112
  `Engineer report digest:`,
111
113
  ...lines,
112
114
  ``,
115
+ `Engineer reviewable output (authoritative for non-file deliverables and no-write tasks):`,
116
+ formatReviewableOutput(report),
117
+ ``,
113
118
  `Instructions:`,
114
119
  `1. Review the complete current result against the original WRFC ask above. Do not narrow the review to the latest fix, files touched in the last child turn, or functions mentioned in the digest.`,
115
- `2. Read the referenced files directly before scoring. Do not rely on this digest alone.`,
116
- `3. Inspect the engineer's gatheredContext, plannedActions, appliedChanges, and decisions for discipline and coherence.`,
117
- `4. Verify the implementation meets all stated requirements and that prior passing behavior was not regressed by later fix loops.`,
118
- `5. Score the implementation using the 10-dimension review rubric.`,
119
- `6. The passing score threshold is ${threshold}/10.`,
120
- `7. Return a structured ReviewerReport JSON block in your final response.`,
120
+ `2. If the original ask requested a non-file deliverable or explicitly said not to write files, review the Engineer reviewable output as the deliverable. Do not fail only because no files exist.`,
121
+ `3. Read referenced files directly when files were created or modified. Do not rely on the digest alone for file-backed work.`,
122
+ `4. Inspect the engineer's gatheredContext, plannedActions, appliedChanges, decisions, and reviewable output for discipline and coherence.`,
123
+ `5. Verify the implementation meets all stated requirements and that prior passing behavior was not regressed by later fix loops.`,
124
+ `6. Score the implementation using the 10-dimension review rubric.`,
125
+ `7. The passing score threshold is ${threshold}/10.`,
126
+ `8. Return a structured ReviewerReport JSON block in your final response.`,
121
127
  ``,
122
128
  `The ReviewerReport must include:`,
123
129
  `- version: 1`,
@@ -126,6 +132,7 @@ export function buildReviewTask(chainId, originalTask, report, threshold, constr
126
132
  `- passed: <boolean>`,
127
133
  `- dimensions: array of { name, score, maxScore, issues[] }`,
128
134
  `- issues: array of { severity, description, file?, line?, pointValue }`,
135
+ `- constraintFindings: array of exactly { constraintId: string, satisfied: boolean, evidence: string, severity?: "critical" | "major" | "minor" }`,
129
136
  ];
130
137
  if (constraints.length === 0) {
131
138
  return base.join('\n');
@@ -151,6 +158,14 @@ function truncateReviewText(text, max = REVIEW_BRIEF_TEXT_LIMIT) {
151
158
  return normalized;
152
159
  return `${normalized.slice(0, max - 3)}...`;
153
160
  }
161
+ function formatReviewableOutput(report) {
162
+ const output = typeof report.reviewableOutput === 'string' ? report.reviewableOutput.trim() : '';
163
+ if (output.length === 0)
164
+ return '(no reviewable output recorded)';
165
+ if (output.length <= REVIEWABLE_OUTPUT_LIMIT)
166
+ return output;
167
+ return `${output.slice(0, REVIEWABLE_OUTPUT_LIMIT)}\n\n[truncated from ${output.length} characters; inspect agent fullOutput directly if more detail is required]`;
168
+ }
154
169
  function formatInlineList(items, limit) {
155
170
  if (items.length === 0)
156
171
  return 'none';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/platform/tools/agent/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAG7D,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAmB,YAAY,EAAE,MAAM,cAAc,CAAC;AAI7D,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAqB7D,wBAAgB,eAAe,CAAC,MAAM,EAAE;IACtC,OAAO,EAAE,YAAY,CAAC;IACtB,UAAU,EAAE,IAAI,CAAC,eAAe,EAAE,aAAa,GAAG,MAAM,CAAC,CAAC;IAC1D,cAAc,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,YAAY,CAAC,GAAG,SAAS,CAAC;IAChE,eAAe,CAAC,EAAE,IAAI,CAAC,eAAe,EAAE,eAAe,CAAC,GAAG,SAAS,CAAC;IACrE,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;CAC3C,GAAG,IAAI,CAkkBP"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/platform/tools/agent/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,sBAAsB,CAAC;AACjD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,yBAAyB,CAAC;AAG7D,OAAO,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAC7D,OAAO,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AAC9D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iCAAiC,CAAC;AACtE,OAAO,EAAmB,YAAY,EAAE,MAAM,cAAc,CAAC;AAK7D,YAAY,EAAE,aAAa,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAC/D,OAAO,EAAE,eAAe,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAqB7D,wBAAgB,eAAe,CAAC,MAAM,EAAE;IACtC,OAAO,EAAE,YAAY,CAAC;IACtB,UAAU,EAAE,IAAI,CAAC,eAAe,EAAE,aAAa,GAAG,MAAM,CAAC,CAAC;IAC1D,cAAc,CAAC,EAAE,IAAI,CAAC,cAAc,EAAE,YAAY,CAAC,GAAG,SAAS,CAAC;IAChE,eAAe,CAAC,EAAE,IAAI,CAAC,eAAe,EAAE,eAAe,CAAC,GAAG,SAAS,CAAC;IACrE,aAAa,EAAE,IAAI,CAAC,aAAa,EAAE,KAAK,CAAC,CAAC;CAC3C,GAAG,IAAI,CAwmBP"}
@@ -5,6 +5,7 @@ import { AGENT_TEMPLATES, AgentManager } from './manager.js';
5
5
  import { evaluateOrchestrationSpawn } from '../../runtime/orchestration/spawn-policy.js';
6
6
  import { summarizeError } from '../../utils/error-display.js';
7
7
  import { toRecord } from '../../utils/record-coerce.js';
8
+ import { evaluateWrfcBatchPolicy, isRootReviewRoleTask } from './wrfc-batch-policy.js';
8
9
  export { AGENT_TEMPLATES, AgentManager } from './manager.js';
9
10
  // ---------------------------------------------------------------------------
10
11
  // Tool implementation
@@ -49,6 +50,12 @@ export function createAgentTool(config) {
49
50
  if (!input.task || typeof input.task !== 'string' || input.task.trim() === '') {
50
51
  return { success: false, error: 'Missing required parameter for spawn: task' };
51
52
  }
53
+ if (!input.parentAgentId && input.dangerously_disable_wrfc && isRootReviewRoleTask({ task: input.task, template: input.template })) {
54
+ return {
55
+ success: false,
56
+ error: 'Root reviewer/tester/verifier agents are not valid independent roots. Start one WRFC owner chain for the deliverable, or spawn genuinely independent sidecar research/implementation tasks.',
57
+ };
58
+ }
52
59
  if (input.template && !AGENT_TEMPLATES[input.template]) {
53
60
  // Also allow custom archetypes loaded from .goodvibes/agents/*.md
54
61
  const customArchetype = archetypeLoader.loadArchetype(input.template);
@@ -374,6 +381,39 @@ export function createAgentTool(config) {
374
381
  if (input.tasks.length > 20) {
375
382
  return { success: false, error: 'batch-spawn limited to 20 tasks per batch.' };
376
383
  }
384
+ const batchPolicy = evaluateWrfcBatchPolicy(input);
385
+ if (batchPolicy.kind === 'collapse-to-wrfc') {
386
+ let record;
387
+ try {
388
+ record = manager.spawn(batchPolicy.ownerInput);
389
+ }
390
+ catch (error) {
391
+ return {
392
+ success: false,
393
+ error: `Failed to collapse role-decomposition batch into a WRFC owner chain: ${summarizeError(error)}`,
394
+ };
395
+ }
396
+ return {
397
+ success: true,
398
+ output: JSON.stringify({
399
+ agents: [{
400
+ id: record.id,
401
+ task: record.task.slice(0, 80),
402
+ template: record.template,
403
+ cohort: record.cohort,
404
+ wrfcId: record.wrfcId ?? null,
405
+ wrfcRole: record.wrfcRole ?? null,
406
+ }],
407
+ count: 1,
408
+ cohort: input.cohort,
409
+ skipped: 0,
410
+ collapsedToWrfc: true,
411
+ collapsedTaskCount: input.tasks.length,
412
+ reason: batchPolicy.reason,
413
+ roleTaskIndexes: batchPolicy.roleTaskIndexes ?? [],
414
+ }),
415
+ };
416
+ }
377
417
  const currentCount = manager.list().filter(a => a.status === 'pending' || a.status === 'running').length;
378
418
  const spawnDecision = evaluateOrchestrationSpawn({
379
419
  configManager: config.configManager,
@@ -1 +1 @@
1
- {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../../../src/platform/tools/agent/manager.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"manager.d.ts","sourceRoot":"","sources":["../../../../src/platform/tools/agent/manager.ts"],"names":[],"mappings":"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"}
@@ -7,6 +7,7 @@ import { evaluateOrchestrationSpawn } from '../../runtime/orchestration/spawn-po
7
7
  import { logger } from '../../utils/logger.js';
8
8
  import { summarizeError } from '../../utils/error-display.js';
9
9
  import { splitModelRegistryKey } from '../../providers/registry-helpers.js';
10
+ import { isRootReviewRoleTask } from './wrfc-batch-policy.js';
10
11
  export const AGENT_TEMPLATES = {
11
12
  engineer: {
12
13
  description: 'Full-stack implementation agent',
@@ -98,6 +99,9 @@ export class AgentManager {
98
99
  throw new Error('AgentManager requires configManager');
99
100
  }
100
101
  const template = input.template ?? 'general';
102
+ if (!input.parentAgentId && input.dangerously_disable_wrfc && isRootReviewRoleTask({ task, template })) {
103
+ throw new Error('Root reviewer/tester/verifier agents are not valid independent roots. Start one WRFC owner chain for the deliverable, or spawn genuinely independent sidecar research/implementation tasks.');
104
+ }
101
105
  const archetype = this.archetypeLoader.loadArchetype(template);
102
106
  const templateDef = AGENT_TEMPLATES[template] ?? AGENT_TEMPLATES.general;
103
107
  const defaultTools = archetype ? archetype.tools : templateDef.defaultTools;
@@ -5,7 +5,7 @@
5
5
  export const AGENT_TOOL_SCHEMA = {
6
6
  name: 'agent',
7
7
  description: 'Manages in-process subagents. Modes: spawn (create a new agent task), ' +
8
- 'batch-spawn (spawn multiple agents at once from a tasks array), ' +
8
+ 'batch-spawn (spawn multiple genuinely independent sidecar agents at once from a tasks array; review/test/verification role decomposition is WRFC and is collapsed to one owner chain), ' +
9
9
  'status (check agent progress by ID), cancel (stop a running agent), ' +
10
10
  'list (show all agents and their status), ' +
11
11
  'templates (list available agent templates with default tool sets), ' +
@@ -194,7 +194,7 @@ export const AGENT_TOOL_SCHEMA = {
194
194
  dangerously_disable_wrfc: { type: 'boolean', description: 'Skip WRFC review.' },
195
195
  },
196
196
  },
197
- description: 'Array of tasks to spawn as agents (mode: batch-spawn). Max 20.',
197
+ description: 'Array of genuinely independent tasks to spawn as agents (mode: batch-spawn). Max 20. Do not place tester/reviewer/verifier role phases here for one deliverable; those are WRFC lifecycle children owned by one owner chain.',
198
198
  },
199
199
  // mode: spawn, batch-spawn, list, cohort-status, cohort-report
200
200
  cohort: {
@@ -0,0 +1,13 @@
1
+ import type { AgentInput } from './schema.js';
2
+ type BatchTask = NonNullable<AgentInput['tasks']>[number];
3
+ export interface WrfcBatchPolicyDecision {
4
+ readonly kind: 'independent' | 'collapse-to-wrfc';
5
+ readonly reason?: string | undefined;
6
+ readonly ownerInput?: AgentInput | undefined;
7
+ readonly roleTaskIndexes?: readonly number[] | undefined;
8
+ }
9
+ export declare function isRootReviewRoleTemplate(template: string | undefined): boolean;
10
+ export declare function isRootReviewRoleTask(task: Pick<BatchTask, 'task' | 'template'>): boolean;
11
+ export declare function evaluateWrfcBatchPolicy(input: AgentInput): WrfcBatchPolicyDecision;
12
+ export {};
13
+ //# sourceMappingURL=wrfc-batch-policy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wrfc-batch-policy.d.ts","sourceRoot":"","sources":["../../../../src/platform/tools/agent/wrfc-batch-policy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAE9C,KAAK,SAAS,GAAG,WAAW,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC;AAsB1D,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,IAAI,EAAE,aAAa,GAAG,kBAAkB,CAAC;IAClD,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,QAAQ,CAAC,UAAU,CAAC,EAAE,UAAU,GAAG,SAAS,CAAC;IAC7C,QAAQ,CAAC,eAAe,CAAC,EAAE,SAAS,MAAM,EAAE,GAAG,SAAS,CAAC;CAC1D;AAED,wBAAgB,wBAAwB,CAAC,QAAQ,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAE9E;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,IAAI,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,CAAC,GAAG,OAAO,CAIxF;AA8BD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,UAAU,GAAG,uBAAuB,CAoElF"}
@@ -0,0 +1,108 @@
1
+ const ROOT_REVIEW_ROLE_TEMPLATES = new Set([
2
+ 'reviewer',
3
+ 'tester',
4
+ 'verifier',
5
+ 'review',
6
+ 'test',
7
+ 'qa',
8
+ ]);
9
+ const IMPLEMENTATION_TEMPLATES = new Set(['engineer', 'general']);
10
+ const ROLE_PREFIX_RE = /^\s*(?:\[?\s*)?(?:reviewer|tester|verifier|qa|quality\s+assurance|test|review|verify|validator)\b[\]\s:;-]*/i;
11
+ const ROLE_ACTION_RE = /\b(?:test|tests|testing|review|reviews|reviewing|verify|verifies|verifying|verification|validate|validates|validating|validation|qa)\s+(?:the|this|that|implementation|solution|feature|deliverable|code|changes|work|output|result|patch|diff)\b/i;
12
+ const IMPLEMENTATION_ACTION_RE = /\b(?:build|implement|create|add|write|fix|repair|update|refactor|change|modify|deliver|make)\b/i;
13
+ export function isRootReviewRoleTemplate(template) {
14
+ return ROOT_REVIEW_ROLE_TEMPLATES.has((template ?? '').trim().toLowerCase());
15
+ }
16
+ export function isRootReviewRoleTask(task) {
17
+ if (isRootReviewRoleTemplate(task.template))
18
+ return true;
19
+ const text = task.task.trim();
20
+ return ROLE_PREFIX_RE.test(text) || ROLE_ACTION_RE.test(text);
21
+ }
22
+ function isImplementationLikeTask(task) {
23
+ const template = (task.template ?? '').trim().toLowerCase();
24
+ return IMPLEMENTATION_TEMPLATES.has(template) || IMPLEMENTATION_ACTION_RE.test(task.task);
25
+ }
26
+ function uniqueStrings(values) {
27
+ const unique = [...new Set(values.flatMap((value) => value ?? []).filter((value) => value.trim().length > 0))];
28
+ return unique.length > 0 ? unique : undefined;
29
+ }
30
+ function formatTask(task, index) {
31
+ const template = task.template ?? 'general';
32
+ return `${index + 1}. [${template}] ${task.task}`;
33
+ }
34
+ function buildCollapsedContext(input, tasks, roleTaskIndexes) {
35
+ const roleIndexText = roleTaskIndexes.map((index) => index + 1).join(', ');
36
+ const existing = input.context?.trim();
37
+ return [
38
+ existing ? `Caller context:\n${existing}` : null,
39
+ 'SDK WRFC topology enforcement collapsed this batch because root review/test/verification tasks are lifecycle phases, not independent root agents.',
40
+ `Collapsed role-task indexes: ${roleIndexText}.`,
41
+ 'The WRFC owner must keep one root chain for the original deliverable. The controller owns engineer, reviewer, tester/verifier, and fixer child lifecycle agents after owner output exists.',
42
+ 'Original batch:',
43
+ ...tasks.map(formatTask),
44
+ ].filter((line) => Boolean(line)).join('\n');
45
+ }
46
+ export function evaluateWrfcBatchPolicy(input) {
47
+ const tasks = input.tasks ?? [];
48
+ if (input.mode !== 'batch-spawn' || tasks.length <= 1) {
49
+ return { kind: 'independent' };
50
+ }
51
+ const roleTaskIndexes = tasks
52
+ .map((task, index) => isRootReviewRoleTask(task) ? index : -1)
53
+ .filter((index) => index >= 0);
54
+ if (roleTaskIndexes.length === 0) {
55
+ return { kind: 'independent' };
56
+ }
57
+ const primaryIndex = tasks.findIndex((task, index) => !roleTaskIndexes.includes(index) && isImplementationLikeTask(task));
58
+ const ownerTask = tasks[primaryIndex >= 0 ? primaryIndex : 0];
59
+ const ownerTemplate = isRootReviewRoleTemplate(ownerTask.template)
60
+ ? 'engineer'
61
+ : ownerTask.template ?? input.template ?? 'engineer';
62
+ const template = isRootReviewRoleTemplate(ownerTemplate) ? 'engineer' : ownerTemplate;
63
+ const ownerInput = {
64
+ mode: 'spawn',
65
+ task: ownerTask.task,
66
+ template,
67
+ model: ownerTask.model ?? input.model,
68
+ provider: ownerTask.provider ?? input.provider,
69
+ fallbackModels: ownerTask.fallbackModels ?? input.fallbackModels,
70
+ routing: ownerTask.routing ?? input.routing,
71
+ executionIntent: ownerTask.executionIntent ?? input.executionIntent,
72
+ reasoningEffort: ownerTask.reasoningEffort ?? input.reasoningEffort,
73
+ tools: ownerTask.tools ?? input.tools,
74
+ restrictTools: ownerTask.restrictTools ?? input.restrictTools,
75
+ context: buildCollapsedContext(input, tasks, roleTaskIndexes),
76
+ successCriteria: uniqueStrings([
77
+ ownerTask.successCriteria,
78
+ input.successCriteria,
79
+ ...tasks.map((task) => task.successCriteria),
80
+ ['Keep the WRFC work as one owner chain; review, test, verification, and fix work must be WRFC lifecycle children, not sibling root agents.'],
81
+ ]),
82
+ requiredEvidence: uniqueStrings([
83
+ ownerTask.requiredEvidence,
84
+ input.requiredEvidence,
85
+ ...tasks.map((task) => task.requiredEvidence),
86
+ ]),
87
+ writeScope: uniqueStrings([
88
+ ownerTask.writeScope,
89
+ input.writeScope,
90
+ ...tasks.map((task) => task.writeScope),
91
+ ]),
92
+ executionProtocol: ownerTask.executionProtocol ?? input.executionProtocol,
93
+ reviewMode: 'wrfc',
94
+ communicationLane: ownerTask.communicationLane ?? input.communicationLane,
95
+ parentAgentId: ownerTask.parentAgentId ?? input.parentAgentId,
96
+ orchestrationGraphId: ownerTask.orchestrationGraphId ?? input.orchestrationGraphId,
97
+ orchestrationNodeId: ownerTask.orchestrationNodeId ?? input.orchestrationNodeId,
98
+ parentNodeId: ownerTask.parentNodeId ?? input.parentNodeId,
99
+ dangerously_disable_wrfc: false,
100
+ cohort: input.cohort,
101
+ };
102
+ return {
103
+ kind: 'collapse-to-wrfc',
104
+ reason: 'batch-spawn contained root review/test/verification role tasks for the same deliverable',
105
+ ownerInput,
106
+ roleTaskIndexes,
107
+ };
108
+ }
@@ -1,6 +1,6 @@
1
1
  import { readFileSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
- let version = '0.33.18';
3
+ let version = '0.33.20';
4
4
  try {
5
5
  const pkg = JSON.parse(readFileSync(join(import.meta.dir, '..', '..', 'package.json'), 'utf-8'));
6
6
  version = pkg.version ?? version;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@pellux/goodvibes-sdk",
3
- "version": "0.33.18",
3
+ "version": "0.33.20",
4
4
  "description": "TypeScript SDK for building GoodVibes operator, peer, web, mobile, and daemon-connected apps with typed contracts, auth, realtime events, and transport layers.",
5
5
  "keywords": [
6
6
  "goodvibes",
@@ -449,14 +449,14 @@
449
449
  "sideEffects": false,
450
450
  "type": "module",
451
451
  "dependencies": {
452
- "@pellux/goodvibes-contracts": "0.33.18",
453
- "@pellux/goodvibes-daemon-sdk": "0.33.18",
454
- "@pellux/goodvibes-errors": "0.33.18",
455
- "@pellux/goodvibes-operator-sdk": "0.33.18",
456
- "@pellux/goodvibes-peer-sdk": "0.33.18",
457
- "@pellux/goodvibes-transport-core": "0.33.18",
458
- "@pellux/goodvibes-transport-http": "0.33.18",
459
- "@pellux/goodvibes-transport-realtime": "0.33.18"
452
+ "@pellux/goodvibes-contracts": "0.33.20",
453
+ "@pellux/goodvibes-daemon-sdk": "0.33.20",
454
+ "@pellux/goodvibes-errors": "0.33.20",
455
+ "@pellux/goodvibes-operator-sdk": "0.33.20",
456
+ "@pellux/goodvibes-peer-sdk": "0.33.20",
457
+ "@pellux/goodvibes-transport-core": "0.33.20",
458
+ "@pellux/goodvibes-transport-http": "0.33.20",
459
+ "@pellux/goodvibes-transport-realtime": "0.33.20"
460
460
  },
461
461
  "optionalDependencies": {
462
462
  "@agentclientprotocol/sdk": "^0.21.0",