@tea-agent/loop-agent 0.29.1 → 0.29.3
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 +36 -16
- package/bin/agent-worker.js +0 -0
- package/dist/commands/client-recovery.js +2 -10
- package/dist/commands/init.js +1 -1
- package/dist/executors/dag-pi-executor.js +35 -10
- package/dist/executors/pi-executor.js +5 -3
- package/dist/executors/pi-playwright-cli-tool.js +9 -14
- package/dist/executors/pi-sdk-executor.js +16 -0
- package/dist/shared/operator/capabilities.js +9 -9
- package/dist/shared/pi-retry-settings.js +23 -0
- package/dist/worker/console/chat/pi-runtime.js +167 -41
- package/dist/worker/console/chat/routes.js +21 -2
- package/dist/worker/console/chat/runtime-context.js +50 -8
- package/dist/worker/console/chat/tool-preview.js +90 -0
- package/dist/worker/console/chat/turn-process.js +178 -0
- package/dist/worker/console/chat/usage.js +144 -16
- package/dist/worker/console/night-aux-ticker.js +141 -0
- package/dist/worker/console/operation-runner.js +21 -4
- package/dist/worker/console/operator-user-error.js +12 -0
- package/dist/worker/console/recovery-cta.js +6 -6
- package/dist/worker/console/routes.js +61 -0
- package/dist/worker/console/server.js +7 -0
- package/dist/worker/console/static/assets/index-D9gnJn_l.js +29 -0
- package/dist/worker/console/static/assets/index-rajoXwkM.css +1 -0
- package/dist/worker/console/static/index.html +2 -2
- package/dist/worker/console/static-src/night-prepare-result.js +118 -0
- package/dist/worker/scheduler/clock-install/win32-schtasks.js +70 -15
- package/dist/workflows/dag/backend-test-writer-completeness.js +98 -14
- package/dist/workflows/dag/frontend-test-case-checklist.js +3 -3
- package/dist/workflows/dag/init-hybrid.js +21 -12
- package/dist/workflows/dag/node-execution.js +41 -2
- package/docs/templates/frontend-test-case-checklist.md +1 -1
- package/docs/templates/frontend-test-dag.generate-cases.prompt.md +1 -1
- package/docs/templates/frontend-test-dag.json +1 -1
- package/docs/templates/frontend-test-dag.retrieve-context.prompt.md +1 -1
- package/docs/templates/frontend-test-dag.review-cases.prompt.md +1 -1
- package/docs/templates/init-managed-agents.md +6 -3
- package/package.json +1 -1
- package/skills/playwright-cli/SKILL.md +1 -1
- package/skills/playwright-cli-case-generator/SKILL.md +1 -1
- package/dist/worker/console/static/assets/index-Cwx-ZVEQ.js +0 -29
- package/dist/worker/console/static/assets/index-Yyn3ynVv.css +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -2,34 +2,54 @@
|
|
|
2
2
|
|
|
3
3
|
## [Unreleased]
|
|
4
4
|
|
|
5
|
-
## [0.29.
|
|
5
|
+
## [0.29.3] - 2026-08-07
|
|
6
6
|
|
|
7
7
|
### 重点更新
|
|
8
8
|
|
|
9
|
-
-
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
9
|
+
- 夜间任务控制台升级为引导式工作台,支持点选预约、审阅写入集与任务看板,并保留人工审批门禁
|
|
10
|
+
- 失败 DAG 默认改为从失败节点安全续跑,避免因服务波动无理由新建任务
|
|
11
|
+
- Operator Chat 支持内联展示工具执行过程,并改进 Pi 用量统计的准确解析与状态栏展示
|
|
12
|
+
- 增强 Pi 网关限流容错,遇到 429 状态码时自动按 60 秒间隔退避重试
|
|
13
13
|
|
|
14
14
|
### 新增
|
|
15
15
|
|
|
16
|
-
-
|
|
17
|
-
- 新增前端测试标准场景规范模板(frontend-test-standard-scenarios.v1.json)
|
|
18
|
-
- 前端测试独占节点支持 tools-only 写保护策略,在保留工具级写沙箱的同时跳过 Git 基线的硬失败限制
|
|
16
|
+
- 控制台新增前台辅助夜间任务调度开关,在控制台开启时可按间隔触发调度(仅前台有效,过夜仍需系统定时器)
|
|
19
17
|
|
|
20
18
|
### 改进
|
|
21
19
|
|
|
22
|
-
-
|
|
23
|
-
-
|
|
24
|
-
-
|
|
25
|
-
-
|
|
20
|
+
- 失败 DAG 恢复策略改为先诊断再从失败节点续跑,统一对齐系统提示、恢复入口与工具说明
|
|
21
|
+
- Operator Chat 将工具执行过程内联至消息时间线,支持折叠查看,切会话后可恢复工具记录
|
|
22
|
+
- Operator Chat 用量栏改进 Pi 用量解析,准确展示输入、输出、缓存读取与费用信息
|
|
23
|
+
- 注入上下文面板升级为更大可读面板,展示脱敏后的完整系统提示、技能正文与激活工具列表
|
|
26
24
|
|
|
27
25
|
### 修复
|
|
28
26
|
|
|
29
|
-
-
|
|
30
|
-
-
|
|
31
|
-
-
|
|
32
|
-
-
|
|
27
|
+
- 修复 Windows 计划任务因 /TR 参数超过 261 字符限制导致创建失败的问题,改用短 .cmd 路径绕过
|
|
28
|
+
- 修复 package-lock 中硬编码的镜像源地址导致发布链路 npm ci 失败的问题,统一指向官方源
|
|
29
|
+
- 修复 playwright-cli open 传入不支持的 --headless/--headed 参数报错的问题
|
|
30
|
+
- 修复 Pi 网关返回 429 限流时重试过快导致任务失败的问题,现自动识别并按 60 秒间隔退避
|
|
31
|
+
- 修复标准 DAG 节点将任务相对路径误当作仓库根路径读取,导致找文件超时的问题
|
|
32
|
+
- 修复 Operator Chat 重开会话时因 JSONL 丢失而静默新建会话 ID 导致会话不匹配的问题
|
|
33
|
+
- 修复夜间任务异步执行结果丢失及 agent-worker 可执行文件权限的问题
|
|
34
|
+
|
|
35
|
+
## [0.29.2] - 2026-08-07
|
|
36
|
+
|
|
37
|
+
### 重点更新
|
|
38
|
+
|
|
39
|
+
- 优化后端测试生成 writer 的续写重试机制,直接内嵌具体目标路径以恢复输出,不再依赖读取受限路径
|
|
40
|
+
- 修复三处完整性门禁(Completeness Gate)误报,避免将正确的测试生成误判为残缺写集
|
|
41
|
+
- 修复标准 Happy Path / `contract-pi` 等节点 source prompt:只暴露仓库相对可读路径(`.harness/tasks/<taskId>/source/...`),并明确禁止把 task-relative 的 `source/需求.md` 当工具读路径
|
|
42
|
+
|
|
43
|
+
### 改进
|
|
44
|
+
|
|
45
|
+
- 后端测试生成 writer(N2 MD / N5 pytest)在输出截断或残缺写集后,续写重试直接内嵌具体目标路径清单,不再依赖读取 `.harness/**` 路径
|
|
46
|
+
- 即使遇到结果为空或输出失败的异常,也会评估完整性门禁,将可恢复的部分写入升格为不完整写集,避免重试空转
|
|
47
|
+
|
|
48
|
+
### 修复
|
|
49
|
+
|
|
50
|
+
- 修复 README 正文提及的编号式文件名被误判为缺失模块的问题
|
|
51
|
+
- 修复覆盖率矩阵(Coverage Matrix)表头识别被覆盖率范围(Coverage Scope)数据行遮蔽的问题
|
|
52
|
+
- 修复合法多行 `def` 的 pytest 脚本被误判为截断的问题(真正截断现仍由括号配平计数准确捕获)
|
|
33
53
|
|
|
34
54
|
## [0.29.0] - 2026-08-07
|
|
35
55
|
|
package/bin/agent-worker.js
CHANGED
|
File without changes
|
|
@@ -18,16 +18,8 @@ export const BACKOFF_MS = [2000, 4000, 8000, 16000, 30000];
|
|
|
18
18
|
export const MAX_SESSION_RETRIES = 5;
|
|
19
19
|
/** Hard cap for OpenCode overflow compact+resume recoveries (≤ 2). */
|
|
20
20
|
export const MAX_OVERFLOW_RECOVERIES = 1;
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
maxRetries: 5,
|
|
24
|
-
baseDelayMs: 3000,
|
|
25
|
-
provider: {
|
|
26
|
-
maxRetries: 0,
|
|
27
|
-
maxRetryDelayMs: 60000,
|
|
28
|
-
},
|
|
29
|
-
};
|
|
30
|
-
export const PI_RECOMMENDED_COMPACTION = { enabled: true };
|
|
21
|
+
import { PI_RECOMMENDED_COMPACTION, PI_RECOMMENDED_RETRY, } from "../shared/pi-retry-settings.js";
|
|
22
|
+
export { PI_RECOMMENDED_COMPACTION, PI_RECOMMENDED_RETRY };
|
|
31
23
|
/**
|
|
32
24
|
* Shared overflow phrase sources used by isContextOverflow and generated plugins.
|
|
33
25
|
* Keep English + Chinese intranet gateway messages in one place to avoid drift.
|
package/dist/commands/init.js
CHANGED
|
@@ -2217,7 +2217,7 @@ function buildTargetFeatureWorkflow(input) {
|
|
|
2217
2217
|
'- `taskKind: "backend-test"` selects the dedicated backend test DAG. Its Pi nodes analyze requirements, generate and review backend cases, generate pytest, and retrospect on results; shell gate/execution nodes enforce the review verdict and run the target project\'s pytest. The backend test templates (`backend-test-dag.json` and the `backend-test-dag.*.prompt.md` files) ship inside the loop-agent package as static references and are projected to target projects under the governance `templates/` directory.',
|
|
2218
2218
|
'- `taskKind: "knowledge-sync"` selects the Feature-scoped test-knowledge write-back DAG (collect → draft → validate → apply → pointer). Bind `featureId` in `task.json` (or hardConstraints / requirement text). It writes only under `features/<featureId>/…` after final verification evidence exists.',
|
|
2219
2219
|
'- `taskKind: "knowledge-graph-bootstrap"` selects the business knowledge-graph bootstrap DAG (preflight → inventory → propose → validate → review → gate → promote → materialize). AI writes only `knowledge/bootstrap/staging/**`; promote is merge-new-only.',
|
|
2220
|
-
'- `taskKind: "frontend-test"` selects the FE-test RAG DAG. It writes a traceable frontend RAG package and Markdown case manifest, then executes manifest cases serially with `playwright-cli` in isolated test environments and retains per-case evidence. It never generates pytest or Playwright source code. `frontendTest.maxCasesPerBatch` defaults to 20 (maximum 50); optional `maxTokensPerCase` and `maxTotalTokens` stop only later cases after a completed case\'s token usage is recorded, marking them `blocked: token-budget-exhausted`. Generated browser startup uses `playwright-cli open --browser=chrome
|
|
2220
|
+
'- `taskKind: "frontend-test"` selects the FE-test RAG DAG. It writes a traceable frontend RAG package and Markdown case manifest, then executes manifest cases serially with `playwright-cli` in isolated test environments and retains per-case evidence. It never generates pytest or Playwright source code. `frontendTest.maxCasesPerBatch` defaults to 20 (maximum 50); optional `maxTokensPerCase` and `maxTotalTokens` stop only later cases after a completed case\'s token usage is recorded, marking them `blocked: token-budget-exhausted`. Generated browser startup uses `playwright-cli open --browser=chrome <base-url>`; the generic playwright-cli skill is unchanged.',
|
|
2221
2221
|
"- Only eligible read-only Pi nodes (planner, scout, reviewer, verifier, closeout with no write-capable tool profile) receive the conservative automatic retry policy. Supervisor, implementer, writer, docs-only, dynamic, shell, static, and decision-gate nodes are not retried automatically. Eligible nodes cannot write repository files; the controller only records immutable attempt evidence under `.harness/dag-runs/<state>/<run-id>/<node-id>/attempt-<n>.json`.",
|
|
2222
2222
|
"",
|
|
2223
2223
|
"Use the package-backed public knowledge CLI for graph operations. Do not require target projects to run package-only kb runtime scripts:",
|
|
@@ -685,9 +685,7 @@ export async function executeDagPiNode(input, meta, piStepFn = executePiStep, wr
|
|
|
685
685
|
});
|
|
686
686
|
}
|
|
687
687
|
let completenessFailure;
|
|
688
|
-
if (
|
|
689
|
-
writeGuardOk &&
|
|
690
|
-
!writerOutcomeViolation &&
|
|
688
|
+
if (writeGuardOk &&
|
|
691
689
|
isBackendTestCompletenessRetryCandidate(input.task)) {
|
|
692
690
|
try {
|
|
693
691
|
const progress = input.task.id === "generate-backend-pytest-pi"
|
|
@@ -701,12 +699,25 @@ export async function executeDagPiNode(input, meta, piStepFn = executePiStep, wr
|
|
|
701
699
|
});
|
|
702
700
|
if (progress.status !== "PASS") {
|
|
703
701
|
const classified = classifyBackendTestWriterCompletenessFailure(progress);
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
|
|
709
|
-
|
|
702
|
+
// A recoverable partial write set (missing/broken files) always wins
|
|
703
|
+
// over empty-output / invalid-output / writer-empty-diff: it carries
|
|
704
|
+
// the concrete target paths the continuation attempt needs.
|
|
705
|
+
if (classified.recoverable) {
|
|
706
|
+
completenessFailure = {
|
|
707
|
+
failureCategory: INCOMPLETE_WRITE_SET_RETRY_CATEGORY,
|
|
708
|
+
detail: `backend-test completeness gate ${progress.status}: targets=${progress.targetPaths.join(",") || "(none)"}; issues=${progress.issues.map((issue) => issue.detail).join("; ") || "none"}`,
|
|
709
|
+
};
|
|
710
|
+
}
|
|
711
|
+
else if (mapped.ok && !writerOutcomeViolation) {
|
|
712
|
+
// Non-recoverable completeness issue only overrides a clean
|
|
713
|
+
// successful path; on an already-failed attempt, keep the
|
|
714
|
+
// executor's original category so retries reflect the real
|
|
715
|
+
// cause (empty-output / invalid-output / writer-empty-diff).
|
|
716
|
+
completenessFailure = {
|
|
717
|
+
failureCategory: "invalid-output",
|
|
718
|
+
detail: `backend-test completeness gate ${progress.status}: targets=${progress.targetPaths.join(",") || "(none)"}; issues=${progress.issues.map((issue) => issue.detail).join("; ") || "none"}`,
|
|
719
|
+
};
|
|
720
|
+
}
|
|
710
721
|
}
|
|
711
722
|
}
|
|
712
723
|
catch (error) {
|
|
@@ -746,7 +757,21 @@ export async function executeDagPiNode(input, meta, piStepFn = executePiStep, wr
|
|
|
746
757
|
? WRITER_EMPTY_DIFF_RETRY_CATEGORY
|
|
747
758
|
: "invalid-output"
|
|
748
759
|
: "write-guard"
|
|
749
|
-
:
|
|
760
|
+
: // When the attempt already failed with a writer-style category
|
|
761
|
+
// (empty-output / invalid-output / writer-empty-diff) but the workspace
|
|
762
|
+
// shows a recoverable partial write set, prefer incomplete-write-set so
|
|
763
|
+
// the continuation is retryable and carries the embedded target paths.
|
|
764
|
+
// Provider/transport failures (quota, auth, network, timeout,
|
|
765
|
+
// rate-limit, unavailable) keep their original category so a provider
|
|
766
|
+
// outage is never masked as a recoverable local write problem.
|
|
767
|
+
writeGuardOk &&
|
|
768
|
+
completenessFailure?.failureCategory ===
|
|
769
|
+
INCOMPLETE_WRITE_SET_RETRY_CATEGORY &&
|
|
770
|
+
(mapped.failureCategory === "empty-output" ||
|
|
771
|
+
mapped.failureCategory === "invalid-output" ||
|
|
772
|
+
mapped.failureCategory === WRITER_EMPTY_DIFF_RETRY_CATEGORY)
|
|
773
|
+
? INCOMPLETE_WRITE_SET_RETRY_CATEGORY
|
|
774
|
+
: mapped.failureCategory,
|
|
750
775
|
durationMs: mapped.durationMs || Date.now() - started,
|
|
751
776
|
};
|
|
752
777
|
}
|
|
@@ -961,10 +961,12 @@ export function classifyPiFailure(input) {
|
|
|
961
961
|
if (input.exitCode === 0 && input.assistantText.trim())
|
|
962
962
|
return "success";
|
|
963
963
|
const combined = `${input.stderr}\n${input.stdout}`.toLowerCase();
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
if (/rate.?limit/.test(combined))
|
|
964
|
+
// Prefer explicit rate-limit / HTTP 429 before generic "limit" quota phrases.
|
|
965
|
+
// Chinese gateways often say "请求频率已达到限制" without English "rate limit".
|
|
966
|
+
if (/rate.?limit|too many requests|\b429\b|请求频率|频率.*限制|rpm|tpm/.test(combined))
|
|
967
967
|
return "rate-limit";
|
|
968
|
+
if (/quota|usage limit|reached.*limit|5\s*小时|5小时|insufficient_quota|billing/.test(combined))
|
|
969
|
+
return "quota";
|
|
968
970
|
if (/\bunauthorized\b|\bhttp\s*40[13]\b|invalid api key|authentication (?:failed|required|error)|auth(?:entication)? failed/.test(combined))
|
|
969
971
|
return "auth";
|
|
970
972
|
if (/unknown provider|unknown model|model.*unavailable|provider.*unavailable|\bunavailable\b|overloaded|capacity|temporarily unavailable/.test(combined))
|
|
@@ -197,21 +197,19 @@ function validateOpenArgs(args, baseUrl) {
|
|
|
197
197
|
for (const arg of args) {
|
|
198
198
|
assertNoControlMeta(arg);
|
|
199
199
|
assertNoSessionFlag(arg);
|
|
200
|
-
if (arg === "--browser=chrome"
|
|
200
|
+
if (arg === "--browser=chrome") {
|
|
201
201
|
flags.add(arg);
|
|
202
202
|
normalized.push(arg);
|
|
203
203
|
continue;
|
|
204
204
|
}
|
|
205
|
-
//
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
if (!normalized.includes("--headless"))
|
|
209
|
-
normalized.push("--headless");
|
|
205
|
+
// playwright-cli defaults to headless and does not accept --headless/--headed.
|
|
206
|
+
// Strip legacy flags so model/docs remnants never reach the binary.
|
|
207
|
+
if (arg === "--headless" || arg === "--headed") {
|
|
210
208
|
continue;
|
|
211
209
|
}
|
|
212
210
|
if (arg.startsWith("--browser=") ||
|
|
213
211
|
arg === "--browser") {
|
|
214
|
-
throw new PlaywrightCliPolicyError("open-browser-flags", "open must use --browser=chrome --headless
|
|
212
|
+
throw new PlaywrightCliPolicyError("open-browser-flags", "open must use --browser=chrome only (default headless; do not pass --headless/--headed)");
|
|
215
213
|
}
|
|
216
214
|
if (/^[a-z][a-z0-9+.-]*:/i.test(arg) || arg.startsWith("http")) {
|
|
217
215
|
url = arg;
|
|
@@ -219,12 +217,9 @@ function validateOpenArgs(args, baseUrl) {
|
|
|
219
217
|
}
|
|
220
218
|
throw new PlaywrightCliPolicyError("open-args", `unsupported open argument: ${arg}`);
|
|
221
219
|
}
|
|
222
|
-
if (!flags.has("--browser=chrome")
|
|
223
|
-
// controller injects required
|
|
224
|
-
|
|
225
|
-
normalized.unshift("--browser=chrome");
|
|
226
|
-
if (!flags.has("--headless"))
|
|
227
|
-
normalized.push("--headless");
|
|
220
|
+
if (!flags.has("--browser=chrome")) {
|
|
221
|
+
// controller injects required browser flag when missing from model args
|
|
222
|
+
normalized.unshift("--browser=chrome");
|
|
228
223
|
}
|
|
229
224
|
if (!url) {
|
|
230
225
|
throw new PlaywrightCliPolicyError("open-url-required", "open requires an absolute http(s) URL");
|
|
@@ -515,7 +510,7 @@ export function preparePlaywrightCliArgv(input, ctx) {
|
|
|
515
510
|
catch {
|
|
516
511
|
throw new PlaywrightCliPolicyError("goto-url-invalid", "goto requires a URL relative to the controller baseUrl");
|
|
517
512
|
}
|
|
518
|
-
const openLike = validateOpenArgs(["--browser=chrome",
|
|
513
|
+
const openLike = validateOpenArgs(["--browser=chrome", target], ctx.baseUrl);
|
|
519
514
|
return openLike[openLike.length - 1];
|
|
520
515
|
});
|
|
521
516
|
if (args.length !== 1) {
|
|
@@ -2,6 +2,7 @@ import { appendFile, mkdir } from "node:fs/promises";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { BoundedTextPreview, classifyPiFailure, createPiJsonlStreamCollector, DEFAULT_ABORT_GRACE_MS, DEFAULT_STALL_TIMEOUT_MS, DEFAULT_TIMEOUT_MS, extractAssistantTextFromPiJson, } from "./pi-executor.js";
|
|
4
4
|
import { serializeSessionEvent } from "./pi-event-serializer.js";
|
|
5
|
+
import { PI_RECOMMENDED_COMPACTION, PI_RECOMMENDED_RETRY, } from "../shared/pi-retry-settings.js";
|
|
5
6
|
let sdkSessionFactoryOverride;
|
|
6
7
|
let sdkImportOverrideForTests;
|
|
7
8
|
let sdkModuleOverrideForTests;
|
|
@@ -154,6 +155,7 @@ async function createSdkSession(sdk, input, shared) {
|
|
|
154
155
|
const createAgentSession = sdk.createAgentSession;
|
|
155
156
|
const SessionManager = sdk.SessionManager;
|
|
156
157
|
const DefaultResourceLoader = sdk.DefaultResourceLoader;
|
|
158
|
+
const SettingsManager = sdk.SettingsManager;
|
|
157
159
|
const getAgentDir = sdk.getAgentDir;
|
|
158
160
|
const ModelRuntime = sdk.ModelRuntime;
|
|
159
161
|
const agentDir = shared?.agentDir ?? getAgentDir();
|
|
@@ -168,12 +170,25 @@ async function createSdkSession(sdk, input, shared) {
|
|
|
168
170
|
const model = input.provider && input.model
|
|
169
171
|
? await resolveModel(modelRuntime, input.provider, input.model)
|
|
170
172
|
: undefined;
|
|
173
|
+
// Inject rate-limit-tolerant auto-retry settings for the session lifecycle.
|
|
174
|
+
// Prefer SettingsManager.inMemory so harness runs do not depend on ~/.pi or
|
|
175
|
+
// project .pi/settings.json being present/trusted.
|
|
176
|
+
const settingsManager = typeof SettingsManager?.inMemory === "function"
|
|
177
|
+
? SettingsManager.inMemory({
|
|
178
|
+
retry: {
|
|
179
|
+
...PI_RECOMMENDED_RETRY,
|
|
180
|
+
provider: { ...PI_RECOMMENDED_RETRY.provider },
|
|
181
|
+
},
|
|
182
|
+
compaction: { ...PI_RECOMMENDED_COMPACTION },
|
|
183
|
+
}, { projectTrusted: true })
|
|
184
|
+
: undefined;
|
|
171
185
|
const loader = new DefaultResourceLoader({
|
|
172
186
|
cwd: input.cwd,
|
|
173
187
|
agentDir,
|
|
174
188
|
noContextFiles: true,
|
|
175
189
|
noSkills: true,
|
|
176
190
|
noExtensions: true,
|
|
191
|
+
...(settingsManager ? { settingsManager } : {}),
|
|
177
192
|
appendSystemPromptOverride: (base) => [
|
|
178
193
|
...base,
|
|
179
194
|
input.appendSystemPrompt,
|
|
@@ -191,6 +206,7 @@ async function createSdkSession(sdk, input, shared) {
|
|
|
191
206
|
resourceLoader: loader,
|
|
192
207
|
tools: input.toolNames,
|
|
193
208
|
modelRuntime,
|
|
209
|
+
...(settingsManager ? { settingsManager } : {}),
|
|
194
210
|
...(model ? { model } : {}),
|
|
195
211
|
...(input.thinking ? { thinkingLevel: input.thinking } : {}),
|
|
196
212
|
...(Array.isArray(input.customTools) && input.customTools.length > 0
|
|
@@ -776,7 +776,7 @@ export function buildOperatorCapabilitiesDocument() {
|
|
|
776
776
|
resultSchemaVersion: 1,
|
|
777
777
|
envelopeSchemaVersion: 1,
|
|
778
778
|
requiredErrorCodes: ["NOT_FOUND", "INVALID_INPUT"],
|
|
779
|
-
description: "DAG run handoff report by run id.",
|
|
779
|
+
description: "DAG run handoff report by run id. On failure, read primaryFailure.nodeId + primaryRecovery first; prefer dagRerunPlan from that node before standaloneTaskRerun or a new task.",
|
|
780
780
|
inputParams: [
|
|
781
781
|
{
|
|
782
782
|
name: "runId",
|
|
@@ -919,19 +919,19 @@ export function buildOperatorCapabilitiesDocument() {
|
|
|
919
919
|
resultSchemaVersion: 1,
|
|
920
920
|
envelopeSchemaVersion: 1,
|
|
921
921
|
requiredErrorCodes: ["INVALID_INPUT", "NOT_FOUND"],
|
|
922
|
-
description: "Read-only subgraph
|
|
922
|
+
description: "Read-only R1 subgraph plan (no mutation). Call before dagRerun. Prefer primaryFailure.nodeId from dagReport. If eligible=false (writer/decision/fingerprint), do not force execute — fall back to standaloneTaskRerun or same-task advance. Returns planHash required by execute.",
|
|
923
923
|
inputParams: [
|
|
924
924
|
{
|
|
925
925
|
name: "runId",
|
|
926
926
|
type: "string",
|
|
927
927
|
required: true,
|
|
928
|
-
description: "dag run id",
|
|
928
|
+
description: "completed failed|partial_failed parent dag run id",
|
|
929
929
|
},
|
|
930
930
|
{
|
|
931
931
|
name: "fromNode",
|
|
932
932
|
type: "string",
|
|
933
933
|
required: true,
|
|
934
|
-
description: "node id to rerun from",
|
|
934
|
+
description: "node id to rerun from (prefer failed/attention node from dagReport primaryFailure.nodeId)",
|
|
935
935
|
},
|
|
936
936
|
],
|
|
937
937
|
modelCallable: "always",
|
|
@@ -949,31 +949,31 @@ export function buildOperatorCapabilitiesDocument() {
|
|
|
949
949
|
"BINDING_DRIFT",
|
|
950
950
|
"INVALID_INPUT",
|
|
951
951
|
],
|
|
952
|
-
description: "Execute continuation
|
|
952
|
+
description: "Execute R1 continuation from effective node. Requires planHash from a fresh dagRerunPlan (eligible=true). Prefer this over new task / standaloneTaskRerun for provider flake and safe downstream failures. Human Gate required.",
|
|
953
953
|
inputParams: [
|
|
954
954
|
{
|
|
955
955
|
name: "runId",
|
|
956
956
|
type: "string",
|
|
957
957
|
required: true,
|
|
958
|
-
description: "dag run id",
|
|
958
|
+
description: "parent dag run id (same as dagRerunPlan)",
|
|
959
959
|
},
|
|
960
960
|
{
|
|
961
961
|
name: "fromNode",
|
|
962
962
|
type: "string",
|
|
963
963
|
required: true,
|
|
964
|
-
description: "node id
|
|
964
|
+
description: "node id matching the planned dagRerunPlan",
|
|
965
965
|
},
|
|
966
966
|
{
|
|
967
967
|
name: "planHash",
|
|
968
968
|
type: "string",
|
|
969
969
|
required: true,
|
|
970
|
-
description: "
|
|
970
|
+
description: "sha256 plan hash from dagRerunPlan (must match exactly)",
|
|
971
971
|
},
|
|
972
972
|
{
|
|
973
973
|
name: "reason",
|
|
974
974
|
type: "string",
|
|
975
975
|
required: true,
|
|
976
|
-
description: "
|
|
976
|
+
description: "why continue from this node (e.g. provider flake; resume from review-pi)",
|
|
977
977
|
},
|
|
978
978
|
],
|
|
979
979
|
modelCallable: "prepare-only",
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Recommended Pi auto-retry settings for gateway rate limits.
|
|
3
|
+
*
|
|
4
|
+
* Work-hours gateways often enforce rolling windows (e.g. 100 req / 10 min).
|
|
5
|
+
* Pi's built-in default (2s / 4s / 8s) exhausts before the window recovers;
|
|
6
|
+
* a 60s base delay yields 1m → 2m → 4m … and tolerates transient 429s.
|
|
7
|
+
*
|
|
8
|
+
* Used by:
|
|
9
|
+
* - project / user `.pi` settings merge (`client-recovery`)
|
|
10
|
+
* - loop-agent Pi SDK executor (injected SettingsManager, independent of ~/.pi)
|
|
11
|
+
*/
|
|
12
|
+
export const PI_RECOMMENDED_RETRY = {
|
|
13
|
+
enabled: true,
|
|
14
|
+
maxRetries: 5,
|
|
15
|
+
/** First retry wait; subsequent attempts use exponential backoff. */
|
|
16
|
+
baseDelayMs: 60_000,
|
|
17
|
+
provider: {
|
|
18
|
+
/** Disable nested SDK provider retries; outer auto-retry owns the budget. */
|
|
19
|
+
maxRetries: 0,
|
|
20
|
+
maxRetryDelayMs: 60_000,
|
|
21
|
+
},
|
|
22
|
+
};
|
|
23
|
+
export const PI_RECOMMENDED_COMPACTION = { enabled: true };
|