@copilotkit/web-inspector 1.61.1 → 1.61.2

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
@@ -33,6 +33,8 @@ const DEFAULT_WINDOW_SIZE = {
33
33
  const DOCKED_LEFT_WIDTH = 500;
34
34
  const MAX_AGENT_EVENTS = 200;
35
35
  const MAX_TOTAL_EVENTS = 500;
36
+ const INTELLIGENCE_SIGNUP_URL = "https://go.copilotkit.ai/intelligence-signup";
37
+ const TALK_TO_ENGINEER_URL = "https://www.copilotkit.ai/talk-to-an-engineer";
36
38
  const AGENT_EVENT_TYPES = [
37
39
  "RUN_STARTED",
38
40
  "RUN_FINISHED",
@@ -108,14 +110,14 @@ function eventColors(type) {
108
110
  bg: "rgba(190,194,255,0.102)",
109
111
  fg: "#5558B2"
110
112
  };
113
+ if (type === "RUN_ERROR" || type === "ERROR") return {
114
+ bg: "rgba(250,95,103,0.13)",
115
+ fg: "#c0333a"
116
+ };
111
117
  if (type.startsWith("RUN_") || type.startsWith("STEP_")) return {
112
118
  bg: "rgba(255,172,77,0.2)",
113
119
  fg: "#996300"
114
120
  };
115
- if (type === "ERROR") return {
116
- bg: "rgba(250,95,103,0.13)",
117
- fg: "#c0333a"
118
- };
119
121
  return {
120
122
  bg: "#F7F7F9",
121
123
  fg: "#838389"
@@ -1141,7 +1143,7 @@ var ɵCpkThreadDetails = class ɵCpkThreadDetails extends lit.LitElement {
1141
1143
  this._messagesError = null;
1142
1144
  }
1143
1145
  try {
1144
- const res = await fetch(`${this.runtimeUrl}/threads/${encodeURIComponent(threadId)}/messages`, {
1146
+ const res = await fetch(this.getThreadInspectionUrl(threadId, "messages"), {
1145
1147
  headers: { ...this.headers },
1146
1148
  signal: controller.signal
1147
1149
  });
@@ -1171,7 +1173,7 @@ var ɵCpkThreadDetails = class ɵCpkThreadDetails extends lit.LitElement {
1171
1173
  this._loadingEvents = true;
1172
1174
  this._eventsError = null;
1173
1175
  try {
1174
- const res = await fetch(`${this.runtimeUrl}/threads/${encodeURIComponent(threadId)}/events`, {
1176
+ const res = await fetch(this.getThreadInspectionUrl(threadId, "events"), {
1175
1177
  headers: { ...this.headers },
1176
1178
  signal: controller.signal
1177
1179
  });
@@ -1205,7 +1207,7 @@ var ɵCpkThreadDetails = class ɵCpkThreadDetails extends lit.LitElement {
1205
1207
  this._loadingState = true;
1206
1208
  this._stateError = null;
1207
1209
  try {
1208
- const res = await fetch(`${this.runtimeUrl}/threads/${encodeURIComponent(threadId)}/state`, {
1210
+ const res = await fetch(this.getThreadInspectionUrl(threadId, "state"), {
1209
1211
  headers: { ...this.headers },
1210
1212
  signal: controller.signal
1211
1213
  });
@@ -1228,6 +1230,9 @@ var ɵCpkThreadDetails = class ɵCpkThreadDetails extends lit.LitElement {
1228
1230
  if (!controller.signal.aborted && this.threadId === threadId) this._loadingState = false;
1229
1231
  }
1230
1232
  }
1233
+ getThreadInspectionUrl(threadId, resource) {
1234
+ return `${this.runtimeUrl.replace(/\/+$/, "")}/threads/${encodeURIComponent(threadId)}/${resource}`;
1235
+ }
1231
1236
  mapMessages(messages) {
1232
1237
  const items = [];
1233
1238
  const toolCallMap = /* @__PURE__ */ new Map();
@@ -1882,6 +1887,7 @@ var WebInspectorElement = class extends lit.LitElement {
1882
1887
  this.viewedBannerTimestamps = /* @__PURE__ */ new Set();
1883
1888
  this.pendingBannerViewed = null;
1884
1889
  this.clickedBannerIds = /* @__PURE__ */ new Set();
1890
+ this.viewedThreadsTelemetryStates = /* @__PURE__ */ new Set();
1885
1891
  this.contextState = {
1886
1892
  button: {
1887
1893
  position: {
@@ -2087,6 +2093,27 @@ var WebInspectorElement = class extends lit.LitElement {
2087
2093
  this.expandedTools = /* @__PURE__ */ new Set();
2088
2094
  this.expandedContextItems = /* @__PURE__ */ new Set();
2089
2095
  this.copiedContextItems = /* @__PURE__ */ new Set();
2096
+ this.handleTalkToEngineerClick = () => {
2097
+ if (this.core?.telemetryDisabled) return;
2098
+ require_telemetry.trackTalkToEngineerClicked(this.getThreadsTelemetryProps({
2099
+ cta: "talk_to_engineer",
2100
+ cta_surface: "threads_header"
2101
+ }, { includeUrlAttribution: true }));
2102
+ };
2103
+ this.handleThreadsIntelligenceSignupClick = () => {
2104
+ if (this.core?.telemetryDisabled) return;
2105
+ require_telemetry.trackThreadsIntelligenceSignupClicked(this.getThreadsTelemetryProps({
2106
+ cta: "signup",
2107
+ cta_surface: "threads_locked"
2108
+ }, { includeUrlAttribution: true }));
2109
+ };
2110
+ this.handleThreadsTalkToEngineerClick = () => {
2111
+ if (this.core?.telemetryDisabled) return;
2112
+ require_telemetry.trackThreadsTalkToEngineerClicked(this.getThreadsTelemetryProps({
2113
+ cta: "talk_to_engineer",
2114
+ cta_surface: "threads_locked"
2115
+ }, { includeUrlAttribution: true }));
2116
+ };
2090
2117
  this.handleThreadDividerPointerDown = (event) => {
2091
2118
  this.threadDividerResizing = true;
2092
2119
  this.threadDividerPointerId = event.pointerId;
@@ -2214,7 +2241,36 @@ var WebInspectorElement = class extends lit.LitElement {
2214
2241
  }
2215
2242
  ];
2216
2243
  }
2244
+ getThreadServiceStatus() {
2245
+ if (!this._core) return "unknown";
2246
+ if (!this._core.threadEndpoints) return "unknown";
2247
+ return this._core.threadEndpoints?.list === false ? "unavailable" : "available";
2248
+ }
2249
+ areThreadEndpointsAvailable() {
2250
+ return this.getThreadServiceStatus() !== "unavailable";
2251
+ }
2252
+ getThreadsTelemetryProps(extra = {}, options = {}) {
2253
+ const distinctId = options.includeUrlAttribution && !this.core?.telemetryDisabled ? require_telemetry.getTelemetryDistinctIdForUrl() : null;
2254
+ const threadServiceStatus = this.getThreadServiceStatus();
2255
+ return {
2256
+ posthog_distinct_id: distinctId ?? void 0,
2257
+ intelligence_status: threadServiceStatus === "available" ? "intelligence_enabled" : threadServiceStatus === "unavailable" ? "intelligence_not_enabled" : "unknown",
2258
+ thread_service_status: threadServiceStatus,
2259
+ license_status: this.core?.licenseStatus ?? void 0,
2260
+ runtime_mode: this.core?.runtimeMode ?? void 0,
2261
+ runtime_url_type: require_telemetry.getRuntimeUrlType(this.core?.runtimeUrl),
2262
+ telemetry_disabled: this.core?.telemetryDisabled ?? false,
2263
+ ...extra
2264
+ };
2265
+ }
2266
+ getIntelligenceSignupUrl() {
2267
+ return this.appendRefParam(INTELLIGENCE_SIGNUP_URL, "cpk-inspector");
2268
+ }
2269
+ getTalkToEngineerUrl() {
2270
+ return this.appendRefParam(TALK_TO_ENGINEER_URL, "cpk-inspector-threads");
2271
+ }
2217
2272
  subscribeToThreadStore(agentId, store) {
2273
+ if (!this.areThreadEndpointsAvailable()) return;
2218
2274
  if (this._threadStoreSubscriptions.has(agentId)) return;
2219
2275
  const threadsSub = store.select(_copilotkit_core.ɵselectThreads).subscribe((threads) => {
2220
2276
  this._threadsByAgent.set(agentId, threads);
@@ -2255,7 +2311,7 @@ var WebInspectorElement = class extends lit.LitElement {
2255
2311
  if (this.core?.getThreadStore(agentId)) return;
2256
2312
  const core = this.core;
2257
2313
  if (!core?.runtimeUrl) return;
2258
- if (core.threadEndpoints?.list === false) return;
2314
+ if (!this.areThreadEndpointsAvailable()) return;
2259
2315
  const store = (0, _copilotkit_core.ɵcreateThreadStore)({ fetch: globalThis.fetch });
2260
2316
  store.start();
2261
2317
  store.setContext({
@@ -2279,6 +2335,7 @@ var WebInspectorElement = class extends lit.LitElement {
2279
2335
  for (const [agentId, store] of this._ownedThreadStores) store.setContext({
2280
2336
  runtimeUrl: core.runtimeUrl,
2281
2337
  headers: { ...headers },
2338
+ wsUrl: core.intelligence?.wsUrl,
2282
2339
  agentId
2283
2340
  });
2284
2341
  }
@@ -2309,7 +2366,7 @@ var WebInspectorElement = class extends lit.LitElement {
2309
2366
  require_telemetry.maybeShowDisclosure();
2310
2367
  }
2311
2368
  this.flushPendingBannerViewed();
2312
- if (core.threadEndpoints?.list !== false) for (const agentId of this._ownedThreadStores.keys()) this.refreshOwnedThreadStore(agentId);
2369
+ if (this.areThreadEndpointsAvailable()) for (const agentId of this._ownedThreadStores.keys()) this.refreshOwnedThreadStore(agentId);
2313
2370
  else this.teardownOwnedThreadStores();
2314
2371
  } else {
2315
2372
  this._threadsByAgent.clear();
@@ -2356,6 +2413,13 @@ var WebInspectorElement = class extends lit.LitElement {
2356
2413
  };
2357
2414
  this.coreUnsubscribe = core.subscribe(this.coreSubscriber).unsubscribe;
2358
2415
  this.processAgentsChanged(core.agents);
2416
+ if (core.runtimeConnectionStatus === "connected") {
2417
+ if (!core.telemetryDisabled) {
2418
+ require_telemetry.ensureTelemetryDistinctId();
2419
+ require_telemetry.maybeShowDisclosure();
2420
+ }
2421
+ this.flushPendingBannerViewed();
2422
+ }
2359
2423
  const threadStores = typeof core.getThreadStores === "function" ? core.getThreadStores() : {};
2360
2424
  for (const [agentId, store] of Object.entries(threadStores)) this.subscribeToThreadStore(agentId, store);
2361
2425
  if (core.context) this.contextStore = this.normalizeContextStore(core.context);
@@ -2444,10 +2508,10 @@ var WebInspectorElement = class extends lit.LitElement {
2444
2508
  onRunStartedEvent: ({ event }) => {
2445
2509
  this.recordAgentEvent(agentId, "RUN_STARTED", event);
2446
2510
  },
2447
- onRunFinishedEvent: ({ event, result }) => {
2511
+ onRunFinishedEvent: (params) => {
2448
2512
  this.recordAgentEvent(agentId, "RUN_FINISHED", {
2449
- event,
2450
- result
2513
+ event: params.event,
2514
+ result: "result" in params ? params.result : void 0
2451
2515
  });
2452
2516
  this.refreshOwnedThreadStore(agentId);
2453
2517
  },
@@ -2765,13 +2829,13 @@ ${argsString}</pre
2765
2829
  }
2766
2830
  getEventBadgeClasses(type) {
2767
2831
  const base = "font-mono text-[10px] font-medium inline-flex items-center rounded-sm px-1.5 py-0.5 border";
2832
+ if (type === "RUN_ERROR") return `${base} bg-rose-50 text-rose-700 border-rose-200`;
2768
2833
  if (type.startsWith("RUN_")) return `${base} bg-blue-50 text-blue-700 border-blue-200`;
2769
2834
  if (type.startsWith("TEXT_MESSAGE")) return `${base} bg-emerald-50 text-emerald-700 border-emerald-200`;
2770
2835
  if (type.startsWith("TOOL_CALL")) return `${base} bg-amber-50 text-amber-700 border-amber-200`;
2771
2836
  if (type.startsWith("REASONING")) return `${base} bg-fuchsia-50 text-fuchsia-700 border-fuchsia-200`;
2772
2837
  if (type.startsWith("STATE")) return `${base} bg-violet-50 text-violet-700 border-violet-200`;
2773
2838
  if (type.startsWith("MESSAGES")) return `${base} bg-sky-50 text-sky-700 border-sky-200`;
2774
- if (type === "RUN_ERROR") return `${base} bg-rose-50 text-rose-700 border-rose-200`;
2775
2839
  return `${base} bg-gray-100 text-gray-600 border-gray-200`;
2776
2840
  }
2777
2841
  stringifyPayload(payload, pretty) {
@@ -4328,78 +4392,399 @@ ${argsString}</pre
4328
4392
  cta_label: this.announcementCtaLabel ?? void 0
4329
4393
  });
4330
4394
  }
4395
+ trackThreadsViewStateOnce(state, threadCount) {
4396
+ if (this.core?.telemetryDisabled) return;
4397
+ const key = `${state}:${this.getThreadServiceStatus()}`;
4398
+ if (this.viewedThreadsTelemetryStates.has(key)) return;
4399
+ this.viewedThreadsTelemetryStates.add(key);
4400
+ const props = this.getThreadsTelemetryProps({ thread_count: threadCount });
4401
+ if (state === "locked") require_telemetry.trackThreadsLockedViewed(props);
4402
+ else if (state === "empty_enabled") require_telemetry.trackThreadsEmptyEnabledViewed(props);
4403
+ else require_telemetry.trackThreadsEnabledViewed(props);
4404
+ }
4405
+ renderThreadsLockedBackgroundMockup() {
4406
+ return lit.html`
4407
+ <div
4408
+ aria-hidden="true"
4409
+ style="
4410
+ position: absolute;
4411
+ inset: 0;
4412
+ display: grid;
4413
+ grid-template-columns: minmax(180px, 28%) 1fr;
4414
+ overflow: hidden;
4415
+ opacity: 0.58;
4416
+ pointer-events: none;
4417
+ "
4418
+ >
4419
+ <div
4420
+ style="
4421
+ display: flex;
4422
+ flex-direction: column;
4423
+ gap: 12px;
4424
+ padding: 28px 24px;
4425
+ border-right: 1px solid #dbdbe5;
4426
+ background: #fafafa;
4427
+ "
4428
+ >
4429
+ ${[
4430
+ {
4431
+ width: 74,
4432
+ accent: true
4433
+ },
4434
+ { width: 92 },
4435
+ { width: 68 },
4436
+ { width: 84 },
4437
+ { width: 58 },
4438
+ { width: 76 }
4439
+ ].map((row) => lit.html`
4440
+ <div
4441
+ style="
4442
+ padding: 12px;
4443
+ border-radius: 8px;
4444
+ background: ${row.accent ? "#eee6fe" : "#ffffff"};
4445
+ box-shadow: inset 0 0 0 1px #eeeef4;
4446
+ "
4447
+ >
4448
+ <div
4449
+ style="
4450
+ height: 8px;
4451
+ width: ${row.width}%;
4452
+ border-radius: 99px;
4453
+ background: ${row.accent ? "#a984f5" : "#d7d7df"};
4454
+ "
4455
+ ></div>
4456
+ <div
4457
+ style="
4458
+ height: 6px;
4459
+ width: 88%;
4460
+ margin-top: 10px;
4461
+ border-radius: 99px;
4462
+ background: #e3e3eb;
4463
+ "
4464
+ ></div>
4465
+ <div
4466
+ style="
4467
+ height: 6px;
4468
+ width: 62%;
4469
+ margin-top: 7px;
4470
+ border-radius: 99px;
4471
+ background: #e8e8ef;
4472
+ "
4473
+ ></div>
4474
+ </div>
4475
+ `)}
4476
+ </div>
4477
+ <div
4478
+ style="
4479
+ min-width: 0;
4480
+ padding: 42px 48px;
4481
+ background: #ffffff;
4482
+ "
4483
+ >
4484
+ <div
4485
+ style="
4486
+ height: 10px;
4487
+ width: 180px;
4488
+ border-radius: 99px;
4489
+ background: #d7d7df;
4490
+ "
4491
+ ></div>
4492
+ <div
4493
+ style="
4494
+ height: 8px;
4495
+ width: min(520px, 58%);
4496
+ margin-top: 28px;
4497
+ border-radius: 99px;
4498
+ background: #e3e3eb;
4499
+ "
4500
+ ></div>
4501
+ <div
4502
+ style="
4503
+ height: 8px;
4504
+ width: min(430px, 48%);
4505
+ margin-top: 12px;
4506
+ border-radius: 99px;
4507
+ background: #e8e8ef;
4508
+ "
4509
+ ></div>
4510
+ <div
4511
+ style="
4512
+ display: grid;
4513
+ grid-template-columns: repeat(2, minmax(0, 1fr));
4514
+ gap: 16px;
4515
+ max-width: 620px;
4516
+ margin-top: 30px;
4517
+ "
4518
+ >
4519
+ <div
4520
+ style="
4521
+ height: 116px;
4522
+ border-radius: 8px;
4523
+ background: #f5f5f8;
4524
+ box-shadow: inset 0 0 0 1px #eeeef4;
4525
+ "
4526
+ ></div>
4527
+ <div
4528
+ style="
4529
+ height: 116px;
4530
+ border-radius: 8px;
4531
+ background: #f5f5f8;
4532
+ box-shadow: inset 0 0 0 1px #eeeef4;
4533
+ "
4534
+ ></div>
4535
+ </div>
4536
+ <div
4537
+ style="
4538
+ height: 10px;
4539
+ width: min(680px, 74%);
4540
+ margin-top: 34px;
4541
+ border-radius: 99px;
4542
+ background: #e3e3eb;
4543
+ "
4544
+ ></div>
4545
+ <div
4546
+ style="
4547
+ height: 10px;
4548
+ width: min(560px, 60%);
4549
+ margin-top: 14px;
4550
+ border-radius: 99px;
4551
+ background: #e8e8ef;
4552
+ "
4553
+ ></div>
4554
+ </div>
4555
+ </div>
4556
+ `;
4557
+ }
4558
+ renderThreadsLockedView() {
4559
+ this.trackThreadsViewStateOnce("locked", 0);
4560
+ return lit.html`
4561
+ <div
4562
+ style="
4563
+ position: relative;
4564
+ height: 100%;
4565
+ display: flex;
4566
+ align-items: center;
4567
+ justify-content: center;
4568
+ padding: 32px;
4569
+ overflow: hidden;
4570
+ background: #ffffff;
4571
+ "
4572
+ >
4573
+ ${this.renderThreadsLockedBackgroundMockup()}
4574
+ <div
4575
+ aria-hidden="true"
4576
+ style="
4577
+ position: absolute;
4578
+ inset: 0;
4579
+ pointer-events: none;
4580
+ background:
4581
+ 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%);
4582
+ "
4583
+ ></div>
4584
+ <div
4585
+ style="
4586
+ position: relative;
4587
+ z-index: 1;
4588
+ max-width: 440px;
4589
+ text-align: center;
4590
+ color: #57575b;
4591
+ "
4592
+ >
4593
+ <div
4594
+ aria-hidden="true"
4595
+ style="
4596
+ margin: 0 auto 18px;
4597
+ display: flex;
4598
+ justify-content: center;
4599
+ "
4600
+ >
4601
+ <div
4602
+ style="
4603
+ display: flex;
4604
+ height: 44px;
4605
+ width: 44px;
4606
+ align-items: center;
4607
+ justify-content: center;
4608
+ border: 1px solid #dfd6fb;
4609
+ border-radius: 8px;
4610
+ background: #eee6fe;
4611
+ color: #57575b;
4612
+ box-shadow: 0 8px 18px rgba(87, 87, 91, 0.14);
4613
+ "
4614
+ >
4615
+ ${this.renderIcon("Lock")}
4616
+ </div>
4617
+ </div>
4618
+ <h2
4619
+ style="
4620
+ margin: 0 0 8px;
4621
+ font-size: 16px;
4622
+ line-height: 1.35;
4623
+ font-weight: 600;
4624
+ color: #010507;
4625
+ "
4626
+ >
4627
+ Enable Intelligence to inspect Threads.
4628
+ </h2>
4629
+ <p
4630
+ style="
4631
+ margin: 0 auto 18px;
4632
+ max-width: 380px;
4633
+ font-size: 13px;
4634
+ line-height: 1.55;
4635
+ color: #57575b;
4636
+ "
4637
+ >
4638
+ Persist conversations and inspect saved thread history from the
4639
+ Inspector.
4640
+ </p>
4641
+ <div
4642
+ style="
4643
+ display: flex;
4644
+ flex-wrap: wrap;
4645
+ justify-content: center;
4646
+ gap: 8px;
4647
+ "
4648
+ >
4649
+ <a
4650
+ href=${this.getTalkToEngineerUrl()}
4651
+ target="_blank"
4652
+ rel="noopener"
4653
+ style="
4654
+ display: inline-flex;
4655
+ min-height: 34px;
4656
+ align-items: center;
4657
+ justify-content: center;
4658
+ gap: 6px;
4659
+ border-radius: 6px;
4660
+ background: #010507;
4661
+ padding: 8px 12px;
4662
+ font-size: 12px;
4663
+ font-weight: 600;
4664
+ color: #ffffff;
4665
+ text-decoration: none;
4666
+ "
4667
+ @click=${this.handleThreadsTalkToEngineerClick}
4668
+ >
4669
+ Talk to an Engineer
4670
+ </a>
4671
+ <a
4672
+ href=${this.getIntelligenceSignupUrl()}
4673
+ target="_blank"
4674
+ rel="noopener"
4675
+ style="
4676
+ display: inline-flex;
4677
+ min-height: 34px;
4678
+ align-items: center;
4679
+ justify-content: center;
4680
+ gap: 6px;
4681
+ border-radius: 6px;
4682
+ border: 1px solid #dbdbe5;
4683
+ background: #ffffff;
4684
+ padding: 8px 12px;
4685
+ font-size: 12px;
4686
+ font-weight: 600;
4687
+ color: #57575b;
4688
+ text-decoration: none;
4689
+ "
4690
+ @click=${this.handleThreadsIntelligenceSignupClick}
4691
+ >
4692
+ Sign up for Intelligence
4693
+ </a>
4694
+ </div>
4695
+ </div>
4696
+ </div>
4697
+ `;
4698
+ }
4331
4699
  renderThreadsView() {
4700
+ if (!this.areThreadEndpointsAvailable()) return this.renderThreadsLockedView();
4332
4701
  const displayThreads = this.selectedContext === "all-agents" ? this._threads : this._threadsByAgent.get(this.selectedContext) ?? [];
4333
4702
  let threadsErrorMessage = null;
4334
4703
  if (this.selectedContext === "all-agents") threadsErrorMessage = this._threadsErrorByAgent.values().next().value?.message ?? null;
4335
4704
  else threadsErrorMessage = this._threadsErrorByAgent.get(this.selectedContext)?.message ?? null;
4336
4705
  const selectedThread = this.selectedThreadId != null ? displayThreads.find((t) => t.id === this.selectedThreadId) ?? null : null;
4706
+ if (!threadsErrorMessage) this.trackThreadsViewStateOnce(displayThreads.length === 0 ? "empty_enabled" : "enabled", displayThreads.length);
4337
4707
  return lit.html`
4338
- <div style="display:flex;height:100%;overflow:hidden;">
4339
- <!-- Left sidebar: thread list -->
4708
+ <div style="display:flex;height:100%;overflow:hidden;flex-direction:column;">
4340
4709
  <div
4341
- style="width:${this.threadListWidth}px;flex-shrink:0;overflow:hidden;display:flex;flex-direction:column;border-right:1px solid #DBDBE5;"
4710
+ style="display:flex;align-items:center;justify-content:flex-end;border-bottom:1px solid #DBDBE5;background:#ffffff;padding:8px 12px;flex-shrink:0;"
4342
4711
  >
4343
- <cpk-thread-list
4344
- style="height:100%;"
4345
- .threads=${displayThreads}
4346
- .selectedThreadId=${this.selectedThreadId}
4347
- .errorMessage=${threadsErrorMessage}
4348
- @threadSelected=${(e) => {
4712
+ <a
4713
+ href=${this.getTalkToEngineerUrl()}
4714
+ target="_blank"
4715
+ rel="noopener"
4716
+ 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;"
4717
+ @click=${this.handleTalkToEngineerClick}
4718
+ >
4719
+ Talk to an Engineer
4720
+ </a>
4721
+ </div>
4722
+ <div style="display:flex;min-height:0;flex:1;overflow:hidden;">
4723
+ <!-- Left sidebar: thread list -->
4724
+ <div
4725
+ style="width:${this.threadListWidth}px;flex-shrink:0;overflow:hidden;display:flex;flex-direction:column;border-right:1px solid #DBDBE5;"
4726
+ >
4727
+ <cpk-thread-list
4728
+ style="height:100%;"
4729
+ .threads=${displayThreads}
4730
+ .selectedThreadId=${this.selectedThreadId}
4731
+ .errorMessage=${threadsErrorMessage}
4732
+ @threadSelected=${(e) => {
4349
4733
  this.selectedThreadId = e.detail;
4350
4734
  this.requestUpdate();
4351
4735
  }}
4352
- ></cpk-thread-list>
4353
- </div>
4354
-
4355
- <!-- Resize divider -->
4356
- <div
4357
- style="width:4px;flex-shrink:0;cursor:col-resize;background:transparent;position:relative;z-index:1;"
4358
- @pointerdown=${this.handleThreadDividerPointerDown}
4359
- @pointermove=${this.handleThreadDividerPointerMove}
4360
- @pointerup=${this.handleThreadDividerPointerUp}
4361
- @pointercancel=${this.handleThreadDividerPointerUp}
4362
- ></div>
4736
+ ></cpk-thread-list>
4737
+ </div>
4363
4738
 
4364
- <!-- Center + right: thread details or empty state -->
4365
- <div style="flex:1;min-width:0;overflow:hidden;display:flex;">
4366
- ${this.selectedThreadId ? lit.html`<cpk-thread-details
4367
- style="flex:1;min-width:0;"
4368
- .threadId=${this.selectedThreadId}
4369
- .thread=${selectedThread}
4370
- .runtimeUrl=${this._core?.runtimeUrl ?? ""}
4371
- .headers=${this._core?.headers ?? {}}
4372
- .threadInspectionAvailable=${this._core?.threadEndpoints?.inspect !== false}
4373
- .liveMessageVersion=${this.selectedThreadId ? this.liveMessageVersion.get(this.selectedThreadId) ?? 0 : 0}
4374
- .agentStateInput=${selectedThread ? this.getLatestStateForAgent(selectedThread.agentId) : null}
4375
- .agentEventsInput=${selectedThread ? this.agentEvents.get(selectedThread.agentId) ?? [] : []}
4376
- ></cpk-thread-details>` : lit.html`
4377
- <div
4378
- style="
4379
- flex: 1;
4380
- display: flex;
4381
- flex-direction: column;
4382
- align-items: center;
4383
- justify-content: center;
4384
- gap: 8px;
4385
- color: #838389;
4386
- "
4387
- >
4388
- <svg
4389
- width="32"
4390
- height="32"
4391
- viewBox="0 0 24 24"
4392
- fill="none"
4393
- stroke="#c0c0c8"
4394
- stroke-width="1.5"
4395
- stroke-linecap="round"
4396
- stroke-linejoin="round"
4739
+ <!-- Resize divider -->
4740
+ <div
4741
+ style="width:4px;flex-shrink:0;cursor:col-resize;background:transparent;position:relative;z-index:1;"
4742
+ @pointerdown=${this.handleThreadDividerPointerDown}
4743
+ @pointermove=${this.handleThreadDividerPointerMove}
4744
+ @pointerup=${this.handleThreadDividerPointerUp}
4745
+ @pointercancel=${this.handleThreadDividerPointerUp}
4746
+ ></div>
4747
+
4748
+ <!-- Center + right: thread details or empty state -->
4749
+ <div style="flex:1;min-width:0;overflow:hidden;display:flex;">
4750
+ ${selectedThread ? lit.html`<cpk-thread-details
4751
+ style="flex:1;min-width:0;"
4752
+ .threadId=${selectedThread.id}
4753
+ .thread=${selectedThread}
4754
+ .runtimeUrl=${this._core?.runtimeUrl ?? ""}
4755
+ .headers=${this._core?.headers ?? {}}
4756
+ .threadInspectionAvailable=${this._core?.threadEndpoints?.inspect !== false}
4757
+ .liveMessageVersion=${this.liveMessageVersion.get(selectedThread.id) ?? 0}
4758
+ .agentStateInput=${this.getLatestStateForAgent(selectedThread.agentId)}
4759
+ .agentEventsInput=${this.agentEvents.get(selectedThread.agentId) ?? []}
4760
+ ></cpk-thread-details>` : lit.html`
4761
+ <div
4762
+ style="
4763
+ flex: 1;
4764
+ display: flex;
4765
+ flex-direction: column;
4766
+ align-items: center;
4767
+ justify-content: center;
4768
+ gap: 8px;
4769
+ color: #838389;
4770
+ "
4397
4771
  >
4398
- <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" />
4399
- </svg>
4400
- <span style="font-size: 13px">${displayThreads.length === 0 ? "No threads yet" : "Select a thread to inspect"}</span>
4401
- </div>
4402
- `}
4772
+ <svg
4773
+ width="32"
4774
+ height="32"
4775
+ viewBox="0 0 24 24"
4776
+ fill="none"
4777
+ stroke="#c0c0c8"
4778
+ stroke-width="1.5"
4779
+ stroke-linecap="round"
4780
+ stroke-linejoin="round"
4781
+ >
4782
+ <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" />
4783
+ </svg>
4784
+ <span style="font-size: 13px">${displayThreads.length === 0 ? "No threads yet" : "Select a thread to inspect"}</span>
4785
+ </div>
4786
+ `}
4787
+ </div>
4403
4788
  </div>
4404
4789
  </div>
4405
4790
  `;
@@ -4920,7 +5305,7 @@ ${prettyEvent}</pre
4920
5305
  if (this.contextOptions.filter((opt) => opt.key !== "all-agents").length > 1) this.selectedContext = "all-agents";
4921
5306
  }
4922
5307
  if (key === "threads") {
4923
- if (this.selectedMenu !== "threads" && !this.core?.telemetryDisabled) require_telemetry.trackThreadsTabClicked();
5308
+ if (previousMenu !== "threads" && !this.core?.telemetryDisabled) require_telemetry.trackThreadsTabClicked(this.getThreadsTelemetryProps());
4924
5309
  this.autoSelectLatestThread();
4925
5310
  }
4926
5311
  if (key === "ag-ui-events" || key === "agents") requestAnimationFrame(() => {
@@ -5344,6 +5729,22 @@ ${prettyEvent}</pre
5344
5729
  ${this.copiedContextItems.has(id) ? "Copied" : "Copy JSON"}
5345
5730
  </button>
5346
5731
  </div>
5732
+ <pre
5733
+ style="
5734
+ margin: 0;
5735
+ max-height: 180px;
5736
+ overflow: auto;
5737
+ white-space: pre-wrap;
5738
+ word-break: break-word;
5739
+ border-radius: 6px;
5740
+ border: 1px solid #eeeef4;
5741
+ background: #f7f7f9;
5742
+ padding: 10px;
5743
+ font-size: 11px;
5744
+ line-height: 1.5;
5745
+ color: #2d2d30;
5746
+ "
5747
+ >${this.formatContextValue(context.value)}</pre>
5347
5748
  ` : lit.html`
5348
5749
  <div class="flex items-center justify-center py-4 text-xs text-gray-500">
5349
5750
  <span>No value available</span>
@@ -5534,8 +5935,9 @@ ${prettyEvent}</pre
5534
5935
  async convertMarkdownToHtml(markdown) {
5535
5936
  const renderer = new marked.marked.Renderer();
5536
5937
  renderer.link = (href, title, text) => {
5537
- return `<a href="${this.escapeHtmlAttr(this.appendRefParam(href ?? ""))}" target="_blank" rel="noopener"${title ? ` title="${this.escapeHtmlAttr(title)}"` : ""}>${text}</a>`;
5938
+ return `<a href="${this.escapeHtmlAttr(this.isSafeAnnouncementHref(href ?? "") ? this.appendRefParam(href ?? "") : "#")}" target="_blank" rel="noopener"${title ? ` title="${this.escapeHtmlAttr(title)}"` : ""}>${text}</a>`;
5538
5939
  };
5940
+ renderer.html = (html) => escapeHtml(html);
5539
5941
  renderer.code = (code, lang) => {
5540
5942
  const safeLang = (lang ?? "").replace(/[^a-z0-9-]/gi, "");
5541
5943
  return `<div class="announcement-code"><pre><code${safeLang ? ` class="language-${safeLang}"` : ""}>${escapeHtml(code)}</code></pre><div class="announcement-code__copy-shield"><button type="button" class="announcement-code__copy" data-copy="${this.encodeBase64(code)}" aria-label="Copy code">Copy</button></div></div>`;
@@ -5545,6 +5947,14 @@ ${prettyEvent}</pre
5545
5947
  async: false
5546
5948
  });
5547
5949
  }
5950
+ isSafeAnnouncementHref(href) {
5951
+ try {
5952
+ const url = new URL(href, typeof window !== "undefined" ? window.location.href : "https://copilotkit.ai");
5953
+ return url.protocol === "http:" || url.protocol === "https:" || url.protocol === "mailto:";
5954
+ } catch {
5955
+ return false;
5956
+ }
5957
+ }
5548
5958
  encodeBase64(value) {
5549
5959
  if (typeof window === "undefined" || typeof window.btoa !== "function") return "";
5550
5960
  const bytes = new TextEncoder().encode(value);
@@ -5559,19 +5969,25 @@ ${prettyEvent}</pre
5559
5969
  for (let i = 0; i < decoded.length; i++) bytes[i] = decoded.charCodeAt(i);
5560
5970
  return new TextDecoder().decode(bytes);
5561
5971
  }
5562
- appendRefParam(href) {
5972
+ appendRefParam(href, ref = "cpk-inspector") {
5563
5973
  try {
5974
+ const isRootRelative = href.startsWith("/") && !href.startsWith("//");
5564
5975
  const url = new URL(href, typeof window !== "undefined" ? window.location.href : "https://copilotkit.ai");
5565
- if (!url.searchParams.has("ref")) url.searchParams.append("ref", "cpk-inspector");
5566
- if (!url.searchParams.has("posthog_distinct_id") && !this.core?.telemetryDisabled) {
5976
+ if (!url.searchParams.has("ref")) url.searchParams.append("ref", ref);
5977
+ if (!url.searchParams.has("posthog_distinct_id") && !this.core?.telemetryDisabled && this.isCopilotKitDestination(url)) {
5567
5978
  const distinctId = require_telemetry.getTelemetryDistinctIdForUrl();
5568
5979
  if (distinctId) url.searchParams.append("posthog_distinct_id", distinctId);
5569
5980
  }
5981
+ if (isRootRelative) return `${url.pathname}${url.search}${url.hash}`;
5570
5982
  return url.toString();
5571
5983
  } catch {
5572
5984
  return href;
5573
5985
  }
5574
5986
  }
5987
+ isCopilotKitDestination(url) {
5988
+ const hostname = url.hostname.toLowerCase();
5989
+ return hostname === "copilotkit.ai" || hostname.endsWith(".copilotkit.ai");
5990
+ }
5575
5991
  escapeHtmlAttr(value) {
5576
5992
  return escapeHtml(value).replace(/"/g, "&quot;").replace(/'/g, "&#39;");
5577
5993
  }