feat(agent): generate Skill drafts from conversations and canvases
This commit is contained in:
@@ -23,6 +23,25 @@ test("MCP 读取当前激活网页的画布", async (t) => {
|
||||
assert.equal(field(await session.callTool("canvas_get_state", {}), "projectId"), "canvas-second");
|
||||
});
|
||||
|
||||
test("按精确 clientId 读取画布快照,不受当前焦点影响", (t) => {
|
||||
const session = new CanvasSession();
|
||||
const first = connect(session, "first");
|
||||
const second = connect(session, "second");
|
||||
t.after(() => {
|
||||
first.close();
|
||||
second.close();
|
||||
});
|
||||
session.updateState(snapshot("canvas-first"), "first");
|
||||
session.updateState(snapshot("canvas-second"), "second");
|
||||
session.activateClient("second");
|
||||
|
||||
assert.equal(field(session.canvasStateForClient("first"), "projectId"), "canvas-first");
|
||||
assert.equal(field(session.canvasStateForClient("second"), "projectId"), "canvas-second");
|
||||
assert.equal(session.canvasStateForClient("missing"), null);
|
||||
first.close();
|
||||
assert.equal(session.canvasStateForClient("first"), null);
|
||||
});
|
||||
|
||||
test("画布写操作只发送给当前激活网页", async (t) => {
|
||||
const session = new CanvasSession();
|
||||
const first = connect(session, "first");
|
||||
@@ -202,7 +221,7 @@ test("new clients receive the current Codex state and later updates", (t) => {
|
||||
t.after(() => client.close());
|
||||
|
||||
const hello = client.event("hello");
|
||||
assert.equal(field(hello, "protocolVersion"), 4);
|
||||
assert.equal(field(hello, "protocolVersion"), 5);
|
||||
assert.deepEqual(field(hello, "workspace"), { activeThreadId: "thread-2" });
|
||||
assert.deepEqual(field(hello, "codex"), { busy: true, threadId: "thread-2", turnId: "turn-1" });
|
||||
assert.deepEqual(field(hello, "pendingApprovals"), [{ requestId: "approval-1", threadId: "thread-2" }]);
|
||||
@@ -228,6 +247,46 @@ test("Codex 写操作在多窗口之间互斥且不能与运行 turn 并发", ()
|
||||
assert.equal(session.beginCodexMutation(), false);
|
||||
});
|
||||
|
||||
test("Skill draft generation broadcasts shared busy state and restores the previous thread", (t) => {
|
||||
const session = new CanvasSession();
|
||||
const first = connect(session, "first");
|
||||
const second = connect(session, "second");
|
||||
t.after(() => {
|
||||
first.close();
|
||||
second.close();
|
||||
});
|
||||
session.setCodexState({ threadId: "thread-1", turnId: "turn-previous" });
|
||||
const previous = session.codexStateSnapshot;
|
||||
|
||||
assert.equal(session.beginCodexMutation(), true);
|
||||
session.setCodexState({ busy: true, threadId: previous.threadId, turnId: "" }, { preserveReplay: true });
|
||||
assert.deepEqual(first.events("codex_state").at(-1), { busy: true, threadId: "thread-1", turnId: "" });
|
||||
assert.deepEqual(second.events("codex_state").at(-1), { busy: true, threadId: "thread-1", turnId: "" });
|
||||
assert.equal(session.beginCodexMutation(), false);
|
||||
|
||||
session.setCodexState(previous, { preserveReplay: true });
|
||||
session.endCodexMutation();
|
||||
assert.deepEqual(first.events("codex_state").at(-1), previous);
|
||||
assert.deepEqual(second.events("codex_state").at(-1), previous);
|
||||
assert.equal(session.beginCodexMutation(), true);
|
||||
session.endCodexMutation();
|
||||
});
|
||||
|
||||
test("Skill draft busy state preserves the previous turn replay until history acknowledges it", (t) => {
|
||||
const session = new CanvasSession();
|
||||
session.setCodexState({ busy: true, threadId: "thread-1", turnId: "turn-1" });
|
||||
session.emitThread("agent_event", "thread-1", { turnId: "turn-1", type: "item.updated", item: { id: "assistant-1", type: "agent_message", text: "回答" } });
|
||||
session.setCodexState({ busy: false });
|
||||
const previous = session.codexStateSnapshot;
|
||||
|
||||
session.setCodexState({ busy: true, threadId: "thread-1", turnId: "" }, { preserveReplay: true });
|
||||
session.setCodexState(previous, { preserveReplay: true });
|
||||
|
||||
const client = connect(session, "first", "thread-1");
|
||||
t.after(() => client.close());
|
||||
assert.equal(client.events("agent_event").length, 1);
|
||||
});
|
||||
|
||||
test("a bound client remains the tool target while focus changes", async (t) => {
|
||||
const session = new CanvasSession();
|
||||
const first = connect(session, "first");
|
||||
|
||||
Reference in New Issue
Block a user