@planningo/duul 1.0.0 → 1.1.0
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/README.ko.md +92 -6
- package/README.md +94 -7
- package/build/prompts/code-review-system.js +11 -1
- package/build/prompts/plan-review-system.js +11 -1
- package/build/schemas/code-review.d.ts +48 -11
- package/build/schemas/code-review.js +22 -3
- package/build/schemas/common.d.ts +26 -3
- package/build/schemas/common.js +16 -2
- package/build/schemas/execution-partition.d.ts +97 -63
- package/build/schemas/execution-partition.js +13 -3
- package/build/schemas/plan-review.d.ts +42 -8
- package/build/schemas/plan-review.js +15 -1
- package/build/services/filesystem-tools.d.ts +19 -1
- package/build/services/filesystem-tools.js +50 -13
- package/build/services/filesystem.d.ts +20 -0
- package/build/services/filesystem.js +51 -17
- package/build/services/providers/anthropic.js +5 -3
- package/build/services/providers/codex-auth.d.ts +51 -0
- package/build/services/providers/codex-auth.js +178 -0
- package/build/services/providers/google.js +4 -2
- package/build/services/providers/openai.d.ts +33 -0
- package/build/services/providers/openai.js +173 -30
- package/build/services/providers/types.d.ts +7 -1
- package/build/services/review-limits.d.ts +8 -0
- package/build/services/review-limits.js +21 -0
- package/build/services/reviewer.d.ts +34 -2
- package/build/services/reviewer.js +95 -21
- package/build/tools/code-review.js +50 -7
- package/build/tools/execution-partition.js +55 -10
- package/build/tools/plan-review.js +38 -6
- package/package.json +1 -1
package/build/schemas/common.js
CHANGED
|
@@ -14,9 +14,16 @@ export const ReviewerConfigSchema = z.object({
|
|
|
14
14
|
.optional()
|
|
15
15
|
.describe('Review provider. Default: env REVIEW_PROVIDER or "openai".'),
|
|
16
16
|
model: z
|
|
17
|
-
.
|
|
17
|
+
.union([
|
|
18
|
+
z.string(),
|
|
19
|
+
z.object({
|
|
20
|
+
plan: z.string().optional(),
|
|
21
|
+
code: z.string().optional(),
|
|
22
|
+
partition: z.string().optional(),
|
|
23
|
+
}),
|
|
24
|
+
])
|
|
18
25
|
.optional()
|
|
19
|
-
.describe('Model to use. Default: env REVIEW_MODEL or provider default.'),
|
|
26
|
+
.describe('Model to use. Either a single string applied to all tools, or an object with per-tool overrides (plan/code/partition). Default: env REVIEW_MODEL or provider default.'),
|
|
20
27
|
base_url: z
|
|
21
28
|
.string()
|
|
22
29
|
.optional()
|
|
@@ -45,6 +52,13 @@ export const IterationMetaOutputSchema = z.object({
|
|
|
45
52
|
iteration_count: z.number().describe('Current iteration number (1-based) as reported by the caller.'),
|
|
46
53
|
iteration_limit: z.number().describe('Maximum iterations allowed for this phase.'),
|
|
47
54
|
iteration_limit_reached: z.boolean().describe('Whether the iteration limit has been reached.'),
|
|
55
|
+
cost_warning: z
|
|
56
|
+
.string()
|
|
57
|
+
.optional()
|
|
58
|
+
.nullable()
|
|
59
|
+
.describe('Soft warning string emitted once iteration_count crosses ~60% of iteration_limit. ' +
|
|
60
|
+
'Includes the current round cost so the orchestrator can decide whether to accept a near-verdict or escalate. ' +
|
|
61
|
+
'Null when below the threshold.'),
|
|
48
62
|
});
|
|
49
63
|
/**
|
|
50
64
|
* Token usage fields — added to MCP output for cost/usage tracking.
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { z } from 'zod';
|
|
2
2
|
export declare const ExecutionPartitionInputSchema: z.ZodObject<{
|
|
3
|
-
approved_plan: z.ZodString
|
|
4
|
-
|
|
3
|
+
approved_plan: z.ZodOptional<z.ZodString>;
|
|
4
|
+
approved_plan_file: z.ZodOptional<z.ZodString>;
|
|
5
|
+
workspace_root: z.ZodOptional<z.ZodString>;
|
|
5
6
|
working_directories: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
6
7
|
changed_files: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
7
8
|
entrypoints: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
@@ -25,32 +26,51 @@ export declare const ExecutionPartitionInputSchema: z.ZodObject<{
|
|
|
25
26
|
max_review_iterations: z.ZodOptional<z.ZodNumber>;
|
|
26
27
|
reviewer_config: z.ZodOptional<z.ZodObject<{
|
|
27
28
|
provider: z.ZodOptional<z.ZodEnum<["openai", "anthropic", "google", "openrouter", "compatible"]>>;
|
|
28
|
-
model: z.ZodOptional<z.ZodString
|
|
29
|
+
model: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodObject<{
|
|
30
|
+
plan: z.ZodOptional<z.ZodString>;
|
|
31
|
+
code: z.ZodOptional<z.ZodString>;
|
|
32
|
+
partition: z.ZodOptional<z.ZodString>;
|
|
33
|
+
}, "strip", z.ZodTypeAny, {
|
|
34
|
+
code?: string | undefined;
|
|
35
|
+
plan?: string | undefined;
|
|
36
|
+
partition?: string | undefined;
|
|
37
|
+
}, {
|
|
38
|
+
code?: string | undefined;
|
|
39
|
+
plan?: string | undefined;
|
|
40
|
+
partition?: string | undefined;
|
|
41
|
+
}>]>>;
|
|
29
42
|
base_url: z.ZodOptional<z.ZodString>;
|
|
30
43
|
api_key: z.ZodOptional<z.ZodString>;
|
|
31
44
|
temperature: z.ZodOptional<z.ZodNumber>;
|
|
32
45
|
top_p: z.ZodOptional<z.ZodNumber>;
|
|
33
46
|
}, "strip", z.ZodTypeAny, {
|
|
34
47
|
provider?: "openai" | "anthropic" | "google" | "openrouter" | "compatible" | undefined;
|
|
35
|
-
model?: string |
|
|
48
|
+
model?: string | {
|
|
49
|
+
code?: string | undefined;
|
|
50
|
+
plan?: string | undefined;
|
|
51
|
+
partition?: string | undefined;
|
|
52
|
+
} | undefined;
|
|
36
53
|
base_url?: string | undefined;
|
|
37
54
|
api_key?: string | undefined;
|
|
38
55
|
temperature?: number | undefined;
|
|
39
56
|
top_p?: number | undefined;
|
|
40
57
|
}, {
|
|
41
58
|
provider?: "openai" | "anthropic" | "google" | "openrouter" | "compatible" | undefined;
|
|
42
|
-
model?: string |
|
|
59
|
+
model?: string | {
|
|
60
|
+
code?: string | undefined;
|
|
61
|
+
plan?: string | undefined;
|
|
62
|
+
partition?: string | undefined;
|
|
63
|
+
} | undefined;
|
|
43
64
|
base_url?: string | undefined;
|
|
44
65
|
api_key?: string | undefined;
|
|
45
66
|
temperature?: number | undefined;
|
|
46
67
|
top_p?: number | undefined;
|
|
47
68
|
}>>;
|
|
48
69
|
}, "strip", z.ZodTypeAny, {
|
|
49
|
-
workspace_root: string;
|
|
50
|
-
approved_plan: string;
|
|
51
70
|
iteration_count?: number | undefined;
|
|
52
71
|
changed_files?: string[] | undefined;
|
|
53
72
|
constraints?: string[] | undefined;
|
|
73
|
+
workspace_root?: string | undefined;
|
|
54
74
|
working_directories?: string[] | undefined;
|
|
55
75
|
entrypoints?: string[] | undefined;
|
|
56
76
|
artifact_refs?: {
|
|
@@ -62,19 +82,24 @@ export declare const ExecutionPartitionInputSchema: z.ZodObject<{
|
|
|
62
82
|
max_review_iterations?: number | undefined;
|
|
63
83
|
reviewer_config?: {
|
|
64
84
|
provider?: "openai" | "anthropic" | "google" | "openrouter" | "compatible" | undefined;
|
|
65
|
-
model?: string |
|
|
85
|
+
model?: string | {
|
|
86
|
+
code?: string | undefined;
|
|
87
|
+
plan?: string | undefined;
|
|
88
|
+
partition?: string | undefined;
|
|
89
|
+
} | undefined;
|
|
66
90
|
base_url?: string | undefined;
|
|
67
91
|
api_key?: string | undefined;
|
|
68
92
|
temperature?: number | undefined;
|
|
69
93
|
top_p?: number | undefined;
|
|
70
94
|
} | undefined;
|
|
95
|
+
approved_plan?: string | undefined;
|
|
96
|
+
approved_plan_file?: string | undefined;
|
|
71
97
|
max_parallelism?: number | undefined;
|
|
72
98
|
}, {
|
|
73
|
-
workspace_root: string;
|
|
74
|
-
approved_plan: string;
|
|
75
99
|
iteration_count?: number | undefined;
|
|
76
100
|
changed_files?: string[] | undefined;
|
|
77
101
|
constraints?: string[] | undefined;
|
|
102
|
+
workspace_root?: string | undefined;
|
|
78
103
|
working_directories?: string[] | undefined;
|
|
79
104
|
entrypoints?: string[] | undefined;
|
|
80
105
|
artifact_refs?: {
|
|
@@ -86,12 +111,18 @@ export declare const ExecutionPartitionInputSchema: z.ZodObject<{
|
|
|
86
111
|
max_review_iterations?: number | undefined;
|
|
87
112
|
reviewer_config?: {
|
|
88
113
|
provider?: "openai" | "anthropic" | "google" | "openrouter" | "compatible" | undefined;
|
|
89
|
-
model?: string |
|
|
114
|
+
model?: string | {
|
|
115
|
+
code?: string | undefined;
|
|
116
|
+
plan?: string | undefined;
|
|
117
|
+
partition?: string | undefined;
|
|
118
|
+
} | undefined;
|
|
90
119
|
base_url?: string | undefined;
|
|
91
120
|
api_key?: string | undefined;
|
|
92
121
|
temperature?: number | undefined;
|
|
93
122
|
top_p?: number | undefined;
|
|
94
123
|
} | undefined;
|
|
124
|
+
approved_plan?: string | undefined;
|
|
125
|
+
approved_plan_file?: string | undefined;
|
|
95
126
|
max_parallelism?: number | undefined;
|
|
96
127
|
}>;
|
|
97
128
|
export declare const ExecutionPartitionOutputSchema: z.ZodObject<{
|
|
@@ -154,13 +185,6 @@ export declare const ExecutionPartitionOutputSchema: z.ZodObject<{
|
|
|
154
185
|
review_focus: z.ZodArray<z.ZodString, "many">;
|
|
155
186
|
risk_level: z.ZodEnum<["high", "medium", "low"]>;
|
|
156
187
|
}, "strip", z.ZodTypeAny, {
|
|
157
|
-
id: string;
|
|
158
|
-
title: string;
|
|
159
|
-
goal: string;
|
|
160
|
-
can_run_in_parallel: boolean;
|
|
161
|
-
depends_on: string[];
|
|
162
|
-
workspace_name_hint: string;
|
|
163
|
-
spawn_strategy: "new_workspace" | "reuse_workspace";
|
|
164
188
|
scope: {
|
|
165
189
|
changed_files?: string[] | undefined;
|
|
166
190
|
working_directories?: string[] | undefined;
|
|
@@ -172,11 +196,6 @@ export declare const ExecutionPartitionOutputSchema: z.ZodObject<{
|
|
|
172
196
|
priority: "high" | "medium" | "low";
|
|
173
197
|
}[] | undefined;
|
|
174
198
|
};
|
|
175
|
-
handoff_contract: string[];
|
|
176
|
-
completion_criteria: string[];
|
|
177
|
-
review_focus: string[];
|
|
178
|
-
risk_level: "high" | "medium" | "low";
|
|
179
|
-
}, {
|
|
180
199
|
id: string;
|
|
181
200
|
title: string;
|
|
182
201
|
goal: string;
|
|
@@ -184,6 +203,11 @@ export declare const ExecutionPartitionOutputSchema: z.ZodObject<{
|
|
|
184
203
|
depends_on: string[];
|
|
185
204
|
workspace_name_hint: string;
|
|
186
205
|
spawn_strategy: "new_workspace" | "reuse_workspace";
|
|
206
|
+
handoff_contract: string[];
|
|
207
|
+
completion_criteria: string[];
|
|
208
|
+
review_focus: string[];
|
|
209
|
+
risk_level: "high" | "medium" | "low";
|
|
210
|
+
}, {
|
|
187
211
|
scope: {
|
|
188
212
|
changed_files?: string[] | undefined;
|
|
189
213
|
working_directories?: string[] | undefined;
|
|
@@ -195,6 +219,13 @@ export declare const ExecutionPartitionOutputSchema: z.ZodObject<{
|
|
|
195
219
|
priority: "high" | "medium" | "low";
|
|
196
220
|
}[] | undefined;
|
|
197
221
|
};
|
|
222
|
+
id: string;
|
|
223
|
+
title: string;
|
|
224
|
+
goal: string;
|
|
225
|
+
can_run_in_parallel: boolean;
|
|
226
|
+
depends_on: string[];
|
|
227
|
+
workspace_name_hint: string;
|
|
228
|
+
spawn_strategy: "new_workspace" | "reuse_workspace";
|
|
198
229
|
handoff_contract: string[];
|
|
199
230
|
completion_criteria: string[];
|
|
200
231
|
review_focus: string[];
|
|
@@ -233,13 +264,6 @@ export declare const ExecutionPartitionOutputSchema: z.ZodObject<{
|
|
|
233
264
|
handoff_artifact_pattern: string;
|
|
234
265
|
subtask_result_schema_version: "1.0";
|
|
235
266
|
subtasks: {
|
|
236
|
-
id: string;
|
|
237
|
-
title: string;
|
|
238
|
-
goal: string;
|
|
239
|
-
can_run_in_parallel: boolean;
|
|
240
|
-
depends_on: string[];
|
|
241
|
-
workspace_name_hint: string;
|
|
242
|
-
spawn_strategy: "new_workspace" | "reuse_workspace";
|
|
243
267
|
scope: {
|
|
244
268
|
changed_files?: string[] | undefined;
|
|
245
269
|
working_directories?: string[] | undefined;
|
|
@@ -251,6 +275,13 @@ export declare const ExecutionPartitionOutputSchema: z.ZodObject<{
|
|
|
251
275
|
priority: "high" | "medium" | "low";
|
|
252
276
|
}[] | undefined;
|
|
253
277
|
};
|
|
278
|
+
id: string;
|
|
279
|
+
title: string;
|
|
280
|
+
goal: string;
|
|
281
|
+
can_run_in_parallel: boolean;
|
|
282
|
+
depends_on: string[];
|
|
283
|
+
workspace_name_hint: string;
|
|
284
|
+
spawn_strategy: "new_workspace" | "reuse_workspace";
|
|
254
285
|
handoff_contract: string[];
|
|
255
286
|
completion_criteria: string[];
|
|
256
287
|
review_focus: string[];
|
|
@@ -275,13 +306,6 @@ export declare const ExecutionPartitionOutputSchema: z.ZodObject<{
|
|
|
275
306
|
handoff_artifact_pattern: string;
|
|
276
307
|
subtask_result_schema_version: "1.0";
|
|
277
308
|
subtasks: {
|
|
278
|
-
id: string;
|
|
279
|
-
title: string;
|
|
280
|
-
goal: string;
|
|
281
|
-
can_run_in_parallel: boolean;
|
|
282
|
-
depends_on: string[];
|
|
283
|
-
workspace_name_hint: string;
|
|
284
|
-
spawn_strategy: "new_workspace" | "reuse_workspace";
|
|
285
309
|
scope: {
|
|
286
310
|
changed_files?: string[] | undefined;
|
|
287
311
|
working_directories?: string[] | undefined;
|
|
@@ -293,6 +317,13 @@ export declare const ExecutionPartitionOutputSchema: z.ZodObject<{
|
|
|
293
317
|
priority: "high" | "medium" | "low";
|
|
294
318
|
}[] | undefined;
|
|
295
319
|
};
|
|
320
|
+
id: string;
|
|
321
|
+
title: string;
|
|
322
|
+
goal: string;
|
|
323
|
+
can_run_in_parallel: boolean;
|
|
324
|
+
depends_on: string[];
|
|
325
|
+
workspace_name_hint: string;
|
|
326
|
+
spawn_strategy: "new_workspace" | "reuse_workspace";
|
|
296
327
|
handoff_contract: string[];
|
|
297
328
|
completion_criteria: string[];
|
|
298
329
|
review_focus: string[];
|
|
@@ -369,13 +400,6 @@ export declare const ExecutionPartitionMcpOutputSchema: z.ZodObject<{
|
|
|
369
400
|
review_focus: z.ZodArray<z.ZodString, "many">;
|
|
370
401
|
risk_level: z.ZodEnum<["high", "medium", "low"]>;
|
|
371
402
|
}, "strip", z.ZodTypeAny, {
|
|
372
|
-
id: string;
|
|
373
|
-
title: string;
|
|
374
|
-
goal: string;
|
|
375
|
-
can_run_in_parallel: boolean;
|
|
376
|
-
depends_on: string[];
|
|
377
|
-
workspace_name_hint: string;
|
|
378
|
-
spawn_strategy: "new_workspace" | "reuse_workspace";
|
|
379
403
|
scope: {
|
|
380
404
|
changed_files?: string[] | undefined;
|
|
381
405
|
working_directories?: string[] | undefined;
|
|
@@ -387,11 +411,6 @@ export declare const ExecutionPartitionMcpOutputSchema: z.ZodObject<{
|
|
|
387
411
|
priority: "high" | "medium" | "low";
|
|
388
412
|
}[] | undefined;
|
|
389
413
|
};
|
|
390
|
-
handoff_contract: string[];
|
|
391
|
-
completion_criteria: string[];
|
|
392
|
-
review_focus: string[];
|
|
393
|
-
risk_level: "high" | "medium" | "low";
|
|
394
|
-
}, {
|
|
395
414
|
id: string;
|
|
396
415
|
title: string;
|
|
397
416
|
goal: string;
|
|
@@ -399,6 +418,11 @@ export declare const ExecutionPartitionMcpOutputSchema: z.ZodObject<{
|
|
|
399
418
|
depends_on: string[];
|
|
400
419
|
workspace_name_hint: string;
|
|
401
420
|
spawn_strategy: "new_workspace" | "reuse_workspace";
|
|
421
|
+
handoff_contract: string[];
|
|
422
|
+
completion_criteria: string[];
|
|
423
|
+
review_focus: string[];
|
|
424
|
+
risk_level: "high" | "medium" | "low";
|
|
425
|
+
}, {
|
|
402
426
|
scope: {
|
|
403
427
|
changed_files?: string[] | undefined;
|
|
404
428
|
working_directories?: string[] | undefined;
|
|
@@ -410,6 +434,13 @@ export declare const ExecutionPartitionMcpOutputSchema: z.ZodObject<{
|
|
|
410
434
|
priority: "high" | "medium" | "low";
|
|
411
435
|
}[] | undefined;
|
|
412
436
|
};
|
|
437
|
+
id: string;
|
|
438
|
+
title: string;
|
|
439
|
+
goal: string;
|
|
440
|
+
can_run_in_parallel: boolean;
|
|
441
|
+
depends_on: string[];
|
|
442
|
+
workspace_name_hint: string;
|
|
443
|
+
spawn_strategy: "new_workspace" | "reuse_workspace";
|
|
413
444
|
handoff_contract: string[];
|
|
414
445
|
completion_criteria: string[];
|
|
415
446
|
review_focus: string[];
|
|
@@ -445,6 +476,7 @@ export declare const ExecutionPartitionMcpOutputSchema: z.ZodObject<{
|
|
|
445
476
|
iteration_count: z.ZodNumber;
|
|
446
477
|
iteration_limit: z.ZodNumber;
|
|
447
478
|
iteration_limit_reached: z.ZodBoolean;
|
|
479
|
+
cost_warning: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
448
480
|
} & {
|
|
449
481
|
token_usage: z.ZodObject<{
|
|
450
482
|
input_tokens: z.ZodNumber;
|
|
@@ -501,13 +533,6 @@ export declare const ExecutionPartitionMcpOutputSchema: z.ZodObject<{
|
|
|
501
533
|
handoff_artifact_pattern: string;
|
|
502
534
|
subtask_result_schema_version: "1.0";
|
|
503
535
|
subtasks: {
|
|
504
|
-
id: string;
|
|
505
|
-
title: string;
|
|
506
|
-
goal: string;
|
|
507
|
-
can_run_in_parallel: boolean;
|
|
508
|
-
depends_on: string[];
|
|
509
|
-
workspace_name_hint: string;
|
|
510
|
-
spawn_strategy: "new_workspace" | "reuse_workspace";
|
|
511
536
|
scope: {
|
|
512
537
|
changed_files?: string[] | undefined;
|
|
513
538
|
working_directories?: string[] | undefined;
|
|
@@ -519,6 +544,13 @@ export declare const ExecutionPartitionMcpOutputSchema: z.ZodObject<{
|
|
|
519
544
|
priority: "high" | "medium" | "low";
|
|
520
545
|
}[] | undefined;
|
|
521
546
|
};
|
|
547
|
+
id: string;
|
|
548
|
+
title: string;
|
|
549
|
+
goal: string;
|
|
550
|
+
can_run_in_parallel: boolean;
|
|
551
|
+
depends_on: string[];
|
|
552
|
+
workspace_name_hint: string;
|
|
553
|
+
spawn_strategy: "new_workspace" | "reuse_workspace";
|
|
522
554
|
handoff_contract: string[];
|
|
523
555
|
completion_criteria: string[];
|
|
524
556
|
review_focus: string[];
|
|
@@ -534,6 +566,7 @@ export declare const ExecutionPartitionMcpOutputSchema: z.ZodObject<{
|
|
|
534
566
|
on_blocker: "escalate_to_human";
|
|
535
567
|
on_max_retries_exceeded: "abort_subtask_and_report";
|
|
536
568
|
};
|
|
569
|
+
cost_warning?: string | null | undefined;
|
|
537
570
|
}, {
|
|
538
571
|
iteration_count: number;
|
|
539
572
|
iteration_limit: number;
|
|
@@ -558,13 +591,6 @@ export declare const ExecutionPartitionMcpOutputSchema: z.ZodObject<{
|
|
|
558
591
|
handoff_artifact_pattern: string;
|
|
559
592
|
subtask_result_schema_version: "1.0";
|
|
560
593
|
subtasks: {
|
|
561
|
-
id: string;
|
|
562
|
-
title: string;
|
|
563
|
-
goal: string;
|
|
564
|
-
can_run_in_parallel: boolean;
|
|
565
|
-
depends_on: string[];
|
|
566
|
-
workspace_name_hint: string;
|
|
567
|
-
spawn_strategy: "new_workspace" | "reuse_workspace";
|
|
568
594
|
scope: {
|
|
569
595
|
changed_files?: string[] | undefined;
|
|
570
596
|
working_directories?: string[] | undefined;
|
|
@@ -576,6 +602,13 @@ export declare const ExecutionPartitionMcpOutputSchema: z.ZodObject<{
|
|
|
576
602
|
priority: "high" | "medium" | "low";
|
|
577
603
|
}[] | undefined;
|
|
578
604
|
};
|
|
605
|
+
id: string;
|
|
606
|
+
title: string;
|
|
607
|
+
goal: string;
|
|
608
|
+
can_run_in_parallel: boolean;
|
|
609
|
+
depends_on: string[];
|
|
610
|
+
workspace_name_hint: string;
|
|
611
|
+
spawn_strategy: "new_workspace" | "reuse_workspace";
|
|
579
612
|
handoff_contract: string[];
|
|
580
613
|
completion_criteria: string[];
|
|
581
614
|
review_focus: string[];
|
|
@@ -591,6 +624,7 @@ export declare const ExecutionPartitionMcpOutputSchema: z.ZodObject<{
|
|
|
591
624
|
on_blocker: "escalate_to_human";
|
|
592
625
|
on_max_retries_exceeded: "abort_subtask_and_report";
|
|
593
626
|
};
|
|
627
|
+
cost_warning?: string | null | undefined;
|
|
594
628
|
}>;
|
|
595
629
|
export type ExecutionPartitionInput = z.infer<typeof ExecutionPartitionInputSchema>;
|
|
596
630
|
export type ExecutionPartitionOutput = z.infer<typeof ExecutionPartitionOutputSchema>;
|
|
@@ -3,11 +3,21 @@ import { ArtifactRefSchema, ReviewerConfigSchema, IterationMetaOutputSchema, Tok
|
|
|
3
3
|
export const ExecutionPartitionInputSchema = z.object({
|
|
4
4
|
approved_plan: z
|
|
5
5
|
.string()
|
|
6
|
-
.
|
|
7
|
-
.describe('
|
|
6
|
+
.optional()
|
|
7
|
+
.describe('Full text of the approved plan to partition into subtasks. REQUIRED unless approved_plan_file is provided. ' +
|
|
8
|
+
'Pass the entire approved plan markdown so the partitioner can analyze dependencies and split work. ' +
|
|
9
|
+
'If the plan is large, prefer approved_plan_file — inlining a very large string here can make the tool call fail to serialize.'),
|
|
10
|
+
approved_plan_file: z
|
|
11
|
+
.string()
|
|
12
|
+
.optional()
|
|
13
|
+
.describe('Relative path (within workspace_root) to a markdown file containing the approved plan, ' +
|
|
14
|
+
'e.g. ".duul/plan.md". Use this instead of inlining `approved_plan` when it is large. ' +
|
|
15
|
+
'Exactly one of `approved_plan` or `approved_plan_file` is required. Must be a relative path.'),
|
|
8
16
|
workspace_root: z
|
|
9
17
|
.string()
|
|
10
|
-
.
|
|
18
|
+
.optional()
|
|
19
|
+
.describe('Absolute path to the workspace root directory. REQUIRED (enforced by the handler). ' +
|
|
20
|
+
'Example: "/Users/me/project". The partitioner uses this to verify file paths exist.'),
|
|
11
21
|
working_directories: z
|
|
12
22
|
.array(z.string())
|
|
13
23
|
.optional()
|
|
@@ -31,7 +31,8 @@ export declare const ProjectContextSchema: z.ZodObject<{
|
|
|
31
31
|
}[] | undefined;
|
|
32
32
|
}>;
|
|
33
33
|
export declare const PlanReviewInputSchema: z.ZodObject<{
|
|
34
|
-
plan: z.ZodString
|
|
34
|
+
plan: z.ZodOptional<z.ZodString>;
|
|
35
|
+
plan_file: z.ZodOptional<z.ZodString>;
|
|
35
36
|
project_context: z.ZodOptional<z.ZodObject<{
|
|
36
37
|
file_tree: z.ZodOptional<z.ZodString>;
|
|
37
38
|
changed_files: z.ZodOptional<z.ZodArray<z.ZodString, "many">>;
|
|
@@ -99,30 +100,51 @@ export declare const PlanReviewInputSchema: z.ZodObject<{
|
|
|
99
100
|
max_review_iterations: z.ZodOptional<z.ZodNumber>;
|
|
100
101
|
reviewer_config: z.ZodOptional<z.ZodObject<{
|
|
101
102
|
provider: z.ZodOptional<z.ZodEnum<["openai", "anthropic", "google", "openrouter", "compatible"]>>;
|
|
102
|
-
model: z.ZodOptional<z.ZodString
|
|
103
|
+
model: z.ZodOptional<z.ZodUnion<[z.ZodString, z.ZodObject<{
|
|
104
|
+
plan: z.ZodOptional<z.ZodString>;
|
|
105
|
+
code: z.ZodOptional<z.ZodString>;
|
|
106
|
+
partition: z.ZodOptional<z.ZodString>;
|
|
107
|
+
}, "strip", z.ZodTypeAny, {
|
|
108
|
+
code?: string | undefined;
|
|
109
|
+
plan?: string | undefined;
|
|
110
|
+
partition?: string | undefined;
|
|
111
|
+
}, {
|
|
112
|
+
code?: string | undefined;
|
|
113
|
+
plan?: string | undefined;
|
|
114
|
+
partition?: string | undefined;
|
|
115
|
+
}>]>>;
|
|
103
116
|
base_url: z.ZodOptional<z.ZodString>;
|
|
104
117
|
api_key: z.ZodOptional<z.ZodString>;
|
|
105
118
|
temperature: z.ZodOptional<z.ZodNumber>;
|
|
106
119
|
top_p: z.ZodOptional<z.ZodNumber>;
|
|
107
120
|
}, "strip", z.ZodTypeAny, {
|
|
108
121
|
provider?: "openai" | "anthropic" | "google" | "openrouter" | "compatible" | undefined;
|
|
109
|
-
model?: string |
|
|
122
|
+
model?: string | {
|
|
123
|
+
code?: string | undefined;
|
|
124
|
+
plan?: string | undefined;
|
|
125
|
+
partition?: string | undefined;
|
|
126
|
+
} | undefined;
|
|
110
127
|
base_url?: string | undefined;
|
|
111
128
|
api_key?: string | undefined;
|
|
112
129
|
temperature?: number | undefined;
|
|
113
130
|
top_p?: number | undefined;
|
|
114
131
|
}, {
|
|
115
132
|
provider?: "openai" | "anthropic" | "google" | "openrouter" | "compatible" | undefined;
|
|
116
|
-
model?: string |
|
|
133
|
+
model?: string | {
|
|
134
|
+
code?: string | undefined;
|
|
135
|
+
plan?: string | undefined;
|
|
136
|
+
partition?: string | undefined;
|
|
137
|
+
} | undefined;
|
|
117
138
|
base_url?: string | undefined;
|
|
118
139
|
api_key?: string | undefined;
|
|
119
140
|
temperature?: number | undefined;
|
|
120
141
|
top_p?: number | undefined;
|
|
121
142
|
}>>;
|
|
122
143
|
}, "strip", z.ZodTypeAny, {
|
|
123
|
-
plan
|
|
144
|
+
plan?: string | undefined;
|
|
124
145
|
iteration_count?: number | undefined;
|
|
125
146
|
changed_files?: string[] | undefined;
|
|
147
|
+
plan_file?: string | undefined;
|
|
126
148
|
project_context?: {
|
|
127
149
|
file_tree?: string | undefined;
|
|
128
150
|
changed_files?: string[] | undefined;
|
|
@@ -158,16 +180,21 @@ export declare const PlanReviewInputSchema: z.ZodObject<{
|
|
|
158
180
|
max_review_iterations?: number | undefined;
|
|
159
181
|
reviewer_config?: {
|
|
160
182
|
provider?: "openai" | "anthropic" | "google" | "openrouter" | "compatible" | undefined;
|
|
161
|
-
model?: string |
|
|
183
|
+
model?: string | {
|
|
184
|
+
code?: string | undefined;
|
|
185
|
+
plan?: string | undefined;
|
|
186
|
+
partition?: string | undefined;
|
|
187
|
+
} | undefined;
|
|
162
188
|
base_url?: string | undefined;
|
|
163
189
|
api_key?: string | undefined;
|
|
164
190
|
temperature?: number | undefined;
|
|
165
191
|
top_p?: number | undefined;
|
|
166
192
|
} | undefined;
|
|
167
193
|
}, {
|
|
168
|
-
plan
|
|
194
|
+
plan?: string | undefined;
|
|
169
195
|
iteration_count?: number | undefined;
|
|
170
196
|
changed_files?: string[] | undefined;
|
|
197
|
+
plan_file?: string | undefined;
|
|
171
198
|
project_context?: {
|
|
172
199
|
file_tree?: string | undefined;
|
|
173
200
|
changed_files?: string[] | undefined;
|
|
@@ -203,7 +230,11 @@ export declare const PlanReviewInputSchema: z.ZodObject<{
|
|
|
203
230
|
max_review_iterations?: number | undefined;
|
|
204
231
|
reviewer_config?: {
|
|
205
232
|
provider?: "openai" | "anthropic" | "google" | "openrouter" | "compatible" | undefined;
|
|
206
|
-
model?: string |
|
|
233
|
+
model?: string | {
|
|
234
|
+
code?: string | undefined;
|
|
235
|
+
plan?: string | undefined;
|
|
236
|
+
partition?: string | undefined;
|
|
237
|
+
} | undefined;
|
|
207
238
|
base_url?: string | undefined;
|
|
208
239
|
api_key?: string | undefined;
|
|
209
240
|
temperature?: number | undefined;
|
|
@@ -389,6 +420,7 @@ export declare const PlanReviewMcpOutputSchema: z.ZodObject<{
|
|
|
389
420
|
iteration_count: z.ZodNumber;
|
|
390
421
|
iteration_limit: z.ZodNumber;
|
|
391
422
|
iteration_limit_reached: z.ZodBoolean;
|
|
423
|
+
cost_warning: z.ZodNullable<z.ZodOptional<z.ZodString>>;
|
|
392
424
|
} & {
|
|
393
425
|
token_usage: z.ZodObject<{
|
|
394
426
|
input_tokens: z.ZodNumber;
|
|
@@ -469,6 +501,7 @@ export declare const PlanReviewMcpOutputSchema: z.ZodObject<{
|
|
|
469
501
|
symptom_match_notes: string | null;
|
|
470
502
|
gates_tripped: string[] | null;
|
|
471
503
|
review_id: string;
|
|
504
|
+
cost_warning?: string | null | undefined;
|
|
472
505
|
}, {
|
|
473
506
|
iteration_count: number;
|
|
474
507
|
iteration_limit: number;
|
|
@@ -517,6 +550,7 @@ export declare const PlanReviewMcpOutputSchema: z.ZodObject<{
|
|
|
517
550
|
symptom_match_notes: string | null;
|
|
518
551
|
gates_tripped: string[] | null;
|
|
519
552
|
review_id: string;
|
|
553
|
+
cost_warning?: string | null | undefined;
|
|
520
554
|
}>;
|
|
521
555
|
export type PlanReviewInput = z.infer<typeof PlanReviewInputSchema>;
|
|
522
556
|
export type PlanReviewOutput = z.infer<typeof PlanReviewOutputSchema>;
|
|
@@ -25,7 +25,21 @@ export const ProjectContextSchema = z.object({
|
|
|
25
25
|
'that are relevant to the plan but not part of the change itself.'),
|
|
26
26
|
});
|
|
27
27
|
export const PlanReviewInputSchema = z.object({
|
|
28
|
-
plan: z
|
|
28
|
+
plan: z
|
|
29
|
+
.string()
|
|
30
|
+
.optional()
|
|
31
|
+
.describe('Full implementation plan text (markdown). REQUIRED unless plan_file is provided. ' +
|
|
32
|
+
'Include: problem statement (quote user request), files to create/modify with paths, ' +
|
|
33
|
+
'approach, edge cases, dependencies. ' +
|
|
34
|
+
'If the plan is large, prefer writing it to a file and passing plan_file instead — ' +
|
|
35
|
+
'inlining a very large plan string here can make the tool call fail to serialize.'),
|
|
36
|
+
plan_file: z
|
|
37
|
+
.string()
|
|
38
|
+
.optional()
|
|
39
|
+
.describe('Relative path (within workspace_root) to a markdown file containing the full plan, ' +
|
|
40
|
+
'e.g. ".duul/plan.md". Use this instead of inlining `plan` when the plan is large: ' +
|
|
41
|
+
'write the plan to the file first, then pass its path here. ' +
|
|
42
|
+
'Exactly one of `plan` or `plan_file` is required. Requires workspace_root. Must be a relative path.'),
|
|
29
43
|
project_context: ProjectContextSchema.optional().describe('Structured project context'),
|
|
30
44
|
constraints: z
|
|
31
45
|
.array(z.string())
|
|
@@ -3,4 +3,22 @@
|
|
|
3
3
|
* Handles all 8 standard tools + get_git_diff.
|
|
4
4
|
*/
|
|
5
5
|
import { type WorkspaceScope } from './filesystem.js';
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Mutable per-review byte counter. Passed by reference into executeFilesystemTool
|
|
8
|
+
* so every successful tool return adds to `used`, and calls short-circuit once
|
|
9
|
+
* `used >= cap`.
|
|
10
|
+
*/
|
|
11
|
+
export interface ReviewerByteBudget {
|
|
12
|
+
used: number;
|
|
13
|
+
cap: number;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Resolve the reviewer file-read cap from env. Opt-in: if DUUL_MAX_REVIEWER_BYTES
|
|
17
|
+
* is unset/invalid, returns Infinity (no cap). Measurements showed a 200KB default
|
|
18
|
+
* was too tight — ~1/3 of code reviews hit the cap and spent extra rounds.
|
|
19
|
+
* Cost-conscious setups can opt in explicitly; 200000–500000 is a reasonable
|
|
20
|
+
* starting range, tune based on typical review complexity (see README).
|
|
21
|
+
*/
|
|
22
|
+
export declare function getMaxReviewerBytes(): number;
|
|
23
|
+
export declare function createReviewerByteBudget(cap?: number): ReviewerByteBudget;
|
|
24
|
+
export declare function executeFilesystemTool(projectRoot: string, toolName: string, args: Record<string, unknown>, scope?: WorkspaceScope | null, budget?: ReviewerByteBudget): Promise<string>;
|
|
@@ -3,35 +3,72 @@
|
|
|
3
3
|
* Handles all 8 standard tools + get_git_diff.
|
|
4
4
|
*/
|
|
5
5
|
import { readProjectFile, listProjectDirectory, searchInFiles, readProjectFileRange, statProjectFile, readJsonValue, listTrackedFiles, getGitDiff, } from './filesystem.js';
|
|
6
|
-
|
|
6
|
+
/**
|
|
7
|
+
* Resolve the reviewer file-read cap from env. Opt-in: if DUUL_MAX_REVIEWER_BYTES
|
|
8
|
+
* is unset/invalid, returns Infinity (no cap). Measurements showed a 200KB default
|
|
9
|
+
* was too tight — ~1/3 of code reviews hit the cap and spent extra rounds.
|
|
10
|
+
* Cost-conscious setups can opt in explicitly; 200000–500000 is a reasonable
|
|
11
|
+
* starting range, tune based on typical review complexity (see README).
|
|
12
|
+
*/
|
|
13
|
+
export function getMaxReviewerBytes() {
|
|
14
|
+
const raw = process.env.DUUL_MAX_REVIEWER_BYTES;
|
|
15
|
+
if (!raw)
|
|
16
|
+
return Infinity;
|
|
17
|
+
const parsed = parseInt(raw, 10);
|
|
18
|
+
if (isNaN(parsed) || parsed <= 0)
|
|
19
|
+
return Infinity;
|
|
20
|
+
return parsed;
|
|
21
|
+
}
|
|
22
|
+
export function createReviewerByteBudget(cap) {
|
|
23
|
+
return { used: 0, cap: cap ?? getMaxReviewerBytes() };
|
|
24
|
+
}
|
|
25
|
+
function budgetExhaustedMessage(budget) {
|
|
26
|
+
return `Reviewer file budget exhausted (used ${budget.used} / cap ${budget.cap} bytes). Rely on context already gathered. Do NOT request more files — submit your verdict.`;
|
|
27
|
+
}
|
|
28
|
+
export async function executeFilesystemTool(projectRoot, toolName, args, scope, budget) {
|
|
29
|
+
if (budget && budget.used >= budget.cap) {
|
|
30
|
+
return budgetExhaustedMessage(budget);
|
|
31
|
+
}
|
|
7
32
|
try {
|
|
33
|
+
let result;
|
|
8
34
|
switch (toolName) {
|
|
9
35
|
case 'read_file': {
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
36
|
+
const content = await readProjectFile(projectRoot, args.path, scope);
|
|
37
|
+
result = content.length > 50_000
|
|
38
|
+
? `\u26a0\ufe0f This file is large (${content.length} chars). Consider using read_file_range or search_in_files instead.\n\n${content}`
|
|
39
|
+
: content;
|
|
40
|
+
break;
|
|
15
41
|
}
|
|
16
42
|
case 'list_directory':
|
|
17
|
-
|
|
43
|
+
result = await listProjectDirectory(projectRoot, args.path, scope);
|
|
44
|
+
break;
|
|
18
45
|
case 'search_in_files':
|
|
19
|
-
|
|
46
|
+
result = await searchInFiles(projectRoot, args.query, args.paths, args.glob, scope?.trackedOnly, scope?.workingDirectories, scope);
|
|
47
|
+
break;
|
|
20
48
|
case 'read_file_range':
|
|
21
|
-
|
|
49
|
+
result = await readProjectFileRange(projectRoot, args.path, args.start_line, args.end_line, scope);
|
|
50
|
+
break;
|
|
22
51
|
case 'stat_file':
|
|
23
|
-
|
|
52
|
+
result = await statProjectFile(projectRoot, args.path, scope);
|
|
53
|
+
break;
|
|
24
54
|
case 'read_json':
|
|
25
|
-
|
|
55
|
+
result = await readJsonValue(projectRoot, args.path, args.json_pointer, scope);
|
|
56
|
+
break;
|
|
26
57
|
case 'list_tracked_files': {
|
|
27
58
|
const files = await listTrackedFiles(projectRoot, args.prefix, scope);
|
|
28
|
-
|
|
59
|
+
result = files.join('\n') || 'No tracked files found.';
|
|
60
|
+
break;
|
|
29
61
|
}
|
|
30
62
|
case 'get_git_diff':
|
|
31
|
-
|
|
63
|
+
result = await getGitDiff(projectRoot, args.base, args.paths, scope);
|
|
64
|
+
break;
|
|
32
65
|
default:
|
|
33
66
|
return `Unknown tool: ${toolName}`;
|
|
34
67
|
}
|
|
68
|
+
if (budget && Number.isFinite(budget.cap)) {
|
|
69
|
+
budget.used += Buffer.byteLength(result, 'utf8');
|
|
70
|
+
}
|
|
71
|
+
return result;
|
|
35
72
|
}
|
|
36
73
|
catch (error) {
|
|
37
74
|
return `Error: ${error instanceof Error ? error.message : String(error)}`;
|