- commit
- 92f58cc
- parent
- ce6e8af
- author
- im_wower
- date
- 2026-04-03 09:20:39 +0800 CST
feat: route delivery through conversation-first targets
3 files changed,
+53,
-13
Raw patch view.
1diff --git a/apps/conductor-daemon/src/artifacts/upload-session.ts b/apps/conductor-daemon/src/artifacts/upload-session.ts
2index 0f2d91cc3b0b02a9371620f96199aa995c9e792f..64bf3a7a6b2c32d39353ad3a67d5ff85aca41f2a 100644
3--- a/apps/conductor-daemon/src/artifacts/upload-session.ts
4+++ b/apps/conductor-daemon/src/artifacts/upload-session.ts
5@@ -448,6 +448,20 @@ function buildInvalidRouteReason(route: BaaDeliveryRouteSnapshot): string {
6 ].join(" ");
7 }
8
9+function hasDeliverableBusinessRoute(route: BaaDeliveryRouteSnapshot): boolean {
10+ return route.shellPage !== true && (
11+ route.conversationId != null
12+ || route.pageUrl != null
13+ || route.tabId != null
14+ );
15+}
16+
17+function resolvePreferredTargetTabId(route: BaaDeliveryRouteSnapshot): number | null {
18+ return route.conversationId != null || route.pageUrl != null
19+ ? null
20+ : route.tabId;
21+}
22+
23 function shouldFailClosedWithoutFallback(reason: string): boolean {
24 return reason.startsWith("delivery.route_")
25 || reason.startsWith("delivery.shell_page:")
26@@ -593,11 +607,13 @@ export class BaaBrowserDeliveryBridge {
27 return cloneSessionSnapshot(record.snapshot);
28 }
29
30- if (route.shellPage || route.tabId == null) {
31+ if (!hasDeliverableBusinessRoute(route)) {
32 this.failSession(record, buildInvalidRouteReason(route));
33 return cloneSessionSnapshot(record.snapshot);
34 }
35
36+ const preferredTargetTabId = resolvePreferredTargetTabId(route);
37+
38 try {
39 const proxyDispatch = this.bridge.proxyDelivery({
40 assistantMessageId: input.assistantMessageId,
41@@ -610,7 +626,7 @@ export class BaaBrowserDeliveryBridge {
42 planId,
43 platform: input.platform,
44 shellPage: route.shellPage,
45- tabId: route.tabId,
46+ tabId: preferredTargetTabId,
47 timeoutMs: DEFAULT_BAA_DELIVERY_ACTION_TIMEOUT_MS
48 });
49
50@@ -653,7 +669,7 @@ export class BaaBrowserDeliveryBridge {
51 pageTitle: route.pageTitle,
52 pageUrl: route.pageUrl,
53 shellPage: route.shellPage,
54- tabId: route.tabId,
55+ tabId: preferredTargetTabId,
56 timeoutMs: DEFAULT_BAA_DELIVERY_ACTION_TIMEOUT_MS
57 });
58
59@@ -682,7 +698,7 @@ export class BaaBrowserDeliveryBridge {
60 pageTitle: route.pageTitle,
61 pageUrl: route.pageUrl,
62 shellPage: route.shellPage,
63- tabId: route.tabId,
64+ tabId: preferredTargetTabId,
65 timeoutMs: DEFAULT_BAA_DELIVERY_ACTION_TIMEOUT_MS
66 });
67
68diff --git a/apps/conductor-daemon/src/index.test.js b/apps/conductor-daemon/src/index.test.js
69index b0db8b9bde131540b0fd906b10f150543e6f16ef..cab0f0b69c18ae9b016292fe4bce1f9a71d05366 100644
70--- a/apps/conductor-daemon/src/index.test.js
71+++ b/apps/conductor-daemon/src/index.test.js
72@@ -4248,7 +4248,9 @@ test("renewal dispatcher sends due pending jobs through browser.proxy_delivery a
73 assert.equal(result.result, "ok");
74 assert.equal(browserCalls.length, 1);
75 assert.equal(browserCalls[0].messageText, "[renewal] keepalive");
76- assert.equal(browserCalls[0].tabId, 17);
77+ assert.equal(browserCalls[0].conversationId, "conv_dispatch_success");
78+ assert.equal(browserCalls[0].pageUrl, "https://chatgpt.com/c/conv_dispatch_success");
79+ assert.equal(browserCalls[0].tabId, null);
80 assert.equal(job.status, "done");
81 assert.equal(job.attemptCount, 1);
82 assert.equal(job.lastError, null);
83@@ -9086,7 +9088,7 @@ test("observeRenewalConversation prefers conversation-derived business targets o
84
85 const legacyTabLink = await store.getConversationLink("link-target-priority-tab-1");
86 assert.ok(legacyTabLink);
87- assert.equal(legacyTabLink.isActive, true);
88+ assert.equal(legacyTabLink.isActive, false);
89 assert.equal(legacyTabLink.localConversationId, "lc-target-priority-tab-1");
90
91 assert.deepEqual(
92@@ -9209,7 +9211,7 @@ test("observeRenewalConversation paginates exact-match scans and reports diagnos
93 assert.equal(legacyTabLinks.length, 50);
94 assert.equal(
95 legacyTabLinks.filter((link) => link.isActive).length,
96- 50
97+ 0
98 );
99
100 const conversationLinks = await store.listConversationLinks({
101@@ -9228,7 +9230,26 @@ test("observeRenewalConversation paginates exact-match scans and reports diagnos
102 conversationLinks.find((link) => link.linkId === "link-scan-limit-target")?.isActive,
103 true
104 );
105- assert.deepEqual(diagnostics, []);
106+ assert.deepEqual(diagnostics, [
107+ {
108+ clientId: "firefox-chatgpt",
109+ code: "conversation_link_scan_limit_reached",
110+ limit: 50,
111+ offset: 0,
112+ operation: "resolve",
113+ platform: "chatgpt",
114+ signal: "target_id"
115+ },
116+ {
117+ clientId: "firefox-chatgpt",
118+ code: "conversation_link_scan_limit_reached",
119+ limit: 50,
120+ offset: 0,
121+ operation: "deactivate",
122+ platform: "chatgpt",
123+ signal: "target_id"
124+ }
125+ ]);
126 } finally {
127 store.close();
128 rmSync(rootDir, {
129@@ -10134,8 +10155,7 @@ test("ConductorRuntime exposes proxy-delivery browser snapshots with routed busi
130 "```"
131 ].join("\n"),
132 observed_at: 1710000030000,
133- shell_page: false,
134- tab_id: 71
135+ shell_page: false
136 })
137 );
138
139@@ -10158,7 +10178,7 @@ test("ConductorRuntime exposes proxy-delivery browser snapshots with routed busi
140 );
141 assert.doesNotMatch(proxyDelivery.message_text, /line-260/u);
142 assert.equal(proxyDelivery.page_url, "https://chatgpt.com/c/conv-delivery-artifact");
143- assert.equal(proxyDelivery.target_tab_id, 71);
144+ assert.equal(proxyDelivery.target_tab_id, undefined);
145
146 sendPluginActionResult(client.socket, {
147 action: "proxy_delivery",
148@@ -10178,7 +10198,7 @@ test("ConductorRuntime exposes proxy-delivery browser snapshots with routed busi
149 assert.equal(browserStatus.payload.data.delivery.last_session.delivery_mode, "proxy");
150 assert.equal(browserStatus.payload.data.delivery.last_session.message_truncated, true);
151 assert.equal(browserStatus.payload.data.delivery.last_session.target_page_url, "https://chatgpt.com/c/conv-delivery-artifact");
152- assert.equal(browserStatus.payload.data.delivery.last_session.target_tab_id, 71);
153+ assert.equal(browserStatus.payload.data.delivery.last_session.target_tab_id, undefined);
154 assert.equal(browserStatus.payload.data.delivery.last_route.page_url, "https://chatgpt.com/c/conv-delivery-artifact");
155 assert.ok(
156 browserStatus.payload.data.delivery.last_session.source_line_count
157diff --git a/apps/conductor-daemon/src/renewal/dispatcher.ts b/apps/conductor-daemon/src/renewal/dispatcher.ts
158index bf5e53e849932198ae4ba999dd447c113f36b597..88104cd494d16afb3edd18d11e1c774ce3b399b6 100644
159--- a/apps/conductor-daemon/src/renewal/dispatcher.ts
160+++ b/apps/conductor-daemon/src/renewal/dispatcher.ts
161@@ -675,6 +675,10 @@ async function dispatchRenewalJob(
162 timeoutMs: number;
163 }
164 ): Promise<RenewalDispatchOutcome> {
165+ const targetTabId =
166+ input.target.conversationId != null || input.target.pageUrl != null
167+ ? null
168+ : input.target.tabId;
169 const dispatch = browserBridge.proxyDelivery({
170 assistantMessageId: input.assistantMessageId,
171 clientId: input.target.clientId,
172@@ -686,7 +690,7 @@ async function dispatchRenewalJob(
173 planId: buildRenewalPlanId(input.assistantMessageId),
174 platform: input.target.platform,
175 shellPage: false,
176- tabId: input.target.tabId,
177+ tabId: targetTabId,
178 timeoutMs: input.timeoutMs
179 });
180 const result = await dispatch.result;