fix: 统一 AgentRun session hard-timeout

This commit is contained in:
Codex
2026-07-13 17:57:29 +02:00
parent a566bfb9cb
commit 38efb1605c
5 changed files with 31 additions and 6 deletions
+1 -1
View File
@@ -44,7 +44,7 @@ client:
executionPolicy:
sandbox: workspace-write
approval: never
timeoutMs: 900000
timeoutMs: 7200000
network: enabled
secretScope:
allowCredentialEcho: false
+11 -1
View File
@@ -162,7 +162,17 @@ AgentRun Kafka closeout 需要同时验证 manager 和 runner 两条生产链路
- 终态命令仍被历史 claim、heartbeat、Pod 或 `runner-dispatch-retry` 保护时,修正 retention 分类;
- 禁止强杀 Job/Pod 或手工补 CI/CD。
AgentRun resource/session client policy 也由 `config/agentrun.yaml` 声明。`client.sessionPolicy` 是未显式选择 node/lane 时 `agentrun send session/...` 和相关 session payload 生成的默认 `tenantId``projectId``providerId``backendProfile``workspaceRef` 和 execution policy 来源;显式 `--node <node> --lane <lane>` 后,`explain session-policy``send session`、resource primitives 和 AipodSpec render 都必须改用目标 lane 的 YAML 事实。lane `secrets[].providerCredential.profile` 声明 provider credential Secret 归属,UniDesk CLI 只按 YAML 聚合 Secret name/key,不再用代码拼接 provider Secret 名称。只读入口 `bun scripts/cli.ts agentrun explain session-policy` 用于查看选中目标 lane、policy 来源、实际 executionPolicy payload 和 provider credential binding 来源;输出只能包含 Secret metadata、key 名和 `valuesPrinted=false`,不得打印 Secret value。
- AgentRun resource/session client policy
-`config/agentrun.yaml` 声明;
- `client.sessionPolicy` 是未显式选择 node/lane 时 `agentrun send session/...` 和相关 session payload 生成的默认 `tenantId``projectId``providerId``backendProfile``workspaceRef` 和 execution policy 来源;
- `client.sessionPolicy.executionPolicy.timeoutMs` 是 session follow-up hard-timeout 的唯一事实来源;
- Artificer task 与 session follow-up 统一使用 2 小时 hard-timeout
- 低于 1 小时的 hard-timeout 配置非法,必须在配置解析阶段明确拒绝;
- 显式 `--node <node> --lane <lane>` 后,`explain session-policy``send session`、resource primitives 和 AipodSpec render 都必须改用目标 lane 的 YAML 事实;
- lane `secrets[].providerCredential.profile` 声明 provider credential Secret 归属;
- UniDesk CLI 只按 YAML 聚合 Secret name/key,不再用代码拼接 provider Secret 名称;
- 只读入口 `bun scripts/cli.ts agentrun explain session-policy` 用于查看选中目标 lane、policy 来源、实际 executionPolicy payload 和 provider credential binding 来源;
- 输出只能包含 Secret metadata、key 名和 `valuesPrinted=false`,不得打印 Secret value。
非默认 lane 的 session follow-up 必须证明 `send session` 使用的是选中 node/lane 的 run policy。使用短命令形态前,先用 `agentrun explain session-policy --node <node> --lane <lane> [--backend-profile <profile>]` 或等价 dry-run/describe 路径确认 `backendProfile``providerId``workspaceRef`、execution policy 和 provider credential SecretRef 都来自目标 lane`--prompt-stdin` 短命令形态和 `--json-stdin -o json` 显式 JSON 形态应披露同一份 `sessionPolicy` 摘要。渲染结果回退到全局默认 lane、显示错误的 default lane,或短命令与 JSON body 使用不同 policy,都是 lane policy 缺陷,应修复 YAML 目标解析或 CLI 渲染;不得通过手工创建默认 lane Secret、复制凭据、改写 JSON body 或修改 runtime namespace 来掩盖 policy 选错的问题。
+1 -1
View File
@@ -42,7 +42,7 @@ const agentRunClientYaml = [
" executionPolicy:",
" sandbox: workspace-write",
" approval: never",
" timeoutMs: 900000",
" timeoutMs: 7200000",
" network: enabled",
" secretScope:",
" allowCredentialEcho: false",
+14 -2
View File
@@ -76,7 +76,7 @@ const agentRunClientYaml = [
" executionPolicy:",
" sandbox: workspace-write",
" approval: never",
" timeoutMs: 900000",
" timeoutMs: 7200000",
" network: enabled",
" secretScope:",
" allowCredentialEcho: false",
@@ -108,7 +108,7 @@ const agentRunMinimalClientYaml = [
" executionPolicy:",
" sandbox: workspace-write",
" approval: never",
" timeoutMs: 900000",
" timeoutMs: 7200000",
" network: enabled",
" secretScope:",
" allowCredentialEcho: false",
@@ -166,6 +166,18 @@ describe("AgentRun render-only REST client config", () => {
expect(config.client.transport).toBe("direct-http");
});
test("uses the owning YAML two-hour session hard-timeout", () => {
const config = parseAgentRunClientConfigYaml(readFileSync("config/agentrun.yaml", "utf8"), "config/agentrun.yaml");
expect(config.client.sessionPolicy.executionPolicy.timeoutMs).toBe(7_200_000);
});
test("rejects a session hard-timeout below one hour", () => {
const invalid = agentRunClientYaml.replace(" timeoutMs: 7200000", " timeoutMs: 3599999");
expect(() => parseAgentRunClientConfigYaml(invalid, "config/agentrun.yaml")).toThrow(
"client.sessionPolicy.executionPolicy.timeoutMs hard-timeout must be at least 3600000 ms",
);
});
test("uses env auth before configured file auth without exposing the key", () => {
const config = parseAgentRunClientConfigYaml(agentRunClientYaml, "config/agentrun.yaml");
const auth = resolveAgentRunAuth(config, { HWLAB_API_KEY: "secret-value" });
+4 -1
View File
@@ -124,7 +124,10 @@ export function readAgentRunSessionPolicyConfig(client: Record<string, unknown>,
stringFieldFromRecord(workspaceRef, "kind", `${pathValue}.workspaceRef`);
stringFieldFromRecord(executionPolicy, "sandbox", `${pathValue}.executionPolicy`);
stringFieldFromRecord(executionPolicy, "approval", `${pathValue}.executionPolicy`);
positiveIntegerFieldFromRecord(executionPolicy, "timeoutMs", `${pathValue}.executionPolicy`);
const timeoutMs = positiveIntegerFieldFromRecord(executionPolicy, "timeoutMs", `${pathValue}.executionPolicy`);
if (timeoutMs < 3_600_000) {
throw new Error(`${sourcePath}: ${pathValue}.executionPolicy.timeoutMs hard-timeout must be at least 3600000 ms`);
}
stringFieldFromRecord(executionPolicy, "network", `${pathValue}.executionPolicy`);
booleanFieldFromRecord(secretScope, "allowCredentialEcho", `${pathValue}.executionPolicy.secretScope`);
return {