@copilotkit/web-inspector 1.70.1 → 1.70.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.mjs CHANGED
@@ -1,14 +1,17 @@
1
1
  import generated_default from "./styles/generated.mjs";
2
2
  import inspector_logo_default from "./assets/inspector-logo.mjs";
3
3
  import inspector_logo_kite_default from "./assets/inspector-logo-kite.mjs";
4
+ import { deriveLearningViewState } from "./components/learning-view.mjs";
4
5
  import { applyAnchorPosition, centerContext, clampSize, constrainToViewport, keepPositionWithinViewport, updateAnchorFromPosition, updateSizeFromElement } from "./lib/context-helpers.mjs";
5
6
  import { INSPECTOR_DISMISSAL_MAX_DURATION_MS, clearLegacyAnnouncementReadState, isValidAnchor, isValidDockMode, isValidPosition, isValidSize, loadAnnouncementPulsedTimestamp, loadAnnouncementReadTimestamp, loadInspectorDismissedUntil, loadInspectorState, saveAnnouncementPulsedTimestamp, saveAnnouncementReadTimestamp, saveInspectorDismissedUntil, saveInspectorState } from "./lib/persistence.mjs";
7
+ import { clearLearningSetupMarker, learningSetupMarkerMatches, readLearningSetupMarker, subscribeToLearningSetupMarker, writeLearningSetupMarker } from "./lib/learning-setup.mjs";
8
+ import { InspectorLearningUnsupportedError, fetchInspectorLearning } from "./lib/inspector-learning.mjs";
6
9
  import { buildPopOutFeatures, ensureBrandFont, openPopOutWindow } from "./lib/pop-out.mjs";
7
10
  import { projectInspectorMetadata } from "./lib/inspector-metadata.mjs";
8
11
  import { buildHomeModel, homeFeatureImplementationPrompt, runtimeConnectionNeedsAttention } from "./lib/home-briefing.mjs";
9
12
  import { INSPECTOR_GROUPS, INSPECTOR_NAV_SECTIONS, getGroupForMenu, isInspectorMenuKey, shouldUseIconRail } from "./lib/inspector-nav.mjs";
10
13
  import { selectVisibleRealThreadId } from "./lib/thread-selection.mjs";
11
- import { TELEMETRY_DOCS_URL, ensureTelemetryDistinctId, getRuntimeUrlType, getTelemetryDistinctIdForUrl, maybeShowDisclosure, trackErrorSignalViewed, trackHomeCtaClicked, trackHomeFeaturePromptClicked, trackHomePromptCopied, trackHomeStoryBeatSelected, trackHomeViewed, trackInspectorOpened, trackMemoriesTabClicked, trackMetadataActionClicked, trackMetadataModuleViewed, trackTalkToEngineerClicked, trackThreadsEmptyEnabledViewed, trackThreadsEnabledViewed, trackThreadsExampleSelected, trackThreadsExampleTourCompleted, trackThreadsExampleTourDismissed, trackThreadsExampleTourReopened, trackThreadsExampleTourStarted, trackThreadsExampleTourStepViewed, trackThreadsExampleViewed, trackThreadsIntelligenceSignupClicked, trackThreadsLockedViewed, trackThreadsTabClicked, trackThreadsTalkToEngineerClicked, trackThreadsTryFromHereClicked, trackWhatsNewClicked, trackWhatsNewSignalViewed, trackWhatsNewViewed } from "./lib/telemetry.mjs";
14
+ import { TELEMETRY_DOCS_URL, ensureTelemetryDistinctId, getRuntimeUrlType, getTelemetryDistinctIdForUrl, learningCountBucket, learningDurationBucket, maybeShowDisclosure, trackErrorSignalViewed, trackHomeCtaClicked, trackHomeFeaturePromptClicked, trackHomePromptCopied, trackHomeStoryBeatSelected, trackHomeViewed, trackInspectorOpened, trackLearningEvidenceOpened, trackLearningPageChanged, trackLearningPaneViewed, trackLearningSetupPromptClicked, trackLearningSkillToggled, trackLearningSnapshotLoaded, trackLearningWebAppOpened, trackMemoriesTabClicked, trackMetadataActionClicked, trackMetadataModuleViewed, trackTalkToEngineerClicked, trackThreadsEmptyEnabledViewed, trackThreadsEnabledViewed, trackThreadsExampleSelected, trackThreadsExampleTourCompleted, trackThreadsExampleTourDismissed, trackThreadsExampleTourReopened, trackThreadsExampleTourStarted, trackThreadsExampleTourStepViewed, trackThreadsExampleViewed, trackThreadsIntelligenceSignupClicked, trackThreadsLockedViewed, trackThreadsTabClicked, trackThreadsTalkToEngineerClicked, trackThreadsTryFromHereClicked, trackWhatsNewClicked, trackWhatsNewSignalViewed, trackWhatsNewViewed } from "./lib/telemetry.mjs";
12
15
  import { createOnboardingPrompt, createOnboardingRunId } from "./lib/onboarding-prompt.mjs";
13
16
  import { LitElement, css, html, nothing, render, unsafeCSS } from "lit";
14
17
  import { marked } from "marked";
@@ -388,6 +391,52 @@ const INTELLIGENCE_STORY_CHAIN = [
388
391
  ];
389
392
  const THREADS_EXAMPLE_OVERVIEW_VIDEO_URL = "https://cdn.copilotkit.ai/corp-site/videos/copilotkit-generative-ui-agentic-frontend-demo.webm";
390
393
  const THREADS_EXAMPLE_OVERVIEW_VIDEO_FALLBACK = "The demo video is unavailable. Use the example threads to explore Messages, AG-UI Events, and State.";
394
+ const THREADS_LOCKED_VIDEO_URL = "https://www.loom.com/embed/79817778d29e490c97225127d2f17b3a?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true&hide_speed=true";
395
+ const LEARNING_LOCKED_VIDEO_URL = "https://www.loom.com/embed/2978fbfe42324e509057ac5fd46b7a70?hide_owner=true&hide_share=true&hide_title=true&hideEmbedTopBar=true&hide_speed=true";
396
+ const THREADS_LOCKED_FEATURE_OUTLINE = [
397
+ {
398
+ icon: "MessagesSquare",
399
+ title: "The whole conversation comes back",
400
+ description: "Rich Threads restores the complete interaction, not just a transcript. Messages, tool calls, shared state, generated interfaces, and supported files return together when a user reopens the thread."
401
+ },
402
+ {
403
+ icon: "LayoutGrid",
404
+ title: "Generated UI stays in the thread",
405
+ description: "Cards, charts, A2UI surfaces, MCP Apps, and tool renderers remain part of the conversation. The demo above shows a generated spending chart returning after a reload."
406
+ },
407
+ {
408
+ icon: "RefreshCw",
409
+ title: "Return without starting over",
410
+ description: "Users can move across sessions and devices while thread lists stay synchronized across open tabs. Rich Threads replays missed events and reconnects to work already in progress."
411
+ },
412
+ {
413
+ icon: "Server",
414
+ title: "Infrastructure you do not have to rebuild",
415
+ description: "CopilotKit handles durable event storage, replay, synchronization, lifecycle APIs, and thread locks on one portable AG-UI history model. Use CopilotKit Cloud or deploy Intelligence in your own Kubernetes environment."
416
+ }
417
+ ];
418
+ const LEARNING_LOCKED_FEATURE_OUTLINE = [
419
+ {
420
+ icon: "History",
421
+ title: "Memory across sessions",
422
+ description: "Keep useful facts, preferences, and decisions after the thread closes. Learning gives future conversations the context they need without asking users to repeat themselves."
423
+ },
424
+ {
425
+ icon: "Search",
426
+ title: "Recall by meaning",
427
+ description: "Surface relevant memories by what they mean, not by an exact phrase. Your agent can bring the right context into a new interaction even when the user asks in a completely different way."
428
+ },
429
+ {
430
+ icon: "Layers",
431
+ title: "Built-in structure",
432
+ description: "Turn raw interactions into organized topical, episodic, and operational knowledge. Learning separates enduring facts from individual experiences and useful instructions automatically."
433
+ },
434
+ {
435
+ icon: "Eye",
436
+ title: "Full visibility",
437
+ description: "Inspect exactly what your agent learned and trace each memory back to the threads that shaped it. Review the stored context instead of treating memory like a black box."
438
+ }
439
+ ];
391
440
  const THREADS_EXAMPLE_TOUR_STORAGE_KEY = "cpk:inspector:threads-example-tour:v1";
392
441
  const THREADS_EXAMPLE_AGENT_ID = "threads-feature";
393
442
  /** Keep one row per thread id when flattening per-agent stores. */
@@ -4853,6 +4902,21 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
4853
4902
  this._memoryUnsub = null;
4854
4903
  this._memorySubscribed = false;
4855
4904
  this._memoryStoreUnsupported = false;
4905
+ this.learningSnapshot = null;
4906
+ this.learningSnapshotScope = null;
4907
+ this.learningProjectIdentity = null;
4908
+ this.learningLoading = false;
4909
+ this.learningRefreshing = false;
4910
+ this.learningError = null;
4911
+ this.learningSupported = false;
4912
+ this.learningRequestGeneration = 0;
4913
+ this.learningAbortController = null;
4914
+ this.learningPollTimer = null;
4915
+ this.learningPollFailureCount = 0;
4916
+ this.learningSetupMarker = null;
4917
+ this.learningSetupUnsubscribe = null;
4918
+ this.learningPromptCopyState = "idle";
4919
+ this.learningViewedState = null;
4856
4920
  this._recallResults = null;
4857
4921
  this._recallLoading = false;
4858
4922
  this._recallError = null;
@@ -5089,10 +5153,158 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
5089
5153
  this.resizeEdge = "se";
5090
5154
  this.isResizing = false;
5091
5155
  this.customTabIcons = { threads: `<svg class="h-3.5 w-3.5" width="15" height="15" viewBox="0 0 15 15" fill="none" xmlns="http://www.w3.org/2000/svg"><path d="M9.04167 15C8.29167 15 7.65972 14.7431 7.14583 14.2292C6.63194 13.7153 6.375 13.0972 6.375 12.375C6.375 11.3194 6.80208 10.3646 7.65625 9.51042C8.51042 8.65625 9.57639 8.125 10.8542 7.91667C10.8125 7.41667 10.6875 7.03819 10.4792 6.78125C10.2708 6.52431 9.98611 6.39583 9.625 6.39583C9.20833 6.39583 8.75694 6.56944 8.27083 6.91667C7.78472 7.26389 7.20833 7.83333 6.54167 8.625C5.45833 9.91667 4.66319 10.7569 4.15625 11.1458C3.64931 11.5347 3.10417 11.7292 2.52083 11.7292C1.8125 11.7292 1.21528 11.4653 0.729167 10.9375C0.243056 10.4097 0 9.77083 0 9.02083C0 8.27083 0.163194 7.50347 0.489583 6.71875C0.815972 5.93403 1.36806 4.99306 2.14583 3.89583C2.40972 3.53472 2.60417 3.22917 2.72917 2.97917C2.85417 2.72917 2.91667 2.52778 2.91667 2.375C2.91667 2.27778 2.89931 2.20486 2.86458 2.15625C2.82986 2.10764 2.77778 2.08333 2.70833 2.08333C2.56944 2.08333 2.39583 2.17014 2.1875 2.34375C1.97917 2.51736 1.73611 2.78472 1.45833 3.14583L0 1.66667C0.444444 1.125 0.895833 0.711806 1.35417 0.427083C1.8125 0.142361 2.26389 0 2.70833 0C3.34722 0 3.88889 0.222222 4.33333 0.666667C4.77778 1.11111 5 1.66667 5 2.33333C5 2.73611 4.89583 3.18056 4.6875 3.66667C4.47917 4.15278 4.13194 4.73611 3.64583 5.41667C3.11806 6.16667 2.72569 6.82639 2.46875 7.39583C2.21181 7.96528 2.08333 8.46528 2.08333 8.89583C2.08333 9.13194 2.12153 9.31597 2.19792 9.44792C2.27431 9.57986 2.38194 9.64583 2.52083 9.64583C2.65972 9.64583 2.78125 9.60764 2.88542 9.53125C2.98958 9.45486 3.18056 9.27083 3.45833 8.97917C3.63889 8.78472 3.85417 8.54514 4.10417 8.26042C4.35417 7.97569 4.65972 7.625 5.02083 7.20833C5.89583 6.16667 6.6875 5.42361 7.39583 4.97917C8.10417 4.53472 8.84722 4.3125 9.625 4.3125C10.5556 4.3125 11.3194 4.625 11.9167 5.25C12.5139 5.875 12.8542 6.72917 12.9375 7.8125H15V9.89583H12.9375C12.8264 11.4514 12.4201 12.691 11.7188 13.6146C11.0174 14.5382 10.125 15 9.04167 15ZM9.08333 12.9167C9.52778 12.9167 9.90278 12.6632 10.2083 12.1562C10.5139 11.6493 10.7222 10.9444 10.8333 10.0417C10.1944 10.1944 9.63889 10.4965 9.16667 10.9479C8.69444 11.3993 8.45833 11.8472 8.45833 12.2917C8.45833 12.4861 8.51389 12.6389 8.625 12.75C8.73611 12.8611 8.88889 12.9167 9.08333 12.9167Z" fill="currentColor"/></svg>` };
5156
+ this.refreshLearningSnapshot = async (options = {}) => {
5157
+ const core = this.core;
5158
+ const runtimeUrl = core?.runtimeUrl;
5159
+ this.learningSupported = Boolean(core?.inspectorLearning);
5160
+ if (!core || !runtimeUrl || !this.learningSupported) {
5161
+ this.clearLearningSnapshot();
5162
+ this.requestUpdate();
5163
+ this.trackLearningViewState();
5164
+ return;
5165
+ }
5166
+ this.cancelLearningPoll();
5167
+ const startedAt = performance.now();
5168
+ let loadOutcome = "failure";
5169
+ let loadedSkills = 0;
5170
+ let loadedInsights = 0;
5171
+ let loadedPendingThreads = 0;
5172
+ let resetSkillsPage = false;
5173
+ let resetInsightsPage = false;
5174
+ const previousSnapshot = this.learningSnapshot;
5175
+ const agentId = this.getLearningAgentId();
5176
+ const requestContext = `${runtimeUrl.replace(/\/+$/u, "")}|${agentId ?? ""}`;
5177
+ if (this.learningSnapshotScope && !this.learningSnapshotScope.startsWith(`${requestContext}|`)) this.clearLearningSnapshot();
5178
+ const generation = ++this.learningRequestGeneration;
5179
+ this.learningAbortController?.abort();
5180
+ const controller = new AbortController();
5181
+ this.learningAbortController = controller;
5182
+ const preserve = options.preserve === true && this.learningSnapshot !== null;
5183
+ this.learningLoading = !preserve;
5184
+ this.learningRefreshing = preserve;
5185
+ this.learningError = null;
5186
+ this.requestUpdate();
5187
+ try {
5188
+ const snapshot = await fetchInspectorLearning({
5189
+ runtimeUrl,
5190
+ runtimeTransport: core.runtimeTransport,
5191
+ request: {
5192
+ ...agentId ? { agentId } : {},
5193
+ skillsPage: options.skillsPage ?? this.learningSnapshot?.skillsPage.page ?? 1,
5194
+ insightsPage: options.insightsPage ?? this.learningSnapshot?.insightsPage.page ?? 1
5195
+ },
5196
+ fetch: core.ɵruntimeFetch,
5197
+ headers: core.headers,
5198
+ credentials: core.credentials,
5199
+ signal: controller.signal
5200
+ });
5201
+ if (generation !== this.learningRequestGeneration) return;
5202
+ if (snapshot.pendingThreadCount > 0 && !snapshot.links.runs || snapshot.pendingCandidateCount > 0 && !snapshot.links.candidates) throw new Error("Learning snapshot is missing a required web-app link.");
5203
+ const containerId = snapshot.configuration.state === "configured" ? snapshot.configuration.container.id : "";
5204
+ const previousContainerId = previousSnapshot?.configuration.state === "configured" ? previousSnapshot.configuration.container.id : "";
5205
+ const scopeChanged = previousSnapshot !== null && (previousSnapshot.projectKey !== snapshot.projectKey || previousContainerId !== containerId);
5206
+ const isBackgroundRefresh = options.skillsPage === void 0 && options.insightsPage === void 0;
5207
+ resetSkillsPage = Boolean(isBackgroundRefresh && previousSnapshot && previousSnapshot.skillsPage.page > 1 && (scopeChanged || JSON.stringify([previousSnapshot.skillsPage.total, previousSnapshot.skillsPage.items.map((skill) => [skill.id, skill.revision])]) !== JSON.stringify([snapshot.skillsPage.total, snapshot.skillsPage.items.map((skill) => [skill.id, skill.revision])])));
5208
+ resetInsightsPage = Boolean(isBackgroundRefresh && previousSnapshot && previousSnapshot.insightsPage.page > 1 && (scopeChanged || JSON.stringify([previousSnapshot.insightsPage.total, previousSnapshot.insightsPage.items.map((insight) => insight.id)]) !== JSON.stringify([snapshot.insightsPage.total, snapshot.insightsPage.items.map((insight) => insight.id)])));
5209
+ this.learningSnapshot = snapshot;
5210
+ loadOutcome = "success";
5211
+ loadedSkills = snapshot.skillsPage.total;
5212
+ loadedInsights = snapshot.insightsPage.total;
5213
+ loadedPendingThreads = snapshot.pendingThreadCount;
5214
+ this.learningSnapshotScope = `${requestContext}|${snapshot.projectKey}|${containerId}`;
5215
+ this.learningError = null;
5216
+ this.learningPollFailureCount = 0;
5217
+ if (snapshot.configuration.state === "configured") {
5218
+ clearLearningSetupMarker();
5219
+ this.learningSetupMarker = null;
5220
+ }
5221
+ } catch (error) {
5222
+ if (generation !== this.learningRequestGeneration || controller.signal.aborted) return;
5223
+ if (error instanceof InspectorLearningUnsupportedError) {
5224
+ loadOutcome = "unsupported";
5225
+ this.learningSupported = false;
5226
+ this.learningSnapshot = null;
5227
+ } else {
5228
+ this.learningError = error instanceof Error ? error.message : "Learning data is unavailable.";
5229
+ this.learningPollFailureCount += 1;
5230
+ }
5231
+ } finally {
5232
+ if (generation === this.learningRequestGeneration) {
5233
+ this.learningLoading = false;
5234
+ this.learningRefreshing = false;
5235
+ this.learningAbortController = null;
5236
+ if (!core.telemetryDisabled) trackLearningSnapshotLoaded({
5237
+ outcome: loadOutcome,
5238
+ duration_bucket: learningDurationBucket(performance.now() - startedAt),
5239
+ skills_bucket: learningCountBucket(loadedSkills),
5240
+ insights_bucket: learningCountBucket(loadedInsights),
5241
+ pending_threads_bucket: learningCountBucket(loadedPendingThreads)
5242
+ });
5243
+ this.scheduleLearningPoll();
5244
+ this.requestUpdate();
5245
+ this.trackLearningViewState();
5246
+ if (resetSkillsPage || resetInsightsPage) this.refreshLearningSnapshot({
5247
+ preserve: true,
5248
+ ...resetSkillsPage ? { skillsPage: 1 } : {},
5249
+ ...resetInsightsPage ? { insightsPage: 1 } : {}
5250
+ });
5251
+ }
5252
+ }
5253
+ };
5254
+ this.copyFeaturePromptToClipboard = async (service, event, onboardingRunId = createOnboardingRunId()) => {
5255
+ const clipboard = this.getClipboard(event);
5256
+ if (!clipboard?.writeText) return false;
5257
+ try {
5258
+ await clipboard.writeText(homeFeatureImplementationPrompt(service, { onboardingRunId }));
5259
+ return true;
5260
+ } catch {
5261
+ return false;
5262
+ }
5263
+ };
5264
+ this.handleLearningSetupCopy = async (event) => {
5265
+ const service = this.getHomeFeaturePromptTarget("threads");
5266
+ if (!service || !this.core?.runtimeUrl) return;
5267
+ const copied = await this.copyFeaturePromptToClipboard(service, event, this.getOnboardingRunId());
5268
+ if (!this.core.telemetryDisabled) trackLearningSetupPromptClicked({ outcome: copied ? "success" : "failure" });
5269
+ if (!copied) {
5270
+ this.learningPromptCopyState = "error";
5271
+ this.requestUpdate();
5272
+ return;
5273
+ }
5274
+ this.learningPromptCopyState = "copied";
5275
+ this.learningSetupMarker = writeLearningSetupMarker({
5276
+ runtimeUrl: this.core.runtimeUrl,
5277
+ agentId: this.getLearningAgentId()
5278
+ });
5279
+ this.selectedMenu = "memories";
5280
+ this.persistState();
5281
+ this.requestUpdate();
5282
+ this.refreshLearningSnapshot({ preserve: false });
5283
+ };
5284
+ this.handleLearningPage = (event) => {
5285
+ const { section, page } = event.detail;
5286
+ const currentPage = section === "skills" ? this.learningSnapshot?.skillsPage.page ?? 1 : this.learningSnapshot?.insightsPage.page ?? 1;
5287
+ if (!this.core?.telemetryDisabled) trackLearningPageChanged({
5288
+ section,
5289
+ direction: page < currentPage ? "previous" : "next"
5290
+ });
5291
+ this.refreshLearningSnapshot({
5292
+ preserve: true,
5293
+ ...section === "skills" ? { skillsPage: page } : { insightsPage: page }
5294
+ });
5295
+ };
5296
+ this.handleLearningEvidence = (event) => {
5297
+ this.focusThread({
5298
+ threadId: event.detail.threadId,
5299
+ ...event.detail.messageId ? { messageId: event.detail.messageId } : {}
5300
+ });
5301
+ };
5092
5302
  this.handleDocumentVisibilityChange = () => {
5093
5303
  this.accountCtaMotionPaused = document.visibilityState !== "visible";
5094
5304
  this.refreshInspectorDismissalState();
5095
5305
  if (document.visibilityState === "visible" && !this.isOpen && !this.isInspectorDismissed) this.flushPendingSignalPulse();
5306
+ if (document.visibilityState === "visible" && this.isOpen && this.selectedMenu === "memories") this.refreshLearningSnapshot({ preserve: true });
5307
+ else this.cancelLearningPoll();
5096
5308
  this.requestUpdate();
5097
5309
  };
5098
5310
  this.handlePillClick = (event) => {
@@ -5214,17 +5426,8 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
5214
5426
  feature_id: service.id,
5215
5427
  onboarding_run_id: onboardingRunId
5216
5428
  });
5217
- const clipboard = this.getClipboard(event);
5218
- if (!clipboard?.writeText) {
5219
- this.showHomeFeaturePromptCopyState(service.id, "error", generation);
5220
- return;
5221
- }
5222
- try {
5223
- await clipboard.writeText(homeFeatureImplementationPrompt(service, { onboardingRunId }));
5224
- this.showHomeFeaturePromptCopyState(service.id, "copied", generation);
5225
- } catch {
5226
- this.showHomeFeaturePromptCopyState(service.id, "error", generation);
5227
- }
5429
+ if (await this.copyFeaturePromptToClipboard(service, event, onboardingRunId)) this.showHomeFeaturePromptCopyState(service.id, "copied", generation);
5430
+ else this.showHomeFeaturePromptCopyState(service.id, "error", generation);
5228
5431
  };
5229
5432
  this.handleIntelligencePromptCopy = async (event) => {
5230
5433
  this.clearIntelligencePromptReset();
@@ -6077,6 +6280,7 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
6077
6280
  this._threadsByAgent.set(agentId, threads);
6078
6281
  this.rebuildFlattenedThreads();
6079
6282
  this.autoSelectLatestThread();
6283
+ if (this.selectedMenu === "memories" && this.shouldPollLearningSetup() && !this.learningLoading && !this.learningRefreshing) this.refreshLearningSnapshot({ preserve: true });
6080
6284
  this.requestUpdate();
6081
6285
  });
6082
6286
  const statusSub = store.select(createThreadStoreStatusSelector()).subscribe(({ error, isLoading }) => {
@@ -6257,6 +6461,8 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
6257
6461
  this.clearAllEventErrors();
6258
6462
  const supportsInspectorMetadata = this.coreSupportsInspectorMetadata(core);
6259
6463
  this.updateInspectorMetadataProjection(this.readCoreInspectorMetadata(core));
6464
+ this.learningSupported = core.inspectorLearning;
6465
+ this.learningProjectIdentity = JSON.stringify(this.inspectorMetadataProjection.identity ?? null);
6260
6466
  this.coreSubscriber = {
6261
6467
  onRuntimeConnectionStatusChanged: ({ status }) => {
6262
6468
  this.runtimeStatus = status;
@@ -6264,16 +6470,22 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
6264
6470
  const threadCapabilityWasEnabled = this.threadCapabilityEnabled === true;
6265
6471
  this.synchronizeThreadCapability();
6266
6472
  if (status === "connected") {
6473
+ this.learningSupported = core.inspectorLearning;
6267
6474
  if (!core.telemetryDisabled) {
6268
6475
  ensureTelemetryDistinctId();
6269
6476
  maybeShowDisclosure();
6270
6477
  }
6271
6478
  this.flushPendingWhatsNewTelemetry();
6479
+ if (this.isOpen && this.selectedMenu === "memories") {
6480
+ this.clearLearningSnapshot();
6481
+ this.refreshLearningSnapshot({ preserve: false });
6482
+ }
6272
6483
  if (threadCapabilityWasEnabled && this.areThreadEndpointsAvailable()) for (const agentId of this._ownedThreadStores.keys()) this.refreshOwnedThreadStore(agentId);
6273
6484
  } else {
6274
6485
  this._threadsByAgent.clear();
6275
6486
  this._threads = [];
6276
6487
  this.clearInspectorUsageRefresh();
6488
+ this.clearLearningSnapshot();
6277
6489
  }
6278
6490
  this.requestUpdate();
6279
6491
  },
@@ -6288,6 +6500,12 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
6288
6500
  ...supportsInspectorMetadata ? { onInspectorMetadataChanged: ({ inspectorMetadata }) => {
6289
6501
  if (this._core !== core) return;
6290
6502
  this.updateInspectorMetadataProjection(inspectorMetadata);
6503
+ const identity = JSON.stringify(this.inspectorMetadataProjection.identity ?? null);
6504
+ if (identity !== this.learningProjectIdentity) {
6505
+ this.learningProjectIdentity = identity;
6506
+ this.clearLearningSnapshot();
6507
+ if (this.isOpen && this.selectedMenu === "memories") this.refreshLearningSnapshot({ preserve: false });
6508
+ }
6291
6509
  this.requestUpdate();
6292
6510
  } } : {},
6293
6511
  onError: ({ code, error, context }) => {
@@ -6447,6 +6665,64 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
6447
6665
  this._recallQuery = "";
6448
6666
  this.requestUpdate();
6449
6667
  }
6668
+ getLearningAgentId() {
6669
+ if (this.selectedContext !== "all-agents" && this.core?.agents[this.selectedContext]) return this.selectedContext;
6670
+ return null;
6671
+ }
6672
+ isLearningSetupActive() {
6673
+ const runtimeUrl = this.core?.runtimeUrl;
6674
+ if (!runtimeUrl) return false;
6675
+ return learningSetupMarkerMatches(this.learningSetupMarker, runtimeUrl, this.getLearningAgentId());
6676
+ }
6677
+ trackLearningViewState() {
6678
+ if (!this.isOpen || this.selectedMenu !== "memories" || this.core?.telemetryDisabled) return;
6679
+ const state = deriveLearningViewState({
6680
+ supported: this.learningSupported,
6681
+ loading: this.learningLoading,
6682
+ error: this.learningError,
6683
+ snapshot: this.learningSnapshot,
6684
+ setupActive: this.isLearningSetupActive()
6685
+ });
6686
+ if (state === this.learningViewedState) return;
6687
+ this.learningViewedState = state;
6688
+ trackLearningPaneViewed({ state });
6689
+ }
6690
+ cancelLearningPoll() {
6691
+ if (this.learningPollTimer !== null) {
6692
+ clearTimeout(this.learningPollTimer);
6693
+ this.learningPollTimer = null;
6694
+ }
6695
+ }
6696
+ shouldPollLearningSetup() {
6697
+ if (!this.isOpen || this.selectedMenu !== "memories" || document.visibilityState !== "visible" || !this.learningSupported) return false;
6698
+ const snapshot = this.learningSnapshot;
6699
+ if (!snapshot) return this.isLearningSetupActive();
6700
+ if (snapshot.configuration.state === "not_configured") return this.isLearningSetupActive();
6701
+ return snapshot.configuration.state === "configured" && !snapshot.run.hasEverSucceeded && !snapshot.run.hasActiveRun && snapshot.pendingThreadCount === 0 && snapshot.skillsPage.total === 0 && snapshot.insightsPage.total === 0;
6702
+ }
6703
+ scheduleLearningPoll() {
6704
+ this.cancelLearningPoll();
6705
+ if (!this.shouldPollLearningSetup()) return;
6706
+ const delay = this.learningPollFailureCount === 0 ? 5e3 : this.learningPollFailureCount === 1 ? 1e4 : 3e4;
6707
+ this.learningPollTimer = setTimeout(() => {
6708
+ this.learningPollTimer = null;
6709
+ this.refreshLearningSnapshot({ preserve: true });
6710
+ }, delay);
6711
+ }
6712
+ clearLearningSnapshot() {
6713
+ this.cancelLearningRequest();
6714
+ this.learningSnapshot = null;
6715
+ this.learningSnapshotScope = null;
6716
+ this.learningError = null;
6717
+ this.learningLoading = false;
6718
+ this.learningRefreshing = false;
6719
+ this.cancelLearningPoll();
6720
+ }
6721
+ cancelLearningRequest() {
6722
+ this.learningRequestGeneration += 1;
6723
+ this.learningAbortController?.abort();
6724
+ this.learningAbortController = null;
6725
+ }
6450
6726
  detachFromCore() {
6451
6727
  this.threadCapabilityGeneration += 1;
6452
6728
  this.threadCapabilityEnabled = null;
@@ -6473,6 +6749,8 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
6473
6749
  this._recallLoading = false;
6474
6750
  this._recallError = null;
6475
6751
  this._recallQuery = "";
6752
+ this.clearLearningSnapshot();
6753
+ this.learningSupported = false;
6476
6754
  this.coreSubscriber = null;
6477
6755
  this.runtimeStatus = null;
6478
6756
  this.cancelThreadRefreshDebounce();
@@ -6499,6 +6777,7 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
6499
6777
  this.eventCounter = 0;
6500
6778
  }
6501
6779
  processAgentsChanged(agents) {
6780
+ const previousLearningAgentId = this.getLearningAgentId();
6502
6781
  this.synchronizeThreadCapability();
6503
6782
  const seenAgentIds = /* @__PURE__ */ new Set();
6504
6783
  for (const agent of Object.values(agents)) {
@@ -6514,6 +6793,15 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
6514
6793
  this.agentStates.delete(agentId);
6515
6794
  }
6516
6795
  this.updateContextOptions(seenAgentIds);
6796
+ const learningAgentId = this.getLearningAgentId();
6797
+ if (learningAgentId && this.core?.runtimeUrl && this.learningSetupMarker?.agentId === null && learningSetupMarkerMatches(this.learningSetupMarker, this.core.runtimeUrl, null)) this.learningSetupMarker = writeLearningSetupMarker({
6798
+ runtimeUrl: this.core.runtimeUrl,
6799
+ agentId: learningAgentId
6800
+ });
6801
+ if (previousLearningAgentId !== learningAgentId && this.isOpen && this.selectedMenu === "memories") {
6802
+ this.clearLearningSnapshot();
6803
+ this.refreshLearningSnapshot({ preserve: false });
6804
+ }
6517
6805
  this.refreshToolsSnapshot();
6518
6806
  this.requestUpdate();
6519
6807
  }
@@ -8865,6 +9153,11 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
8865
9153
  height: 100%;
8866
9154
  object-fit: cover;
8867
9155
  }
9156
+ .cpk-threads-overview-video-embed {
9157
+ width: 100%;
9158
+ height: 100%;
9159
+ border: 0;
9160
+ }
8868
9161
 
8869
9162
  /* ── Header controls on the branded account strip ──────────── */
8870
9163
  .drag-handle > div[data-inspector-account-strip] button {
@@ -9168,6 +9461,12 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
9168
9461
  const viteHot = import.meta.hot;
9169
9462
  if (viteHot) viteHot.on("vite:beforeUpdate", this.handleAppBeforeUnload);
9170
9463
  this.hydrateStateFromStorageEarly();
9464
+ this.learningSetupMarker = readLearningSetupMarker();
9465
+ this.learningSetupUnsubscribe = subscribeToLearningSetupMarker((marker) => {
9466
+ this.learningSetupMarker = marker;
9467
+ this.requestUpdate();
9468
+ this.scheduleLearningPoll();
9469
+ });
9171
9470
  this.refreshInspectorDismissalState();
9172
9471
  this.subscribeToSystemColorScheme();
9173
9472
  this.exampleTourDismissed = this.readThreadsExampleTourDismissed();
@@ -9199,6 +9498,9 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
9199
9498
  }
9200
9499
  this.clearIconRailContextCloseTimer();
9201
9500
  this.unsubscribeFromInspectorThreadBridge();
9501
+ this.learningSetupUnsubscribe?.();
9502
+ this.learningSetupUnsubscribe = null;
9503
+ this.clearLearningSnapshot();
9202
9504
  this.stopIntelligenceStory();
9203
9505
  this.clearIntelligencePromptReset();
9204
9506
  this.homeFeaturePromptCopyGeneration += 1;
@@ -10488,10 +10790,10 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
10488
10790
  getHomeFeaturePromptTarget(serviceId) {
10489
10791
  return this.getHomeModel().services.find((service) => service.id === serviceId);
10490
10792
  }
10491
- renderFeatureSetupPrompt(serviceId, className) {
10793
+ renderFeatureSetupPrompt(serviceId, className, options) {
10492
10794
  const service = this.getHomeFeaturePromptTarget(serviceId);
10493
10795
  if (!service) return nothing;
10494
- const copyState = this.homeFeaturePromptCopyState?.serviceId === service.id ? this.homeFeaturePromptCopyState.state : "idle";
10796
+ const copyState = options?.copyState ?? (this.homeFeaturePromptCopyState?.serviceId === service.id ? this.homeFeaturePromptCopyState.state : "idle");
10495
10797
  const label = copyState === "copied" ? "Copied" : copyState === "error" ? "Copy blocked" : "Copy setup prompt";
10496
10798
  return html`
10497
10799
  <button
@@ -10501,7 +10803,7 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
10501
10803
  data-inspector-threads-setup-prompt=${service.id === "threads" ? "" : nothing}
10502
10804
  data-copy-state=${copyState}
10503
10805
  aria-label=${copyState === "copied" ? `${service.label} setup prompt copied` : copyState === "error" ? `Could not copy the ${service.label} setup prompt. Try again` : `Copy setup prompt for ${service.label}`}
10504
- @click=${(event) => this.handleHomeFeaturePromptCopy(service, event)}
10806
+ @click=${(event) => options?.onClick ? options.onClick(event) : this.handleHomeFeaturePromptCopy(service, event)}
10505
10807
  >
10506
10808
  ${this.renderIcon(copyState === "copied" ? "Check" : "Copy")}
10507
10809
  ${label}
@@ -11527,6 +11829,7 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
11527
11829
  }
11528
11830
  this.ensureAnnouncementLoading();
11529
11831
  this.isOpen = true;
11832
+ if (this.selectedMenu === "memories") this.refreshLearningSnapshot({ preserve: this.learningSnapshot !== null });
11530
11833
  this.cancelGestureTail();
11531
11834
  this.persistState();
11532
11835
  this.trackOpened(source, hadUnseenAnnouncement, firstOpen, activeSignalAtOpen);
@@ -11544,6 +11847,9 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
11544
11847
  if (this.isPoppedOut) return;
11545
11848
  if (!this.isOpen) return;
11546
11849
  this.isOpen = false;
11850
+ this.cancelLearningPoll();
11851
+ this.cancelLearningRequest();
11852
+ this.learningViewedState = null;
11547
11853
  if (this.dockMode !== "floating") this.removeDockStyles();
11548
11854
  this.persistState();
11549
11855
  this.updateHostTransform("button");
@@ -12445,15 +12751,11 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
12445
12751
  });
12446
12752
  }
12447
12753
  getVisibleInspectorMetadataAction() {
12448
- const { threadsFooterAction, lockedAction } = this.inspectorMetadataProjection;
12449
- if (threadsFooterAction && !this.settingsOpen && this.selectedMenu === "threads") return {
12754
+ const { threadsFooterAction } = this.inspectorMetadataProjection;
12755
+ if (threadsFooterAction && !this.settingsOpen && this.selectedMenu === "threads" && this.areThreadEndpointsAvailable()) return {
12450
12756
  action: threadsFooterAction,
12451
12757
  placement: "threads-footer"
12452
12758
  };
12453
- if (lockedAction && !this.settingsOpen && this.selectedMenu === "threads" && !this.areThreadEndpointsAvailable()) return {
12454
- action: lockedAction,
12455
- placement: "locked"
12456
- };
12457
12759
  }
12458
12760
  /** Return paired stable navigation keys, or neither for an invalid leaf. */
12459
12761
  getMetadataTelemetryNavigation() {
@@ -12554,8 +12856,8 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
12554
12856
  else if (state === "empty_enabled") trackThreadsEmptyEnabledViewed(props);
12555
12857
  else trackThreadsEnabledViewed(props);
12556
12858
  }
12557
- shouldRenderExampleThreads(locked, displayThreads, threadsErrorMessage, threadsLoading) {
12558
- return locked || !threadsErrorMessage && !threadsLoading && displayThreads.length === 0;
12859
+ shouldRenderExampleThreads(displayThreads, threadsErrorMessage, threadsLoading) {
12860
+ return !threadsErrorMessage && !threadsLoading && displayThreads.length === 0;
12559
12861
  }
12560
12862
  isExampleThreadId(threadId) {
12561
12863
  return THREADS_EXAMPLE_THREADS.some((thread) => thread.id === threadId);
@@ -12966,46 +13268,114 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
12966
13268
  ` : nothing}
12967
13269
  `;
12968
13270
  }
12969
- renderThreadsExampleOverview(locked) {
12970
- const lockedCopy = locked ? this.getThreadsLockedCopy() : void 0;
12971
- const { lockedAction } = this.inspectorMetadataProjection;
13271
+ renderThreadsExampleOverview() {
12972
13272
  const onboardingAction = this.getThreadsEmptyOnboardingAction();
12973
13273
  return html`
12974
13274
  <div class="cpk-threads-overview">
12975
13275
  <div class="cpk-threads-overview-content">
12976
13276
  <h2 class="cpk-threads-overview-title">
12977
- ${lockedCopy?.heading ?? "Threads are persistent, inspectable conversations"}
13277
+ Threads are persistent, inspectable conversations
12978
13278
  </h2>
12979
13279
  ${this.renderThreadsExampleOverviewVideo()}
12980
13280
  <p class="cpk-threads-overview-copy">
12981
- ${lockedCopy?.description ?? "Take a tour with the example threads in the sidebar. Then, start chatting in your app to create the first real thread."}
13281
+ Take a tour with the example threads in the sidebar. Then, start
13282
+ chatting in your app to create the first real thread.
12982
13283
  </p>
12983
- ${locked ? this.renderRuntimeEntitlementDiagnostic(this.getRuntimeEntitlementDiagnostic()) : nothing}
12984
13284
  <div class="cpk-threads-overview-actions">
12985
- ${locked ? html`
12986
- ${this.renderFeatureSetupPrompt("threads", "cpk-threads-overview-action cpk-threads-overview-action-primary")}
12987
- ${lockedAction ? this.renderInspectorAction(lockedAction, "locked") : nothing}
12988
- ` : html`
12989
- <a
12990
- href=${this.getThreadsDocsUrl()}
12991
- target="_blank"
12992
- rel="noopener"
12993
- class="cpk-threads-overview-action cpk-threads-overview-action-primary"
12994
- >
12995
- Learn how Threads work
12996
- </a>
12997
- <a
12998
- href=${onboardingAction.href}
12999
- target="_blank"
13000
- rel="noopener"
13001
- class="cpk-threads-overview-action cpk-threads-overview-action-secondary"
13002
- >
13003
- ${onboardingAction.label}
13004
- </a>
13005
- `}
13285
+ <a
13286
+ href=${this.getThreadsDocsUrl()}
13287
+ target="_blank"
13288
+ rel="noopener"
13289
+ class="cpk-threads-overview-action cpk-threads-overview-action-primary"
13290
+ >
13291
+ Learn how Threads work
13292
+ </a>
13293
+ <a
13294
+ href=${onboardingAction.href}
13295
+ target="_blank"
13296
+ rel="noopener"
13297
+ class="cpk-threads-overview-action cpk-threads-overview-action-secondary"
13298
+ >
13299
+ ${onboardingAction.label}
13300
+ </a>
13006
13301
  </div>
13007
13302
  </div>
13008
13303
  </div>
13304
+ `;
13305
+ }
13306
+ renderLockedFeatureOverview({ serviceId, featureName, heading, description, videoUrl, videoTitle, outlineItems, setupPrompt }) {
13307
+ return html`
13308
+ <div
13309
+ class="cpk-locked-feature"
13310
+ data-inspector-locked-feature=${serviceId}
13311
+ >
13312
+ <div class="cpk-locked-feature-layout">
13313
+ <div class="cpk-locked-feature-hero">
13314
+ <div class="cpk-locked-feature-copy">
13315
+ <div class="cpk-locked-feature-name">
13316
+ <span class="cpk-locked-feature-icon" aria-hidden="true">
13317
+ ${serviceId === "threads" ? unsafeHTML(this.customTabIcons.threads) : this.renderIcon("Brain")}
13318
+ </span>
13319
+ ${featureName}
13320
+ </div>
13321
+ <h2 class="cpk-locked-feature-title">${heading}</h2>
13322
+ <p class="cpk-locked-feature-description">${description}</p>
13323
+ <div class="cpk-threads-overview-actions">
13324
+ ${this.renderFeatureSetupPrompt(setupPrompt?.serviceId ?? serviceId, "inspector-account-cta cpk-locked-feature-setup-cta", setupPrompt ? {
13325
+ copyState: setupPrompt.copyState,
13326
+ onClick: setupPrompt.onClick
13327
+ } : void 0)}
13328
+ <a
13329
+ data-inspector-locked-feature-talk=${serviceId}
13330
+ href=${this.getTalkToEngineerUrl()}
13331
+ target="_blank"
13332
+ rel="noopener noreferrer"
13333
+ aria-label="Talk to an Engineer (opens in a new tab)"
13334
+ class="cpk-threads-overview-action cpk-threads-overview-action-secondary"
13335
+ @click=${this.handleThreadsTalkToEngineerClick}
13336
+ >
13337
+ Talk to an Engineer
13338
+ </a>
13339
+ </div>
13340
+ </div>
13341
+ <div class="cpk-locked-feature-media">
13342
+ <div class="cpk-threads-overview-video-frame cpk-locked-feature-video">
13343
+ <iframe
13344
+ class="cpk-threads-overview-video-embed"
13345
+ data-inspector-feature-video=${serviceId}
13346
+ src=${videoUrl}
13347
+ title=${videoTitle}
13348
+ loading="lazy"
13349
+ allow="fullscreen; picture-in-picture"
13350
+ allowfullscreen
13351
+ ></iframe>
13352
+ </div>
13353
+ </div>
13354
+ </div>
13355
+ <section
13356
+ class="cpk-locked-feature-outline"
13357
+ data-inspector-feature-outline=${serviceId}
13358
+ aria-label="${featureName} capabilities"
13359
+ >
13360
+ <div class="cpk-locked-feature-outline-list">
13361
+ ${outlineItems.map((item) => html`
13362
+ <section class="cpk-locked-feature-outline-item">
13363
+ <h3>
13364
+ <span
13365
+ class="cpk-locked-feature-outline-icon"
13366
+ aria-hidden="true"
13367
+ >
13368
+ ${this.renderIcon(item.icon)}
13369
+ </span>
13370
+ ${item.title}
13371
+ </h3>
13372
+ <p>${item.description}</p>
13373
+ </section>
13374
+ `)}
13375
+ </div>
13376
+ </section>
13377
+ </div>
13378
+ </div>
13009
13379
  `;
13010
13380
  }
13011
13381
  renderThreadsExampleTour() {
@@ -13061,56 +13431,6 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
13061
13431
  </div>
13062
13432
  </div>
13063
13433
  </div>
13064
- `;
13065
- }
13066
- renderThreadsLockedBackgroundMockup() {
13067
- return html`
13068
- <div aria-hidden="true" class="cpk-locked-preview">
13069
- <div class="cpk-locked-preview-sidebar">
13070
- ${[
13071
- {
13072
- width: 74,
13073
- accent: true
13074
- },
13075
- { width: 92 },
13076
- { width: 68 },
13077
- { width: 84 },
13078
- { width: 58 },
13079
- { width: 76 }
13080
- ].map((row) => html`
13081
- <div
13082
- class="cpk-locked-preview-row"
13083
- data-accent=${row.accent ? "true" : "false"}
13084
- >
13085
- <div
13086
- class="cpk-locked-preview-bar cpk-locked-preview-row-title"
13087
- style="--preview-width: ${row.width}%;"
13088
- ></div>
13089
- <div
13090
- class="cpk-locked-preview-bar cpk-locked-preview-row-line"
13091
- ></div>
13092
- <div
13093
- class="cpk-locked-preview-bar cpk-locked-preview-row-line"
13094
- ></div>
13095
- </div>
13096
- `)}
13097
- </div>
13098
- <div class="cpk-locked-preview-main">
13099
- <div class="cpk-locked-preview-bar cpk-locked-preview-heading"></div>
13100
- <div class="cpk-locked-preview-bar cpk-locked-preview-copy"></div>
13101
- <div class="cpk-locked-preview-bar cpk-locked-preview-copy"></div>
13102
- <div class="cpk-locked-preview-cards">
13103
- <div class="cpk-locked-preview-card"></div>
13104
- <div class="cpk-locked-preview-card"></div>
13105
- </div>
13106
- <div
13107
- class="cpk-locked-preview-bar cpk-locked-preview-footer-line"
13108
- ></div>
13109
- <div
13110
- class="cpk-locked-preview-bar cpk-locked-preview-footer-line"
13111
- ></div>
13112
- </div>
13113
- </div>
13114
13434
  `;
13115
13435
  }
13116
13436
  getThreadsLockedCopy() {
@@ -13119,89 +13439,18 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
13119
13439
  heading: "Finish setting up Rich Threads",
13120
13440
  description: "Copy this prompt into your coding agent to finish the setup."
13121
13441
  };
13122
- case "none": return {
13123
- heading: "Enable Intelligence to inspect Threads.",
13124
- description: "Persist conversations and inspect saved thread history from the Inspector."
13442
+ case "none":
13443
+ case "unknown": return {
13444
+ heading: "Production-grade chat threads without the complexity. Self hostable.",
13445
+ description: "Chat threads that go beyond text with generative UI and multimodal inputs, built to replay missed events and stay in sync across tabs, sessions, and devices."
13125
13446
  };
13126
13447
  case "expired": return {
13127
13448
  heading: "Renew Intelligence to inspect Threads.",
13128
13449
  description: "Your Intelligence access has expired. Renew it to inspect saved thread history."
13129
13450
  };
13130
- case "unknown": return {
13131
- heading: "Threads are unavailable.",
13132
- description: "This runtime does not expose Threads for the Inspector."
13133
- };
13134
13451
  }
13135
13452
  }
13136
13453
  /**
13137
- * Prefer the Runtime's structured entitlement diagnostic and derive a
13138
- * compatibility diagnostic only when an older Core exposes legacy status.
13139
- */
13140
- getRuntimeEntitlementDiagnostic() {
13141
- const runtimeEntitlements = this.core?.runtimeEntitlements;
13142
- if (runtimeEntitlements) return runtimeEntitlements.status === "ready" ? { status: runtimeEntitlements.status } : {
13143
- status: runtimeEntitlements.status,
13144
- error: runtimeEntitlements.error
13145
- };
13146
- switch (this.core?.licenseStatus) {
13147
- case "valid": return { status: "ready" };
13148
- case "expired": return {
13149
- status: "degraded",
13150
- error: {
13151
- code: "legacy_license_expired",
13152
- message: "Legacy Runtime license has expired.",
13153
- retryable: false
13154
- }
13155
- };
13156
- case "expiring": return {
13157
- status: "degraded",
13158
- error: {
13159
- code: "legacy_license_expiring",
13160
- message: "Legacy Runtime license is expiring.",
13161
- retryable: false
13162
- }
13163
- };
13164
- case "invalid": return {
13165
- status: "misconfigured",
13166
- error: {
13167
- code: "legacy_license_invalid",
13168
- message: "Legacy Runtime license is invalid.",
13169
- retryable: false
13170
- }
13171
- };
13172
- case "none":
13173
- case "unknown": return { status: "unavailable" };
13174
- default: return null;
13175
- }
13176
- }
13177
- /** Render exact Runtime entitlement correlation details without gating UI. */
13178
- renderRuntimeEntitlementDiagnostic(diagnostic) {
13179
- if (!diagnostic) return nothing;
13180
- return html`
13181
- <div
13182
- role="status"
13183
- data-runtime-entitlement-status=${diagnostic.status}
13184
- style="
13185
- margin: -8px auto 18px;
13186
- max-width: 380px;
13187
- font-size: 11px;
13188
- line-height: 1.5;
13189
- color: #57575b;
13190
- "
13191
- >
13192
- <div style="font-weight: 600;">
13193
- Runtime entitlement: ${diagnostic.status}
13194
- </div>
13195
- ${diagnostic.error ? html`
13196
- <div>${diagnostic.error.message}</div>
13197
- <div>Code: ${diagnostic.error.code}</div>
13198
- ${diagnostic.error.requestId ? html`<div>Request ID: ${diagnostic.error.requestId}</div>` : nothing}
13199
- ${diagnostic.error.traceId ? html`<div>Trace ID: ${diagnostic.error.traceId}</div>` : nothing}
13200
- ` : nothing}
13201
- </div>
13202
- `;
13203
- }
13204
- /**
13205
13454
  * Renders the realtime-connection indicator in the memory-store header.
13206
13455
  * Only `"connected"` shows the live (green-dot) state; `"connecting"` shows a
13207
13456
  * muted amber "reconnecting" and `"unavailable"` a muted grey "offline", so
@@ -13236,44 +13485,64 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
13236
13485
  `;
13237
13486
  }
13238
13487
  renderMemoriesView() {
13239
- if (!this.getHomeModel().services.some((service) => service.id === "memory" && service.enabled)) return html`
13240
- <div class="cpk-memory-locked">
13241
- ${this.renderThreadsLockedBackgroundMockup()}
13242
- <div aria-hidden="true" class="cpk-memory-locked-scrim"></div>
13243
- <div class="cpk-memory-locked-content">
13244
- <div aria-hidden="true" class="cpk-memory-locked-icon-wrap">
13245
- <div class="cpk-memory-locked-icon">
13246
- ${this.renderIcon("Lock")}
13247
- </div>
13248
- </div>
13249
- <h2 class="cpk-memory-locked-title">Learning</h2>
13250
- <p class="cpk-memory-locked-copy">
13251
- ${this._memoryStoreUnsupported ? "Learning is unavailable in this version of the @copilotkit SDK. Upgrade @copilotkit/core (and @copilotkit/react) to a version that supports long-term memory." : "Learning turns durable information from agent interactions into reusable context. It isn't enabled on this deployment."}
13252
- </p>
13253
- <div class="cpk-memory-locked-actions">
13254
- ${this.renderFeatureSetupPrompt("memory", "cpk-memory-locked-action")}
13255
- <a
13256
- href=${this.getTalkToEngineerUrl()}
13257
- target="_blank"
13258
- rel="noopener"
13259
- class="cpk-memory-locked-action"
13260
- @click=${this.handleThreadsTalkToEngineerClick}
13261
- >
13262
- Talk to an Engineer
13263
- </a>
13264
- <a
13265
- href=${this.getIntelligenceSignupUrl()}
13266
- target="_blank"
13267
- rel="noopener"
13268
- class="cpk-memory-locked-action cpk-memory-locked-action-secondary"
13269
- @click=${this.handleThreadsIntelligenceSignupClick}
13270
- >
13271
- Sign up for Intelligence
13272
- </a>
13273
- </div>
13274
- </div>
13275
- </div>
13276
- `;
13488
+ if (deriveLearningViewState({
13489
+ supported: this.learningSupported,
13490
+ loading: this.learningLoading,
13491
+ error: this.learningError,
13492
+ snapshot: this.learningSnapshot,
13493
+ setupActive: this.isLearningSetupActive()
13494
+ }) === "landing") return this.renderLockedFeatureOverview({
13495
+ serviceId: "memory",
13496
+ featureName: "Learning",
13497
+ heading: "Turn every interaction into reusable context.",
13498
+ description: "Learning captures durable information from agent interactions and brings it back when it matters, so your product gets more useful over time.",
13499
+ videoUrl: LEARNING_LOCKED_VIDEO_URL,
13500
+ videoTitle: "CopilotKit Learning overview",
13501
+ outlineItems: LEARNING_LOCKED_FEATURE_OUTLINE,
13502
+ setupPrompt: {
13503
+ serviceId: "threads",
13504
+ copyState: this.learningPromptCopyState,
13505
+ onClick: (event) => void this.handleLearningSetupCopy(event)
13506
+ }
13507
+ });
13508
+ return html`
13509
+ <cpk-learning-view
13510
+ data-color-scheme=${this.colorScheme}
13511
+ .supported=${this.learningSupported}
13512
+ .loading=${this.learningLoading}
13513
+ .refreshing=${this.learningRefreshing}
13514
+ .error=${this.learningError}
13515
+ .snapshot=${this.learningSnapshot}
13516
+ .setupActive=${this.isLearningSetupActive()}
13517
+ .copyState=${this.learningPromptCopyState}
13518
+ .setupPrompt=${this.getHomeFeaturePromptTarget("threads") ? homeFeatureImplementationPrompt(this.getHomeFeaturePromptTarget("threads"), { onboardingRunId: this.getOnboardingRunId() }) : ""}
13519
+ @learning-retry=${() => this.refreshLearningSnapshot({ preserve: this.learningSnapshot !== null })}
13520
+ @learning-copy-setup=${(event) => this.handleLearningSetupCopy(event)}
13521
+ @learning-page=${(event) => this.handleLearningPage(event)}
13522
+ @learning-open-evidence=${(event) => this.handleLearningEvidence(event)}
13523
+ @learning-evidence-opened=${() => {
13524
+ if (!this.core?.telemetryDisabled) trackLearningEvidenceOpened();
13525
+ }}
13526
+ @learning-skill-toggle=${(event) => {
13527
+ if (!this.core?.telemetryDisabled) trackLearningSkillToggled({ action: event.detail.action });
13528
+ }}
13529
+ @learning-web-link=${(event) => {
13530
+ if (!this.core?.telemetryDisabled) trackLearningWebAppOpened({ category: event.detail.category });
13531
+ }}
13532
+ ></cpk-learning-view>
13533
+ `;
13534
+ }
13535
+ /** Legacy Memory rendering kept isolated while published Memory APIs remain. */
13536
+ renderLegacyMemoriesView() {
13537
+ if (!this.getHomeModel().services.some((service) => service.id === "memory" && service.enabled)) return this.renderLockedFeatureOverview({
13538
+ serviceId: "memory",
13539
+ featureName: "Learning",
13540
+ heading: this._memoryStoreUnsupported ? "Upgrade to enable Learning" : "Turn every interaction into reusable context.",
13541
+ description: this._memoryStoreUnsupported ? "Learning requires a newer version of @copilotkit/core and @copilotkit/react. Copy the setup prompt to upgrade and add long-term memory." : "Learning captures durable information from agent interactions and brings it back when it matters, so your product gets more useful over time.",
13542
+ videoUrl: LEARNING_LOCKED_VIDEO_URL,
13543
+ videoTitle: "CopilotKit Learning overview",
13544
+ outlineItems: LEARNING_LOCKED_FEATURE_OUTLINE
13545
+ });
13277
13546
  if (this._memoriesError && this._memories.length === 0) return html`
13278
13547
  <div
13279
13548
  style="
@@ -13484,16 +13753,27 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
13484
13753
  `;
13485
13754
  }
13486
13755
  renderThreadsView() {
13487
- const locked = !this.areThreadEndpointsAvailable();
13756
+ if (!this.areThreadEndpointsAvailable()) {
13757
+ this.trackThreadsViewStateOnce("locked");
13758
+ const lockedCopy = this.getThreadsLockedCopy();
13759
+ return this.renderLockedFeatureOverview({
13760
+ serviceId: "threads",
13761
+ featureName: "Rich Threads",
13762
+ heading: lockedCopy.heading,
13763
+ description: lockedCopy.description,
13764
+ videoUrl: THREADS_LOCKED_VIDEO_URL,
13765
+ videoTitle: "Rich Threads overview",
13766
+ outlineItems: THREADS_LOCKED_FEATURE_OUTLINE
13767
+ });
13768
+ }
13488
13769
  const { displayThreads, threadsErrorMessage, threadsLoading } = this.getActiveThreadsState();
13489
- const loadingWithoutRows = !locked && threadsLoading && !threadsErrorMessage && displayThreads.length === 0;
13490
- const showingExamples = this.shouldRenderExampleThreads(locked, displayThreads, threadsErrorMessage, threadsLoading);
13491
- const visibleThreads = !locked && (threadsErrorMessage || loadingWithoutRows) ? [] : showingExamples ? THREADS_EXAMPLE_THREADS : displayThreads;
13770
+ const loadingWithoutRows = threadsLoading && !threadsErrorMessage && displayThreads.length === 0;
13771
+ const showingExamples = this.shouldRenderExampleThreads(displayThreads, threadsErrorMessage, threadsLoading);
13772
+ const visibleThreads = threadsErrorMessage || loadingWithoutRows ? [] : showingExamples ? THREADS_EXAMPLE_THREADS : displayThreads;
13492
13773
  if (showingExamples) this.trackThreadsExampleViewedOnce();
13493
13774
  const selectedThread = this.selectedThreadId != null ? visibleThreads.find((t) => t.id === this.selectedThreadId) ?? null : null;
13494
13775
  const selectedThreadIsLocalExample = selectedThread !== null && selectedThread.id === this.selectedLocalExampleThreadId;
13495
- if (locked) this.trackThreadsViewStateOnce("locked");
13496
- else if (!threadsErrorMessage && (!threadsLoading || displayThreads.length > 0)) this.trackThreadsViewStateOnce(displayThreads.length === 0 ? "empty_enabled" : "enabled");
13776
+ if (!threadsErrorMessage && (!threadsLoading || displayThreads.length > 0)) this.trackThreadsViewStateOnce(displayThreads.length === 0 ? "empty_enabled" : "enabled");
13497
13777
  return html`
13498
13778
  <div
13499
13779
  style="display:flex;height:100%;overflow:hidden;flex-direction:column;"
@@ -13531,7 +13811,7 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
13531
13811
  <div
13532
13812
  style="flex:1;min-width:0;overflow:hidden;display:flex;position:relative;"
13533
13813
  >
13534
- ${!locked && threadsErrorMessage ? html`
13814
+ ${threadsErrorMessage ? html`
13535
13815
  <div
13536
13816
  role="alert"
13537
13817
  style="
@@ -13594,7 +13874,7 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
13594
13874
  this.handleTryFromHere(event.detail);
13595
13875
  }}
13596
13876
  ></cpk-thread-details>
13597
- ${selectedThreadIsLocalExample ? this.renderThreadsExampleTour() : nothing}` : showingExamples ? this.renderThreadsExampleOverview(locked) : html`
13877
+ ${selectedThreadIsLocalExample ? this.renderThreadsExampleTour() : nothing}` : showingExamples ? this.renderThreadsExampleOverview() : html`
13598
13878
  <div
13599
13879
  style="
13600
13880
  flex: 1;
@@ -14286,8 +14566,13 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
14286
14566
  }
14287
14567
  if (key === "playground" && !this.playgroundAgent) this.startPlaygroundSession(false);
14288
14568
  if (key === "memories") {
14289
- this.ensureMemorySubscription();
14569
+ this.learningSupported = Boolean(this.core?.inspectorLearning);
14570
+ if (previousMenu !== "memories" || this.learningSnapshot === null) this.refreshLearningSnapshot({ preserve: previousMenu === "memories" });
14290
14571
  if (previousMenu !== "memories" && !this.core?.telemetryDisabled) trackMemoriesTabClicked(this.getMemoriesTelemetryProps());
14572
+ } else if (previousMenu === "memories") {
14573
+ this.learningViewedState = null;
14574
+ this.cancelLearningPoll();
14575
+ this.cancelLearningRequest();
14291
14576
  }
14292
14577
  if (key === "home" && previousMenu !== "home") this.homeViewedThisOpen = false;
14293
14578
  if (key === "ag-ui-events" || key === "agents") {
@@ -14321,6 +14606,10 @@ var WebInspectorElement = class WebInspectorElement extends LitElement {
14321
14606
  this.expandedRows.clear();
14322
14607
  this.autoSelectLatestThread();
14323
14608
  if (this.selectedMenu === "playground") this.startPlaygroundSession(false);
14609
+ else if (this.selectedMenu === "memories") {
14610
+ this.clearLearningSnapshot();
14611
+ this.refreshLearningSnapshot({ preserve: false });
14612
+ }
14324
14613
  }
14325
14614
  this.contextMenuOpen = false;
14326
14615
  this.persistState();