@tea-agent/loop-agent 0.39.0-beta.0 → 0.39.0-beta.1
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/dist/build-stamp.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"version": "0.39.0-beta.
|
|
4
|
-
"gitSha": "
|
|
5
|
-
"builtAt": "2026-08-
|
|
3
|
+
"version": "0.39.0-beta.1",
|
|
4
|
+
"gitSha": "d4e9fcaf663c172451bc1dd0553fbf7132e97132",
|
|
5
|
+
"builtAt": "2026-08-21T06:38:45.518Z"
|
|
6
6
|
}
|
|
@@ -41,9 +41,6 @@ export function serializeDeterministicJson(value) {
|
|
|
41
41
|
export function deterministicSha256(value) {
|
|
42
42
|
return sha256Hex(serializeDeterministicJson(value));
|
|
43
43
|
}
|
|
44
|
-
/** Provider-safe limits for the two planner outputs. Larger work must split. */
|
|
45
|
-
export const FRONTEND_PLAN_RESPONSE_MAX_BYTES = 14 * 1024;
|
|
46
|
-
export const FRONTEND_CANONICAL_CONTRACT_MAX_BYTES = 16 * 1024;
|
|
47
44
|
/** A contract materialization failure carries its classification plus the
|
|
48
45
|
* audit context collected up to the failure point, so the prewrite gate can
|
|
49
46
|
* persist a complete frontend-prewrite-result-v1 even when the canonical
|
|
@@ -1796,9 +1793,6 @@ export async function validateFrontendPlanPatchNodeOutput(input) {
|
|
|
1796
1793
|
});
|
|
1797
1794
|
};
|
|
1798
1795
|
try {
|
|
1799
|
-
if (Buffer.byteLength(input.text, "utf8") > FRONTEND_PLAN_RESPONSE_MAX_BYTES) {
|
|
1800
|
-
throw new Error(`frontend plan response exceeds the ${FRONTEND_PLAN_RESPONSE_MAX_BYTES}-byte limit`);
|
|
1801
|
-
}
|
|
1802
1796
|
if (!input.sourceBinding)
|
|
1803
1797
|
throw new Error("frontend plan patch validator requires DAG sourceBinding");
|
|
1804
1798
|
const skeleton = input.structuredContractOutput?.skeleton;
|
|
@@ -1826,10 +1820,6 @@ export async function validateFrontendPlanPatchNodeOutput(input) {
|
|
|
1826
1820
|
rawContractText: serializeDeterministicJson(merged),
|
|
1827
1821
|
sourceBinding: input.sourceBinding,
|
|
1828
1822
|
});
|
|
1829
|
-
if (Buffer.byteLength(serializeDeterministicJson(analysis.canonical), "utf8") >
|
|
1830
|
-
FRONTEND_CANONICAL_CONTRACT_MAX_BYTES) {
|
|
1831
|
-
throw new Error(`frontend canonical contract exceeds the ${FRONTEND_CANONICAL_CONTRACT_MAX_BYTES}-byte limit; split the task`);
|
|
1832
|
-
}
|
|
1833
1823
|
const normalizedArtifact = await writeDeterministicJsonArtifact(input.runDir, path.posix.join(candidateDir, `attempt-${attempt}.normalized.json`), analysis.canonical);
|
|
1834
1824
|
await writeReport({
|
|
1835
1825
|
classification: "accepted-normalized",
|
|
@@ -1924,12 +1914,6 @@ export async function validateFrontendRevisionPatchNodeOutput(input) {
|
|
|
1924
1914
|
attempt,
|
|
1925
1915
|
text: input.text,
|
|
1926
1916
|
});
|
|
1927
|
-
if (Buffer.byteLength(input.text, "utf8") > FRONTEND_PLAN_RESPONSE_MAX_BYTES) {
|
|
1928
|
-
return {
|
|
1929
|
-
ok: false,
|
|
1930
|
-
reason: `frontend revision response exceeds the ${FRONTEND_PLAN_RESPONSE_MAX_BYTES}-byte limit`,
|
|
1931
|
-
};
|
|
1932
|
-
}
|
|
1933
1917
|
let citationsBlock;
|
|
1934
1918
|
let patch;
|
|
1935
1919
|
try {
|
|
@@ -4,15 +4,13 @@ import { z } from "zod";
|
|
|
4
4
|
import { isOpenspecSpecFilePath } from "../../shared/openspec-spec.js";
|
|
5
5
|
import { writeTextArtifactFile } from "../../infrastructure/harness/artifact-store.js";
|
|
6
6
|
import { countExcludedGovernanceSpecFiles, resolveOpenspecGovernanceRoot, } from "../../task/frontend-project-capability.js";
|
|
7
|
-
import { analyzeFrontendImplementationContract, writeFrontendImplementationContractArtifact, writeDeterministicJsonArtifact, assertFrontendSourceBindingFresh, deterministicSha256, sha256Hex, serializeDeterministicJson,
|
|
7
|
+
import { analyzeFrontendImplementationContract, writeFrontendImplementationContractArtifact, writeDeterministicJsonArtifact, assertFrontendSourceBindingFresh, deterministicSha256, sha256Hex, serializeDeterministicJson, applyFrontendImplementationContractPatch, extractFrontendImplementationJson, FrontendContractFailure, frontendNormalizationActionSchema, } from "./frontend-implementation-contract.js";
|
|
8
8
|
import { renderFrontendPlanMarkdown } from "./frontend-plan-render.js";
|
|
9
9
|
import { captureFrontendWorktreeBaseline } from "./frontend-worktree-diff.js";
|
|
10
10
|
import { pathMatchesPattern } from "../../shared/git-progress.js";
|
|
11
11
|
import { normalizeVerdictCandidateLine } from "./dynamic-runtime/shared.js";
|
|
12
12
|
export const FRONTEND_PREWRITE_RESULT_SCHEMA_ID = "frontend-prewrite-result-v1";
|
|
13
13
|
export const FRONTEND_PREWRITE_RESULT_ARTIFACT_NAME = "frontend-prewrite-result.json";
|
|
14
|
-
/** Canonical contract serialization must stay at or below this byte size. */
|
|
15
|
-
export const FRONTEND_CONTRACT_MAX_BYTES = FRONTEND_CANONICAL_CONTRACT_MAX_BYTES;
|
|
16
14
|
/**
|
|
17
15
|
* Machine-readable failure classification for blocked/retryable-invalid
|
|
18
16
|
* prewrite outcomes. Kept alongside the human-readable failureReason so
|
|
@@ -39,7 +37,6 @@ export const frontendPrewriteFailureCodeSchema = z.enum([
|
|
|
39
37
|
"component-spec-reference-invalid",
|
|
40
38
|
"component-spec-not-cited",
|
|
41
39
|
"component-choices-missing",
|
|
42
|
-
"contract-too-large",
|
|
43
40
|
"revision-patch-unmergeable",
|
|
44
41
|
]);
|
|
45
42
|
export const frontendPrewriteResultV1Schema = z
|
|
@@ -732,21 +729,6 @@ export async function runFrontendPrewriteGate(input) {
|
|
|
732
729
|
}
|
|
733
730
|
throw error;
|
|
734
731
|
}
|
|
735
|
-
// Size guard: a canonical contract above 64KB is a retryable-invalid defect
|
|
736
|
-
// (compress the contract) rather than a writer authorization failure.
|
|
737
|
-
const contractSizeBytes = Buffer.byteLength(serializeDeterministicJson(analysis.canonical), "utf8");
|
|
738
|
-
if (contractSizeBytes > FRONTEND_CONTRACT_MAX_BYTES) {
|
|
739
|
-
return finalizePrewrite(input, {
|
|
740
|
-
...basePending,
|
|
741
|
-
verdict,
|
|
742
|
-
candidateJsonSha256: analysis.candidateJsonSha256,
|
|
743
|
-
normalizationActions: [],
|
|
744
|
-
mockStrategy: analysis.canonical.mockApi.strategy,
|
|
745
|
-
classification: "retryable-invalid",
|
|
746
|
-
failureReason: `frontend prewrite gate: canonical contract serialization is ${contractSizeBytes} bytes, exceeding the ${FRONTEND_CONTRACT_MAX_BYTES}-byte limit. 压缩契约(移除冗余 prose、重复目标或过长描述)后重试。`,
|
|
747
|
-
failureCode: "contract-too-large",
|
|
748
|
-
});
|
|
749
|
-
}
|
|
750
732
|
const mockStrategy = analysis.canonical.mockApi.strategy;
|
|
751
733
|
if (!input.config.allowedMockStrategies.includes(mockStrategy)) {
|
|
752
734
|
const quotedAllowed = input.config.allowedMockStrategies
|
|
@@ -2536,19 +2536,9 @@ async function buildFrontendHybridDagFromTask(sources) {
|
|
|
2536
2536
|
const requirementIds = frontendSourceBinding.requirementIds;
|
|
2537
2537
|
const requirementCoverageInstruction = requirementIds.length > 0
|
|
2538
2538
|
? [
|
|
2539
|
-
|
|
2540
|
-
`
|
|
2541
|
-
|
|
2542
|
-
``,
|
|
2543
|
-
`Bad example (empty expectedOutcome, empty targets -- REJECTED at contract materialization):`,
|
|
2544
|
-
`- AC-001: expectedOutcome="" implementationTargets=[] verificationTargets=[]`,
|
|
2545
|
-
``,
|
|
2546
|
-
`Good example (concrete expectedOutcome, real files, real verification targets):`,
|
|
2547
|
-
`- AC-001: expectedOutcome="TypeScript compilation exits with code 0 and produces no errors in dist/" implementationTargets=["src/app.tsx"] verificationTargets=["vt-typecheck":"npm run typecheck","tsconfig.json"]`,
|
|
2548
|
-
``,
|
|
2549
|
-
...requirementIds.map((id) => `- ${id}: [expectedOutcome] [implementation files] [verification targets]`),
|
|
2550
|
-
``,
|
|
2551
|
-
`Every requirement MUST have a non-empty expectedOutcome. Every interaction MUST have non-empty trigger and expectedBehavior. UI states with applicable=true MUST have non-empty expectedBehavior. Empty strings or omitted fields for these will cause contract rejection.`,
|
|
2539
|
+
"## Requirement Coverage",
|
|
2540
|
+
`Cover each frozen ID exactly once in requirements[]: ${requirementIds.join(", ")}. Each item needs a concrete expectedOutcome, implementationTargets, and verificationTargetIds.`,
|
|
2541
|
+
"Interactions need trigger + expectedBehavior; applicable uiStates need expectedBehavior + implementationTargets + verificationTargetIds. Do not use empty strings.",
|
|
2552
2542
|
].join("\n")
|
|
2553
2543
|
: "";
|
|
2554
2544
|
const verificationTargetFileInstruction = [
|
|
@@ -2562,6 +2552,11 @@ async function buildFrontendHybridDagFromTask(sources) {
|
|
|
2562
2552
|
"Before producing this contract/plan, use the Pi read tool to read the FULL bound source files (需求.md, 执行约束.md, and every `references/*` Bound readPath listed above) — the inline copies above may be truncated excerpts, and requirement/acceptance references are authoritative only in their full form.",
|
|
2563
2553
|
"Do not drop scope fields, acceptance criteria, non-goals, UI states, or column/field definitions that exist in the full sources but are absent from the inline excerpts; if a field appears in the full source, it belongs in the contract.",
|
|
2564
2554
|
].join("\n");
|
|
2555
|
+
const plannerSourceReadInstruction = [
|
|
2556
|
+
"## Source-read policy",
|
|
2557
|
+
"Use the injected task sources plus frontend-contract-pi and frontend-scout-pi as the primary evidence. Do not repeat reads that those facts already settle.",
|
|
2558
|
+
"Read a bound source only to resolve a missing or conflicting field; read every applicable OpenSpec candidate directly before citing it. Never infer omitted task fields from a preview.",
|
|
2559
|
+
].join("\n");
|
|
2565
2560
|
const strategy = resolveDagVerifyStrategy(taskConfig);
|
|
2566
2561
|
const readOnlyPaths = taskConfig.allowedPaths.length > 0 ? taskConfig.allowedPaths : ["**"];
|
|
2567
2562
|
const behaviorPaths = deriveFrontendBehaviorPaths(taskConfig);
|
|
@@ -2799,7 +2794,7 @@ async function buildFrontendHybridDagFromTask(sources) {
|
|
|
2799
2794
|
allowedPaths: readOnlyPaths,
|
|
2800
2795
|
forbiddenPaths,
|
|
2801
2796
|
skills: [],
|
|
2802
|
-
outputContract: "JSON-only patch output:
|
|
2797
|
+
outputContract: "JSON-only patch output: exactly ONE fenced json object (```json ... ```) containing only the editable RFC 7386 plan patch for the runtime contract skeleton, immediately followed by exactly one ```openspec-citations``` fenced citation block. Omit protected fields: schemaVersion, sourceBinding, riskLevel, targets.files, and mockApi.productionDefaultOff. The runtime applies the patch, validates it, and promotes canonical full-contract JSON for downstream review. Do NOT emit a full contract, Markdown plan explanation, raw JSON, or any other fenced block. No file writes.",
|
|
2803
2798
|
subtask_prompt: [
|
|
2804
2799
|
"Use frontend-contract-pi, frontend-scout-pi, task sources, and the generation-time Mock capability evidence to fill the runtime-owned frontend contract skeleton. Return JSON-only output containing only an editable RFC 7386 plan patch. The runtime already owns schemaVersion, sourceBinding, riskLevel, targets.files, and mockApi.productionDefaultOff; omit those protected paths even when their values look obvious.",
|
|
2805
2800
|
"The patch fields become the complete implementation plan after deterministic merge. Do not produce a separate plan document, prose mirror, or full contract.",
|
|
@@ -2807,13 +2802,13 @@ async function buildFrontendHybridDagFromTask(sources) {
|
|
|
2807
2802
|
"Encode ordered steps (implementationSteps), target files, UI state handling, styling/component strategy (stylingStrategy), interaction notes, Mock/API strategy, dependency policy (dependencyPolicy), deterministic verification entrypoints, Real Integration Gap (realIntegrationGap), and residual risks (residualRisks) into the contract JSON fields. Use only the fixed entrypoints below; implementation may add tests behind them but cannot replace them.",
|
|
2808
2803
|
"Every target file and verification target must be selected from the current target workspace and task scope. Do not reuse paths or symbols from examples, prior tasks, or loop-agent itself; if the project uses app/, packages/, spec/, __tests__, or another layout, preserve that layout.",
|
|
2809
2804
|
"Consume the Scout TARGET_SURFACE evidence before selecting files. Preserve the discovered existing entrypoint and data source. If implementationPaths or testPaths are outside task allowedPaths, record a blocking scope conflict; do not substitute a new page or silently broaden the writeSet.",
|
|
2810
|
-
"Output
|
|
2805
|
+
"Output exactly two adjacent blocks: (1) one fenced json object containing the editable plan patch; (2) one openspec-citations citation block. Do NOT emit protected skeleton fields, a full contract, Markdown plan explanation, raw JSON, or any other fenced block.",
|
|
2811
2806
|
"Each requirement must state its user-observable or logic-observable expectedOutcome. Each interaction must state its trigger and expectedBehavior. IDs plus file paths are not sufficient behavior semantics.",
|
|
2812
2807
|
requirementCoverageInstruction,
|
|
2813
2808
|
"verificationTargets[].commandLabel MUST be one of the frozen command labels listed above. Any other value will be rejected at contract materialization.",
|
|
2814
2809
|
verificationTargetFileInstruction,
|
|
2815
2810
|
"Read-only: do not modify code, docs, artifacts, or repository files.",
|
|
2816
|
-
|
|
2811
|
+
plannerSourceReadInstruction,
|
|
2817
2812
|
fixedVerificationContext,
|
|
2818
2813
|
sourceContext,
|
|
2819
2814
|
mockContextBlock,
|
|
@@ -2866,15 +2861,15 @@ async function buildFrontendHybridDagFromTask(sources) {
|
|
|
2866
2861
|
allowedPaths: readOnlyPaths,
|
|
2867
2862
|
forbiddenPaths,
|
|
2868
2863
|
skills: [],
|
|
2869
|
-
outputContract: "When the initial design review requests revision, return
|
|
2864
|
+
outputContract: "When the initial design review requests revision, return exactly ONE fenced json object (```json ... ```) containing an RFC 7386 merge-patch delta against the original frontend-implementation-contract-v1 (only the fields you change; null deletes a key; arrays and scalars replace; plain objects merge recursively), immediately followed by exactly one ```openspec-citations``` fenced citation block. Do NOT emit a full contract, Markdown explanation, or prose — the output is JSON-only; the gate applies the patch on the original contract and renders plan.md deterministically. Apart from the patch JSON fenced block and the openspec-citations block, do not emit any other fenced block or raw JSON. No file writes.",
|
|
2870
2865
|
subtask_prompt: [
|
|
2871
|
-
"Consume frontend-plan-pi
|
|
2866
|
+
"Consume the hash-bound frontend-plan-pi contract artifact and frontend-design-review-pi findings. Read the artifact only for fields affected by a Required Plan Correction.",
|
|
2872
2867
|
"This node runs only when frontend-design-review-pi emitted VERDICT: request-revision. Produce an RFC 7386 merge-patch delta against the original contract JSON that addresses every Required Plan Correction from the design findings.",
|
|
2873
2868
|
"The patch delta may update editable contract fields such as requirements, implementationSteps, targets.routes/publicApiChanges, uiStates, interactions, mockApi.strategy/activation/endpoints, dependencyPolicy, stylingStrategy, uiComponentChoices, verificationTargets, evidenceGaps, residualRisks, and realIntegrationGap. It must not modify protected schemaVersion, sourceBinding, riskLevel, targets.files, or mockApi.productionDefaultOff. Only include fields you change; omit unchanged fields (the gate applies the patch on the original contract). null deletes a key; arrays and scalars replace; plain objects merge recursively.",
|
|
2874
|
-
|
|
2869
|
+
"Only include changed fields. For a changed requirement, preserve its expectedOutcome, implementationTargets, and verificationTargetIds; do not resend unchanged requirements.",
|
|
2875
2870
|
"Do not turn MOCK_STRATEGY: blocked into an implementable strategy without new repository or contract evidence that resolves every blocker.",
|
|
2876
2871
|
"Read-only: do not modify code, docs, artifacts, or repository files. This node revises the plan only.",
|
|
2877
|
-
"Output
|
|
2872
|
+
"Output exactly two adjacent blocks: (1) one fenced json object containing the merge-patch delta; (2) one openspec-citations citation block. Do NOT emit a full contract, Markdown explanation, or prose. Do not emit raw JSON or JSON objects in prose, secrets, or unsafe paths.",
|
|
2878
2873
|
"Preserve each requirement expectedOutcome and each interaction trigger/expectedBehavior in the effective (merged) contract; do not reduce behavior semantics to IDs and paths.",
|
|
2879
2874
|
"verificationTargets[].commandLabel MUST be one of the frozen command labels listed above. Any other value will be rejected at contract materialization.",
|
|
2880
2875
|
verificationTargetFileInstruction,
|
|
@@ -132,14 +132,14 @@ export function buildNodePrompt(spec, task, upstream, options) {
|
|
|
132
132
|
function frontendStructuredArtifactRetryGuidance(schemaId) {
|
|
133
133
|
if (schemaId === "frontend-implementation-contract-plan-patch-v1") {
|
|
134
134
|
return [
|
|
135
|
-
"Return exactly
|
|
135
|
+
"Return exactly two blocks and nothing else: one fenced json block containing only the editable RFC 7386 plan patch, immediately followed by one fenced openspec-citations block.",
|
|
136
136
|
"The runtime applies your patch to its protected contract skeleton. Do not emit schemaVersion, sourceBinding, riskLevel, targets.files, or mockApi.productionDefaultOff; do not emit the full contract.",
|
|
137
137
|
"Do not emit Markdown headings, bullets, plan prose, explanations, raw JSON, or any other fenced block.",
|
|
138
138
|
];
|
|
139
139
|
}
|
|
140
140
|
if (schemaId === "frontend-implementation-contract-revision-patch-v1") {
|
|
141
141
|
return [
|
|
142
|
-
"Return exactly
|
|
142
|
+
"Return exactly two blocks and nothing else: one fenced json block containing the RFC 7386 merge-patch delta, immediately followed by one fenced openspec-citations block.",
|
|
143
143
|
"The delta contains only the fields you change; null deletes a key, arrays and scalars replace, and plain objects merge recursively. Do not emit a full contract or a schemaVersion/targets section.",
|
|
144
144
|
"Do not emit Markdown headings, bullets, plan prose, explanations, raw JSON, or any other fenced block.",
|
|
145
145
|
];
|
|
@@ -149,6 +149,27 @@ function frontendStructuredArtifactRetryGuidance(schemaId) {
|
|
|
149
149
|
"The contract JSON fields are the complete implementation plan. Do not emit a separate plan document, Markdown headings, bullets, plan prose, explanations, raw JSON, or any other fenced block.",
|
|
150
150
|
];
|
|
151
151
|
}
|
|
152
|
+
function isFrontendPlanArtifactSchema(schemaId) {
|
|
153
|
+
return (schemaId === "frontend-implementation-contract-plan-patch-v1" ||
|
|
154
|
+
schemaId === "frontend-implementation-contract-revision-patch-v1");
|
|
155
|
+
}
|
|
156
|
+
function buildFrontendPlanArtifactRecoveryPrompt(options) {
|
|
157
|
+
const cause = options.failure === "truncated"
|
|
158
|
+
? "Previous response was truncated by the provider (stopReason=length)."
|
|
159
|
+
: options.failure === "too-large"
|
|
160
|
+
? "Previous response could not be retained by the provider."
|
|
161
|
+
: "Previous response failed structured validation.";
|
|
162
|
+
return [
|
|
163
|
+
"<retry_instruction>",
|
|
164
|
+
cause,
|
|
165
|
+
options.reason ? `Validation error: ${options.reason}` : "",
|
|
166
|
+
...frontendStructuredArtifactRetryGuidance(options.schemaId),
|
|
167
|
+
"Use concise values and reference paths/IDs instead of copying source prose. Do not omit required semantics.",
|
|
168
|
+
"</retry_instruction>",
|
|
169
|
+
]
|
|
170
|
+
.filter(Boolean)
|
|
171
|
+
.join("\n");
|
|
172
|
+
}
|
|
152
173
|
function buildAttemptPrompt(task, basePrompt, attemptNumber, previousFailureCategory, previousProtocolReason, recoveryTargetPaths, recoveryDiagnostics) {
|
|
153
174
|
if (attemptNumber <= 1)
|
|
154
175
|
return basePrompt;
|
|
@@ -164,6 +185,13 @@ function buildAttemptPrompt(task, basePrompt, attemptNumber, previousFailureCate
|
|
|
164
185
|
if (previousFailureCategory === "invalid-output" &&
|
|
165
186
|
task.structuredContractOutput &&
|
|
166
187
|
previousProtocolReason) {
|
|
188
|
+
if (isFrontendPlanArtifactSchema(task.structuredContractOutput.schemaId)) {
|
|
189
|
+
return buildFrontendPlanArtifactRecoveryPrompt({
|
|
190
|
+
failure: "invalid",
|
|
191
|
+
reason: previousProtocolReason,
|
|
192
|
+
schemaId: task.structuredContractOutput.schemaId,
|
|
193
|
+
});
|
|
194
|
+
}
|
|
167
195
|
return [
|
|
168
196
|
basePrompt,
|
|
169
197
|
"",
|
|
@@ -178,22 +206,12 @@ function buildAttemptPrompt(task, basePrompt, attemptNumber, previousFailureCate
|
|
|
178
206
|
if (previousFailureCategory === "structured-output-truncated" &&
|
|
179
207
|
task.structuredContractOutput) {
|
|
180
208
|
const schemaId = task.structuredContractOutput.schemaId;
|
|
181
|
-
if (schemaId
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
"<retry_instruction>",
|
|
188
|
-
"Previous response was truncated (stopReason=length).",
|
|
189
|
-
previousProtocolReason ? `Validation error: ${previousProtocolReason}` : "",
|
|
190
|
-
`Return one short lead-in, one complete fenced json ${payloadKind}, then one fenced openspec-citations block.`,
|
|
191
|
-
"Protected: schemaVersion, sourceBinding, riskLevel, targets.files, mockApi.productionDefaultOff. Required semantics: requirement expectedOutcome; interaction trigger + expectedBehavior; frozen verification command labels.",
|
|
192
|
-
"No prose, examples, schema copy, Markdown headings, raw JSON, or other fences.",
|
|
193
|
-
"</retry_instruction>",
|
|
194
|
-
]
|
|
195
|
-
.filter(Boolean)
|
|
196
|
-
.join("\n");
|
|
209
|
+
if (isFrontendPlanArtifactSchema(schemaId)) {
|
|
210
|
+
return buildFrontendPlanArtifactRecoveryPrompt({
|
|
211
|
+
failure: "truncated",
|
|
212
|
+
reason: previousProtocolReason,
|
|
213
|
+
schemaId,
|
|
214
|
+
});
|
|
197
215
|
}
|
|
198
216
|
return [
|
|
199
217
|
basePrompt,
|
|
@@ -271,6 +289,12 @@ function buildAttemptPrompt(task, basePrompt, attemptNumber, previousFailureCate
|
|
|
271
289
|
}
|
|
272
290
|
if (task.outputMode === "structured-required") {
|
|
273
291
|
if (task.structuredContractOutput) {
|
|
292
|
+
if (isFrontendPlanArtifactSchema(task.structuredContractOutput.schemaId)) {
|
|
293
|
+
return buildFrontendPlanArtifactRecoveryPrompt({
|
|
294
|
+
failure: "too-large",
|
|
295
|
+
schemaId: task.structuredContractOutput.schemaId,
|
|
296
|
+
});
|
|
297
|
+
}
|
|
274
298
|
return [
|
|
275
299
|
basePrompt,
|
|
276
300
|
"",
|