@copilotkit/web-inspector 1.73.2 → 1.74.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.
Files changed (47) hide show
  1. package/dist/index.cjs +363 -271
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.d.cts +29 -6
  4. package/dist/index.d.cts.map +1 -1
  5. package/dist/index.d.mts +29 -6
  6. package/dist/index.d.mts.map +1 -1
  7. package/dist/index.mjs +364 -272
  8. package/dist/index.mjs.map +1 -1
  9. package/dist/index.umd.js +1274 -628
  10. package/dist/index.umd.js.map +1 -1
  11. package/dist/lib/notification-loader.cjs +38 -0
  12. package/dist/lib/notification-loader.cjs.map +1 -0
  13. package/dist/lib/notification-loader.mjs +38 -0
  14. package/dist/lib/notification-loader.mjs.map +1 -0
  15. package/dist/lib/notifications.cjs +173 -0
  16. package/dist/lib/notifications.cjs.map +1 -0
  17. package/dist/lib/notifications.d.cts +17 -0
  18. package/dist/lib/notifications.d.cts.map +1 -0
  19. package/dist/lib/notifications.d.mts +17 -0
  20. package/dist/lib/notifications.d.mts.map +1 -0
  21. package/dist/lib/notifications.mjs +168 -0
  22. package/dist/lib/notifications.mjs.map +1 -0
  23. package/dist/lib/onboarding-prompt.cjs +11 -17
  24. package/dist/lib/onboarding-prompt.cjs.map +1 -1
  25. package/dist/lib/onboarding-prompt.mjs +11 -17
  26. package/dist/lib/onboarding-prompt.mjs.map +1 -1
  27. package/dist/lib/persistence.cjs +124 -48
  28. package/dist/lib/persistence.cjs.map +1 -1
  29. package/dist/lib/persistence.mjs +121 -45
  30. package/dist/lib/persistence.mjs.map +1 -1
  31. package/dist/lib/telemetry.cjs +42 -0
  32. package/dist/lib/telemetry.cjs.map +1 -1
  33. package/dist/lib/telemetry.d.cts.map +1 -1
  34. package/dist/lib/telemetry.d.mts.map +1 -1
  35. package/dist/lib/telemetry.mjs +35 -1
  36. package/dist/lib/telemetry.mjs.map +1 -1
  37. package/dist/package.cjs +1 -1
  38. package/dist/package.mjs +1 -1
  39. package/dist/styles/generated.cjs +1 -1
  40. package/dist/styles/generated.cjs.map +1 -1
  41. package/dist/styles/generated.mjs +1 -1
  42. package/dist/styles/generated.mjs.map +1 -1
  43. package/dist/styles/notification-article.cjs +244 -0
  44. package/dist/styles/notification-article.cjs.map +1 -0
  45. package/dist/styles/notification-article.mjs +244 -0
  46. package/dist/styles/notification-article.mjs.map +1 -0
  47. package/package.json +4 -3
package/dist/index.cjs CHANGED
@@ -1,10 +1,13 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
2
+ const require_notifications = require('./lib/notifications.cjs');
3
+ const require_notification_loader = require('./lib/notification-loader.cjs');
4
+ const require_persistence = require('./lib/persistence.cjs');
2
5
  const require_generated = require('./styles/generated.cjs');
6
+ const require_notification_article = require('./styles/notification-article.cjs');
3
7
  const require_inspector_logo = require('./assets/inspector-logo.cjs');
4
8
  const require_inspector_logo_kite = require('./assets/inspector-logo-kite.cjs');
5
9
  const require_learning_view = require('./components/learning-view.cjs');
6
10
  const require_context_helpers = require('./lib/context-helpers.cjs');
7
- const require_persistence = require('./lib/persistence.cjs');
8
11
  const require_learning_setup = require('./lib/learning-setup.cjs');
9
12
  const require_inspector_learning = require('./lib/inspector-learning.cjs');
10
13
  const require_pop_out = require('./lib/pop-out.cjs');
@@ -265,7 +268,6 @@ const MIN_WINDOW_WIDTH = 880;
265
268
  const MIN_WINDOW_WIDTH_DOCKED_LEFT = 640;
266
269
  const MIN_WINDOW_HEIGHT = 480;
267
270
  const INSPECTOR_STORAGE_KEY = "cpk:inspector:state";
268
- const ANNOUNCEMENT_URL = "https://cdn.copilotkit.ai/announcements.json";
269
271
  const LAUNCHER_MIN_SIZE = 51.84;
270
272
  const LAUNCHER_MAX_SIZE = 62.208;
271
273
  const DEFAULT_BUTTON_SIZE = {
@@ -1264,6 +1266,7 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
1264
1266
  this._loadingEvents = false;
1265
1267
  this._loadingState = false;
1266
1268
  this._messagesError = null;
1269
+ this._messageRefreshError = null;
1267
1270
  this._eventsError = null;
1268
1271
  this._stateError = null;
1269
1272
  this._expandedTools = /* @__PURE__ */ new Set();
@@ -1356,6 +1359,7 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
1356
1359
  _loadingEvents: { state: true },
1357
1360
  _loadingState: { state: true },
1358
1361
  _messagesError: { state: true },
1362
+ _messageRefreshError: { state: true },
1359
1363
  _eventsError: { state: true },
1360
1364
  _stateError: { state: true },
1361
1365
  _expandedTools: { state: true },
@@ -1432,7 +1436,7 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
1432
1436
  </div>`;
1433
1437
  }
1434
1438
  renderTabContent(id) {
1435
- if (id === "timeline") return lit.html`${this._showEventTimeline ? lit.html`<div class="cpk-td__timeline-toolbar">${this.renderTimelineBulkButtons()}</div>${this.renderTimeline()}` : this._conversation.length || this._loadingMessages || this._messagesError ? this.renderConversation() : this.renderTimeline()}`;
1439
+ if (id === "timeline") return lit.html`${this._messageRefreshError ? lit.html`<div class="cpk-td__status cpk-td__status--error" role="status">${this._messageRefreshError}</div>` : lit.nothing}${this._showEventTimeline ? lit.html`<div class="cpk-td__timeline-toolbar">${this.renderTimelineBulkButtons()}</div>${this.renderTimeline()}` : this._conversation.length || this._loadingMessages || this._messagesError ? this.renderConversation() : this.renderTimeline()}`;
1436
1440
  if (id === "state") return this.renderState();
1437
1441
  return this.renderEvents();
1438
1442
  }
@@ -1985,10 +1989,19 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
1985
1989
  background: #ffffff;
1986
1990
  color: #71717a;
1987
1991
  cursor: pointer;
1992
+ width: 100%;
1993
+ border: 0;
1994
+ font-family: inherit;
1995
+ text-align: left;
1988
1996
  font-size: 11px;
1989
1997
  user-select: none;
1990
1998
  }
1991
1999
 
2000
+ .cpk-td__tool-header:focus-visible {
2001
+ outline: 2px solid var(--cpk-primary-color, #7076b3);
2002
+ outline-offset: -2px;
2003
+ }
2004
+
1992
2005
  .cpk-td__tool-header:hover {
1993
2006
  background: #fafafa;
1994
2007
  }
@@ -2825,7 +2838,7 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
2825
2838
  }
2826
2839
  scrollToFocusedMessage() {
2827
2840
  if (!this.focusMessageId) return;
2828
- const message = Array.from(this.shadowRoot?.querySelectorAll("[data-message-id]") ?? []).find((candidate) => candidate.dataset.messageId === this.focusMessageId);
2841
+ const message = Array.from(this.shadowRoot?.querySelectorAll(`#${this.panelDomId(this._tab)}:not([hidden]) [data-message-id]`) ?? []).find((candidate) => candidate.dataset.messageId === this.focusMessageId);
2829
2842
  if (!message) return;
2830
2843
  message.scrollIntoView?.({ block: "center" });
2831
2844
  this._scrolledFocusRequestId = this.focusRequestId;
@@ -2893,6 +2906,7 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
2893
2906
  this._loadingEvents = false;
2894
2907
  this._loadingState = false;
2895
2908
  this._messagesError = null;
2909
+ this._messageRefreshError = null;
2896
2910
  this._eventsError = null;
2897
2911
  this._stateError = null;
2898
2912
  this._fetchedMetadata = null;
@@ -2911,7 +2925,7 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
2911
2925
  this._fetchedMetadata = metadata;
2912
2926
  } catch (err) {
2913
2927
  if (err instanceof Error && err.name === "AbortError") return;
2914
- if (this.threadId !== threadId) return;
2928
+ if (controller.signal.aborted || this.threadId !== threadId) return;
2915
2929
  this._fetchedMetadata = null;
2916
2930
  }
2917
2931
  }
@@ -2936,19 +2950,23 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
2936
2950
  if (!silent) {
2937
2951
  this._loadingMessages = true;
2938
2952
  this._messagesError = null;
2953
+ this._messageRefreshError = null;
2939
2954
  }
2940
2955
  try {
2941
2956
  const messages = this.provider?.getMessages ? await this.provider.getMessages(threadId, { signal: controller.signal }) : await this.fetchRuntimeMessages(threadId, controller.signal);
2942
2957
  if (controller.signal.aborted || this.threadId !== threadId) return;
2943
2958
  this._conversation = this.mapMessages(messages);
2959
+ this._messagesError = null;
2960
+ this._messageRefreshError = null;
2944
2961
  } catch (err) {
2962
+ if (controller.signal.aborted || this.threadId !== threadId) return;
2945
2963
  if (err instanceof Error && err.name === "AbortError") return;
2946
- if (!silent) {
2964
+ if (!silent || this._conversation.length === 0) {
2947
2965
  this._messagesError = err instanceof Error ? err.message : "Failed to load messages";
2948
2966
  this._conversation = [];
2949
- }
2967
+ } else this._messageRefreshError = "Could not refresh messages. Showing the last loaded conversation.";
2950
2968
  } finally {
2951
- if (!silent && !controller.signal.aborted) this._loadingMessages = false;
2969
+ if (!controller.signal.aborted && this.threadId === threadId) this._loadingMessages = false;
2952
2970
  }
2953
2971
  }
2954
2972
  async fetchEvents(threadId) {
@@ -2975,7 +2993,7 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
2975
2993
  this._fetchedEvents = this.mapApiEvents(result.events);
2976
2994
  } catch (err) {
2977
2995
  if (err instanceof Error && err.name === "AbortError") return;
2978
- if (this.threadId !== threadId) return;
2996
+ if (controller.signal.aborted || this.threadId !== threadId) return;
2979
2997
  this._eventsError = err instanceof Error ? err.message : "Failed to load events";
2980
2998
  this._fetchedEvents = [];
2981
2999
  } finally {
@@ -3006,7 +3024,7 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
3006
3024
  this._fetchedState = result.state ?? null;
3007
3025
  } catch (err) {
3008
3026
  if (err instanceof Error && err.name === "AbortError") return;
3009
- if (this.threadId !== threadId) return;
3027
+ if (controller.signal.aborted || this.threadId !== threadId) return;
3010
3028
  this._stateError = err instanceof Error ? err.message : "Failed to load state";
3011
3029
  this._fetchedState = null;
3012
3030
  } finally {
@@ -3083,6 +3101,7 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
3083
3101
  toolCallId: tc.id,
3084
3102
  arguments: args,
3085
3103
  result: null,
3104
+ hasResult: false,
3086
3105
  createdAt: ""
3087
3106
  };
3088
3107
  toolCallMap.set(tc.id, item);
@@ -3103,18 +3122,23 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
3103
3122
  });
3104
3123
  else if (msg.role === "tool" && msg.toolCallId) {
3105
3124
  const tc = toolCallMap.get(msg.toolCallId);
3106
- if (tc) try {
3107
- tc.result = this.parseToolCallContent(msg.content);
3108
- } catch (err) {
3109
- console.error("[CopilotKit Inspector] Failed to parse tool-call result content", {
3110
- toolCallId: msg.toolCallId,
3111
- raw: msg.content,
3112
- error: err
3113
- });
3114
- tc.result = {
3115
- __parseError: true,
3116
- __raw: msg.content ?? null
3117
- };
3125
+ if (tc) {
3126
+ tc.hasResult = true;
3127
+ tc.resultUnreadable = false;
3128
+ try {
3129
+ tc.result = this.parseToolCallContent(msg.content);
3130
+ } catch (err) {
3131
+ console.error("[CopilotKit Inspector] Failed to parse tool-call result content", {
3132
+ toolCallId: msg.toolCallId,
3133
+ raw: msg.content,
3134
+ error: err
3135
+ });
3136
+ tc.resultUnreadable = true;
3137
+ tc.result = {
3138
+ __parseError: true,
3139
+ __raw: msg.content ?? null
3140
+ };
3141
+ }
3118
3142
  }
3119
3143
  }
3120
3144
  return items;
@@ -3870,13 +3894,60 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
3870
3894
  <span>No messages yet</span>
3871
3895
  </div>
3872
3896
  `;
3897
+ const items = this.renderItems;
3898
+ const errors = this.conversationRunErrors(items);
3873
3899
  return this.cachedPanelTpl("timeline-fallback", [
3874
3900
  this._conversation,
3875
3901
  this._expandedTools,
3876
- this._expandedMessages
3902
+ this._expandedMessages,
3903
+ JSON.stringify(errors),
3904
+ this._expandedTimelineDetails
3877
3905
  ], () => {
3878
- return lit.html`${this.renderItems.map((item) => this.renderRenderItem(item))}`;
3906
+ const errorsAfter = /* @__PURE__ */ new Map();
3907
+ for (const { after, item } of errors) {
3908
+ const group = errorsAfter.get(after) ?? [];
3909
+ group.push(item);
3910
+ errorsAfter.set(after, group);
3911
+ }
3912
+ const renderErrors = (after) => errorsAfter.get(after)?.map((item) => this.renderTimelineItem(item));
3913
+ return lit.html`
3914
+ ${renderErrors(-1)}
3915
+ ${items.map((item, index) => lit.html`${this.renderRenderItem(item)}${renderErrors(index)}`)}
3916
+ `;
3917
+ });
3918
+ }
3919
+ conversationRunErrors(items) {
3920
+ const positions = /* @__PURE__ */ new Map();
3921
+ items.forEach((item, index) => {
3922
+ positions.set(item.id, index);
3923
+ if (item.type === "tool_call_group") for (const tool of item.items) positions.set(tool.id, index);
3879
3924
  });
3925
+ const errors = [];
3926
+ let after = -1;
3927
+ let hasAnchor = false;
3928
+ for (const event of this.activeEvents) {
3929
+ const id = (event.type.startsWith("TOOL_CALL") ? [
3930
+ "toolCallId",
3931
+ "tool_call_id",
3932
+ "callId",
3933
+ "id"
3934
+ ] : event.type.startsWith("TEXT_MESSAGE") || event.type.startsWith("ACTIVITY") ? [
3935
+ "messageId",
3936
+ "message_id",
3937
+ "id"
3938
+ ] : []).map((key) => event.payload[key]).find((value) => typeof value === "string");
3939
+ const position = id == null ? void 0 : positions.get(id);
3940
+ if (position !== void 0) {
3941
+ after = Math.max(after, position);
3942
+ hasAnchor = true;
3943
+ }
3944
+ if (event.type === "RUN_ERROR" || event.type === "ERROR") for (const item of this.timelineItemsFromEvents([event])) errors.push({
3945
+ after,
3946
+ item
3947
+ });
3948
+ }
3949
+ if (!hasAnchor) for (const error of errors) error.after = items.length - 1;
3950
+ return errors;
3880
3951
  }
3881
3952
  /**
3882
3953
  * Memoize the rendered TemplateResult for `slot` keyed by tuple
@@ -3950,32 +4021,40 @@ var CpkThreadInspector = class CpkThreadInspector extends PortableLitElement {
3950
4021
  const expanded = this._expandedTools.has(item.id);
3951
4022
  return lit.html`
3952
4023
  <div class="cpk-td__tool-block">
3953
- <div
4024
+ <button
4025
+ type="button"
3954
4026
  class="cpk-td__tool-header"
4027
+ aria-expanded=${expanded}
3955
4028
  @click=${() => this.toggleToolExpand(item.id)}
3956
4029
  >
3957
- <svg width="10" height="10" viewBox="0 0 10 10" fill="none">
4030
+ <svg width="14" height="14" viewBox="0 0 24 24" fill="none" aria-hidden="true">
3958
4031
  <path
3959
- d="M1 9C1 9 2 7 5 7C8 7 9 9 9 9M5 1C5 1 7 2.5 7 4.5C7 6.5 5 7 5 7C5 7 3 6.5 3 4.5C3 2.5 5 1 5 1Z"
4032
+ d="M14.7 6.3a1 1 0 0 0 0 1.4l1.6 1.6a1 1 0 0 0 1.4 0l3.77-3.77a6 6 0 0 1-7.94 7.94l-6.91 6.91a2.12 2.12 0 0 1-3-3l6.91-6.91a6 6 0 0 1 7.94-7.94z"
3960
4033
  stroke="currentColor"
3961
- stroke-width="1.2"
4034
+ stroke-width="2"
3962
4035
  stroke-linecap="round"
3963
4036
  stroke-linejoin="round"
3964
4037
  />
3965
4038
  </svg>
3966
4039
  <span class="cpk-td__tool-name">${item.toolName}</span>
3967
- ${item.result || Object.keys(item.arguments).length > 0 ? lit.html`
3968
- <span class="cpk-td__tool-status">Complete</span>
3969
- ` : lit.html`
3970
- <span class="cpk-td__tool-status cpk-td__tool-status--pending">Pending</span>
3971
- `}
4040
+ ${item.resultUnreadable ? lit.html`
4041
+ <span class="cpk-td__tool-status cpk-td__tool-status--pending"
4042
+ >Result unreadable</span
4043
+ >
4044
+ ` : item.hasResult ? lit.html`
4045
+ <span class="cpk-td__tool-status">Result received</span>
4046
+ ` : lit.html`
4047
+ <span class="cpk-td__tool-status cpk-td__tool-status--pending"
4048
+ >No result recorded</span
4049
+ >
4050
+ `}
3972
4051
  <span class="cpk-td__tool-chevron">${expanded ? "▾" : "▸"}</span>
3973
- </div>
4052
+ </button>
3974
4053
  ${expanded ? lit.html`
3975
4054
  <div class="cpk-td__tool-body">
3976
4055
  <div class="cpk-td__tool-section-label">Arguments</div>
3977
4056
  ${renderHighlightedJsonBlock(item.arguments)}
3978
- ${item.result ? lit.html`
4057
+ ${item.hasResult ? lit.html`
3979
4058
  <div
3980
4059
  class="cpk-td__tool-section-label"
3981
4060
  style="margin-top:8px"
@@ -5055,11 +5134,13 @@ var WebInspectorElement = class WebInspectorElement extends lit.LitElement {
5055
5134
  150
5056
5135
  ];
5057
5136
  this._evtColResize = null;
5137
+ this.notificationContext = { development: false };
5138
+ this.notificationFeed = null;
5139
+ this.notificationState = require_notifications.emptyNotificationState();
5140
+ this.notificationDocuments = /* @__PURE__ */ new Map();
5141
+ this.selectedNotificationId = null;
5058
5142
  this.announcementHtml = null;
5059
- this.announcementMarkdown = null;
5060
- this.announcementTimestamp = null;
5061
- this.announcementPreviewText = null;
5062
- this.announcementCtaLabel = null;
5143
+ this.announcementId = null;
5063
5144
  this.announcementLoaded = false;
5064
5145
  this.announcementPromise = null;
5065
5146
  this.newsSignalArmed = false;
@@ -5096,6 +5177,10 @@ var WebInspectorElement = class WebInspectorElement extends lit.LitElement {
5096
5177
  this.launcherHudIntro = false;
5097
5178
  this.launcherHudIntroStartTimer = null;
5098
5179
  this.launcherHudIntroEndTimer = null;
5180
+ this.viewedHudElement = null;
5181
+ this.launcherHudTrigger = "user";
5182
+ this.viewedHudParts = /* @__PURE__ */ new Set();
5183
+ this.pendingHudTelemetry = [];
5099
5184
  this.inspectorDismissedUntil = null;
5100
5185
  this.lastReportedInspectorVisibility = null;
5101
5186
  this.inspectorDismissalTimer = null;
@@ -5384,9 +5469,18 @@ var WebInspectorElement = class WebInspectorElement extends lit.LitElement {
5384
5469
  this.closeLauncherHud();
5385
5470
  this.activeRoot.querySelector(".console-button")?.focus();
5386
5471
  };
5387
- this.handleHudActionClick = (event, row) => {
5472
+ this.handleHudActionClick = (event, row, control) => {
5388
5473
  event.preventDefault();
5389
5474
  event.stopPropagation();
5475
+ const trigger = this.launcherHudTrigger;
5476
+ this.queueHudTelemetry(() => control === "toggle" ? require_telemetry.trackHudFeatureToggleClicked({
5477
+ feature: row,
5478
+ trigger
5479
+ }) : require_telemetry.trackHudFeatureClicked({
5480
+ feature: row,
5481
+ control,
5482
+ trigger
5483
+ }));
5390
5484
  this.hudLandingMenu = row === "threads" ? "threads" : row === "learning" ? "memories" : "home";
5391
5485
  this.closeLauncherHud();
5392
5486
  this.openInspector("floating_button");
@@ -5394,24 +5488,47 @@ var WebInspectorElement = class WebInspectorElement extends lit.LitElement {
5394
5488
  this.handleHudRowClick = (event, row) => {
5395
5489
  const target = event.target;
5396
5490
  if (target instanceof Element && target.closest(".cpk-launcher-hud__controls, [data-cpk-hud-action]")) return;
5397
- this.handleHudActionClick(event, row);
5491
+ this.handleHudActionClick(event, row, "row");
5398
5492
  };
5399
5493
  this.handleHudNewsClick = (event) => {
5400
5494
  event.preventDefault();
5401
5495
  event.stopPropagation();
5496
+ const banner_id = this.announcementId;
5497
+ if (banner_id) {
5498
+ const trigger = this.launcherHudTrigger;
5499
+ this.queueHudTelemetry(() => require_telemetry.trackHudNotificationClicked({
5500
+ banner_id,
5501
+ notification_id: banner_id,
5502
+ action: "open",
5503
+ trigger
5504
+ }));
5505
+ }
5402
5506
  this.hudLandingMenu = WHATS_NEW_MENU_KEY;
5507
+ if (this.notificationState.activeId) this.readNotification(this.notificationState.activeId);
5403
5508
  this.closeLauncherHud();
5404
5509
  this.openInspector("floating_button");
5405
5510
  };
5406
5511
  this.handleHudNewsDismissClick = (event) => {
5407
5512
  event.preventDefault();
5408
5513
  event.stopPropagation();
5514
+ const banner_id = this.announcementId;
5515
+ if (banner_id) {
5516
+ const trigger = this.launcherHudTrigger;
5517
+ this.queueHudTelemetry(() => require_telemetry.trackHudNotificationClicked({
5518
+ banner_id,
5519
+ notification_id: banner_id,
5520
+ action: "dismiss",
5521
+ trigger
5522
+ }));
5523
+ }
5409
5524
  this.clearNewsSignal();
5410
5525
  this.activeRoot.querySelector(".console-button")?.focus({ preventScroll: true });
5411
5526
  };
5412
5527
  this.handleHudDismissDayClick = (event) => {
5413
5528
  event.preventDefault();
5414
5529
  event.stopPropagation();
5530
+ const trigger = this.launcherHudTrigger;
5531
+ this.queueHudTelemetry(() => require_telemetry.trackHudHideClicked({ trigger }));
5415
5532
  this.dismissInspectorFor("day");
5416
5533
  };
5417
5534
  this.handleSidebarToggle = () => {
@@ -6062,6 +6179,7 @@ var WebInspectorElement = class WebInspectorElement extends lit.LitElement {
6062
6179
  static {
6063
6180
  this.properties = {
6064
6181
  core: { attribute: false },
6182
+ notificationContext: { attribute: false },
6065
6183
  autoAttachCore: {
6066
6184
  type: Boolean,
6067
6185
  attribute: "auto-attach-core"
@@ -6497,6 +6615,7 @@ var WebInspectorElement = class WebInspectorElement extends lit.LitElement {
6497
6615
  runtimeLicense = void 0;
6498
6616
  }
6499
6617
  this.inspectorMetadataProjection = require_inspector_metadata.projectInspectorMetadata(value, runtimeLicense);
6618
+ this.refreshNotifications();
6500
6619
  }
6501
6620
  attachToCore(core) {
6502
6621
  this.runtimeStatus = core.runtimeConnectionStatus;
@@ -7850,158 +7969,7 @@ var WebInspectorElement = class WebInspectorElement extends lit.LitElement {
7850
7969
  font-weight: 600 !important;
7851
7970
  }
7852
7971
 
7853
- .announcement-content {
7854
- color: #1f2230;
7855
- font-size: 13px;
7856
- font-family: "Plus Jakarta Sans", system-ui, sans-serif;
7857
- line-height: 1.55;
7858
- }
7859
-
7860
- .announcement-content h1,
7861
- .announcement-content h2,
7862
- .announcement-content h3 {
7863
- color: #010507;
7864
- font-weight: 700;
7865
- line-height: 1.3;
7866
- margin: 0.9rem 0 0.4rem;
7867
- }
7868
- .announcement-content > h1:first-child,
7869
- .announcement-content > h2:first-child,
7870
- .announcement-content > h3:first-child {
7871
- margin-top: 0;
7872
- }
7873
-
7874
- .announcement-content h1 {
7875
- font-size: 1.15rem;
7876
- letter-spacing: -0.01em;
7877
- }
7878
- .announcement-content h2 {
7879
- font-size: 1rem;
7880
- }
7881
- .announcement-content h3 {
7882
- font-size: 0.9rem;
7883
- text-transform: none;
7884
- }
7885
-
7886
- .announcement-content p {
7887
- margin: 0.45rem 0;
7888
- }
7889
-
7890
- .announcement-content strong {
7891
- color: #010507;
7892
- font-weight: 700;
7893
- }
7894
-
7895
- .announcement-content ul {
7896
- list-style: disc;
7897
- padding-left: 1.25rem;
7898
- margin: 0.45rem 0;
7899
- }
7900
-
7901
- .announcement-content ol {
7902
- list-style: decimal;
7903
- padding-left: 1.25rem;
7904
- margin: 0.45rem 0;
7905
- }
7906
-
7907
- .announcement-content li + li {
7908
- margin-top: 0.15rem;
7909
- }
7910
-
7911
- .announcement-content a {
7912
- color: #5558b2;
7913
- text-decoration: underline;
7914
- }
7915
-
7916
- .announcement-content :not(pre) > code {
7917
- background: #f3f3f7;
7918
- border: 1px solid #e4e4ec;
7919
- border-radius: 5px;
7920
- padding: 1px 5px;
7921
- font-size: 0.85em;
7922
- color: #4a3a8a;
7923
- }
7924
-
7925
- .announcement-code {
7926
- position: relative;
7927
- margin: 0.6rem 0;
7928
- }
7929
-
7930
- .announcement-code pre {
7931
- background: #0f1117;
7932
- color: #e6e8f2;
7933
- border-radius: 10px;
7934
- padding: 10px 12px;
7935
- overflow-x: auto;
7936
- font-size: 12px;
7937
- line-height: 1.5;
7938
- white-space: pre;
7939
- }
7940
-
7941
- .announcement-code pre code::after {
7942
- content: "";
7943
- display: inline-block;
7944
- width: 80px;
7945
- }
7946
-
7947
- .announcement-code__copy-shield {
7948
- position: absolute;
7949
- top: 4px;
7950
- right: 4px;
7951
- padding: 4px 4px 4px 24px;
7952
- border-top-right-radius: 10px;
7953
- background: linear-gradient(
7954
- to right,
7955
- rgba(15, 17, 23, 0) 0%,
7956
- rgba(15, 17, 23, 0.95) 40%,
7957
- #0f1117 100%
7958
- );
7959
- pointer-events: none;
7960
- }
7961
-
7962
- .announcement-code pre code {
7963
- background: transparent;
7964
- border: none;
7965
- padding: 0;
7966
- color: inherit;
7967
- font-size: inherit;
7968
- }
7969
-
7970
- .announcement-code pre::-webkit-scrollbar {
7971
- height: 6px;
7972
- }
7973
- .announcement-code pre::-webkit-scrollbar-track {
7974
- background: transparent;
7975
- }
7976
- .announcement-code pre::-webkit-scrollbar-thumb {
7977
- background: rgba(255, 255, 255, 0.2);
7978
- border-radius: 4px;
7979
- }
7980
-
7981
- .announcement-code__copy {
7982
- position: relative;
7983
- pointer-events: auto;
7984
- padding: 3px 8px;
7985
- font-family: "Plus Jakarta Sans", system-ui, sans-serif;
7986
- font-size: 11px;
7987
- font-weight: 600;
7988
- color: #e6e8f2;
7989
- background: #1f222d;
7990
- border: 1px solid rgba(255, 255, 255, 0.15);
7991
- border-radius: 6px;
7992
- cursor: pointer;
7993
- transition:
7994
- background 0.12s ease,
7995
- color 0.12s ease;
7996
- }
7997
- .announcement-code__copy:hover {
7998
- background: #2a2e3c;
7999
- }
8000
- .announcement-code__copy[data-copied="true"] {
8001
- background: #eee6fe;
8002
- color: #6430ab;
8003
- border-color: transparent;
8004
- }
7972
+ ${require_notification_article.notificationArticleStyles}
8005
7973
 
8006
7974
  /* ── What's new ──────────────────────────────────────────────── */
8007
7975
  .whats-new {
@@ -9529,6 +9497,7 @@ var WebInspectorElement = class WebInspectorElement extends lit.LitElement {
9529
9497
  }
9530
9498
  connectedCallback() {
9531
9499
  super.connectedCallback();
9500
+ this.notificationState = require_persistence.loadNotificationState();
9532
9501
  if (typeof window !== "undefined") {
9533
9502
  this.accountCtaMotionPaused = document.visibilityState !== "visible";
9534
9503
  this.threadsExampleOverviewVideoReducedMotion = window.matchMedia?.("(prefers-reduced-motion: reduce)").matches ?? false;
@@ -9643,7 +9612,11 @@ var WebInspectorElement = class WebInspectorElement extends lit.LitElement {
9643
9612
  if (this.isOpen && this.dockMode === "docked-left") this.setAttribute("data-docked", "true");
9644
9613
  else this.removeAttribute("data-docked");
9645
9614
  }
9646
- updated() {
9615
+ updated(changed) {
9616
+ if (changed.has("notificationContext") || changed.has("core")) {
9617
+ this.ensureAnnouncementLoading();
9618
+ this.refreshNotifications();
9619
+ }
9647
9620
  const visible = !this.isInspectorDismissed;
9648
9621
  if (visible !== this.lastReportedInspectorVisibility) {
9649
9622
  this.lastReportedInspectorVisibility = visible;
@@ -9653,6 +9626,7 @@ var WebInspectorElement = class WebInspectorElement extends lit.LitElement {
9653
9626
  this.syncThreadsExampleOverviewVideo();
9654
9627
  this.maybeTrackInspectorMetadataViews();
9655
9628
  this.maybeTrackNewsSignalViewed();
9629
+ this.maybeTrackHudViews();
9656
9630
  this.resolvePillDirection();
9657
9631
  this.maybeTrackErrorSignalViewed();
9658
9632
  this.maybeCompleteWhatsNewView();
@@ -9894,6 +9868,7 @@ var WebInspectorElement = class WebInspectorElement extends lit.LitElement {
9894
9868
  this.resolveLauncherHudSide();
9895
9869
  this.launcherHudIntro = true;
9896
9870
  this.launcherHudOpen = true;
9871
+ this.launcherHudTrigger = "intro";
9897
9872
  this.refreshLearningSnapshot({ preserve: true });
9898
9873
  this.requestUpdate();
9899
9874
  this.launcherHudIntroEndTimer = setTimeout(() => {
@@ -9942,6 +9917,7 @@ var WebInspectorElement = class WebInspectorElement extends lit.LitElement {
9942
9917
  }
9943
9918
  if (this.launcherHudOpen) return;
9944
9919
  this.launcherHudOpen = true;
9920
+ this.launcherHudTrigger = "user";
9945
9921
  this.refreshLearningSnapshot({ preserve: true });
9946
9922
  this.requestUpdate();
9947
9923
  }
@@ -9953,11 +9929,61 @@ var WebInspectorElement = class WebInspectorElement extends lit.LitElement {
9953
9929
  }
9954
9930
  if (!this.launcherHudOpen) return;
9955
9931
  this.launcherHudOpen = false;
9932
+ this.viewedHudElement = null;
9933
+ this.viewedHudParts.clear();
9956
9934
  this.requestUpdate();
9957
9935
  }
9936
+ queueHudTelemetry(send) {
9937
+ if (this.core?.telemetryDisabled) return;
9938
+ if (this.runtimeStatus === _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Connected) send();
9939
+ else if (this.pendingHudTelemetry.length < MAX_PENDING_BANNER_VIEWED) this.pendingHudTelemetry.push(send);
9940
+ }
9941
+ flushPendingHudTelemetry() {
9942
+ if (this.core?.telemetryDisabled) {
9943
+ this.pendingHudTelemetry = [];
9944
+ return;
9945
+ }
9946
+ if (this.runtimeStatus !== _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Connected) return;
9947
+ const queued = this.pendingHudTelemetry;
9948
+ this.pendingHudTelemetry = [];
9949
+ for (const send of queued) send();
9950
+ }
9951
+ maybeTrackHudViews() {
9952
+ const hud = this.activeRoot.querySelector("[data-cpk-launcher-hud]");
9953
+ if (!hud) {
9954
+ this.viewedHudElement = null;
9955
+ this.viewedHudParts.clear();
9956
+ return;
9957
+ }
9958
+ if (document.visibilityState !== "visible") return;
9959
+ if (hud !== this.viewedHudElement) {
9960
+ this.viewedHudElement = hud;
9961
+ this.viewedHudParts.clear();
9962
+ }
9963
+ const once = (key, send) => {
9964
+ if (this.viewedHudParts.has(key)) return;
9965
+ this.viewedHudParts.add(key);
9966
+ this.queueHudTelemetry(send);
9967
+ };
9968
+ const trigger = this.launcherHudTrigger;
9969
+ once("hud", () => require_telemetry.trackHudViewed({ trigger }));
9970
+ if (hud.querySelector("[data-cpk-hud-news]") && this.announcementId) {
9971
+ const banner_id = this.announcementId;
9972
+ once(`notification:${banner_id}`, () => require_telemetry.trackHudNotificationViewed({
9973
+ banner_id,
9974
+ notification_id: banner_id,
9975
+ trigger
9976
+ }));
9977
+ }
9978
+ for (const feature of ["threads", "learning"]) if (hud.querySelector(`[data-cpk-hud-toggle="${feature}"]`)) once(`toggle:${feature}`, () => require_telemetry.trackHudFeatureToggleViewed({
9979
+ feature,
9980
+ trigger
9981
+ }));
9982
+ if (hud.querySelector("[data-cpk-dismiss-inspector=\"day\"]")) once("hide", () => require_telemetry.trackHudHideViewed({ trigger }));
9983
+ }
9958
9984
  getUnreadAnnouncementTitle() {
9959
9985
  if (!this.newsSignalArmed || !this.announcementLoaded) return null;
9960
- const title = this.announcementPreviewText?.trim() || "New in CopilotKit";
9986
+ const title = this.notificationFeed?.notifications.find((notice) => notice.id === this.notificationState.activeId)?.title.trim() || "New in CopilotKit";
9961
9987
  const titleCharacters = Array.from(title);
9962
9988
  return titleCharacters.length > HUD_ANNOUNCEMENT_TITLE_LIMIT ? `${titleCharacters.slice(0, HUD_ANNOUNCEMENT_TITLE_LIMIT).join("").trimEnd()}...` : title;
9963
9989
  }
@@ -9978,7 +10004,7 @@ var WebInspectorElement = class WebInspectorElement extends lit.LitElement {
9978
10004
  class="cpk-launcher-hud__action"
9979
10005
  data-cpk-hud-action
9980
10006
  aria-label=${`Open ${args.label} in Inspector`}
9981
- @click=${(event) => this.handleHudActionClick(event, args.id)}
10007
+ @click=${(event) => this.handleHudActionClick(event, args.id, "action")}
9982
10008
  @pointerdown=${(event) => event.stopPropagation()}
9983
10009
  >
9984
10010
  <span
@@ -10003,7 +10029,7 @@ var WebInspectorElement = class WebInspectorElement extends lit.LitElement {
10003
10029
  data-cpk-hud-learn-more=${args.id}
10004
10030
  aria-label=${`Learn more about ${args.label}`}
10005
10031
  aria-describedby=${detailId}
10006
- @click=${(event) => this.handleHudActionClick(event, args.id)}
10032
+ @click=${(event) => this.handleHudActionClick(event, args.id, "learn_more")}
10007
10033
  @pointerdown=${(event) => event.stopPropagation()}
10008
10034
  >
10009
10035
  ${this.renderIcon("CircleHelp")}
@@ -10015,7 +10041,7 @@ var WebInspectorElement = class WebInspectorElement extends lit.LitElement {
10015
10041
  data-enabled=${args.connected ? "true" : "false"}
10016
10042
  aria-label=${args.connected ? `${args.label} is enabled` : `Open ${args.label} in Inspector`}
10017
10043
  ?disabled=${args.connected}
10018
- @click=${(event) => this.handleHudActionClick(event, args.id)}
10044
+ @click=${(event) => this.handleHudActionClick(event, args.id, "toggle")}
10019
10045
  @pointerdown=${(event) => event.stopPropagation()}
10020
10046
  >
10021
10047
  <span
@@ -10332,6 +10358,7 @@ var WebInspectorElement = class WebInspectorElement extends lit.LitElement {
10332
10358
  }
10333
10359
  getHomeModel() {
10334
10360
  const lastRuntimeEvent = this.flattenedEvents[0];
10361
+ const activeNotice = this.notificationFeed?.notifications.find((notice) => notice.id === this.notificationState.activeId);
10335
10362
  return require_home_briefing.buildHomeModel({
10336
10363
  intelligenceConnected: Boolean(this._core?.intelligence),
10337
10364
  threadsAvailable: this.areThreadEndpointsAvailable(),
@@ -10350,25 +10377,23 @@ var WebInspectorElement = class WebInspectorElement extends lit.LitElement {
10350
10377
  suggestionsOn: this._core?.suggestions === true,
10351
10378
  audioOn: this._core?.audioFileTranscriptionEnabled === true,
10352
10379
  websocketUrl: this._core?.intelligence?.wsUrl,
10353
- announcementPreviewText: this.announcementPreviewText ?? void 0,
10354
- announcementMarkdown: this.announcementMarkdown ?? void 0,
10355
- announcementHtml: this.announcementHtml ?? void 0,
10380
+ announcementPreviewText: activeNotice?.title,
10381
+ announcementMarkdown: activeNotice?.body,
10382
+ announcementHtml: activeNotice ? this.notificationDocuments.get(activeNotice.id) : void 0,
10356
10383
  intelligenceSignupUrl: this.getIntelligenceSignupUrl()
10357
10384
  });
10358
10385
  }
10359
10386
  renderHomeView() {
10360
10387
  const model = this.getHomeModel();
10361
- const connected = model.hero.connection === "connected";
10362
10388
  return lit.html`
10363
10389
  <div
10364
10390
  class="inspector-home"
10365
10391
  data-inspector-home
10366
- data-inspector-home-state=${connected ? "connected" : "disconnected"}
10392
+ data-inspector-home-state=${model.hero.connection === "connected" ? "connected" : "disconnected"}
10367
10393
  >
10368
10394
  ${this.renderHomeWhatsNewPreview(model.news)}
10369
- <header class="inspector-home-heading"><div><h1>${connected ? model.project?.projectName ?? "Your agent workspace" : "Welcome to Intelligence"}</h1><p>${connected ? "Inspect conversations and see what your agent is learning." : "Connect your agent. Intelligence learns from experience."}</p></div></header>
10370
- ${connected ? this.renderHomeSystemHealth(model) : this.renderHomeIntelligenceHud(model)}
10371
- ${connected ? this.renderHomeIntelligenceHud(model) : this.renderHomeSystemHealth(model)}
10395
+ ${this.renderHomeSystemHealth(model)}
10396
+ ${this.renderHomeIntelligenceHud(model)}
10372
10397
  ${this.renderHomeFeatures(model)}
10373
10398
  </div>
10374
10399
  `;
@@ -10390,7 +10415,7 @@ var WebInspectorElement = class WebInspectorElement extends lit.LitElement {
10390
10415
  data-inspector-whats-new-preview
10391
10416
  aria-label="Open What's New"
10392
10417
  style=${INTERACTIVE_FOCUS_BASE_STYLE}
10393
- @click=${() => this.handleMenuSelect(WHATS_NEW_MENU_KEY)}
10418
+ @click=${() => this.notificationState.activeId ? this.readNotification(this.notificationState.activeId) : this.handleMenuSelect(WHATS_NEW_MENU_KEY)}
10394
10419
  >
10395
10420
  <span class="inspector-whats-new-preview-copy">
10396
10421
  <span class="inspector-whats-new-preview-title">
@@ -10407,47 +10432,89 @@ var WebInspectorElement = class WebInspectorElement extends lit.LitElement {
10407
10432
  `;
10408
10433
  }
10409
10434
  renderWhatsNewView() {
10410
- const state = this.getWhatsNewState();
10411
- const news = this.getHomeModel().news;
10412
- const updatedAt = this.announcementTimestamp ? new Date(this.announcementTimestamp) : null;
10413
- const updatedLabel = updatedAt && !Number.isNaN(updatedAt.getTime()) ? new Intl.DateTimeFormat(void 0, {
10414
- month: "long",
10435
+ const notices = this.notificationFeed?.notifications.filter((n) => this.notificationState.eligibleIds.includes(n.id)).sort(require_notifications.compareNotifications) ?? [];
10436
+ const selected = notices.find((n) => n.id === this.selectedNotificationId);
10437
+ const formatDate = (date) => new Date(date).toLocaleDateString(void 0, {
10438
+ month: "short",
10415
10439
  day: "numeric",
10416
10440
  year: "numeric"
10417
- }).format(updatedAt) : null;
10441
+ });
10418
10442
  return lit.html`
10419
10443
  <div
10420
10444
  class="inspector-home inspector-whats-new"
10421
10445
  data-inspector-whats-new
10422
10446
  data-cpk-whats-new
10423
- data-cpk-whats-new-state=${state}
10447
+ data-cpk-whats-new-state=${this.getWhatsNewState()}
10424
10448
  >
10425
- <header class="inspector-whats-new-header">
10426
- <h1 class="inspector-home-title">What's New</h1>
10427
- ${updatedLabel ? lit.html`
10428
- <p class="inspector-whats-new-updated">
10429
- Updated
10430
- <time datetime=${updatedAt?.toISOString()}
10431
- >${updatedLabel}</time
10432
- >
10433
- </p>
10434
- ` : lit.nothing}
10435
- </header>
10436
10449
  <section class="inspector-home-news" aria-label="CopilotKit updates">
10437
- ${news.empty || !news.documentHtml ? lit.html`
10438
- <article class="inspector-whats-new-empty">
10439
- <h2 class="inspector-home-card-title">${news.title}</h2>
10440
- <p class="inspector-home-card-copy">${news.previewText}</p>
10441
- </article>
10442
- ` : lit.html`
10450
+ ${selected ? lit.html`
10451
+ <button
10452
+ type="button"
10453
+ class="inspector-whats-new-back"
10454
+ @click=${() => {
10455
+ this.selectedNotificationId = null;
10456
+ this.requestUpdate();
10457
+ }}
10458
+ >
10459
+ <span aria-hidden="true"
10460
+ >${this.renderIcon("ArrowLeft")}</span
10461
+ >
10462
+ All updates
10463
+ </button>
10443
10464
  <article class="inspector-whats-new-document">
10465
+ <header class="inspector-whats-new-document-header">
10466
+ <h1>${selected.title}</h1>
10467
+ <time datetime=${selected.publishedAt}>
10468
+ ${formatDate(selected.publishedAt)}
10469
+ </time>
10470
+ </header>
10444
10471
  <div
10445
10472
  class="announcement-content"
10446
10473
  @click=${this.handleAnnouncementContentClick}
10447
10474
  >
10448
- ${(0, lit_directives_unsafe_html_js.unsafeHTML)(news.documentHtml)}
10475
+ ${(0, lit_directives_unsafe_html_js.unsafeHTML)(this.notificationDocuments.get(selected.id) ?? "")}
10449
10476
  </div>
10450
10477
  </article>
10478
+ ` : lit.html`
10479
+ <header class="inspector-whats-new-header">
10480
+ <h1 class="inspector-home-title">What's New</h1>
10481
+ </header>
10482
+ ${notices.length ? lit.html`
10483
+ <ul class="inspector-whats-new-list">
10484
+ ${notices.map((notice) => {
10485
+ const read = this.notificationState.readIds.includes(notice.id);
10486
+ return lit.html`
10487
+ <li>
10488
+ <button
10489
+ type="button"
10490
+ class="cpk-notification-row"
10491
+ data-notification-id=${notice.id}
10492
+ @click=${() => this.readNotification(notice.id)}
10493
+ >
10494
+ <span class="cpk-notification-copy">
10495
+ <strong>${notice.title}</strong>
10496
+ <span class="cpk-notification-meta">
10497
+ <time datetime=${notice.publishedAt}
10498
+ >${formatDate(notice.publishedAt)}</time
10499
+ >
10500
+ ${read ? lit.nothing : lit.html`
10501
+ <span class="cpk-notification-unread">Unread</span>
10502
+ `}
10503
+ </span>
10504
+ </span>
10505
+ <span
10506
+ class="cpk-notification-chevron"
10507
+ aria-hidden="true"
10508
+ >${this.renderIcon("ChevronRight")}</span
10509
+ >
10510
+ </button>
10511
+ </li>
10512
+ `;
10513
+ })}
10514
+ </ul>
10515
+ ` : lit.html`<p class="inspector-whats-new-empty" role="status">
10516
+ ${this.announcementLoaded || !this.notificationContext.development ? "You're all caught up." : "Loading updates…"}
10517
+ </p>`}
10451
10518
  `}
10452
10519
  </section>
10453
10520
  </div>
@@ -12930,15 +12997,15 @@ var WebInspectorElement = class WebInspectorElement extends lit.LitElement {
12930
12997
  }
12931
12998
  trackWhatsNewClickedOnce(opts) {
12932
12999
  if (this.runtimeStatus !== _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Connected || this.core?.telemetryDisabled) return;
12933
- const id = this.announcementTimestamp;
13000
+ const id = this.announcementId;
12934
13001
  if (!id) return;
12935
13002
  const key = `${id}:${opts.cta}`;
12936
13003
  if (this.clickedBannerIds.has(key)) return;
12937
13004
  this.clickedBannerIds.add(key);
12938
13005
  require_telemetry.trackWhatsNewClicked({
12939
13006
  banner_id: id,
12940
- cta: opts.cta,
12941
- cta_label: this.announcementCtaLabel ?? void 0
13007
+ notification_id: id,
13008
+ cta: opts.cta
12942
13009
  });
12943
13010
  }
12944
13011
  trackThreadsViewStateOnce(state) {
@@ -15450,11 +15517,9 @@ var WebInspectorElement = class WebInspectorElement extends lit.LitElement {
15450
15517
  else if (!wasArmed) this.requestUpdate();
15451
15518
  }
15452
15519
  clearNewsSignal() {
15453
- if (!this.newsSignalArmed) return;
15454
- this.newsSignalArmed = false;
15455
- if (this.announcementTimestamp) require_persistence.saveAnnouncementReadTimestamp(this.announcementTimestamp);
15456
- this.retireSignal(NEWS_SIGNAL_ID);
15457
- this.requestUpdate();
15520
+ if (!this.notificationState.activeId) return;
15521
+ this.notificationState = require_notifications.acknowledgeNotification(this.notificationState, this.notificationState.activeId);
15522
+ this.refreshNotifications();
15458
15523
  }
15459
15524
  /**
15460
15525
  * Requests one beat for a signal, running it now or deferring it.
@@ -15487,7 +15552,7 @@ var WebInspectorElement = class WebInspectorElement extends lit.LitElement {
15487
15552
  this.pendingPulseSignal = null;
15488
15553
  this.pulsingSignal = key;
15489
15554
  if (isWiringErrorKey(key)) this.errorBeatSpent = true;
15490
- else if (this.announcementTimestamp && key === NEWS_SIGNAL_ID) require_persistence.saveAnnouncementPulsedTimestamp(this.announcementTimestamp);
15555
+ else if (this.notificationState.activeId && key === NEWS_SIGNAL_ID) require_persistence.saveNotificationPulsedId(this.notificationState.activeId);
15491
15556
  this.beginGestureTail(key);
15492
15557
  this.requestUpdate();
15493
15558
  if (typeof window === "undefined") return;
@@ -15787,14 +15852,14 @@ var WebInspectorElement = class WebInspectorElement extends lit.LitElement {
15787
15852
  }
15788
15853
  maybeTrackNewsSignalViewed() {
15789
15854
  if (!this.newsSignalArmed || this.pulsingSignal !== NEWS_SIGNAL_ID || this.isOpen || typeof document === "undefined" || document.visibilityState !== "visible") return;
15790
- const id = this.announcementTimestamp;
15855
+ const id = (this.notificationFeed?.notifications.find((n) => n.id === this.notificationState.activeId))?.id;
15791
15856
  if (!id || this.viewedNewsSignalIds.has(id)) return;
15792
15857
  this.viewedNewsSignalIds.add(id);
15793
15858
  this.pendingNewsSignalViewed = {
15794
15859
  banner_id: id,
15860
+ notification_id: id,
15795
15861
  surface: "launcher",
15796
- presentation: typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches ? "reduced_motion" : "animated",
15797
- cta_label: this.announcementCtaLabel ?? void 0
15862
+ presentation: typeof window !== "undefined" && window.matchMedia?.("(prefers-reduced-motion: reduce)").matches ? "reduced_motion" : "animated"
15798
15863
  };
15799
15864
  this.flushPendingWhatsNewTelemetry();
15800
15865
  }
@@ -15812,7 +15877,7 @@ var WebInspectorElement = class WebInspectorElement extends lit.LitElement {
15812
15877
  getVisibleBannerSurface() {
15813
15878
  if (!this.isOpen || this.settingsOpen) return null;
15814
15879
  if (this.selectedMenu !== WHATS_NEW_MENU_KEY) return null;
15815
- return this.announcementHtml ? "whats_new" : null;
15880
+ return this.selectedNotificationId && this.announcementHtml ? "whats_new" : null;
15816
15881
  }
15817
15882
  /**
15818
15883
  * The single condition that retires the news signal: What's new has
@@ -15831,14 +15896,13 @@ var WebInspectorElement = class WebInspectorElement extends lit.LitElement {
15831
15896
  maybeCompleteWhatsNewView() {
15832
15897
  if (!this.getVisibleBannerSurface()) return;
15833
15898
  this.maybeTrackWhatsNewViewed();
15834
- this.clearNewsSignal();
15835
15899
  }
15836
15900
  /**
15837
15901
  * Records a `whats_new_viewed` impression for whichever surface is
15838
15902
  * currently visible, once per announcement per surface.
15839
15903
  */
15840
15904
  maybeTrackWhatsNewViewed() {
15841
- const id = this.announcementTimestamp;
15905
+ const id = this.announcementId;
15842
15906
  if (!id) return;
15843
15907
  const surface = this.getVisibleBannerSurface();
15844
15908
  if (!surface) return;
@@ -15848,12 +15912,13 @@ var WebInspectorElement = class WebInspectorElement extends lit.LitElement {
15848
15912
  this.viewedBannerSurfaces.add(key);
15849
15913
  this.pendingBannerViewed.push({
15850
15914
  banner_id: id,
15851
- surface,
15852
- cta_label: this.announcementCtaLabel ?? void 0
15915
+ notification_id: id,
15916
+ surface
15853
15917
  });
15854
15918
  this.flushPendingWhatsNewTelemetry();
15855
15919
  }
15856
15920
  flushPendingWhatsNewTelemetry() {
15921
+ this.flushPendingHudTelemetry();
15857
15922
  if (this.pendingBannerViewed.length === 0 && !this.pendingNewsSignalViewed) return;
15858
15923
  if (this.core?.telemetryDisabled) {
15859
15924
  this.pendingBannerViewed = [];
@@ -15871,32 +15936,58 @@ var WebInspectorElement = class WebInspectorElement extends lit.LitElement {
15871
15936
  }
15872
15937
  }
15873
15938
  ensureAnnouncementLoading() {
15874
- if (this.announcementPromise || typeof window === "undefined" || typeof fetch === "undefined") return;
15939
+ if (this.isInspectorDismissed || !this.notificationContext.development || !this.isConnected || this.announcementPromise || typeof window === "undefined" || typeof fetch === "undefined") return;
15875
15940
  this.announcementPromise = this.fetchAnnouncement();
15876
15941
  }
15877
15942
  async fetchAnnouncement() {
15878
15943
  try {
15879
- const response = await fetch(ANNOUNCEMENT_URL, { cache: "no-cache" });
15880
- if (!response.ok) throw new Error(`Failed to load announcement (${response.status})`);
15881
- const data = await response.json();
15882
- const timestamp = typeof data?.timestamp === "string" ? data.timestamp : null;
15883
- const previewText = typeof data?.previewText === "string" ? data.previewText : null;
15884
- const markdown = typeof data?.announcement === "string" ? data.announcement : null;
15885
- const ctaLabel = typeof data?.cta_label === "string" ? data.cta_label : null;
15886
- if (!timestamp || !markdown) throw new Error("Malformed announcement payload");
15887
- this.announcementTimestamp = timestamp;
15888
- this.announcementPreviewText = previewText ?? "";
15889
- this.announcementMarkdown = markdown;
15890
- this.announcementCtaLabel = ctaLabel;
15891
- this.announcementHtml = await this.convertMarkdownToHtml(markdown);
15892
- this.announcementLoaded = true;
15893
- if (this.announcementHtml && require_persistence.loadAnnouncementReadTimestamp() !== timestamp) this.armNewsSignal({ pulse: require_persistence.loadAnnouncementPulsedTimestamp() !== timestamp });
15894
- this.requestUpdate();
15895
- } catch (error) {
15896
- console.warn("[CopilotKit Inspector] Failed to load announcement", error);
15897
- this.announcementLoaded = true;
15898
- this.requestUpdate();
15944
+ const feed = await require_notification_loader.loadNotificationFeed(this.notificationContext);
15945
+ if (feed) {
15946
+ const documents = await Promise.all(feed.notifications.map(async (notice) => [notice.id, await this.convertMarkdownToHtml(notice.body) ?? ""]));
15947
+ this.notificationDocuments = new Map(documents);
15948
+ this.notificationFeed = feed;
15949
+ }
15950
+ } catch {}
15951
+ this.announcementLoaded = true;
15952
+ this.refreshNotifications();
15953
+ this.requestUpdate();
15954
+ }
15955
+ /** Resolve only confirmed runtime metadata; missing fields stay unknown. */
15956
+ getNotificationContext() {
15957
+ const base = this.notificationContext;
15958
+ const core = this.core;
15959
+ if (!core || this.runtimeStatus !== _copilotkit_core.CopilotKitCoreRuntimeConnectionStatus.Connected) return base;
15960
+ const mode = core.runtimeMode;
15961
+ const entitlement = core.runtimeEntitlements?.status === "ready" ? core.runtimeEntitlements.entitlement : void 0;
15962
+ return {
15963
+ ...base,
15964
+ intelligence: mode === "intelligence" ? "enabled" : mode === "sse" ? "disabled" : void 0,
15965
+ plan: this.inspectorMetadataProjection.plan?.code ?? entitlement?.planCode,
15966
+ deployment: entitlement?.source === "managedOrgSubscription" ? "managed" : entitlement ? "self-hosted" : void 0
15967
+ };
15968
+ }
15969
+ refreshNotifications() {
15970
+ if (!this.notificationFeed) return;
15971
+ this.notificationState = require_persistence.migrateAnnouncementReadState(this.notificationState, this.notificationFeed);
15972
+ const previousActiveId = this.notificationState.activeId;
15973
+ this.notificationState = require_notifications.reconcileNotifications(this.notificationState, this.notificationFeed, this.getNotificationContext());
15974
+ require_persistence.saveNotificationState(this.notificationState);
15975
+ if (!this.notificationState.eligibleIds.includes(this.selectedNotificationId ?? "")) this.selectedNotificationId = null;
15976
+ const notice = this.notificationFeed.notifications.find((n) => this.notificationState.eligibleIds.includes(n.id) && n.id === (this.selectedNotificationId ?? this.notificationState.activeId)) ?? this.notificationFeed.notifications.filter((n) => this.notificationState.eligibleIds.includes(n.id)).sort(require_notifications.compareNotifications)[0];
15977
+ this.announcementId = notice?.id ?? null;
15978
+ this.announcementHtml = notice ? this.notificationDocuments.get(notice.id) ?? null : null;
15979
+ if (this.notificationState.activeId && this.notificationState.eligibleIds.includes(this.notificationState.activeId)) this.armNewsSignal({ pulse: (previousActiveId !== this.notificationState.activeId || !this.newsSignalArmed) && !require_persistence.hasNotificationPulsed(this.notificationState.activeId, this.notificationFeed.notifications.find((n) => n.id === this.notificationState.activeId).publishedAt) });
15980
+ else {
15981
+ this.newsSignalArmed = false;
15982
+ this.retireSignal(NEWS_SIGNAL_ID);
15899
15983
  }
15984
+ this.requestUpdate();
15985
+ }
15986
+ readNotification(id) {
15987
+ this.selectedNotificationId = id;
15988
+ this.notificationState = require_notifications.acknowledgeNotification(this.notificationState, id);
15989
+ this.refreshNotifications();
15990
+ this.handleMenuSelect(WHATS_NEW_MENU_KEY);
15900
15991
  }
15901
15992
  async convertMarkdownToHtml(markdown) {
15902
15993
  const renderer = new marked.marked.Renderer();
@@ -15971,8 +16062,9 @@ function defineWebInspector(registry = globalThis.customElements) {
15971
16062
  * auto-attachment first prevents `connectedCallback` from briefly selecting a
15972
16063
  * different global core.
15973
16064
  */
15974
- function configureWebInspectorElement(inspector, core) {
16065
+ function configureWebInspectorElement(inspector, core, notificationContext = { development: false }) {
15975
16066
  inspector.autoAttachCore = false;
16067
+ inspector.notificationContext = notificationContext;
15976
16068
  inspector.core = core;
15977
16069
  return inspector;
15978
16070
  }