@copilotkit/web-inspector 1.62.3 → 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.cjs CHANGED
@@ -35,7 +35,13 @@ const DOCKED_LEFT_WIDTH = 500;
35
35
  const MAX_AGENT_EVENTS = 200;
36
36
  const MAX_TOTAL_EVENTS = 500;
37
37
  const INTELLIGENCE_SIGNUP_URL = "https://go.copilotkit.ai/intelligence-signup";
38
+ const THREADS_INTELLIGENCE_SIGNIN_URL = "https://dashboard.operations.copilotkit.ai/sign-in";
38
39
  const TALK_TO_ENGINEER_URL = "https://www.copilotkit.ai/talk-to-an-engineer";
40
+ const THREADS_DOCS_URL = "https://docs.copilotkit.ai/threads";
41
+ const SELF_HOSTED_INTELLIGENCE_URL = "https://docs.copilotkit.ai/premium/self-hosting";
42
+ const THREADS_EXAMPLE_OVERVIEW_VIDEO_URL = "https://cdn.copilotkit.ai/corp-site/videos/copilotkit-generative-ui-agentic-frontend-demo.webm";
43
+ const THREADS_EXAMPLE_TOUR_STORAGE_KEY = "cpk:inspector:threads-example-tour:v1";
44
+ const THREADS_EXAMPLE_AGENT_ID = "threads-feature";
39
45
  const AGENT_EVENT_TYPES = [
40
46
  "RUN_STARTED",
41
47
  "RUN_FINISHED",
@@ -61,6 +67,201 @@ const AGENT_EVENT_TYPES = [
61
67
  "ACTIVITY_SNAPSHOT",
62
68
  "ACTIVITY_DELTA"
63
69
  ];
70
+ const THREADS_EXAMPLE_THREADS = [
71
+ {
72
+ id: "example-realtime-sync",
73
+ name: "Realtime thread sync",
74
+ agentId: THREADS_EXAMPLE_AGENT_ID,
75
+ organizationId: "example-organization",
76
+ createdById: "example-user",
77
+ archived: false,
78
+ createdAt: "2026-07-08T16:00:00.000Z",
79
+ updatedAt: "2026-07-08T16:30:00.000Z",
80
+ isExample: true
81
+ },
82
+ {
83
+ id: "example-manage-history",
84
+ name: "Manage saved conversations",
85
+ agentId: THREADS_EXAMPLE_AGENT_ID,
86
+ organizationId: "example-organization",
87
+ createdById: "example-user",
88
+ archived: false,
89
+ createdAt: "2026-07-07T17:45:00.000Z",
90
+ updatedAt: "2026-07-07T18:15:00.000Z",
91
+ isExample: true
92
+ },
93
+ {
94
+ id: "example-inspect-runs",
95
+ name: "Inspect durable run history",
96
+ agentId: THREADS_EXAMPLE_AGENT_ID,
97
+ organizationId: "example-organization",
98
+ createdById: "example-user",
99
+ archived: false,
100
+ createdAt: "2026-07-06T20:15:00.000Z",
101
+ updatedAt: "2026-07-06T20:45:00.000Z",
102
+ isExample: true
103
+ }
104
+ ];
105
+ const THREADS_EXAMPLE_DETAILS = {
106
+ "example-realtime-sync": {
107
+ messages: [{
108
+ id: "example-sync-user",
109
+ role: "user",
110
+ content: "Resume the checkout support thread from yesterday."
111
+ }, {
112
+ id: "example-sync-assistant",
113
+ role: "assistant",
114
+ content: "I found the saved thread, restored the cart state, and continued from the latest user message."
115
+ }],
116
+ events: [
117
+ {
118
+ type: "RUN_STARTED",
119
+ timestamp: "2026-07-08T16:30:00.000Z",
120
+ payload: {
121
+ threadId: "example-realtime-sync",
122
+ agentId: THREADS_EXAMPLE_AGENT_ID
123
+ }
124
+ },
125
+ {
126
+ type: "MESSAGES_SNAPSHOT",
127
+ timestamp: "2026-07-08T16:30:01.000Z",
128
+ payload: {
129
+ messageCount: 6,
130
+ source: "thread-history"
131
+ }
132
+ },
133
+ {
134
+ type: "STATE_SNAPSHOT",
135
+ timestamp: "2026-07-08T16:30:02.000Z",
136
+ payload: {
137
+ cartId: "cart_demo_42",
138
+ checkoutStep: "shipping",
139
+ resumed: true
140
+ }
141
+ },
142
+ {
143
+ type: "RUN_FINISHED",
144
+ timestamp: "2026-07-08T16:30:04.000Z",
145
+ payload: { status: "completed" }
146
+ }
147
+ ],
148
+ state: {
149
+ cartId: "cart_demo_42",
150
+ checkoutStep: "shipping",
151
+ userIntent: "resume_previous_checkout",
152
+ persistedThread: true
153
+ }
154
+ },
155
+ "example-manage-history": {
156
+ messages: [{
157
+ id: "example-history-user",
158
+ role: "user",
159
+ content: "Rename this saved support conversation for the handoff."
160
+ }, {
161
+ id: "example-history-assistant",
162
+ role: "assistant",
163
+ content: "Renamed the thread and kept the prior messages available for the next session."
164
+ }],
165
+ events: [
166
+ {
167
+ type: "RUN_STARTED",
168
+ timestamp: "2026-07-07T18:15:00.000Z",
169
+ payload: {
170
+ threadId: "example-manage-history",
171
+ agentId: THREADS_EXAMPLE_AGENT_ID
172
+ }
173
+ },
174
+ {
175
+ type: "CUSTOM_EVENT",
176
+ timestamp: "2026-07-07T18:15:01.000Z",
177
+ payload: {
178
+ action: "thread_renamed",
179
+ previousName: "Untitled",
180
+ name: "Billing escalation handoff"
181
+ }
182
+ },
183
+ {
184
+ type: "RUN_FINISHED",
185
+ timestamp: "2026-07-07T18:15:03.000Z",
186
+ payload: { status: "completed" }
187
+ }
188
+ ],
189
+ state: {
190
+ name: "Billing escalation handoff",
191
+ savedMessages: 14,
192
+ lastHandoff: "support-team"
193
+ }
194
+ },
195
+ "example-inspect-runs": {
196
+ messages: [{
197
+ id: "example-inspect-user",
198
+ role: "user",
199
+ content: "Why did the assistant recommend the enterprise plan?"
200
+ }, {
201
+ id: "example-inspect-assistant",
202
+ role: "assistant",
203
+ content: "The recommendation came from the account size, SSO requirement, and audit-log constraint in state."
204
+ }],
205
+ events: [
206
+ {
207
+ type: "RUN_STARTED",
208
+ timestamp: "2026-07-06T20:45:00.000Z",
209
+ payload: {
210
+ threadId: "example-inspect-runs",
211
+ agentId: THREADS_EXAMPLE_AGENT_ID
212
+ }
213
+ },
214
+ {
215
+ type: "TOOL_CALL_START",
216
+ timestamp: "2026-07-06T20:45:01.000Z",
217
+ payload: {
218
+ toolCallId: "call_account_lookup",
219
+ toolName: "lookupAccount"
220
+ }
221
+ },
222
+ {
223
+ type: "TOOL_CALL_RESULT",
224
+ timestamp: "2026-07-06T20:45:02.000Z",
225
+ payload: {
226
+ toolCallId: "call_account_lookup",
227
+ seats: 220,
228
+ requiresSso: true
229
+ }
230
+ },
231
+ {
232
+ type: "RUN_FINISHED",
233
+ timestamp: "2026-07-06T20:45:04.000Z",
234
+ payload: { status: "completed" }
235
+ }
236
+ ],
237
+ state: {
238
+ accountTier: "growth",
239
+ seats: 220,
240
+ requiresSso: true,
241
+ auditLogsRequired: true
242
+ }
243
+ }
244
+ };
245
+ const THREADS_EXAMPLE_TOUR_STEPS = [
246
+ {
247
+ tab: "timeline",
248
+ label: "Timeline",
249
+ title: "Read the run as a story",
250
+ body: "The timeline turns messages, tool calls, state changes, and run markers into a scannable debugging trail."
251
+ },
252
+ {
253
+ tab: "raw-events",
254
+ label: "Raw AG-UI Events",
255
+ title: "Drop into the protocol payloads",
256
+ body: "Raw events show the exact AG-UI stream behind the timeline when you need to verify ordering or payload shape."
257
+ },
258
+ {
259
+ tab: "state",
260
+ label: "State",
261
+ title: "Check the durable state",
262
+ body: "The state tab shows the saved values that make a thread resumable across sessions."
263
+ }
264
+ ];
64
265
  function escapeHtml(s) {
65
266
  return s.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
66
267
  }
@@ -276,6 +477,11 @@ var CpkThreadList = class extends lit.LitElement {
276
477
  color: #57575b;
277
478
  }
278
479
 
480
+ .cpk-tl__pill--example {
481
+ background: rgba(133, 236, 206, 0.22);
482
+ color: #189370;
483
+ }
484
+
279
485
  /* ── Empty state ── */
280
486
  .cpk-tl__empty {
281
487
  padding: 32px 16px;
@@ -349,6 +555,9 @@ var CpkThreadList = class extends lit.LitElement {
349
555
  </div>
350
556
  <div class="cpk-tl__meta">
351
557
  <span class="cpk-tl__pill">${thread.agentId}</span>
558
+ ${thread.isExample ? lit.html`
559
+ <span class="cpk-tl__pill cpk-tl__pill--example">Example</span>
560
+ ` : lit.nothing}
352
561
  </div>
353
562
  </div>
354
563
  `)}
@@ -572,6 +781,9 @@ var CpkThreadInspector = class CpkThreadInspector extends lit.LitElement {
572
781
  }
573
782
  this.maybeFetchTabData(id);
574
783
  }
784
+ selectTab(id) {
785
+ this.activateTab(id);
786
+ }
575
787
  maybeFetchTabData(id) {
576
788
  if (!this.threadId) return;
577
789
  if ((id === "timeline" || id === "raw-events") && !this._eventsFetched) {
@@ -3052,6 +3264,18 @@ var WebInspectorElement = class extends lit.LitElement {
3052
3264
  this.pendingBannerViewed = null;
3053
3265
  this.clickedBannerIds = /* @__PURE__ */ new Set();
3054
3266
  this.viewedThreadsTelemetryStates = /* @__PURE__ */ new Set();
3267
+ this.viewedExampleThreadIds = /* @__PURE__ */ new Set();
3268
+ this.selectedExampleThreadIds = /* @__PURE__ */ new Set();
3269
+ this.viewedExampleTourSteps = /* @__PURE__ */ new Set();
3270
+ this.exampleThreadProviders = /* @__PURE__ */ new Map();
3271
+ this.exampleTourDismissed = false;
3272
+ this.exampleTourActive = false;
3273
+ this.exampleTourStep = 0;
3274
+ this.exampleTourAutoShown = false;
3275
+ this.threadsExampleOverviewVideoShouldLoad = false;
3276
+ this.threadsExampleOverviewVideoReady = false;
3277
+ this.threadsExampleOverviewVideoLoadTimer = null;
3278
+ this.threadsExampleOverviewVideoIdleCallbackId = null;
3055
3279
  this.contextState = {
3056
3280
  button: {
3057
3281
  position: {
@@ -3298,6 +3522,10 @@ var WebInspectorElement = class extends lit.LitElement {
3298
3522
  if (target.hasPointerCapture(this.threadDividerPointerId)) target.releasePointerCapture(this.threadDividerPointerId);
3299
3523
  this.threadDividerResizing = false;
3300
3524
  };
3525
+ this.handleThreadsExampleOverviewVideoLoaded = () => {
3526
+ this.threadsExampleOverviewVideoReady = true;
3527
+ this.requestUpdate();
3528
+ };
3301
3529
  this.handleClearEvents = () => {
3302
3530
  if (this.selectedContext === "all-agents") {
3303
3531
  this.agentEvents.clear();
@@ -3418,6 +3646,16 @@ var WebInspectorElement = class extends lit.LitElement {
3418
3646
  areThreadEndpointsAvailable() {
3419
3647
  return this.getThreadServiceStatus() !== "unavailable";
3420
3648
  }
3649
+ getActiveThreadsState() {
3650
+ const displayThreads = this.selectedContext === "all-agents" ? this._threads : this._threadsByAgent.get(this.selectedContext) ?? [];
3651
+ let threadsErrorMessage = null;
3652
+ if (this.selectedContext === "all-agents") threadsErrorMessage = this._threadsErrorByAgent.values().next().value?.message ?? null;
3653
+ else threadsErrorMessage = this._threadsErrorByAgent.get(this.selectedContext)?.message ?? null;
3654
+ return {
3655
+ displayThreads,
3656
+ threadsErrorMessage
3657
+ };
3658
+ }
3421
3659
  getThreadsTelemetryProps(extra = {}, options = {}) {
3422
3660
  const distinctId = options.includeUrlAttribution && !this.core?.telemetryDisabled ? require_telemetry.getTelemetryDistinctIdForUrl() : null;
3423
3661
  const threadServiceStatus = this.getThreadServiceStatus();
@@ -3442,9 +3680,21 @@ var WebInspectorElement = class extends lit.LitElement {
3442
3680
  getIntelligenceSignupUrl() {
3443
3681
  return this.appendRefParam(INTELLIGENCE_SIGNUP_URL, "cpk-inspector");
3444
3682
  }
3683
+ getThreadsIntelligenceSignupUrl() {
3684
+ return this.appendRefParam(THREADS_INTELLIGENCE_SIGNIN_URL, "cpk-inspector");
3685
+ }
3445
3686
  getTalkToEngineerUrl() {
3446
3687
  return this.appendRefParam(TALK_TO_ENGINEER_URL, "cpk-inspector-threads");
3447
3688
  }
3689
+ getThreadsTalkToEngineerUrl() {
3690
+ return this.appendRefParam(TALK_TO_ENGINEER_URL, "cpk-inspector-threads");
3691
+ }
3692
+ getThreadsDocsUrl() {
3693
+ return this.appendRefParam(THREADS_DOCS_URL, "cpk-inspector-threads");
3694
+ }
3695
+ getSelfHostedIntelligenceUrl() {
3696
+ return this.appendRefParam(SELF_HOSTED_INTELLIGENCE_URL, "cpk-inspector-threads");
3697
+ }
3448
3698
  subscribeToThreadStore(agentId, store) {
3449
3699
  if (!this.areThreadEndpointsAvailable()) return;
3450
3700
  if (this._threadStoreSubscriptions.has(agentId)) return;
@@ -3473,7 +3723,7 @@ var WebInspectorElement = class extends lit.LitElement {
3473
3723
  }
3474
3724
  autoSelectLatestThread() {
3475
3725
  if (this._threads.length === 0) return;
3476
- if (!(this.selectedThreadId != null && this._threads.some((t) => t.id === this.selectedThreadId))) this.selectedThreadId = this._threads[0].id;
3726
+ if (!(this.selectedThreadId != null && !this.isExampleThreadId(this.selectedThreadId) && this._threads.some((t) => t.id === this.selectedThreadId))) this.selectedThreadId = this._threads[0].id;
3477
3727
  }
3478
3728
  teardownThreadStoreSubscriptions() {
3479
3729
  for (const unsub of this._threadStoreSubscriptions.values()) unsub();
@@ -4668,6 +4918,35 @@ ${argsString}</pre
4668
4918
  .cpk-tab-active {
4669
4919
  cursor: pointer;
4670
4920
  }
4921
+ .cpk-threads-overview-video-frame {
4922
+ position: relative;
4923
+ display: block;
4924
+ width: 100%;
4925
+ max-width: 440px;
4926
+ aspect-ratio: 16 / 9;
4927
+ margin: 0 0 14px;
4928
+ overflow: hidden;
4929
+ border: 1px solid #dbdbe5;
4930
+ border-radius: 8px;
4931
+ background:
4932
+ linear-gradient(
4933
+ 135deg,
4934
+ rgba(190, 194, 255, 0.18),
4935
+ rgba(133, 236, 206, 0.12)
4936
+ ),
4937
+ #ffffff;
4938
+ box-shadow: 0 8px 20px rgba(1, 5, 7, 0.08);
4939
+ }
4940
+ .cpk-threads-overview-video {
4941
+ width: 100%;
4942
+ height: 100%;
4943
+ object-fit: cover;
4944
+ opacity: 0;
4945
+ transition: opacity 220ms ease;
4946
+ }
4947
+ .cpk-threads-overview-video[data-ready="true"] {
4948
+ opacity: 1;
4949
+ }
4671
4950
 
4672
4951
  /* ── Header control buttons (dock, close) — first row only ───── */
4673
4952
  .drag-handle > div:first-child button {
@@ -4844,6 +5123,7 @@ ${argsString}</pre
4844
5123
  window.addEventListener("resize", this.handleResize);
4845
5124
  window.addEventListener("pointerdown", this.handleGlobalPointerDown);
4846
5125
  this.hydrateStateFromStorageEarly();
5126
+ this.exampleTourDismissed = this.readThreadsExampleTourDismissed();
4847
5127
  this.tryAutoAttachCore();
4848
5128
  this.ensureAnnouncementLoading();
4849
5129
  }
@@ -4869,6 +5149,14 @@ ${argsString}</pre
4869
5149
  clearTimeout(this.transitionTimeoutId);
4870
5150
  this.transitionTimeoutId = null;
4871
5151
  }
5152
+ if (this.threadsExampleOverviewVideoLoadTimer !== null) {
5153
+ window.clearTimeout(this.threadsExampleOverviewVideoLoadTimer);
5154
+ this.threadsExampleOverviewVideoLoadTimer = null;
5155
+ }
5156
+ if (this.threadsExampleOverviewVideoIdleCallbackId !== null && typeof window.cancelIdleCallback === "function") {
5157
+ window.cancelIdleCallback(this.threadsExampleOverviewVideoIdleCallbackId);
5158
+ this.threadsExampleOverviewVideoIdleCallbackId = null;
5159
+ }
4872
5160
  this.removeDockStyles(true);
4873
5161
  this.detachFromCore();
4874
5162
  }
@@ -5065,6 +5353,17 @@ ${argsString}</pre
5065
5353
  </button>
5066
5354
  `;
5067
5355
  })}
5356
+ ${this.selectedMenu === "threads" ? lit.html`
5357
+ <a
5358
+ href=${this.getThreadsTalkToEngineerUrl()}
5359
+ target="_blank"
5360
+ rel="noopener"
5361
+ 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;"
5362
+ @click=${this.handleTalkToEngineerClick}
5363
+ >
5364
+ Talk to an Engineer
5365
+ </a>
5366
+ ` : lit.nothing}
5068
5367
  </div>
5069
5368
  </div>
5070
5369
  <div class="flex flex-1 flex-col overflow-hidden">
@@ -5650,6 +5949,372 @@ ${argsString}</pre
5650
5949
  else if (state === "empty_enabled") require_telemetry.trackThreadsEmptyEnabledViewed(props);
5651
5950
  else require_telemetry.trackThreadsEnabledViewed(props);
5652
5951
  }
5952
+ shouldRenderExampleThreads(displayThreads, threadsErrorMessage) {
5953
+ return this.areThreadEndpointsAvailable() && !threadsErrorMessage && displayThreads.length === 0;
5954
+ }
5955
+ getVisibleThreads(displayThreads, threadsErrorMessage) {
5956
+ return this.shouldRenderExampleThreads(displayThreads, threadsErrorMessage) ? THREADS_EXAMPLE_THREADS : displayThreads;
5957
+ }
5958
+ isExampleThreadId(threadId) {
5959
+ return THREADS_EXAMPLE_THREADS.some((thread) => thread.id === threadId);
5960
+ }
5961
+ getExampleThreadProvider(threadId) {
5962
+ const cached = this.exampleThreadProviders.get(threadId);
5963
+ if (cached) return cached;
5964
+ const thread = THREADS_EXAMPLE_THREADS.find((item) => item.id === threadId);
5965
+ const details = THREADS_EXAMPLE_DETAILS[threadId];
5966
+ const provider = {
5967
+ getThreadMetadata: async () => thread ? {
5968
+ id: thread.id,
5969
+ name: thread.name,
5970
+ agentId: thread.agentId,
5971
+ endUserId: "example-user",
5972
+ status: "completed",
5973
+ updatedAt: thread.updatedAt
5974
+ } : null,
5975
+ getMessages: async () => details?.messages ?? [],
5976
+ getEvents: async () => details?.events ?? [],
5977
+ getState: async () => details?.state ?? null
5978
+ };
5979
+ this.exampleThreadProviders.set(threadId, provider);
5980
+ return provider;
5981
+ }
5982
+ trackThreadsExampleViewedOnce() {
5983
+ if (this.core?.telemetryDisabled) return;
5984
+ for (const thread of THREADS_EXAMPLE_THREADS) {
5985
+ if (this.viewedExampleThreadIds.has(thread.id)) continue;
5986
+ this.viewedExampleThreadIds.add(thread.id);
5987
+ require_telemetry.trackThreadsExampleViewed(this.getThreadsTelemetryProps({
5988
+ example_thread_id: thread.id,
5989
+ thread_count: 0
5990
+ }));
5991
+ }
5992
+ }
5993
+ trackThreadsExampleSelectedOnce(threadId) {
5994
+ if (this.core?.telemetryDisabled) return;
5995
+ if (this.selectedExampleThreadIds.has(threadId)) return;
5996
+ this.selectedExampleThreadIds.add(threadId);
5997
+ require_telemetry.trackThreadsExampleSelected(this.getThreadsTelemetryProps({
5998
+ example_thread_id: threadId,
5999
+ thread_count: 0
6000
+ }));
6001
+ }
6002
+ getCurrentExampleTourProps() {
6003
+ const step = THREADS_EXAMPLE_TOUR_STEPS[this.exampleTourStep] ?? THREADS_EXAMPLE_TOUR_STEPS[0];
6004
+ return this.getThreadsTelemetryProps({
6005
+ example_thread_id: this.selectedThreadId ?? void 0,
6006
+ thread_count: 0,
6007
+ tour_step: this.exampleTourStep + 1,
6008
+ tour_tab: step?.tab
6009
+ });
6010
+ }
6011
+ trackThreadsExampleTourStepViewedOnce() {
6012
+ if (this.core?.telemetryDisabled || !this.selectedThreadId) return;
6013
+ if (!(THREADS_EXAMPLE_TOUR_STEPS[this.exampleTourStep] ?? THREADS_EXAMPLE_TOUR_STEPS[0])) return;
6014
+ const key = `${this.selectedThreadId}:${this.exampleTourStep}`;
6015
+ if (this.viewedExampleTourSteps.has(key)) return;
6016
+ this.viewedExampleTourSteps.add(key);
6017
+ require_telemetry.trackThreadsExampleTourStepViewed(this.getCurrentExampleTourProps());
6018
+ }
6019
+ syncExampleTourTab() {
6020
+ const step = THREADS_EXAMPLE_TOUR_STEPS[this.exampleTourStep] ?? THREADS_EXAMPLE_TOUR_STEPS[0];
6021
+ if (!step) return;
6022
+ this.updateComplete.then(() => {
6023
+ (this.shadowRoot?.querySelector("cpk-thread-details"))?.selectTab?.(step.tab);
6024
+ });
6025
+ }
6026
+ startExampleTour(autoStarted) {
6027
+ if (!this.selectedThreadId) return;
6028
+ this.exampleTourActive = true;
6029
+ this.exampleTourStep = 0;
6030
+ if (autoStarted) {
6031
+ this.exampleTourAutoShown = true;
6032
+ if (!this.core?.telemetryDisabled) require_telemetry.trackThreadsExampleTourStarted(this.getCurrentExampleTourProps());
6033
+ } else if (!this.core?.telemetryDisabled) require_telemetry.trackThreadsExampleTourReopened(this.getCurrentExampleTourProps());
6034
+ this.trackThreadsExampleTourStepViewedOnce();
6035
+ this.syncExampleTourTab();
6036
+ this.requestUpdate();
6037
+ }
6038
+ setExampleTourStep(nextStep) {
6039
+ this.exampleTourStep = Math.max(0, Math.min(THREADS_EXAMPLE_TOUR_STEPS.length - 1, nextStep));
6040
+ this.trackThreadsExampleTourStepViewedOnce();
6041
+ this.syncExampleTourTab();
6042
+ this.requestUpdate();
6043
+ }
6044
+ dismissExampleTour(method) {
6045
+ if (!this.selectedThreadId) return;
6046
+ const props = {
6047
+ ...this.getCurrentExampleTourProps(),
6048
+ dismiss_method: method
6049
+ };
6050
+ this.exampleTourActive = false;
6051
+ this.exampleTourDismissed = true;
6052
+ this.writeThreadsExampleTourDismissed();
6053
+ if (!this.core?.telemetryDisabled) if (method === "done") require_telemetry.trackThreadsExampleTourCompleted(props);
6054
+ else require_telemetry.trackThreadsExampleTourDismissed(props);
6055
+ this.requestUpdate();
6056
+ }
6057
+ handleThreadsThreadSelected(threadId, showingExamples) {
6058
+ if (showingExamples && this.selectedThreadId === threadId) {
6059
+ this.selectedThreadId = null;
6060
+ this.exampleTourActive = false;
6061
+ this.requestUpdate();
6062
+ return;
6063
+ }
6064
+ this.selectedThreadId = threadId;
6065
+ if (showingExamples && this.isExampleThreadId(threadId)) {
6066
+ this.trackThreadsExampleSelectedOnce(threadId);
6067
+ if (!this.exampleTourDismissed && !this.exampleTourAutoShown) this.startExampleTour(true);
6068
+ else this.exampleTourActive = false;
6069
+ } else this.exampleTourActive = false;
6070
+ this.requestUpdate();
6071
+ }
6072
+ readThreadsExampleTourDismissed() {
6073
+ if (typeof window === "undefined") return false;
6074
+ try {
6075
+ const raw = window.localStorage.getItem(THREADS_EXAMPLE_TOUR_STORAGE_KEY);
6076
+ if (!raw) return false;
6077
+ return JSON.parse(raw).dismissed === true;
6078
+ } catch {
6079
+ return false;
6080
+ }
6081
+ }
6082
+ writeThreadsExampleTourDismissed() {
6083
+ if (typeof window === "undefined") return;
6084
+ try {
6085
+ window.localStorage.setItem(THREADS_EXAMPLE_TOUR_STORAGE_KEY, JSON.stringify({ dismissed: true }));
6086
+ } catch {}
6087
+ }
6088
+ scheduleThreadsExampleOverviewVideoLoad() {
6089
+ if (this.threadsExampleOverviewVideoShouldLoad || this.threadsExampleOverviewVideoLoadTimer !== null || this.threadsExampleOverviewVideoIdleCallbackId !== null || typeof window === "undefined") return;
6090
+ if (window.matchMedia?.("(prefers-reduced-motion: reduce)").matches) return;
6091
+ const loadVideo = () => {
6092
+ this.threadsExampleOverviewVideoLoadTimer = null;
6093
+ this.threadsExampleOverviewVideoIdleCallbackId = null;
6094
+ this.threadsExampleOverviewVideoShouldLoad = true;
6095
+ this.requestUpdate();
6096
+ };
6097
+ if (typeof window.requestIdleCallback === "function") {
6098
+ this.threadsExampleOverviewVideoIdleCallbackId = window.requestIdleCallback(loadVideo, { timeout: 1200 });
6099
+ return;
6100
+ }
6101
+ this.threadsExampleOverviewVideoLoadTimer = window.setTimeout(loadVideo, 450);
6102
+ }
6103
+ renderThreadsExampleOverviewVideo() {
6104
+ this.scheduleThreadsExampleOverviewVideoLoad();
6105
+ return lit.html`
6106
+ <div class="cpk-threads-overview-video-frame" aria-hidden="true">
6107
+ ${this.threadsExampleOverviewVideoShouldLoad ? lit.html`
6108
+ <video
6109
+ class="cpk-threads-overview-video"
6110
+ data-ready=${this.threadsExampleOverviewVideoReady}
6111
+ src=${THREADS_EXAMPLE_OVERVIEW_VIDEO_URL}
6112
+ autoplay
6113
+ loop
6114
+ muted
6115
+ playsinline
6116
+ preload="metadata"
6117
+ @loadeddata=${this.handleThreadsExampleOverviewVideoLoaded}
6118
+ ></video>
6119
+ ` : lit.nothing}
6120
+ </div>
6121
+ `;
6122
+ }
6123
+ renderThreadsExampleOverview() {
6124
+ return lit.html`
6125
+ <div
6126
+ style="
6127
+ flex: 1;
6128
+ min-width: 0;
6129
+ display: flex;
6130
+ align-items: center;
6131
+ justify-content: center;
6132
+ padding: 32px;
6133
+ background: #f7f7f9;
6134
+ "
6135
+ >
6136
+ <div style="max-width: 440px; color: #57575b;">
6137
+ <h2
6138
+ style="
6139
+ margin: 0 0 10px;
6140
+ font-size: 20px;
6141
+ line-height: 1.25;
6142
+ font-weight: 600;
6143
+ color: #010507;
6144
+ "
6145
+ >
6146
+ Threads are persistent, inspectable conversations
6147
+ </h2>
6148
+ ${this.renderThreadsExampleOverviewVideo()}
6149
+ <p
6150
+ style="
6151
+ margin: 0 0 16px;
6152
+ font-size: 13px;
6153
+ line-height: 1.55;
6154
+ color: #57575b;
6155
+ "
6156
+ >
6157
+ Take a tour with the example threads in the sidebar. Then, start
6158
+ chatting in your app to create the first real thread.
6159
+ </p>
6160
+ <div style="display:flex;flex-wrap:wrap;gap:8px;">
6161
+ <a
6162
+ href=${this.getThreadsDocsUrl()}
6163
+ target="_blank"
6164
+ rel="noopener"
6165
+ style="
6166
+ display: inline-flex;
6167
+ align-items: center;
6168
+ justify-content: center;
6169
+ gap: 6px;
6170
+ min-height: 34px;
6171
+ border-radius: 6px;
6172
+ background: #010507;
6173
+ padding: 8px 12px;
6174
+ font-size: 12px;
6175
+ font-weight: 600;
6176
+ color: #ffffff;
6177
+ text-decoration: none;
6178
+ "
6179
+ >
6180
+ Learn how Threads work
6181
+ </a>
6182
+ <a
6183
+ href=${this.getSelfHostedIntelligenceUrl()}
6184
+ target="_blank"
6185
+ rel="noopener"
6186
+ style="
6187
+ display: inline-flex;
6188
+ align-items: center;
6189
+ justify-content: center;
6190
+ gap: 6px;
6191
+ min-height: 34px;
6192
+ border-radius: 6px;
6193
+ border: 1px solid #dbdbe5;
6194
+ background: #ffffff;
6195
+ padding: 8px 12px;
6196
+ font-size: 12px;
6197
+ font-weight: 600;
6198
+ color: #010507;
6199
+ text-decoration: none;
6200
+ "
6201
+ >
6202
+ Explore self-hosted Intelligence
6203
+ </a>
6204
+ </div>
6205
+ </div>
6206
+ </div>
6207
+ `;
6208
+ }
6209
+ renderThreadsExampleTour() {
6210
+ if (!this.selectedThreadId || !this.isExampleThreadId(this.selectedThreadId)) return lit.nothing;
6211
+ if (!this.exampleTourActive) return lit.html`
6212
+ <button
6213
+ type="button"
6214
+ style="
6215
+ position: absolute;
6216
+ right: 16px;
6217
+ bottom: 16px;
6218
+ z-index: 2;
6219
+ border: 1px solid #dbdbe5;
6220
+ border-radius: 6px;
6221
+ background: #ffffff;
6222
+ padding: 7px 10px;
6223
+ color: #57575b;
6224
+ font-size: 12px;
6225
+ font-weight: 600;
6226
+ cursor: pointer;
6227
+ box-shadow: 0 8px 18px rgba(1, 5, 7, 0.08);
6228
+ "
6229
+ @click=${() => this.startExampleTour(false)}
6230
+ >
6231
+ Show tour
6232
+ </button>
6233
+ `;
6234
+ const step = THREADS_EXAMPLE_TOUR_STEPS[this.exampleTourStep] ?? THREADS_EXAMPLE_TOUR_STEPS[0];
6235
+ const isFirst = this.exampleTourStep === 0;
6236
+ const isLast = this.exampleTourStep === THREADS_EXAMPLE_TOUR_STEPS.length - 1;
6237
+ return lit.html`
6238
+ <div
6239
+ role="dialog"
6240
+ aria-label="Example thread tour"
6241
+ style="
6242
+ position: absolute;
6243
+ right: 16px;
6244
+ bottom: 16px;
6245
+ z-index: 3;
6246
+ width: min(340px, calc(100% - 32px));
6247
+ border: 1px solid #dbdbe5;
6248
+ border-radius: 8px;
6249
+ background: #ffffff;
6250
+ padding: 14px;
6251
+ box-shadow: 0 16px 36px rgba(1, 5, 7, 0.14);
6252
+ color: #57575b;
6253
+ "
6254
+ >
6255
+ <div
6256
+ style="
6257
+ margin-bottom: 8px;
6258
+ font-family: 'Spline Sans Mono', monospace;
6259
+ font-size: 10px;
6260
+ font-weight: 600;
6261
+ color: #189370;
6262
+ text-transform: uppercase;
6263
+ "
6264
+ >
6265
+ ${this.exampleTourStep + 1}/${THREADS_EXAMPLE_TOUR_STEPS.length}
6266
+ ${step.label}
6267
+ </div>
6268
+ <div
6269
+ style="
6270
+ margin-bottom: 6px;
6271
+ font-size: 14px;
6272
+ line-height: 1.35;
6273
+ font-weight: 600;
6274
+ color: #010507;
6275
+ "
6276
+ >
6277
+ ${step.title}
6278
+ </div>
6279
+ <div style="font-size: 12px; line-height: 1.5; color: #57575b;">
6280
+ ${step.body}
6281
+ </div>
6282
+ <div
6283
+ style="
6284
+ display: flex;
6285
+ justify-content: space-between;
6286
+ gap: 8px;
6287
+ margin-top: 14px;
6288
+ "
6289
+ >
6290
+ <button
6291
+ type="button"
6292
+ style="border:0;background:transparent;color:#838389;font-size:12px;font-weight:600;cursor:pointer;padding:7px 0;"
6293
+ @click=${() => this.dismissExampleTour("skip")}
6294
+ >
6295
+ Skip
6296
+ </button>
6297
+ <div style="display:flex;gap:8px;">
6298
+ <button
6299
+ type="button"
6300
+ style="border:1px solid #dbdbe5;border-radius:6px;background:#ffffff;color:#57575b;font-size:12px;font-weight:600;cursor:pointer;padding:7px 10px;"
6301
+ ?disabled=${isFirst}
6302
+ @click=${() => this.setExampleTourStep(this.exampleTourStep - 1)}
6303
+ >
6304
+ Back
6305
+ </button>
6306
+ <button
6307
+ type="button"
6308
+ style="border:1px solid #010507;border-radius:6px;background:#010507;color:#ffffff;font-size:12px;font-weight:600;cursor:pointer;padding:7px 10px;"
6309
+ @click=${() => isLast ? this.dismissExampleTour("done") : this.setExampleTourStep(this.exampleTourStep + 1)}
6310
+ >
6311
+ ${isLast ? "Done" : "Next"}
6312
+ </button>
6313
+ </div>
6314
+ </div>
6315
+ </div>
6316
+ `;
6317
+ }
5653
6318
  renderThreadsLockedBackgroundMockup() {
5654
6319
  return lit.html`
5655
6320
  <div
@@ -5895,29 +6560,7 @@ ${argsString}</pre
5895
6560
  "
5896
6561
  >
5897
6562
  <a
5898
- href=${this.getTalkToEngineerUrl()}
5899
- target="_blank"
5900
- rel="noopener"
5901
- style="
5902
- display: inline-flex;
5903
- min-height: 34px;
5904
- align-items: center;
5905
- justify-content: center;
5906
- gap: 6px;
5907
- border-radius: 6px;
5908
- background: #010507;
5909
- padding: 8px 12px;
5910
- font-size: 12px;
5911
- font-weight: 600;
5912
- color: #ffffff;
5913
- text-decoration: none;
5914
- "
5915
- @click=${this.handleThreadsTalkToEngineerClick}
5916
- >
5917
- Talk to an Engineer
5918
- </a>
5919
- <a
5920
- href=${this.getIntelligenceSignupUrl()}
6563
+ href=${this.getThreadsIntelligenceSignupUrl()}
5921
6564
  target="_blank"
5922
6565
  rel="noopener"
5923
6566
  style="
@@ -6250,27 +6893,15 @@ ${argsString}</pre
6250
6893
  }
6251
6894
  renderThreadsView() {
6252
6895
  if (!this.areThreadEndpointsAvailable()) return this.renderThreadsLockedView();
6253
- const displayThreads = this.selectedContext === "all-agents" ? this._threads : this._threadsByAgent.get(this.selectedContext) ?? [];
6254
- let threadsErrorMessage = null;
6255
- if (this.selectedContext === "all-agents") threadsErrorMessage = this._threadsErrorByAgent.values().next().value?.message ?? null;
6256
- else threadsErrorMessage = this._threadsErrorByAgent.get(this.selectedContext)?.message ?? null;
6257
- const selectedThread = this.selectedThreadId != null ? displayThreads.find((t) => t.id === this.selectedThreadId) ?? null : null;
6896
+ const { displayThreads, threadsErrorMessage } = this.getActiveThreadsState();
6897
+ const showingExamples = this.shouldRenderExampleThreads(displayThreads, threadsErrorMessage);
6898
+ const visibleThreads = this.getVisibleThreads(displayThreads, threadsErrorMessage);
6899
+ if (showingExamples) this.trackThreadsExampleViewedOnce();
6900
+ const selectedThread = this.selectedThreadId != null ? visibleThreads.find((t) => t.id === this.selectedThreadId) ?? null : null;
6901
+ const selectedThreadIsExample = this.isExampleThreadId(selectedThread?.id);
6258
6902
  if (!threadsErrorMessage) this.trackThreadsViewStateOnce(displayThreads.length === 0 ? "empty_enabled" : "enabled", displayThreads.length);
6259
6903
  return lit.html`
6260
6904
  <div style="display:flex;height:100%;overflow:hidden;flex-direction:column;">
6261
- <div
6262
- style="display:flex;align-items:center;justify-content:flex-end;border-bottom:1px solid #DBDBE5;background:#ffffff;padding:8px 12px;flex-shrink:0;"
6263
- >
6264
- <a
6265
- href=${this.getTalkToEngineerUrl()}
6266
- target="_blank"
6267
- rel="noopener"
6268
- 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;"
6269
- @click=${this.handleTalkToEngineerClick}
6270
- >
6271
- Talk to an Engineer
6272
- </a>
6273
- </div>
6274
6905
  <div style="display:flex;min-height:0;flex:1;overflow:hidden;">
6275
6906
  <!-- Left sidebar: thread list -->
6276
6907
  <div
@@ -6278,12 +6909,11 @@ ${argsString}</pre
6278
6909
  >
6279
6910
  <cpk-thread-list
6280
6911
  style="height:100%;"
6281
- .threads=${displayThreads}
6912
+ .threads=${visibleThreads}
6282
6913
  .selectedThreadId=${this.selectedThreadId}
6283
6914
  .errorMessage=${threadsErrorMessage}
6284
6915
  @threadSelected=${(e) => {
6285
- this.selectedThreadId = e.detail;
6286
- this.requestUpdate();
6916
+ this.handleThreadsThreadSelected(e.detail, showingExamples);
6287
6917
  }}
6288
6918
  ></cpk-thread-list>
6289
6919
  </div>
@@ -6298,18 +6928,20 @@ ${argsString}</pre
6298
6928
  ></div>
6299
6929
 
6300
6930
  <!-- Center + right: thread details or empty state -->
6301
- <div style="flex:1;min-width:0;overflow:hidden;display:flex;">
6931
+ <div style="flex:1;min-width:0;overflow:hidden;display:flex;position:relative;">
6302
6932
  ${selectedThread ? lit.html`<cpk-thread-details
6303
6933
  style="flex:1;min-width:0;"
6304
6934
  .threadId=${selectedThread.id}
6305
6935
  .thread=${selectedThread}
6936
+ .provider=${selectedThreadIsExample ? this.getExampleThreadProvider(selectedThread.id) : null}
6306
6937
  .runtimeUrl=${this._core?.runtimeUrl ?? ""}
6307
6938
  .headers=${this._core?.headers ?? {}}
6308
- .threadInspectionAvailable=${this._core?.threadEndpoints?.inspect !== false}
6939
+ .threadInspectionAvailable=${selectedThreadIsExample || this._core?.threadEndpoints?.inspect !== false}
6309
6940
  .liveMessageVersion=${this.liveMessageVersion.get(selectedThread.id) ?? 0}
6310
6941
  .agentStateInput=${this.getLatestStateForAgent(selectedThread.agentId)}
6311
6942
  .agentEventsInput=${this.agentEvents.get(selectedThread.agentId) ?? []}
6312
- ></cpk-thread-details>` : lit.html`
6943
+ ></cpk-thread-details>
6944
+ ${selectedThreadIsExample ? this.renderThreadsExampleTour() : lit.nothing}` : showingExamples ? this.renderThreadsExampleOverview() : lit.html`
6313
6945
  <div
6314
6946
  style="
6315
6947
  flex: 1;