fix(agent): synchronize conversation preparation state
This commit is contained in:
@@ -214,7 +214,7 @@ test("shared thread events are broadcast with the active thread id", (t) => {
|
||||
});
|
||||
|
||||
test("new clients receive the current Codex state and later updates", (t) => {
|
||||
const session = new CanvasSession();
|
||||
const session = new CanvasSession("thread-2");
|
||||
session.setCodexState({ busy: true, threadId: "thread-2", turnId: "turn-1" });
|
||||
session.trackCodexEvent("codex_approval", { requestId: "approval-1", threadId: "thread-2" });
|
||||
const client = connect(session, "first", "thread-2");
|
||||
@@ -223,6 +223,7 @@ test("new clients receive the current Codex state and later updates", (t) => {
|
||||
const hello = client.event("hello");
|
||||
assert.equal(field(hello, "protocolVersion"), 5);
|
||||
assert.deepEqual(field(hello, "workspace"), { activeThreadId: "thread-2" });
|
||||
assert.deepEqual(field(hello, "conversation"), { revision: 1, conversationId: "thread-2", threadId: "thread-2", status: "ready", mcpStatuses: {} });
|
||||
assert.deepEqual(field(hello, "codex"), { busy: true, threadId: "thread-2", turnId: "turn-1" });
|
||||
assert.deepEqual(field(hello, "pendingApprovals"), [{ requestId: "approval-1", threadId: "thread-2" }]);
|
||||
|
||||
@@ -236,6 +237,50 @@ test("new clients receive the current Codex state and later updates", (t) => {
|
||||
assert.deepEqual(client.event("codex_state"), { busy: false, threadId: "thread-2", turnId: "turn-1" });
|
||||
});
|
||||
|
||||
test("对话 revision 单调递增且 MCP 全部进入终态前保持 preparing", () => {
|
||||
const session = new CanvasSession();
|
||||
const revisions = [session.conversationStateSnapshot.revision];
|
||||
|
||||
revisions.push(session.beginConversation({ sourceClientId: "first" }).revision);
|
||||
revisions.push(session.updateConversationMcp("late-service", "starting").revision);
|
||||
revisions.push(session.completeConversationMcpInventory([{ name: "infinite-canvas", authStatus: "unsupported" }]).revision);
|
||||
const pending = session.completeConversationPreparation("thread-1");
|
||||
revisions.push(pending.revision);
|
||||
assert.equal(pending.status, "preparing");
|
||||
|
||||
const ready = session.updateConversationMcp("late-service", "ready");
|
||||
revisions.push(ready.revision);
|
||||
assert.equal(ready.status, "ready");
|
||||
assert.equal(ready.threadId, "thread-1");
|
||||
revisions.slice(1).forEach((revision, index) => assert.ok(revision > revisions[index]));
|
||||
});
|
||||
|
||||
test("可选 MCP 失败进入 warning,画布 MCP 失败进入 failed", () => {
|
||||
const optionalFailure = new CanvasSession();
|
||||
optionalFailure.beginConversation();
|
||||
optionalFailure.completeConversationMcpInventory([
|
||||
{ name: "infinite-canvas", authStatus: "unsupported" },
|
||||
{ name: "notion", authStatus: "notLoggedIn" },
|
||||
]);
|
||||
const warning = optionalFailure.completeConversationPreparation("thread-1");
|
||||
assert.equal(warning.status, "warning");
|
||||
assert.equal(warning.mcpStatuses.notion.status, "failed");
|
||||
|
||||
const requiredFailure = new CanvasSession();
|
||||
requiredFailure.beginConversation();
|
||||
requiredFailure.completeConversationMcpInventory([{ name: "infinite-canvas", authStatus: "notLoggedIn" }]);
|
||||
const failed = requiredFailure.completeConversationPreparation("thread-2");
|
||||
assert.equal(failed.status, "failed");
|
||||
assert.match(failed.error || "", /Infinite Canvas MCP/);
|
||||
|
||||
const requiredMissing = new CanvasSession();
|
||||
requiredMissing.beginConversation();
|
||||
requiredMissing.completeConversationMcpInventory([{ name: "notion", authStatus: "unsupported" }]);
|
||||
const missing = requiredMissing.completeConversationPreparation("thread-3");
|
||||
assert.equal(missing.status, "failed");
|
||||
assert.match(missing.error || "", /Infinite Canvas MCP/);
|
||||
});
|
||||
|
||||
test("Codex 写操作在多窗口之间互斥且不能与运行 turn 并发", () => {
|
||||
const session = new CanvasSession();
|
||||
assert.equal(session.beginCodexMutation(), true);
|
||||
|
||||
Reference in New Issue
Block a user