@copilotkit/web-inspector 1.62.2 → 1.63.0

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/dist/index.mjs CHANGED
@@ -3,13 +3,13 @@ import inspector_logo_default from "./assets/inspector-logo.mjs";
3
3
  import inspector_logo_icon_default from "./assets/inspector-logo-icon.mjs";
4
4
  import { applyAnchorPosition, centerContext, clampSize, constrainToViewport, keepPositionWithinViewport, updateAnchorFromPosition, updateSizeFromElement } from "./lib/context-helpers.mjs";
5
5
  import { isValidAnchor, isValidDockMode, isValidPosition, isValidSize, loadInspectorState, saveInspectorState } from "./lib/persistence.mjs";
6
- import { TELEMETRY_DOCS_URL, ensureTelemetryDistinctId, getRuntimeUrlType, getTelemetryDistinctIdForUrl, maybeShowDisclosure, trackBannerClicked, trackBannerViewed, trackTalkToEngineerClicked, trackThreadsEmptyEnabledViewed, trackThreadsEnabledViewed, trackThreadsIntelligenceSignupClicked, trackThreadsLockedViewed, trackThreadsTabClicked, trackThreadsTalkToEngineerClicked } from "./lib/telemetry.mjs";
6
+ import { TELEMETRY_DOCS_URL, ensureTelemetryDistinctId, getRuntimeUrlType, getTelemetryDistinctIdForUrl, maybeShowDisclosure, trackBannerClicked, trackBannerViewed, trackMemoriesTabClicked, trackTalkToEngineerClicked, trackThreadsEmptyEnabledViewed, trackThreadsEnabledViewed, trackThreadsExampleSelected, trackThreadsExampleTourCompleted, trackThreadsExampleTourDismissed, trackThreadsExampleTourReopened, trackThreadsExampleTourStarted, trackThreadsExampleTourStepViewed, trackThreadsExampleViewed, trackThreadsIntelligenceSignupClicked, trackThreadsLockedViewed, trackThreadsTabClicked, trackThreadsTalkToEngineerClicked } from "./lib/telemetry.mjs";
7
7
  import { LitElement, css, html, nothing, unsafeCSS } from "lit";
8
8
  import { marked } from "marked";
9
9
  import { styleMap } from "lit/directives/style-map.js";
10
10
  import { unsafeHTML } from "lit/directives/unsafe-html.js";
11
11
  import { icons } from "lucide";
12
- import { CopilotKitCoreRuntimeConnectionStatus, ɵcreateThreadStore, ɵselectThreads, ɵselectThreadsError } from "@copilotkit/core";
12
+ import { CopilotKitCoreRuntimeConnectionStatus, ɵcreateThreadStore, ɵselectMemories, ɵselectMemoriesAvailable, ɵselectMemoriesError, ɵselectMemoriesIsLoading, ɵselectMemoriesRealtimeStatus, ɵselectThreads, ɵselectThreadsError } from "@copilotkit/core";
13
13
 
14
14
  //#region src/index.ts
15
15
  const WEB_INSPECTOR_TAG = "cpk-web-inspector";
@@ -34,7 +34,13 @@ const DOCKED_LEFT_WIDTH = 500;
34
34
  const MAX_AGENT_EVENTS = 200;
35
35
  const MAX_TOTAL_EVENTS = 500;
36
36
  const INTELLIGENCE_SIGNUP_URL = "https://go.copilotkit.ai/intelligence-signup";
37
+ const THREADS_INTELLIGENCE_SIGNIN_URL = "https://dashboard.operations.copilotkit.ai/sign-in";
37
38
  const TALK_TO_ENGINEER_URL = "https://www.copilotkit.ai/talk-to-an-engineer";
39
+ const THREADS_DOCS_URL = "https://docs.copilotkit.ai/threads";
40
+ const SELF_HOSTED_INTELLIGENCE_URL = "https://docs.copilotkit.ai/premium/self-hosting";
41
+ const THREADS_EXAMPLE_OVERVIEW_VIDEO_URL = "https://cdn.copilotkit.ai/corp-site/videos/copilotkit-generative-ui-agentic-frontend-demo.webm";
42
+ const THREADS_EXAMPLE_TOUR_STORAGE_KEY = "cpk:inspector:threads-example-tour:v1";
43
+ const THREADS_EXAMPLE_AGENT_ID = "threads-feature";
38
44
  const AGENT_EVENT_TYPES = [
39
45
  "RUN_STARTED",
40
46
  "RUN_FINISHED",
@@ -60,6 +66,201 @@ const AGENT_EVENT_TYPES = [
60
66
  "ACTIVITY_SNAPSHOT",
61
67
  "ACTIVITY_DELTA"
62
68
  ];
69
+ const THREADS_EXAMPLE_THREADS = [
70
+ {
71
+ id: "example-realtime-sync",
72
+ name: "Realtime thread sync",
73
+ agentId: THREADS_EXAMPLE_AGENT_ID,
74
+ organizationId: "example-organization",
75
+ createdById: "example-user",
76
+ archived: false,
77
+ createdAt: "2026-07-08T16:00:00.000Z",
78
+ updatedAt: "2026-07-08T16:30:00.000Z",
79
+ isExample: true
80
+ },
81
+ {
82
+ id: "example-manage-history",
83
+ name: "Manage saved conversations",
84
+ agentId: THREADS_EXAMPLE_AGENT_ID,
85
+ organizationId: "example-organization",
86
+ createdById: "example-user",
87
+ archived: false,
88
+ createdAt: "2026-07-07T17:45:00.000Z",
89
+ updatedAt: "2026-07-07T18:15:00.000Z",
90
+ isExample: true
91
+ },
92
+ {
93
+ id: "example-inspect-runs",
94
+ name: "Inspect durable run history",
95
+ agentId: THREADS_EXAMPLE_AGENT_ID,
96
+ organizationId: "example-organization",
97
+ createdById: "example-user",
98
+ archived: false,
99
+ createdAt: "2026-07-06T20:15:00.000Z",
100
+ updatedAt: "2026-07-06T20:45:00.000Z",
101
+ isExample: true
102
+ }
103
+ ];
104
+ const THREADS_EXAMPLE_DETAILS = {
105
+ "example-realtime-sync": {
106
+ messages: [{
107
+ id: "example-sync-user",
108
+ role: "user",
109
+ content: "Resume the checkout support thread from yesterday."
110
+ }, {
111
+ id: "example-sync-assistant",
112
+ role: "assistant",
113
+ content: "I found the saved thread, restored the cart state, and continued from the latest user message."
114
+ }],
115
+ events: [
116
+ {
117
+ type: "RUN_STARTED",
118
+ timestamp: "2026-07-08T16:30:00.000Z",
119
+ payload: {
120
+ threadId: "example-realtime-sync",
121
+ agentId: THREADS_EXAMPLE_AGENT_ID
122
+ }
123
+ },
124
+ {
125
+ type: "MESSAGES_SNAPSHOT",
126
+ timestamp: "2026-07-08T16:30:01.000Z",
127
+ payload: {
128
+ messageCount: 6,
129
+ source: "thread-history"
130
+ }
131
+ },
132
+ {
133
+ type: "STATE_SNAPSHOT",
134
+ timestamp: "2026-07-08T16:30:02.000Z",
135
+ payload: {
136
+ cartId: "cart_demo_42",
137
+ checkoutStep: "shipping",
138
+ resumed: true
139
+ }
140
+ },
141
+ {
142
+ type: "RUN_FINISHED",
143
+ timestamp: "2026-07-08T16:30:04.000Z",
144
+ payload: { status: "completed" }
145
+ }
146
+ ],
147
+ state: {
148
+ cartId: "cart_demo_42",
149
+ checkoutStep: "shipping",
150
+ userIntent: "resume_previous_checkout",
151
+ persistedThread: true
152
+ }
153
+ },
154
+ "example-manage-history": {
155
+ messages: [{
156
+ id: "example-history-user",
157
+ role: "user",
158
+ content: "Rename this saved support conversation for the handoff."
159
+ }, {
160
+ id: "example-history-assistant",
161
+ role: "assistant",
162
+ content: "Renamed the thread and kept the prior messages available for the next session."
163
+ }],
164
+ events: [
165
+ {
166
+ type: "RUN_STARTED",
167
+ timestamp: "2026-07-07T18:15:00.000Z",
168
+ payload: {
169
+ threadId: "example-manage-history",
170
+ agentId: THREADS_EXAMPLE_AGENT_ID
171
+ }
172
+ },
173
+ {
174
+ type: "CUSTOM_EVENT",
175
+ timestamp: "2026-07-07T18:15:01.000Z",
176
+ payload: {
177
+ action: "thread_renamed",
178
+ previousName: "Untitled",
179
+ name: "Billing escalation handoff"
180
+ }
181
+ },
182
+ {
183
+ type: "RUN_FINISHED",
184
+ timestamp: "2026-07-07T18:15:03.000Z",
185
+ payload: { status: "completed" }
186
+ }
187
+ ],
188
+ state: {
189
+ name: "Billing escalation handoff",
190
+ savedMessages: 14,
191
+ lastHandoff: "support-team"
192
+ }
193
+ },
194
+ "example-inspect-runs": {
195
+ messages: [{
196
+ id: "example-inspect-user",
197
+ role: "user",
198
+ content: "Why did the assistant recommend the enterprise plan?"
199
+ }, {
200
+ id: "example-inspect-assistant",
201
+ role: "assistant",
202
+ content: "The recommendation came from the account size, SSO requirement, and audit-log constraint in state."
203
+ }],
204
+ events: [
205
+ {
206
+ type: "RUN_STARTED",
207
+ timestamp: "2026-07-06T20:45:00.000Z",
208
+ payload: {
209
+ threadId: "example-inspect-runs",
210
+ agentId: THREADS_EXAMPLE_AGENT_ID
211
+ }
212
+ },
213
+ {
214
+ type: "TOOL_CALL_START",
215
+ timestamp: "2026-07-06T20:45:01.000Z",
216
+ payload: {
217
+ toolCallId: "call_account_lookup",
218
+ toolName: "lookupAccount"
219
+ }
220
+ },
221
+ {
222
+ type: "TOOL_CALL_RESULT",
223
+ timestamp: "2026-07-06T20:45:02.000Z",
224
+ payload: {
225
+ toolCallId: "call_account_lookup",
226
+ seats: 220,
227
+ requiresSso: true
228
+ }
229
+ },
230
+ {
231
+ type: "RUN_FINISHED",
232
+ timestamp: "2026-07-06T20:45:04.000Z",
233
+ payload: { status: "completed" }
234
+ }
235
+ ],
236
+ state: {
237
+ accountTier: "growth",
238
+ seats: 220,
239
+ requiresSso: true,
240
+ auditLogsRequired: true
241
+ }
242
+ }
243
+ };
244
+ const THREADS_EXAMPLE_TOUR_STEPS = [
245
+ {
246
+ tab: "timeline",
247
+ label: "Timeline",
248
+ title: "Read the run as a story",
249
+ body: "The timeline turns messages, tool calls, state changes, and run markers into a scannable debugging trail."
250
+ },
251
+ {
252
+ tab: "raw-events",
253
+ label: "Raw AG-UI Events",
254
+ title: "Drop into the protocol payloads",
255
+ body: "Raw events show the exact AG-UI stream behind the timeline when you need to verify ordering or payload shape."
256
+ },
257
+ {
258
+ tab: "state",
259
+ label: "State",
260
+ title: "Check the durable state",
261
+ body: "The state tab shows the saved values that make a thread resumable across sessions."
262
+ }
263
+ ];
63
264
  function escapeHtml(s) {
64
265
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
65
266
  }
@@ -275,6 +476,11 @@ var CpkThreadList = class extends LitElement {
275
476
  color: #57575b;
276
477
  }
277
478
 
479
+ .cpk-tl__pill--example {
480
+ background: rgba(133, 236, 206, 0.22);
481
+ color: #189370;
482
+ }
483
+
278
484
  /* ── Empty state ── */
279
485
  .cpk-tl__empty {
280
486
  padding: 32px 16px;
@@ -348,6 +554,9 @@ var CpkThreadList = class extends LitElement {
348
554
  </div>
349
555
  <div class="cpk-tl__meta">
350
556
  <span class="cpk-tl__pill">${thread.agentId}</span>
557
+ ${thread.isExample ? html`
558
+ <span class="cpk-tl__pill cpk-tl__pill--example">Example</span>
559
+ ` : nothing}
351
560
  </div>
352
561
  </div>
353
562
  `)}
@@ -571,6 +780,9 @@ var CpkThreadInspector = class CpkThreadInspector extends LitElement {
571
780
  }
572
781
  this.maybeFetchTabData(id);
573
782
  }
783
+ selectTab(id) {
784
+ this.activateTab(id);
785
+ }
574
786
  maybeFetchTabData(id) {
575
787
  if (!this.threadId) return;
576
788
  if ((id === "timeline" || id === "raw-events") && !this._eventsFetched) {
@@ -2627,219 +2839,580 @@ ${unsafeHTML(highlightedJson(stateValue))}</pre
2627
2839
  `;
2628
2840
  }
2629
2841
  };
2630
- var ɵCpkThreadDetails = class extends CpkThreadInspector {};
2631
- if (!customElements.get("cpk-thread-list")) customElements.define("cpk-thread-list", CpkThreadList);
2632
- if (!customElements.get(THREAD_INSPECTOR_TAG)) customElements.define(THREAD_INSPECTOR_TAG, CpkThreadInspector);
2633
- if (!customElements.get("cpk-thread-details")) customElements.define("cpk-thread-details", ɵCpkThreadDetails);
2634
- var WebInspectorElement = class extends LitElement {
2842
+ var CpkMemoryList = class extends LitElement {
2635
2843
  constructor(..._args3) {
2636
2844
  super(..._args3);
2637
- this._core = null;
2638
- this.coreSubscriber = null;
2639
- this.coreUnsubscribe = null;
2640
- this.runtimeStatus = null;
2641
- this.coreProperties = {};
2642
- this.lastCoreError = null;
2643
- this.agentSubscriptions = /* @__PURE__ */ new Map();
2644
- this.agentEvents = /* @__PURE__ */ new Map();
2645
- this.agentMessages = /* @__PURE__ */ new Map();
2646
- this.liveMessageVersion = /* @__PURE__ */ new Map();
2647
- this.agentStates = /* @__PURE__ */ new Map();
2648
- this.flattenedEvents = [];
2649
- this.eventCounter = 0;
2650
- this.contextStore = {};
2651
- this.pointerId = null;
2652
- this.dragStart = null;
2653
- this.dragOffset = {
2654
- x: 0,
2655
- y: 0
2656
- };
2657
- this.isDragging = false;
2658
- this.pointerContext = null;
2659
- this.isOpen = false;
2660
- this.draggedDuringInteraction = false;
2661
- this.ignoreNextButtonClick = false;
2662
- this.selectedMenu = "ag-ui-events";
2663
- this.selectedThreadId = null;
2664
- this.threadListWidth = 290;
2665
- this.threadDividerResizing = false;
2666
- this.threadDividerPointerId = -1;
2667
- this.threadDividerStartX = 0;
2668
- this.threadDividerStartWidth = 0;
2669
- this._threads = [];
2670
- this._threadStoreSubscriptions = /* @__PURE__ */ new Map();
2671
- this._threadsByAgent = /* @__PURE__ */ new Map();
2672
- this._threadsErrorByAgent = /* @__PURE__ */ new Map();
2673
- this._ownedThreadStores = /* @__PURE__ */ new Map();
2674
- this.contextMenuOpen = false;
2675
- this.dockMode = "floating";
2676
- this.previousBodyMargins = null;
2677
- this.transitionTimeoutId = null;
2678
- this.bodyTransitionTimeoutIds = /* @__PURE__ */ new Set();
2679
- this.pendingSelectedContext = null;
2680
- this.autoAttachCore = true;
2681
- this.attemptedAutoAttach = false;
2682
- this.cachedTools = [];
2683
- this.toolSignature = "";
2684
- this.eventFilterText = "";
2685
- this.eventTypeFilter = "all";
2686
- this.evtColWidths = [
2687
- 100,
2688
- 80,
2689
- 150
2690
- ];
2691
- this._evtColResize = null;
2692
- this.announcementHtml = null;
2693
- this.announcementTimestamp = null;
2694
- this.announcementPreviewText = null;
2695
- this.announcementCtaLabel = null;
2696
- this.hasUnseenAnnouncement = false;
2697
- this.announcementLoaded = false;
2698
- this.announcementPromise = null;
2699
- this.showAnnouncementPreview = true;
2700
- this.announcementExpanded = false;
2701
- this.viewedBannerTimestamps = /* @__PURE__ */ new Set();
2702
- this.pendingBannerViewed = null;
2703
- this.clickedBannerIds = /* @__PURE__ */ new Set();
2704
- this.viewedThreadsTelemetryStates = /* @__PURE__ */ new Set();
2705
- this.contextState = {
2706
- button: {
2707
- position: {
2708
- x: EDGE_MARGIN,
2709
- y: EDGE_MARGIN
2710
- },
2711
- size: { ...DEFAULT_BUTTON_SIZE },
2712
- anchor: {
2713
- horizontal: "right",
2714
- vertical: "top"
2715
- },
2716
- anchorOffset: {
2717
- x: EDGE_MARGIN,
2718
- y: EDGE_MARGIN
2719
- }
2720
- },
2721
- window: {
2722
- position: {
2723
- x: EDGE_MARGIN,
2724
- y: EDGE_MARGIN
2725
- },
2726
- size: { ...DEFAULT_WINDOW_SIZE },
2727
- anchor: {
2728
- horizontal: "right",
2729
- vertical: "top"
2730
- },
2731
- anchorOffset: {
2732
- x: EDGE_MARGIN,
2733
- y: EDGE_MARGIN
2734
- }
2735
- }
2736
- };
2737
- this.hasCustomPosition = {
2738
- button: false,
2739
- window: false
2740
- };
2741
- this.resizePointerId = null;
2742
- this.resizeStart = null;
2743
- this.resizeInitialSize = null;
2744
- this.isResizing = false;
2745
- this.customTabIcons = { threads: `<svg class="h-3.5 w-3.5" width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M9.04167 15C8.29167 15 7.65972 14.7431 7.14583 14.2292C6.63194 13.7153 6.375 13.0972 6.375 12.375C6.375 11.3194 6.80208 10.3646 7.65625 9.51042C8.51042 8.65625 9.57639 8.125 10.8542 7.91667C10.8125 7.41667 10.6875 7.03819 10.4792 6.78125C10.2708 6.52431 9.98611 6.39583 9.625 6.39583C9.20833 6.39583 8.75694 6.56944 8.27083 6.91667C7.78472 7.26389 7.20833 7.83333 6.54167 8.625C5.45833 9.91667 4.66319 10.7569 4.15625 11.1458C3.64931 11.5347 3.10417 11.7292 2.52083 11.7292C1.8125 11.7292 1.21528 11.4653 0.729167 10.9375C0.243056 10.4097 0 9.77083 0 9.02083C0 8.27083 0.163194 7.50347 0.489583 6.71875C0.815972 5.93403 1.36806 4.99306 2.14583 3.89583C2.40972 3.53472 2.60417 3.22917 2.72917 2.97917C2.85417 2.72917 2.91667 2.52778 2.91667 2.375C2.91667 2.27778 2.89931 2.20486 2.86458 2.15625C2.82986 2.10764 2.77778 2.08333 2.70833 2.08333C2.56944 2.08333 2.39583 2.17014 2.1875 2.34375C1.97917 2.51736 1.73611 2.78472 1.45833 3.14583L0 1.66667C0.444444 1.125 0.895833 0.711806 1.35417 0.427083C1.8125 0.142361 2.26389 0 2.70833 0C3.34722 0 3.88889 0.222222 4.33333 0.666667C4.77778 1.11111 5 1.66667 5 2.33333C5 2.73611 4.89583 3.18056 4.6875 3.66667C4.47917 4.15278 4.13194 4.73611 3.64583 5.41667C3.11806 6.16667 2.72569 6.82639 2.46875 7.39583C2.21181 7.96528 2.08333 8.46528 2.08333 8.89583C2.08333 9.13194 2.12153 9.31597 2.19792 9.44792C2.27431 9.57986 2.38194 9.64583 2.52083 9.64583C2.65972 9.64583 2.78125 9.60764 2.88542 9.53125C2.98958 9.45486 3.18056 9.27083 3.45833 8.97917C3.63889 8.78472 3.85417 8.54514 4.10417 8.26042C4.35417 7.97569 4.65972 7.625 5.02083 7.20833C5.89583 6.16667 6.6875 5.42361 7.39583 4.97917C8.10417 4.53472 8.84722 4.3125 9.625 4.3125C10.5556 4.3125 11.3194 4.625 11.9167 5.25C12.5139 5.875 12.8542 6.72917 12.9375 7.8125H15V9.89583H12.9375C12.8264 11.4514 12.4201 12.691 11.7188 13.6146C11.0174 14.5382 10.125 15 9.04167 15ZM9.08333 12.9167C9.52778 12.9167 9.90278 12.6632 10.2083 12.1562C10.5139 11.6493 10.7222 10.9444 10.8333 10.0417C10.1944 10.1944 9.63889 10.4965 9.16667 10.9479C8.69444 11.3993 8.45833 11.8472 8.45833 12.2917C8.45833 12.4861 8.51389 12.6389 8.625 12.75C8.73611 12.8611 8.88889 12.9167 9.08333 12.9167Z" fill="currentColor"/></svg>` };
2746
- this.handlePointerDown = (event) => {
2747
- if (this.dockMode !== "floating" && this.isOpen) return;
2748
- const target = event.currentTarget;
2749
- const context = target?.dataset.dragContext === "window" ? "window" : "button";
2750
- const eventTarget = event.target;
2751
- if (context === "window" && eventTarget?.closest("button")) return;
2752
- this.pointerContext = context;
2753
- this.measureContext(context);
2754
- event.preventDefault();
2755
- this.pointerId = event.pointerId;
2756
- this.dragStart = {
2757
- x: event.clientX,
2758
- y: event.clientY
2759
- };
2760
- const state = this.contextState[context];
2761
- this.dragOffset = {
2762
- x: event.clientX - state.position.x,
2763
- y: event.clientY - state.position.y
2764
- };
2765
- this.isDragging = false;
2766
- this.draggedDuringInteraction = false;
2767
- this.ignoreNextButtonClick = false;
2768
- target?.setPointerCapture?.(this.pointerId);
2769
- };
2770
- this.handlePointerMove = (event) => {
2771
- if (this.pointerId !== event.pointerId || !this.dragStart || !this.pointerContext) return;
2772
- const distance = Math.hypot(event.clientX - this.dragStart.x, event.clientY - this.dragStart.y);
2773
- if (!this.isDragging && distance < DRAG_THRESHOLD) return;
2774
- event.preventDefault();
2775
- this.setDragging(true);
2776
- this.draggedDuringInteraction = true;
2777
- const desired = {
2778
- x: event.clientX - this.dragOffset.x,
2779
- y: event.clientY - this.dragOffset.y
2780
- };
2781
- const constrained = this.constrainToViewport(desired, this.pointerContext);
2782
- this.contextState[this.pointerContext].position = constrained;
2783
- this.updateHostTransform(this.pointerContext);
2784
- };
2785
- this.handlePointerUp = (event) => {
2786
- if (this.pointerId !== event.pointerId) return;
2787
- const target = event.currentTarget;
2788
- if (target?.hasPointerCapture(this.pointerId)) target.releasePointerCapture(this.pointerId);
2789
- const context = this.pointerContext ?? this.activeContext;
2790
- if (this.isDragging && this.pointerContext) {
2791
- event.preventDefault();
2792
- this.setDragging(false);
2793
- if (this.pointerContext === "window") {
2794
- this.updateAnchorFromPosition(this.pointerContext);
2795
- this.hasCustomPosition.window = true;
2796
- this.applyAnchorPosition(this.pointerContext);
2797
- } else if (this.pointerContext === "button") {
2798
- this.snapButtonToCorner();
2799
- this.hasCustomPosition.button = true;
2800
- if (this.draggedDuringInteraction) this.ignoreNextButtonClick = true;
2801
- }
2802
- } else if (context === "button" && !this.isOpen && !this.draggedDuringInteraction) this.openInspector();
2803
- this.resetPointerTracking();
2804
- };
2805
- this.handlePointerCancel = (event) => {
2806
- if (this.pointerId !== event.pointerId) return;
2807
- const target = event.currentTarget;
2808
- if (target?.hasPointerCapture(this.pointerId)) target.releasePointerCapture(this.pointerId);
2809
- this.resetPointerTracking();
2810
- };
2811
- this.handleButtonClick = (event) => {
2812
- if (this.isDragging) {
2813
- event.preventDefault();
2814
- return;
2815
- }
2816
- if (this.ignoreNextButtonClick) {
2817
- event.preventDefault();
2818
- this.ignoreNextButtonClick = false;
2819
- return;
2820
- }
2821
- if (!this.isOpen) {
2822
- event.preventDefault();
2823
- this.openInspector();
2824
- }
2845
+ this.memories = [];
2846
+ this.search = "";
2847
+ this.kind = "all";
2848
+ this.onSearchInput = (event) => {
2849
+ this.search = event.target.value;
2825
2850
  };
2826
- this.handleClosePointerDown = (event) => {
2827
- event.stopPropagation();
2828
- event.preventDefault();
2851
+ this.onKindClick = (event) => {
2852
+ const seg = event.target.closest("[data-kind]");
2853
+ if (!seg) return;
2854
+ this.kind = seg.dataset["kind"];
2829
2855
  };
2830
- this.handleCloseClick = () => {
2831
- this.closeInspector();
2856
+ }
2857
+ static {
2858
+ this.properties = {
2859
+ memories: { attribute: false },
2860
+ search: { state: true },
2861
+ kind: { state: true }
2832
2862
  };
2833
- this.handleResizePointerDown = (event) => {
2834
- event.stopPropagation();
2835
- event.preventDefault();
2836
- this.hasCustomPosition.window = true;
2837
- this.isResizing = true;
2838
- this.resizePointerId = event.pointerId;
2839
- this.resizeStart = {
2840
- x: event.clientX,
2841
- y: event.clientY
2842
- };
2863
+ }
2864
+ static {
2865
+ this.styles = css`
2866
+ @import url("https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600&family=Spline+Sans+Mono:wght@400;500&display=swap");
2867
+
2868
+ :host {
2869
+ display: flex;
2870
+ flex-direction: column;
2871
+ height: 100%;
2872
+ overflow: hidden;
2873
+ }
2874
+
2875
+ .cpk-ml {
2876
+ font-family: "Plus Jakarta Sans", sans-serif;
2877
+ display: flex;
2878
+ flex-direction: column;
2879
+ height: 100%;
2880
+ overflow: hidden;
2881
+ background: #f7f7f9;
2882
+ }
2883
+
2884
+ /* ── Search ── */
2885
+ .cpk-ml__search {
2886
+ padding: 10px 12px;
2887
+ border-bottom: 1px solid #dbdbe5;
2888
+ flex-shrink: 0;
2889
+ }
2890
+
2891
+ .cpk-ml__search-input {
2892
+ width: 100%;
2893
+ box-sizing: border-box;
2894
+ font-family: "Plus Jakarta Sans", sans-serif;
2895
+ font-size: 12px;
2896
+ padding: 7px 10px;
2897
+ border-radius: 6px;
2898
+ border: 1px solid #dbdbe5;
2899
+ background: #ffffff;
2900
+ color: #010507;
2901
+ outline: none;
2902
+ transition: border-color 0.15s;
2903
+ }
2904
+
2905
+ .cpk-ml__search-input:focus {
2906
+ border-color: #bec2ff;
2907
+ }
2908
+
2909
+ /* ── Kind filter ── */
2910
+ .cpk-ml__filter {
2911
+ display: flex;
2912
+ gap: 4px;
2913
+ padding: 8px 12px;
2914
+ border-bottom: 1px solid #dbdbe5;
2915
+ flex-shrink: 0;
2916
+ flex-wrap: wrap;
2917
+ }
2918
+
2919
+ .cpk-ml__filter-seg {
2920
+ font-family: "Plus Jakarta Sans", sans-serif;
2921
+ font-size: 11px;
2922
+ font-weight: 500;
2923
+ padding: 3px 9px;
2924
+ border-radius: 5px;
2925
+ border: 1px solid #dbdbe5;
2926
+ background: #ffffff;
2927
+ color: #57575b;
2928
+ cursor: pointer;
2929
+ transition:
2930
+ background 0.1s,
2931
+ border-color 0.1s,
2932
+ color 0.1s;
2933
+ user-select: none;
2934
+ }
2935
+
2936
+ .cpk-ml__filter-seg:hover {
2937
+ background: #f0f0f5;
2938
+ }
2939
+
2940
+ .cpk-ml__filter-seg--active {
2941
+ background: #bec2ff1a;
2942
+ border-color: #bec2ff;
2943
+ color: #010507;
2944
+ }
2945
+
2946
+ .cpk-ml__filter-count {
2947
+ font-family: "Spline Sans Mono", monospace;
2948
+ font-size: 9px;
2949
+ margin-left: 4px;
2950
+ color: #838389;
2951
+ }
2952
+
2953
+ /* ── List ── */
2954
+ .cpk-ml__list {
2955
+ flex: 1;
2956
+ overflow-y: auto;
2957
+ padding: 8px 12px;
2958
+ display: flex;
2959
+ flex-direction: column;
2960
+ gap: 8px;
2961
+ }
2962
+
2963
+ /* ── Card ── */
2964
+ .cpk-ml__card {
2965
+ background: #ffffff;
2966
+ border: 1px solid #e9e9ef;
2967
+ border-radius: 8px;
2968
+ padding: 10px 12px;
2969
+ display: flex;
2970
+ flex-direction: column;
2971
+ gap: 6px;
2972
+ }
2973
+
2974
+ .cpk-ml__card-badges {
2975
+ display: flex;
2976
+ gap: 6px;
2977
+ align-items: center;
2978
+ flex-wrap: wrap;
2979
+ }
2980
+
2981
+ /* Kind badge — color per kind */
2982
+ .cpk-ml__kind-badge {
2983
+ font-family: "Spline Sans Mono", monospace;
2984
+ font-size: 9px;
2985
+ padding: 1px 7px;
2986
+ border-radius: 4px;
2987
+ text-transform: uppercase;
2988
+ font-weight: 500;
2989
+ white-space: nowrap;
2990
+ }
2991
+
2992
+ .cpk-ml__kind-badge--topical {
2993
+ background: #eee6fe;
2994
+ color: #57575b;
2995
+ }
2996
+
2997
+ .cpk-ml__kind-badge--episodic {
2998
+ background: #e6f4fe;
2999
+ color: #2d5f80;
3000
+ }
3001
+
3002
+ .cpk-ml__kind-badge--operational {
3003
+ background: #e6feee;
3004
+ color: #2d6645;
3005
+ }
3006
+
3007
+ /* Scope badge */
3008
+ .cpk-ml__scope-badge {
3009
+ font-family: "Spline Sans Mono", monospace;
3010
+ font-size: 9px;
3011
+ padding: 1px 7px;
3012
+ border-radius: 4px;
3013
+ text-transform: uppercase;
3014
+ font-weight: 500;
3015
+ white-space: nowrap;
3016
+ background: #f0f0f5;
3017
+ color: #838389;
3018
+ }
3019
+
3020
+ /* Content */
3021
+ .cpk-ml__content {
3022
+ font-size: 12px;
3023
+ color: #010507;
3024
+ line-height: 1.5;
3025
+ word-break: break-word;
3026
+ }
3027
+
3028
+ /* Footer */
3029
+ .cpk-ml__footer {
3030
+ display: flex;
3031
+ align-items: center;
3032
+ justify-content: space-between;
3033
+ gap: 8px;
3034
+ margin-top: 2px;
3035
+ }
3036
+
3037
+ .cpk-ml__footer-threads {
3038
+ font-size: 10px;
3039
+ color: #838389;
3040
+ }
3041
+
3042
+ .cpk-ml__footer-id {
3043
+ font-family: "Spline Sans Mono", monospace;
3044
+ font-size: 9px;
3045
+ color: #c0c0c8;
3046
+ }
3047
+
3048
+ /* ── Empty state ── */
3049
+ .cpk-ml__empty {
3050
+ padding: 32px 16px;
3051
+ text-align: center;
3052
+ color: #838389;
3053
+ font-size: 12px;
3054
+ display: flex;
3055
+ flex-direction: column;
3056
+ align-items: center;
3057
+ gap: 8px;
3058
+ }
3059
+
3060
+ .cpk-ml__empty-icon {
3061
+ color: #c0c0c8;
3062
+ }
3063
+ `;
3064
+ }
3065
+ /** Memories that pass the current text search (before kind filter). */
3066
+ get searchFiltered() {
3067
+ const q = this.search.trim().toLowerCase();
3068
+ if (!q) return this.memories;
3069
+ return this.memories.filter((m) => m.content.toLowerCase().includes(q));
3070
+ }
3071
+ /** Memories that pass both search and kind filter. */
3072
+ get filtered() {
3073
+ const searched = this.searchFiltered;
3074
+ if (this.kind === "all") return searched;
3075
+ return searched.filter((m) => m.kind === this.kind);
3076
+ }
3077
+ /** Count of search-filtered memories for a given kind (for segment labels). */
3078
+ countForKind(kind) {
3079
+ return this.searchFiltered.filter((m) => m.kind === kind).length;
3080
+ }
3081
+ /** Truncate an id to first-4…last-4 characters. */
3082
+ shortId(id) {
3083
+ if (id.length <= 12) return id;
3084
+ return `${id.slice(0, 4)}…${id.slice(-4)}`;
3085
+ }
3086
+ renderKindBadge(kind) {
3087
+ return html`<span class="cpk-ml__kind-badge cpk-ml__kind-badge--${kind}"
3088
+ >${kind}</span
3089
+ >`;
3090
+ }
3091
+ renderEmpty() {
3092
+ const q = this.search.trim();
3093
+ if (this.memories.length === 0) return html`
3094
+ <div class="cpk-ml__empty">
3095
+ <svg
3096
+ width="24"
3097
+ height="24"
3098
+ viewBox="0 0 24 24"
3099
+ fill="none"
3100
+ stroke="currentColor"
3101
+ stroke-width="1.5"
3102
+ stroke-linecap="round"
3103
+ stroke-linejoin="round"
3104
+ class="cpk-ml__empty-icon"
3105
+ >
3106
+ <ellipse cx="12" cy="5" rx="9" ry="3" />
3107
+ <path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3" />
3108
+ <path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5" />
3109
+ </svg>
3110
+ No memories yet — tell the agent a durable fact and watch it appear.
3111
+ </div>
3112
+ `;
3113
+ if (q) return html`
3114
+ <div class="cpk-ml__empty">
3115
+ No memories match &ldquo;${q}&rdquo;.
3116
+ </div>
3117
+ `;
3118
+ return html`
3119
+ <div class="cpk-ml__empty">No ${this.kind} memories yet.</div>
3120
+ `;
3121
+ }
3122
+ render() {
3123
+ const filtered = this.filtered;
3124
+ return html`
3125
+ <div class="cpk-ml">
3126
+ <!-- Search -->
3127
+ <div class="cpk-ml__search">
3128
+ <input
3129
+ type="text"
3130
+ placeholder="Search memories…"
3131
+ .value=${this.search}
3132
+ @input=${this.onSearchInput}
3133
+ class="cpk-ml__search-input"
3134
+ />
3135
+ </div>
3136
+
3137
+ <!-- Kind filter -->
3138
+ <div class="cpk-ml__filter" @click=${this.onKindClick}>
3139
+ <button
3140
+ class="cpk-ml__filter-seg ${this.kind === "all" ? "cpk-ml__filter-seg--active" : ""}"
3141
+ data-kind="all"
3142
+ >
3143
+ All<span class="cpk-ml__filter-count">${this.searchFiltered.length}</span>
3144
+ </button>
3145
+ ${[
3146
+ "topical",
3147
+ "episodic",
3148
+ "operational"
3149
+ ].map((k) => html`
3150
+ <button
3151
+ class="cpk-ml__filter-seg ${this.kind === k ? "cpk-ml__filter-seg--active" : ""}"
3152
+ data-kind="${k}"
3153
+ >
3154
+ ${k}<span class="cpk-ml__filter-count">${this.countForKind(k)}</span>
3155
+ </button>
3156
+ `)}
3157
+ </div>
3158
+
3159
+ <!-- Memory list -->
3160
+ <div class="cpk-ml__list">
3161
+ ${filtered.map((m) => html`
3162
+ <div class="cpk-ml__card">
3163
+ <div class="cpk-ml__card-badges">
3164
+ ${this.renderKindBadge(m.kind)}
3165
+ <span class="cpk-ml__scope-badge">${m.scope}</span>
3166
+ </div>
3167
+ <div class="cpk-ml__content">${m.content}</div>
3168
+ <div class="cpk-ml__footer">
3169
+ <span class="cpk-ml__footer-threads"
3170
+ >${m.sourceThreadIds.length} source thread${m.sourceThreadIds.length === 1 ? "" : "s"}</span
3171
+ >
3172
+ <span class="cpk-ml__footer-id">${this.shortId(m.id)}</span>
3173
+ </div>
3174
+ </div>
3175
+ `)}
3176
+ ${filtered.length === 0 ? this.renderEmpty() : nothing}
3177
+ </div>
3178
+ </div>
3179
+ `;
3180
+ }
3181
+ };
3182
+ var ɵCpkThreadDetails = class extends CpkThreadInspector {};
3183
+ if (!customElements.get("cpk-thread-list")) customElements.define("cpk-thread-list", CpkThreadList);
3184
+ if (!customElements.get(THREAD_INSPECTOR_TAG)) customElements.define(THREAD_INSPECTOR_TAG, CpkThreadInspector);
3185
+ if (!customElements.get("cpk-thread-details")) customElements.define("cpk-thread-details", ɵCpkThreadDetails);
3186
+ if (!customElements.get("cpk-memory-list")) customElements.define("cpk-memory-list", CpkMemoryList);
3187
+ var WebInspectorElement = class extends LitElement {
3188
+ constructor(..._args4) {
3189
+ super(..._args4);
3190
+ this._core = null;
3191
+ this.coreSubscriber = null;
3192
+ this.coreUnsubscribe = null;
3193
+ this._memories = [];
3194
+ this._memoriesLoading = false;
3195
+ this._memoriesError = null;
3196
+ this._memoriesAvailable = true;
3197
+ this._memoriesRealtimeStatus = "connecting";
3198
+ this._memoryUnsub = null;
3199
+ this._memorySubscribed = false;
3200
+ this._memoryStoreUnsupported = false;
3201
+ this.runtimeStatus = null;
3202
+ this.coreProperties = {};
3203
+ this.lastCoreError = null;
3204
+ this.agentSubscriptions = /* @__PURE__ */ new Map();
3205
+ this.agentEvents = /* @__PURE__ */ new Map();
3206
+ this.agentMessages = /* @__PURE__ */ new Map();
3207
+ this.liveMessageVersion = /* @__PURE__ */ new Map();
3208
+ this.agentStates = /* @__PURE__ */ new Map();
3209
+ this.flattenedEvents = [];
3210
+ this.eventCounter = 0;
3211
+ this.contextStore = {};
3212
+ this.pointerId = null;
3213
+ this.dragStart = null;
3214
+ this.dragOffset = {
3215
+ x: 0,
3216
+ y: 0
3217
+ };
3218
+ this.isDragging = false;
3219
+ this.pointerContext = null;
3220
+ this.isOpen = false;
3221
+ this.draggedDuringInteraction = false;
3222
+ this.ignoreNextButtonClick = false;
3223
+ this.selectedMenu = "ag-ui-events";
3224
+ this.selectedThreadId = null;
3225
+ this.threadListWidth = 290;
3226
+ this.threadDividerResizing = false;
3227
+ this.threadDividerPointerId = -1;
3228
+ this.threadDividerStartX = 0;
3229
+ this.threadDividerStartWidth = 0;
3230
+ this._threads = [];
3231
+ this._threadStoreSubscriptions = /* @__PURE__ */ new Map();
3232
+ this._threadsByAgent = /* @__PURE__ */ new Map();
3233
+ this._threadsErrorByAgent = /* @__PURE__ */ new Map();
3234
+ this._ownedThreadStores = /* @__PURE__ */ new Map();
3235
+ this.contextMenuOpen = false;
3236
+ this.dockMode = "floating";
3237
+ this.previousBodyMargins = null;
3238
+ this.transitionTimeoutId = null;
3239
+ this.bodyTransitionTimeoutIds = /* @__PURE__ */ new Set();
3240
+ this.pendingSelectedContext = null;
3241
+ this.autoAttachCore = true;
3242
+ this.attemptedAutoAttach = false;
3243
+ this.cachedTools = [];
3244
+ this.toolSignature = "";
3245
+ this.eventFilterText = "";
3246
+ this.eventTypeFilter = "all";
3247
+ this.evtColWidths = [
3248
+ 100,
3249
+ 80,
3250
+ 150
3251
+ ];
3252
+ this._evtColResize = null;
3253
+ this.announcementHtml = null;
3254
+ this.announcementTimestamp = null;
3255
+ this.announcementPreviewText = null;
3256
+ this.announcementCtaLabel = null;
3257
+ this.hasUnseenAnnouncement = false;
3258
+ this.announcementLoaded = false;
3259
+ this.announcementPromise = null;
3260
+ this.showAnnouncementPreview = true;
3261
+ this.announcementExpanded = false;
3262
+ this.viewedBannerTimestamps = /* @__PURE__ */ new Set();
3263
+ this.pendingBannerViewed = null;
3264
+ this.clickedBannerIds = /* @__PURE__ */ new Set();
3265
+ this.viewedThreadsTelemetryStates = /* @__PURE__ */ new Set();
3266
+ this.viewedExampleThreadIds = /* @__PURE__ */ new Set();
3267
+ this.selectedExampleThreadIds = /* @__PURE__ */ new Set();
3268
+ this.viewedExampleTourSteps = /* @__PURE__ */ new Set();
3269
+ this.exampleThreadProviders = /* @__PURE__ */ new Map();
3270
+ this.exampleTourDismissed = false;
3271
+ this.exampleTourActive = false;
3272
+ this.exampleTourStep = 0;
3273
+ this.exampleTourAutoShown = false;
3274
+ this.threadsExampleOverviewVideoShouldLoad = false;
3275
+ this.threadsExampleOverviewVideoReady = false;
3276
+ this.threadsExampleOverviewVideoLoadTimer = null;
3277
+ this.threadsExampleOverviewVideoIdleCallbackId = null;
3278
+ this.contextState = {
3279
+ button: {
3280
+ position: {
3281
+ x: EDGE_MARGIN,
3282
+ y: EDGE_MARGIN
3283
+ },
3284
+ size: { ...DEFAULT_BUTTON_SIZE },
3285
+ anchor: {
3286
+ horizontal: "right",
3287
+ vertical: "top"
3288
+ },
3289
+ anchorOffset: {
3290
+ x: EDGE_MARGIN,
3291
+ y: EDGE_MARGIN
3292
+ }
3293
+ },
3294
+ window: {
3295
+ position: {
3296
+ x: EDGE_MARGIN,
3297
+ y: EDGE_MARGIN
3298
+ },
3299
+ size: { ...DEFAULT_WINDOW_SIZE },
3300
+ anchor: {
3301
+ horizontal: "right",
3302
+ vertical: "top"
3303
+ },
3304
+ anchorOffset: {
3305
+ x: EDGE_MARGIN,
3306
+ y: EDGE_MARGIN
3307
+ }
3308
+ }
3309
+ };
3310
+ this.hasCustomPosition = {
3311
+ button: false,
3312
+ window: false
3313
+ };
3314
+ this.resizePointerId = null;
3315
+ this.resizeStart = null;
3316
+ this.resizeInitialSize = null;
3317
+ this.isResizing = false;
3318
+ this.customTabIcons = { threads: `<svg class="h-3.5 w-3.5" width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M9.04167 15C8.29167 15 7.65972 14.7431 7.14583 14.2292C6.63194 13.7153 6.375 13.0972 6.375 12.375C6.375 11.3194 6.80208 10.3646 7.65625 9.51042C8.51042 8.65625 9.57639 8.125 10.8542 7.91667C10.8125 7.41667 10.6875 7.03819 10.4792 6.78125C10.2708 6.52431 9.98611 6.39583 9.625 6.39583C9.20833 6.39583 8.75694 6.56944 8.27083 6.91667C7.78472 7.26389 7.20833 7.83333 6.54167 8.625C5.45833 9.91667 4.66319 10.7569 4.15625 11.1458C3.64931 11.5347 3.10417 11.7292 2.52083 11.7292C1.8125 11.7292 1.21528 11.4653 0.729167 10.9375C0.243056 10.4097 0 9.77083 0 9.02083C0 8.27083 0.163194 7.50347 0.489583 6.71875C0.815972 5.93403 1.36806 4.99306 2.14583 3.89583C2.40972 3.53472 2.60417 3.22917 2.72917 2.97917C2.85417 2.72917 2.91667 2.52778 2.91667 2.375C2.91667 2.27778 2.89931 2.20486 2.86458 2.15625C2.82986 2.10764 2.77778 2.08333 2.70833 2.08333C2.56944 2.08333 2.39583 2.17014 2.1875 2.34375C1.97917 2.51736 1.73611 2.78472 1.45833 3.14583L0 1.66667C0.444444 1.125 0.895833 0.711806 1.35417 0.427083C1.8125 0.142361 2.26389 0 2.70833 0C3.34722 0 3.88889 0.222222 4.33333 0.666667C4.77778 1.11111 5 1.66667 5 2.33333C5 2.73611 4.89583 3.18056 4.6875 3.66667C4.47917 4.15278 4.13194 4.73611 3.64583 5.41667C3.11806 6.16667 2.72569 6.82639 2.46875 7.39583C2.21181 7.96528 2.08333 8.46528 2.08333 8.89583C2.08333 9.13194 2.12153 9.31597 2.19792 9.44792C2.27431 9.57986 2.38194 9.64583 2.52083 9.64583C2.65972 9.64583 2.78125 9.60764 2.88542 9.53125C2.98958 9.45486 3.18056 9.27083 3.45833 8.97917C3.63889 8.78472 3.85417 8.54514 4.10417 8.26042C4.35417 7.97569 4.65972 7.625 5.02083 7.20833C5.89583 6.16667 6.6875 5.42361 7.39583 4.97917C8.10417 4.53472 8.84722 4.3125 9.625 4.3125C10.5556 4.3125 11.3194 4.625 11.9167 5.25C12.5139 5.875 12.8542 6.72917 12.9375 7.8125H15V9.89583H12.9375C12.8264 11.4514 12.4201 12.691 11.7188 13.6146C11.0174 14.5382 10.125 15 9.04167 15ZM9.08333 12.9167C9.52778 12.9167 9.90278 12.6632 10.2083 12.1562C10.5139 11.6493 10.7222 10.9444 10.8333 10.0417C10.1944 10.1944 9.63889 10.4965 9.16667 10.9479C8.69444 11.3993 8.45833 11.8472 8.45833 12.2917C8.45833 12.4861 8.51389 12.6389 8.625 12.75C8.73611 12.8611 8.88889 12.9167 9.08333 12.9167Z" fill="currentColor"/></svg>` };
3319
+ this.handlePointerDown = (event) => {
3320
+ if (this.dockMode !== "floating" && this.isOpen) return;
3321
+ const target = event.currentTarget;
3322
+ const context = target?.dataset.dragContext === "window" ? "window" : "button";
3323
+ const eventTarget = event.target;
3324
+ if (context === "window" && eventTarget?.closest("button")) return;
3325
+ this.pointerContext = context;
3326
+ this.measureContext(context);
3327
+ event.preventDefault();
3328
+ this.pointerId = event.pointerId;
3329
+ this.dragStart = {
3330
+ x: event.clientX,
3331
+ y: event.clientY
3332
+ };
3333
+ const state = this.contextState[context];
3334
+ this.dragOffset = {
3335
+ x: event.clientX - state.position.x,
3336
+ y: event.clientY - state.position.y
3337
+ };
3338
+ this.isDragging = false;
3339
+ this.draggedDuringInteraction = false;
3340
+ this.ignoreNextButtonClick = false;
3341
+ target?.setPointerCapture?.(this.pointerId);
3342
+ };
3343
+ this.handlePointerMove = (event) => {
3344
+ if (this.pointerId !== event.pointerId || !this.dragStart || !this.pointerContext) return;
3345
+ const distance = Math.hypot(event.clientX - this.dragStart.x, event.clientY - this.dragStart.y);
3346
+ if (!this.isDragging && distance < DRAG_THRESHOLD) return;
3347
+ event.preventDefault();
3348
+ this.setDragging(true);
3349
+ this.draggedDuringInteraction = true;
3350
+ const desired = {
3351
+ x: event.clientX - this.dragOffset.x,
3352
+ y: event.clientY - this.dragOffset.y
3353
+ };
3354
+ const constrained = this.constrainToViewport(desired, this.pointerContext);
3355
+ this.contextState[this.pointerContext].position = constrained;
3356
+ this.updateHostTransform(this.pointerContext);
3357
+ };
3358
+ this.handlePointerUp = (event) => {
3359
+ if (this.pointerId !== event.pointerId) return;
3360
+ const target = event.currentTarget;
3361
+ if (target?.hasPointerCapture(this.pointerId)) target.releasePointerCapture(this.pointerId);
3362
+ const context = this.pointerContext ?? this.activeContext;
3363
+ if (this.isDragging && this.pointerContext) {
3364
+ event.preventDefault();
3365
+ this.setDragging(false);
3366
+ if (this.pointerContext === "window") {
3367
+ this.updateAnchorFromPosition(this.pointerContext);
3368
+ this.hasCustomPosition.window = true;
3369
+ this.applyAnchorPosition(this.pointerContext);
3370
+ } else if (this.pointerContext === "button") {
3371
+ this.snapButtonToCorner();
3372
+ this.hasCustomPosition.button = true;
3373
+ if (this.draggedDuringInteraction) this.ignoreNextButtonClick = true;
3374
+ }
3375
+ } else if (context === "button" && !this.isOpen && !this.draggedDuringInteraction) this.openInspector();
3376
+ this.resetPointerTracking();
3377
+ };
3378
+ this.handlePointerCancel = (event) => {
3379
+ if (this.pointerId !== event.pointerId) return;
3380
+ const target = event.currentTarget;
3381
+ if (target?.hasPointerCapture(this.pointerId)) target.releasePointerCapture(this.pointerId);
3382
+ this.resetPointerTracking();
3383
+ };
3384
+ this.handleButtonClick = (event) => {
3385
+ if (this.isDragging) {
3386
+ event.preventDefault();
3387
+ return;
3388
+ }
3389
+ if (this.ignoreNextButtonClick) {
3390
+ event.preventDefault();
3391
+ this.ignoreNextButtonClick = false;
3392
+ return;
3393
+ }
3394
+ if (!this.isOpen) {
3395
+ event.preventDefault();
3396
+ this.openInspector();
3397
+ }
3398
+ };
3399
+ this.handleClosePointerDown = (event) => {
3400
+ event.stopPropagation();
3401
+ event.preventDefault();
3402
+ };
3403
+ this.handleCloseClick = () => {
3404
+ this.closeInspector();
3405
+ };
3406
+ this.handleResizePointerDown = (event) => {
3407
+ event.stopPropagation();
3408
+ event.preventDefault();
3409
+ this.hasCustomPosition.window = true;
3410
+ this.isResizing = true;
3411
+ this.resizePointerId = event.pointerId;
3412
+ this.resizeStart = {
3413
+ x: event.clientX,
3414
+ y: event.clientY
3415
+ };
2843
3416
  this.resizeInitialSize = { ...this.contextState.window.size };
2844
3417
  if (document.body && this.dockMode !== "floating") document.body.style.transition = "";
2845
3418
  event.currentTarget?.setPointerCapture?.(event.pointerId);
@@ -2948,6 +3521,10 @@ var WebInspectorElement = class extends LitElement {
2948
3521
  if (target.hasPointerCapture(this.threadDividerPointerId)) target.releasePointerCapture(this.threadDividerPointerId);
2949
3522
  this.threadDividerResizing = false;
2950
3523
  };
3524
+ this.handleThreadsExampleOverviewVideoLoaded = () => {
3525
+ this.threadsExampleOverviewVideoReady = true;
3526
+ this.requestUpdate();
3527
+ };
2951
3528
  this.handleClearEvents = () => {
2952
3529
  if (this.selectedContext === "all-agents") {
2953
3530
  this.agentEvents.clear();
@@ -3052,6 +3629,11 @@ var WebInspectorElement = class extends LitElement {
3052
3629
  key: "threads",
3053
3630
  label: "Threads",
3054
3631
  icon: "MessageSquare"
3632
+ },
3633
+ {
3634
+ key: "memories",
3635
+ label: "Learning",
3636
+ icon: "Brain"
3055
3637
  }
3056
3638
  ];
3057
3639
  }
@@ -3063,6 +3645,16 @@ var WebInspectorElement = class extends LitElement {
3063
3645
  areThreadEndpointsAvailable() {
3064
3646
  return this.getThreadServiceStatus() !== "unavailable";
3065
3647
  }
3648
+ getActiveThreadsState() {
3649
+ const displayThreads = this.selectedContext === "all-agents" ? this._threads : this._threadsByAgent.get(this.selectedContext) ?? [];
3650
+ let threadsErrorMessage = null;
3651
+ if (this.selectedContext === "all-agents") threadsErrorMessage = this._threadsErrorByAgent.values().next().value?.message ?? null;
3652
+ else threadsErrorMessage = this._threadsErrorByAgent.get(this.selectedContext)?.message ?? null;
3653
+ return {
3654
+ displayThreads,
3655
+ threadsErrorMessage
3656
+ };
3657
+ }
3066
3658
  getThreadsTelemetryProps(extra = {}, options = {}) {
3067
3659
  const distinctId = options.includeUrlAttribution && !this.core?.telemetryDisabled ? getTelemetryDistinctIdForUrl() : null;
3068
3660
  const threadServiceStatus = this.getThreadServiceStatus();
@@ -3077,12 +3669,31 @@ var WebInspectorElement = class extends LitElement {
3077
3669
  ...extra
3078
3670
  };
3079
3671
  }
3672
+ getMemoriesTelemetryProps() {
3673
+ return {
3674
+ posthog_distinct_id: (!this.core?.telemetryDisabled ? getTelemetryDistinctIdForUrl() : null) ?? void 0,
3675
+ memory_count: this._memories.length,
3676
+ available: this._memoriesAvailable
3677
+ };
3678
+ }
3080
3679
  getIntelligenceSignupUrl() {
3081
3680
  return this.appendRefParam(INTELLIGENCE_SIGNUP_URL, "cpk-inspector");
3082
3681
  }
3682
+ getThreadsIntelligenceSignupUrl() {
3683
+ return this.appendRefParam(THREADS_INTELLIGENCE_SIGNIN_URL, "cpk-inspector");
3684
+ }
3083
3685
  getTalkToEngineerUrl() {
3084
3686
  return this.appendRefParam(TALK_TO_ENGINEER_URL, "cpk-inspector-threads");
3085
3687
  }
3688
+ getThreadsTalkToEngineerUrl() {
3689
+ return this.appendRefParam(TALK_TO_ENGINEER_URL, "cpk-inspector-threads");
3690
+ }
3691
+ getThreadsDocsUrl() {
3692
+ return this.appendRefParam(THREADS_DOCS_URL, "cpk-inspector-threads");
3693
+ }
3694
+ getSelfHostedIntelligenceUrl() {
3695
+ return this.appendRefParam(SELF_HOSTED_INTELLIGENCE_URL, "cpk-inspector-threads");
3696
+ }
3086
3697
  subscribeToThreadStore(agentId, store) {
3087
3698
  if (!this.areThreadEndpointsAvailable()) return;
3088
3699
  if (this._threadStoreSubscriptions.has(agentId)) return;
@@ -3111,7 +3722,7 @@ var WebInspectorElement = class extends LitElement {
3111
3722
  }
3112
3723
  autoSelectLatestThread() {
3113
3724
  if (this._threads.length === 0) return;
3114
- if (!(this.selectedThreadId != null && this._threads.some((t) => t.id === this.selectedThreadId))) this.selectedThreadId = this._threads[0].id;
3725
+ if (!(this.selectedThreadId != null && !this.isExampleThreadId(this.selectedThreadId) && this._threads.some((t) => t.id === this.selectedThreadId))) this.selectedThreadId = this._threads[0].id;
3115
3726
  }
3116
3727
  teardownThreadStoreSubscriptions() {
3117
3728
  for (const unsub of this._threadStoreSubscriptions.values()) unsub();
@@ -3241,12 +3852,75 @@ var WebInspectorElement = class extends LitElement {
3241
3852
  const threadStores = typeof core.getThreadStores === "function" ? core.getThreadStores() : {};
3242
3853
  for (const [agentId, store] of Object.entries(threadStores)) this.subscribeToThreadStore(agentId, store);
3243
3854
  if (core.context) this.contextStore = this.normalizeContextStore(core.context);
3855
+ if (this.selectedMenu === "memories") this.ensureMemorySubscription();
3856
+ }
3857
+ /**
3858
+ * Lazily subscribes to the singleton memory store the first time the user
3859
+ * activates the Memories tab. This is deferred out of `attachToCore` because
3860
+ * `core.getMemoryStore()` is what creates + starts the store and opens
3861
+ * realtime — doing it on attach would start memory for apps that never use
3862
+ * it. Idempotent: repeated tab activations are guarded by
3863
+ * `_memorySubscribed`. On an older @copilotkit/core without `getMemoryStore`,
3864
+ * records the unsupported state so the teaser can guide an SDK upgrade.
3865
+ */
3866
+ ensureMemorySubscription() {
3867
+ if (this._memorySubscribed) return;
3868
+ const core = this._core;
3869
+ if (!core) return;
3870
+ if (typeof core.getMemoryStore !== "function") {
3871
+ this._memoryStoreUnsupported = true;
3872
+ this._memoriesAvailable = false;
3873
+ this.requestUpdate();
3874
+ return;
3875
+ }
3876
+ this._memorySubscribed = true;
3877
+ this._memoryStoreUnsupported = false;
3878
+ const memoryStore = core.getMemoryStore();
3879
+ const ms = memoryStore.getState();
3880
+ this._memories = ɵselectMemories(ms);
3881
+ this._memoriesLoading = ɵselectMemoriesIsLoading(ms);
3882
+ this._memoriesError = ɵselectMemoriesError(ms);
3883
+ this._memoriesAvailable = ɵselectMemoriesAvailable(ms);
3884
+ this._memoriesRealtimeStatus = ɵselectMemoriesRealtimeStatus(ms);
3885
+ const memSubs = [
3886
+ memoryStore.select(ɵselectMemories).subscribe((v) => {
3887
+ this._memories = v;
3888
+ this.requestUpdate();
3889
+ }),
3890
+ memoryStore.select(ɵselectMemoriesIsLoading).subscribe((v) => {
3891
+ this._memoriesLoading = v;
3892
+ this.requestUpdate();
3893
+ }),
3894
+ memoryStore.select(ɵselectMemoriesError).subscribe((v) => {
3895
+ this._memoriesError = v;
3896
+ this.requestUpdate();
3897
+ }),
3898
+ memoryStore.select(ɵselectMemoriesAvailable).subscribe((v) => {
3899
+ this._memoriesAvailable = v;
3900
+ this.requestUpdate();
3901
+ }),
3902
+ memoryStore.select(ɵselectMemoriesRealtimeStatus).subscribe((v) => {
3903
+ this._memoriesRealtimeStatus = v;
3904
+ this.requestUpdate();
3905
+ })
3906
+ ];
3907
+ this._memoryUnsub = () => memSubs.forEach((s) => s.unsubscribe());
3908
+ this.requestUpdate();
3244
3909
  }
3245
3910
  detachFromCore() {
3246
3911
  if (this.coreUnsubscribe) {
3247
3912
  this.coreUnsubscribe();
3248
3913
  this.coreUnsubscribe = null;
3249
3914
  }
3915
+ this._memoryUnsub?.();
3916
+ this._memoryUnsub = null;
3917
+ this._memories = [];
3918
+ this._memoriesLoading = false;
3919
+ this._memoriesError = null;
3920
+ this._memoriesAvailable = true;
3921
+ this._memoriesRealtimeStatus = "connecting";
3922
+ this._memorySubscribed = false;
3923
+ this._memoryStoreUnsupported = false;
3250
3924
  this.coreSubscriber = null;
3251
3925
  this.runtimeStatus = null;
3252
3926
  this.lastCoreError = null;
@@ -4243,6 +4917,35 @@ ${argsString}</pre
4243
4917
  .cpk-tab-active {
4244
4918
  cursor: pointer;
4245
4919
  }
4920
+ .cpk-threads-overview-video-frame {
4921
+ position: relative;
4922
+ display: block;
4923
+ width: 100%;
4924
+ max-width: 440px;
4925
+ aspect-ratio: 16 / 9;
4926
+ margin: 0 0 14px;
4927
+ overflow: hidden;
4928
+ border: 1px solid #dbdbe5;
4929
+ border-radius: 8px;
4930
+ background:
4931
+ linear-gradient(
4932
+ 135deg,
4933
+ rgba(190, 194, 255, 0.18),
4934
+ rgba(133, 236, 206, 0.12)
4935
+ ),
4936
+ #ffffff;
4937
+ box-shadow: 0 8px 20px rgba(1, 5, 7, 0.08);
4938
+ }
4939
+ .cpk-threads-overview-video {
4940
+ width: 100%;
4941
+ height: 100%;
4942
+ object-fit: cover;
4943
+ opacity: 0;
4944
+ transition: opacity 220ms ease;
4945
+ }
4946
+ .cpk-threads-overview-video[data-ready="true"] {
4947
+ opacity: 1;
4948
+ }
4246
4949
 
4247
4950
  /* ── Header control buttons (dock, close) — first row only ───── */
4248
4951
  .drag-handle > div:first-child button {
@@ -4419,6 +5122,7 @@ ${argsString}</pre
4419
5122
  window.addEventListener("resize", this.handleResize);
4420
5123
  window.addEventListener("pointerdown", this.handleGlobalPointerDown);
4421
5124
  this.hydrateStateFromStorageEarly();
5125
+ this.exampleTourDismissed = this.readThreadsExampleTourDismissed();
4422
5126
  this.tryAutoAttachCore();
4423
5127
  this.ensureAnnouncementLoading();
4424
5128
  }
@@ -4444,6 +5148,14 @@ ${argsString}</pre
4444
5148
  clearTimeout(this.transitionTimeoutId);
4445
5149
  this.transitionTimeoutId = null;
4446
5150
  }
5151
+ if (this.threadsExampleOverviewVideoLoadTimer !== null) {
5152
+ window.clearTimeout(this.threadsExampleOverviewVideoLoadTimer);
5153
+ this.threadsExampleOverviewVideoLoadTimer = null;
5154
+ }
5155
+ if (this.threadsExampleOverviewVideoIdleCallbackId !== null && typeof window.cancelIdleCallback === "function") {
5156
+ window.cancelIdleCallback(this.threadsExampleOverviewVideoIdleCallbackId);
5157
+ this.threadsExampleOverviewVideoIdleCallbackId = null;
5158
+ }
4447
5159
  this.removeDockStyles(true);
4448
5160
  this.detachFromCore();
4449
5161
  }
@@ -4469,6 +5181,7 @@ ${argsString}</pre
4469
5181
  y: EDGE_MARGIN
4470
5182
  };
4471
5183
  this.hydrateStateFromStorage();
5184
+ if (this.selectedMenu === "memories") this.ensureMemorySubscription();
4472
5185
  if (this.isOpen && this.dockMode !== "floating") this.applyDockStyles(true);
4473
5186
  this.applyAnchorPosition("button");
4474
5187
  if (this.dockMode === "floating") if (this.hasCustomPosition.window) this.applyAnchorPosition("window");
@@ -4639,6 +5352,17 @@ ${argsString}</pre
4639
5352
  </button>
4640
5353
  `;
4641
5354
  })}
5355
+ ${this.selectedMenu === "threads" ? html`
5356
+ <a
5357
+ href=${this.getThreadsTalkToEngineerUrl()}
5358
+ target="_blank"
5359
+ rel="noopener"
5360
+ style="margin-left:auto;display:inline-flex;align-items:center;gap:6px;border-radius:6px;border:1px solid #dbdbe5;background:#ffffff;padding:7px 10px;font-size:12px;font-weight:600;color:#57575b;text-decoration:none;"
5361
+ @click=${this.handleTalkToEngineerClick}
5362
+ >
5363
+ Talk to an Engineer
5364
+ </a>
5365
+ ` : nothing}
4642
5366
  </div>
4643
5367
  </div>
4644
5368
  <div class="flex flex-1 flex-col overflow-hidden">
@@ -5164,65 +5888,432 @@ ${argsString}</pre
5164
5888
  if (this.selectedMenu === "frontend-tools") return this.renderToolsView();
5165
5889
  if (this.selectedMenu === "agent-context") return this.renderContextView();
5166
5890
  if (this.selectedMenu === "threads") return this.renderThreadsView();
5891
+ if (this.selectedMenu === "memories") return this.renderMemoriesView();
5167
5892
  if (this.selectedMenu === "settings") return this.renderSettingsPanel();
5168
5893
  return nothing;
5169
5894
  }
5170
- renderSettingsPanel() {
5171
- const optedOut = this.core?.telemetryDisabled ?? false;
5895
+ renderSettingsPanel() {
5896
+ const optedOut = this.core?.telemetryDisabled ?? false;
5897
+ return html`
5898
+ <div class="flex h-full flex-col overflow-hidden">
5899
+ <div class="overflow-auto p-4">
5900
+ <div class="space-y-3">
5901
+ <h2 class="text-sm font-semibold text-slate-900">Settings</h2>
5902
+
5903
+ <div class="space-y-2">
5904
+ <h3 class="text-sm text-slate-500">Privacy</h3>
5905
+ <div
5906
+ class="rounded-lg border border-slate-200 bg-white p-4 space-y-3"
5907
+ >
5908
+ <p class="text-sm text-gray-600 flex items-start gap-2">
5909
+ <span>${optedOut ? "❌" : "✅"}</span>
5910
+ <span>
5911
+ ${optedOut ? "You have disabled anonymous interaction data collection." : "CopilotKit is currently collecting anonymous interaction data from the inspector so we know which features people use. We never collect message content, agent state, prompts, or completions."}
5912
+ </span>
5913
+ </p>
5914
+ <a
5915
+ class="inline-flex items-center gap-1 text-sm text-slate-700 underline hover:text-slate-900"
5916
+ href=${TELEMETRY_DOCS_URL}
5917
+ target="_blank"
5918
+ rel="noopener"
5919
+ >Learn more →</a
5920
+ >
5921
+ </div>
5922
+ </div>
5923
+ </div>
5924
+ </div>
5925
+ </div>
5926
+ `;
5927
+ }
5928
+ trackBannerClickedOnce(opts) {
5929
+ if (this.core?.telemetryDisabled) return;
5930
+ const id = this.announcementTimestamp;
5931
+ if (!id) return;
5932
+ const key = `${id}:${opts.cta}`;
5933
+ if (this.clickedBannerIds.has(key)) return;
5934
+ this.clickedBannerIds.add(key);
5935
+ trackBannerClicked({
5936
+ banner_id: id,
5937
+ cta: opts.cta,
5938
+ cta_label: this.announcementCtaLabel ?? void 0
5939
+ });
5940
+ }
5941
+ trackThreadsViewStateOnce(state, threadCount) {
5942
+ if (this.core?.telemetryDisabled) return;
5943
+ const key = `${state}:${this.getThreadServiceStatus()}`;
5944
+ if (this.viewedThreadsTelemetryStates.has(key)) return;
5945
+ this.viewedThreadsTelemetryStates.add(key);
5946
+ const props = this.getThreadsTelemetryProps({ thread_count: threadCount });
5947
+ if (state === "locked") trackThreadsLockedViewed(props);
5948
+ else if (state === "empty_enabled") trackThreadsEmptyEnabledViewed(props);
5949
+ else trackThreadsEnabledViewed(props);
5950
+ }
5951
+ shouldRenderExampleThreads(displayThreads, threadsErrorMessage) {
5952
+ return this.areThreadEndpointsAvailable() && !threadsErrorMessage && displayThreads.length === 0;
5953
+ }
5954
+ getVisibleThreads(displayThreads, threadsErrorMessage) {
5955
+ return this.shouldRenderExampleThreads(displayThreads, threadsErrorMessage) ? THREADS_EXAMPLE_THREADS : displayThreads;
5956
+ }
5957
+ isExampleThreadId(threadId) {
5958
+ return THREADS_EXAMPLE_THREADS.some((thread) => thread.id === threadId);
5959
+ }
5960
+ getExampleThreadProvider(threadId) {
5961
+ const cached = this.exampleThreadProviders.get(threadId);
5962
+ if (cached) return cached;
5963
+ const thread = THREADS_EXAMPLE_THREADS.find((item) => item.id === threadId);
5964
+ const details = THREADS_EXAMPLE_DETAILS[threadId];
5965
+ const provider = {
5966
+ getThreadMetadata: async () => thread ? {
5967
+ id: thread.id,
5968
+ name: thread.name,
5969
+ agentId: thread.agentId,
5970
+ endUserId: "example-user",
5971
+ status: "completed",
5972
+ updatedAt: thread.updatedAt
5973
+ } : null,
5974
+ getMessages: async () => details?.messages ?? [],
5975
+ getEvents: async () => details?.events ?? [],
5976
+ getState: async () => details?.state ?? null
5977
+ };
5978
+ this.exampleThreadProviders.set(threadId, provider);
5979
+ return provider;
5980
+ }
5981
+ trackThreadsExampleViewedOnce() {
5982
+ if (this.core?.telemetryDisabled) return;
5983
+ for (const thread of THREADS_EXAMPLE_THREADS) {
5984
+ if (this.viewedExampleThreadIds.has(thread.id)) continue;
5985
+ this.viewedExampleThreadIds.add(thread.id);
5986
+ trackThreadsExampleViewed(this.getThreadsTelemetryProps({
5987
+ example_thread_id: thread.id,
5988
+ thread_count: 0
5989
+ }));
5990
+ }
5991
+ }
5992
+ trackThreadsExampleSelectedOnce(threadId) {
5993
+ if (this.core?.telemetryDisabled) return;
5994
+ if (this.selectedExampleThreadIds.has(threadId)) return;
5995
+ this.selectedExampleThreadIds.add(threadId);
5996
+ trackThreadsExampleSelected(this.getThreadsTelemetryProps({
5997
+ example_thread_id: threadId,
5998
+ thread_count: 0
5999
+ }));
6000
+ }
6001
+ getCurrentExampleTourProps() {
6002
+ const step = THREADS_EXAMPLE_TOUR_STEPS[this.exampleTourStep] ?? THREADS_EXAMPLE_TOUR_STEPS[0];
6003
+ return this.getThreadsTelemetryProps({
6004
+ example_thread_id: this.selectedThreadId ?? void 0,
6005
+ thread_count: 0,
6006
+ tour_step: this.exampleTourStep + 1,
6007
+ tour_tab: step?.tab
6008
+ });
6009
+ }
6010
+ trackThreadsExampleTourStepViewedOnce() {
6011
+ if (this.core?.telemetryDisabled || !this.selectedThreadId) return;
6012
+ if (!(THREADS_EXAMPLE_TOUR_STEPS[this.exampleTourStep] ?? THREADS_EXAMPLE_TOUR_STEPS[0])) return;
6013
+ const key = `${this.selectedThreadId}:${this.exampleTourStep}`;
6014
+ if (this.viewedExampleTourSteps.has(key)) return;
6015
+ this.viewedExampleTourSteps.add(key);
6016
+ trackThreadsExampleTourStepViewed(this.getCurrentExampleTourProps());
6017
+ }
6018
+ syncExampleTourTab() {
6019
+ const step = THREADS_EXAMPLE_TOUR_STEPS[this.exampleTourStep] ?? THREADS_EXAMPLE_TOUR_STEPS[0];
6020
+ if (!step) return;
6021
+ this.updateComplete.then(() => {
6022
+ (this.shadowRoot?.querySelector("cpk-thread-details"))?.selectTab?.(step.tab);
6023
+ });
6024
+ }
6025
+ startExampleTour(autoStarted) {
6026
+ if (!this.selectedThreadId) return;
6027
+ this.exampleTourActive = true;
6028
+ this.exampleTourStep = 0;
6029
+ if (autoStarted) {
6030
+ this.exampleTourAutoShown = true;
6031
+ if (!this.core?.telemetryDisabled) trackThreadsExampleTourStarted(this.getCurrentExampleTourProps());
6032
+ } else if (!this.core?.telemetryDisabled) trackThreadsExampleTourReopened(this.getCurrentExampleTourProps());
6033
+ this.trackThreadsExampleTourStepViewedOnce();
6034
+ this.syncExampleTourTab();
6035
+ this.requestUpdate();
6036
+ }
6037
+ setExampleTourStep(nextStep) {
6038
+ this.exampleTourStep = Math.max(0, Math.min(THREADS_EXAMPLE_TOUR_STEPS.length - 1, nextStep));
6039
+ this.trackThreadsExampleTourStepViewedOnce();
6040
+ this.syncExampleTourTab();
6041
+ this.requestUpdate();
6042
+ }
6043
+ dismissExampleTour(method) {
6044
+ if (!this.selectedThreadId) return;
6045
+ const props = {
6046
+ ...this.getCurrentExampleTourProps(),
6047
+ dismiss_method: method
6048
+ };
6049
+ this.exampleTourActive = false;
6050
+ this.exampleTourDismissed = true;
6051
+ this.writeThreadsExampleTourDismissed();
6052
+ if (!this.core?.telemetryDisabled) if (method === "done") trackThreadsExampleTourCompleted(props);
6053
+ else trackThreadsExampleTourDismissed(props);
6054
+ this.requestUpdate();
6055
+ }
6056
+ handleThreadsThreadSelected(threadId, showingExamples) {
6057
+ if (showingExamples && this.selectedThreadId === threadId) {
6058
+ this.selectedThreadId = null;
6059
+ this.exampleTourActive = false;
6060
+ this.requestUpdate();
6061
+ return;
6062
+ }
6063
+ this.selectedThreadId = threadId;
6064
+ if (showingExamples && this.isExampleThreadId(threadId)) {
6065
+ this.trackThreadsExampleSelectedOnce(threadId);
6066
+ if (!this.exampleTourDismissed && !this.exampleTourAutoShown) this.startExampleTour(true);
6067
+ else this.exampleTourActive = false;
6068
+ } else this.exampleTourActive = false;
6069
+ this.requestUpdate();
6070
+ }
6071
+ readThreadsExampleTourDismissed() {
6072
+ if (typeof window === "undefined") return false;
6073
+ try {
6074
+ const raw = window.localStorage.getItem(THREADS_EXAMPLE_TOUR_STORAGE_KEY);
6075
+ if (!raw) return false;
6076
+ return JSON.parse(raw).dismissed === true;
6077
+ } catch {
6078
+ return false;
6079
+ }
6080
+ }
6081
+ writeThreadsExampleTourDismissed() {
6082
+ if (typeof window === "undefined") return;
6083
+ try {
6084
+ window.localStorage.setItem(THREADS_EXAMPLE_TOUR_STORAGE_KEY, JSON.stringify({ dismissed: true }));
6085
+ } catch {}
6086
+ }
6087
+ scheduleThreadsExampleOverviewVideoLoad() {
6088
+ if (this.threadsExampleOverviewVideoShouldLoad || this.threadsExampleOverviewVideoLoadTimer !== null || this.threadsExampleOverviewVideoIdleCallbackId !== null || typeof window === "undefined") return;
6089
+ if (window.matchMedia?.("(prefers-reduced-motion: reduce)").matches) return;
6090
+ const loadVideo = () => {
6091
+ this.threadsExampleOverviewVideoLoadTimer = null;
6092
+ this.threadsExampleOverviewVideoIdleCallbackId = null;
6093
+ this.threadsExampleOverviewVideoShouldLoad = true;
6094
+ this.requestUpdate();
6095
+ };
6096
+ if (typeof window.requestIdleCallback === "function") {
6097
+ this.threadsExampleOverviewVideoIdleCallbackId = window.requestIdleCallback(loadVideo, { timeout: 1200 });
6098
+ return;
6099
+ }
6100
+ this.threadsExampleOverviewVideoLoadTimer = window.setTimeout(loadVideo, 450);
6101
+ }
6102
+ renderThreadsExampleOverviewVideo() {
6103
+ this.scheduleThreadsExampleOverviewVideoLoad();
6104
+ return html`
6105
+ <div class="cpk-threads-overview-video-frame" aria-hidden="true">
6106
+ ${this.threadsExampleOverviewVideoShouldLoad ? html`
6107
+ <video
6108
+ class="cpk-threads-overview-video"
6109
+ data-ready=${this.threadsExampleOverviewVideoReady}
6110
+ src=${THREADS_EXAMPLE_OVERVIEW_VIDEO_URL}
6111
+ autoplay
6112
+ loop
6113
+ muted
6114
+ playsinline
6115
+ preload="metadata"
6116
+ @loadeddata=${this.handleThreadsExampleOverviewVideoLoaded}
6117
+ ></video>
6118
+ ` : nothing}
6119
+ </div>
6120
+ `;
6121
+ }
6122
+ renderThreadsExampleOverview() {
6123
+ return html`
6124
+ <div
6125
+ style="
6126
+ flex: 1;
6127
+ min-width: 0;
6128
+ display: flex;
6129
+ align-items: center;
6130
+ justify-content: center;
6131
+ padding: 32px;
6132
+ background: #f7f7f9;
6133
+ "
6134
+ >
6135
+ <div style="max-width: 440px; color: #57575b;">
6136
+ <h2
6137
+ style="
6138
+ margin: 0 0 10px;
6139
+ font-size: 20px;
6140
+ line-height: 1.25;
6141
+ font-weight: 600;
6142
+ color: #010507;
6143
+ "
6144
+ >
6145
+ Threads are persistent, inspectable conversations
6146
+ </h2>
6147
+ ${this.renderThreadsExampleOverviewVideo()}
6148
+ <p
6149
+ style="
6150
+ margin: 0 0 16px;
6151
+ font-size: 13px;
6152
+ line-height: 1.55;
6153
+ color: #57575b;
6154
+ "
6155
+ >
6156
+ Take a tour with the example threads in the sidebar. Then, start
6157
+ chatting in your app to create the first real thread.
6158
+ </p>
6159
+ <div style="display:flex;flex-wrap:wrap;gap:8px;">
6160
+ <a
6161
+ href=${this.getThreadsDocsUrl()}
6162
+ target="_blank"
6163
+ rel="noopener"
6164
+ style="
6165
+ display: inline-flex;
6166
+ align-items: center;
6167
+ justify-content: center;
6168
+ gap: 6px;
6169
+ min-height: 34px;
6170
+ border-radius: 6px;
6171
+ background: #010507;
6172
+ padding: 8px 12px;
6173
+ font-size: 12px;
6174
+ font-weight: 600;
6175
+ color: #ffffff;
6176
+ text-decoration: none;
6177
+ "
6178
+ >
6179
+ Learn how Threads work
6180
+ </a>
6181
+ <a
6182
+ href=${this.getSelfHostedIntelligenceUrl()}
6183
+ target="_blank"
6184
+ rel="noopener"
6185
+ style="
6186
+ display: inline-flex;
6187
+ align-items: center;
6188
+ justify-content: center;
6189
+ gap: 6px;
6190
+ min-height: 34px;
6191
+ border-radius: 6px;
6192
+ border: 1px solid #dbdbe5;
6193
+ background: #ffffff;
6194
+ padding: 8px 12px;
6195
+ font-size: 12px;
6196
+ font-weight: 600;
6197
+ color: #010507;
6198
+ text-decoration: none;
6199
+ "
6200
+ >
6201
+ Explore self-hosted Intelligence
6202
+ </a>
6203
+ </div>
6204
+ </div>
6205
+ </div>
6206
+ `;
6207
+ }
6208
+ renderThreadsExampleTour() {
6209
+ if (!this.selectedThreadId || !this.isExampleThreadId(this.selectedThreadId)) return nothing;
6210
+ if (!this.exampleTourActive) return html`
6211
+ <button
6212
+ type="button"
6213
+ style="
6214
+ position: absolute;
6215
+ right: 16px;
6216
+ bottom: 16px;
6217
+ z-index: 2;
6218
+ border: 1px solid #dbdbe5;
6219
+ border-radius: 6px;
6220
+ background: #ffffff;
6221
+ padding: 7px 10px;
6222
+ color: #57575b;
6223
+ font-size: 12px;
6224
+ font-weight: 600;
6225
+ cursor: pointer;
6226
+ box-shadow: 0 8px 18px rgba(1, 5, 7, 0.08);
6227
+ "
6228
+ @click=${() => this.startExampleTour(false)}
6229
+ >
6230
+ Show tour
6231
+ </button>
6232
+ `;
6233
+ const step = THREADS_EXAMPLE_TOUR_STEPS[this.exampleTourStep] ?? THREADS_EXAMPLE_TOUR_STEPS[0];
6234
+ const isFirst = this.exampleTourStep === 0;
6235
+ const isLast = this.exampleTourStep === THREADS_EXAMPLE_TOUR_STEPS.length - 1;
5172
6236
  return html`
5173
- <div class="flex h-full flex-col overflow-hidden">
5174
- <div class="overflow-auto p-4">
5175
- <div class="space-y-3">
5176
- <h2 class="text-sm font-semibold text-slate-900">Settings</h2>
5177
-
5178
- <div class="space-y-2">
5179
- <h3 class="text-sm text-slate-500">Privacy</h3>
5180
- <div
5181
- class="rounded-lg border border-slate-200 bg-white p-4 space-y-3"
5182
- >
5183
- <p class="text-sm text-gray-600 flex items-start gap-2">
5184
- <span>${optedOut ? "❌" : "✅"}</span>
5185
- <span>
5186
- ${optedOut ? "You have disabled anonymous interaction data collection." : "CopilotKit is currently collecting anonymous interaction data from the inspector so we know which features people use. We never collect message content, agent state, prompts, or completions."}
5187
- </span>
5188
- </p>
5189
- <a
5190
- class="inline-flex items-center gap-1 text-sm text-slate-700 underline hover:text-slate-900"
5191
- href=${TELEMETRY_DOCS_URL}
5192
- target="_blank"
5193
- rel="noopener"
5194
- >Learn more →</a
5195
- >
5196
- </div>
5197
- </div>
6237
+ <div
6238
+ role="dialog"
6239
+ aria-label="Example thread tour"
6240
+ style="
6241
+ position: absolute;
6242
+ right: 16px;
6243
+ bottom: 16px;
6244
+ z-index: 3;
6245
+ width: min(340px, calc(100% - 32px));
6246
+ border: 1px solid #dbdbe5;
6247
+ border-radius: 8px;
6248
+ background: #ffffff;
6249
+ padding: 14px;
6250
+ box-shadow: 0 16px 36px rgba(1, 5, 7, 0.14);
6251
+ color: #57575b;
6252
+ "
6253
+ >
6254
+ <div
6255
+ style="
6256
+ margin-bottom: 8px;
6257
+ font-family: 'Spline Sans Mono', monospace;
6258
+ font-size: 10px;
6259
+ font-weight: 600;
6260
+ color: #189370;
6261
+ text-transform: uppercase;
6262
+ "
6263
+ >
6264
+ ${this.exampleTourStep + 1}/${THREADS_EXAMPLE_TOUR_STEPS.length}
6265
+ ${step.label}
6266
+ </div>
6267
+ <div
6268
+ style="
6269
+ margin-bottom: 6px;
6270
+ font-size: 14px;
6271
+ line-height: 1.35;
6272
+ font-weight: 600;
6273
+ color: #010507;
6274
+ "
6275
+ >
6276
+ ${step.title}
6277
+ </div>
6278
+ <div style="font-size: 12px; line-height: 1.5; color: #57575b;">
6279
+ ${step.body}
6280
+ </div>
6281
+ <div
6282
+ style="
6283
+ display: flex;
6284
+ justify-content: space-between;
6285
+ gap: 8px;
6286
+ margin-top: 14px;
6287
+ "
6288
+ >
6289
+ <button
6290
+ type="button"
6291
+ style="border:0;background:transparent;color:#838389;font-size:12px;font-weight:600;cursor:pointer;padding:7px 0;"
6292
+ @click=${() => this.dismissExampleTour("skip")}
6293
+ >
6294
+ Skip
6295
+ </button>
6296
+ <div style="display:flex;gap:8px;">
6297
+ <button
6298
+ type="button"
6299
+ style="border:1px solid #dbdbe5;border-radius:6px;background:#ffffff;color:#57575b;font-size:12px;font-weight:600;cursor:pointer;padding:7px 10px;"
6300
+ ?disabled=${isFirst}
6301
+ @click=${() => this.setExampleTourStep(this.exampleTourStep - 1)}
6302
+ >
6303
+ Back
6304
+ </button>
6305
+ <button
6306
+ type="button"
6307
+ style="border:1px solid #010507;border-radius:6px;background:#010507;color:#ffffff;font-size:12px;font-weight:600;cursor:pointer;padding:7px 10px;"
6308
+ @click=${() => isLast ? this.dismissExampleTour("done") : this.setExampleTourStep(this.exampleTourStep + 1)}
6309
+ >
6310
+ ${isLast ? "Done" : "Next"}
6311
+ </button>
5198
6312
  </div>
5199
6313
  </div>
5200
6314
  </div>
5201
6315
  `;
5202
6316
  }
5203
- trackBannerClickedOnce(opts) {
5204
- if (this.core?.telemetryDisabled) return;
5205
- const id = this.announcementTimestamp;
5206
- if (!id) return;
5207
- const key = `${id}:${opts.cta}`;
5208
- if (this.clickedBannerIds.has(key)) return;
5209
- this.clickedBannerIds.add(key);
5210
- trackBannerClicked({
5211
- banner_id: id,
5212
- cta: opts.cta,
5213
- cta_label: this.announcementCtaLabel ?? void 0
5214
- });
5215
- }
5216
- trackThreadsViewStateOnce(state, threadCount) {
5217
- if (this.core?.telemetryDisabled) return;
5218
- const key = `${state}:${this.getThreadServiceStatus()}`;
5219
- if (this.viewedThreadsTelemetryStates.has(key)) return;
5220
- this.viewedThreadsTelemetryStates.add(key);
5221
- const props = this.getThreadsTelemetryProps({ thread_count: threadCount });
5222
- if (state === "locked") trackThreadsLockedViewed(props);
5223
- else if (state === "empty_enabled") trackThreadsEmptyEnabledViewed(props);
5224
- else trackThreadsEnabledViewed(props);
5225
- }
5226
6317
  renderThreadsLockedBackgroundMockup() {
5227
6318
  return html`
5228
6319
  <div
@@ -5468,7 +6559,7 @@ ${argsString}</pre
5468
6559
  "
5469
6560
  >
5470
6561
  <a
5471
- href=${this.getTalkToEngineerUrl()}
6562
+ href=${this.getThreadsIntelligenceSignupUrl()}
5472
6563
  target="_blank"
5473
6564
  rel="noopener"
5474
6565
  style="
@@ -5478,68 +6569,338 @@ ${argsString}</pre
5478
6569
  justify-content: center;
5479
6570
  gap: 6px;
5480
6571
  border-radius: 6px;
5481
- background: #010507;
6572
+ border: 1px solid #dbdbe5;
6573
+ background: #ffffff;
5482
6574
  padding: 8px 12px;
5483
6575
  font-size: 12px;
5484
6576
  font-weight: 600;
5485
- color: #ffffff;
6577
+ color: #57575b;
5486
6578
  text-decoration: none;
5487
6579
  "
5488
- @click=${this.handleThreadsTalkToEngineerClick}
6580
+ @click=${this.handleThreadsIntelligenceSignupClick}
5489
6581
  >
5490
- Talk to an Engineer
6582
+ Sign up for Intelligence
5491
6583
  </a>
5492
- <a
5493
- href=${this.getIntelligenceSignupUrl()}
5494
- target="_blank"
5495
- rel="noopener"
6584
+ </div>
6585
+ </div>
6586
+ </div>
6587
+ `;
6588
+ }
6589
+ /**
6590
+ * Renders the realtime-connection indicator in the memory-store header.
6591
+ * Only `"connected"` shows the live (green-dot) state; `"connecting"` shows a
6592
+ * muted amber "reconnecting" and `"unavailable"` a muted grey "offline", so
6593
+ * the indicator never claims "live" over a frozen snapshot once the realtime
6594
+ * socket has permanently given up.
6595
+ */
6596
+ renderMemoryRealtimeIndicator() {
6597
+ const status = this._memoriesRealtimeStatus;
6598
+ const connected = status === "connected";
6599
+ return html`
6600
+ <span
6601
+ style="
6602
+ display: inline-flex;
6603
+ align-items: center;
6604
+ gap: 4px;
6605
+ font-size: 10px;
6606
+ font-weight: 500;
6607
+ color: ${connected ? "#57575b" : "#838389"};
6608
+ "
6609
+ >
6610
+ <span
6611
+ style="
6612
+ display: inline-block;
6613
+ width: 6px;
6614
+ height: 6px;
6615
+ border-radius: 50%;
6616
+ background: ${connected ? "#22c55e" : status === "connecting" ? "#f59e0b" : "#9ca3af"};
6617
+ "
6618
+ ></span>
6619
+ ${status === "connected" ? "live" : status === "connecting" ? "reconnecting" : "offline"}
6620
+ </span>
6621
+ `;
6622
+ }
6623
+ renderMemoriesView() {
6624
+ if (!this.core?.intelligence || !this._memoriesAvailable) return html`
6625
+ <div
6626
+ style="
6627
+ position: relative;
6628
+ height: 100%;
6629
+ display: flex;
6630
+ align-items: center;
6631
+ justify-content: center;
6632
+ padding: 32px;
6633
+ overflow: hidden;
6634
+ background: #ffffff;
6635
+ "
6636
+ >
6637
+ ${this.renderThreadsLockedBackgroundMockup()}
6638
+ <div
6639
+ aria-hidden="true"
6640
+ style="
6641
+ position: absolute;
6642
+ inset: 0;
6643
+ pointer-events: none;
6644
+ background:
6645
+ radial-gradient(circle at center, rgba(255,255,255,0.9) 0, rgba(255,255,255,0.78) 24%, rgba(255,255,255,0.34) 48%, rgba(255,255,255,0.56) 100%);
6646
+ "
6647
+ ></div>
6648
+ <div
6649
+ style="
6650
+ position: relative;
6651
+ z-index: 1;
6652
+ max-width: 440px;
6653
+ text-align: center;
6654
+ color: #57575b;
6655
+ "
6656
+ >
6657
+ <div
6658
+ aria-hidden="true"
5496
6659
  style="
5497
- display: inline-flex;
5498
- min-height: 34px;
5499
- align-items: center;
6660
+ margin: 0 auto 18px;
6661
+ display: flex;
5500
6662
  justify-content: center;
5501
- gap: 6px;
5502
- border-radius: 6px;
5503
- border: 1px solid #dbdbe5;
5504
- background: #ffffff;
5505
- padding: 8px 12px;
5506
- font-size: 12px;
6663
+ "
6664
+ >
6665
+ <div
6666
+ style="
6667
+ display: flex;
6668
+ height: 44px;
6669
+ width: 44px;
6670
+ align-items: center;
6671
+ justify-content: center;
6672
+ border: 1px solid #dfd6fb;
6673
+ border-radius: 8px;
6674
+ background: #eee6fe;
6675
+ color: #57575b;
6676
+ box-shadow: 0 8px 18px rgba(87, 87, 91, 0.14);
6677
+ "
6678
+ >
6679
+ ${this.renderIcon("Lock")}
6680
+ </div>
6681
+ </div>
6682
+ <h2
6683
+ style="
6684
+ margin: 0 0 8px;
6685
+ font-size: 16px;
6686
+ line-height: 1.35;
5507
6687
  font-weight: 600;
6688
+ color: #010507;
6689
+ "
6690
+ >
6691
+ Long-term memory
6692
+ </h2>
6693
+ <p
6694
+ style="
6695
+ margin: 0 auto 18px;
6696
+ max-width: 380px;
6697
+ font-size: 13px;
6698
+ line-height: 1.55;
5508
6699
  color: #57575b;
5509
- text-decoration: none;
5510
6700
  "
5511
- @click=${this.handleThreadsIntelligenceSignupClick}
5512
6701
  >
5513
- Sign up for Intelligence
5514
- </a>
6702
+ ${this._memoryStoreUnsupported ? "Long-term memory isn't available in this version of the @copilotkit SDK. Upgrade @copilotkit/core (and @copilotkit/react) to a version that supports memory." : "Long-term memory isn't enabled on this deployment."}
6703
+ </p>
6704
+ <div
6705
+ style="
6706
+ display: flex;
6707
+ flex-wrap: wrap;
6708
+ justify-content: center;
6709
+ gap: 8px;
6710
+ "
6711
+ >
6712
+ <a
6713
+ href=${this.getTalkToEngineerUrl()}
6714
+ target="_blank"
6715
+ rel="noopener"
6716
+ style="
6717
+ display: inline-flex;
6718
+ min-height: 34px;
6719
+ align-items: center;
6720
+ justify-content: center;
6721
+ gap: 6px;
6722
+ border-radius: 6px;
6723
+ background: #010507;
6724
+ padding: 8px 12px;
6725
+ font-size: 12px;
6726
+ font-weight: 600;
6727
+ color: #ffffff;
6728
+ text-decoration: none;
6729
+ "
6730
+ @click=${this.handleThreadsTalkToEngineerClick}
6731
+ >
6732
+ Talk to an Engineer
6733
+ </a>
6734
+ <a
6735
+ href=${this.getIntelligenceSignupUrl()}
6736
+ target="_blank"
6737
+ rel="noopener"
6738
+ style="
6739
+ display: inline-flex;
6740
+ min-height: 34px;
6741
+ align-items: center;
6742
+ justify-content: center;
6743
+ gap: 6px;
6744
+ border-radius: 6px;
6745
+ border: 1px solid #dbdbe5;
6746
+ background: #ffffff;
6747
+ padding: 8px 12px;
6748
+ font-size: 12px;
6749
+ font-weight: 600;
6750
+ color: #57575b;
6751
+ text-decoration: none;
6752
+ "
6753
+ @click=${this.handleThreadsIntelligenceSignupClick}
6754
+ >
6755
+ Sign up for Intelligence
6756
+ </a>
6757
+ </div>
5515
6758
  </div>
5516
6759
  </div>
6760
+ `;
6761
+ if (this._memoriesError && this._memories.length === 0) return html`
6762
+ <div
6763
+ style="
6764
+ display: flex;
6765
+ height: 100%;
6766
+ flex-direction: column;
6767
+ align-items: center;
6768
+ justify-content: center;
6769
+ gap: 8px;
6770
+ color: #838389;
6771
+ "
6772
+ >
6773
+ <svg
6774
+ width="24"
6775
+ height="24"
6776
+ viewBox="0 0 24 24"
6777
+ fill="none"
6778
+ stroke="#c0333a"
6779
+ stroke-width="1.5"
6780
+ stroke-linecap="round"
6781
+ stroke-linejoin="round"
6782
+ >
6783
+ <circle cx="12" cy="12" r="10" />
6784
+ <line x1="12" y1="8" x2="12" y2="12" />
6785
+ <line x1="12" y1="16" x2="12.01" y2="16" />
6786
+ </svg>
6787
+ <span style="font-size: 13px; color: #c0333a;">
6788
+ Failed to load memories
6789
+ </span>
6790
+ <span
6791
+ style="
6792
+ max-width: 320px;
6793
+ text-align: center;
6794
+ font-size: 11px;
6795
+ line-height: 1.5;
6796
+ color: #c0333a;
6797
+ "
6798
+ >
6799
+ ${this._memoriesError.message}
6800
+ </span>
6801
+ </div>
6802
+ `;
6803
+ if (this._memoriesLoading && this._memories.length === 0) return html`
6804
+ <div
6805
+ style="
6806
+ display: flex;
6807
+ height: 100%;
6808
+ flex-direction: column;
6809
+ align-items: center;
6810
+ justify-content: center;
6811
+ gap: 8px;
6812
+ color: #838389;
6813
+ "
6814
+ >
6815
+ <svg
6816
+ width="24"
6817
+ height="24"
6818
+ viewBox="0 0 24 24"
6819
+ fill="none"
6820
+ stroke="#c0c0c8"
6821
+ stroke-width="1.5"
6822
+ stroke-linecap="round"
6823
+ stroke-linejoin="round"
6824
+ >
6825
+ <path d="M21 12a9 9 0 1 1-6.219-8.56" />
6826
+ </svg>
6827
+ <span style="font-size: 13px">Loading memories…</span>
6828
+ </div>
6829
+ `;
6830
+ return html`
6831
+ <div style="display:flex;height:100%;overflow:hidden;flex-direction:column;">
6832
+ <div class="cpk-section-header" style="display:flex;align-items:center;justify-content:space-between;">
6833
+ <h4>Learning</h4>
6834
+ <div style="display:flex;align-items:center;gap:6px;">
6835
+ ${this.renderMemoryRealtimeIndicator()}
6836
+ <span
6837
+ style="
6838
+ font-size: 11px;
6839
+ font-weight: 500;
6840
+ color: #57575b;
6841
+ background: rgba(0,0,0,0.07);
6842
+ border-radius: 9999px;
6843
+ padding: 1px 7px;
6844
+ "
6845
+ >
6846
+ ${this._memories.length}
6847
+ </span>
6848
+ </div>
6849
+ </div>
6850
+ ${this._memoriesError ? html`
6851
+ <div
6852
+ role="alert"
6853
+ style="
6854
+ display: flex;
6855
+ align-items: flex-start;
6856
+ gap: 8px;
6857
+ flex-shrink: 0;
6858
+ border-bottom: 1px solid #f1c7c9;
6859
+ background: #fdf3f3;
6860
+ padding: 8px 12px;
6861
+ color: #c0333a;
6862
+ font-size: 12px;
6863
+ line-height: 1.45;
6864
+ "
6865
+ >
6866
+ <svg
6867
+ width="16"
6868
+ height="16"
6869
+ viewBox="0 0 24 24"
6870
+ fill="none"
6871
+ stroke="#c0333a"
6872
+ stroke-width="1.5"
6873
+ stroke-linecap="round"
6874
+ stroke-linejoin="round"
6875
+ style="flex-shrink:0;margin-top:1px;"
6876
+ >
6877
+ <circle cx="12" cy="12" r="10" />
6878
+ <line x1="12" y1="8" x2="12" y2="12" />
6879
+ <line x1="12" y1="16" x2="12.01" y2="16" />
6880
+ </svg>
6881
+ <span>Action failed: ${this._memoriesError.message}</span>
6882
+ </div>
6883
+ ` : nothing}
6884
+ <div style="flex:1;min-height:0;overflow:hidden;">
6885
+ <cpk-memory-list
6886
+ style="height:100%;"
6887
+ .memories=${this._memories}
6888
+ ></cpk-memory-list>
6889
+ </div>
5517
6890
  </div>
5518
6891
  `;
5519
6892
  }
5520
6893
  renderThreadsView() {
5521
6894
  if (!this.areThreadEndpointsAvailable()) return this.renderThreadsLockedView();
5522
- const displayThreads = this.selectedContext === "all-agents" ? this._threads : this._threadsByAgent.get(this.selectedContext) ?? [];
5523
- let threadsErrorMessage = null;
5524
- if (this.selectedContext === "all-agents") threadsErrorMessage = this._threadsErrorByAgent.values().next().value?.message ?? null;
5525
- else threadsErrorMessage = this._threadsErrorByAgent.get(this.selectedContext)?.message ?? null;
5526
- const selectedThread = this.selectedThreadId != null ? displayThreads.find((t) => t.id === this.selectedThreadId) ?? null : null;
6895
+ const { displayThreads, threadsErrorMessage } = this.getActiveThreadsState();
6896
+ const showingExamples = this.shouldRenderExampleThreads(displayThreads, threadsErrorMessage);
6897
+ const visibleThreads = this.getVisibleThreads(displayThreads, threadsErrorMessage);
6898
+ if (showingExamples) this.trackThreadsExampleViewedOnce();
6899
+ const selectedThread = this.selectedThreadId != null ? visibleThreads.find((t) => t.id === this.selectedThreadId) ?? null : null;
6900
+ const selectedThreadIsExample = this.isExampleThreadId(selectedThread?.id);
5527
6901
  if (!threadsErrorMessage) this.trackThreadsViewStateOnce(displayThreads.length === 0 ? "empty_enabled" : "enabled", displayThreads.length);
5528
6902
  return html`
5529
6903
  <div style="display:flex;height:100%;overflow:hidden;flex-direction:column;">
5530
- <div
5531
- style="display:flex;align-items:center;justify-content:flex-end;border-bottom:1px solid #DBDBE5;background:#ffffff;padding:8px 12px;flex-shrink:0;"
5532
- >
5533
- <a
5534
- href=${this.getTalkToEngineerUrl()}
5535
- target="_blank"
5536
- rel="noopener"
5537
- style="display:inline-flex;align-items:center;gap:6px;border-radius:6px;border:1px solid #dbdbe5;background:#ffffff;padding:7px 10px;font-size:12px;font-weight:600;color:#57575b;text-decoration:none;"
5538
- @click=${this.handleTalkToEngineerClick}
5539
- >
5540
- Talk to an Engineer
5541
- </a>
5542
- </div>
5543
6904
  <div style="display:flex;min-height:0;flex:1;overflow:hidden;">
5544
6905
  <!-- Left sidebar: thread list -->
5545
6906
  <div
@@ -5547,12 +6908,11 @@ ${argsString}</pre
5547
6908
  >
5548
6909
  <cpk-thread-list
5549
6910
  style="height:100%;"
5550
- .threads=${displayThreads}
6911
+ .threads=${visibleThreads}
5551
6912
  .selectedThreadId=${this.selectedThreadId}
5552
6913
  .errorMessage=${threadsErrorMessage}
5553
6914
  @threadSelected=${(e) => {
5554
- this.selectedThreadId = e.detail;
5555
- this.requestUpdate();
6915
+ this.handleThreadsThreadSelected(e.detail, showingExamples);
5556
6916
  }}
5557
6917
  ></cpk-thread-list>
5558
6918
  </div>
@@ -5567,18 +6927,20 @@ ${argsString}</pre
5567
6927
  ></div>
5568
6928
 
5569
6929
  <!-- Center + right: thread details or empty state -->
5570
- <div style="flex:1;min-width:0;overflow:hidden;display:flex;">
6930
+ <div style="flex:1;min-width:0;overflow:hidden;display:flex;position:relative;">
5571
6931
  ${selectedThread ? html`<cpk-thread-details
5572
6932
  style="flex:1;min-width:0;"
5573
6933
  .threadId=${selectedThread.id}
5574
6934
  .thread=${selectedThread}
6935
+ .provider=${selectedThreadIsExample ? this.getExampleThreadProvider(selectedThread.id) : null}
5575
6936
  .runtimeUrl=${this._core?.runtimeUrl ?? ""}
5576
6937
  .headers=${this._core?.headers ?? {}}
5577
- .threadInspectionAvailable=${this._core?.threadEndpoints?.inspect !== false}
6938
+ .threadInspectionAvailable=${selectedThreadIsExample || this._core?.threadEndpoints?.inspect !== false}
5578
6939
  .liveMessageVersion=${this.liveMessageVersion.get(selectedThread.id) ?? 0}
5579
6940
  .agentStateInput=${this.getLatestStateForAgent(selectedThread.agentId)}
5580
6941
  .agentEventsInput=${this.agentEvents.get(selectedThread.agentId) ?? []}
5581
- ></cpk-thread-details>` : html`
6942
+ ></cpk-thread-details>
6943
+ ${selectedThreadIsExample ? this.renderThreadsExampleTour() : nothing}` : showingExamples ? this.renderThreadsExampleOverview() : html`
5582
6944
  <div
5583
6945
  style="
5584
6946
  flex: 1;
@@ -6134,6 +7496,10 @@ ${prettyEvent}</pre
6134
7496
  if (previousMenu !== "threads" && !this.core?.telemetryDisabled) trackThreadsTabClicked(this.getThreadsTelemetryProps());
6135
7497
  this.autoSelectLatestThread();
6136
7498
  }
7499
+ if (key === "memories") {
7500
+ this.ensureMemorySubscription();
7501
+ if (previousMenu !== "memories" && !this.core?.telemetryDisabled) trackMemoriesTabClicked(this.getMemoriesTelemetryProps());
7502
+ }
6137
7503
  if (key === "ag-ui-events" || key === "agents") requestAnimationFrame(() => {
6138
7504
  const scroller = this.shadowRoot?.getElementById("cpk-main-scroll");
6139
7505
  if (scroller) scroller.scrollTop = 0;