@copilotkit/web-inspector 1.61.0 → 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"
@@ -405,6 +407,7 @@ var ɵCpkThreadDetails = class ɵCpkThreadDetails extends lit.LitElement {
405
407
  this.thread = null;
406
408
  this.runtimeUrl = "";
407
409
  this.headers = {};
410
+ this.threadInspectionAvailable = false;
408
411
  this.agentStateInput = null;
409
412
  this.agentEventsInput = [];
410
413
  this.liveMessageVersion = 0;
@@ -464,6 +467,7 @@ var ɵCpkThreadDetails = class ɵCpkThreadDetails extends lit.LitElement {
464
467
  thread: { attribute: false },
465
468
  runtimeUrl: { attribute: false },
466
469
  headers: { attribute: false },
470
+ threadInspectionAvailable: { attribute: false },
467
471
  agentStateInput: { attribute: false },
468
472
  agentEventsInput: { attribute: false },
469
473
  liveMessageVersion: { attribute: false },
@@ -1128,7 +1132,7 @@ var ɵCpkThreadDetails = class ɵCpkThreadDetails extends lit.LitElement {
1128
1132
  * so users see an explicit loading indicator on first load.
1129
1133
  */
1130
1134
  async fetchMessages(threadId, silent = false) {
1131
- if (!this.runtimeUrl) {
1135
+ if (!this.runtimeUrl || !this.threadInspectionAvailable) {
1132
1136
  if (!silent) this._conversation = [];
1133
1137
  return;
1134
1138
  }
@@ -1139,7 +1143,7 @@ var ɵCpkThreadDetails = class ɵCpkThreadDetails extends lit.LitElement {
1139
1143
  this._messagesError = null;
1140
1144
  }
1141
1145
  try {
1142
- const res = await fetch(`${this.runtimeUrl}/threads/${encodeURIComponent(threadId)}/messages`, {
1146
+ const res = await fetch(this.getThreadInspectionUrl(threadId, "messages"), {
1143
1147
  headers: { ...this.headers },
1144
1148
  signal: controller.signal
1145
1149
  });
@@ -1160,7 +1164,7 @@ var ɵCpkThreadDetails = class ɵCpkThreadDetails extends lit.LitElement {
1160
1164
  }
1161
1165
  async fetchEvents(threadId) {
1162
1166
  this._eventsNotAvailable = false;
1163
- if (!this.runtimeUrl) {
1167
+ if (!this.runtimeUrl || !this.threadInspectionAvailable) {
1164
1168
  this._fetchedEvents = null;
1165
1169
  return;
1166
1170
  }
@@ -1169,7 +1173,7 @@ var ɵCpkThreadDetails = class ɵCpkThreadDetails extends lit.LitElement {
1169
1173
  this._loadingEvents = true;
1170
1174
  this._eventsError = null;
1171
1175
  try {
1172
- const res = await fetch(`${this.runtimeUrl}/threads/${encodeURIComponent(threadId)}/events`, {
1176
+ const res = await fetch(this.getThreadInspectionUrl(threadId, "events"), {
1173
1177
  headers: { ...this.headers },
1174
1178
  signal: controller.signal
1175
1179
  });
@@ -1194,7 +1198,7 @@ var ɵCpkThreadDetails = class ɵCpkThreadDetails extends lit.LitElement {
1194
1198
  }
1195
1199
  async fetchState(threadId) {
1196
1200
  this._stateNotAvailable = false;
1197
- if (!this.runtimeUrl) {
1201
+ if (!this.runtimeUrl || !this.threadInspectionAvailable) {
1198
1202
  this._fetchedState = null;
1199
1203
  return;
1200
1204
  }
@@ -1203,7 +1207,7 @@ var ɵCpkThreadDetails = class ɵCpkThreadDetails extends lit.LitElement {
1203
1207
  this._loadingState = true;
1204
1208
  this._stateError = null;
1205
1209
  try {
1206
- const res = await fetch(`${this.runtimeUrl}/threads/${encodeURIComponent(threadId)}/state`, {
1210
+ const res = await fetch(this.getThreadInspectionUrl(threadId, "state"), {
1207
1211
  headers: { ...this.headers },
1208
1212
  signal: controller.signal
1209
1213
  });
@@ -1226,6 +1230,9 @@ var ɵCpkThreadDetails = class ɵCpkThreadDetails extends lit.LitElement {
1226
1230
  if (!controller.signal.aborted && this.threadId === threadId) this._loadingState = false;
1227
1231
  }
1228
1232
  }
1233
+ getThreadInspectionUrl(threadId, resource) {
1234
+ return `${this.runtimeUrl.replace(/\/+$/, "")}/threads/${encodeURIComponent(threadId)}/${resource}`;
1235
+ }
1229
1236
  mapMessages(messages) {
1230
1237
  const items = [];
1231
1238
  const toolCallMap = /* @__PURE__ */ new Map();
@@ -1880,6 +1887,7 @@ var WebInspectorElement = class extends lit.LitElement {
1880
1887
  this.viewedBannerTimestamps = /* @__PURE__ */ new Set();
1881
1888
  this.pendingBannerViewed = null;
1882
1889
  this.clickedBannerIds = /* @__PURE__ */ new Set();
1890
+ this.viewedThreadsTelemetryStates = /* @__PURE__ */ new Set();
1883
1891
  this.contextState = {
1884
1892
  button: {
1885
1893
  position: {
@@ -2085,6 +2093,27 @@ var WebInspectorElement = class extends lit.LitElement {
2085
2093
  this.expandedTools = /* @__PURE__ */ new Set();
2086
2094
  this.expandedContextItems = /* @__PURE__ */ new Set();
2087
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
+ };
2088
2117
  this.handleThreadDividerPointerDown = (event) => {
2089
2118
  this.threadDividerResizing = true;
2090
2119
  this.threadDividerPointerId = event.pointerId;
@@ -2212,7 +2241,36 @@ var WebInspectorElement = class extends lit.LitElement {
2212
2241
  }
2213
2242
  ];
2214
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
+ }
2215
2272
  subscribeToThreadStore(agentId, store) {
2273
+ if (!this.areThreadEndpointsAvailable()) return;
2216
2274
  if (this._threadStoreSubscriptions.has(agentId)) return;
2217
2275
  const threadsSub = store.select(_copilotkit_core.ɵselectThreads).subscribe((threads) => {
2218
2276
  this._threadsByAgent.set(agentId, threads);
@@ -2253,11 +2311,13 @@ var WebInspectorElement = class extends lit.LitElement {
2253
2311
  if (this.core?.getThreadStore(agentId)) return;
2254
2312
  const core = this.core;
2255
2313
  if (!core?.runtimeUrl) return;
2314
+ if (!this.areThreadEndpointsAvailable()) return;
2256
2315
  const store = (0, _copilotkit_core.ɵcreateThreadStore)({ fetch: globalThis.fetch });
2257
2316
  store.start();
2258
2317
  store.setContext({
2259
2318
  runtimeUrl: core.runtimeUrl,
2260
- headers: {},
2319
+ headers: { ...core.headers },
2320
+ wsUrl: core.intelligence?.wsUrl,
2261
2321
  agentId
2262
2322
  });
2263
2323
  this._ownedThreadStores.set(agentId, store);
@@ -2269,6 +2329,16 @@ var WebInspectorElement = class extends lit.LitElement {
2269
2329
  if (!store) return;
2270
2330
  store.refresh();
2271
2331
  }
2332
+ updateOwnedThreadStoreHeaders(headers) {
2333
+ const core = this.core;
2334
+ if (!core?.runtimeUrl) return;
2335
+ for (const [agentId, store] of this._ownedThreadStores) store.setContext({
2336
+ runtimeUrl: core.runtimeUrl,
2337
+ headers: { ...headers },
2338
+ wsUrl: core.intelligence?.wsUrl,
2339
+ agentId
2340
+ });
2341
+ }
2272
2342
  removeOwnedThreadStore(agentId) {
2273
2343
  const store = this._ownedThreadStores.get(agentId);
2274
2344
  if (!store) return;
@@ -2296,7 +2366,8 @@ var WebInspectorElement = class extends lit.LitElement {
2296
2366
  require_telemetry.maybeShowDisclosure();
2297
2367
  }
2298
2368
  this.flushPendingBannerViewed();
2299
- for (const agentId of this._ownedThreadStores.keys()) this.refreshOwnedThreadStore(agentId);
2369
+ if (this.areThreadEndpointsAvailable()) for (const agentId of this._ownedThreadStores.keys()) this.refreshOwnedThreadStore(agentId);
2370
+ else this.teardownOwnedThreadStores();
2300
2371
  } else {
2301
2372
  this._threadsByAgent.clear();
2302
2373
  this._threads = [];
@@ -2307,6 +2378,9 @@ var WebInspectorElement = class extends lit.LitElement {
2307
2378
  this.coreProperties = properties;
2308
2379
  this.requestUpdate();
2309
2380
  },
2381
+ onHeadersChanged: ({ headers }) => {
2382
+ this.updateOwnedThreadStoreHeaders(headers);
2383
+ },
2310
2384
  onError: ({ code, error }) => {
2311
2385
  this.lastCoreError = {
2312
2386
  code,
@@ -2339,6 +2413,13 @@ var WebInspectorElement = class extends lit.LitElement {
2339
2413
  };
2340
2414
  this.coreUnsubscribe = core.subscribe(this.coreSubscriber).unsubscribe;
2341
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
+ }
2342
2423
  const threadStores = typeof core.getThreadStores === "function" ? core.getThreadStores() : {};
2343
2424
  for (const [agentId, store] of Object.entries(threadStores)) this.subscribeToThreadStore(agentId, store);
2344
2425
  if (core.context) this.contextStore = this.normalizeContextStore(core.context);
@@ -2427,10 +2508,10 @@ var WebInspectorElement = class extends lit.LitElement {
2427
2508
  onRunStartedEvent: ({ event }) => {
2428
2509
  this.recordAgentEvent(agentId, "RUN_STARTED", event);
2429
2510
  },
2430
- onRunFinishedEvent: ({ event, result }) => {
2511
+ onRunFinishedEvent: (params) => {
2431
2512
  this.recordAgentEvent(agentId, "RUN_FINISHED", {
2432
- event,
2433
- result
2513
+ event: params.event,
2514
+ result: "result" in params ? params.result : void 0
2434
2515
  });
2435
2516
  this.refreshOwnedThreadStore(agentId);
2436
2517
  },
@@ -2748,13 +2829,13 @@ ${argsString}</pre
2748
2829
  }
2749
2830
  getEventBadgeClasses(type) {
2750
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`;
2751
2833
  if (type.startsWith("RUN_")) return `${base} bg-blue-50 text-blue-700 border-blue-200`;
2752
2834
  if (type.startsWith("TEXT_MESSAGE")) return `${base} bg-emerald-50 text-emerald-700 border-emerald-200`;
2753
2835
  if (type.startsWith("TOOL_CALL")) return `${base} bg-amber-50 text-amber-700 border-amber-200`;
2754
2836
  if (type.startsWith("REASONING")) return `${base} bg-fuchsia-50 text-fuchsia-700 border-fuchsia-200`;
2755
2837
  if (type.startsWith("STATE")) return `${base} bg-violet-50 text-violet-700 border-violet-200`;
2756
2838
  if (type.startsWith("MESSAGES")) return `${base} bg-sky-50 text-sky-700 border-sky-200`;
2757
- if (type === "RUN_ERROR") return `${base} bg-rose-50 text-rose-700 border-rose-200`;
2758
2839
  return `${base} bg-gray-100 text-gray-600 border-gray-200`;
2759
2840
  }
2760
2841
  stringifyPayload(payload, pretty) {
@@ -4311,77 +4392,399 @@ ${argsString}</pre
4311
4392
  cta_label: this.announcementCtaLabel ?? void 0
4312
4393
  });
4313
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
+ }
4314
4699
  renderThreadsView() {
4700
+ if (!this.areThreadEndpointsAvailable()) return this.renderThreadsLockedView();
4315
4701
  const displayThreads = this.selectedContext === "all-agents" ? this._threads : this._threadsByAgent.get(this.selectedContext) ?? [];
4316
4702
  let threadsErrorMessage = null;
4317
4703
  if (this.selectedContext === "all-agents") threadsErrorMessage = this._threadsErrorByAgent.values().next().value?.message ?? null;
4318
4704
  else threadsErrorMessage = this._threadsErrorByAgent.get(this.selectedContext)?.message ?? null;
4319
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);
4320
4707
  return lit.html`
4321
- <div style="display:flex;height:100%;overflow:hidden;">
4322
- <!-- Left sidebar: thread list -->
4708
+ <div style="display:flex;height:100%;overflow:hidden;flex-direction:column;">
4323
4709
  <div
4324
- 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;"
4325
4711
  >
4326
- <cpk-thread-list
4327
- style="height:100%;"
4328
- .threads=${displayThreads}
4329
- .selectedThreadId=${this.selectedThreadId}
4330
- .errorMessage=${threadsErrorMessage}
4331
- @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) => {
4332
4733
  this.selectedThreadId = e.detail;
4333
4734
  this.requestUpdate();
4334
4735
  }}
4335
- ></cpk-thread-list>
4336
- </div>
4337
-
4338
- <!-- Resize divider -->
4339
- <div
4340
- style="width:4px;flex-shrink:0;cursor:col-resize;background:transparent;position:relative;z-index:1;"
4341
- @pointerdown=${this.handleThreadDividerPointerDown}
4342
- @pointermove=${this.handleThreadDividerPointerMove}
4343
- @pointerup=${this.handleThreadDividerPointerUp}
4344
- @pointercancel=${this.handleThreadDividerPointerUp}
4345
- ></div>
4736
+ ></cpk-thread-list>
4737
+ </div>
4346
4738
 
4347
- <!-- Center + right: thread details or empty state -->
4348
- <div style="flex:1;min-width:0;overflow:hidden;display:flex;">
4349
- ${this.selectedThreadId ? lit.html`<cpk-thread-details
4350
- style="flex:1;min-width:0;"
4351
- .threadId=${this.selectedThreadId}
4352
- .thread=${selectedThread}
4353
- .runtimeUrl=${this._core?.runtimeUrl ?? ""}
4354
- .headers=${this._core?.headers ?? {}}
4355
- .liveMessageVersion=${this.selectedThreadId ? this.liveMessageVersion.get(this.selectedThreadId) ?? 0 : 0}
4356
- .agentStateInput=${selectedThread ? this.getLatestStateForAgent(selectedThread.agentId) : null}
4357
- .agentEventsInput=${selectedThread ? this.agentEvents.get(selectedThread.agentId) ?? [] : []}
4358
- ></cpk-thread-details>` : lit.html`
4359
- <div
4360
- style="
4361
- flex: 1;
4362
- display: flex;
4363
- flex-direction: column;
4364
- align-items: center;
4365
- justify-content: center;
4366
- gap: 8px;
4367
- color: #838389;
4368
- "
4369
- >
4370
- <svg
4371
- width="32"
4372
- height="32"
4373
- viewBox="0 0 24 24"
4374
- fill="none"
4375
- stroke="#c0c0c8"
4376
- stroke-width="1.5"
4377
- stroke-linecap="round"
4378
- 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
+ "
4379
4771
  >
4380
- <path d="M21 15a2 2 0 0 1-2 2H7l-4 4V5a2 2 0 0 1 2-2h14a2 2 0 0 1 2 2z" />
4381
- </svg>
4382
- <span style="font-size: 13px">${displayThreads.length === 0 ? "No threads yet" : "Select a thread to inspect"}</span>
4383
- </div>
4384
- `}
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>
4385
4788
  </div>
4386
4789
  </div>
4387
4790
  `;
@@ -4902,7 +5305,7 @@ ${prettyEvent}</pre
4902
5305
  if (this.contextOptions.filter((opt) => opt.key !== "all-agents").length > 1) this.selectedContext = "all-agents";
4903
5306
  }
4904
5307
  if (key === "threads") {
4905
- if (this.selectedMenu !== "threads" && !this.core?.telemetryDisabled) require_telemetry.trackThreadsTabClicked();
5308
+ if (previousMenu !== "threads" && !this.core?.telemetryDisabled) require_telemetry.trackThreadsTabClicked(this.getThreadsTelemetryProps());
4906
5309
  this.autoSelectLatestThread();
4907
5310
  }
4908
5311
  if (key === "ag-ui-events" || key === "agents") requestAnimationFrame(() => {
@@ -5326,6 +5729,22 @@ ${prettyEvent}</pre
5326
5729
  ${this.copiedContextItems.has(id) ? "Copied" : "Copy JSON"}
5327
5730
  </button>
5328
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>
5329
5748
  ` : lit.html`
5330
5749
  <div class="flex items-center justify-center py-4 text-xs text-gray-500">
5331
5750
  <span>No value available</span>
@@ -5516,8 +5935,9 @@ ${prettyEvent}</pre
5516
5935
  async convertMarkdownToHtml(markdown) {
5517
5936
  const renderer = new marked.marked.Renderer();
5518
5937
  renderer.link = (href, title, text) => {
5519
- 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>`;
5520
5939
  };
5940
+ renderer.html = (html) => escapeHtml(html);
5521
5941
  renderer.code = (code, lang) => {
5522
5942
  const safeLang = (lang ?? "").replace(/[^a-z0-9-]/gi, "");
5523
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>`;
@@ -5527,6 +5947,14 @@ ${prettyEvent}</pre
5527
5947
  async: false
5528
5948
  });
5529
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
+ }
5530
5958
  encodeBase64(value) {
5531
5959
  if (typeof window === "undefined" || typeof window.btoa !== "function") return "";
5532
5960
  const bytes = new TextEncoder().encode(value);
@@ -5541,19 +5969,25 @@ ${prettyEvent}</pre
5541
5969
  for (let i = 0; i < decoded.length; i++) bytes[i] = decoded.charCodeAt(i);
5542
5970
  return new TextDecoder().decode(bytes);
5543
5971
  }
5544
- appendRefParam(href) {
5972
+ appendRefParam(href, ref = "cpk-inspector") {
5545
5973
  try {
5974
+ const isRootRelative = href.startsWith("/") && !href.startsWith("//");
5546
5975
  const url = new URL(href, typeof window !== "undefined" ? window.location.href : "https://copilotkit.ai");
5547
- if (!url.searchParams.has("ref")) url.searchParams.append("ref", "cpk-inspector");
5548
- 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)) {
5549
5978
  const distinctId = require_telemetry.getTelemetryDistinctIdForUrl();
5550
5979
  if (distinctId) url.searchParams.append("posthog_distinct_id", distinctId);
5551
5980
  }
5981
+ if (isRootRelative) return `${url.pathname}${url.search}${url.hash}`;
5552
5982
  return url.toString();
5553
5983
  } catch {
5554
5984
  return href;
5555
5985
  }
5556
5986
  }
5987
+ isCopilotKitDestination(url) {
5988
+ const hostname = url.hostname.toLowerCase();
5989
+ return hostname === "copilotkit.ai" || hostname.endsWith(".copilotkit.ai");
5990
+ }
5557
5991
  escapeHtmlAttr(value) {
5558
5992
  return escapeHtml(value).replace(/"/g, "&quot;").replace(/'/g, "&#39;");
5559
5993
  }