@tea-agent/loop-agent 0.39.0-next.10 → 0.39.0-next.11
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 +1 -0
- package/dist/build-stamp.json +2 -2
- package/dist/workflows/dag/contract-validator-registrations.js +2 -1
- package/dist/workflows/dag/frontend-implementation-contract.js +40 -0
- package/dist/workflows/dag/init-hybrid.js +1 -1
- package/dist/workflows/dag/node-execution.js +15 -3
- package/dist/workflows/dag/types.js +1 -0
- package/package.json +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
|
|
24
24
|
### 修复
|
|
25
25
|
|
|
26
|
+
- `frontend-plan-revision-pi` 节点级校验与 merge-patch 输出协议矛盾修复:新增 schemaId `frontend-implementation-contract-revision-patch-v1` 与格式级宽松校验 `validateFrontendRevisionPatchNodeOutput`(至少一个 `openspec-citations` 块 + 剥离引用块后恰好一个 JSON 对象,不做完整契约 schema 校验),revision 节点 `structuredContractOutput.schemaId` 切换(plan-pi 仍为 v1);node-execution 的 invalid-output retry 指令按 schemaId 分支,patch 协议提示 merge-patch delta + 引用块,消除「prompt 要求 patch、retry 要求完整契约」的 retryable 死循环;gate 仍是唯一权威合并/校验点(零改动)。ADR 0015 补「节点级校验」决策 7
|
|
26
27
|
- `frontend-implementation-contract.schema.json` 的 `uiComponentChoices` items 补 `if/then` 决策语义(`specified` ⇒ `specReference` 必填非 null;`new` ⇒ `specReference` 为 null/缺失);`frontend-plan-render.ts` 空 `section` 不再渲染尾随 `#`;ADR 0016 增补「门禁边界」小节
|
|
27
28
|
|
|
28
29
|
### 文档
|
package/dist/build-stamp.json
CHANGED
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
* its schemaId in the contract output registry. Imported once by the node
|
|
4
4
|
* executor; keeps per-contract imports out of the executor.
|
|
5
5
|
*/
|
|
6
|
-
import { validateFrontendContractNodeOutput } from "./frontend-implementation-contract.js";
|
|
6
|
+
import { validateFrontendContractNodeOutput, validateFrontendRevisionPatchNodeOutput, } from "./frontend-implementation-contract.js";
|
|
7
7
|
import { registerStructuredContractValidator } from "./contract-output-registry.js";
|
|
8
8
|
registerStructuredContractValidator("frontend-implementation-contract-v1", validateFrontendContractNodeOutput);
|
|
9
|
+
registerStructuredContractValidator("frontend-implementation-contract-revision-patch-v1", validateFrontendRevisionPatchNodeOutput);
|
|
@@ -1632,6 +1632,46 @@ export async function validateFrontendContractNodeOutput(input) {
|
|
|
1632
1632
|
};
|
|
1633
1633
|
}
|
|
1634
1634
|
}
|
|
1635
|
+
/**
|
|
1636
|
+
* Node-output self-check for the plan revision node, which emits an RFC 7386
|
|
1637
|
+
* merge-patch delta against the original contract instead of a full contract.
|
|
1638
|
+
* Deliberately loose and format-level: the output must contain at least one
|
|
1639
|
+
* ```openspec-citations fenced block and must extract (after the citations
|
|
1640
|
+
* blocks are stripped) to exactly one JSON object. The delta carries no
|
|
1641
|
+
* schemaVersion/targets, so no full-contract schema/semantic checks run here;
|
|
1642
|
+
* content parsing, patch application, and merged-contract validation stay with
|
|
1643
|
+
* the prewrite gate, which remains the only authority.
|
|
1644
|
+
*/
|
|
1645
|
+
export async function validateFrontendRevisionPatchNodeOutput(input) {
|
|
1646
|
+
// Mirror the prewrite gate's block-presence semantics (a fenced
|
|
1647
|
+
// ```openspec-citations block with a newline-terminated body).
|
|
1648
|
+
if (!/```openspec-citations[ \t]*\r?\n[\s\S]*?\r?\n```/.test(input.text)) {
|
|
1649
|
+
return {
|
|
1650
|
+
ok: false,
|
|
1651
|
+
reason: "revision patch output must include at least one ```openspec-citations fenced block",
|
|
1652
|
+
};
|
|
1653
|
+
}
|
|
1654
|
+
// Strip the citation blocks before extraction: their per-row JSON objects
|
|
1655
|
+
// would otherwise count as competing balanced objects in the extractor.
|
|
1656
|
+
const textWithoutCitations = input.text.replace(/```openspec-citations[ \t]*\r?\n[\s\S]*?\r?\n```/g, "");
|
|
1657
|
+
let patch;
|
|
1658
|
+
try {
|
|
1659
|
+
patch = extractFrontendImplementationJson(textWithoutCitations);
|
|
1660
|
+
}
|
|
1661
|
+
catch (error) {
|
|
1662
|
+
return {
|
|
1663
|
+
ok: false,
|
|
1664
|
+
reason: `revision patch output must contain exactly one valid JSON object: ${error instanceof Error ? error.message : String(error)}`,
|
|
1665
|
+
};
|
|
1666
|
+
}
|
|
1667
|
+
if (!patch || typeof patch !== "object" || Array.isArray(patch)) {
|
|
1668
|
+
return {
|
|
1669
|
+
ok: false,
|
|
1670
|
+
reason: "revision patch output must extract to exactly one JSON object (RFC 7386 merge-patch delta)",
|
|
1671
|
+
};
|
|
1672
|
+
}
|
|
1673
|
+
return { ok: true, contract: patch };
|
|
1674
|
+
}
|
|
1635
1675
|
export async function materializeFrontendImplementationContract(input) {
|
|
1636
1676
|
const analysis = await analyzeFrontendImplementationContract(input);
|
|
1637
1677
|
return writeFrontendImplementationContractArtifact({
|
|
@@ -2859,7 +2859,7 @@ async function buildFrontendHybridDagFromTask(sources) {
|
|
|
2859
2859
|
outputMode: "structured-required",
|
|
2860
2860
|
retryPolicy: STRUCTURED_REQUIRED_PI_RETRY_POLICY,
|
|
2861
2861
|
structuredContractOutput: {
|
|
2862
|
-
schemaId: "frontend-implementation-contract-v1",
|
|
2862
|
+
schemaId: "frontend-implementation-contract-revision-patch-v1",
|
|
2863
2863
|
retryOnInvalid: true,
|
|
2864
2864
|
},
|
|
2865
2865
|
allowedPaths: readOnlyPaths,
|
|
@@ -144,15 +144,27 @@ function buildAttemptPrompt(task, basePrompt, attemptNumber, previousFailureCate
|
|
|
144
144
|
if (previousFailureCategory === "invalid-output" &&
|
|
145
145
|
task.structuredContractOutput &&
|
|
146
146
|
previousProtocolReason) {
|
|
147
|
+
// Revision nodes emit an RFC 7386 merge-patch delta (no schemaVersion /
|
|
148
|
+
// targets), so the retry instruction must not push them toward a full
|
|
149
|
+
// contract rewrite; plan nodes keep the strict v1 guidance.
|
|
150
|
+
const guidance = task.structuredContractOutput.schemaId ===
|
|
151
|
+
"frontend-implementation-contract-revision-patch-v1"
|
|
152
|
+
? [
|
|
153
|
+
"Return exactly one fenced json object containing the RFC 7386 merge-patch delta against the original contract (null deletes a key; arrays and scalars replace; plain objects merge recursively) + exactly one openspec-citations block.",
|
|
154
|
+
"The delta contains only the fields you change; do not emit a full contract or a schemaVersion/targets section.",
|
|
155
|
+
]
|
|
156
|
+
: [
|
|
157
|
+
"Return exactly one fenced json block conforming to the frontend-implementation-contract-v1 schema.",
|
|
158
|
+
"Fix every reported field violation: do not emit null for optional fields, do not misspell field names, and match the required types exactly.",
|
|
159
|
+
"The Markdown explanation may be omitted; prioritize a complete contract.",
|
|
160
|
+
];
|
|
147
161
|
return [
|
|
148
162
|
basePrompt,
|
|
149
163
|
"",
|
|
150
164
|
"<retry_instruction>",
|
|
151
165
|
"Previous attempt produced an invalid frontend implementation contract:",
|
|
152
166
|
previousProtocolReason,
|
|
153
|
-
|
|
154
|
-
"Fix every reported field violation: do not emit null for optional fields, do not misspell field names, and match the required types exactly.",
|
|
155
|
-
"The Markdown explanation may be omitted; prioritize a complete contract.",
|
|
167
|
+
...guidance,
|
|
156
168
|
"</retry_instruction>",
|
|
157
169
|
].join("\n");
|
|
158
170
|
}
|
|
@@ -704,6 +704,7 @@ export const dagConvergenceSpecSchema = z
|
|
|
704
704
|
*/
|
|
705
705
|
export const structuredContractOutputSchemaIds = [
|
|
706
706
|
"frontend-implementation-contract-v1",
|
|
707
|
+
"frontend-implementation-contract-revision-patch-v1",
|
|
707
708
|
];
|
|
708
709
|
export const dagTaskSchema = z.object({ id: z.string().regex(/^[a-z][a-z0-9-]*$/, "task id must be kebab-case"),
|
|
709
710
|
depends_on: z.array(z.string()).default([]),
|