feat(tasks): enforce dynamic execution plans

This commit is contained in:
2026-09-24 16:36:12 +08:00
parent 485ceff7e3
commit e0d37f9da9
13 changed files with 1942 additions and 17 deletions
+2 -2
View File
@@ -96,7 +96,7 @@ describe("OpenCode internal bridge tools", () => {
"-e",
[
'import tool from "./.opencode/tools/publish_execution_plan.ts";',
'const result = await tool.execute({ request_id: "60000000-0000-4000-8000-000000000001", title: "调查", reason: "开始", nodes: [{ id: "read", title: "读取", status: "completed", owner: "agent", detail: "完成", evidence: ["evidence-1"], action_refs: [] }], edges: [] }, { sessionID: "runtime-session-1" });',
'const result = await tool.execute({ request_id: "60000000-0000-4000-8000-000000000001", schema: "execution-plan@2", title: "调查", reason: "开始", nodes: [{ id: "read", title: "读取", status: "completed", owner: "agent", detail: "完成", evidence: ["evidence-1"], action_refs: [], kind: "activity" }], edges: [] }, { sessionID: "runtime-session-1" });',
"process.stdout.write(result);",
].join("\n"),
], {
@@ -141,7 +141,7 @@ describe("OpenCode internal bridge tools", () => {
"-e",
[
'import tool from "./.opencode/tools/publish_execution_plan.ts";',
'await tool.execute({ request_id: "60000000-0000-4000-8000-000000000001", title: "调查", reason: "开始", nodes: [{ id: "read", title: "读取", status: "completed", owner: "agent", detail: "完成", evidence: ["evidence-1"], action_refs: [] }], edges: [] }, { sessionID: "runtime-session-1" });',
'await tool.execute({ request_id: "60000000-0000-4000-8000-000000000001", schema: "execution-plan@2", title: "调查", reason: "开始", nodes: [{ id: "read", title: "读取", status: "completed", owner: "agent", detail: "完成", evidence: ["evidence-1"], action_refs: [], kind: "activity" }], edges: [] }, { sessionID: "runtime-session-1" });',
].join("\n"),
], {
cwd: process.cwd(),
+2 -1
View File
@@ -32,7 +32,8 @@ describe("agent event trigger", () => {
expect(prompt).toContain("水质监测点");
expect(prompt).toContain("二次供水");
expect(prompt).toContain("合成演练数据");
expect(prompt).toContain("疑似二次供水环节问题(待现场核验)");
expect(prompt).toContain("动态规划本次调查");
expect(prompt).not.toContain("请按‘上游数据质量正常");
expect(prompt).toContain(trigger.trigger_id);
});
+33 -1
View File
@@ -1,5 +1,5 @@
import { describe, expect, it } from "bun:test";
import { createExecutionPlanSnapshot, executionPlanNeedsTaskPublish, executionPlanSchema, readExecutionPlans } from "../../src/routes/executionPlan.js";
import { createExecutionPlanSnapshot, executionPlanNeedsTaskPublish, executionPlanSchema, newExecutionPlanSchema, readExecutionPlans } from "../../src/routes/executionPlan.js";
import { streamPromptResponse } from "../../src/routes/chatStream.js";
import type { OpencodeRuntimeAdapter } from "../../src/runtime/opencode.js";
@@ -13,6 +13,38 @@ const plan = {
};
describe("execution plans", () => {
it("requires v2 for newly published task plans while retaining legacy reads", () => {
const legacy = {
title: "Legacy plan",
reason: "Stored before graph plans",
nodes: [{ id: "inspect", title: "Inspect", status: "pending", owner: "agent", detail: "", evidence: [] }],
edges: [],
};
expect(executionPlanSchema.parse(legacy).schema).toBe("execution-plan@1");
expect(newExecutionPlanSchema.safeParse(legacy).success).toBe(false);
});
it("accepts explicit v2 branches and structural joins without invented evidence", () => {
const v2 = {
schema: "execution-plan@2", title: "动态调查", reason: "工单请求现场及数据并行核验",
nodes: [
{ id: "split", title: "并行启动", status: "completed", owner: "agent", detail: "同时核查", evidence: [], kind: "parallel_split" },
{ id: "field", title: "现场采样", status: "waiting", owner: "human", detail: "等待采样", evidence: [], kind: "activity" },
{ id: "data", title: "监测数据", status: "completed", owner: "agent", detail: "已核对", evidence: ["e-1"], kind: "activity" },
{ id: "join", title: "证据汇合", status: "waiting", owner: "agent", detail: "等待现场", evidence: [], kind: "parallel_join" },
],
edges: [
{ id: "field-route", from: "split", to: "field", label: "现场" },
{ id: "data-route", from: "split", to: "data", label: "数据" },
{ id: "field-join", from: "field", to: "join", label: "" },
{ id: "data-join", from: "data", to: "join", label: "" },
],
};
const parsed = executionPlanSchema.parse(v2);
expect(createExecutionPlanSnapshot(parsed, [], "session-1").schema_version).toBe("execution-plan@2");
expect(executionPlanSchema.safeParse({ ...v2, edges: [{ ...v2.edges[0], id: "data-route" }, ...v2.edges.slice(1)] }).success).toBe(false);
});
it("rejects missing dependencies, cycles, duplicate IDs and unsupported completion", () => {
for (const invalid of [
{ ...plan, edges: [{ from: "unknown", to: "sample", label: "" }] },