fix(runtime): include app session context in lifecycle events
This commit is contained in:
@@ -75,6 +75,11 @@ describe("LineUpRuntime", () => {
|
|||||||
await runtime.login(login);
|
await runtime.login(login);
|
||||||
await runtime.syncOnce();
|
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 });
|
expect(runtime.lifecycle.instances.get("draw-and-guess:game-001")).toMatchObject({ state: "foreground", conversation_id: conversationID });
|
||||||
const interaction = runtime.lifecycle.instances.activeFor("chat", conversationID);
|
const interaction = runtime.lifecycle.instances.activeFor("chat", conversationID);
|
||||||
expect(interaction).toMatchObject({ state: "background" });
|
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" });
|
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 () => {
|
it("adapts legacy LineUp v1 messages into chat scope before SDK delivery", async () => {
|
||||||
const conversationID = "user_1:2:channel_1";
|
const conversationID = "user_1:2:channel_1";
|
||||||
const transport = new FakeTransport([[{ message_seq: 7, from_uid: "agent_1", payload: agentEnvelope("agent_msg_7", conversationID) }], []]);
|
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"))
|
.filter(interaction => interaction.app_session_id === currentInstance.app_session_id && (interaction.status === "pending" || interaction.status === "presented"))
|
||||||
.map(interaction => interaction.call_id);
|
.map(interaction => interaction.call_id);
|
||||||
void this.queueProtocolAction("app-result", "lineup.v1.app.session.closed", {
|
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,
|
app_scope: currentInstance.app_scope,
|
||||||
instance_id: currentInstance.instance_id,
|
instance_id: currentInstance.instance_id,
|
||||||
app_session_id: currentInstance.app_session_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 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;
|
if (!instance.app_session_id) return;
|
||||||
void this.queueProtocolAction("app-result", "lineup.v1.app.session.opened", {
|
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,
|
app_scope: instance.app_scope,
|
||||||
instance_id: instance.instance_id,
|
instance_id: instance.instance_id,
|
||||||
app_session_id: instance.app_session_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 | 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 | 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 重启后可恢复,且补充状态机和重启回归测试。 |
|
| ✅ | 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 约束的适配器。 |
|
| 🔴 | P3 | A11 | 旧的 `openExtensionApp` 公开入口仍提供较宽的旁路能力 | `lineup-runtime.ts:286-300` | P3 也必须在本迭代处理:删除公开旁路,或让它只返回受统一 SDK v1 约束的适配器。 |
|
||||||
|
|
||||||
## 1. 已验证通过的部分
|
## 1. 已验证通过的部分
|
||||||
@@ -96,10 +96,10 @@ Interact 仍然可以使用可信 DOM,但它的 SDK 已明确拆成两层:`s
|
|||||||
基础构建与自动化测试:通过
|
基础构建与自动化测试:通过
|
||||||
真实登录和消息发送:通过
|
真实登录和消息发送:通过
|
||||||
App 架构边界:部分通过(A1/A2/A5/A6 已实现,A2 待浏览器复验)
|
App 架构边界:部分通过(A1/A2/A5/A6 已实现,A2 待浏览器复验)
|
||||||
MiniApp 隔离与 SDK 规范:A1~A9 已通过,仍需处理后续 P3
|
MiniApp 隔离与 SDK 规范:A1~A10 已通过,仍需处理后续 P3
|
||||||
标准交互终态契约:通过
|
标准交互终态契约:通过
|
||||||
迭代整体验收:不通过,继续处理 A8、A10、A11;A2 需在最终浏览器复验中确认
|
迭代整体验收:不通过,继续处理 A8、A11;A2 需在最终浏览器复验中确认
|
||||||
```
|
```
|
||||||
|
|
||||||
本轮独立验收由子 agent 完成。A6 已在本轮修复并通过自动化验证,A7 已完成契约收敛并通过全量测试,A9 已完成进度持久化并通过重启回归;下一轮继续处理 A8、A10、A11,并重新执行
|
本轮独立验收由子 agent 完成。A6 已在本轮修复并通过自动化验证,A7 已完成契约收敛并通过全量测试,A9 已完成进度持久化并通过重启回归,A10 已补齐生命周期事件上下文;下一轮继续处理 A8、A11,并重新执行
|
||||||
独立验收。P2/P3 不能被静默删除,必须在本迭代结束前解决或保留明确的延期记录。
|
独立验收。P2/P3 不能被静默删除,必须在本迭代结束前解决或保留明确的延期记录。
|
||||||
|
|||||||
Reference in New Issue
Block a user