refactor: consolidate chat state and task bridges
Centralize session scope, chat projections and typed task bridges. Keep historical interaction replies authoritative and publish terminal state to subscribers. Validate Server contracts before replacing generated artifacts.
This commit is contained in:
@@ -296,6 +296,11 @@ it("marks an explicitly aborted response incomplete and preserves scoped history
|
||||
const text = await response.text();
|
||||
expect(text).toContain("event: response.incomplete");
|
||||
expect(text).not.toContain("event: response.completed");
|
||||
const context = { actorKey: toActorKey("product:owner"), projectKey: toProjectKey(`product:${project}`), sessionId: "owned" };
|
||||
const saved = (await states.read(context))!.messages as Array<{ parts: Array<{ type: string; data?: { status?: string } }> }>;
|
||||
expect(saved.at(-1)?.parts.find((part) => part.type === "data-run_status")?.data?.status).toBe("aborted");
|
||||
const loaded = await http(`${base}/api/v1/session/owned`, { headers: { Authorization: "Bearer owner", "X-Project-Id": project } });
|
||||
expect((await loaded.json()).messages).toEqual(saved);
|
||||
});
|
||||
|
||||
it("continues a paged conversation from the complete saved history and preserves client message IDs", async () => {
|
||||
@@ -316,3 +321,28 @@ it("continues a paged conversation from the complete saved history and preserves
|
||||
expect((await call({ input: "重复提交", conversation: "owned", tjwater: { client_message_id: "client-turn-a" } })).status).toBe(409);
|
||||
expect(prompted).toHaveLength(1);
|
||||
});
|
||||
|
||||
it("uses the same canonical live messages for session reads and older pages", async () => {
|
||||
gate = new Promise<void>((resolve) => { release = resolve; });
|
||||
const context = { actorKey: toActorKey("product:owner"), projectKey: toProjectKey(`product:${project}`), sessionId: "owned" };
|
||||
const history = Array.from({ length: 5 }, (_, index) => ({ id: `old-${index}`, role: index % 2 ? "assistant" : "user",
|
||||
parts: [{ type: "text", text: `历史 ${index}` }] as unknown[] }));
|
||||
history[1].parts.push({ type: "data-question_request", data: { request_id: "old-question", session_id: "owned", questions: [] } });
|
||||
await states.write(context, { sessionId: "owned", messages: history });
|
||||
const response = await call({ input: "新一轮", conversation: "owned", stream: true, tjwater: { client_message_id: "live-user" } });
|
||||
const headers = { Authorization: "Bearer owner", "X-Project-Id": project };
|
||||
const live = await http(`${base}/api/v1/session/owned`, { headers });
|
||||
const snapshot = await live.json();
|
||||
expect(snapshot.is_streaming).toBe(true);
|
||||
expect(snapshot.messages).toHaveLength(7);
|
||||
expect(snapshot.messages.slice(0, 5)).toEqual(history);
|
||||
expect(snapshot.messages[5].id).toBe("live-user");
|
||||
const recent = await http(`${base}/api/v1/session/owned?message_limit=2`, { headers });
|
||||
const page = await recent.json();
|
||||
expect(page.messages).toEqual(snapshot.messages.slice(-2));
|
||||
const older = await http(`${base}/api/v1/session/owned/messages?limit=40&before=${encodeURIComponent(page.message_page.before_cursor)}`, { headers });
|
||||
expect(older.status).toBe(200);
|
||||
expect((await older.json()).messages).toEqual(history);
|
||||
release();
|
||||
await response.text();
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user