fix(runtime): include app session context in lifecycle events

This commit is contained in:
2026-08-06 00:53:31 +08:00
parent 0b7257f3d3
commit 75529cdd49
3 changed files with 28 additions and 5 deletions
@@ -75,6 +75,11 @@ describe("LineUpRuntime", () => {
await runtime.login(login);
await runtime.syncOnce();
await runtime.flushOutbox();
expect(transport.sent.map(entry => JSON.parse(entry.payload)).find(entry => entry.type === "lineup.v1.app.session.opened")).toMatchObject({
payload: { agent_id: "agent_1", conversation_id: conversationID, app_session_id: expect.any(String) },
});
expect(runtime.lifecycle.instances.get("draw-and-guess:game-001")).toMatchObject({ state: "foreground", conversation_id: conversationID });
const interaction = runtime.lifecycle.instances.activeFor("chat", conversationID);
expect(interaction).toMatchObject({ state: "background" });
@@ -115,6 +120,20 @@ describe("LineUpRuntime", () => {
expect(chat.snapshot()).toMatchObject({ app_scope: "chat", active: true, conversation_id: "user_1:2:channel_1" });
});
it("includes agent and conversation context in App session closed events", async () => {
const conversationID = "user_1:2:channel_1";
const transport = new FakeTransport();
const runtime = new LineUpRuntime({ storage: new MemoryStorage(), createTransport: () => transport });
await runtime.login(login);
const instance = runtime.lifecycle.start({ app_scope: "whiteboard", instance_id: "whiteboard:context-1", app_session_id: "whiteboard:session-1", conversation_id: conversationID }, "2026-08-04T00:00:00.000Z");
runtime.lifecycle.foreground(instance.instance_id, "2026-08-04T00:00:00.000Z");
await runtime.openBundledMiniApp("whiteboard", instance.instance_id).lifecycle.requestBackground();
runtime.closeAppInstance(instance.instance_id);
await runtime.flushOutbox();
const event = transport.sent.map(entry => JSON.parse(entry.payload) as { type: string; payload: Record<string, unknown> }).find(entry => entry.type === "lineup.v1.app.session.closed");
expect(event).toMatchObject({ type: "lineup.v1.app.session.closed", payload: { agent_id: "agent_1", conversation_id: conversationID, app_session_id: "whiteboard:session-1" } });
});
it("adapts legacy LineUp v1 messages into chat scope before SDK delivery", async () => {
const conversationID = "user_1:2:channel_1";
const transport = new FakeTransport([[{ message_seq: 7, from_uid: "agent_1", payload: agentEnvelope("agent_msg_7", conversationID) }], []]);
@@ -208,6 +208,8 @@ export class LineUpRuntime {
.filter(interaction => interaction.app_session_id === currentInstance.app_session_id && (interaction.status === "pending" || interaction.status === "presented"))
.map(interaction => interaction.call_id);
void this.queueProtocolAction("app-result", "lineup.v1.app.session.closed", {
agent_id: this.session.agent_uid,
conversation_id: currentInstance.conversation_id ?? this.requireConversationID(),
app_scope: currentInstance.app_scope,
instance_id: currentInstance.instance_id,
app_session_id: currentInstance.app_session_id,
@@ -1241,9 +1243,11 @@ export class LineUpRuntime {
private persistWorkspace(): void { this.store.replaceAppWorkspace(this.lifecycle.snapshot()); }
private queueAppSessionOpened(instance: { app_scope: AppScope; instance_id: string; app_session_id?: string }): void {
private queueAppSessionOpened(instance: { app_scope: AppScope; instance_id: string; app_session_id?: string; conversation_id?: string }): void {
if (!instance.app_session_id) return;
void this.queueProtocolAction("app-result", "lineup.v1.app.session.opened", {
agent_id: this.session.agent_uid,
conversation_id: instance.conversation_id ?? this.requireConversationID(),
app_scope: instance.app_scope,
instance_id: instance.instance_id,
app_session_id: instance.app_session_id,