@tea-agent/loop-agent 0.16.1 → 0.16.2
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 +21 -0
- package/dist/executors/dag-pi-executor.js +4 -2
- package/dist/executors/pi-sdk-executor.js +66 -3
- package/dist/executors/shell-executor.js +212 -29
- package/dist/executors/shell-presets.js +12 -2
- package/dist/executors/shell-write-guard.js +20 -1
- package/dist/shared/git-progress.js +9 -2
- package/dist/worker/observability/read-model.js +56 -0
- package/dist/worker/observe/server.js +6 -3
- package/dist/workflows/dag/backend-test-analysis-contract.js +87 -30
- package/dist/workflows/dag/backend-test-case-manifest.js +71 -8
- package/dist/workflows/dag/backend-test-execution-contract.js +63 -11
- package/dist/workflows/dag/backend-test-repair-contract.js +94 -0
- package/dist/workflows/dag/backend-test-result-contract.js +6 -4
- package/dist/workflows/dag/backend-test-semantic-review-contract.js +36 -0
- package/dist/workflows/dag/dynamic-runtime/condition.js +1 -1
- package/dist/workflows/dag/dynamic-runtime/shared.js +42 -0
- package/dist/workflows/dag/failure-routing.js +1 -1
- package/dist/workflows/dag/frontend-implementation-contract.js +32 -16
- package/dist/workflows/dag/init-hybrid.js +591 -119
- package/dist/workflows/dag/lifecycle.js +33 -2
- package/dist/workflows/dag/scheduler.js +87 -17
- package/dist/workflows/dag/types.js +31 -0
- package/dist/workflows/dag/validate.js +20 -14
- package/docs/templates/agent-dag.schema.json +25 -2
- package/docs/templates/backend-test-analysis.schema.json +9 -16
- package/docs/templates/backend-test-dag.json +493 -197
- package/docs/templates/backend-test-dag.review-cases.prompt.md +10 -4
- package/docs/templates/backend-test-execution.schema.json +6 -1
- package/package.json +1 -1
- package/skills/loop-agent/references/hybrid-dag.md +4 -1
|
@@ -186,6 +186,26 @@ export function extractFrontendImplementationJson(text) {
|
|
|
186
186
|
throw new Error("output must contain exactly one fenced json object");
|
|
187
187
|
return JSON.parse(blocks[0][1]);
|
|
188
188
|
}
|
|
189
|
+
/**
|
|
190
|
+
* Build the authoritative frontend-implementation-contract sourceBinding from
|
|
191
|
+
* the DAG-owned binding. Model JSON must not invent taskId/path/sha256; the
|
|
192
|
+
* gate overwrites whatever the model emitted so identity cannot drift.
|
|
193
|
+
*/
|
|
194
|
+
export function canonicalFrontendContractSourceBinding(binding) {
|
|
195
|
+
const requirement = binding.sources.find((source) => source.kind === "requirement");
|
|
196
|
+
if (!requirement)
|
|
197
|
+
throw new Error("frontend implementation contract gate requires a requirement source in DAG sourceBinding");
|
|
198
|
+
return {
|
|
199
|
+
taskId: binding.taskId,
|
|
200
|
+
requirementPath: requirement.path,
|
|
201
|
+
requirementSha256: requirement.sha256,
|
|
202
|
+
referencePaths: binding.sources
|
|
203
|
+
.filter((source) => source.kind === "reference")
|
|
204
|
+
.map((source) => source.path)
|
|
205
|
+
.sort(),
|
|
206
|
+
requirementIds: [...binding.requirementIds],
|
|
207
|
+
};
|
|
208
|
+
}
|
|
189
209
|
export async function materializeFrontendImplementationContract(input) {
|
|
190
210
|
if (!input.sourceBinding)
|
|
191
211
|
throw new Error("frontend implementation contract gate requires DAG sourceBinding");
|
|
@@ -200,23 +220,19 @@ export async function materializeFrontendImplementationContract(input) {
|
|
|
200
220
|
const secrets = secretIssues(parsed);
|
|
201
221
|
if (secrets.length)
|
|
202
222
|
throw new Error(`invalid-output: ${secrets.join("; ")}`);
|
|
203
|
-
|
|
223
|
+
if (!parsed || typeof parsed !== "object" || Array.isArray(parsed))
|
|
224
|
+
throw new Error("invalid-output: frontend contract must be a JSON object");
|
|
225
|
+
const canonicalBinding = canonicalFrontendContractSourceBinding(input.sourceBinding);
|
|
226
|
+
// Always inject DAG-owned identity. Model-provided sourceBinding is advisory
|
|
227
|
+
// only and must not fail a otherwise-valid contract (common live failure:
|
|
228
|
+
// wrong requirementPath/sha, extra referencePaths, or omitted binding).
|
|
229
|
+
const withCanonicalBinding = {
|
|
230
|
+
...parsed,
|
|
231
|
+
sourceBinding: canonicalBinding,
|
|
232
|
+
};
|
|
233
|
+
const result = frontendImplementationContractSchema.safeParse(withCanonicalBinding);
|
|
204
234
|
if (!result.success)
|
|
205
235
|
throw new Error(`invalid-output: ${result.error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join("; ")}`);
|
|
206
|
-
const requirement = input.sourceBinding.sources.find((source) => source.kind === "requirement");
|
|
207
|
-
const refs = input.sourceBinding.sources
|
|
208
|
-
.filter((source) => source.kind === "reference")
|
|
209
|
-
.map((source) => source.path)
|
|
210
|
-
.sort();
|
|
211
|
-
const bound = result.data.sourceBinding;
|
|
212
|
-
if (!requirement ||
|
|
213
|
-
bound.taskId !== input.sourceBinding.taskId ||
|
|
214
|
-
bound.requirementPath !== requirement.path ||
|
|
215
|
-
bound.requirementSha256 !== requirement.sha256 ||
|
|
216
|
-
JSON.stringify([...bound.referencePaths].sort()) !== JSON.stringify(refs) ||
|
|
217
|
-
JSON.stringify(bound.requirementIds) !==
|
|
218
|
-
JSON.stringify(input.sourceBinding.requirementIds))
|
|
219
|
-
throw new Error("frontend contract source binding does not match DAG source binding");
|
|
220
236
|
const blockingGaps = [
|
|
221
237
|
...result.data.evidenceGaps,
|
|
222
238
|
...result.data.requirements.flatMap((item) => item.evidenceGap ? [item.evidenceGap] : []),
|
|
@@ -225,7 +241,7 @@ export async function materializeFrontendImplementationContract(input) {
|
|
|
225
241
|
throw new Error(`frontend contract has blocking evidence gap: ${blockingGaps
|
|
226
242
|
.map((item) => item.requirementId ?? item.description)
|
|
227
243
|
.join(", ")}`);
|
|
228
|
-
for (const requirementId of
|
|
244
|
+
for (const requirementId of canonicalBinding.requirementIds)
|
|
229
245
|
if (!result.data.requirements.some((item) => item.id === requirementId) &&
|
|
230
246
|
!result.data.evidenceGaps.some((item) => item.requirementId === requirementId))
|
|
231
247
|
throw new Error(`frontend contract does not cover ${requirementId}`);
|