fix(iteration): align reference miniapp tool names

This commit is contained in:
2026-08-06 00:50:21 +08:00
parent 309dd6161d
commit 6fa350267a
9 changed files with 39 additions and 35 deletions
@@ -22,7 +22,7 @@ export class TaskDashboardMiniApp {
private async handleTool(call: { call_id: string; tool_id: string; input: JsonObject }): Promise<void> {
await this.sdk.tools.reportProgress(call.call_id, { status: "running", percent: 10, detail: call.tool_id });
if (call.tool_id === "task.create") {
if (call.tool_id === "task-dashboard.open") {
const title = typeof call.input.title === "string" ? call.input.title : "未命名任务";
const taskID = typeof call.input.task_id === "string" ? call.input.task_id : `task-${call.call_id}`;
this.createTask(taskID, { title, status: "open" });
@@ -30,8 +30,12 @@ export class TaskDashboardMiniApp {
await this.sdk.tools.complete(call.call_id, { task_id: taskID });
return;
}
if (call.tool_id === "task.list") {
await this.sdk.tools.complete(call.call_id, { tasks: [...this.tasks.entries()].map(([task_id, task]) => ({ task_id, ...task })) });
if (call.tool_id === "task-dashboard.update") {
const taskID = typeof call.input.task_id === "string" ? call.input.task_id : `task-${call.call_id}`;
const previous = this.tasks.get(taskID) ?? {};
const next = { ...previous, ...(typeof call.input.status === "string" ? { status: call.input.status } : {}), ...(typeof call.input.progress === "number" ? { progress: call.input.progress } : {}) };
this.tasks.set(taskID, next);
await this.sdk.tools.complete(call.call_id, { task_id: taskID, task: next });
return;
}
await this.sdk.tools.fail(call.call_id, { code: "tool_not_supported", message: `不支持的任务工具:${call.tool_id}` });
@@ -45,7 +49,7 @@ export class TaskDashboardMiniApp {
public async completeTask(callID: string, taskID: string): Promise<void> {
const task = this.tasks.get(taskID) ?? {};
await this.sdk.tools.reportProgress(callID, { status: "completed", percent: 100 });
await this.sdk.tools.complete(callID, { task_id: taskID, task });
await this.sdk.tools.complete(callID, { status: "completed", task_id: taskID, task });
}
public stop(): void {
@@ -24,7 +24,7 @@ export class WhiteboardMiniApp {
await this.sdk.tools.complete(call.call_id, { status: "completed" });
return;
}
if (call.tool_id === "whiteboard.export") {
if (call.tool_id === "whiteboard.submit") {
const artifactID = typeof call.input.artifact_id === "string" ? call.input.artifact_id : `whiteboard-${call.call_id}`;
await this.sdk.tools.reportProgress(call.call_id, { status: "exporting", percent: 80 });
await this.sdk.surfaces.request("patch", { state: this.state, artifact: { artifact_id: artifactID } });
@@ -10,20 +10,20 @@ export const TASK_DASHBOARD_MANIFEST: MiniAppManifestV1 = {
host: { min_version: "1.0.0", surface_required: true },
tools: [
{
id: "task.create",
id: "task-dashboard.open",
version: 1,
handling: "operation",
handling: "launch",
target: { app_scope: "task-dashboard", requires_foreground: true, restore_previous_focus: true },
input_schema: { type: "object", required: ["title"], properties: { title: { type: "string", minLength: 1, maxLength: 200 } }, additionalProperties: false },
output_schema: { type: "object", required: ["task_id"], properties: { task_id: { type: "string", minLength: 1 } }, additionalProperties: false },
input_schema: { type: "object", required: ["title"], properties: { task_id: { type: "string", minLength: 1 }, title: { type: "string", minLength: 1, maxLength: 200 }, initial_state: { type: "object" } }, additionalProperties: false },
output_schema: { type: "object", required: ["status", "task_id"], properties: { status: { type: "string", enum: ["completed", "cancelled", "failed"] }, task_id: { type: "string", minLength: 1 }, task: { type: "object" } }, additionalProperties: false },
},
{
id: "task.list",
id: "task-dashboard.update",
version: 1,
handling: "direct",
target: { app_scope: "task-dashboard", requires_foreground: false, restore_previous_focus: false },
input_schema: { type: "object", additionalProperties: false },
output_schema: { type: "object" },
input_schema: { type: "object", required: ["task_id"], properties: { task_id: { type: "string", minLength: 1 }, progress: { type: "number", minimum: 0, maximum: 100 }, status: { type: "string" } }, additionalProperties: false },
output_schema: { type: "object", required: ["task_id"], properties: { task_id: { type: "string", minLength: 1 }, task: { type: "object" } }, additionalProperties: false },
},
],
};
@@ -41,16 +41,16 @@ export const WHITEBOARD_MANIFEST: MiniAppManifestV1 = {
version: 1,
handling: "launch",
target: { app_scope: "whiteboard", requires_foreground: true, restore_previous_focus: true },
input_schema: { type: "object", additionalProperties: false },
input_schema: { type: "object", required: ["board_id", "title"], properties: { board_id: { type: "string", minLength: 1 }, title: { type: "string", minLength: 1 }, initial_state: { type: "object" } }, additionalProperties: false },
output_schema: { type: "object" },
},
{
id: "whiteboard.export",
id: "whiteboard.submit",
version: 1,
handling: "operation",
target: { app_scope: "whiteboard", requires_foreground: true, restore_previous_focus: true },
input_schema: { type: "object", additionalProperties: false },
output_schema: { type: "object", required: ["artifact_id"], properties: { artifact_id: { type: "string", minLength: 1 } }, additionalProperties: false },
input_schema: { type: "object", required: ["board_id"], properties: { board_id: { type: "string", minLength: 1 }, submit_request: { type: "object" } }, additionalProperties: false },
output_schema: { type: "object", properties: { artifact_id: { type: "string", minLength: 1 }, summary: { type: "object" } }, additionalProperties: false },
},
],
};
@@ -271,7 +271,7 @@ describe("LineUpRuntime", () => {
const call = JSON.stringify({
v: 1, id: "task-tool-call", type: "lineup.v1.miniapp.tool.call", conversation_id: conversationID,
sender: { kind: "agent", id: "agent_1" },
payload: { call_id: "task-tool-call", tool_id: "task.create", app_scope: "task-dashboard", inventory_revision: "catalog-1", input: { title: "写验收记录" } },
payload: { call_id: "task-tool-call", tool_id: "task-dashboard.open", app_scope: "task-dashboard", inventory_revision: "catalog-1", input: { title: "写验收记录" } },
});
const transport = new FakeTransport([[{ message_seq: 60, from_uid: "agent_1", payload: call }], []]);
const runtime = new LineUpRuntime({ storage: new MemoryStorage(), createTransport: () => transport, now: () => "2026-08-04T00:00:00.000Z", newID: prefix => `${prefix}-id` });
@@ -285,7 +285,7 @@ describe("LineUpRuntime", () => {
sdk.tools.subscribe(tool => received.push(tool.call_id));
expect(received).toEqual(["task-tool-call"]);
expect(runtime.miniAppToolCalls()).toEqual([expect.objectContaining({ call_id: "task-tool-call", status: "running", instance_id: instance!.instance_id })]);
await sdk.tools.complete("task-tool-call", { task_id: "task-1" });
await sdk.tools.complete("task-tool-call", { status: "completed", task_id: "task-1" });
await runtime.flushOutbox();
expect(runtime.miniAppToolCalls()).toEqual([expect.objectContaining({ call_id: "task-tool-call", status: "completed" })]);
expect(runtime.lifecycle.instances.get(instance!.instance_id)).toMatchObject({ state: "foreground" });
@@ -337,7 +337,7 @@ describe("LineUpRuntime", () => {
const launch = JSON.stringify({
v: 1, id: "whiteboard-launch", type: "lineup.v1.miniapp.tool.call", conversation_id: conversationID,
sender: { kind: "agent", id: "agent_1" },
payload: { call_id: "whiteboard-launch", tool_id: "whiteboard.open", app_scope: "whiteboard", inventory_revision: "catalog-1", input: {} },
payload: { call_id: "whiteboard-launch", tool_id: "whiteboard.open", app_scope: "whiteboard", inventory_revision: "catalog-1", input: { board_id: "board-1", title: "验收画板" } },
});
const transport = new FakeTransport([[{ message_seq: 62, from_uid: "agent_1", payload: launch }], []]);
const runtime = new LineUpRuntime({ storage: new MemoryStorage(), createTransport: () => transport });
@@ -359,7 +359,7 @@ describe("LineUpRuntime", () => {
it("converges an unclaimed bundled Tool once on App close and keeps no new delivery path", async () => {
const conversationID = "user_1:2:channel_1";
const call = JSON.stringify({ v: 1, id: "task-tool-close", type: "lineup.v1.miniapp.tool.call", conversation_id: conversationID, sender: { kind: "agent", id: "agent_1" }, payload: { call_id: "task-tool-close", tool_id: "task.create", app_scope: "task-dashboard", inventory_revision: "catalog-1", input: { title: "关闭测试" } } });
const call = JSON.stringify({ v: 1, id: "task-tool-close", type: "lineup.v1.miniapp.tool.call", conversation_id: conversationID, sender: { kind: "agent", id: "agent_1" }, payload: { call_id: "task-tool-close", tool_id: "task-dashboard.open", app_scope: "task-dashboard", inventory_revision: "catalog-1", input: { title: "关闭测试" } } });
const transport = new FakeTransport([[{ message_seq: 61, from_uid: "agent_1", payload: call }], []]);
const runtime = new LineUpRuntime({ storage: new MemoryStorage(), createTransport: () => transport, now: () => "2026-08-04T00:00:00.000Z" });
await runtime.login(login);
@@ -393,7 +393,7 @@ describe("LineUpRuntime", () => {
const call = JSON.stringify({
v: 1, id: "restart-tool-call", type: "lineup.v1.miniapp.tool.call", conversation_id: conversationID,
sender: { kind: "agent", id: "agent_1" },
payload: { call_id: "restart-tool-call", tool_id: "task.create", app_scope: "task-dashboard", inventory_revision: "catalog-1", input: { title: "重启恢复" } },
payload: { call_id: "restart-tool-call", tool_id: "task-dashboard.open", app_scope: "task-dashboard", inventory_revision: "catalog-1", input: { title: "重启恢复" } },
});
const storage = new MemoryStorage();
const firstTransport = new FakeTransport([[{ message_seq: 70, from_uid: "agent_1", payload: call }], []]);
@@ -404,7 +404,7 @@ describe("LineUpRuntime", () => {
const instance = first.lifecycle.instances.activeFor("task-dashboard", conversationID)!;
const sdk = first.openBundledMiniApp("task-dashboard", instance.instance_id);
sdk.tools.subscribe(() => undefined);
await sdk.tools.complete("restart-tool-call", { task_id: "restart-task" });
await sdk.tools.complete("restart-tool-call", { status: "completed", task_id: "restart-task" });
expect(first.miniAppToolCalls()).toEqual([expect.objectContaining({ call_id: "restart-tool-call", status: "submitted" })]);
const secondTransport = new FakeTransport();
@@ -4,7 +4,7 @@ import { MiniAppToolStateMachine } from "@/runtime/coordination/miniapp-tool-sta
describe("MiniAppToolStateMachine", () => {
it("moves a call through claim and submitted result, while rejecting duplicate terminal writes", () => {
const machine = new MiniAppToolStateMachine();
machine.receive({ call_id: "call-1", tool_id: "task.create", inventory_revision: "catalog-1", app_scope: "task-dashboard", instance_id: "task:1", conversation_id: "c", input: {}, created_at: "2026-08-04T00:00:00.000Z" });
machine.receive({ call_id: "call-1", tool_id: "task-dashboard.open", inventory_revision: "catalog-1", app_scope: "task-dashboard", instance_id: "task:1", conversation_id: "c", input: {}, created_at: "2026-08-04T00:00:00.000Z" });
expect(machine.route("call-1", "task:1", "2026-08-04T00:00:01.000Z")).toMatchObject({ disposition: "accepted", record: { status: "waiting_for_app" } });
expect(machine.start("call-1", "task:1", "2026-08-04T00:00:02.000Z")).toMatchObject({ disposition: "accepted", record: { status: "running" } });
expect(machine.submit("call-1", "task:1", { task_id: "t1" }, "2026-08-04T00:00:03.000Z")).toMatchObject({ disposition: "accepted", record: { status: "submitted" } });
@@ -14,7 +14,7 @@ describe("MiniAppToolStateMachine", () => {
it("cancels only the instance that owns a pending call", () => {
const machine = new MiniAppToolStateMachine();
machine.receive({ call_id: "call-2", tool_id: "task.create", inventory_revision: "catalog-1", app_scope: "task-dashboard", instance_id: "task:1", conversation_id: "c", input: {}, created_at: "2026-08-04T00:00:00.000Z" });
machine.receive({ call_id: "call-2", tool_id: "task-dashboard.open", inventory_revision: "catalog-1", app_scope: "task-dashboard", instance_id: "task:1", conversation_id: "c", input: {}, created_at: "2026-08-04T00:00:00.000Z" });
machine.route("call-2", "task:1", "2026-08-04T00:00:01.000Z");
expect(machine.cancel("call-2", "task:2", "app_closed", "2026-08-04T00:00:02.000Z")).toEqual(expect.objectContaining({ disposition: "invalid_scope" }));
expect(machine.cancel("call-2", "task:1", "app_closed", "2026-08-04T00:00:02.000Z")).toMatchObject({ disposition: "accepted", record: { status: "cancelled", cancel_reason: "app_closed" } });
@@ -26,10 +26,10 @@ describe("ToolRouter", () => {
const apps = new CoreAppRegistry();
apps.install({
app_scope: "custom-dashboard", kind: "bundled", enabled: true, default_eligible: false, recovery: false,
manifest: { app_scope: "custom-dashboard", version: "1.0.0", permissions: [], tools: [{ name: "task.create", handling: "operation", parameters: [], input_schema: { type: "object", required: ["title"], properties: { title: { type: "string" } }, additionalProperties: false } }] },
manifest: { app_scope: "custom-dashboard", version: "1.0.0", permissions: [], tools: [{ name: "task-dashboard.open", handling: "operation", parameters: [], input_schema: { type: "object", required: ["title"], properties: { title: { type: "string" } }, additionalProperties: false } }] },
});
const router = new ToolRouter(apps);
const raw = JSON.stringify({ v: 1, id: "miniapp-call-1", type: "lineup.v1.miniapp.tool.call", conversation_id: "c1", sender: { kind: "agent", id: "agent" }, payload: { call_id: "miniapp-call-1", tool_id: "task.create", app_scope: "custom-dashboard", inventory_revision: "catalog-1", input: { title: "测试任务" } } });
const raw = JSON.stringify({ v: 1, id: "miniapp-call-1", type: "lineup.v1.miniapp.tool.call", conversation_id: "c1", sender: { kind: "agent", id: "agent" }, payload: { call_id: "miniapp-call-1", tool_id: "task-dashboard.open", app_scope: "custom-dashboard", inventory_revision: "catalog-1", input: { title: "测试任务" } } });
expect(router.route(raw, { app_scope: "chat", conversation_id: "c1", inventory_revision: "catalog-1" })).toEqual(expect.objectContaining({ disposition: "miniapp", handling: "operation", app_scope: "custom-dashboard" }));
expect(router.route(raw.replace("catalog-1", "catalog-2"), { app_scope: "chat", conversation_id: "c1", inventory_revision: "catalog-1" })).toEqual({ disposition: "rejected", code: "inventory_revision_mismatch" });
expect(router.route(raw.replace('"title":"测试任务"', '"unknown":true'), { app_scope: "chat", conversation_id: "c1", inventory_revision: "catalog-1" })).toEqual({ disposition: "rejected", code: "invalid_request" });
@@ -243,7 +243,7 @@ describe("ConversationStore", () => {
const storage = new MemoryStorage();
const conversationID = "user_test:2:agent_channel";
const record: MiniAppToolCallRecord = {
call_id: "miniapp_001", tool_id: "task.create", inventory_revision: "catalog-1", app_scope: "task-dashboard", instance_id: "task:instance", conversation_id: conversationID,
call_id: "miniapp_001", tool_id: "task-dashboard.open", inventory_revision: "catalog-1", app_scope: "task-dashboard", instance_id: "task:instance", conversation_id: conversationID,
status: "submitted", input: { title: "任务" }, result: { task_id: "task-1" }, created_at: "2026-08-04T00:00:00.000Z", updated_at: "2026-08-04T00:00:01.000Z", submitted_at: "2026-08-04T00:00:01.000Z",
};
const first = new ConversationStore(storage);
@@ -188,11 +188,11 @@ function bridgeScript(): string {
}
function taskDashboardSurfaceScript(): string {
return `const handled=new Set;const tasks=new Map;const editor=document.getElementById("editor");document.getElementById("cancel").onclick=()=>bridge("lifecycle.close",{reason:"用户关闭任务面板"});async function poll(){try{const result=await bridge("tools.list");for(const call of Array.isArray(result.calls)?result.calls:[]){if(handled.has(call.call_id)||!(call.status==="waiting_for_app"||call.status==="running"))continue;handled.add(call.call_id);await handleTask(call)}}catch(_){}}async function handleTask(call){try{await bridge("tools.reportProgress",{call_id:call.call_id,progress:{status:"running",percent:10}});if(call.tool_id==="task.create"){const title=typeof call.input?.title==="string"?call.input.title:"未命名任务";const task_id=typeof call.input?.task_id==="string"?call.input.task_id:"task-"+call.call_id;tasks.set(task_id,{title,status:"open"});await bridge("surface.patch",{data:{state:{title:"任务面板",status:"已创建:"+title,percent:100,steps:[...tasks.values()].map(x=>x.title)}}});await bridge("tools.complete",{call_id:call.call_id,result:{task_id}})}else if(call.tool_id==="task.list"){await bridge("tools.complete",{call_id:call.call_id,result:{tasks:[...tasks.entries()].map(([task_id,task])=>Object.assign({task_id},task))}})}else await bridge("tools.fail",{call_id:call.call_id,code:"tool_not_supported",message:"不支持的任务工具"})}catch(_){await bridge("tools.fail",{call_id:call.call_id,code:"app_bridge_failed",message:"任务面板处理失败"}).catch(()=>{})}}setInterval(poll,500);poll();`;
return `const handled=new Set;const tasks=new Map;const editor=document.getElementById("editor");document.getElementById("cancel").onclick=()=>bridge("lifecycle.close",{reason:"用户关闭任务面板"});async function poll(){try{const result=await bridge("tools.list");for(const call of Array.isArray(result.calls)?result.calls:[]){if(handled.has(call.call_id)||!(call.status==="waiting_for_app"||call.status==="running"))continue;handled.add(call.call_id);await handleTask(call)}}catch(_){}}async function handleTask(call){try{await bridge("tools.reportProgress",{call_id:call.call_id,progress:{status:"running",percent:10}});if(call.tool_id==="task-dashboard.open"){const title=typeof call.input?.title==="string"?call.input.title:"未命名任务";const task_id=typeof call.input?.task_id==="string"?call.input.task_id:"task-"+call.call_id;tasks.set(task_id,{title,status:"open"});await bridge("surface.patch",{data:{state:{title:"任务面板",status:"已创建:"+title,percent:100,steps:[...tasks.values()].map(x=>x.title)}}});await bridge("tools.complete",{call_id:call.call_id,result:{status:"completed",task_id}})}else if(call.tool_id==="task-dashboard.update"){const task_id=String(call.input?.task_id||("task-"+call.call_id));const task={...(tasks.get(task_id)||{}),...(typeof call.input?.status==="string"?{status:call.input.status}:{}),...(typeof call.input?.progress==="number"?{progress:call.input.progress}: {})};tasks.set(task_id,task);await bridge("tools.complete",{call_id:call.call_id,result:{task_id,task}})}else await bridge("tools.fail",{call_id:call.call_id,code:"tool_not_supported",message:"不支持的任务工具"})}catch(_){await bridge("tools.fail",{call_id:call.call_id,code:"app_bridge_failed",message:"任务面板处理失败"}).catch(()=>{})}}setInterval(poll,500);poll();`;
}
function whiteboardSurfaceScript(): string {
return `const handled=new Set;let board={title:"Whiteboard",status:"可编辑",elements:[]};const editor=document.getElementById("editor");document.getElementById("cancel").onclick=()=>bridge("lifecycle.close",{reason:"用户关闭画板"});editor.addEventListener("input",()=>{board={...board,text:editor.value};bridge("surface.patch",{data:{state:board}}).catch(()=>{})});async function poll(){try{const result=await bridge("tools.list");for(const call of Array.isArray(result.calls)?result.calls:[]){if(handled.has(call.call_id)||!(call.status==="waiting_for_app"||call.status==="running"))continue;handled.add(call.call_id);await handleBoard(call)}}catch(_){}}async function handleBoard(call){try{if(call.tool_id==="whiteboard.open"){await bridge("tools.reportProgress",{call_id:call.call_id,progress:{status:"opening",percent:40}});await bridge("tools.complete",{call_id:call.call_id,result:{status:"completed"}})}else if(call.tool_id==="whiteboard.export"){const artifact_id=typeof call.input?.artifact_id==="string"?call.input.artifact_id:"whiteboard-"+call.call_id;await bridge("tools.reportProgress",{call_id:call.call_id,progress:{status:"exporting",percent:80}});await bridge("surface.patch",{data:{state:{...board,artifact:{artifact_id}}}});await bridge("tools.complete",{call_id:call.call_id,result:{artifact_id}})}else await bridge("tools.fail",{call_id:call.call_id,code:"tool_not_supported",message:"不支持的画板工具"})}catch(_){await bridge("tools.fail",{call_id:call.call_id,code:"app_bridge_failed",message:"画板处理失败"}).catch(()=>{})}}setInterval(poll,500);poll();`;
return `const handled=new Set;let board={title:"Whiteboard",status:"可编辑",elements:[]};const editor=document.getElementById("editor");document.getElementById("cancel").onclick=()=>bridge("lifecycle.close",{reason:"用户关闭画板"});editor.addEventListener("input",()=>{board={...board,text:editor.value};bridge("surface.patch",{data:{state:board}}).catch(()=>{})});async function poll(){try{const result=await bridge("tools.list");for(const call of Array.isArray(result.calls)?result.calls:[]){if(handled.has(call.call_id)||!(call.status==="waiting_for_app"||call.status==="running"))continue;handled.add(call.call_id);await handleBoard(call)}}catch(_){}}async function handleBoard(call){try{if(call.tool_id==="whiteboard.open"){await bridge("tools.reportProgress",{call_id:call.call_id,progress:{status:"opening",percent:40}});await bridge("tools.complete",{call_id:call.call_id,result:{status:"completed"}})}else if(call.tool_id==="whiteboard.submit"){const artifact_id=typeof call.input?.artifact_id==="string"?call.input.artifact_id:"whiteboard-"+call.call_id;await bridge("tools.reportProgress",{call_id:call.call_id,progress:{status:"submitting",percent:80}});await bridge("surface.patch",{data:{state:{...board,artifact:{artifact_id}}}});await bridge("tools.complete",{call_id:call.call_id,result:{artifact_id}})}else await bridge("tools.fail",{call_id:call.call_id,code:"tool_not_supported",message:"不支持的画板工具"})}catch(_){await bridge("tools.fail",{call_id:call.call_id,code:"app_bridge_failed",message:"画板处理失败"}).catch(()=>{})}}setInterval(poll,500);poll();`;
}
export function productionSurfaceDocument(instanceID: string, verifiedBundle: string): string {
@@ -22,7 +22,7 @@
| ✅ | P1 | A4 | 同一个 App 的多个 instance 之间 Inbox 订阅没有隔离 | `lineup-runtime.ts` | 已按 `app_scope + conversation_id + instance_id` 过滤实时订阅,并补充双实例回归测试。 |
| ✅ | P1 | A5 | Interact 使用专用 `ChatRuntimeSDK` 旁路,没有和其他 MiniApp 共用 SDK v1 语义 | `tauri/src/runtime/app-management/app-sdk.ts``lineup-runtime.ts``main.ts` | 已明确为“通用 Runtime 操作 + 可信 UI 投影”:Interact 保留可信 DOM 和 IM 展示,但行为统一走 `sdk.runtime.*`,展示走 `sdk.ui.*`;旧扁平方法仅作兼容别名。 |
| ✅ | P1 | A6 | 标准交互的超时、dismiss、提交和答案 schema 没有由 Runtime 统一裁决 | `lineup-runtime.ts``agent-interaction-service.ts``standard-interaction-contract.ts` | 已让本地提交、取消、过期和 Agent dismiss 同步推进 Interaction 与 Kernelnotice 也会完成 Kernel;四种答案在 Runtime 按固定 schema 校验,默认有效期和重启过期均只写一条 outbox。 |
| 🔴 | P2 | A7 | 迭代文档中的 Tool 名称和代码 Manifest 不一致 | 主文档 §5.2/§5.3;`reference-miniapps.ts` | 统一契约、Manifest、fixture、Agent Inventory 和验收脚本中的名称。 |
| | P2 | A7 | 迭代文档中的 Tool 名称和代码 Manifest 不一致 | 主文档 §5.2/§5.3;`reference-miniapps.ts` | 统一`task-dashboard.open``task-dashboard.update``whiteboard.open``whiteboard.submit`Manifest schema、MiniApp 实现、sandbox iframe、fixture 和测试均已同步。 |
| 🔴 | P2 | A8 | 当前 Task Dashboard/Whiteboard Surface 主要是 Host 硬编码的静态页面,无法证明真实业务 UI 在各自受限 Surface 内运行 | `main.ts:180-198``isolated-surface-host.ts` | 至少提供能代表业务边界的受限 Surface fixture,并验证 MiniApp 业务逻辑不能取得 Host DOM 或 Runtime 内部。 |
| 🔴 | P2 | A9 | MiniApp progress 没有进入可恢复的 Tool 状态记录 | `miniapp-tool-state.ts` | 如果契约要求进度可恢复,需持久化最后进度并覆盖 Runtime 重启;否则修改文档,明确 progress 只是一种可丢失事件。 |
| 🔴 | P3 | A10 | App session 记录和 opened/closed 事件没有显式保存 `agent_id` / `conversation_id` 字段 | `app-instance-manager.ts``lineup-runtime.ts:203-209,1052-1058` | P3 也必须在本迭代处理:App session opened/closed 事件和持久化记录补齐两个上下文字段。 |
@@ -31,7 +31,7 @@
## 1. 已验证通过的部分
- `npm run build` 通过。
- `npm test -- --run` 通过:29 个测试文件、129 个测试(含默认有效期、重启过期和答案 schema 回归)。
- `npm test -- --run` 通过:29 个测试文件、131 个测试(含 Tool 契约、默认有效期、重启过期和答案 schema 回归)。
- `git diff --check` 通过。
- 使用独立 `agent-browser` 会话登录本地测试账号成功。
- 主 IM 页面、同步状态、应用子会话区域和“启用任务面板”入口可见。
@@ -88,17 +88,17 @@ Interact 仍然可以使用可信 DOM,但它的 SDK 已明确拆成两层:`s
## 3. 验收结论
当前结论为(完成本轮 P1-1~P1-4 后):
当前结论为(完成本轮 P1-1~P1-4,并收敛 A7 后):
```text
功能回归:通过
基础构建与自动化测试:通过
真实登录和消息发送:通过
App 架构边界:部分通过(A1/A2/A5/A6 已实现,A2 待浏览器复验)
MiniApp 隔离与 SDK 规范:A1A6 已通过,仍需处理后续 P2/P3
MiniApp 隔离与 SDK 规范:A1A7 已通过,仍需处理后续 P2/P3
标准交互终态契约:通过
迭代整体验收:不通过,继续处理 A7~A11;A2 需在最终浏览器复验中确认
迭代整体验收:不通过,继续处理 A8~A11;A2 需在最终浏览器复验中确认
```
本轮独立验收由子 agent 完成。A6 已在本轮修复并通过自动化验证;下一轮继续处理 A7A11,并重新执行
本轮独立验收由子 agent 完成。A6 已在本轮修复并通过自动化验证A7 已完成契约收敛并通过全量测试;下一轮继续处理 A8A11,并重新执行
独立验收。P2/P3 不能被静默删除,必须在本迭代结束前解决或保留明确的延期记录。