@tea-agent/loop-agent 0.39.0-beta.10 → 0.39.0-beta.12
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 +99 -0
- package/dist/build-stamp.json +3 -3
- package/dist/executors/dag-pi-executor.js +93 -32
- package/dist/executors/pi-executor.js +4 -2
- package/dist/executors/pi-sdk-executor.js +46 -1
- package/dist/executors/pi-writer-tool-policy.js +57 -1
- package/dist/executors/shell-executor.js +10 -1
- package/dist/worker/console/chat/chat-event-store.js +13 -1
- package/dist/worker/console/chat/pi-runtime.js +70 -5
- package/dist/worker/console/chat/routes.js +99 -29
- package/dist/worker/console/chat/workspace-landing.js +65 -0
- package/dist/worker/console/static/assets/{abnfDiagram-N423BO3Z-BAsjg7ew.js → abnfDiagram-N423BO3Z-CXj_GnSb.js} +1 -1
- package/dist/worker/console/static/assets/{arc-CyIlrwZw.js → arc-BZp6JAp7.js} +1 -1
- package/dist/worker/console/static/assets/{architectureDiagram-T3A2C74G-Bo4tobhH.js → architectureDiagram-T3A2C74G-DfpcEuYU.js} +1 -1
- package/dist/worker/console/static/assets/{blockDiagram-VBNYF7ZC-Dfpow9gu.js → blockDiagram-VBNYF7ZC-_Gf0xadb.js} +1 -1
- package/dist/worker/console/static/assets/{c4Diagram-5PPSVZJV-DPmzG_B4.js → c4Diagram-5PPSVZJV-Ct2QPCmv.js} +1 -1
- package/dist/worker/console/static/assets/channel-3TxJgYaH.js +1 -0
- package/dist/worker/console/static/assets/{chunk-2GRJ4B5K-pKQpB1UW.js → chunk-2GRJ4B5K-BfklkzKl.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-2Q5K7J3B-5n9YYquZ.js → chunk-2Q5K7J3B-Dy25vZJV.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5RXB4S5H-DP3CtA2a.js → chunk-5RXB4S5H-BFlCRZep.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-5VM5RSS4-DYxMJPUy.js → chunk-5VM5RSS4-op3oVxIE.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-6Q2QTUOP-CS3D50Io.js → chunk-6Q2QTUOP-C0R7rzF2.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-GF5L2VYU-gSdDfo5_.js → chunk-GF5L2VYU-Bt44TCGy.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-JWPE2WC7-A48q0ZNt.js → chunk-JWPE2WC7-_uEE_XFx.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-KBJHAD2P-ow8Mm3DY.js → chunk-KBJHAD2P-C3TOYGZ9.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-RYQCIY6F-CMKfLWYE.js → chunk-RYQCIY6F-Cz60oBPV.js} +1 -1
- package/dist/worker/console/static/assets/{chunk-XXDRQBXY-BiTBdQPX.js → chunk-XXDRQBXY-8Bik0qis.js} +1 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-BHIkXpp3.js +1 -0
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-BHIkXpp3.js +1 -0
- package/dist/worker/console/static/assets/{cose-bilkent-JH36ORCC-Cm7exRz_.js → cose-bilkent-JH36ORCC-C2QIOA4a.js} +1 -1
- package/dist/worker/console/static/assets/{cynefin-VYW2F7L2-D9O5qGOu.js → cynefin-VYW2F7L2-CSH_yUUd.js} +1 -1
- package/dist/worker/console/static/assets/{cynefinDiagram-MW4NZA55-CkvQnako.js → cynefinDiagram-MW4NZA55-BDLw2XFM.js} +1 -1
- package/dist/worker/console/static/assets/{dagre-VZM6K2ZE-B1rzp7CB.js → dagre-VZM6K2ZE-CcD9ZtF4.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-7IWD3JNH-BP07Ipcc.js → diagram-7IWD3JNH-DqwtkBsI.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-B4RE2ZJO-BlPzweQb.js → diagram-B4RE2ZJO-BWVEcqsC.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-LBJQPF4R-CxPa7n0S.js → diagram-LBJQPF4R-M-WAbtQi.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-Q27KOJAE-CMTZs53A.js → diagram-Q27KOJAE-DKW7SixP.js} +1 -1
- package/dist/worker/console/static/assets/{diagram-UB23O5K3-CxG_X52r.js → diagram-UB23O5K3-PHHPPtrj.js} +1 -1
- package/dist/worker/console/static/assets/{ebnfDiagram-BXEA7PRR-D8axtJM0.js → ebnfDiagram-BXEA7PRR-BQD-B4RX.js} +1 -1
- package/dist/worker/console/static/assets/{erDiagram-JOGREHBK-DIsGzn7b.js → erDiagram-JOGREHBK-BFvULb51.js} +1 -1
- package/dist/worker/console/static/assets/{flowDiagram-UKHOOZJN-CU9zkDG0.js → flowDiagram-UKHOOZJN-Bw-aXTCb.js} +1 -1
- package/dist/worker/console/static/assets/{ganttDiagram-PKOTCBZU-DCjTmz5P.js → ganttDiagram-PKOTCBZU-BGKw04Qx.js} +1 -1
- package/dist/worker/console/static/assets/{gitGraphDiagram-DS77QQ5N-BksdmFzg.js → gitGraphDiagram-DS77QQ5N-RqKaPR-I.js} +1 -1
- package/dist/worker/console/static/assets/index-B_D8rbWc.js +407 -0
- package/dist/worker/console/static/assets/index-BdNx6fj0.css +1 -0
- package/dist/worker/console/static/assets/{infoDiagram-6WML65LV-CGzzzJtL.js → infoDiagram-6WML65LV-YO5dnzrJ.js} +1 -1
- package/dist/worker/console/static/assets/{ishikawaDiagram-WSZJBQD7-BdseB80N.js → ishikawaDiagram-WSZJBQD7-Bi1VZHMq.js} +1 -1
- package/dist/worker/console/static/assets/{journeyDiagram-NVQOT4AX-DM9gsgha.js → journeyDiagram-NVQOT4AX-Bszls1DD.js} +1 -1
- package/dist/worker/console/static/assets/{kanban-definition-27J2QSJJ-3q-_9R2b.js → kanban-definition-27J2QSJJ-PhzeaZ09.js} +1 -1
- package/dist/worker/console/static/assets/{linear-B8N-Mxsd.js → linear-BsjbDoXi.js} +1 -1
- package/dist/worker/console/static/assets/{mermaid.core-EPIHUUsu.js → mermaid.core-0B7NnWKk.js} +5 -5
- package/dist/worker/console/static/assets/{mindmap-definition-FAOFIHXS-CxwO12aa.js → mindmap-definition-FAOFIHXS-BJr4Fj-q.js} +1 -1
- package/dist/worker/console/static/assets/{pegDiagram-VL7TDLO6-bPqbVX6Y.js → pegDiagram-VL7TDLO6-moC4fpGB.js} +1 -1
- package/dist/worker/console/static/assets/{pieDiagram-7S7Q4E2Y-KzqIvzeX.js → pieDiagram-7S7Q4E2Y-BEw37-2c.js} +1 -1
- package/dist/worker/console/static/assets/{quadrantDiagram-CIZ2JOQS-CyofpWiV.js → quadrantDiagram-CIZ2JOQS-Cq6LyasU.js} +1 -1
- package/dist/worker/console/static/assets/{railroadDiagram-AXF67PYL-cTWJvLTP.js → railroadDiagram-AXF67PYL-DUCMcK0D.js} +1 -1
- package/dist/worker/console/static/assets/{requirementDiagram-LRYGKXZP-BK--q27B.js → requirementDiagram-LRYGKXZP-C3upTZm7.js} +1 -1
- package/dist/worker/console/static/assets/{sankeyDiagram-W5VNT64P-C0SDOHXK.js → sankeyDiagram-W5VNT64P-BI_gMsCW.js} +1 -1
- package/dist/worker/console/static/assets/{sequenceDiagram-SI44F4Z6-Cong6YIo.js → sequenceDiagram-SI44F4Z6-YFOIRzfN.js} +1 -1
- package/dist/worker/console/static/assets/{sizeCapture-X5ZJPWSS-DUVkgZx8.js → sizeCapture-X5ZJPWSS-dOnB7UDD.js} +1 -1
- package/dist/worker/console/static/assets/{stateDiagram-OKZ733FA-C7XgxuZg.js → stateDiagram-OKZ733FA-BXUniaIh.js} +1 -1
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-Cdi6UhLa.js +1 -0
- package/dist/worker/console/static/assets/{swimlanes-SLNWSIFB-D9Ayvwcy.js → swimlanes-SLNWSIFB-2tA4wTNu.js} +2 -2
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-D-RJBbb0.js +8 -0
- package/dist/worker/console/static/assets/{timeline-definition-Z64GVDOM-Byb000cH.js → timeline-definition-Z64GVDOM-DO0HkJXC.js} +1 -1
- package/dist/worker/console/static/assets/{vennDiagram-T6HMQDX7-DMLegPt4.js → vennDiagram-T6HMQDX7-DvIOzixv.js} +1 -1
- package/dist/worker/console/static/assets/{wardleyDiagram-T6FBY63Y-ChMMeOsP.js → wardleyDiagram-T6FBY63Y-DXDZ0cTj.js} +1 -1
- package/dist/worker/console/static/assets/{xychartDiagram-ELKLHX3M-bEMEPisW.js → xychartDiagram-ELKLHX3M-B32Ark0D.js} +1 -1
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +33 -32
- package/dist/worker/console/static-src/operator-chat/compaction-message.js +79 -0
- package/dist/worker/console/static-src/operator-chat/spatial-overlay.js +1 -2
- package/dist/worker/console/static-src/operator-chat/turn-stream-controller.js +25 -0
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +54 -56
- package/dist/worker/console/static-src/operator-chat/useChatStream.js +81 -27
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +14 -25
- package/dist/worker/console/static-src/shell/workspace-route.js +7 -5
- package/dist/workflows/dag/backend-test-writer-completeness.js +7 -12
- package/dist/workflows/dag/dynamic-runtime/map.js +1 -0
- package/dist/workflows/dag/init-hybrid.js +156 -55
- package/dist/workflows/dag/node-execution.js +168 -0
- package/dist/workflows/dag/types.js +17 -0
- package/docs/templates/README.md +1 -0
- package/docs/templates/agent-dag.schema.json +18 -0
- package/docs/templates/backend-test-dag.json +265 -237
- package/docs/templates/frontend-implementation-dag.json +89 -0
- package/harness.json +3 -3
- package/package.json +1 -1
- package/skills/loop-agent/references/hybrid-dag.md +1 -1
- package/dist/worker/console/static/assets/channel-DSrJAn0-.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-JCYQIIEL-DeMmPl0_.js +0 -1
- package/dist/worker/console/static/assets/classDiagram-v2-OCEON4UE-DeMmPl0_.js +0 -1
- package/dist/worker/console/static/assets/index-B-O5ChYq.css +0 -1
- package/dist/worker/console/static/assets/index-CfnY8AQx.js +0 -407
- package/dist/worker/console/static/assets/stateDiagram-v2-UEYNNEHI-Dzbnd5oX.js +0 -1
- package/dist/worker/console/static/assets/swimlanesDiagram-ULZ7WXOC-BY0hHk6G.js +0 -8
- package/dist/worker/console/static-src/operator-chat/activity-rail-presentation.js +0 -73
- package/dist/worker/console/static-src/operator-chat/useActivityRailTransition.js +0 -59
|
@@ -238,6 +238,163 @@ async function readFrontendPlanCommittedSnapshot(runDir, nodeId) {
|
|
|
238
238
|
const hasTerminalFact = committed.some((record) => record.fact.kind === "finalize_plan");
|
|
239
239
|
return { digest, hasTerminalFact };
|
|
240
240
|
}
|
|
241
|
+
function planInputRecord(value) {
|
|
242
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
243
|
+
}
|
|
244
|
+
function planInputText(value, maxChars = 240) {
|
|
245
|
+
if (typeof value !== "string" || value.trim().length === 0)
|
|
246
|
+
return undefined;
|
|
247
|
+
const normalized = value.trim();
|
|
248
|
+
return normalized.length <= maxChars
|
|
249
|
+
? normalized
|
|
250
|
+
: `${normalized.slice(0, maxChars - 1)}…`;
|
|
251
|
+
}
|
|
252
|
+
function planInputStrings(value) {
|
|
253
|
+
return Array.isArray(value)
|
|
254
|
+
? value.filter((item) => typeof item === "string")
|
|
255
|
+
: [];
|
|
256
|
+
}
|
|
257
|
+
/** Input bound for the planner evidence block; protects the model input budget. */
|
|
258
|
+
const FRONTEND_PLAN_INPUT_MAX_CHARS = 12_000;
|
|
259
|
+
const FRONTEND_PLAN_INPUT_CAP_LADDER = [
|
|
260
|
+
{ text: 240, array: 40 },
|
|
261
|
+
{ text: 120, array: 20 },
|
|
262
|
+
{ text: 60, array: 10 },
|
|
263
|
+
{ text: 24, array: 4 },
|
|
264
|
+
];
|
|
265
|
+
/**
|
|
266
|
+
* Render the planner's complete-but-bounded evidence handoff from committed
|
|
267
|
+
* typed facts. It deliberately excludes upstream response prose and artifact
|
|
268
|
+
* paths: Contract and Scout have already established these facts, so Plan
|
|
269
|
+
* should decide and commit rather than spend another model turn reading them.
|
|
270
|
+
*
|
|
271
|
+
* The block is always valid JSON under the char bound: field texts shrink
|
|
272
|
+
* through a cap ladder before any fact is dropped, and the last-resort
|
|
273
|
+
* fallback keeps every requirement id (with `text: "(truncated)"`) while
|
|
274
|
+
* declaring the degradation, so the planner records targeted evidence gaps
|
|
275
|
+
* instead of receiving a silently corrupted tail.
|
|
276
|
+
*/
|
|
277
|
+
export function renderFrontendPlanInputContext(input) {
|
|
278
|
+
const committedFacts = (records) => records.flatMap((record) => record.phase === "committed" && planInputRecord(record.fact)
|
|
279
|
+
? [record.fact]
|
|
280
|
+
: []);
|
|
281
|
+
const contractFacts = committedFacts(input.contractRecords);
|
|
282
|
+
const scoutFacts = committedFacts(input.scoutRecords);
|
|
283
|
+
const requirements = contractFacts
|
|
284
|
+
.filter((fact) => fact.kind === "requirement" && fact.origin === "contract")
|
|
285
|
+
.map((fact) => ({
|
|
286
|
+
id: planInputText(fact.id, 80),
|
|
287
|
+
text: planInputText(fact.text),
|
|
288
|
+
sourceFragmentIds: planInputStrings(fact.sourceFragmentIds),
|
|
289
|
+
}))
|
|
290
|
+
.filter((fact) => fact.id !== undefined);
|
|
291
|
+
const targetSurface = scoutFacts
|
|
292
|
+
.filter((fact) => fact.kind === "target-surface" && fact.origin === "scout")
|
|
293
|
+
.map((fact) => ({
|
|
294
|
+
completeness: fact.completeness,
|
|
295
|
+
entrypoint: fact.entrypoint,
|
|
296
|
+
routeOrMount: fact.routeOrMount,
|
|
297
|
+
implementationPaths: fact.implementationPaths,
|
|
298
|
+
testPaths: fact.testPaths,
|
|
299
|
+
dataSource: fact.dataSource,
|
|
300
|
+
allowedPathConflicts: fact.allowedPathConflicts,
|
|
301
|
+
unresolvedPaths: fact.unresolvedPaths,
|
|
302
|
+
}));
|
|
303
|
+
const designEvidence = scoutFacts
|
|
304
|
+
.filter((fact) => fact.kind === "design-evidence" && fact.origin === "scout")
|
|
305
|
+
.map((fact) => ({
|
|
306
|
+
source: fact.source,
|
|
307
|
+
paths: fact.paths,
|
|
308
|
+
conflicts: fact.conflicts,
|
|
309
|
+
}));
|
|
310
|
+
const serializeAtCap = (cap) => JSON.stringify({
|
|
311
|
+
requirements: requirements.map((requirement) => ({
|
|
312
|
+
id: requirement.id,
|
|
313
|
+
text: planInputText(requirement.text, cap.text),
|
|
314
|
+
sourceFragmentIds: planInputStrings(requirement.sourceFragmentIds).slice(0, cap.array),
|
|
315
|
+
})),
|
|
316
|
+
targetSurface: targetSurface.map((surface) => ({
|
|
317
|
+
completeness: planInputText(surface.completeness, 32),
|
|
318
|
+
entrypoint: planInputText(surface.entrypoint, cap.text),
|
|
319
|
+
routeOrMount: planInputText(surface.routeOrMount, cap.text),
|
|
320
|
+
implementationPaths: planInputStrings(surface.implementationPaths).slice(0, cap.array),
|
|
321
|
+
testPaths: planInputStrings(surface.testPaths).slice(0, cap.array),
|
|
322
|
+
dataSource: planInputText(surface.dataSource, cap.text),
|
|
323
|
+
allowedPathConflicts: planInputStrings(surface.allowedPathConflicts).slice(0, cap.array),
|
|
324
|
+
unresolvedPaths: planInputStrings(surface.unresolvedPaths).slice(0, cap.array),
|
|
325
|
+
})),
|
|
326
|
+
designEvidence: designEvidence.map((evidence) => ({
|
|
327
|
+
source: planInputText(evidence.source, cap.text),
|
|
328
|
+
paths: planInputStrings(evidence.paths).slice(0, cap.array),
|
|
329
|
+
conflicts: planInputStrings(evidence.conflicts).slice(0, cap.array),
|
|
330
|
+
})),
|
|
331
|
+
});
|
|
332
|
+
let serialized = serializeAtCap(FRONTEND_PLAN_INPUT_CAP_LADDER[0]);
|
|
333
|
+
for (const cap of FRONTEND_PLAN_INPUT_CAP_LADDER.slice(1)) {
|
|
334
|
+
if (serialized.length <= FRONTEND_PLAN_INPUT_MAX_CHARS)
|
|
335
|
+
break;
|
|
336
|
+
serialized = serializeAtCap(cap);
|
|
337
|
+
}
|
|
338
|
+
if (serialized.length > FRONTEND_PLAN_INPUT_MAX_CHARS) {
|
|
339
|
+
// Last resort: keep every requirement id (ids are short and the plan
|
|
340
|
+
// prompt separately lists them) but drop their texts, shrink scout facts
|
|
341
|
+
// to the minimum, and declare the degradation instead of corrupting JSON.
|
|
342
|
+
let fallback = {
|
|
343
|
+
degraded: "requirement-texts-truncated",
|
|
344
|
+
requirements: requirements.map((requirement) => ({
|
|
345
|
+
id: requirement.id,
|
|
346
|
+
text: "(truncated)",
|
|
347
|
+
})),
|
|
348
|
+
targetSurface: targetSurface.map((surface) => ({
|
|
349
|
+
completeness: planInputText(surface.completeness, 32),
|
|
350
|
+
implementationPaths: planInputStrings(surface.implementationPaths).slice(0, FRONTEND_PLAN_INPUT_CAP_LADDER[3].array),
|
|
351
|
+
})),
|
|
352
|
+
designEvidence: [],
|
|
353
|
+
};
|
|
354
|
+
let bounded = JSON.stringify(fallback);
|
|
355
|
+
let keep = fallback.requirements.length;
|
|
356
|
+
while (bounded.length > FRONTEND_PLAN_INPUT_MAX_CHARS &&
|
|
357
|
+
keep > 0) {
|
|
358
|
+
keep = Math.max(0, Math.floor(keep / 2));
|
|
359
|
+
fallback = { ...fallback, requirements: fallback.requirements.slice(0, keep) };
|
|
360
|
+
bounded = JSON.stringify({
|
|
361
|
+
...fallback,
|
|
362
|
+
requirementIdsTruncated: keep < requirements.length,
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
serialized = bounded;
|
|
366
|
+
}
|
|
367
|
+
return [
|
|
368
|
+
"<frontend_plan_input>",
|
|
369
|
+
"Committed Contract/Scout facts, compiled by the runner. Treat them as the complete planning evidence.",
|
|
370
|
+
serialized,
|
|
371
|
+
"Do not read upstream artifacts, task sources, or repository files. If this input cannot support a decision, record a genuine evidence gap.",
|
|
372
|
+
"</frontend_plan_input>",
|
|
373
|
+
].join("\n");
|
|
374
|
+
}
|
|
375
|
+
export async function buildFrontendPlanInputContext(runDir) {
|
|
376
|
+
const contractFactsPath = path.join(runDir, "frontend-contract-pi", "contract-typed-facts.jsonl");
|
|
377
|
+
const scoutFactsPath = path.join(runDir, "frontend-scout-pi", "scout-typed-facts.jsonl");
|
|
378
|
+
let contractRecords;
|
|
379
|
+
let scoutRecords;
|
|
380
|
+
try {
|
|
381
|
+
[contractRecords, scoutRecords] = await Promise.all([
|
|
382
|
+
readTypedEventStoreFromJsonl(contractFactsPath),
|
|
383
|
+
readTypedEventStoreFromJsonl(scoutFactsPath),
|
|
384
|
+
]);
|
|
385
|
+
}
|
|
386
|
+
catch (error) {
|
|
387
|
+
// A missing/unreadable upstream store is a broken pipeline, not an
|
|
388
|
+
// evidence gap; fail before spending a model turn on a prompt that
|
|
389
|
+
// forbids reading anything.
|
|
390
|
+
throw new Error(`frontend-plan-input-unavailable: cannot read committed typed facts (${error instanceof Error ? error.message : String(error)})`);
|
|
391
|
+
}
|
|
392
|
+
const committedCount = [...contractRecords, ...scoutRecords].filter((record) => record.phase === "committed").length;
|
|
393
|
+
if (committedCount === 0) {
|
|
394
|
+
throw new Error(`frontend-plan-input-unavailable: no committed Contract/Scout facts in ${contractFactsPath} / ${scoutFactsPath}`);
|
|
395
|
+
}
|
|
396
|
+
return renderFrontendPlanInputContext({ contractRecords, scoutRecords });
|
|
397
|
+
}
|
|
241
398
|
export function buildAttemptPrompt(task, basePrompt, attemptNumber, previousFailureCategory, previousProtocolReason, recoveryTargetPaths, recoveryDiagnostics, frontendPlanRetryStep) {
|
|
242
399
|
if (attemptNumber <= 1)
|
|
243
400
|
return basePrompt;
|
|
@@ -938,6 +1095,17 @@ export async function executeDagNode(input) {
|
|
|
938
1095
|
await failSkillSnapshot(error);
|
|
939
1096
|
return;
|
|
940
1097
|
}
|
|
1098
|
+
if (isFrontendPlanLadderTask(task)) {
|
|
1099
|
+
let planInputContext;
|
|
1100
|
+
try {
|
|
1101
|
+
planInputContext = await buildFrontendPlanInputContext(runDir);
|
|
1102
|
+
}
|
|
1103
|
+
catch (error) {
|
|
1104
|
+
await failBeforePrompt(error, "frontend-plan-input-unavailable");
|
|
1105
|
+
return;
|
|
1106
|
+
}
|
|
1107
|
+
prompt = `${prompt}\n\n${planInputContext}`;
|
|
1108
|
+
}
|
|
941
1109
|
node.resolvedSkills = resolvedSkills;
|
|
942
1110
|
await writeNodeSkillArtifacts(runDir, nodeId, resolvedSkills);
|
|
943
1111
|
let model = resolveModelForTask(task, spec.executorModels);
|
|
@@ -770,6 +770,8 @@ export const dagDynamicExpansionChildTaskSchema = z.object({
|
|
|
770
770
|
allowedPaths: z.array(z.string()).optional().default([]),
|
|
771
771
|
forbiddenPaths: z.array(z.string()).optional().default([]),
|
|
772
772
|
writeSet: z.array(z.string()).optional(),
|
|
773
|
+
/** Template-rendered strict repository-relative read allowlist. */
|
|
774
|
+
readSet: z.array(z.string()).optional(),
|
|
773
775
|
/**
|
|
774
776
|
* Materialized-child pass-through fields for bounded Pi writer children
|
|
775
777
|
* (backend-test md/pytest case sharding). All optional so legacy
|
|
@@ -970,6 +972,21 @@ export const dagTaskSchema = z.object({ id: z.string().regex(/^[a-z][a-z0-9-]*$/
|
|
|
970
972
|
commandPolicy: dagCommandPolicySchema.optional(),
|
|
971
973
|
writePolicy: dagWritePolicySchema.optional(),
|
|
972
974
|
writeSet: z.array(z.string()).optional(),
|
|
975
|
+
/** Strict repository-relative read allowlist for bounded Pi nodes. */
|
|
976
|
+
readSet: z.array(z.string()).optional(),
|
|
977
|
+
/**
|
|
978
|
+
* Online per-attempt Pi context guard. Unlike run/map cost budgets, this
|
|
979
|
+
* aborts the active SDK session before an oversized conversation reaches
|
|
980
|
+
* the provider's context rejection boundary.
|
|
981
|
+
*/
|
|
982
|
+
contextBudget: z
|
|
983
|
+
.object({
|
|
984
|
+
maxTurns: z.number().int().positive().optional(),
|
|
985
|
+
maxTokens: z.number().int().positive().optional(),
|
|
986
|
+
})
|
|
987
|
+
.strict()
|
|
988
|
+
.refine((value) => value.maxTurns !== undefined || value.maxTokens !== undefined, "contextBudget requires maxTurns or maxTokens")
|
|
989
|
+
.optional(),
|
|
973
990
|
piStep: z.string().optional(),
|
|
974
991
|
shell: dagShellConfigSchema.optional(),
|
|
975
992
|
static: dagStaticConfigSchema.optional(),
|
package/docs/templates/README.md
CHANGED
|
@@ -38,6 +38,7 @@
|
|
|
38
38
|
|
|
39
39
|
- `frontend-task-requirement.md`、`frontend-task-constraints.md`、`frontend-design-contract.md` — 前端任务输入与设计合同。
|
|
40
40
|
- `frontend-implementation-contract.schema.json` — 前端实现合同 schema(sourceBinding v2 ledger 字段 all-or-none:任一出现则四项齐全,禁止 v1+optional 冒充 v2)。`requirements[].sourceRefs[].items` 使用合法 `$ref: #/$defs/path`(相对路径、无 `..` 逃逸、无反斜杠),模板 JSON 无非法键,运行时加载器可直接编译(AC-003)。
|
|
41
|
+
- `frontend-implementation-dag.json` — 自包含的前端实现 DAG 模板:契约 → 侦察 → 计划 → 设计策略/评审 → writer 准入 → 有界写入 → 验证 → 真实 diff 审查 → closeout。它不依赖 runtime builder 或其他模板;执行前必须将所有 `REPLACE/WITH/...` 路径和确定性命令替换为当前项目的具体值。
|
|
41
42
|
- `frontend-test-dag.json` — frontend-test DAG 模板;其 deterministic checklist 会拒绝 alternative executable instructions,仅允许 allowlisted `playwright-cli` command。Pi generator/reviser 的 runtime writeSet 仅授权下列目标项目生成路径(不是本仓库文档索引目标):
|
|
42
43
|
|
|
43
44
|
~~~text
|
|
@@ -538,6 +538,24 @@
|
|
|
538
538
|
"type": "array",
|
|
539
539
|
"items": { "type": "string", "minLength": 1 }
|
|
540
540
|
},
|
|
541
|
+
"readSet": {
|
|
542
|
+
"type": "array",
|
|
543
|
+
"items": { "type": "string", "minLength": 1 },
|
|
544
|
+
"description": "Strict repository-relative read allowlist for bounded Pi nodes."
|
|
545
|
+
},
|
|
546
|
+
"contextBudget": {
|
|
547
|
+
"type": "object",
|
|
548
|
+
"additionalProperties": false,
|
|
549
|
+
"description": "Online per-attempt Pi SDK conversation guard. At least one threshold is required; exhaustion aborts the active session with context-budget-exhausted partial evidence.",
|
|
550
|
+
"properties": {
|
|
551
|
+
"maxTurns": { "type": "integer", "minimum": 1 },
|
|
552
|
+
"maxTokens": { "type": "integer", "minimum": 1 }
|
|
553
|
+
},
|
|
554
|
+
"anyOf": [
|
|
555
|
+
{ "required": ["maxTurns"] },
|
|
556
|
+
{ "required": ["maxTokens"] }
|
|
557
|
+
]
|
|
558
|
+
},
|
|
541
559
|
"piStep": {
|
|
542
560
|
"type": "string",
|
|
543
561
|
"minLength": 1
|