@tea-agent/loop-agent 0.35.2 → 0.35.4-beta.0
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/AGENTS.md +2 -0
- package/CHANGELOG.md +43 -1
- package/README.md +1 -1
- package/bin/loop-agent.js +37 -1
- package/dist/build-stamp.json +6 -0
- package/dist/cli/program.js +2 -2
- package/dist/executors/dag-pi-executor.js +44 -0
- package/dist/shared/package-metadata.js +42 -0
- package/dist/worker/console/chat/assistant-content.js +11 -0
- package/dist/worker/console/chat/pi-runtime.js +6 -2
- package/dist/worker/console/chat/turn-process.js +17 -9
- package/dist/worker/console/chat/workspace-landing.js +1 -1
- package/dist/worker/console/static/assets/index-DuVLjCIT.js +57 -0
- package/dist/worker/console/static/index.html +1 -1
- package/dist/worker/console/static-src/app/useRecoveryConsole.js +5 -0
- package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +15 -3
- package/dist/worker/console/static-src/operator-chat/refs.js +3 -0
- package/dist/worker/console/static-src/operator-chat/useChatSessions.js +3 -0
- package/dist/worker/console/static-src/operator-chat/useChatThread.js +1 -0
- package/dist/worker/loop-agent/loop-agent-client.js +17 -3
- package/dist/worker/observability/read-model.js +20 -0
- package/dist/worker/observe/spec-evidence.js +3 -8
- package/dist/worker/observe/static/views/dag-inspector.js +6 -71
- package/dist/worker/preflight.js +2 -1
- package/dist/workflows/dag/backend-test-scenario-param.js +33 -23
- package/dist/workflows/dag/contract-output-registry.js +14 -0
- package/dist/workflows/dag/contract-validator-registrations.js +8 -0
- package/dist/workflows/dag/dynamic-runtime/shared.js +9 -1
- package/dist/workflows/dag/failure-routing.js +9 -4
- package/dist/workflows/dag/frontend-implementation-contract.js +233 -39
- package/dist/workflows/dag/frontend-prewrite-gate.js +364 -61
- package/dist/workflows/dag/frontend-recovery-plan.js +73 -0
- package/dist/workflows/dag/frontend-recovery-root-manifest.js +123 -0
- package/dist/workflows/dag/frontend-recovery-run.js +539 -0
- package/dist/workflows/dag/frontend-repair.js +219 -18
- package/dist/workflows/dag/frontend-verification-trace.js +47 -32
- package/dist/workflows/dag/frontend-writer-recovery.js +106 -0
- package/dist/workflows/dag/frontend-writer-rollback.js +821 -0
- package/dist/workflows/dag/init-hybrid.js +49 -24
- package/dist/workflows/dag/lifecycle.js +4 -0
- package/dist/workflows/dag/node-execution.js +89 -0
- package/dist/workflows/dag/recovery-recommendation.js +58 -0
- package/dist/workflows/dag/report.js +6 -0
- package/dist/workflows/dag/runner.js +245 -11
- package/dist/workflows/dag/scheduler.js +257 -3
- package/dist/workflows/dag/types.js +130 -2
- package/docs/templates/frontend-task-constraints.md +13 -7
- package/package.json +4 -3
- package/dist/worker/console/static/assets/index-gVHrlqI9.js +0 -56
|
@@ -654,8 +654,15 @@ export const dagConvergenceSpecSchema = z
|
|
|
654
654
|
chainNodeIds: z.array(z.string()).optional(),
|
|
655
655
|
})
|
|
656
656
|
.optional();
|
|
657
|
-
|
|
658
|
-
|
|
657
|
+
/**
|
|
658
|
+
* Schema ids that may opt a node into producing-node structured contract
|
|
659
|
+
* self-validation. Validators are registered in the contract output registry
|
|
660
|
+
* (src/workflows/dag/contract-output-registry.ts).
|
|
661
|
+
*/
|
|
662
|
+
export const structuredContractOutputSchemaIds = [
|
|
663
|
+
"frontend-implementation-contract-v1",
|
|
664
|
+
];
|
|
665
|
+
export const dagTaskSchema = z.object({ id: z.string().regex(/^[a-z][a-z0-9-]*$/, "task id must be kebab-case"),
|
|
659
666
|
depends_on: z.array(z.string()).default([]),
|
|
660
667
|
/**
|
|
661
668
|
* How SKIPPED upstreams affect readiness.
|
|
@@ -704,6 +711,20 @@ export const dagTaskSchema = z.object({
|
|
|
704
711
|
* on safe read-only Pi nodes before the node becomes ERROR.
|
|
705
712
|
*/
|
|
706
713
|
outputProtocol: dagOutputProtocolSchema.optional(),
|
|
714
|
+
/**
|
|
715
|
+
* Node-level structured contract self-check: after the Pi output is
|
|
716
|
+
* produced, validate it against the named contract schema at the node so
|
|
717
|
+
* schema/typo/null violations become invalid-output (retryable on the node)
|
|
718
|
+
* instead of failing later at a downstream deterministic gate. Validators
|
|
719
|
+
* are resolved via the contract output registry keyed by schemaId.
|
|
720
|
+
*/
|
|
721
|
+
structuredContractOutput: z
|
|
722
|
+
.object({
|
|
723
|
+
schemaId: z.enum(structuredContractOutputSchemaIds),
|
|
724
|
+
retryOnInvalid: z.boolean().default(true),
|
|
725
|
+
})
|
|
726
|
+
.strict()
|
|
727
|
+
.optional(),
|
|
707
728
|
/**
|
|
708
729
|
* Fail-closed outcome/diff consistency contract for bounded Pi writers.
|
|
709
730
|
* The writer must begin with IMPLEMENTATION_OUTCOME: changed,
|
|
@@ -874,6 +895,113 @@ export const dagSpecSchema = z
|
|
|
874
895
|
});
|
|
875
896
|
}
|
|
876
897
|
});
|
|
898
|
+
export const FRONTEND_RECOVERY_STATE_SCHEMA_VERSION = 1;
|
|
899
|
+
export const FRONTEND_RECOVERY_RESULT_SCHEMA_VERSION = 1;
|
|
900
|
+
/**
|
|
901
|
+
* Frontend candidate-continuation recovery phase (decision B, phase-3 subset).
|
|
902
|
+
* Phase 3a parents converge first, so `rollback-pending` is not produced and
|
|
903
|
+
* was removed by AC-1; the phase starts at `child-staging` and ends at
|
|
904
|
+
* `settled`.
|
|
905
|
+
*/
|
|
906
|
+
export const frontendRecoveryPhaseSchema = z.enum([
|
|
907
|
+
"child-staging",
|
|
908
|
+
"child-activating",
|
|
909
|
+
"child-running",
|
|
910
|
+
"settled",
|
|
911
|
+
]);
|
|
912
|
+
/**
|
|
913
|
+
* Single-writer recovery intent/lineage stored on `DagRunState`. The parent run
|
|
914
|
+
* owns the authoritative copy and advances it via revision-guarded CAS writes;
|
|
915
|
+
* the child carries a frozen lineage snapshot so the activation gate can prove
|
|
916
|
+
* it is the reserved child of a child-running parent.
|
|
917
|
+
*
|
|
918
|
+
* Invariants: `attemptIndex ∈ {0,1}`; `continuationCount ∈ {0,1}`; a child's
|
|
919
|
+
* `recoveryRootRunId` always equals the root runId; `revision` is the CAS
|
|
920
|
+
* pre-comparison counter. `revision` monotonicity is enforced at runtime by the
|
|
921
|
+
* runner's `(existing?.revision ?? 0) + 1` CAS write (the schema only bounds it
|
|
922
|
+
* non-negative). `childRunId` may be absent through `child-activating` and must
|
|
923
|
+
* be non-empty from `child-running` onward.
|
|
924
|
+
*/
|
|
925
|
+
export const frontendRecoveryStateSchema = z
|
|
926
|
+
.object({
|
|
927
|
+
schemaVersion: z.literal(FRONTEND_RECOVERY_STATE_SCHEMA_VERSION),
|
|
928
|
+
phase: frontendRecoveryPhaseSchema,
|
|
929
|
+
requestId: z.string().min(1),
|
|
930
|
+
recoveryRootRunId: z.string().min(1),
|
|
931
|
+
parentRunId: z.string().min(1),
|
|
932
|
+
childRunId: z.string().min(1).optional(),
|
|
933
|
+
attemptId: z.string().min(1),
|
|
934
|
+
attemptIndex: z.number().int().min(0).max(1),
|
|
935
|
+
continuationCount: z.number().int().min(0).max(1),
|
|
936
|
+
/** Node id of the reset-closure root: frontend-plan-pi /
|
|
937
|
+
* frontend-plan-revision-pi / frontend-prewrite-gate-shell /
|
|
938
|
+
* frontend-implement-pi (writer partial write). */
|
|
939
|
+
failureSource: z.string().min(1).optional(),
|
|
940
|
+
revision: z.number().int().nonnegative(),
|
|
941
|
+
})
|
|
942
|
+
.strict()
|
|
943
|
+
.superRefine((value, ctx) => {
|
|
944
|
+
const requiresChild = value.phase === "child-running" || value.phase === "settled";
|
|
945
|
+
if (requiresChild && !value.childRunId) {
|
|
946
|
+
ctx.addIssue({
|
|
947
|
+
code: z.ZodIssueCode.custom,
|
|
948
|
+
message: `phase ${value.phase} requires a non-empty childRunId`,
|
|
949
|
+
path: ["childRunId"],
|
|
950
|
+
});
|
|
951
|
+
}
|
|
952
|
+
});
|
|
953
|
+
export const frontendRecoveryOutcomeSchema = z.enum([
|
|
954
|
+
"none",
|
|
955
|
+
"recovered",
|
|
956
|
+
"candidate-contract-invalid",
|
|
957
|
+
"prewrite-blocked",
|
|
958
|
+
"repair-exhausted",
|
|
959
|
+
"auto-recovery-blocked",
|
|
960
|
+
]);
|
|
961
|
+
export const frontendRecoveryOriginSchema = z
|
|
962
|
+
.object({
|
|
963
|
+
kind: z.enum(["frontend-prewrite-gate", "frontend-writer"]),
|
|
964
|
+
parentRunId: z.string().min(1),
|
|
965
|
+
childRunId: z.string().min(1).optional(),
|
|
966
|
+
requestId: z.string().min(1),
|
|
967
|
+
failedNodeId: z.string(),
|
|
968
|
+
})
|
|
969
|
+
.strict();
|
|
970
|
+
export const frontendRecoveryFailureClassSchema = z
|
|
971
|
+
.object({
|
|
972
|
+
code: z.enum([
|
|
973
|
+
"candidate-contract-invalid",
|
|
974
|
+
"prewrite-blocked",
|
|
975
|
+
"staging-failed",
|
|
976
|
+
"writer-transient-partial-write",
|
|
977
|
+
]),
|
|
978
|
+
classification: z.string(),
|
|
979
|
+
reason: z.string(),
|
|
980
|
+
})
|
|
981
|
+
.strict();
|
|
982
|
+
export const frontendRecoveryEvidenceRefSchema = z
|
|
983
|
+
.object({
|
|
984
|
+
runId: z.string().min(1),
|
|
985
|
+
relativePath: z.string().min(1),
|
|
986
|
+
sha256: z.string().min(1),
|
|
987
|
+
})
|
|
988
|
+
.strict();
|
|
989
|
+
/**
|
|
990
|
+
* Terminal frontend recovery result. `failureClass` is absent for `none`,
|
|
991
|
+
* `recovered` and `auto-recovery-blocked` outcomes. The schema intentionally
|
|
992
|
+
* stays permissive (failureClass optional, evidenceRefs may be empty) so it
|
|
993
|
+
* accepts the runner's actual phase-3a products, which do not always carry a
|
|
994
|
+
* failure class or evidence reference.
|
|
995
|
+
*/
|
|
996
|
+
export const frontendRecoveryResultSchema = z
|
|
997
|
+
.object({
|
|
998
|
+
schemaVersion: z.literal(FRONTEND_RECOVERY_RESULT_SCHEMA_VERSION),
|
|
999
|
+
outcome: frontendRecoveryOutcomeSchema,
|
|
1000
|
+
origin: frontendRecoveryOriginSchema,
|
|
1001
|
+
failureClass: frontendRecoveryFailureClassSchema.optional(),
|
|
1002
|
+
evidenceRefs: z.array(frontendRecoveryEvidenceRefSchema),
|
|
1003
|
+
})
|
|
1004
|
+
.strict();
|
|
877
1005
|
export const DEFAULT_DAG_EXECUTOR_MODELS = {
|
|
878
1006
|
pi: {
|
|
879
1007
|
LOW: "gpt-5.3-codex-spark",
|
|
@@ -18,13 +18,19 @@ TODO
|
|
|
18
18
|
|
|
19
19
|
## Mock 约束(数据型任务)
|
|
20
20
|
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
26
|
-
-
|
|
27
|
-
-
|
|
21
|
+
本段决定生成期 `allowedMockStrategies` 与冻结的 Mock 验证命令。只有当生成期**能证明任务确实包含 Mock 且有确定性验证命令**时,DAG 才会放行 `native` / `browser-intercept` / `request-adapter`;否则自动收敛为 `not-needed`,design review 若按项目规范改选 `native`,会在 prewrite 被 `mock-strategy-outside-allowed` 拦截、`implement` 被跳过。
|
|
22
|
+
|
|
23
|
+
- **何时必须填**:项目规范(`openspec/project-specs/**`、`ai_workspace/**`、mock 规则或类似 DEC-* 决策)要求/建议 Mock;或需求涉及远端接口且后端未就绪。规范要求 Mock 时,优先 `task.json.frontendMock.policy: "required"`。
|
|
24
|
+
- **命令要探索、不要硬编码**:到项目 `package.json` scripts 里找实际存在的 Mock 相关脚本(如 `mock`、`mock:*`、`dev:mock`,或名字含 mock 的脚本),结合既有 service root 的 handler/fixture/bootstrap 启动方式,确定一条**真实存在、确定、可自终止**(启动→断言→退出 0)的验证命令。常驻 dev server 必须包装成自终止脚本(start→assert→stop),否则 verify shell 会超时 fail-closed。
|
|
25
|
+
- **写入 task.json**:把探索到的命令原样写进 `frontendMock.verifyCommands`(`label` 唯一、`command` 与项目脚本一致)。`label` 会进入冻结命令集,implementation contract 的 `verificationTarget.commandLabel` 必须逐字引用它。
|
|
26
|
+
- **命令来源白名单**:只允许项目 `package.json` 已有脚本、Mock capability seed、或本段声明的 `verifyCommands`;plan/design 阶段不能发明 shell 命令。
|
|
27
|
+
- **Mock/API/schema 规范路径**:TODO
|
|
28
|
+
- **既有 Mock service root、handler/fixture/bootstrap**:TODO
|
|
29
|
+
- **既有 browser/e2e interception 或 request adapter/DI seam**:TODO
|
|
30
|
+
- **production 禁用边界**:TODO
|
|
31
|
+
- **真实请求默认路径与 Mock 显式启用方式**:TODO
|
|
32
|
+
- **`task.json.frontendMock.policy`**:`auto | required | disabled`(规范强制 Mock 用 `required`)
|
|
33
|
+
- **被拦截时怎么修**:`mock-strategy-outside-allowed` / `no authorized Mock verification commands` 是**生成期契约问题,不是 plan 问题**——补 `frontendMock.verifyCommands`(或 `policy: "required"` + 命令)后**重新生成 DAG** 再跑,plan-revision 无法修复它。
|
|
28
34
|
|
|
29
35
|
## allowedPaths
|
|
30
36
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@tea-agent/loop-agent",
|
|
3
|
-
"version": "0.35.
|
|
3
|
+
"version": "0.35.4-beta.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"bin": {
|
|
6
6
|
"loop-agent": "bin/loop-agent.js",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"pi-prompt": "node --import tsx/esm src/cli.ts pi-prompt",
|
|
46
46
|
"clean": "node -e \"require('node:fs').rmSync('dist',{recursive:true,force:true})\"",
|
|
47
47
|
"brand:sync": "node scripts/sync-brand-assets.mjs",
|
|
48
|
-
"build": "npm run brand:sync && npm run clean && tsc -p tsconfig.build.json && node -e \"const fs=require('node:fs');const p='dist/worker/observe/static';fs.mkdirSync(p,{recursive:true});fs.cpSync('src/worker/observe/static',p,{recursive:true});\" && npm run console:build",
|
|
48
|
+
"build": "npm run brand:sync && npm run clean && tsc -p tsconfig.build.json && node -e \"const fs=require('node:fs');const p='dist/worker/observe/static';fs.mkdirSync(p,{recursive:true});fs.cpSync('src/worker/observe/static',p,{recursive:true});\" && npm run console:build && node scripts/write-build-stamp.mjs",
|
|
49
49
|
"console:typecheck": "tsc -p src/worker/console/tsconfig.json",
|
|
50
50
|
"console:build": "npm run console:typecheck && vite build --config src/worker/console/vite.config.ts",
|
|
51
51
|
"prepack": "npm run build",
|
|
@@ -88,5 +88,6 @@
|
|
|
88
88
|
"typescript": "^5.9.3",
|
|
89
89
|
"vite": "^7.0.0",
|
|
90
90
|
"vitest": "^3.2.4"
|
|
91
|
-
}
|
|
91
|
+
},
|
|
92
|
+
"packageManager": "pnpm@10.33.0+sha512.10568bb4a6afb58c9eb3630da90cc9516417abebd3fabbe6739f0ae795728da1491e9db5a544c76ad8eb7570f5c4bb3d6c637b2cb41bfdcdb47fa823c8649319"
|
|
92
93
|
}
|