@copilotkit/web-inspector 1.62.0 → 1.62.2-canary.1783457132
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +975 -24
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +45 -0
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.mts +45 -0
- package/dist/index.d.mts.map +1 -1
- package/dist/index.mjs +977 -26
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +1012 -55
- package/dist/index.umd.js.map +1 -1
- package/dist/lib/telemetry.cjs +7 -2
- package/dist/lib/telemetry.cjs.map +1 -1
- package/dist/lib/telemetry.mjs +7 -3
- package/dist/lib/telemetry.mjs.map +1 -1
- package/dist/package.cjs +1 -1
- package/dist/package.mjs +1 -1
- package/package.json +2 -2
- package/src/__tests__/web-inspector.spec.ts +1150 -1
- package/src/index.ts +1208 -60
- package/src/lib/telemetry.ts +18 -1
- package/src/styles/generated.css +1 -1
package/src/index.ts
CHANGED
|
@@ -13,12 +13,19 @@ import {
|
|
|
13
13
|
ɵselectThreads,
|
|
14
14
|
ɵselectThreadsError,
|
|
15
15
|
ɵcreateThreadStore,
|
|
16
|
+
ɵselectMemories,
|
|
17
|
+
ɵselectMemoriesIsLoading,
|
|
18
|
+
ɵselectMemoriesError,
|
|
19
|
+
ɵselectMemoriesAvailable,
|
|
20
|
+
ɵselectMemoriesRealtimeStatus,
|
|
16
21
|
} from "@copilotkit/core";
|
|
17
22
|
import type {
|
|
18
23
|
CopilotKitCoreSubscriber,
|
|
19
24
|
CopilotKitCoreErrorCode,
|
|
20
25
|
ɵThreadStore,
|
|
21
26
|
ɵThread,
|
|
27
|
+
Memory,
|
|
28
|
+
MemoryRealtimeStatus,
|
|
22
29
|
} from "@copilotkit/core";
|
|
23
30
|
import type { AbstractAgent, AgentSubscriber } from "@ag-ui/client";
|
|
24
31
|
import type {
|
|
@@ -60,10 +67,14 @@ import {
|
|
|
60
67
|
trackThreadsEnabledViewed,
|
|
61
68
|
trackThreadsIntelligenceSignupClicked,
|
|
62
69
|
trackThreadsLockedViewed,
|
|
70
|
+
trackMemoriesTabClicked,
|
|
63
71
|
trackThreadsTabClicked,
|
|
64
72
|
trackThreadsTalkToEngineerClicked,
|
|
65
73
|
} from "./lib/telemetry.js";
|
|
66
|
-
import type {
|
|
74
|
+
import type {
|
|
75
|
+
InspectorMemoryTelemetryProps,
|
|
76
|
+
InspectorThreadTelemetryProps,
|
|
77
|
+
} from "./lib/telemetry.js";
|
|
67
78
|
|
|
68
79
|
export type { Anchor } from "./lib/types.js";
|
|
69
80
|
|
|
@@ -78,6 +89,7 @@ type MenuKey =
|
|
|
78
89
|
| "frontend-tools"
|
|
79
90
|
| "agent-context"
|
|
80
91
|
| "threads"
|
|
92
|
+
| "memories"
|
|
81
93
|
| "settings";
|
|
82
94
|
|
|
83
95
|
type MenuItem = {
|
|
@@ -779,6 +791,8 @@ export class CpkThreadInspector extends LitElement {
|
|
|
779
791
|
_stateError: { state: true },
|
|
780
792
|
_expandedTools: { state: true },
|
|
781
793
|
_expandedMessages: { state: true },
|
|
794
|
+
_expandedTimelineDetails: { state: true },
|
|
795
|
+
_expandedRawEvents: { state: true },
|
|
782
796
|
_showDetailPanel: { state: true },
|
|
783
797
|
_detailPanelWidth: { state: true },
|
|
784
798
|
_eventsNotAvailable: { state: true },
|
|
@@ -816,6 +830,8 @@ export class CpkThreadInspector extends LitElement {
|
|
|
816
830
|
private _stateError: string | null = null;
|
|
817
831
|
private _expandedTools = new Set<string>();
|
|
818
832
|
private _expandedMessages = new Set<string>();
|
|
833
|
+
private _expandedTimelineDetails = new Set<string>();
|
|
834
|
+
private _expandedRawEvents = new Set<string>();
|
|
819
835
|
private _showDetailPanel = false;
|
|
820
836
|
private _detailPanelWidth = 250;
|
|
821
837
|
/** True when the /events endpoint returned 501 — don't fall back to live data. */
|
|
@@ -1102,6 +1118,7 @@ export class CpkThreadInspector extends LitElement {
|
|
|
1102
1118
|
|
|
1103
1119
|
.cpk-td__metadata-strip {
|
|
1104
1120
|
display: flex;
|
|
1121
|
+
align-items: center;
|
|
1105
1122
|
gap: 6px;
|
|
1106
1123
|
flex-wrap: wrap;
|
|
1107
1124
|
padding: 10px 16px;
|
|
@@ -1110,6 +1127,14 @@ export class CpkThreadInspector extends LitElement {
|
|
|
1110
1127
|
flex-shrink: 0;
|
|
1111
1128
|
}
|
|
1112
1129
|
|
|
1130
|
+
.cpk-td__metadata-pills {
|
|
1131
|
+
display: flex;
|
|
1132
|
+
gap: 6px;
|
|
1133
|
+
flex: 1;
|
|
1134
|
+
flex-wrap: wrap;
|
|
1135
|
+
min-width: 0;
|
|
1136
|
+
}
|
|
1137
|
+
|
|
1113
1138
|
.cpk-td__metadata-pill {
|
|
1114
1139
|
display: inline-flex;
|
|
1115
1140
|
align-items: center;
|
|
@@ -1404,13 +1429,44 @@ export class CpkThreadInspector extends LitElement {
|
|
|
1404
1429
|
}
|
|
1405
1430
|
|
|
1406
1431
|
.cpk-td__timeline-body {
|
|
1407
|
-
|
|
1432
|
+
margin: 0;
|
|
1433
|
+
padding: 0 10px 9px;
|
|
1408
1434
|
font-size: 12px;
|
|
1409
1435
|
line-height: 1.55;
|
|
1410
1436
|
color: #57575b;
|
|
1411
1437
|
white-space: pre-wrap;
|
|
1412
1438
|
word-break: break-word;
|
|
1413
|
-
|
|
1439
|
+
}
|
|
1440
|
+
|
|
1441
|
+
.cpk-td__timeline-toolbar {
|
|
1442
|
+
display: flex;
|
|
1443
|
+
gap: 6px;
|
|
1444
|
+
margin-left: auto;
|
|
1445
|
+
}
|
|
1446
|
+
|
|
1447
|
+
.cpk-td__timeline-bulk-toggle {
|
|
1448
|
+
margin: 0;
|
|
1449
|
+
padding: 4px 8px;
|
|
1450
|
+
border: 1px solid #dcdce8;
|
|
1451
|
+
border-radius: 6px;
|
|
1452
|
+
background: #ffffff;
|
|
1453
|
+
color: #36363a;
|
|
1454
|
+
cursor: pointer;
|
|
1455
|
+
font-family: "Inter", sans-serif;
|
|
1456
|
+
font-size: 11px;
|
|
1457
|
+
font-weight: 600;
|
|
1458
|
+
line-height: 1.2;
|
|
1459
|
+
}
|
|
1460
|
+
|
|
1461
|
+
.cpk-td__timeline-bulk-toggle:hover {
|
|
1462
|
+
border-color: rgba(85, 88, 178, 0.38);
|
|
1463
|
+
background: #f7f7ff;
|
|
1464
|
+
color: #010507;
|
|
1465
|
+
}
|
|
1466
|
+
|
|
1467
|
+
.cpk-td__timeline-bulk-toggle:disabled {
|
|
1468
|
+
cursor: not-allowed;
|
|
1469
|
+
opacity: 0.45;
|
|
1414
1470
|
}
|
|
1415
1471
|
|
|
1416
1472
|
.cpk-td__source-link {
|
|
@@ -1431,6 +1487,34 @@ export class CpkThreadInspector extends LitElement {
|
|
|
1431
1487
|
color: #010507;
|
|
1432
1488
|
}
|
|
1433
1489
|
|
|
1490
|
+
.cpk-td__timeline-details-toggle {
|
|
1491
|
+
margin: 0;
|
|
1492
|
+
padding: 5px 10px;
|
|
1493
|
+
border: none;
|
|
1494
|
+
background: #ffffff;
|
|
1495
|
+
color: #5558b2;
|
|
1496
|
+
cursor: pointer;
|
|
1497
|
+
display: inline-flex;
|
|
1498
|
+
align-items: center;
|
|
1499
|
+
gap: 5px;
|
|
1500
|
+
font-family: "Inter", sans-serif;
|
|
1501
|
+
font-size: 12px;
|
|
1502
|
+
font-weight: 600;
|
|
1503
|
+
line-height: 1.2;
|
|
1504
|
+
width: 100%;
|
|
1505
|
+
}
|
|
1506
|
+
|
|
1507
|
+
.cpk-td__timeline-details-toggle:hover {
|
|
1508
|
+
background: #f7f7ff;
|
|
1509
|
+
color: #010507;
|
|
1510
|
+
}
|
|
1511
|
+
|
|
1512
|
+
.cpk-td__timeline-details-toggle svg {
|
|
1513
|
+
width: 12px;
|
|
1514
|
+
height: 12px;
|
|
1515
|
+
stroke-width: 2;
|
|
1516
|
+
}
|
|
1517
|
+
|
|
1434
1518
|
/* ── Generative UI ──────────────────────────────────────────────── */
|
|
1435
1519
|
@keyframes cpk-genui-enter {
|
|
1436
1520
|
from {
|
|
@@ -1720,6 +1804,8 @@ export class CpkThreadInspector extends LitElement {
|
|
|
1720
1804
|
this._liveEventsWithSourceIndexCache = null;
|
|
1721
1805
|
this._expandedTools = new Set();
|
|
1722
1806
|
this._expandedMessages = new Set();
|
|
1807
|
+
this._expandedTimelineDetails = new Set();
|
|
1808
|
+
this._expandedRawEvents = new Set();
|
|
1723
1809
|
this._metadataAbort?.abort();
|
|
1724
1810
|
this._metadataAbort = null;
|
|
1725
1811
|
this._messagesAbort?.abort();
|
|
@@ -2391,6 +2477,47 @@ export class CpkThreadInspector extends LitElement {
|
|
|
2391
2477
|
this._expandedMessages = next;
|
|
2392
2478
|
}
|
|
2393
2479
|
|
|
2480
|
+
private toggleTimelineDetails(id: string): void {
|
|
2481
|
+
const next = new Set(this._expandedTimelineDetails);
|
|
2482
|
+
if (next.has(id)) next.delete(id);
|
|
2483
|
+
else next.add(id);
|
|
2484
|
+
this._expandedTimelineDetails = next;
|
|
2485
|
+
}
|
|
2486
|
+
|
|
2487
|
+
private expandTimelineDetails(ids: string[]): void {
|
|
2488
|
+
this._expandedTimelineDetails = new Set([
|
|
2489
|
+
...this._expandedTimelineDetails,
|
|
2490
|
+
...ids,
|
|
2491
|
+
]);
|
|
2492
|
+
}
|
|
2493
|
+
|
|
2494
|
+
private collapseTimelineDetails(ids: string[]): void {
|
|
2495
|
+
const next = new Set(this._expandedTimelineDetails);
|
|
2496
|
+
for (const id of ids) next.delete(id);
|
|
2497
|
+
this._expandedTimelineDetails = next;
|
|
2498
|
+
}
|
|
2499
|
+
|
|
2500
|
+
private toggleRawEventDetails(id: string): void {
|
|
2501
|
+
const next = new Set(this._expandedRawEvents);
|
|
2502
|
+
if (next.has(id)) next.delete(id);
|
|
2503
|
+
else next.add(id);
|
|
2504
|
+
this._expandedRawEvents = next;
|
|
2505
|
+
}
|
|
2506
|
+
|
|
2507
|
+
private expandRawEventDetails(ids: string[]): void {
|
|
2508
|
+
this._expandedRawEvents = new Set([...this._expandedRawEvents, ...ids]);
|
|
2509
|
+
}
|
|
2510
|
+
|
|
2511
|
+
private collapseRawEventDetails(ids: string[]): void {
|
|
2512
|
+
const next = new Set(this._expandedRawEvents);
|
|
2513
|
+
for (const id of ids) next.delete(id);
|
|
2514
|
+
this._expandedRawEvents = next;
|
|
2515
|
+
}
|
|
2516
|
+
|
|
2517
|
+
private rawEventId(event: ApiAgentEvent): string {
|
|
2518
|
+
return `raw-event-${event.sourceIndex ?? event.timestamp ?? event.type}`;
|
|
2519
|
+
}
|
|
2520
|
+
|
|
2394
2521
|
private get activeEvents(): ApiAgentEvent[] {
|
|
2395
2522
|
// When the endpoint explicitly returned 501 we report no events rather
|
|
2396
2523
|
// than leaking the parent's agent-keyed live events across historical
|
|
@@ -2562,25 +2689,95 @@ export class CpkThreadInspector extends LitElement {
|
|
|
2562
2689
|
},
|
|
2563
2690
|
{ label: "Status", value: metadata?.status },
|
|
2564
2691
|
].filter((pill) => pill.value != null && pill.value !== "");
|
|
2692
|
+
const bulkControls = this.renderActiveBulkControls();
|
|
2565
2693
|
|
|
2566
|
-
if (pills.length === 0) return nothing;
|
|
2694
|
+
if (pills.length === 0 && bulkControls === nothing) return nothing;
|
|
2567
2695
|
|
|
2568
2696
|
return html`
|
|
2569
2697
|
<div class="cpk-td__metadata-strip" aria-label="Thread metadata">
|
|
2570
|
-
|
|
2571
|
-
(
|
|
2572
|
-
|
|
2573
|
-
<span class="cpk-td__metadata-
|
|
2574
|
-
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
2578
|
-
|
|
2579
|
-
|
|
2698
|
+
<div class="cpk-td__metadata-pills">
|
|
2699
|
+
${pills.map(
|
|
2700
|
+
(pill) => html`
|
|
2701
|
+
<span class="cpk-td__metadata-pill" title=${pill.value ?? ""}>
|
|
2702
|
+
<span class="cpk-td__metadata-label">${pill.label}</span>
|
|
2703
|
+
<span class="cpk-td__metadata-value"
|
|
2704
|
+
>${this.shortId(pill.value)}</span
|
|
2705
|
+
>
|
|
2706
|
+
</span>
|
|
2707
|
+
`,
|
|
2708
|
+
)}
|
|
2709
|
+
</div>
|
|
2710
|
+
${bulkControls}
|
|
2580
2711
|
</div>
|
|
2581
2712
|
`;
|
|
2582
2713
|
}
|
|
2583
2714
|
|
|
2715
|
+
private renderActiveBulkControls() {
|
|
2716
|
+
if (this._eventsNotAvailable) return nothing;
|
|
2717
|
+
if (this._tab === "raw-events") return this.renderRawEventBulkControls();
|
|
2718
|
+
if (this._tab !== "timeline") return nothing;
|
|
2719
|
+
|
|
2720
|
+
const detailIds = this.timelineItemsForEvents(this.activeEvents)
|
|
2721
|
+
.filter((item) => item.details)
|
|
2722
|
+
.map((item) => item.id);
|
|
2723
|
+
if (detailIds.length <= 1) return nothing;
|
|
2724
|
+
|
|
2725
|
+
const allExpanded = detailIds.every((id) =>
|
|
2726
|
+
this._expandedTimelineDetails.has(id),
|
|
2727
|
+
);
|
|
2728
|
+
const allCollapsed = detailIds.every(
|
|
2729
|
+
(id) => !this._expandedTimelineDetails.has(id),
|
|
2730
|
+
);
|
|
2731
|
+
|
|
2732
|
+
return html`<div class="cpk-td__timeline-toolbar">
|
|
2733
|
+
<button
|
|
2734
|
+
type="button"
|
|
2735
|
+
class="cpk-td__timeline-bulk-toggle"
|
|
2736
|
+
?disabled=${allExpanded}
|
|
2737
|
+
@click=${() => this.expandTimelineDetails(detailIds)}
|
|
2738
|
+
>
|
|
2739
|
+
Expand all
|
|
2740
|
+
</button>
|
|
2741
|
+
<button
|
|
2742
|
+
type="button"
|
|
2743
|
+
class="cpk-td__timeline-bulk-toggle"
|
|
2744
|
+
?disabled=${allCollapsed}
|
|
2745
|
+
@click=${() => this.collapseTimelineDetails(detailIds)}
|
|
2746
|
+
>
|
|
2747
|
+
Collapse all
|
|
2748
|
+
</button>
|
|
2749
|
+
</div>`;
|
|
2750
|
+
}
|
|
2751
|
+
|
|
2752
|
+
private renderRawEventBulkControls() {
|
|
2753
|
+
const eventIds = this.activeEvents.map((event) => this.rawEventId(event));
|
|
2754
|
+
if (eventIds.length <= 1) return nothing;
|
|
2755
|
+
|
|
2756
|
+
const allExpanded = eventIds.every((id) => this._expandedRawEvents.has(id));
|
|
2757
|
+
const allCollapsed = eventIds.every(
|
|
2758
|
+
(id) => !this._expandedRawEvents.has(id),
|
|
2759
|
+
);
|
|
2760
|
+
|
|
2761
|
+
return html`<div class="cpk-td__timeline-toolbar">
|
|
2762
|
+
<button
|
|
2763
|
+
type="button"
|
|
2764
|
+
class="cpk-td__timeline-bulk-toggle"
|
|
2765
|
+
?disabled=${allExpanded}
|
|
2766
|
+
@click=${() => this.expandRawEventDetails(eventIds)}
|
|
2767
|
+
>
|
|
2768
|
+
Expand all
|
|
2769
|
+
</button>
|
|
2770
|
+
<button
|
|
2771
|
+
type="button"
|
|
2772
|
+
class="cpk-td__timeline-bulk-toggle"
|
|
2773
|
+
?disabled=${allCollapsed}
|
|
2774
|
+
@click=${() => this.collapseRawEventDetails(eventIds)}
|
|
2775
|
+
>
|
|
2776
|
+
Collapse all
|
|
2777
|
+
</button>
|
|
2778
|
+
</div>`;
|
|
2779
|
+
}
|
|
2780
|
+
|
|
2584
2781
|
private revealSourceEvent(sourceIndex: number): void {
|
|
2585
2782
|
this._activatedTabs = new Set([...this._activatedTabs, "raw-events"]);
|
|
2586
2783
|
this._tab = "raw-events";
|
|
@@ -2619,7 +2816,10 @@ export class CpkThreadInspector extends LitElement {
|
|
|
2619
2816
|
}
|
|
2620
2817
|
|
|
2621
2818
|
const events = this.activeEvents;
|
|
2622
|
-
const cachedTimeline = this.getCachedPanelTpl("timeline", [
|
|
2819
|
+
const cachedTimeline = this.getCachedPanelTpl("timeline", [
|
|
2820
|
+
events,
|
|
2821
|
+
this._expandedTimelineDetails,
|
|
2822
|
+
]);
|
|
2623
2823
|
if (cachedTimeline) return cachedTimeline;
|
|
2624
2824
|
|
|
2625
2825
|
const timelineItems = this.timelineItemsForEvents(events);
|
|
@@ -2637,13 +2837,16 @@ export class CpkThreadInspector extends LitElement {
|
|
|
2637
2837
|
`;
|
|
2638
2838
|
}
|
|
2639
2839
|
|
|
2640
|
-
return this.cachedPanelTpl(
|
|
2641
|
-
|
|
2642
|
-
|
|
2840
|
+
return this.cachedPanelTpl(
|
|
2841
|
+
"timeline",
|
|
2842
|
+
[events, this._expandedTimelineDetails],
|
|
2843
|
+
() => html`${timelineItems.map((item) => this.renderTimelineItem(item))}`,
|
|
2844
|
+
);
|
|
2643
2845
|
}
|
|
2644
2846
|
|
|
2645
2847
|
private renderTimelineItem(item: TimelineItem) {
|
|
2646
2848
|
const isWarning = item.kind === "warning";
|
|
2849
|
+
const detailsExpanded = this._expandedTimelineDetails.has(item.id);
|
|
2647
2850
|
return html`
|
|
2648
2851
|
<div
|
|
2649
2852
|
class="cpk-td__timeline-item ${
|
|
@@ -2666,14 +2869,56 @@ export class CpkThreadInspector extends LitElement {
|
|
|
2666
2869
|
>${formatTimestamp(item.timestamp)}</span
|
|
2667
2870
|
>
|
|
2668
2871
|
</div>
|
|
2872
|
+
${
|
|
2873
|
+
item.details
|
|
2874
|
+
? html`<button
|
|
2875
|
+
type="button"
|
|
2876
|
+
class="cpk-td__timeline-details-toggle"
|
|
2877
|
+
aria-expanded=${detailsExpanded ? "true" : "false"}
|
|
2878
|
+
@click=${() => this.toggleTimelineDetails(item.id)}
|
|
2879
|
+
>
|
|
2880
|
+
${
|
|
2881
|
+
detailsExpanded
|
|
2882
|
+
? html`
|
|
2883
|
+
<svg
|
|
2884
|
+
aria-hidden="true"
|
|
2885
|
+
viewBox="0 0 24 24"
|
|
2886
|
+
fill="none"
|
|
2887
|
+
stroke="currentColor"
|
|
2888
|
+
stroke-linecap="round"
|
|
2889
|
+
stroke-linejoin="round"
|
|
2890
|
+
>
|
|
2891
|
+
<path d="m6 9 6 6 6-6" />
|
|
2892
|
+
</svg>
|
|
2893
|
+
`
|
|
2894
|
+
: html`
|
|
2895
|
+
<svg
|
|
2896
|
+
aria-hidden="true"
|
|
2897
|
+
viewBox="0 0 24 24"
|
|
2898
|
+
fill="none"
|
|
2899
|
+
stroke="currentColor"
|
|
2900
|
+
stroke-linecap="round"
|
|
2901
|
+
stroke-linejoin="round"
|
|
2902
|
+
>
|
|
2903
|
+
<path d="m9 18 6-6-6-6" />
|
|
2904
|
+
</svg>
|
|
2905
|
+
`
|
|
2906
|
+
}
|
|
2907
|
+
<span>${detailsExpanded ? "Hide details" : "Show details"}</span>
|
|
2908
|
+
</button>`
|
|
2909
|
+
: nothing
|
|
2910
|
+
}
|
|
2669
2911
|
${
|
|
2670
2912
|
item.body
|
|
2671
2913
|
? html`<div class="cpk-td__timeline-body">${item.body}</div>`
|
|
2672
|
-
:
|
|
2673
|
-
|
|
2674
|
-
${
|
|
2675
|
-
|
|
2676
|
-
|
|
2914
|
+
: nothing
|
|
2915
|
+
}
|
|
2916
|
+
${
|
|
2917
|
+
item.details && detailsExpanded
|
|
2918
|
+
? html`<pre class="cpk-td__timeline-body">${unsafeHTML(
|
|
2919
|
+
highlightedJson(item.details),
|
|
2920
|
+
)}</pre>`
|
|
2921
|
+
: nothing
|
|
2677
2922
|
}
|
|
2678
2923
|
</div>
|
|
2679
2924
|
`;
|
|
@@ -3011,10 +3256,15 @@ ${unsafeHTML(highlightedJson(stateValue))}</pre
|
|
|
3011
3256
|
</div>
|
|
3012
3257
|
`;
|
|
3013
3258
|
}
|
|
3014
|
-
return this.cachedPanelTpl(
|
|
3015
|
-
|
|
3016
|
-
|
|
3017
|
-
|
|
3259
|
+
return this.cachedPanelTpl(
|
|
3260
|
+
"raw-events",
|
|
3261
|
+
[events, this._expandedRawEvents],
|
|
3262
|
+
() => {
|
|
3263
|
+
return html`${events.map((event) => {
|
|
3264
|
+
const { bg, fg } = eventColors(event.type);
|
|
3265
|
+
const eventId = this.rawEventId(event);
|
|
3266
|
+
const detailsExpanded = this._expandedRawEvents.has(eventId);
|
|
3267
|
+
return html`
|
|
3018
3268
|
<div class="cpk-td__event" data-source-index=${event.sourceIndex}>
|
|
3019
3269
|
<div class="cpk-td__event-header" style="background:${bg}">
|
|
3020
3270
|
<span class="cpk-td__event-type" style="color:${fg}"
|
|
@@ -3024,13 +3274,53 @@ ${unsafeHTML(highlightedJson(stateValue))}</pre
|
|
|
3024
3274
|
>${formatTimestamp(event.timestamp)}</span
|
|
3025
3275
|
>
|
|
3026
3276
|
</div>
|
|
3027
|
-
<
|
|
3028
|
-
|
|
3277
|
+
<button
|
|
3278
|
+
type="button"
|
|
3279
|
+
class="cpk-td__timeline-details-toggle"
|
|
3280
|
+
aria-expanded=${detailsExpanded ? "true" : "false"}
|
|
3281
|
+
@click=${() => this.toggleRawEventDetails(eventId)}
|
|
3029
3282
|
>
|
|
3283
|
+
${
|
|
3284
|
+
detailsExpanded
|
|
3285
|
+
? html`
|
|
3286
|
+
<svg
|
|
3287
|
+
aria-hidden="true"
|
|
3288
|
+
viewBox="0 0 24 24"
|
|
3289
|
+
fill="none"
|
|
3290
|
+
stroke="currentColor"
|
|
3291
|
+
stroke-linecap="round"
|
|
3292
|
+
stroke-linejoin="round"
|
|
3293
|
+
>
|
|
3294
|
+
<path d="m6 9 6 6 6-6" />
|
|
3295
|
+
</svg>
|
|
3296
|
+
`
|
|
3297
|
+
: html`
|
|
3298
|
+
<svg
|
|
3299
|
+
aria-hidden="true"
|
|
3300
|
+
viewBox="0 0 24 24"
|
|
3301
|
+
fill="none"
|
|
3302
|
+
stroke="currentColor"
|
|
3303
|
+
stroke-linecap="round"
|
|
3304
|
+
stroke-linejoin="round"
|
|
3305
|
+
>
|
|
3306
|
+
<path d="m9 18 6-6-6-6" />
|
|
3307
|
+
</svg>
|
|
3308
|
+
`
|
|
3309
|
+
}
|
|
3310
|
+
<span>${detailsExpanded ? "Hide details" : "Show details"}</span>
|
|
3311
|
+
</button>
|
|
3312
|
+
${
|
|
3313
|
+
detailsExpanded
|
|
3314
|
+
? html`<pre class="cpk-td__event-payload">${unsafeHTML(
|
|
3315
|
+
highlightedJson(event.rawEvent ?? event),
|
|
3316
|
+
)}</pre>`
|
|
3317
|
+
: nothing
|
|
3318
|
+
}
|
|
3030
3319
|
</div>
|
|
3031
3320
|
`;
|
|
3032
|
-
|
|
3033
|
-
|
|
3321
|
+
})}`;
|
|
3322
|
+
},
|
|
3323
|
+
);
|
|
3034
3324
|
}
|
|
3035
3325
|
|
|
3036
3326
|
private renderPanelToggle() {
|
|
@@ -3103,38 +3393,400 @@ ${unsafeHTML(highlightedJson(event.rawEvent ?? event))}</pre
|
|
|
3103
3393
|
>
|
|
3104
3394
|
</div>
|
|
3105
3395
|
|
|
3106
|
-
<div class="cpk-tdp__divider"></div>
|
|
3396
|
+
<div class="cpk-tdp__divider"></div>
|
|
3397
|
+
|
|
3398
|
+
<!-- Timestamps -->
|
|
3399
|
+
<div class="cpk-tdp__section-title">Timestamps</div>
|
|
3400
|
+
<div class="cpk-tdp__row">
|
|
3401
|
+
<span class="cpk-tdp__label">Created</span>
|
|
3402
|
+
<span class="cpk-tdp__value">${this.fmtTime(metadata?.createdAt)}</span>
|
|
3403
|
+
</div>
|
|
3404
|
+
<div class="cpk-tdp__row">
|
|
3405
|
+
<span class="cpk-tdp__label">Updated</span>
|
|
3406
|
+
<span class="cpk-tdp__value">${this.fmtTime(metadata?.updatedAt)}</span>
|
|
3407
|
+
</div>
|
|
3408
|
+
<div class="cpk-tdp__row">
|
|
3409
|
+
<span class="cpk-tdp__label">Duration</span>
|
|
3410
|
+
<span class="cpk-tdp__value">${this.duration}</span>
|
|
3411
|
+
</div>
|
|
3412
|
+
|
|
3413
|
+
<div class="cpk-tdp__divider"></div>
|
|
3414
|
+
|
|
3415
|
+
<!-- Activity -->
|
|
3416
|
+
<div class="cpk-tdp__section-title">Activity</div>
|
|
3417
|
+
<div class="cpk-tdp__row">
|
|
3418
|
+
<span class="cpk-tdp__label">Messages</span>
|
|
3419
|
+
<span class="cpk-tdp__value">${counts.messages}</span>
|
|
3420
|
+
</div>
|
|
3421
|
+
<div class="cpk-tdp__row">
|
|
3422
|
+
<span class="cpk-tdp__label">Tool calls</span>
|
|
3423
|
+
<span class="cpk-tdp__value">${counts.toolCalls}</span>
|
|
3424
|
+
</div>
|
|
3425
|
+
<div class="cpk-tdp__row">
|
|
3426
|
+
<span class="cpk-tdp__label">AG-UI events</span>
|
|
3427
|
+
<span class="cpk-tdp__value">${this.activeEvents.length}</span>
|
|
3428
|
+
</div>
|
|
3429
|
+
`;
|
|
3430
|
+
}
|
|
3431
|
+
}
|
|
3432
|
+
|
|
3433
|
+
// ─── cpk-memory-list ─────────────────────────────────────────────────────────
|
|
3434
|
+
|
|
3435
|
+
/** Memory kind values including the "all" sentinel used by the filter UI. */
|
|
3436
|
+
type MemoryKindFilter = "all" | "topical" | "episodic" | "operational";
|
|
3437
|
+
|
|
3438
|
+
class CpkMemoryList extends LitElement {
|
|
3439
|
+
static properties = {
|
|
3440
|
+
memories: { attribute: false },
|
|
3441
|
+
search: { state: true },
|
|
3442
|
+
kind: { state: true },
|
|
3443
|
+
};
|
|
3444
|
+
|
|
3445
|
+
/** Ordered (newest-first) list of memories supplied by the parent. */
|
|
3446
|
+
memories: Memory[] = [];
|
|
3447
|
+
private search = "";
|
|
3448
|
+
private kind: MemoryKindFilter = "all";
|
|
3449
|
+
|
|
3450
|
+
static styles = css`
|
|
3451
|
+
@import url("https://fonts.googleapis.com/css2?family=Plus+Jakarta+Sans:wght@400;500;600&family=Spline+Sans+Mono:wght@400;500&display=swap");
|
|
3452
|
+
|
|
3453
|
+
:host {
|
|
3454
|
+
display: flex;
|
|
3455
|
+
flex-direction: column;
|
|
3456
|
+
height: 100%;
|
|
3457
|
+
overflow: hidden;
|
|
3458
|
+
}
|
|
3459
|
+
|
|
3460
|
+
.cpk-ml {
|
|
3461
|
+
font-family: "Plus Jakarta Sans", sans-serif;
|
|
3462
|
+
display: flex;
|
|
3463
|
+
flex-direction: column;
|
|
3464
|
+
height: 100%;
|
|
3465
|
+
overflow: hidden;
|
|
3466
|
+
background: #f7f7f9;
|
|
3467
|
+
}
|
|
3468
|
+
|
|
3469
|
+
/* ── Search ── */
|
|
3470
|
+
.cpk-ml__search {
|
|
3471
|
+
padding: 10px 12px;
|
|
3472
|
+
border-bottom: 1px solid #dbdbe5;
|
|
3473
|
+
flex-shrink: 0;
|
|
3474
|
+
}
|
|
3475
|
+
|
|
3476
|
+
.cpk-ml__search-input {
|
|
3477
|
+
width: 100%;
|
|
3478
|
+
box-sizing: border-box;
|
|
3479
|
+
font-family: "Plus Jakarta Sans", sans-serif;
|
|
3480
|
+
font-size: 12px;
|
|
3481
|
+
padding: 7px 10px;
|
|
3482
|
+
border-radius: 6px;
|
|
3483
|
+
border: 1px solid #dbdbe5;
|
|
3484
|
+
background: #ffffff;
|
|
3485
|
+
color: #010507;
|
|
3486
|
+
outline: none;
|
|
3487
|
+
transition: border-color 0.15s;
|
|
3488
|
+
}
|
|
3489
|
+
|
|
3490
|
+
.cpk-ml__search-input:focus {
|
|
3491
|
+
border-color: #bec2ff;
|
|
3492
|
+
}
|
|
3493
|
+
|
|
3494
|
+
/* ── Kind filter ── */
|
|
3495
|
+
.cpk-ml__filter {
|
|
3496
|
+
display: flex;
|
|
3497
|
+
gap: 4px;
|
|
3498
|
+
padding: 8px 12px;
|
|
3499
|
+
border-bottom: 1px solid #dbdbe5;
|
|
3500
|
+
flex-shrink: 0;
|
|
3501
|
+
flex-wrap: wrap;
|
|
3502
|
+
}
|
|
3503
|
+
|
|
3504
|
+
.cpk-ml__filter-seg {
|
|
3505
|
+
font-family: "Plus Jakarta Sans", sans-serif;
|
|
3506
|
+
font-size: 11px;
|
|
3507
|
+
font-weight: 500;
|
|
3508
|
+
padding: 3px 9px;
|
|
3509
|
+
border-radius: 5px;
|
|
3510
|
+
border: 1px solid #dbdbe5;
|
|
3511
|
+
background: #ffffff;
|
|
3512
|
+
color: #57575b;
|
|
3513
|
+
cursor: pointer;
|
|
3514
|
+
transition:
|
|
3515
|
+
background 0.1s,
|
|
3516
|
+
border-color 0.1s,
|
|
3517
|
+
color 0.1s;
|
|
3518
|
+
user-select: none;
|
|
3519
|
+
}
|
|
3520
|
+
|
|
3521
|
+
.cpk-ml__filter-seg:hover {
|
|
3522
|
+
background: #f0f0f5;
|
|
3523
|
+
}
|
|
3524
|
+
|
|
3525
|
+
.cpk-ml__filter-seg--active {
|
|
3526
|
+
background: #bec2ff1a;
|
|
3527
|
+
border-color: #bec2ff;
|
|
3528
|
+
color: #010507;
|
|
3529
|
+
}
|
|
3530
|
+
|
|
3531
|
+
.cpk-ml__filter-count {
|
|
3532
|
+
font-family: "Spline Sans Mono", monospace;
|
|
3533
|
+
font-size: 9px;
|
|
3534
|
+
margin-left: 4px;
|
|
3535
|
+
color: #838389;
|
|
3536
|
+
}
|
|
3537
|
+
|
|
3538
|
+
/* ── List ── */
|
|
3539
|
+
.cpk-ml__list {
|
|
3540
|
+
flex: 1;
|
|
3541
|
+
overflow-y: auto;
|
|
3542
|
+
padding: 8px 12px;
|
|
3543
|
+
display: flex;
|
|
3544
|
+
flex-direction: column;
|
|
3545
|
+
gap: 8px;
|
|
3546
|
+
}
|
|
3547
|
+
|
|
3548
|
+
/* ── Card ── */
|
|
3549
|
+
.cpk-ml__card {
|
|
3550
|
+
background: #ffffff;
|
|
3551
|
+
border: 1px solid #e9e9ef;
|
|
3552
|
+
border-radius: 8px;
|
|
3553
|
+
padding: 10px 12px;
|
|
3554
|
+
display: flex;
|
|
3555
|
+
flex-direction: column;
|
|
3556
|
+
gap: 6px;
|
|
3557
|
+
}
|
|
3558
|
+
|
|
3559
|
+
.cpk-ml__card-badges {
|
|
3560
|
+
display: flex;
|
|
3561
|
+
gap: 6px;
|
|
3562
|
+
align-items: center;
|
|
3563
|
+
flex-wrap: wrap;
|
|
3564
|
+
}
|
|
3565
|
+
|
|
3566
|
+
/* Kind badge — color per kind */
|
|
3567
|
+
.cpk-ml__kind-badge {
|
|
3568
|
+
font-family: "Spline Sans Mono", monospace;
|
|
3569
|
+
font-size: 9px;
|
|
3570
|
+
padding: 1px 7px;
|
|
3571
|
+
border-radius: 4px;
|
|
3572
|
+
text-transform: uppercase;
|
|
3573
|
+
font-weight: 500;
|
|
3574
|
+
white-space: nowrap;
|
|
3575
|
+
}
|
|
3576
|
+
|
|
3577
|
+
.cpk-ml__kind-badge--topical {
|
|
3578
|
+
background: #eee6fe;
|
|
3579
|
+
color: #57575b;
|
|
3580
|
+
}
|
|
3581
|
+
|
|
3582
|
+
.cpk-ml__kind-badge--episodic {
|
|
3583
|
+
background: #e6f4fe;
|
|
3584
|
+
color: #2d5f80;
|
|
3585
|
+
}
|
|
3586
|
+
|
|
3587
|
+
.cpk-ml__kind-badge--operational {
|
|
3588
|
+
background: #e6feee;
|
|
3589
|
+
color: #2d6645;
|
|
3590
|
+
}
|
|
3591
|
+
|
|
3592
|
+
/* Scope badge */
|
|
3593
|
+
.cpk-ml__scope-badge {
|
|
3594
|
+
font-family: "Spline Sans Mono", monospace;
|
|
3595
|
+
font-size: 9px;
|
|
3596
|
+
padding: 1px 7px;
|
|
3597
|
+
border-radius: 4px;
|
|
3598
|
+
text-transform: uppercase;
|
|
3599
|
+
font-weight: 500;
|
|
3600
|
+
white-space: nowrap;
|
|
3601
|
+
background: #f0f0f5;
|
|
3602
|
+
color: #838389;
|
|
3603
|
+
}
|
|
3604
|
+
|
|
3605
|
+
/* Content */
|
|
3606
|
+
.cpk-ml__content {
|
|
3607
|
+
font-size: 12px;
|
|
3608
|
+
color: #010507;
|
|
3609
|
+
line-height: 1.5;
|
|
3610
|
+
word-break: break-word;
|
|
3611
|
+
}
|
|
3612
|
+
|
|
3613
|
+
/* Footer */
|
|
3614
|
+
.cpk-ml__footer {
|
|
3615
|
+
display: flex;
|
|
3616
|
+
align-items: center;
|
|
3617
|
+
justify-content: space-between;
|
|
3618
|
+
gap: 8px;
|
|
3619
|
+
margin-top: 2px;
|
|
3620
|
+
}
|
|
3621
|
+
|
|
3622
|
+
.cpk-ml__footer-threads {
|
|
3623
|
+
font-size: 10px;
|
|
3624
|
+
color: #838389;
|
|
3625
|
+
}
|
|
3626
|
+
|
|
3627
|
+
.cpk-ml__footer-id {
|
|
3628
|
+
font-family: "Spline Sans Mono", monospace;
|
|
3629
|
+
font-size: 9px;
|
|
3630
|
+
color: #c0c0c8;
|
|
3631
|
+
}
|
|
3632
|
+
|
|
3633
|
+
/* ── Empty state ── */
|
|
3634
|
+
.cpk-ml__empty {
|
|
3635
|
+
padding: 32px 16px;
|
|
3636
|
+
text-align: center;
|
|
3637
|
+
color: #838389;
|
|
3638
|
+
font-size: 12px;
|
|
3639
|
+
display: flex;
|
|
3640
|
+
flex-direction: column;
|
|
3641
|
+
align-items: center;
|
|
3642
|
+
gap: 8px;
|
|
3643
|
+
}
|
|
3644
|
+
|
|
3645
|
+
.cpk-ml__empty-icon {
|
|
3646
|
+
color: #c0c0c8;
|
|
3647
|
+
}
|
|
3648
|
+
`;
|
|
3649
|
+
|
|
3650
|
+
/** Memories that pass the current text search (before kind filter). */
|
|
3651
|
+
private get searchFiltered(): Memory[] {
|
|
3652
|
+
const q = this.search.trim().toLowerCase();
|
|
3653
|
+
if (!q) return this.memories;
|
|
3654
|
+
return this.memories.filter((m) => m.content.toLowerCase().includes(q));
|
|
3655
|
+
}
|
|
3656
|
+
|
|
3657
|
+
/** Memories that pass both search and kind filter. */
|
|
3658
|
+
private get filtered(): Memory[] {
|
|
3659
|
+
const searched = this.searchFiltered;
|
|
3660
|
+
if (this.kind === "all") return searched;
|
|
3661
|
+
return searched.filter((m) => m.kind === this.kind);
|
|
3662
|
+
}
|
|
3663
|
+
|
|
3664
|
+
/** Count of search-filtered memories for a given kind (for segment labels). */
|
|
3665
|
+
private countForKind(kind: Exclude<MemoryKindFilter, "all">): number {
|
|
3666
|
+
return this.searchFiltered.filter((m) => m.kind === kind).length;
|
|
3667
|
+
}
|
|
3668
|
+
|
|
3669
|
+
private onSearchInput = (event: Event): void => {
|
|
3670
|
+
this.search = (event.target as HTMLInputElement).value;
|
|
3671
|
+
};
|
|
3672
|
+
|
|
3673
|
+
private onKindClick = (event: Event): void => {
|
|
3674
|
+
const seg = (event.target as HTMLElement).closest("[data-kind]");
|
|
3675
|
+
if (!seg) return;
|
|
3676
|
+
const k = (seg as HTMLElement).dataset["kind"] as MemoryKindFilter;
|
|
3677
|
+
this.kind = k;
|
|
3678
|
+
};
|
|
3679
|
+
|
|
3680
|
+
/** Truncate an id to first-4…last-4 characters. */
|
|
3681
|
+
private shortId(id: string): string {
|
|
3682
|
+
if (id.length <= 12) return id;
|
|
3683
|
+
return `${id.slice(0, 4)}…${id.slice(-4)}`;
|
|
3684
|
+
}
|
|
3685
|
+
|
|
3686
|
+
private renderKindBadge(kind: string): TemplateResult {
|
|
3687
|
+
return html`<span class="cpk-ml__kind-badge cpk-ml__kind-badge--${kind}"
|
|
3688
|
+
>${kind}</span
|
|
3689
|
+
>`;
|
|
3690
|
+
}
|
|
3691
|
+
|
|
3692
|
+
private renderEmpty(): TemplateResult {
|
|
3693
|
+
const q = this.search.trim();
|
|
3694
|
+
if (this.memories.length === 0) {
|
|
3695
|
+
return html`
|
|
3696
|
+
<div class="cpk-ml__empty">
|
|
3697
|
+
<svg
|
|
3698
|
+
width="24"
|
|
3699
|
+
height="24"
|
|
3700
|
+
viewBox="0 0 24 24"
|
|
3701
|
+
fill="none"
|
|
3702
|
+
stroke="currentColor"
|
|
3703
|
+
stroke-width="1.5"
|
|
3704
|
+
stroke-linecap="round"
|
|
3705
|
+
stroke-linejoin="round"
|
|
3706
|
+
class="cpk-ml__empty-icon"
|
|
3707
|
+
>
|
|
3708
|
+
<ellipse cx="12" cy="5" rx="9" ry="3" />
|
|
3709
|
+
<path d="M21 12c0 1.66-4 3-9 3s-9-1.34-9-3" />
|
|
3710
|
+
<path d="M3 5v14c0 1.66 4 3 9 3s9-1.34 9-3V5" />
|
|
3711
|
+
</svg>
|
|
3712
|
+
No memories yet — tell the agent a durable fact and watch it appear.
|
|
3713
|
+
</div>
|
|
3714
|
+
`;
|
|
3715
|
+
}
|
|
3716
|
+
if (q) {
|
|
3717
|
+
return html`
|
|
3718
|
+
<div class="cpk-ml__empty">
|
|
3719
|
+
No memories match “${q}”.
|
|
3720
|
+
</div>
|
|
3721
|
+
`;
|
|
3722
|
+
}
|
|
3723
|
+
return html`
|
|
3724
|
+
<div class="cpk-ml__empty">No ${this.kind} memories yet.</div>
|
|
3725
|
+
`;
|
|
3726
|
+
}
|
|
3727
|
+
|
|
3728
|
+
render() {
|
|
3729
|
+
const filtered = this.filtered;
|
|
3730
|
+
const kinds: Array<Exclude<MemoryKindFilter, "all">> = [
|
|
3731
|
+
"topical",
|
|
3732
|
+
"episodic",
|
|
3733
|
+
"operational",
|
|
3734
|
+
];
|
|
3107
3735
|
|
|
3108
|
-
|
|
3109
|
-
<div class="cpk-
|
|
3110
|
-
|
|
3111
|
-
<
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
<span class="cpk-tdp__value">${this.duration}</span>
|
|
3121
|
-
</div>
|
|
3736
|
+
return html`
|
|
3737
|
+
<div class="cpk-ml">
|
|
3738
|
+
<!-- Search -->
|
|
3739
|
+
<div class="cpk-ml__search">
|
|
3740
|
+
<input
|
|
3741
|
+
type="text"
|
|
3742
|
+
placeholder="Search memories…"
|
|
3743
|
+
.value=${this.search}
|
|
3744
|
+
@input=${this.onSearchInput}
|
|
3745
|
+
class="cpk-ml__search-input"
|
|
3746
|
+
/>
|
|
3747
|
+
</div>
|
|
3122
3748
|
|
|
3123
|
-
|
|
3749
|
+
<!-- Kind filter -->
|
|
3750
|
+
<div class="cpk-ml__filter" @click=${this.onKindClick}>
|
|
3751
|
+
<button
|
|
3752
|
+
class="cpk-ml__filter-seg ${this.kind === "all" ? "cpk-ml__filter-seg--active" : ""}"
|
|
3753
|
+
data-kind="all"
|
|
3754
|
+
>
|
|
3755
|
+
All<span class="cpk-ml__filter-count">${this.searchFiltered.length}</span>
|
|
3756
|
+
</button>
|
|
3757
|
+
${kinds.map(
|
|
3758
|
+
(k) => html`
|
|
3759
|
+
<button
|
|
3760
|
+
class="cpk-ml__filter-seg ${this.kind === k ? "cpk-ml__filter-seg--active" : ""}"
|
|
3761
|
+
data-kind="${k}"
|
|
3762
|
+
>
|
|
3763
|
+
${k}<span class="cpk-ml__filter-count">${this.countForKind(k)}</span>
|
|
3764
|
+
</button>
|
|
3765
|
+
`,
|
|
3766
|
+
)}
|
|
3767
|
+
</div>
|
|
3124
3768
|
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3769
|
+
<!-- Memory list -->
|
|
3770
|
+
<div class="cpk-ml__list">
|
|
3771
|
+
${filtered.map(
|
|
3772
|
+
(m) => html`
|
|
3773
|
+
<div class="cpk-ml__card">
|
|
3774
|
+
<div class="cpk-ml__card-badges">
|
|
3775
|
+
${this.renderKindBadge(m.kind)}
|
|
3776
|
+
<span class="cpk-ml__scope-badge">${m.scope}</span>
|
|
3777
|
+
</div>
|
|
3778
|
+
<div class="cpk-ml__content">${m.content}</div>
|
|
3779
|
+
<div class="cpk-ml__footer">
|
|
3780
|
+
<span class="cpk-ml__footer-threads"
|
|
3781
|
+
>${m.sourceThreadIds.length} source thread${m.sourceThreadIds.length === 1 ? "" : "s"}</span
|
|
3782
|
+
>
|
|
3783
|
+
<span class="cpk-ml__footer-id">${this.shortId(m.id)}</span>
|
|
3784
|
+
</div>
|
|
3785
|
+
</div>
|
|
3786
|
+
`,
|
|
3787
|
+
)}
|
|
3788
|
+
${filtered.length === 0 ? this.renderEmpty() : nothing}
|
|
3789
|
+
</div>
|
|
3138
3790
|
</div>
|
|
3139
3791
|
`;
|
|
3140
3792
|
}
|
|
@@ -3154,6 +3806,9 @@ if (!customElements.get(THREAD_INSPECTOR_TAG)) {
|
|
|
3154
3806
|
if (!customElements.get("cpk-thread-details")) {
|
|
3155
3807
|
customElements.define("cpk-thread-details", ɵCpkThreadDetails);
|
|
3156
3808
|
}
|
|
3809
|
+
if (!customElements.get("cpk-memory-list")) {
|
|
3810
|
+
customElements.define("cpk-memory-list", CpkMemoryList);
|
|
3811
|
+
}
|
|
3157
3812
|
|
|
3158
3813
|
export class WebInspectorElement extends LitElement {
|
|
3159
3814
|
static properties = {
|
|
@@ -3164,6 +3819,25 @@ export class WebInspectorElement extends LitElement {
|
|
|
3164
3819
|
private _core: CopilotKitCore | null = null;
|
|
3165
3820
|
private coreSubscriber: CopilotKitCoreSubscriber | null = null;
|
|
3166
3821
|
private coreUnsubscribe: (() => void) | null = null;
|
|
3822
|
+
private _memories: Memory[] = [];
|
|
3823
|
+
private _memoriesLoading = false;
|
|
3824
|
+
private _memoriesError: Error | null = null;
|
|
3825
|
+
private _memoriesAvailable = true;
|
|
3826
|
+
// Realtime-connection health, independent of `_memoriesAvailable` (the REST
|
|
3827
|
+
// list route). Drives the "live" indicator: only "connected" shows "live".
|
|
3828
|
+
private _memoriesRealtimeStatus: MemoryRealtimeStatus = "connecting";
|
|
3829
|
+
private _memoryUnsub: (() => void) | null = null;
|
|
3830
|
+
// Lazy-subscription guard. The memory store is created + started + opens
|
|
3831
|
+
// realtime the first time `core.getMemoryStore()` is called, so we defer
|
|
3832
|
+
// that call until the user actually activates the Memories tab (see
|
|
3833
|
+
// `ensureMemorySubscription`). This flag prevents a repeated tab click from
|
|
3834
|
+
// double-subscribing; `detachFromCore` resets it so a later attach + tab
|
|
3835
|
+
// activation re-subscribes cleanly.
|
|
3836
|
+
private _memorySubscribed = false;
|
|
3837
|
+
// True when the attached core predates `getMemoryStore` (older @copilotkit
|
|
3838
|
+
// SDK). Distinct from `_memoriesAvailable` (memory not enabled on an
|
|
3839
|
+
// otherwise-current deployment) so the teaser can show upgrade-the-SDK copy.
|
|
3840
|
+
private _memoryStoreUnsupported = false;
|
|
3167
3841
|
private runtimeStatus: CopilotKitCoreRuntimeConnectionStatus | null = null;
|
|
3168
3842
|
private coreProperties: Readonly<Record<string, unknown>> = {};
|
|
3169
3843
|
private lastCoreError: {
|
|
@@ -3341,6 +4015,7 @@ export class WebInspectorElement extends LitElement {
|
|
|
3341
4015
|
label: "Threads",
|
|
3342
4016
|
icon: "MessageSquare" as LucideIconName,
|
|
3343
4017
|
},
|
|
4018
|
+
{ key: "memories", label: "Learning", icon: "Brain" as LucideIconName },
|
|
3344
4019
|
];
|
|
3345
4020
|
}
|
|
3346
4021
|
|
|
@@ -3382,6 +4057,17 @@ export class WebInspectorElement extends LitElement {
|
|
|
3382
4057
|
};
|
|
3383
4058
|
}
|
|
3384
4059
|
|
|
4060
|
+
private getMemoriesTelemetryProps(): InspectorMemoryTelemetryProps {
|
|
4061
|
+
const distinctId = !this.core?.telemetryDisabled
|
|
4062
|
+
? getTelemetryDistinctIdForUrl()
|
|
4063
|
+
: null;
|
|
4064
|
+
return {
|
|
4065
|
+
posthog_distinct_id: distinctId ?? undefined,
|
|
4066
|
+
memory_count: this._memories.length,
|
|
4067
|
+
available: this._memoriesAvailable,
|
|
4068
|
+
};
|
|
4069
|
+
}
|
|
4070
|
+
|
|
3385
4071
|
private getIntelligenceSignupUrl(): string {
|
|
3386
4072
|
return this.appendRefParam(INTELLIGENCE_SIGNUP_URL, "cpk-inspector");
|
|
3387
4073
|
}
|
|
@@ -3608,6 +4294,91 @@ export class WebInspectorElement extends LitElement {
|
|
|
3608
4294
|
if (core.context) {
|
|
3609
4295
|
this.contextStore = this.normalizeContextStore(core.context);
|
|
3610
4296
|
}
|
|
4297
|
+
|
|
4298
|
+
// NOTE: the memory store is intentionally NOT touched here. Calling
|
|
4299
|
+
// `core.getMemoryStore()` lazily creates + `.start()`s the store and opens
|
|
4300
|
+
// a realtime connection, so merely attaching the inspector would spin up a
|
|
4301
|
+
// memory store + realtime even in apps that never use memory. Instead, the
|
|
4302
|
+
// store is created + subscribed on first Memories-tab activation via
|
|
4303
|
+
// `ensureMemorySubscription` (user-initiated, acceptable). Attaching the
|
|
4304
|
+
// inspector creates nothing.
|
|
4305
|
+
//
|
|
4306
|
+
// Exception: if the Memories tab is ALREADY the active tab when core is
|
|
4307
|
+
// wired (e.g. core attaches after `firstUpdated` restored a persisted
|
|
4308
|
+
// `selectedMenu: "memories"`), subscribe now so the live store + realtime
|
|
4309
|
+
// status paint instead of the stuck defaults. This preserves INSP-1 (no
|
|
4310
|
+
// unconditional subscribe on attach) because it is gated on the active tab,
|
|
4311
|
+
// and is safe to call when already subscribed — `ensureMemorySubscription`
|
|
4312
|
+
// early-returns on `_memorySubscribed`.
|
|
4313
|
+
if (this.selectedMenu === "memories") {
|
|
4314
|
+
this.ensureMemorySubscription();
|
|
4315
|
+
}
|
|
4316
|
+
}
|
|
4317
|
+
|
|
4318
|
+
/**
|
|
4319
|
+
* Lazily subscribes to the singleton memory store the first time the user
|
|
4320
|
+
* activates the Memories tab. This is deferred out of `attachToCore` because
|
|
4321
|
+
* `core.getMemoryStore()` is what creates + starts the store and opens
|
|
4322
|
+
* realtime — doing it on attach would start memory for apps that never use
|
|
4323
|
+
* it. Idempotent: repeated tab activations are guarded by
|
|
4324
|
+
* `_memorySubscribed`. On an older @copilotkit/core without `getMemoryStore`,
|
|
4325
|
+
* records the unsupported state so the teaser can guide an SDK upgrade.
|
|
4326
|
+
*/
|
|
4327
|
+
private ensureMemorySubscription(): void {
|
|
4328
|
+
if (this._memorySubscribed) {
|
|
4329
|
+
return;
|
|
4330
|
+
}
|
|
4331
|
+
const core = this._core;
|
|
4332
|
+
if (!core) {
|
|
4333
|
+
return;
|
|
4334
|
+
}
|
|
4335
|
+
|
|
4336
|
+
// Guard like getThreadStores: older @copilotkit/core has no getMemoryStore.
|
|
4337
|
+
// When absent, flag the unsupported state so the teaser shows upgrade copy
|
|
4338
|
+
// instead of throwing a TypeError that would break the entire inspector.
|
|
4339
|
+
if (typeof core.getMemoryStore !== "function") {
|
|
4340
|
+
this._memoryStoreUnsupported = true;
|
|
4341
|
+
this._memoriesAvailable = false;
|
|
4342
|
+
this.requestUpdate();
|
|
4343
|
+
return;
|
|
4344
|
+
}
|
|
4345
|
+
|
|
4346
|
+
this._memorySubscribed = true;
|
|
4347
|
+
this._memoryStoreUnsupported = false;
|
|
4348
|
+
|
|
4349
|
+
// First touch of getMemoryStore() — creates + starts the store, opens realtime.
|
|
4350
|
+
const memoryStore = core.getMemoryStore();
|
|
4351
|
+
const ms = memoryStore.getState();
|
|
4352
|
+
this._memories = ɵselectMemories(ms);
|
|
4353
|
+
this._memoriesLoading = ɵselectMemoriesIsLoading(ms);
|
|
4354
|
+
this._memoriesError = ɵselectMemoriesError(ms);
|
|
4355
|
+
this._memoriesAvailable = ɵselectMemoriesAvailable(ms);
|
|
4356
|
+
this._memoriesRealtimeStatus = ɵselectMemoriesRealtimeStatus(ms);
|
|
4357
|
+
const memSubs = [
|
|
4358
|
+
memoryStore.select(ɵselectMemories).subscribe((v) => {
|
|
4359
|
+
this._memories = v;
|
|
4360
|
+
this.requestUpdate();
|
|
4361
|
+
}),
|
|
4362
|
+
memoryStore.select(ɵselectMemoriesIsLoading).subscribe((v) => {
|
|
4363
|
+
this._memoriesLoading = v;
|
|
4364
|
+
this.requestUpdate();
|
|
4365
|
+
}),
|
|
4366
|
+
memoryStore.select(ɵselectMemoriesError).subscribe((v) => {
|
|
4367
|
+
this._memoriesError = v;
|
|
4368
|
+
this.requestUpdate();
|
|
4369
|
+
}),
|
|
4370
|
+
memoryStore.select(ɵselectMemoriesAvailable).subscribe((v) => {
|
|
4371
|
+
this._memoriesAvailable = v;
|
|
4372
|
+
this.requestUpdate();
|
|
4373
|
+
}),
|
|
4374
|
+
// Group E — realtime connection health.
|
|
4375
|
+
memoryStore.select(ɵselectMemoriesRealtimeStatus).subscribe((v) => {
|
|
4376
|
+
this._memoriesRealtimeStatus = v;
|
|
4377
|
+
this.requestUpdate();
|
|
4378
|
+
}),
|
|
4379
|
+
];
|
|
4380
|
+
this._memoryUnsub = () => memSubs.forEach((s) => s.unsubscribe());
|
|
4381
|
+
this.requestUpdate();
|
|
3611
4382
|
}
|
|
3612
4383
|
|
|
3613
4384
|
private detachFromCore(): void {
|
|
@@ -3615,6 +4386,17 @@ export class WebInspectorElement extends LitElement {
|
|
|
3615
4386
|
this.coreUnsubscribe();
|
|
3616
4387
|
this.coreUnsubscribe = null;
|
|
3617
4388
|
}
|
|
4389
|
+
this._memoryUnsub?.();
|
|
4390
|
+
this._memoryUnsub = null;
|
|
4391
|
+
this._memories = [];
|
|
4392
|
+
this._memoriesLoading = false;
|
|
4393
|
+
this._memoriesError = null;
|
|
4394
|
+
this._memoriesAvailable = true;
|
|
4395
|
+
this._memoriesRealtimeStatus = "connecting";
|
|
4396
|
+
// Reset the lazy-subscription guards so a later attach + Memories-tab
|
|
4397
|
+
// activation re-subscribes (and re-evaluates SDK support) cleanly.
|
|
4398
|
+
this._memorySubscribed = false;
|
|
4399
|
+
this._memoryStoreUnsupported = false;
|
|
3618
4400
|
this.coreSubscriber = null;
|
|
3619
4401
|
this.runtimeStatus = null;
|
|
3620
4402
|
this.lastCoreError = null;
|
|
@@ -5161,6 +5943,18 @@ ${argsString}</pre
|
|
|
5161
5943
|
|
|
5162
5944
|
this.hydrateStateFromStorage();
|
|
5163
5945
|
|
|
5946
|
+
// `hydrateStateFromStorage` may have restored `selectedMenu: "memories"`.
|
|
5947
|
+
// The memory subscription is normally created on a Memories-tab CLICK via
|
|
5948
|
+
// `handleMenuSelect`, which never fires when the tab boots already active —
|
|
5949
|
+
// leaving the realtime indicator stuck on the default "connecting" and the
|
|
5950
|
+
// list empty until the user toggles tabs. Subscribe now when the Memories
|
|
5951
|
+
// tab is the active tab. Gated on the active tab to preserve INSP-1 (no
|
|
5952
|
+
// unconditional subscribe), and safe if core is not yet attached or already
|
|
5953
|
+
// subscribed — `ensureMemorySubscription` early-returns in both cases.
|
|
5954
|
+
if (this.selectedMenu === "memories") {
|
|
5955
|
+
this.ensureMemorySubscription();
|
|
5956
|
+
}
|
|
5957
|
+
|
|
5164
5958
|
// Apply docking styles if open and docked (skip transition on initial load)
|
|
5165
5959
|
if (this.isOpen && this.dockMode !== "floating") {
|
|
5166
5960
|
this.applyDockStyles(true);
|
|
@@ -6618,6 +7412,10 @@ ${argsString}</pre
|
|
|
6618
7412
|
return this.renderThreadsView();
|
|
6619
7413
|
}
|
|
6620
7414
|
|
|
7415
|
+
if (this.selectedMenu === "memories") {
|
|
7416
|
+
return this.renderMemoriesView();
|
|
7417
|
+
}
|
|
7418
|
+
|
|
6621
7419
|
if (this.selectedMenu === "settings") {
|
|
6622
7420
|
return this.renderSettingsPanel();
|
|
6623
7421
|
}
|
|
@@ -7065,6 +7863,346 @@ ${argsString}</pre
|
|
|
7065
7863
|
`;
|
|
7066
7864
|
}
|
|
7067
7865
|
|
|
7866
|
+
/**
|
|
7867
|
+
* Renders the realtime-connection indicator in the memory-store header.
|
|
7868
|
+
* Only `"connected"` shows the live (green-dot) state; `"connecting"` shows a
|
|
7869
|
+
* muted amber "reconnecting" and `"unavailable"` a muted grey "offline", so
|
|
7870
|
+
* the indicator never claims "live" over a frozen snapshot once the realtime
|
|
7871
|
+
* socket has permanently given up.
|
|
7872
|
+
*/
|
|
7873
|
+
private renderMemoryRealtimeIndicator() {
|
|
7874
|
+
const status = this._memoriesRealtimeStatus;
|
|
7875
|
+
const connected = status === "connected";
|
|
7876
|
+
const dotColor = connected
|
|
7877
|
+
? "#22c55e"
|
|
7878
|
+
: status === "connecting"
|
|
7879
|
+
? "#f59e0b"
|
|
7880
|
+
: "#9ca3af";
|
|
7881
|
+
const label =
|
|
7882
|
+
status === "connected"
|
|
7883
|
+
? "live"
|
|
7884
|
+
: status === "connecting"
|
|
7885
|
+
? "reconnecting"
|
|
7886
|
+
: "offline";
|
|
7887
|
+
return html`
|
|
7888
|
+
<span
|
|
7889
|
+
style="
|
|
7890
|
+
display: inline-flex;
|
|
7891
|
+
align-items: center;
|
|
7892
|
+
gap: 4px;
|
|
7893
|
+
font-size: 10px;
|
|
7894
|
+
font-weight: 500;
|
|
7895
|
+
color: ${connected ? "#57575b" : "#838389"};
|
|
7896
|
+
"
|
|
7897
|
+
>
|
|
7898
|
+
<span
|
|
7899
|
+
style="
|
|
7900
|
+
display: inline-block;
|
|
7901
|
+
width: 6px;
|
|
7902
|
+
height: 6px;
|
|
7903
|
+
border-radius: 50%;
|
|
7904
|
+
background: ${dotColor};
|
|
7905
|
+
"
|
|
7906
|
+
></span>
|
|
7907
|
+
${label}
|
|
7908
|
+
</span>
|
|
7909
|
+
`;
|
|
7910
|
+
}
|
|
7911
|
+
|
|
7912
|
+
private renderMemoriesView() {
|
|
7913
|
+
// 1. Locked teaser — intelligence not configured or memories not available.
|
|
7914
|
+
if (!this.core?.intelligence || !this._memoriesAvailable) {
|
|
7915
|
+
return html`
|
|
7916
|
+
<div
|
|
7917
|
+
style="
|
|
7918
|
+
position: relative;
|
|
7919
|
+
height: 100%;
|
|
7920
|
+
display: flex;
|
|
7921
|
+
align-items: center;
|
|
7922
|
+
justify-content: center;
|
|
7923
|
+
padding: 32px;
|
|
7924
|
+
overflow: hidden;
|
|
7925
|
+
background: #ffffff;
|
|
7926
|
+
"
|
|
7927
|
+
>
|
|
7928
|
+
${this.renderThreadsLockedBackgroundMockup()}
|
|
7929
|
+
<div
|
|
7930
|
+
aria-hidden="true"
|
|
7931
|
+
style="
|
|
7932
|
+
position: absolute;
|
|
7933
|
+
inset: 0;
|
|
7934
|
+
pointer-events: none;
|
|
7935
|
+
background:
|
|
7936
|
+
radial-gradient(circle at center, rgba(255,255,255,0.9) 0, rgba(255,255,255,0.78) 24%, rgba(255,255,255,0.34) 48%, rgba(255,255,255,0.56) 100%);
|
|
7937
|
+
"
|
|
7938
|
+
></div>
|
|
7939
|
+
<div
|
|
7940
|
+
style="
|
|
7941
|
+
position: relative;
|
|
7942
|
+
z-index: 1;
|
|
7943
|
+
max-width: 440px;
|
|
7944
|
+
text-align: center;
|
|
7945
|
+
color: #57575b;
|
|
7946
|
+
"
|
|
7947
|
+
>
|
|
7948
|
+
<div
|
|
7949
|
+
aria-hidden="true"
|
|
7950
|
+
style="
|
|
7951
|
+
margin: 0 auto 18px;
|
|
7952
|
+
display: flex;
|
|
7953
|
+
justify-content: center;
|
|
7954
|
+
"
|
|
7955
|
+
>
|
|
7956
|
+
<div
|
|
7957
|
+
style="
|
|
7958
|
+
display: flex;
|
|
7959
|
+
height: 44px;
|
|
7960
|
+
width: 44px;
|
|
7961
|
+
align-items: center;
|
|
7962
|
+
justify-content: center;
|
|
7963
|
+
border: 1px solid #dfd6fb;
|
|
7964
|
+
border-radius: 8px;
|
|
7965
|
+
background: #eee6fe;
|
|
7966
|
+
color: #57575b;
|
|
7967
|
+
box-shadow: 0 8px 18px rgba(87, 87, 91, 0.14);
|
|
7968
|
+
"
|
|
7969
|
+
>
|
|
7970
|
+
${this.renderIcon("Lock")}
|
|
7971
|
+
</div>
|
|
7972
|
+
</div>
|
|
7973
|
+
<h2
|
|
7974
|
+
style="
|
|
7975
|
+
margin: 0 0 8px;
|
|
7976
|
+
font-size: 16px;
|
|
7977
|
+
line-height: 1.35;
|
|
7978
|
+
font-weight: 600;
|
|
7979
|
+
color: #010507;
|
|
7980
|
+
"
|
|
7981
|
+
>
|
|
7982
|
+
Long-term memory
|
|
7983
|
+
</h2>
|
|
7984
|
+
<p
|
|
7985
|
+
style="
|
|
7986
|
+
margin: 0 auto 18px;
|
|
7987
|
+
max-width: 380px;
|
|
7988
|
+
font-size: 13px;
|
|
7989
|
+
line-height: 1.55;
|
|
7990
|
+
color: #57575b;
|
|
7991
|
+
"
|
|
7992
|
+
>
|
|
7993
|
+
${
|
|
7994
|
+
this._memoryStoreUnsupported
|
|
7995
|
+
? "Long-term memory isn't available in this version of the @copilotkit SDK. Upgrade @copilotkit/core (and @copilotkit/react) to a version that supports memory."
|
|
7996
|
+
: "Long-term memory isn't enabled on this deployment."
|
|
7997
|
+
}
|
|
7998
|
+
</p>
|
|
7999
|
+
<div
|
|
8000
|
+
style="
|
|
8001
|
+
display: flex;
|
|
8002
|
+
flex-wrap: wrap;
|
|
8003
|
+
justify-content: center;
|
|
8004
|
+
gap: 8px;
|
|
8005
|
+
"
|
|
8006
|
+
>
|
|
8007
|
+
<a
|
|
8008
|
+
href=${this.getTalkToEngineerUrl()}
|
|
8009
|
+
target="_blank"
|
|
8010
|
+
rel="noopener"
|
|
8011
|
+
style="
|
|
8012
|
+
display: inline-flex;
|
|
8013
|
+
min-height: 34px;
|
|
8014
|
+
align-items: center;
|
|
8015
|
+
justify-content: center;
|
|
8016
|
+
gap: 6px;
|
|
8017
|
+
border-radius: 6px;
|
|
8018
|
+
background: #010507;
|
|
8019
|
+
padding: 8px 12px;
|
|
8020
|
+
font-size: 12px;
|
|
8021
|
+
font-weight: 600;
|
|
8022
|
+
color: #ffffff;
|
|
8023
|
+
text-decoration: none;
|
|
8024
|
+
"
|
|
8025
|
+
@click=${this.handleThreadsTalkToEngineerClick}
|
|
8026
|
+
>
|
|
8027
|
+
Talk to an Engineer
|
|
8028
|
+
</a>
|
|
8029
|
+
<a
|
|
8030
|
+
href=${this.getIntelligenceSignupUrl()}
|
|
8031
|
+
target="_blank"
|
|
8032
|
+
rel="noopener"
|
|
8033
|
+
style="
|
|
8034
|
+
display: inline-flex;
|
|
8035
|
+
min-height: 34px;
|
|
8036
|
+
align-items: center;
|
|
8037
|
+
justify-content: center;
|
|
8038
|
+
gap: 6px;
|
|
8039
|
+
border-radius: 6px;
|
|
8040
|
+
border: 1px solid #dbdbe5;
|
|
8041
|
+
background: #ffffff;
|
|
8042
|
+
padding: 8px 12px;
|
|
8043
|
+
font-size: 12px;
|
|
8044
|
+
font-weight: 600;
|
|
8045
|
+
color: #57575b;
|
|
8046
|
+
text-decoration: none;
|
|
8047
|
+
"
|
|
8048
|
+
@click=${this.handleThreadsIntelligenceSignupClick}
|
|
8049
|
+
>
|
|
8050
|
+
Sign up for Intelligence
|
|
8051
|
+
</a>
|
|
8052
|
+
</div>
|
|
8053
|
+
</div>
|
|
8054
|
+
</div>
|
|
8055
|
+
`;
|
|
8056
|
+
}
|
|
8057
|
+
|
|
8058
|
+
// 2. Full-screen error — only for a snapshot-LOAD failure (no memories
|
|
8059
|
+
// loaded). A mutation failure that arrives while memories are already on
|
|
8060
|
+
// screen must NOT blank the list; it is surfaced inline below (step 4).
|
|
8061
|
+
if (this._memoriesError && this._memories.length === 0) {
|
|
8062
|
+
return html`
|
|
8063
|
+
<div
|
|
8064
|
+
style="
|
|
8065
|
+
display: flex;
|
|
8066
|
+
height: 100%;
|
|
8067
|
+
flex-direction: column;
|
|
8068
|
+
align-items: center;
|
|
8069
|
+
justify-content: center;
|
|
8070
|
+
gap: 8px;
|
|
8071
|
+
color: #838389;
|
|
8072
|
+
"
|
|
8073
|
+
>
|
|
8074
|
+
<svg
|
|
8075
|
+
width="24"
|
|
8076
|
+
height="24"
|
|
8077
|
+
viewBox="0 0 24 24"
|
|
8078
|
+
fill="none"
|
|
8079
|
+
stroke="#c0333a"
|
|
8080
|
+
stroke-width="1.5"
|
|
8081
|
+
stroke-linecap="round"
|
|
8082
|
+
stroke-linejoin="round"
|
|
8083
|
+
>
|
|
8084
|
+
<circle cx="12" cy="12" r="10" />
|
|
8085
|
+
<line x1="12" y1="8" x2="12" y2="12" />
|
|
8086
|
+
<line x1="12" y1="16" x2="12.01" y2="16" />
|
|
8087
|
+
</svg>
|
|
8088
|
+
<span style="font-size: 13px; color: #c0333a;">
|
|
8089
|
+
Failed to load memories
|
|
8090
|
+
</span>
|
|
8091
|
+
<span
|
|
8092
|
+
style="
|
|
8093
|
+
max-width: 320px;
|
|
8094
|
+
text-align: center;
|
|
8095
|
+
font-size: 11px;
|
|
8096
|
+
line-height: 1.5;
|
|
8097
|
+
color: #c0333a;
|
|
8098
|
+
"
|
|
8099
|
+
>
|
|
8100
|
+
${this._memoriesError.message}
|
|
8101
|
+
</span>
|
|
8102
|
+
</div>
|
|
8103
|
+
`;
|
|
8104
|
+
}
|
|
8105
|
+
|
|
8106
|
+
// 3. Initial loading placeholder (no memories yet to show behind it).
|
|
8107
|
+
if (this._memoriesLoading && this._memories.length === 0) {
|
|
8108
|
+
return html`
|
|
8109
|
+
<div
|
|
8110
|
+
style="
|
|
8111
|
+
display: flex;
|
|
8112
|
+
height: 100%;
|
|
8113
|
+
flex-direction: column;
|
|
8114
|
+
align-items: center;
|
|
8115
|
+
justify-content: center;
|
|
8116
|
+
gap: 8px;
|
|
8117
|
+
color: #838389;
|
|
8118
|
+
"
|
|
8119
|
+
>
|
|
8120
|
+
<svg
|
|
8121
|
+
width="24"
|
|
8122
|
+
height="24"
|
|
8123
|
+
viewBox="0 0 24 24"
|
|
8124
|
+
fill="none"
|
|
8125
|
+
stroke="#c0c0c8"
|
|
8126
|
+
stroke-width="1.5"
|
|
8127
|
+
stroke-linecap="round"
|
|
8128
|
+
stroke-linejoin="round"
|
|
8129
|
+
>
|
|
8130
|
+
<path d="M21 12a9 9 0 1 1-6.219-8.56" />
|
|
8131
|
+
</svg>
|
|
8132
|
+
<span style="font-size: 13px">Loading memories…</span>
|
|
8133
|
+
</div>
|
|
8134
|
+
`;
|
|
8135
|
+
}
|
|
8136
|
+
|
|
8137
|
+
// 4. Content — header + memory list.
|
|
8138
|
+
return html`
|
|
8139
|
+
<div style="display:flex;height:100%;overflow:hidden;flex-direction:column;">
|
|
8140
|
+
<div class="cpk-section-header" style="display:flex;align-items:center;justify-content:space-between;">
|
|
8141
|
+
<h4>Learning</h4>
|
|
8142
|
+
<div style="display:flex;align-items:center;gap:6px;">
|
|
8143
|
+
${this.renderMemoryRealtimeIndicator()}
|
|
8144
|
+
<span
|
|
8145
|
+
style="
|
|
8146
|
+
font-size: 11px;
|
|
8147
|
+
font-weight: 500;
|
|
8148
|
+
color: #57575b;
|
|
8149
|
+
background: rgba(0,0,0,0.07);
|
|
8150
|
+
border-radius: 9999px;
|
|
8151
|
+
padding: 1px 7px;
|
|
8152
|
+
"
|
|
8153
|
+
>
|
|
8154
|
+
${this._memories.length}
|
|
8155
|
+
</span>
|
|
8156
|
+
</div>
|
|
8157
|
+
</div>
|
|
8158
|
+
${
|
|
8159
|
+
this._memoriesError
|
|
8160
|
+
? html`
|
|
8161
|
+
<div
|
|
8162
|
+
role="alert"
|
|
8163
|
+
style="
|
|
8164
|
+
display: flex;
|
|
8165
|
+
align-items: flex-start;
|
|
8166
|
+
gap: 8px;
|
|
8167
|
+
flex-shrink: 0;
|
|
8168
|
+
border-bottom: 1px solid #f1c7c9;
|
|
8169
|
+
background: #fdf3f3;
|
|
8170
|
+
padding: 8px 12px;
|
|
8171
|
+
color: #c0333a;
|
|
8172
|
+
font-size: 12px;
|
|
8173
|
+
line-height: 1.45;
|
|
8174
|
+
"
|
|
8175
|
+
>
|
|
8176
|
+
<svg
|
|
8177
|
+
width="16"
|
|
8178
|
+
height="16"
|
|
8179
|
+
viewBox="0 0 24 24"
|
|
8180
|
+
fill="none"
|
|
8181
|
+
stroke="#c0333a"
|
|
8182
|
+
stroke-width="1.5"
|
|
8183
|
+
stroke-linecap="round"
|
|
8184
|
+
stroke-linejoin="round"
|
|
8185
|
+
style="flex-shrink:0;margin-top:1px;"
|
|
8186
|
+
>
|
|
8187
|
+
<circle cx="12" cy="12" r="10" />
|
|
8188
|
+
<line x1="12" y1="8" x2="12" y2="12" />
|
|
8189
|
+
<line x1="12" y1="16" x2="12.01" y2="16" />
|
|
8190
|
+
</svg>
|
|
8191
|
+
<span>Action failed: ${this._memoriesError.message}</span>
|
|
8192
|
+
</div>
|
|
8193
|
+
`
|
|
8194
|
+
: nothing
|
|
8195
|
+
}
|
|
8196
|
+
<div style="flex:1;min-height:0;overflow:hidden;">
|
|
8197
|
+
<cpk-memory-list
|
|
8198
|
+
style="height:100%;"
|
|
8199
|
+
.memories=${this._memories}
|
|
8200
|
+
></cpk-memory-list>
|
|
8201
|
+
</div>
|
|
8202
|
+
</div>
|
|
8203
|
+
`;
|
|
8204
|
+
}
|
|
8205
|
+
|
|
7068
8206
|
private renderThreadsView() {
|
|
7069
8207
|
if (!this.areThreadEndpointsAvailable()) {
|
|
7070
8208
|
return this.renderThreadsLockedView();
|
|
@@ -7884,6 +9022,16 @@ ${prettyEvent}</pre
|
|
|
7884
9022
|
this.autoSelectLatestThread();
|
|
7885
9023
|
}
|
|
7886
9024
|
|
|
9025
|
+
if (key === "memories") {
|
|
9026
|
+
// Lazily create + subscribe to the memory store on first activation. This
|
|
9027
|
+
// is the only place that touches getMemoryStore(), so the store/realtime
|
|
9028
|
+
// are never started just by attaching the inspector.
|
|
9029
|
+
this.ensureMemorySubscription();
|
|
9030
|
+
if (previousMenu !== "memories" && !this.core?.telemetryDisabled) {
|
|
9031
|
+
trackMemoriesTabClicked(this.getMemoriesTelemetryProps());
|
|
9032
|
+
}
|
|
9033
|
+
}
|
|
9034
|
+
|
|
7887
9035
|
if (key === "ag-ui-events" || key === "agents") {
|
|
7888
9036
|
requestAnimationFrame(() => {
|
|
7889
9037
|
const scroller = this.shadowRoot?.getElementById("cpk-main-scroll");
|