baa-conductor


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;