@tea-agent/loop-agent 0.33.4 → 0.33.6-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.
Files changed (27) hide show
  1. package/CHANGELOG.md +36 -0
  2. package/dist/executors/dag-pi-executor.js +34 -12
  3. package/dist/executors/shell-executor.js +26 -66
  4. package/dist/task/config-types.js +2 -2
  5. package/dist/worker/console/chat/chat-event-store.js +57 -18
  6. package/dist/worker/console/chat/routes.js +850 -170
  7. package/dist/worker/console/static/assets/{index-PzYzcuFG.js → index-CteJFFL2.js} +17 -17
  8. package/dist/worker/console/static/index.html +1 -1
  9. package/dist/worker/console/static-src/operator-chat/chat-sse-events.js +33 -8
  10. package/dist/worker/console/static-src/operator-chat/refs.js +3 -0
  11. package/dist/worker/console/static-src/operator-chat/useChatSessions.js +3 -0
  12. package/dist/worker/console/static-src/operator-chat/useChatStream.js +80 -2
  13. package/dist/workflows/dag/backend-test-case-coverage-analysis.js +27 -2
  14. package/dist/workflows/dag/backend-test-markdown-workflow.js +17 -0
  15. package/dist/workflows/dag/backend-test-module-stem.js +26 -0
  16. package/dist/workflows/dag/backend-test-pytest-collection.js +44 -0
  17. package/dist/workflows/dag/backend-test-writer-completeness.js +165 -49
  18. package/dist/workflows/dag/dynamic-runtime/map.js +24 -8
  19. package/dist/workflows/dag/init-hybrid.js +44 -167
  20. package/dist/workflows/dag/types.js +7 -0
  21. package/docs/templates/backend-test-dag.json +10 -10
  22. package/docs/templates/frontend-test-dag.generate-cases.prompt.md +2 -2
  23. package/docs/templates/frontend-test-dag.json +9 -9
  24. package/docs/templates/frontend-test-dag.retrieve-context.prompt.md +7 -7
  25. package/harness.json +1 -1
  26. package/package.json +1 -1
  27. package/skills/playwright-cli/SKILL.md +2 -3
@@ -11,19 +11,19 @@
11
11
  "globalConstraints": [
12
12
  "Do not generate pytest or Playwright source code.",
13
13
  "Only use declared isolated test environments; production URLs and real credentials are blocked.",
14
- "Every generated browser start command uses playwright-cli open --browser=chrome followed by the concrete controller-resolved URL (resolved from an explicit allowlist of controller-owned, hash-bound task source/reference documents and URL keys: baseUrl, targetUrl, loginUrl and common case/separator variants; http://localhost:5173 is used only when no allowed candidate exists, and conflicting same-priority candidates fail closed); executable case lines never retain an angle-bracket URL/ref placeholder; subsequent commands stay in that default session and must not use unverified named-session flags.",
14
+ "Every generated browser start command uses playwright-cli open --browser=chrome followed by the concrete URL selected by retrieve-frontend-test-context-pi from bound task source/config and written to context.md; the environment shell must mark that URL reachable before generation/execution; executable case lines never retain an angle-bracket URL/ref placeholder; subsequent commands stay in that default session and must not use unverified named-session flags.",
15
15
  "Case children execute serially. Persist each case result, logs and browser evidence before the next child starts.",
16
16
  "A token threshold is a post-case stop check, not a model hard token cap; unstarted cases must be recorded as blocked: token-budget-exhausted.",
17
17
  "Default pipeline acceptance is the final frontend-test-result-v1 plus testcase/frontend/reports/frontend-test-report.html",
18
18
  "Default frontendTest.reviewMode=off uses mechanical checklist-shell before materialize; set reviewMode=blocking for legacy dual LLM review gate.",
19
19
  "playwright-cli-only: generators and executors may call only skill-declared playwright-cli commands; bare playwright / npx playwright / @playwright/test / Playwright source are forbidden with no native Playwright fallback.",
20
- "Browser-tool preflight (preflight-frontend-browser-tool-shell) must reject CODE_AGENT_PI_BACKEND=cli-only, verify the Pi SDK structured custom-tool surface, freeze baseUrl from allowlisted hash-bound task references and explicit baseUrl/targetUrl/loginUrl keys (or controller default localhost only when no candidate exists), and confirm the verified playwright-cli launcher + --help contract before any frontend-test Pi node; missing capability/CLI fails with zero Pi calls.",
20
+ "Browser-tool preflight (preflight-frontend-browser-tool-shell) must reject CODE_AGENT_PI_BACKEND=cli-only, verify the Pi SDK structured custom-tool surface, and confirm the verified playwright-cli launcher + --help open/close/find/snapshot/click contract before any frontend-test Pi node; it does not select or freeze the tested URL; missing capability/CLI fails with zero Pi calls.",
21
21
  "Case executors use structured playwright_cli custom tool under commandPolicy capability-allowlist; playwright-cli stays capability-gated while ordinary writers have bash.",
22
22
  "File outputs use canonical --filename: playwright-cli screenshot --filename final.png (a real target/ref may precede it), playwright-cli pdf --filename final.pdf, and playwright-cli snapshot --filename snapshot.txt only when a snapshot file is needed; a snapshot without filename is response-only. Never use --path, --output, --file, or an output path as a positional target.",
23
23
  "Passed cases require same-child ordered controller receipts: successful open → successful find → successful post-execution cleanup. Pre-start cleanup, snapshot/goto/screenshot/request/console, and ordinary interactions cannot establish passed authority; model prose cannot fake green.",
24
- "Environment preflight must curl-probe the frozen non-production baseUrl before generate; unreachable or curl-unavailable ends preflight as blocked (frontend-base-url-unreachable|curl-unavailable) so generate/map do not run.",
24
+ "Environment preflight must parse the retrieve-authored context.md baseUrl, reject unsafe/non-production violations, and curl-probe it before generate; unreachable or curl-unavailable ends preflight as blocked (frontend-base-url-unreachable|curl-unavailable) so generate/map do not run.",
25
25
  "U/D cases must prove current-user data ownership or create cleanable current-user data or authorized Mock; otherwise blocked (current-user-data-unavailable|data-ownership-unverifiable|safe-test-data-setup-unavailable) without cross-user mutation.",
26
- "Rerun topology is bounded by frontendTest.maxRerunAttempts (0..4, default 2): the runtime hybrid emits one select+map pair per attempt round, each round only candidates blocked or missing-result cases and rewrites the authoritative case-result.json/execution.md, so the final round's evidence controls the report."
26
+ "Rerun topology is bounded by frontendTest.maxRerunAttempts (0..4): lean off/advisory defaults to 1 round, full reviewMode=blocking defaults to 2 rounds, and an explicit value overrides either default. The runtime hybrid emits one select+map pair per attempt round; each round only candidates blocked or missing-result cases and rewrites the authoritative case-result.json/execution.md, so the final round's evidence controls the report."
27
27
  ],
28
28
  "tasks": [
29
29
  {
@@ -38,8 +38,8 @@
38
38
  ".harness/**",
39
39
  "artifacts/**"
40
40
  ],
41
- "outputContract": "Deterministic SDK-only browser-tool preflight before any frontend-test Pi node; freeze a controller-owned origin (baseUrl/targetUrl/loginUrl allowlist with deterministic priority and fail-closed ambiguity) and fail closed with browser-command-capability-unavailable | playwright-cli-unavailable | playwright-cli-contract-incompatible.",
42
- "subtask_prompt": "Reject cli-only rollback, verify the Pi SDK structured custom-tool capability, freeze baseUrl from controller-owned task source/reference via the explicit document+key allowlist (baseUrl/targetUrl/loginUrl variants; default localhost only when no candidate; fail closed on ambiguity), and verify the controller-resolved playwright-cli launcher plus --help lists open/close/find/snapshot/click. Do not install packages. Do not start a browser session.",
41
+ "outputContract": "Deterministic SDK-only browser-tool capability preflight before any frontend-test Pi node; no target URL selection; fail closed with browser-command-capability-unavailable | playwright-cli-unavailable | playwright-cli-contract-incompatible.",
42
+ "subtask_prompt": "Reject cli-only rollback, verify the Pi SDK structured custom-tool capability, and verify the controller-resolved playwright-cli launcher plus --help lists open/close/find/snapshot/click. Do not resolve or freeze the tested URL. Do not install packages. Do not start a browser session.",
43
43
  "shell": {
44
44
  "commands": [],
45
45
  "frontendBrowserToolPreflight": {},
@@ -121,7 +121,7 @@
121
121
  "artifacts/**"
122
122
  ],
123
123
  "outputContract": "Fail-closed environment preflight: absolute non-production baseUrl + curl HTTP reachability; writes environmentProbe facts; unreachable => blockedReason frontend-base-url-unreachable (node ERROR so generate/map do not run).",
124
- "subtask_prompt": "Use the controller-frozen baseUrl; the runtime resolver recognizes allowlisted hash-bound reference documents and baseUrl/targetUrl/loginUrl variants, falling back only when no candidate exists. Reject production / non-http(s). Probe with curl (HEAD then GET fallback; connect/max-time; no auth/cookie). 2xx/3xx => reachable and continue. 4xx/5xx/DNS/timeout/connection refused/TLS => blockedReason frontend-base-url-unreachable. Missing curl => blockedReason curl-unavailable. Do not start the app. Runtime hybrid generator embeds the authoritative probe script.",
124
+ "subtask_prompt": "Parse the concrete baseUrl selected by retrieve-frontend-test-context-pi from testcase/frontend/rag/context.md. Reject production, non-http(s), credentials, query and fragment. Probe with curl (HEAD then GET fallback; connect/max-time; no auth/cookie). 2xx/3xx => reachable and continue. 4xx/5xx/DNS/timeout/connection refused/TLS => blockedReason frontend-base-url-unreachable. Missing curl => blockedReason curl-unavailable. Do not start the app. Runtime hybrid generator embeds the authoritative probe script.",
125
125
  "shell": {
126
126
  "commands": [
127
127
  "node -e \"console.log('template placeholder: runtime hybrid DAG embeds curl preflight; do not use this static command as source of truth')\""
@@ -271,11 +271,11 @@
271
271
  ".harness/**",
272
272
  "artifacts/**"
273
273
  ],
274
- "outputContract": "Round 1 of the bounded rerun topology (default 2 rounds): stdout final JSON line {cases:[...]} for blocked or missing-result-file cases with rerunAttempt < 1; the runtime hybrid generates one selector/map pair per configured maxRerunAttempts so the latest rerun evidence is authoritative.",
274
+ "outputContract": "Round 1 of the bounded rerun topology (lean default 1 round; full reviewMode=blocking default 2): stdout final JSON line {cases:[...]} for blocked or missing-result-file cases with rerunAttempt < 1; the runtime hybrid generates one selector/map pair per configured maxRerunAttempts so the latest rerun evidence is authoritative.",
275
275
  "subtask_prompt": "Select frontend-test cases eligible for bounded rerun.",
276
276
  "shell": {
277
277
  "commands": [
278
- "node -e \"const fs=require('fs'),path=require('path');const manifestPath='testcase/frontend/cases/manifest.json';if(!fs.existsSync(manifestPath)){process.stdout.write(JSON.stringify({cases:[]}));process.exit(0);}const manifest=JSON.parse(fs.readFileSync(manifestPath,'utf8'));const cases=[];for(const c of (manifest.cases||[])){const evidenceDir=(c.evidenceDir||('testcase/frontend/evidence/'+c.caseId+'/')).replace(/\\/+$/,'')+'/';const resultPath=path.join(evidenceDir,'case-result.json');const execPath=path.join(evidenceDir,'execution.md');let reason=null;let attempt=0;let missing=false;if(!fs.existsSync(resultPath)){missing=true;reason='missing-result-files';}else{try{const r=JSON.parse(fs.readFileSync(resultPath,'utf8'));attempt=Number(r.rerunAttempt||0)||0;if(r.status==='blocked')reason='blocked';if(!r.status){missing=true;reason='missing-result-files';}}catch(e){missing=true;reason='missing-result-files';}}if(!fs.existsSync(execPath)){const st=reason;if(st!=='blocked'){missing=true;reason=reason||'missing-result-files';}}const should=(reason==='blocked'||missing)&&attempt<2;if(should){cases.push({caseId:c.caseId,casePath:c.casePath||('testcase/frontend/cases/'+c.caseId+'.md'),evidenceDir,dimension:c.dimension||'core',acIds:c.acIds||[],rerunAttempt:attempt+1,reason:reason||'blocked'});}}const out={schemaVersion:1,cases};fs.mkdirSync('testcase/frontend/evidence',{recursive:true});fs.writeFileSync('testcase/frontend/evidence/rerun-candidates.json',JSON.stringify(out,null,2)+'\\n');process.stdout.write(JSON.stringify({cases}));"
278
+ "node -e \"const fs=require('fs'),path=require('path');const manifestPath='testcase/frontend/cases/manifest.json';if(!fs.existsSync(manifestPath)){process.stdout.write(JSON.stringify({cases:[]}));process.exit(0);}const manifest=JSON.parse(fs.readFileSync(manifestPath,'utf8'));const cases=[];for(const c of (manifest.cases||[])){const evidenceDir=(c.evidenceDir||('testcase/frontend/evidence/'+c.caseId+'/')).replace(/\\/+$/,'')+'/';const resultPath=path.join(evidenceDir,'case-result.json');const execPath=path.join(evidenceDir,'execution.md');let reason=null;let attempt=0;let missing=false;if(!fs.existsSync(resultPath)){missing=true;reason='missing-result-files';}else{try{const r=JSON.parse(fs.readFileSync(resultPath,'utf8'));attempt=Number(r.rerunAttempt||0)||0;if(r.status==='blocked')reason='blocked';if(!r.status){missing=true;reason='missing-result-files';}}catch(e){missing=true;reason='missing-result-files';}}if(!fs.existsSync(execPath)){const st=reason;if(st!=='blocked'){missing=true;reason=reason||'missing-result-files';}}const should=(reason==='blocked'||missing)&&attempt<1;if(should){cases.push({caseId:c.caseId,casePath:c.casePath||('testcase/frontend/cases/'+c.caseId+'.md'),evidenceDir,dimension:c.dimension||'core',acIds:c.acIds||[],rerunAttempt:attempt+1,reason:reason||'blocked'});}}const out={schemaVersion:1,cases};fs.mkdirSync('testcase/frontend/evidence',{recursive:true});fs.writeFileSync('testcase/frontend/evidence/rerun-candidates.json',JSON.stringify(out,null,2)+'\\n');process.stdout.write(JSON.stringify({cases}));"
279
279
  ],
280
280
  "cwd": ".",
281
281
  "timeoutMs": 120000
@@ -2,15 +2,15 @@
2
2
 
3
3
  Write only `testcase/frontend/rag/context.md` and `coverage-map.md`. Record traceable facts from the task source, routes, components, API/Mock contracts, existing tests and execution contract. Do not invent fields, credentials, limits or test data.
4
4
 
5
- ## Controller-frozen Base URL (required)
5
+ ## Runtime Base URL resolution (required)
6
6
 
7
- The preflight controller resolves and freezes one absolute browser base URL before this Pi node runs. It accepts only controller-owned, hash-bound reference documents on its filename/key allowlists (including `config.md`, `environment.md`, `urls.md` and explicit `baseUrl` / `targetUrl` / `loginUrl` variants); it fails closed on conflicting candidates and uses the localhost default only when no candidate exists. Copy the supplied value and source exactly into `context.md` as `baseUrl: <url>` and `baseUrlSource: <source>`.
7
+ Read the bound task source and environment/config references, then select one concrete browser entry URL. Prefer `TARGET_URL`/`targetUrl`, then `BASE_URL`/`baseUrl` or `FRONTEND_BASE_URL`/`frontendUrl`, then `LOGIN_URL`/`loginUrl`; accept common case, underscore, kebab and space variants. If no usable URL exists, use `http://localhost:5173`.
8
8
 
9
- - Do not derive, replace, or override the origin from model reasoning, route text, case prose, existing RAG files, or other repository content.
10
- - Never use production hosts or credentials.
11
- - Write `environmentProbe: pending`. The environment preflight shell will replace this with `reachable`, `unreachable`, or `curl-unavailable` plus a structured `blockedReason` (for example `frontend-base-url-unreachable`).
12
- - Include the exact browser start prefix using the supplied controller-frozen URL:
13
- `playwright-cli open --browser=chrome <controller-frozen-base-url>`.
9
+ - Write the selected value and its bound source into `context.md` as `baseUrl: <url>` and `baseUrlSource: <source>|default-localhost-5173`.
10
+ - Never select API-only endpoints, production hosts, credential URLs, query-bearing URLs or fragment URLs.
11
+ - Write `environmentProbe: pending`. The following environment shell deterministically parses `context.md`, validates URL safety, probes curl HEAD→GET, and replaces this with `reachable`, `unreachable`, or `curl-unavailable` plus a structured `blockedReason`.
12
+ - Include the exact browser start prefix using the selected concrete URL:
13
+ `playwright-cli open --browser=chrome <resolved-base-url>`.
14
14
 
15
15
  Do not claim the environment is reachable until preflight completes. Preflight does not start the application.
16
16
 
package/harness.json CHANGED
@@ -81,7 +81,7 @@
81
81
  "pi": {
82
82
  "description": "Pi 负责规划、评审、诊断;当 DAG toolProfile=write 时也可做有界写入。模型按复杂度三档配置,格式为 provider/model 字符串(例:wizard-local/grok-4.5);斜杠前为 Pi provider,后为 modelId,勿只写裸 modelId。",
83
83
  "LOW": "wizard-local/minimax-m3",
84
- "MED": "wizard-local/grok-4.5",
84
+ "MED": "wizard-local/gpt-5.6-sol",
85
85
  "HIGH": "wizard-local/gpt-5.6-sol"
86
86
  }
87
87
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tea-agent/loop-agent",
3
- "version": "0.33.4",
3
+ "version": "0.33.6-beta.0",
4
4
  "type": "module",
5
5
  "bin": {
6
6
  "loop-agent": "bin/loop-agent.js",
@@ -54,8 +54,7 @@ request
54
54
 
55
55
  ## 推荐执行流程
56
56
 
57
- 使用 controller 冻结的非生产 `baseUrl` 和默认浏览器 session;不得创建 named session。交互前先
58
- 获取 snapshot,并只使用 snapshot 中可见的 ref 或已知安全 locator。
57
+ 使用 `testcase/frontend/rag/context.md` 中已由 environment shell 标记为 `reachable` 的非生产 `baseUrl` 和默认浏览器 session;不得创建 named session。交互前先获取 snapshot,并只使用 snapshot 中可见的 ref 或已知安全 locator。
59
58
 
60
59
  ```text
61
60
  playwright-cli open --browser=chrome http://localhost:5173
@@ -89,6 +88,6 @@ controller receipts:successful `open` → successful `find` → successful pos
89
88
 
90
89
  ## 阻塞处理
91
90
 
92
- 当环境、数据、权限、时序、异常路径或响应内容无法用 RAG、冻结配置和 runtime allowlist 证明时,
91
+ 当环境、数据、权限、时序、异常路径或响应内容无法用 RAG、已验证 context URL 和 runtime allowlist 证明时,
93
92
  写入 `blocked` evidence,并提供具体 `blockedReason`。不要引入替代执行路径,也不要把隐藏状态或
94
93
  未观察到的网络结果当作通过证据。