@dtlabs/ai-toolkit 0.24.3 → 0.24.5
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/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,20 @@
|
|
|
1
1
|
## 0.1.4 (2026-07-21)
|
|
2
|
+
## [0.24.5](https://github.com/dtlab-tech/ai-toolkit/compare/v0.24.4...v0.24.5) (2026-10-27)
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
### Bug Fixes
|
|
6
|
+
|
|
7
|
+
* **pm-phase2:** run the semantic WB validator per phase ([3f279e6](https://github.com/dtlab-tech/ai-toolkit/commit/3f279e6e386eee6c86cea90caec7e5d64b6aa756))
|
|
8
|
+
* **pm-phase2:** run the semantic WB validator per phase, not once over the whole breakdown ([62389cb](https://github.com/dtlab-tech/ai-toolkit/commit/62389cbb8fcf70f4019ee83ed9f8a5a99a96dd23))
|
|
9
|
+
|
|
10
|
+
## [0.24.4](https://github.com/dtlab-tech/ai-toolkit/compare/v0.24.3...v0.24.4) (2026-10-27)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
### Bug Fixes
|
|
14
|
+
|
|
15
|
+
* **pm-phase2:** regenerate a task whose Estimate is stale, not just missing verification commands ([a772767](https://github.com/dtlab-tech/ai-toolkit/commit/a772767a9d960bfe468829651e7ca2cbc7c6a17e))
|
|
16
|
+
* regenerate a task whose Estimate is stale, not just missing verification commands ([e9d794b](https://github.com/dtlab-tech/ai-toolkit/commit/e9d794b81575c49e95d0291174964058fafd009b))
|
|
17
|
+
|
|
2
18
|
## [0.24.3](https://github.com/dtlab-tech/ai-toolkit/compare/v0.24.2...v0.24.3) (2026-10-27)
|
|
3
19
|
|
|
4
20
|
|
package/package.json
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: gaia-validate-work-breakdown-semantic
|
|
3
|
-
description: "Semantic validator for Work Breakdown
|
|
3
|
+
description: "Semantic validator for one phase of a Work Breakdown — analyzes task coherence, scope alignment, and estimate realism. Runs once per phase after wb-validate.js exits 0. Input: the phase's inlined task details, a scoped Requirements excerpt, and an index of other tasks"
|
|
4
4
|
model: sonnet
|
|
5
|
-
tools: Read
|
|
5
|
+
tools: Read
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
# Validate Work Breakdown — Semantic
|
|
@@ -15,17 +15,16 @@ You do NOT repeat structural checks (schema conformance, required fields, ID for
|
|
|
15
15
|
|
|
16
16
|
## Input
|
|
17
17
|
|
|
18
|
-
|
|
18
|
+
Your prompt directly inlines everything you need — you review ONE phase per call:
|
|
19
19
|
|
|
20
|
-
1.
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
(FTR-021; User Story descriptions and Acceptance Criteria text live in its own tables there,
|
|
25
|
-
unaffected by the per-UC split), or a legacy `{PREFIX}-Requirements.md` file otherwise. Read
|
|
26
|
-
whichever path is actually given — do not assume either shape.
|
|
20
|
+
1. **Requirements source path** and a **scoped Requirements excerpt** — feature-wide sections in full, plus only the use case(s) this phase realizes.
|
|
21
|
+
2. **The phase under review** — its id, type, title, and `sourceUC`.
|
|
22
|
+
3. **Task details for THIS phase only** — the full detail file of every task in the phase. These are what you review.
|
|
23
|
+
4. **Other tasks in the feature** — a one-line index (id — title — outcome) of every task outside this phase. Use it only to recognize a duplicate of work another phase already owns; do not review those tasks.
|
|
27
24
|
|
|
28
|
-
|
|
25
|
+
Do **not** read any file yourself. Do **not** explore the filesystem. Everything you need is in your prompt, and another call reviews every other phase.
|
|
26
|
+
|
|
27
|
+
Because each call sees only one phase, cross-phase concerns are out of scope for you. Judge the tasks in front of you.
|
|
29
28
|
|
|
30
29
|
---
|
|
31
30
|
|
|
@@ -98,4 +97,4 @@ Or when issues are found:
|
|
|
98
97
|
|
|
99
98
|
## Tool use
|
|
100
99
|
|
|
101
|
-
|
|
100
|
+
None needed — everything is inlined. Do not write any files. Do not produce any output other than the single JSON object described above.
|
|
@@ -375,6 +375,21 @@ function buildAgentsConventions(root) {
|
|
|
375
375
|
return kept.length ? kept.join('\n').trim() : null
|
|
376
376
|
}
|
|
377
377
|
|
|
378
|
+
// Per-phase semantic validation prompt. The whole-WB validator used to receive a directory path and
|
|
379
|
+
// explore it itself with Read/Glob/Grep — on a 123-task feature that single unbounded turn hit the
|
|
380
|
+
// 30-minute worker ceiling, the same failure mode FTR-033 removed from skeleton generation. Each
|
|
381
|
+
// call now sees only its own phase's task details, a one-line index of every OTHER task (for
|
|
382
|
+
// duplicate-across-phases awareness), and that phase's scoped Requirements excerpt.
|
|
383
|
+
function buildSemanticPhasePrompt(phase, taskDetailsText, otherTasksText, requirementsExcerpt, reqIndexPath) {
|
|
384
|
+
return [
|
|
385
|
+
`Requirements source: ${reqIndexPath}`,
|
|
386
|
+
`Phase under review:\n${JSON.stringify({ id: phase.id, type: phase.type, title: phase.title, sourceUC: phase.sourceUC }, null, 2)}`,
|
|
387
|
+
`Requirements (scoped to this phase's own sourceUC, plus feature-wide sections):\n${requirementsExcerpt}`,
|
|
388
|
+
`Task details for THIS phase (review these):\n${taskDetailsText}`,
|
|
389
|
+
`Other tasks in the feature (id — title — outcome; for cross-phase duplicate awareness only, do not review them):\n${otherTasksText || '(none)'}`,
|
|
390
|
+
].join('\n\n')
|
|
391
|
+
}
|
|
392
|
+
|
|
378
393
|
// Compact prompt for the per-phase task-generation worker: this phase's own skeleton entry, its
|
|
379
394
|
// scoped Requirements excerpt, the Tech-Spec skeleton, and every prior phase's own tasks as a
|
|
380
395
|
// lightweight id/title/outcome/domain projection (never a later phase's tasks, which do not exist
|
|
@@ -440,6 +455,21 @@ function hasVerificationCommands(content) {
|
|
|
440
455
|
return FENCE_RE_LOCAL.test(verifPart)
|
|
441
456
|
}
|
|
442
457
|
|
|
458
|
+
// Same resume-validity role as hasVerificationCommands, for the OTHER field this agent's own
|
|
459
|
+
// prompt once asked it to merely restate (removed from "already given" wording in a prior fix —
|
|
460
|
+
// see gaia-generate-work-breakdown-task.md's own Estimate section) but which a task file
|
|
461
|
+
// generated BEFORE that fix can still carry as a literal "—" or explanatory prose instead of a
|
|
462
|
+
// number: wbs-assembler.js's own _numberOrNull throws on exactly that shape at assembly time,
|
|
463
|
+
// well after the dispatch loop below would have skipped regenerating it. A task file whose
|
|
464
|
+
// Estimate fields are not both plain integers is treated the same as one with zero verification
|
|
465
|
+
// commands — regenerated, not skipped forever — so a stale pre-fix file self-heals on the very
|
|
466
|
+
// next resume instead of requiring a hand-fix or a one-off repair script.
|
|
467
|
+
function hasValidEstimate(content) {
|
|
468
|
+
const minutes = content.match(/^- \*\*Estimate — agent minutes:\*\*\s*(.*)$/m)
|
|
469
|
+
const tokens = content.match(/^- \*\*Estimate — tokens:\*\*\s*(.*)$/m)
|
|
470
|
+
return !!minutes && !!tokens && /^\d+$/.test(minutes[1].trim()) && /^\d+$/.test(tokens[1].trim())
|
|
471
|
+
}
|
|
472
|
+
|
|
443
473
|
// Compact prompt for the per-task detail-generation worker: this task's own skeleton entry,
|
|
444
474
|
// a sibling task list (id + title + outcome only, for duplicate-implementation awareness), and
|
|
445
475
|
// the Tech-Spec excerpt (FTR-026: already pre-sliced to this task's own relevant component(s) by
|
|
@@ -637,7 +667,10 @@ return c.run(meta.name, featureDir, prefix, async () => {
|
|
|
637
667
|
for (const taskId of phase.taskIds) {
|
|
638
668
|
const task = index.tasks[taskId]
|
|
639
669
|
const detailPath = `${wbsDir}/${task.detailFile}`
|
|
640
|
-
if (task.status === 'generated' && c.exists(detailPath)
|
|
670
|
+
if (task.status === 'generated' && c.exists(detailPath)) {
|
|
671
|
+
const existing = c.read(detailPath)
|
|
672
|
+
if (hasVerificationCommands(existing) && hasValidEstimate(existing)) continue // resume: skip, no dispatch
|
|
673
|
+
}
|
|
641
674
|
const techSpecExcerpt = hasSpec
|
|
642
675
|
? buildTaskTechSpecExcerpt(components, task, specDir, c.read(specIndexPath))
|
|
643
676
|
: c.read(file('Tech-Spec.md')) // legacy fallback: unchanged, full text
|
|
@@ -660,11 +693,35 @@ return c.run(meta.name, featureDir, prefix, async () => {
|
|
|
660
693
|
if (!parsed.valid || parsed.errors.length) throw new Error('Work breakdown structural validation failed: ' + res.stdout)
|
|
661
694
|
return parsed
|
|
662
695
|
})
|
|
663
|
-
|
|
664
|
-
|
|
665
|
-
|
|
666
|
-
} }
|
|
667
|
-
|
|
696
|
+
// Every phase is reviewed even after one fails, so a single run surfaces every blocking finding
|
|
697
|
+
// at once instead of making the operator fix them one resume at a time.
|
|
698
|
+
const semanticSchema = {
|
|
699
|
+
type: 'object', properties: { valid: { type: 'boolean' }, findings: { type: 'array' } }, required: ['valid', 'findings'],
|
|
700
|
+
}
|
|
701
|
+
const reqIndexForSemantic = c.read(reqIndexPath)
|
|
702
|
+
const allFindings = []
|
|
703
|
+
let semanticValid = true
|
|
704
|
+
for (const phase of index.phases) {
|
|
705
|
+
const phaseTaskIds = phase.taskIds
|
|
706
|
+
const taskDetailsText = phaseTaskIds
|
|
707
|
+
.map(taskId => `### ${taskId}\n\n${c.read(`${wbsDir}/${index.tasks[taskId].detailFile}`)}`).join('\n\n---\n\n')
|
|
708
|
+
const otherTasksText = Object.entries(index.tasks)
|
|
709
|
+
.filter(([id]) => !phaseTaskIds.includes(id))
|
|
710
|
+
.map(([id, t]) => `- ${id} — ${t.title} — ${t.outcome}`).join('\n')
|
|
711
|
+
const requirementsExcerpt = hasReq
|
|
712
|
+
? buildPhaseRequirementsExcerpt(reqIndexForSemantic, phase.sourceUC, reqDir)
|
|
713
|
+
: reqIndexForSemantic
|
|
714
|
+
const verdict = await c.worker('gaia.agent.planner.validate-work-breakdown',
|
|
715
|
+
buildSemanticPhasePrompt(phase, taskDetailsText, otherTasksText, requirementsExcerpt, reqIndexPath),
|
|
716
|
+
{ schema: semanticSchema, label: `validate-work-breakdown:${phase.id}` })
|
|
717
|
+
if (!verdict.valid) semanticValid = false
|
|
718
|
+
for (const finding of verdict.findings) allFindings.push({ ...finding, phaseId: phase.id })
|
|
719
|
+
}
|
|
720
|
+
const semantic = { valid: semanticValid, findings: allFindings }
|
|
721
|
+
if (!semantic.valid || semantic.findings.some(f => f.blocking)) {
|
|
722
|
+
const blocking = semantic.findings.filter(f => f.blocking).map(f => `[${f.phaseId}] ${f.taskId}: ${f.description}`)
|
|
723
|
+
throw new Error('Work breakdown semantic validation failed' + (blocking.length ? ':\n' + blocking.join('\n') : ''))
|
|
724
|
+
}
|
|
668
725
|
// FTR-025: wb-render.js is no longer called automatically here — nothing downstream ever read
|
|
669
726
|
// {PREFIX}-Work-Breakdown.md/.csv (every real consumer already reads wbs/ directly via
|
|
670
727
|
// wbs-assembler.js's loadWorkBreakdown()), so this view is now produced only on demand, via
|