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,
@@ -25,7 +25,7 @@
| ✅ | 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``lineup-runtime.test.ts` | 已在 Tool 记录保存最后一次 `percent/status/detail`ConversationStore 随记录持久化;Runtime 重启后可恢复,且补充状态机和重启回归测试。 |
| 🔴 | 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 事件和持久化记录补齐两个上下文字段。 |
| | P3 | A10 | App session 记录和 opened/closed 事件没有显式保存 `agent_id` / `conversation_id` 字段 | `lineup-runtime.ts``lineup-runtime.test.ts` | opened/closed 事件现在都带 `agent_id``conversation_id``app_session_id``instance_id``app_scope`;并补充生命周期回归测试。 |
| 🔴 | P3 | A11 | 旧的 `openExtensionApp` 公开入口仍提供较宽的旁路能力 | `lineup-runtime.ts:286-300` | P3 也必须在本迭代处理:删除公开旁路,或让它只返回受统一 SDK v1 约束的适配器。 |
## 1. 已验证通过的部分
@@ -96,10 +96,10 @@ Interact 仍然可以使用可信 DOM,但它的 SDK 已明确拆成两层:`s
基础构建与自动化测试:通过
真实登录和消息发送:通过
App 架构边界:部分通过(A1/A2/A5/A6 已实现,A2 待浏览器复验)
MiniApp 隔离与 SDK 规范:A1A9 已通过,仍需处理后续 P3
MiniApp 隔离与 SDK 规范:A1A10 已通过,仍需处理后续 P3
标准交互终态契约:通过
迭代整体验收:不通过,继续处理 A8、A10、A11;A2 需在最终浏览器复验中确认
迭代整体验收:不通过,继续处理 A8、A11;A2 需在最终浏览器复验中确认
```
本轮独立验收由子 agent 完成。A6 已在本轮修复并通过自动化验证,A7 已完成契约收敛并通过全量测试,A9 已完成进度持久化并通过重启回归;下一轮继续处理 A8、A10、A11,并重新执行
本轮独立验收由子 agent 完成。A6 已在本轮修复并通过自动化验证,A7 已完成契约收敛并通过全量测试,A9 已完成进度持久化并通过重启回归A10 已补齐生命周期事件上下文;下一轮继续处理 A8、A11,并重新执行
独立验收。P2/P3 不能被静默删除,必须在本迭代结束前解决或保留明确的延期记录。