@agent-native/core 0.84.27 → 0.84.28

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/corpus/README.md CHANGED
@@ -28,4 +28,4 @@ rg -n "defineAction|useActionQuery" node_modules/@agent-native/core/corpus
28
28
  ## Generated Counts
29
29
 
30
30
  - core files: 2043
31
- - template files: 4971
31
+ - template files: 4972
@@ -1,5 +1,11 @@
1
1
  # @agent-native/core
2
2
 
3
+ ## 0.84.28
4
+
5
+ ### Patch Changes
6
+
7
+ - ffd5b99: Make agent chat thread handoffs robust when opening the panel from external UI controls.
8
+
3
9
  ## 0.84.27
4
10
 
5
11
  ### Patch Changes
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agent-native/core",
3
- "version": "0.84.27",
3
+ "version": "0.84.28",
4
4
  "description": "Framework for agent-native application development — where AI agents and UI share SQL state, actions, and context",
5
5
  "homepage": "https://github.com/BuilderIO/agent-native#readme",
6
6
  "bugs": {
@@ -26,7 +26,9 @@ import {
26
26
  AGENT_CHAT_REMOVE_CONTEXT_MESSAGE_TYPE,
27
27
  AGENT_CHAT_SET_CONTEXT_MESSAGE_TYPE,
28
28
  appendAgentChatContextToMessage,
29
+ claimAgentChatOpenRequest,
29
30
  claimAgentChatSubmit,
31
+ drainBufferedAgentChatOpenRequests,
30
32
  drainBufferedAgentChatSubmits,
31
33
  normalizeAgentChatContextItem,
32
34
  parseSubmitChatMessage,
@@ -2087,11 +2089,12 @@ export function MultiTabAssistantChat({
2087
2089
  useEffect(() => {
2088
2090
  const handleOpenThread = (event: Event) => {
2089
2091
  const detail = (event as CustomEvent).detail as
2090
- | { threadId?: unknown; newThread?: unknown }
2092
+ | { threadId?: unknown; newThread?: unknown; openRequestId?: unknown }
2091
2093
  | undefined;
2092
2094
  const threadId =
2093
2095
  typeof detail?.threadId === "string" ? detail.threadId : "";
2094
- if (!threadId) return;
2096
+ if (!detail || !threadId) return;
2097
+ if (!claimAgentChatOpenRequest(detail.openRequestId)) return;
2095
2098
 
2096
2099
  if (detail?.newThread === true) {
2097
2100
  newThreadIds.current.add(threadId);
@@ -2143,6 +2146,7 @@ export function MultiTabAssistantChat({
2143
2146
  const detail = (e as CustomEvent).detail;
2144
2147
  const threadId = detail?.threadId;
2145
2148
  if (!threadId) return;
2149
+ if (!claimAgentChatOpenRequest(detail.openRequestId)) return;
2146
2150
  dismissedSubAgentTabsRef.current.delete(threadId);
2147
2151
  // Prefer an explicit parent (RunsTray/background hydration knows it);
2148
2152
  // inline task cards fall back to the active orchestrator thread.
@@ -2196,6 +2200,17 @@ export function MultiTabAssistantChat({
2196
2200
  return () => window.removeEventListener("agent-task-open", handleOpenTask);
2197
2201
  }, [openTabIds, switchThread, refreshThreads, parentMap]);
2198
2202
 
2203
+ // Replay thread/task opens requested before this lazy panel's listeners
2204
+ // attached. Live events claim their id; replay drains only unclaimed requests.
2205
+ useEffect(() => {
2206
+ const buffered = drainBufferedAgentChatOpenRequests();
2207
+ for (const request of buffered) {
2208
+ window.dispatchEvent(
2209
+ new CustomEvent(request.eventType, { detail: request.detail }),
2210
+ );
2211
+ }
2212
+ }, []);
2213
+
2199
2214
  // Watch for agent-issued chat-command in application-state
2200
2215
  const lastChatCommandRef = useRef(0);
2201
2216
  useEffect(() => {
@@ -130,6 +130,26 @@ export interface AgentChatContextState {
130
130
  updatedAt: number;
131
131
  }
132
132
 
133
+ export interface AgentChatOpenThreadRequest {
134
+ threadId: string;
135
+ newThread?: boolean;
136
+ openRequestId?: string;
137
+ }
138
+
139
+ export interface AgentChatOpenTaskRequest {
140
+ threadId: string;
141
+ parentThreadId?: string;
142
+ description?: string;
143
+ name?: string;
144
+ openRequestId?: string;
145
+ }
146
+
147
+ export type BufferedAgentChatOpenRequest = {
148
+ id: string;
149
+ eventType: "agent-chat:open-thread" | "agent-task-open";
150
+ detail: AgentChatOpenThreadRequest | AgentChatOpenTaskRequest;
151
+ };
152
+
133
153
  export interface AgentComposerReference {
134
154
  label: string;
135
155
  icon?: string;
@@ -243,6 +263,14 @@ const SELF_SUBMIT_BUFFER_TTL_MS = 8000;
243
263
  const bufferedSelfSubmits: BufferedSelfSubmit[] = [];
244
264
  const claimedSubmitIds = new Set<string>();
245
265
 
266
+ interface BufferedOpenRequest extends BufferedAgentChatOpenRequest {
267
+ at: number;
268
+ }
269
+
270
+ const OPEN_REQUEST_BUFFER_TTL_MS = 8000;
271
+ const bufferedOpenRequests: BufferedOpenRequest[] = [];
272
+ const claimedOpenRequestIds = new Set<string>();
273
+
246
274
  function pruneSelfSubmitBuffer(now: number): void {
247
275
  for (let i = bufferedSelfSubmits.length - 1; i >= 0; i -= 1) {
248
276
  if (now - bufferedSelfSubmits[i].at > SELF_SUBMIT_BUFFER_TTL_MS) {
@@ -261,6 +289,32 @@ function bufferSelfSubmit(data: Record<string, unknown>): void {
261
289
  bufferedSelfSubmits.push({ id, data, at: now });
262
290
  }
263
291
 
292
+ function pruneOpenRequestBuffer(now: number): void {
293
+ for (let i = bufferedOpenRequests.length - 1; i >= 0; i -= 1) {
294
+ if (now - bufferedOpenRequests[i].at > OPEN_REQUEST_BUFFER_TTL_MS) {
295
+ const [removed] = bufferedOpenRequests.splice(i, 1);
296
+ if (removed) claimedOpenRequestIds.delete(removed.id);
297
+ }
298
+ }
299
+ }
300
+
301
+ function bufferOpenRequest(
302
+ eventType: BufferedAgentChatOpenRequest["eventType"],
303
+ detail: AgentChatOpenThreadRequest | AgentChatOpenTaskRequest,
304
+ ): BufferedOpenRequest {
305
+ const now = Date.now();
306
+ pruneOpenRequestBuffer(now);
307
+ const id = `open-${now}-${Math.random().toString(36).slice(2, 8)}`;
308
+ const entry: BufferedOpenRequest = {
309
+ id,
310
+ eventType,
311
+ detail: { ...detail, openRequestId: id },
312
+ at: now,
313
+ };
314
+ bufferedOpenRequests.push(entry);
315
+ return entry;
316
+ }
317
+
264
318
  /** Unclaimed self-submit payloads, for the panel to replay once it mounts. */
265
319
  export function drainBufferedAgentChatSubmits(): Array<
266
320
  Record<string, unknown>
@@ -279,10 +333,28 @@ export function claimAgentChatSubmit(id: string | undefined): boolean {
279
333
  return true;
280
334
  }
281
335
 
336
+ /** Unclaimed open-thread/task requests, for the panel to replay once it mounts. */
337
+ export function drainBufferedAgentChatOpenRequests(): BufferedAgentChatOpenRequest[] {
338
+ pruneOpenRequestBuffer(Date.now());
339
+ return bufferedOpenRequests
340
+ .filter((entry) => !claimedOpenRequestIds.has(entry.id))
341
+ .map(({ id, eventType, detail }) => ({ id, eventType, detail }));
342
+ }
343
+
344
+ /** Claim an open-thread/task request; false if already handled. Idless events pass. */
345
+ export function claimAgentChatOpenRequest(id: unknown): boolean {
346
+ if (typeof id !== "string" || !id) return true;
347
+ if (claimedOpenRequestIds.has(id)) return false;
348
+ claimedOpenRequestIds.add(id);
349
+ return true;
350
+ }
351
+
282
352
  /** Test-only: reset the self-submit buffer and claim set. */
283
353
  export function _resetAgentChatSubmitBufferForTests(): void {
284
354
  bufferedSelfSubmits.length = 0;
285
355
  claimedSubmitIds.clear();
356
+ bufferedOpenRequests.length = 0;
357
+ claimedOpenRequestIds.clear();
286
358
  }
287
359
 
288
360
  export function normalizeAgentChatContextItem(
@@ -638,6 +710,52 @@ function postAgentChatReferenceMessage(
638
710
  }
639
711
  }
640
712
 
713
+ function openAgentPanelForChat(): void {
714
+ if (typeof window === "undefined") return;
715
+ window.dispatchEvent(
716
+ new CustomEvent("agent-panel:set-mode", {
717
+ detail: { mode: "chat" },
718
+ }),
719
+ );
720
+ window.dispatchEvent(new CustomEvent("agent-panel:open"));
721
+ }
722
+
723
+ function dispatchBufferedOpenRequest(entry: BufferedOpenRequest): void {
724
+ if (typeof window === "undefined") return;
725
+ const dispatch = () => {
726
+ window.dispatchEvent(
727
+ new CustomEvent(entry.eventType, { detail: entry.detail }),
728
+ );
729
+ };
730
+ setTimeout(dispatch, 0);
731
+ }
732
+
733
+ export function requestAgentChatThreadOpen(
734
+ detail: AgentChatOpenThreadRequest,
735
+ ): void {
736
+ if (typeof window === "undefined" || !detail.threadId.trim()) return;
737
+ openAgentPanelForChat();
738
+ dispatchBufferedOpenRequest(
739
+ bufferOpenRequest("agent-chat:open-thread", {
740
+ ...detail,
741
+ threadId: detail.threadId.trim(),
742
+ }),
743
+ );
744
+ }
745
+
746
+ export function requestAgentTaskOpen(detail: AgentChatOpenTaskRequest): void {
747
+ if (typeof window === "undefined" || !detail.threadId.trim()) return;
748
+ openAgentPanelForChat();
749
+ const parentThreadId = detail.parentThreadId?.trim();
750
+ dispatchBufferedOpenRequest(
751
+ bufferOpenRequest("agent-task-open", {
752
+ ...detail,
753
+ threadId: detail.threadId.trim(),
754
+ ...(parentThreadId ? { parentThreadId } : {}),
755
+ }),
756
+ );
757
+ }
758
+
641
759
  function isMcpAppChatBridgeEnabled(): boolean {
642
760
  if (typeof window === "undefined" || window.parent === window) return false;
643
761
  if (readEmbedMcpChatBridgeFlagFromUrl()) markEmbedMcpChatBridgeActive();
@@ -16,12 +16,16 @@ export {
16
16
  normalizeAgentComposerReference,
17
17
  refreshAgentChatContext,
18
18
  removeAgentChatContextItem,
19
+ requestAgentChatThreadOpen,
20
+ requestAgentTaskOpen,
19
21
  sendToAgentChat,
20
22
  parseSubmitChatMessage,
21
23
  setAgentChatContextItem,
22
24
  setContextToAgentChat,
23
25
  generateTabId,
24
26
  type ParsedSubmitChat,
27
+ type AgentChatOpenTaskRequest,
28
+ type AgentChatOpenThreadRequest,
25
29
  type AgentChatContextItem,
26
30
  type AgentChatContextMessage,
27
31
  type AgentChatContextMutationOptions,
@@ -1,4 +1,9 @@
1
- import { useActionQuery, useT } from "@agent-native/core/client";
1
+ import {
2
+ requestAgentChatThreadOpen,
3
+ requestAgentTaskOpen,
4
+ useActionQuery,
5
+ useT,
6
+ } from "@agent-native/core/client";
2
7
  import { AgentToggleButton } from "@agent-native/core/client";
3
8
  import { RunsTray } from "@agent-native/core/client/progress";
4
9
  import { useCallback } from "react";
@@ -50,12 +55,6 @@ export function Header() {
50
55
  const actions = useHeaderActions();
51
56
  const openRunThread = useCallback(
52
57
  (threadId: string, run?: HeaderAgentRun) => {
53
- window.dispatchEvent(
54
- new CustomEvent("agent-panel:set-mode", {
55
- detail: { mode: "chat" },
56
- }),
57
- );
58
- window.dispatchEvent(new CustomEvent("agent-panel:open"));
59
58
  const metadata = run?.metadata ?? {};
60
59
  const parentThreadId =
61
60
  typeof metadata.parentThreadId === "string"
@@ -64,24 +63,18 @@ export function Header() {
64
63
  const isAgentTeam =
65
64
  metadata.kind === "agent-team" || metadata.source === "agent-teams";
66
65
  if (isAgentTeam && parentThreadId && parentThreadId !== threadId) {
67
- window.dispatchEvent(
68
- new CustomEvent("agent-task-open", {
69
- detail: {
70
- threadId,
71
- parentThreadId,
72
- description:
73
- typeof metadata.description === "string"
74
- ? metadata.description
75
- : run?.title || "",
76
- name: typeof metadata.name === "string" ? metadata.name : "",
77
- },
78
- }),
79
- );
66
+ requestAgentTaskOpen({
67
+ threadId,
68
+ parentThreadId,
69
+ description:
70
+ typeof metadata.description === "string"
71
+ ? metadata.description
72
+ : run?.title || "",
73
+ name: typeof metadata.name === "string" ? metadata.name : "",
74
+ });
80
75
  return;
81
76
  }
82
- window.dispatchEvent(
83
- new CustomEvent("agent-chat:open-thread", { detail: { threadId } }),
84
- );
77
+ requestAgentChatThreadOpen({ threadId });
85
78
  },
86
79
  [],
87
80
  );
@@ -15617,11 +15617,13 @@ ${serializedHtml}
15617
15617
  );
15618
15618
 
15619
15619
  const zoomLabel = `${Math.round(zoom)}%`;
15620
- const [zoomMenuOpen, setZoomMenuOpen] = useState(false);
15620
+ const [openZoomControl, setOpenZoomControl] = useState<
15621
+ "toolbar" | "inspector" | null
15622
+ >(null);
15621
15623
  const [zoomInputValue, setZoomInputValue] = useState(zoomLabel);
15622
15624
  useEffect(() => {
15623
- if (!zoomMenuOpen) setZoomInputValue(zoomLabel);
15624
- }, [zoomLabel, zoomMenuOpen]);
15625
+ if (!openZoomControl) setZoomInputValue(zoomLabel);
15626
+ }, [zoomLabel, openZoomControl]);
15625
15627
  const commitZoomInput = useCallback(() => {
15626
15628
  const next = Number(zoomInputValue.replace("%", "").trim());
15627
15629
  if (!Number.isFinite(next)) {
@@ -15629,7 +15631,7 @@ ${serializedHtml}
15629
15631
  return;
15630
15632
  }
15631
15633
  setZoom(Math.max(10, Math.min(500, next)));
15632
- setZoomMenuOpen(false);
15634
+ setOpenZoomControl(null);
15633
15635
  }, [setZoom, zoomInputValue, zoomLabel]);
15634
15636
 
15635
15637
  const handleTokensApplied = useCallback(
@@ -15970,8 +15972,20 @@ ${serializedHtml}
15970
15972
  </span>
15971
15973
  );
15972
15974
 
15973
- const renderZoomControl = () => (
15974
- <DropdownMenu open={zoomMenuOpen} onOpenChange={setZoomMenuOpen}>
15975
+ const renderZoomControl = (controlId: "toolbar" | "inspector") => (
15976
+ <DropdownMenu
15977
+ open={openZoomControl === controlId}
15978
+ onOpenChange={(open) => {
15979
+ if (open) {
15980
+ setZoomInputValue(zoomLabel);
15981
+ setOpenZoomControl(controlId);
15982
+ return;
15983
+ }
15984
+ setOpenZoomControl((current) =>
15985
+ current === controlId ? null : current,
15986
+ );
15987
+ }}
15988
+ >
15975
15989
  <Tooltip>
15976
15990
  <TooltipTrigger asChild>
15977
15991
  <DropdownMenuTrigger asChild>
@@ -16005,7 +16019,7 @@ ${serializedHtml}
16005
16019
  } else if (event.key === "Escape") {
16006
16020
  event.preventDefault();
16007
16021
  setZoomInputValue(zoomLabel);
16008
- setZoomMenuOpen(false);
16022
+ setOpenZoomControl(null);
16009
16023
  }
16010
16024
  }}
16011
16025
  className="h-10 rounded-md border-[var(--design-editor-accent-color)] bg-[var(--design-editor-control-bg)] px-3 text-base font-medium tabular-nums text-foreground shadow-none focus-visible:ring-2 focus-visible:ring-[var(--design-editor-accent-color)]"
@@ -16563,7 +16577,7 @@ ${serializedHtml}
16563
16577
  </DropdownMenuContent>
16564
16578
  </DropdownMenu>
16565
16579
 
16566
- {renderZoomControl()}
16580
+ {renderZoomControl("toolbar")}
16567
16581
 
16568
16582
  <div className="mx-1 h-5 w-px bg-border" />
16569
16583
  </>
@@ -17637,7 +17651,7 @@ ${serializedHtml}
17637
17651
  selectedElements={selectedInspectorElements}
17638
17652
  pageStyles={pageStyles}
17639
17653
  zoom={zoom}
17640
- headerTrailing={renderZoomControl()}
17654
+ headerTrailing={renderZoomControl("inspector")}
17641
17655
  width={rightSidebarWidth}
17642
17656
  activeTab={activeInspectorTab}
17643
17657
  onActiveTabChange={setActiveInspectorTab}
@@ -0,0 +1,6 @@
1
+ ---
2
+ type: fixed
3
+ date: 2026-07-01
4
+ ---
5
+
6
+ Zoom menus in the design editor now open independently from the toolbar and inspector.
@@ -1 +1 @@
1
- {"version":3,"file":"MultiTabAssistantChat.d.ts","sourceRoot":"","sources":["../../src/client/MultiTabAssistantChat.tsx"],"names":[],"mappings":"AASA,OAAO,KAMN,MAAM,OAAO,CAAC;AAoBf,OAAO,EAEL,KAAK,kBAAkB,EAExB,MAAM,oBAAoB,CAAC;AAoB5B,OAAO,EAEL,KAAK,eAAe,EAErB,MAAM,uBAAuB,CAAC;AA8mB/B,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,WAAW,CAAC;IACzC,uDAAuD;IACvD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAsGD,MAAM,WAAW,wBAAwB;IACvC,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,8EAA8E;IAC9E,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,KAAK,MAAM,CAAC;IAC9C,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC;CACpE;AAyED,MAAM,WAAW,gCAAgC;IAC/C,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,+BAA+B;IAC/B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,CAAC;CAClB;AAID,MAAM,MAAM,0BAA0B,GAAG,IAAI,CAC3C,kBAAkB,EAClB,OAAO,GAAG,UAAU,CACrB,GAAG;IACF,sCAAsC;IACtC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,iDAAiD;IACjD,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,gCAAgC,KAAK,KAAK,CAAC,SAAS,CAAC;IAC5E,2DAA2D;IAC3D,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,gCAAgC,KAAK,KAAK,CAAC,SAAS,CAAC;IAC7E,sGAAsG;IACtG,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,yFAAyF;IACzF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4EAA4E;IAC5E,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,mEAAmE;IACnE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,GAAG,wBAAwB,CAAC;IACnD;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IAC/B,qEAAqE;IACrE,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,EACpC,UAAiB,EACjB,YAAY,EACZ,aAAa,EACb,aAAqB,EACrB,MAAqD,EACrD,UAAU,EACV,mBAA0B,EAC1B,YAAY,EACZ,aAAqB,EACrB,KAAY,EACZ,cAAqB,EACrB,GAAG,KAAK,EACT,EAAE,0BAA0B,qBAgwD5B"}
1
+ {"version":3,"file":"MultiTabAssistantChat.d.ts","sourceRoot":"","sources":["../../src/client/MultiTabAssistantChat.tsx"],"names":[],"mappings":"AASA,OAAO,KAMN,MAAM,OAAO,CAAC;AAsBf,OAAO,EAEL,KAAK,kBAAkB,EAExB,MAAM,oBAAoB,CAAC;AAoB5B,OAAO,EAEL,KAAK,eAAe,EAErB,MAAM,uBAAuB,CAAC;AA8mB/B,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,WAAW,CAAC;IACzC,uDAAuD;IACvD,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,qEAAqE;IACrE,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAsGD,MAAM,WAAW,wBAAwB;IACvC,iFAAiF;IACjF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;OAGG;IACH,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,8EAA8E;IAC9E,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,KAAK,MAAM,CAAC;IAC9C,+DAA+D;IAC/D,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE;QAAE,OAAO,CAAC,EAAE,OAAO,CAAA;KAAE,KAAK,IAAI,CAAC;CACpE;AAyED,MAAM,WAAW,gCAAgC;IAC/C,IAAI,EAAE,OAAO,EAAE,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,qBAAqB,EAAE,MAAM,CAAC;IAC9B,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,MAAM,EAAE,MAAM,IAAI,CAAC;IACnB,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,cAAc,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,YAAY,EAAE,MAAM,IAAI,CAAC;IACzB,cAAc,EAAE,MAAM,IAAI,CAAC;IAC3B,+BAA+B;IAC/B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;IAC3B,6EAA6E;IAC7E,QAAQ,EAAE,MAAM,CAAC;CAClB;AAID,MAAM,MAAM,0BAA0B,GAAG,IAAI,CAC3C,kBAAkB,EAClB,OAAO,GAAG,UAAU,CACrB,GAAG;IACF,sCAAsC;IACtC,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,iDAAiD;IACjD,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,gCAAgC,KAAK,KAAK,CAAC,SAAS,CAAC;IAC5E,2DAA2D;IAC3D,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,gCAAgC,KAAK,KAAK,CAAC,SAAS,CAAC;IAC7E,sGAAsG;IACtG,aAAa,CAAC,EAAE,OAAO,CAAC;IACxB,yFAAyF;IACzF,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4EAA4E;IAC5E,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,mEAAmE;IACnE,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB;;;;OAIG;IACH,aAAa,CAAC,EAAE,OAAO,GAAG,wBAAwB,CAAC;IACnD;;;;;;OAMG;IACH,KAAK,CAAC,EAAE,eAAe,GAAG,IAAI,CAAC;IAC/B,qEAAqE;IACrE,cAAc,CAAC,EAAE,OAAO,CAAC;CAC1B,CAAC;AAEF,wBAAgB,qBAAqB,CAAC,EACpC,UAAiB,EACjB,YAAY,EACZ,aAAa,EACb,aAAqB,EACrB,MAAqD,EACrD,UAAU,EACV,mBAA0B,EAC1B,YAAY,EACZ,aAAqB,EACrB,KAAY,EACZ,cAAqB,EACrB,GAAG,KAAK,EACT,EAAE,0BAA0B,qBA6wD5B"}
@@ -3,7 +3,7 @@ import { IconX, IconPlus, IconHistory, IconSearch, IconLink, IconLinkOff, IconCh
3
3
  import { useState, useRef, useEffect, useCallback, useMemo, } from "react";
4
4
  import { DEFAULT_MODEL } from "../agent/default-model.js";
5
5
  import { getReasoningEffortOptionsForModel, isReasoningEffort, } from "../shared/reasoning-effort.js";
6
- import { AGENT_CHAT_CLEAR_CONTEXT_MESSAGE_TYPE, AGENT_CHAT_REMOVE_CONTEXT_MESSAGE_TYPE, AGENT_CHAT_SET_CONTEXT_MESSAGE_TYPE, appendAgentChatContextToMessage, claimAgentChatSubmit, drainBufferedAgentChatSubmits, normalizeAgentChatContextItem, parseSubmitChatMessage, } from "./agent-chat.js";
6
+ import { AGENT_CHAT_CLEAR_CONTEXT_MESSAGE_TYPE, AGENT_CHAT_REMOVE_CONTEXT_MESSAGE_TYPE, AGENT_CHAT_SET_CONTEXT_MESSAGE_TYPE, appendAgentChatContextToMessage, claimAgentChatOpenRequest, claimAgentChatSubmit, drainBufferedAgentChatOpenRequests, drainBufferedAgentChatSubmits, normalizeAgentChatContextItem, parseSubmitChatMessage, } from "./agent-chat.js";
7
7
  import { agentNativePath, appPath } from "./api-path.js";
8
8
  import { AssistantChat, } from "./AssistantChat.js";
9
9
  import { buildChatModelGroups, } from "./chat-model-groups.js";
@@ -1402,7 +1402,9 @@ export function MultiTabAssistantChat({ showTabBar = true, renderHeader, renderO
1402
1402
  const handleOpenThread = (event) => {
1403
1403
  const detail = event.detail;
1404
1404
  const threadId = typeof detail?.threadId === "string" ? detail.threadId : "";
1405
- if (!threadId)
1405
+ if (!detail || !threadId)
1406
+ return;
1407
+ if (!claimAgentChatOpenRequest(detail.openRequestId))
1406
1408
  return;
1407
1409
  if (detail?.newThread === true) {
1408
1410
  newThreadIds.current.add(threadId);
@@ -1445,6 +1447,8 @@ export function MultiTabAssistantChat({ showTabBar = true, renderHeader, renderO
1445
1447
  const threadId = detail?.threadId;
1446
1448
  if (!threadId)
1447
1449
  return;
1450
+ if (!claimAgentChatOpenRequest(detail.openRequestId))
1451
+ return;
1448
1452
  dismissedSubAgentTabsRef.current.delete(threadId);
1449
1453
  // Prefer an explicit parent (RunsTray/background hydration knows it);
1450
1454
  // inline task cards fall back to the active orchestrator thread.
@@ -1490,6 +1494,14 @@ export function MultiTabAssistantChat({ showTabBar = true, renderHeader, renderO
1490
1494
  window.addEventListener("agent-task-open", handleOpenTask);
1491
1495
  return () => window.removeEventListener("agent-task-open", handleOpenTask);
1492
1496
  }, [openTabIds, switchThread, refreshThreads, parentMap]);
1497
+ // Replay thread/task opens requested before this lazy panel's listeners
1498
+ // attached. Live events claim their id; replay drains only unclaimed requests.
1499
+ useEffect(() => {
1500
+ const buffered = drainBufferedAgentChatOpenRequests();
1501
+ for (const request of buffered) {
1502
+ window.dispatchEvent(new CustomEvent(request.eventType, { detail: request.detail }));
1503
+ }
1504
+ }, []);
1493
1505
  // Watch for agent-issued chat-command in application-state
1494
1506
  const lastChatCommandRef = useRef(0);
1495
1507
  useEffect(() => {