@copilotkitnext/web-inspector 1.51.4-next.7 → 1.51.4-next.8
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/CHANGELOG.md +6 -0
- package/dist/index.js +594 -189
- package/dist/index.js.map +1 -1
- package/dist/index.mjs +594 -189
- package/dist/index.mjs.map +1 -1
- package/dist/index.umd.js +388 -139
- package/dist/index.umd.js.map +1 -1
- package/package.json +4 -5
- package/src/__tests__/web-inspector.spec.ts +25 -9
- package/src/components.d.ts +6 -10
- package/src/index.ts +958 -373
- package/src/lib/context-helpers.ts +60 -19
- package/src/lib/persistence.ts +16 -11
- package/src/lib/types.ts +4 -4
- package/tsup.config.ts +7 -7
- package/.turbo/turbo-build$colon$css.log +0 -7
- package/.turbo/turbo-build.log +0 -36
package/src/index.ts
CHANGED
|
@@ -13,7 +13,14 @@ import {
|
|
|
13
13
|
type CopilotKitCoreErrorCode,
|
|
14
14
|
} from "@copilotkitnext/core";
|
|
15
15
|
import type { AbstractAgent, AgentSubscriber } from "@ag-ui/client";
|
|
16
|
-
import type {
|
|
16
|
+
import type {
|
|
17
|
+
Anchor,
|
|
18
|
+
ContextKey,
|
|
19
|
+
ContextState,
|
|
20
|
+
DockMode,
|
|
21
|
+
Position,
|
|
22
|
+
Size,
|
|
23
|
+
} from "./lib/types";
|
|
17
24
|
import {
|
|
18
25
|
applyAnchorPosition as applyAnchorPositionHelper,
|
|
19
26
|
centerContext as centerContextHelper,
|
|
@@ -147,14 +154,20 @@ export class WebInspectorElement extends LitElement {
|
|
|
147
154
|
private coreUnsubscribe: (() => void) | null = null;
|
|
148
155
|
private runtimeStatus: CopilotKitCoreRuntimeConnectionStatus | null = null;
|
|
149
156
|
private coreProperties: Readonly<Record<string, unknown>> = {};
|
|
150
|
-
private lastCoreError: {
|
|
157
|
+
private lastCoreError: {
|
|
158
|
+
code: CopilotKitCoreErrorCode;
|
|
159
|
+
message: string;
|
|
160
|
+
} | null = null;
|
|
151
161
|
private agentSubscriptions: Map<string, () => void> = new Map();
|
|
152
162
|
private agentEvents: Map<string, InspectorEvent[]> = new Map();
|
|
153
163
|
private agentMessages: Map<string, InspectorMessage[]> = new Map();
|
|
154
164
|
private agentStates: Map<string, SanitizedValue> = new Map();
|
|
155
165
|
private flattenedEvents: InspectorEvent[] = [];
|
|
156
166
|
private eventCounter = 0;
|
|
157
|
-
private contextStore: Record<
|
|
167
|
+
private contextStore: Record<
|
|
168
|
+
string,
|
|
169
|
+
{ description?: string; value: unknown }
|
|
170
|
+
> = {};
|
|
158
171
|
|
|
159
172
|
private pointerId: number | null = null;
|
|
160
173
|
private dragStart: Position | null = null;
|
|
@@ -301,7 +314,9 @@ export class WebInspectorElement extends LitElement {
|
|
|
301
314
|
this.eventCounter = 0;
|
|
302
315
|
}
|
|
303
316
|
|
|
304
|
-
private processAgentsChanged(
|
|
317
|
+
private processAgentsChanged(
|
|
318
|
+
agents: Readonly<Record<string, AbstractAgent>>,
|
|
319
|
+
): void {
|
|
305
320
|
const seenAgentIds = new Set<string>();
|
|
306
321
|
|
|
307
322
|
for (const agent of Object.values(agents)) {
|
|
@@ -355,7 +370,12 @@ export class WebInspectorElement extends LitElement {
|
|
|
355
370
|
}
|
|
356
371
|
|
|
357
372
|
private tryAutoAttachCore(): void {
|
|
358
|
-
if (
|
|
373
|
+
if (
|
|
374
|
+
this.attemptedAutoAttach ||
|
|
375
|
+
this._core ||
|
|
376
|
+
!this.autoAttachCore ||
|
|
377
|
+
typeof window === "undefined"
|
|
378
|
+
) {
|
|
359
379
|
return;
|
|
360
380
|
}
|
|
361
381
|
|
|
@@ -370,7 +390,8 @@ export class WebInspectorElement extends LitElement {
|
|
|
370
390
|
];
|
|
371
391
|
|
|
372
392
|
const foundCore = globalCandidates.find(
|
|
373
|
-
(candidate): candidate is CopilotKitCore =>
|
|
393
|
+
(candidate): candidate is CopilotKitCore =>
|
|
394
|
+
!!candidate && typeof candidate === "object",
|
|
374
395
|
);
|
|
375
396
|
|
|
376
397
|
if (foundCore) {
|
|
@@ -401,19 +422,39 @@ export class WebInspectorElement extends LitElement {
|
|
|
401
422
|
this.recordAgentEvent(agentId, "TEXT_MESSAGE_START", event);
|
|
402
423
|
},
|
|
403
424
|
onTextMessageContentEvent: ({ event, textMessageBuffer }) => {
|
|
404
|
-
this.recordAgentEvent(agentId, "TEXT_MESSAGE_CONTENT", {
|
|
425
|
+
this.recordAgentEvent(agentId, "TEXT_MESSAGE_CONTENT", {
|
|
426
|
+
event,
|
|
427
|
+
textMessageBuffer,
|
|
428
|
+
});
|
|
405
429
|
},
|
|
406
430
|
onTextMessageEndEvent: ({ event, textMessageBuffer }) => {
|
|
407
|
-
this.recordAgentEvent(agentId, "TEXT_MESSAGE_END", {
|
|
431
|
+
this.recordAgentEvent(agentId, "TEXT_MESSAGE_END", {
|
|
432
|
+
event,
|
|
433
|
+
textMessageBuffer,
|
|
434
|
+
});
|
|
408
435
|
},
|
|
409
436
|
onToolCallStartEvent: ({ event }) => {
|
|
410
437
|
this.recordAgentEvent(agentId, "TOOL_CALL_START", event);
|
|
411
438
|
},
|
|
412
|
-
onToolCallArgsEvent: ({
|
|
413
|
-
|
|
439
|
+
onToolCallArgsEvent: ({
|
|
440
|
+
event,
|
|
441
|
+
toolCallBuffer,
|
|
442
|
+
toolCallName,
|
|
443
|
+
partialToolCallArgs,
|
|
444
|
+
}) => {
|
|
445
|
+
this.recordAgentEvent(agentId, "TOOL_CALL_ARGS", {
|
|
446
|
+
event,
|
|
447
|
+
toolCallBuffer,
|
|
448
|
+
toolCallName,
|
|
449
|
+
partialToolCallArgs,
|
|
450
|
+
});
|
|
414
451
|
},
|
|
415
452
|
onToolCallEndEvent: ({ event, toolCallArgs, toolCallName }) => {
|
|
416
|
-
this.recordAgentEvent(agentId, "TOOL_CALL_END", {
|
|
453
|
+
this.recordAgentEvent(agentId, "TOOL_CALL_END", {
|
|
454
|
+
event,
|
|
455
|
+
toolCallArgs,
|
|
456
|
+
toolCallName,
|
|
457
|
+
});
|
|
417
458
|
},
|
|
418
459
|
onToolCallResultEvent: ({ event }) => {
|
|
419
460
|
this.recordAgentEvent(agentId, "TOOL_CALL_RESULT", event);
|
|
@@ -459,7 +500,11 @@ export class WebInspectorElement extends LitElement {
|
|
|
459
500
|
}
|
|
460
501
|
}
|
|
461
502
|
|
|
462
|
-
private recordAgentEvent(
|
|
503
|
+
private recordAgentEvent(
|
|
504
|
+
agentId: string,
|
|
505
|
+
type: InspectorAgentEventType,
|
|
506
|
+
payload: unknown,
|
|
507
|
+
): void {
|
|
463
508
|
const eventId = `${agentId}:${++this.eventCounter}`;
|
|
464
509
|
const normalizedPayload = this.normalizeEventPayload(type, payload);
|
|
465
510
|
const event: InspectorEvent = {
|
|
@@ -471,10 +516,16 @@ export class WebInspectorElement extends LitElement {
|
|
|
471
516
|
};
|
|
472
517
|
|
|
473
518
|
const currentAgentEvents = this.agentEvents.get(agentId) ?? [];
|
|
474
|
-
const nextAgentEvents = [event, ...currentAgentEvents].slice(
|
|
519
|
+
const nextAgentEvents = [event, ...currentAgentEvents].slice(
|
|
520
|
+
0,
|
|
521
|
+
MAX_AGENT_EVENTS,
|
|
522
|
+
);
|
|
475
523
|
this.agentEvents.set(agentId, nextAgentEvents);
|
|
476
524
|
|
|
477
|
-
this.flattenedEvents = [event, ...this.flattenedEvents].slice(
|
|
525
|
+
this.flattenedEvents = [event, ...this.flattenedEvents].slice(
|
|
526
|
+
0,
|
|
527
|
+
MAX_TOTAL_EVENTS,
|
|
528
|
+
);
|
|
478
529
|
this.refreshToolsSnapshot();
|
|
479
530
|
this.requestUpdate();
|
|
480
531
|
}
|
|
@@ -484,7 +535,9 @@ export class WebInspectorElement extends LitElement {
|
|
|
484
535
|
return;
|
|
485
536
|
}
|
|
486
537
|
|
|
487
|
-
const messages = this.normalizeAgentMessages(
|
|
538
|
+
const messages = this.normalizeAgentMessages(
|
|
539
|
+
(agent as { messages?: unknown }).messages,
|
|
540
|
+
);
|
|
488
541
|
if (messages) {
|
|
489
542
|
this.agentMessages.set(agent.agentId, messages);
|
|
490
543
|
} else {
|
|
@@ -520,7 +573,9 @@ export class WebInspectorElement extends LitElement {
|
|
|
520
573
|
|
|
521
574
|
const optionsChanged =
|
|
522
575
|
this.contextOptions.length !== nextOptions.length ||
|
|
523
|
-
this.contextOptions.some(
|
|
576
|
+
this.contextOptions.some(
|
|
577
|
+
(option, index) => option.key !== nextOptions[index]?.key,
|
|
578
|
+
);
|
|
524
579
|
|
|
525
580
|
if (optionsChanged) {
|
|
526
581
|
this.contextOptions = nextOptions;
|
|
@@ -528,7 +583,8 @@ export class WebInspectorElement extends LitElement {
|
|
|
528
583
|
|
|
529
584
|
const pendingContext = this.pendingSelectedContext;
|
|
530
585
|
if (pendingContext) {
|
|
531
|
-
const isPendingAvailable =
|
|
586
|
+
const isPendingAvailable =
|
|
587
|
+
pendingContext === "all-agents" || agentIds.has(pendingContext);
|
|
532
588
|
if (isPendingAvailable) {
|
|
533
589
|
if (this.selectedContext !== pendingContext) {
|
|
534
590
|
this.selectedContext = pendingContext;
|
|
@@ -541,7 +597,9 @@ export class WebInspectorElement extends LitElement {
|
|
|
541
597
|
}
|
|
542
598
|
}
|
|
543
599
|
|
|
544
|
-
const hasSelectedContext = nextOptions.some(
|
|
600
|
+
const hasSelectedContext = nextOptions.some(
|
|
601
|
+
(option) => option.key === this.selectedContext,
|
|
602
|
+
);
|
|
545
603
|
|
|
546
604
|
if (!hasSelectedContext && this.pendingSelectedContext === null) {
|
|
547
605
|
// Auto-select "default" agent if it exists, otherwise first agent, otherwise "all-agents"
|
|
@@ -550,7 +608,9 @@ export class WebInspectorElement extends LitElement {
|
|
|
550
608
|
if (agentIds.has("default")) {
|
|
551
609
|
nextSelected = "default";
|
|
552
610
|
} else if (agentIds.size > 0) {
|
|
553
|
-
nextSelected = Array.from(agentIds).sort((a, b) =>
|
|
611
|
+
nextSelected = Array.from(agentIds).sort((a, b) =>
|
|
612
|
+
a.localeCompare(b),
|
|
613
|
+
)[0]!;
|
|
554
614
|
}
|
|
555
615
|
|
|
556
616
|
if (this.selectedContext !== nextSelected) {
|
|
@@ -573,7 +633,10 @@ export class WebInspectorElement extends LitElement {
|
|
|
573
633
|
const query = this.eventFilterText.trim().toLowerCase();
|
|
574
634
|
|
|
575
635
|
return events.filter((event) => {
|
|
576
|
-
if (
|
|
636
|
+
if (
|
|
637
|
+
this.eventTypeFilter !== "all" &&
|
|
638
|
+
event.type !== this.eventTypeFilter
|
|
639
|
+
) {
|
|
577
640
|
return false;
|
|
578
641
|
}
|
|
579
642
|
|
|
@@ -581,7 +644,10 @@ export class WebInspectorElement extends LitElement {
|
|
|
581
644
|
return true;
|
|
582
645
|
}
|
|
583
646
|
|
|
584
|
-
const payloadText = this.stringifyPayload(
|
|
647
|
+
const payloadText = this.stringifyPayload(
|
|
648
|
+
event.payload,
|
|
649
|
+
false,
|
|
650
|
+
).toLowerCase();
|
|
585
651
|
return (
|
|
586
652
|
event.type.toLowerCase().includes(query) ||
|
|
587
653
|
event.agentId.toLowerCase().includes(query) ||
|
|
@@ -604,7 +670,9 @@ export class WebInspectorElement extends LitElement {
|
|
|
604
670
|
return stateEvent.payload;
|
|
605
671
|
}
|
|
606
672
|
|
|
607
|
-
private getLatestMessagesForAgent(
|
|
673
|
+
private getLatestMessagesForAgent(
|
|
674
|
+
agentId: string,
|
|
675
|
+
): InspectorMessage[] | null {
|
|
608
676
|
const messages = this.agentMessages.get(agentId);
|
|
609
677
|
return messages ?? null;
|
|
610
678
|
}
|
|
@@ -616,7 +684,12 @@ export class WebInspectorElement extends LitElement {
|
|
|
616
684
|
}
|
|
617
685
|
|
|
618
686
|
// Check most recent run-related event
|
|
619
|
-
const runEvent = events.find(
|
|
687
|
+
const runEvent = events.find(
|
|
688
|
+
(e) =>
|
|
689
|
+
e.type === "RUN_STARTED" ||
|
|
690
|
+
e.type === "RUN_FINISHED" ||
|
|
691
|
+
e.type === "RUN_ERROR",
|
|
692
|
+
);
|
|
620
693
|
|
|
621
694
|
if (!runEvent) {
|
|
622
695
|
return "idle";
|
|
@@ -629,7 +702,7 @@ export class WebInspectorElement extends LitElement {
|
|
|
629
702
|
if (runEvent.type === "RUN_STARTED") {
|
|
630
703
|
// Check if there's a RUN_FINISHED after this
|
|
631
704
|
const finishedAfter = events.find(
|
|
632
|
-
(e) => e.type === "RUN_FINISHED" && e.timestamp > runEvent.timestamp
|
|
705
|
+
(e) => e.type === "RUN_FINISHED" && e.timestamp > runEvent.timestamp,
|
|
633
706
|
);
|
|
634
707
|
return finishedAfter ? "idle" : "running";
|
|
635
708
|
}
|
|
@@ -637,13 +710,22 @@ export class WebInspectorElement extends LitElement {
|
|
|
637
710
|
return "idle";
|
|
638
711
|
}
|
|
639
712
|
|
|
640
|
-
private getAgentStats(agentId: string): {
|
|
713
|
+
private getAgentStats(agentId: string): {
|
|
714
|
+
totalEvents: number;
|
|
715
|
+
lastActivity: number | null;
|
|
716
|
+
messages: number;
|
|
717
|
+
toolCalls: number;
|
|
718
|
+
errors: number;
|
|
719
|
+
} {
|
|
641
720
|
const events = this.agentEvents.get(agentId) ?? [];
|
|
642
721
|
|
|
643
722
|
const messages = this.agentMessages.get(agentId);
|
|
644
723
|
|
|
645
724
|
const toolCallCount = messages
|
|
646
|
-
? messages.reduce(
|
|
725
|
+
? messages.reduce(
|
|
726
|
+
(count, message) => count + (message.toolCalls?.length ?? 0),
|
|
727
|
+
0,
|
|
728
|
+
)
|
|
647
729
|
: events.filter((e) => e.type === "TOOL_CALL_END").length;
|
|
648
730
|
|
|
649
731
|
const messageCount = messages?.length ?? 0;
|
|
@@ -665,17 +747,29 @@ export class WebInspectorElement extends LitElement {
|
|
|
665
747
|
return html`
|
|
666
748
|
<div class="mt-2 space-y-2">
|
|
667
749
|
${toolCalls.map((call, index) => {
|
|
668
|
-
const functionName =
|
|
669
|
-
|
|
670
|
-
const
|
|
750
|
+
const functionName =
|
|
751
|
+
call.function?.name ?? call.toolName ?? "Unknown function";
|
|
752
|
+
const callId =
|
|
753
|
+
typeof call?.id === "string" ? call.id : `tool-call-${index + 1}`;
|
|
754
|
+
const argsString = this.formatToolCallArguments(
|
|
755
|
+
call.function?.arguments,
|
|
756
|
+
);
|
|
671
757
|
return html`
|
|
672
|
-
<div
|
|
673
|
-
|
|
758
|
+
<div
|
|
759
|
+
class="rounded-md border border-gray-200 bg-gray-50 p-3 text-xs text-gray-700"
|
|
760
|
+
>
|
|
761
|
+
<div
|
|
762
|
+
class="flex flex-wrap items-center justify-between gap-1 font-medium text-gray-900"
|
|
763
|
+
>
|
|
674
764
|
<span>${functionName}</span>
|
|
675
765
|
<span class="text-[10px] text-gray-500">ID: ${callId}</span>
|
|
676
766
|
</div>
|
|
677
767
|
${argsString
|
|
678
|
-
? html`<pre
|
|
768
|
+
? html`<pre
|
|
769
|
+
class="mt-2 overflow-auto rounded bg-white p-2 text-[11px] leading-relaxed text-gray-800"
|
|
770
|
+
>
|
|
771
|
+
${argsString}</pre
|
|
772
|
+
>`
|
|
679
773
|
: nothing}
|
|
680
774
|
</div>
|
|
681
775
|
`;
|
|
@@ -685,11 +779,11 @@ export class WebInspectorElement extends LitElement {
|
|
|
685
779
|
}
|
|
686
780
|
|
|
687
781
|
private formatToolCallArguments(args: unknown): string | null {
|
|
688
|
-
if (args === undefined || args === null || args ===
|
|
782
|
+
if (args === undefined || args === null || args === "") {
|
|
689
783
|
return null;
|
|
690
784
|
}
|
|
691
785
|
|
|
692
|
-
if (typeof args ===
|
|
786
|
+
if (typeof args === "string") {
|
|
693
787
|
try {
|
|
694
788
|
const parsed = JSON.parse(args);
|
|
695
789
|
return JSON.stringify(parsed, null, 2);
|
|
@@ -698,7 +792,7 @@ export class WebInspectorElement extends LitElement {
|
|
|
698
792
|
}
|
|
699
793
|
}
|
|
700
794
|
|
|
701
|
-
if (typeof args ===
|
|
795
|
+
if (typeof args === "object") {
|
|
702
796
|
try {
|
|
703
797
|
return JSON.stringify(args, null, 2);
|
|
704
798
|
} catch {
|
|
@@ -718,13 +812,13 @@ export class WebInspectorElement extends LitElement {
|
|
|
718
812
|
return state.length > 0;
|
|
719
813
|
}
|
|
720
814
|
|
|
721
|
-
if (typeof state ===
|
|
815
|
+
if (typeof state === "object") {
|
|
722
816
|
return Object.keys(state as Record<string, unknown>).length > 0;
|
|
723
817
|
}
|
|
724
818
|
|
|
725
|
-
if (typeof state ===
|
|
819
|
+
if (typeof state === "string") {
|
|
726
820
|
const trimmed = state.trim();
|
|
727
|
-
return trimmed.length > 0 && trimmed !==
|
|
821
|
+
return trimmed.length > 0 && trimmed !== "{}";
|
|
728
822
|
}
|
|
729
823
|
|
|
730
824
|
return true;
|
|
@@ -732,13 +826,13 @@ export class WebInspectorElement extends LitElement {
|
|
|
732
826
|
|
|
733
827
|
private formatStateForDisplay(state: unknown): string {
|
|
734
828
|
if (state === null || state === undefined) {
|
|
735
|
-
return
|
|
829
|
+
return "";
|
|
736
830
|
}
|
|
737
831
|
|
|
738
|
-
if (typeof state ===
|
|
832
|
+
if (typeof state === "string") {
|
|
739
833
|
const trimmed = state.trim();
|
|
740
834
|
if (trimmed.length === 0) {
|
|
741
|
-
return
|
|
835
|
+
return "";
|
|
742
836
|
}
|
|
743
837
|
try {
|
|
744
838
|
const parsed = JSON.parse(trimmed);
|
|
@@ -748,7 +842,7 @@ export class WebInspectorElement extends LitElement {
|
|
|
748
842
|
}
|
|
749
843
|
}
|
|
750
844
|
|
|
751
|
-
if (typeof state ===
|
|
845
|
+
if (typeof state === "object") {
|
|
752
846
|
try {
|
|
753
847
|
return JSON.stringify(state, null, 2);
|
|
754
848
|
} catch {
|
|
@@ -760,7 +854,8 @@ export class WebInspectorElement extends LitElement {
|
|
|
760
854
|
}
|
|
761
855
|
|
|
762
856
|
private getEventBadgeClasses(type: string): string {
|
|
763
|
-
const base =
|
|
857
|
+
const base =
|
|
858
|
+
"font-mono text-[10px] font-medium inline-flex items-center rounded-sm px-1.5 py-0.5 border";
|
|
764
859
|
|
|
765
860
|
if (type.startsWith("RUN_")) {
|
|
766
861
|
return `${base} bg-blue-50 text-blue-700 border-blue-200`;
|
|
@@ -856,7 +951,9 @@ export class WebInspectorElement extends LitElement {
|
|
|
856
951
|
}
|
|
857
952
|
|
|
858
953
|
.inspector-window[data-transitioning="true"] {
|
|
859
|
-
transition:
|
|
954
|
+
transition:
|
|
955
|
+
width 300ms ease,
|
|
956
|
+
height 300ms ease;
|
|
860
957
|
}
|
|
861
958
|
|
|
862
959
|
.inspector-window[data-docked="true"] {
|
|
@@ -901,7 +998,9 @@ export class WebInspectorElement extends LitElement {
|
|
|
901
998
|
box-shadow: 0 4px 10px rgba(0, 0, 0, 0.15);
|
|
902
999
|
opacity: 0;
|
|
903
1000
|
pointer-events: none;
|
|
904
|
-
transition:
|
|
1001
|
+
transition:
|
|
1002
|
+
opacity 120ms ease,
|
|
1003
|
+
transform 120ms ease;
|
|
905
1004
|
z-index: 4000;
|
|
906
1005
|
}
|
|
907
1006
|
|
|
@@ -973,7 +1072,9 @@ export class WebInspectorElement extends LitElement {
|
|
|
973
1072
|
border-radius: 8px;
|
|
974
1073
|
border: 1px solid rgba(148, 163, 184, 0.5);
|
|
975
1074
|
background: rgba(248, 250, 252, 0.9);
|
|
976
|
-
transition:
|
|
1075
|
+
transition:
|
|
1076
|
+
background 120ms ease,
|
|
1077
|
+
color 120ms ease;
|
|
977
1078
|
}
|
|
978
1079
|
|
|
979
1080
|
.announcement-dismiss:hover {
|
|
@@ -1033,7 +1134,10 @@ export class WebInspectorElement extends LitElement {
|
|
|
1033
1134
|
super.connectedCallback();
|
|
1034
1135
|
if (typeof window !== "undefined") {
|
|
1035
1136
|
window.addEventListener("resize", this.handleResize);
|
|
1036
|
-
window.addEventListener(
|
|
1137
|
+
window.addEventListener(
|
|
1138
|
+
"pointerdown",
|
|
1139
|
+
this.handleGlobalPointerDown as EventListener,
|
|
1140
|
+
);
|
|
1037
1141
|
|
|
1038
1142
|
// Load state early (before first render) so menu selection is correct
|
|
1039
1143
|
this.hydrateStateFromStorageEarly();
|
|
@@ -1046,7 +1150,10 @@ export class WebInspectorElement extends LitElement {
|
|
|
1046
1150
|
super.disconnectedCallback();
|
|
1047
1151
|
if (typeof window !== "undefined") {
|
|
1048
1152
|
window.removeEventListener("resize", this.handleResize);
|
|
1049
|
-
window.removeEventListener(
|
|
1153
|
+
window.removeEventListener(
|
|
1154
|
+
"pointerdown",
|
|
1155
|
+
this.handleGlobalPointerDown as EventListener,
|
|
1156
|
+
);
|
|
1050
1157
|
}
|
|
1051
1158
|
this.removeDockStyles(); // Clean up any docking styles
|
|
1052
1159
|
this.detachFromCore();
|
|
@@ -1073,13 +1180,13 @@ export class WebInspectorElement extends LitElement {
|
|
|
1073
1180
|
this.hydrateStateFromStorage();
|
|
1074
1181
|
|
|
1075
1182
|
// Apply docking styles if open and docked (skip transition on initial load)
|
|
1076
|
-
if (this.isOpen && this.dockMode !==
|
|
1183
|
+
if (this.isOpen && this.dockMode !== "floating") {
|
|
1077
1184
|
this.applyDockStyles(true);
|
|
1078
1185
|
}
|
|
1079
1186
|
|
|
1080
1187
|
this.applyAnchorPosition("button");
|
|
1081
1188
|
|
|
1082
|
-
if (this.dockMode ===
|
|
1189
|
+
if (this.dockMode === "floating") {
|
|
1083
1190
|
if (this.hasCustomPosition.window) {
|
|
1084
1191
|
this.applyAnchorPosition("window");
|
|
1085
1192
|
} else {
|
|
@@ -1136,7 +1243,9 @@ export class WebInspectorElement extends LitElement {
|
|
|
1136
1243
|
type="button"
|
|
1137
1244
|
aria-label="Web Inspector"
|
|
1138
1245
|
data-drag-context="button"
|
|
1139
|
-
data-dragging=${this.isDragging && this.pointerContext === "button"
|
|
1246
|
+
data-dragging=${this.isDragging && this.pointerContext === "button"
|
|
1247
|
+
? "true"
|
|
1248
|
+
: "false"}
|
|
1140
1249
|
@pointerdown=${this.handlePointerDown}
|
|
1141
1250
|
@pointermove=${this.handlePointerMove}
|
|
1142
1251
|
@pointerup=${this.handlePointerUp}
|
|
@@ -1144,15 +1253,20 @@ export class WebInspectorElement extends LitElement {
|
|
|
1144
1253
|
@click=${this.handleButtonClick}
|
|
1145
1254
|
>
|
|
1146
1255
|
${this.renderAnnouncementPreview()}
|
|
1147
|
-
<img
|
|
1256
|
+
<img
|
|
1257
|
+
src=${inspectorLogoIconUrl}
|
|
1258
|
+
alt="Inspector logo"
|
|
1259
|
+
class="h-5 w-auto"
|
|
1260
|
+
loading="lazy"
|
|
1261
|
+
/>
|
|
1148
1262
|
</button>
|
|
1149
1263
|
`;
|
|
1150
1264
|
}
|
|
1151
1265
|
|
|
1152
1266
|
private renderWindow() {
|
|
1153
1267
|
const windowState = this.contextState.window;
|
|
1154
|
-
const isDocked = this.dockMode !==
|
|
1155
|
-
const isTransitioning = this.hasAttribute(
|
|
1268
|
+
const isDocked = this.dockMode !== "floating";
|
|
1269
|
+
const isTransitioning = this.hasAttribute("data-transitioning");
|
|
1156
1270
|
|
|
1157
1271
|
const windowStyles = isDocked
|
|
1158
1272
|
? this.getDockedWindowStyles()
|
|
@@ -1164,12 +1278,16 @@ export class WebInspectorElement extends LitElement {
|
|
|
1164
1278
|
};
|
|
1165
1279
|
|
|
1166
1280
|
const hasContextDropdown = this.contextOptions.length > 0;
|
|
1167
|
-
const contextDropdown = hasContextDropdown
|
|
1281
|
+
const contextDropdown = hasContextDropdown
|
|
1282
|
+
? this.renderContextDropdown()
|
|
1283
|
+
: nothing;
|
|
1168
1284
|
const coreStatus = this.getCoreStatusSummary();
|
|
1169
1285
|
const agentSelector = hasContextDropdown
|
|
1170
1286
|
? contextDropdown
|
|
1171
1287
|
: html`
|
|
1172
|
-
<div
|
|
1288
|
+
<div
|
|
1289
|
+
class="flex items-center gap-2 rounded-md border border-dashed border-gray-200 px-2 py-1 text-xs text-gray-400"
|
|
1290
|
+
>
|
|
1173
1291
|
<span>${this.renderIcon("Bot")}</span>
|
|
1174
1292
|
<span class="truncate">No agents available</span>
|
|
1175
1293
|
</div>
|
|
@@ -1195,9 +1313,15 @@ export class WebInspectorElement extends LitElement {
|
|
|
1195
1313
|
></div>
|
|
1196
1314
|
`
|
|
1197
1315
|
: nothing}
|
|
1198
|
-
<div
|
|
1316
|
+
<div
|
|
1317
|
+
class="flex flex-1 flex-col overflow-hidden bg-white text-gray-800"
|
|
1318
|
+
>
|
|
1199
1319
|
<div
|
|
1200
|
-
class="drag-handle relative z-30 flex flex-col border-b border-gray-200 bg-white/95 backdrop-blur-sm ${isDocked
|
|
1320
|
+
class="drag-handle relative z-30 flex flex-col border-b border-gray-200 bg-white/95 backdrop-blur-sm ${isDocked
|
|
1321
|
+
? ""
|
|
1322
|
+
: this.isDragging && this.pointerContext === "window"
|
|
1323
|
+
? "cursor-grabbing"
|
|
1324
|
+
: "cursor-grab"}"
|
|
1201
1325
|
data-drag-context="window"
|
|
1202
1326
|
@pointerdown=${isDocked ? undefined : this.handlePointerDown}
|
|
1203
1327
|
@pointermove=${isDocked ? undefined : this.handlePointerMove}
|
|
@@ -1206,12 +1330,15 @@ export class WebInspectorElement extends LitElement {
|
|
|
1206
1330
|
>
|
|
1207
1331
|
<div class="flex flex-wrap items-center gap-3 px-4 py-3">
|
|
1208
1332
|
<div class="flex items-center min-w-0">
|
|
1209
|
-
<img
|
|
1333
|
+
<img
|
|
1334
|
+
src=${inspectorLogoUrl}
|
|
1335
|
+
alt="Inspector logo"
|
|
1336
|
+
class="h-6 w-auto"
|
|
1337
|
+
loading="lazy"
|
|
1338
|
+
/>
|
|
1210
1339
|
</div>
|
|
1211
1340
|
<div class="ml-auto flex min-w-0 items-center gap-2">
|
|
1212
|
-
<div class="min-w-[160px] max-w-xs">
|
|
1213
|
-
${agentSelector}
|
|
1214
|
-
</div>
|
|
1341
|
+
<div class="min-w-[160px] max-w-xs">${agentSelector}</div>
|
|
1215
1342
|
<div class="flex items-center gap-1">
|
|
1216
1343
|
${this.renderDockControls()}
|
|
1217
1344
|
<button
|
|
@@ -1226,12 +1353,16 @@ export class WebInspectorElement extends LitElement {
|
|
|
1226
1353
|
</div>
|
|
1227
1354
|
</div>
|
|
1228
1355
|
</div>
|
|
1229
|
-
<div
|
|
1356
|
+
<div
|
|
1357
|
+
class="flex flex-wrap items-center gap-2 border-t border-gray-100 px-3 py-2 text-xs"
|
|
1358
|
+
>
|
|
1230
1359
|
${this.menuItems.map(({ key, label, icon }) => {
|
|
1231
1360
|
const isSelected = this.selectedMenu === key;
|
|
1232
1361
|
const tabClasses = [
|
|
1233
1362
|
"inline-flex items-center gap-2 rounded-md px-3 py-2 transition focus-visible:outline focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-gray-300",
|
|
1234
|
-
isSelected
|
|
1363
|
+
isSelected
|
|
1364
|
+
? "bg-gray-900 text-white shadow-sm"
|
|
1365
|
+
: "text-gray-600 hover:bg-gray-100 hover:text-gray-900",
|
|
1235
1366
|
].join(" ");
|
|
1236
1367
|
|
|
1237
1368
|
return html`
|
|
@@ -1241,7 +1372,9 @@ export class WebInspectorElement extends LitElement {
|
|
|
1241
1372
|
aria-pressed=${isSelected}
|
|
1242
1373
|
@click=${() => this.handleMenuSelect(key)}
|
|
1243
1374
|
>
|
|
1244
|
-
<span
|
|
1375
|
+
<span
|
|
1376
|
+
class="text-gray-400 ${isSelected ? "text-white" : ""}"
|
|
1377
|
+
>
|
|
1245
1378
|
${this.renderIcon(icon)}
|
|
1246
1379
|
</span>
|
|
1247
1380
|
<span>${label}</span>
|
|
@@ -1250,27 +1383,30 @@ export class WebInspectorElement extends LitElement {
|
|
|
1250
1383
|
})}
|
|
1251
1384
|
</div>
|
|
1252
1385
|
</div>
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
<div
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1386
|
+
<div class="flex flex-1 flex-col overflow-hidden">
|
|
1387
|
+
<div class="flex-1 overflow-auto">
|
|
1388
|
+
${this.renderAnnouncementPanel()}
|
|
1389
|
+
${this.renderCoreWarningBanner()} ${this.renderMainContent()}
|
|
1390
|
+
<slot></slot>
|
|
1391
|
+
</div>
|
|
1392
|
+
<div class="border-t border-gray-200 bg-gray-50 px-4 py-2">
|
|
1393
|
+
<div
|
|
1394
|
+
class="flex items-center gap-2 rounded-md px-3 py-2 text-xs ${coreStatus.tone} w-full overflow-hidden my-1"
|
|
1395
|
+
title=${coreStatus.description}
|
|
1396
|
+
>
|
|
1397
|
+
<span
|
|
1398
|
+
class="flex h-6 w-6 items-center justify-center rounded bg-white/60"
|
|
1399
|
+
>
|
|
1400
|
+
${this.renderIcon("Activity")}
|
|
1401
|
+
</span>
|
|
1402
|
+
<span class="font-medium">${coreStatus.label}</span>
|
|
1403
|
+
<span class="truncate text-[11px] opacity-80"
|
|
1404
|
+
>${coreStatus.description}</span
|
|
1264
1405
|
>
|
|
1265
|
-
<span class="flex h-6 w-6 items-center justify-center rounded bg-white/60">
|
|
1266
|
-
${this.renderIcon("Activity")}
|
|
1267
|
-
</span>
|
|
1268
|
-
<span class="font-medium">${coreStatus.label}</span>
|
|
1269
|
-
<span class="truncate text-[11px] opacity-80">${coreStatus.description}</span>
|
|
1270
|
-
</div>
|
|
1271
1406
|
</div>
|
|
1272
1407
|
</div>
|
|
1273
1408
|
</div>
|
|
1409
|
+
</div>
|
|
1274
1410
|
<div
|
|
1275
1411
|
class="resize-handle pointer-events-auto absolute bottom-1 right-1 flex h-5 w-5 cursor-nwse-resize items-center justify-center text-gray-400 transition hover:text-gray-600"
|
|
1276
1412
|
role="presentation"
|
|
@@ -1318,7 +1454,9 @@ export class WebInspectorElement extends LitElement {
|
|
|
1318
1454
|
|
|
1319
1455
|
// Restore selected menu
|
|
1320
1456
|
if (typeof persisted.selectedMenu === "string") {
|
|
1321
|
-
const validMenu = this.menuItems.find(
|
|
1457
|
+
const validMenu = this.menuItems.find(
|
|
1458
|
+
(item) => item.key === persisted.selectedMenu,
|
|
1459
|
+
);
|
|
1322
1460
|
if (validMenu) {
|
|
1323
1461
|
this.selectedMenu = validMenu.key;
|
|
1324
1462
|
}
|
|
@@ -1368,7 +1506,9 @@ export class WebInspectorElement extends LitElement {
|
|
|
1368
1506
|
|
|
1369
1507
|
if (isValidSize(persistedWindow.size)) {
|
|
1370
1508
|
// Now clampWindowSize will use the correct minimum based on dockMode
|
|
1371
|
-
this.contextState.window.size = this.clampWindowSize(
|
|
1509
|
+
this.contextState.window.size = this.clampWindowSize(
|
|
1510
|
+
persistedWindow.size,
|
|
1511
|
+
);
|
|
1372
1512
|
}
|
|
1373
1513
|
|
|
1374
1514
|
if (typeof persistedWindow.hasCustomPosition === "boolean") {
|
|
@@ -1388,7 +1528,7 @@ export class WebInspectorElement extends LitElement {
|
|
|
1388
1528
|
|
|
1389
1529
|
private handlePointerDown = (event: PointerEvent) => {
|
|
1390
1530
|
// Don't allow dragging when docked
|
|
1391
|
-
if (this.dockMode !==
|
|
1531
|
+
if (this.dockMode !== "floating" && this.isOpen) {
|
|
1392
1532
|
return;
|
|
1393
1533
|
}
|
|
1394
1534
|
|
|
@@ -1421,11 +1561,18 @@ export class WebInspectorElement extends LitElement {
|
|
|
1421
1561
|
};
|
|
1422
1562
|
|
|
1423
1563
|
private handlePointerMove = (event: PointerEvent) => {
|
|
1424
|
-
if (
|
|
1564
|
+
if (
|
|
1565
|
+
this.pointerId !== event.pointerId ||
|
|
1566
|
+
!this.dragStart ||
|
|
1567
|
+
!this.pointerContext
|
|
1568
|
+
) {
|
|
1425
1569
|
return;
|
|
1426
1570
|
}
|
|
1427
1571
|
|
|
1428
|
-
const distance = Math.hypot(
|
|
1572
|
+
const distance = Math.hypot(
|
|
1573
|
+
event.clientX - this.dragStart.x,
|
|
1574
|
+
event.clientY - this.dragStart.y,
|
|
1575
|
+
);
|
|
1429
1576
|
if (!this.isDragging && distance < DRAG_THRESHOLD) {
|
|
1430
1577
|
return;
|
|
1431
1578
|
}
|
|
@@ -1471,7 +1618,11 @@ export class WebInspectorElement extends LitElement {
|
|
|
1471
1618
|
this.ignoreNextButtonClick = true;
|
|
1472
1619
|
}
|
|
1473
1620
|
}
|
|
1474
|
-
} else if (
|
|
1621
|
+
} else if (
|
|
1622
|
+
context === "button" &&
|
|
1623
|
+
!this.isOpen &&
|
|
1624
|
+
!this.draggedDuringInteraction
|
|
1625
|
+
) {
|
|
1475
1626
|
this.openInspector();
|
|
1476
1627
|
}
|
|
1477
1628
|
|
|
@@ -1529,8 +1680,8 @@ export class WebInspectorElement extends LitElement {
|
|
|
1529
1680
|
this.resizeInitialSize = { ...this.contextState.window.size };
|
|
1530
1681
|
|
|
1531
1682
|
// Remove transition from body during resize to prevent lag
|
|
1532
|
-
if (document.body && this.dockMode !==
|
|
1533
|
-
document.body.style.transition =
|
|
1683
|
+
if (document.body && this.dockMode !== "floating") {
|
|
1684
|
+
document.body.style.transition = "";
|
|
1534
1685
|
}
|
|
1535
1686
|
|
|
1536
1687
|
const target = event.currentTarget as HTMLElement | null;
|
|
@@ -1538,7 +1689,12 @@ export class WebInspectorElement extends LitElement {
|
|
|
1538
1689
|
};
|
|
1539
1690
|
|
|
1540
1691
|
private handleResizePointerMove = (event: PointerEvent) => {
|
|
1541
|
-
if (
|
|
1692
|
+
if (
|
|
1693
|
+
!this.isResizing ||
|
|
1694
|
+
this.resizePointerId !== event.pointerId ||
|
|
1695
|
+
!this.resizeStart ||
|
|
1696
|
+
!this.resizeInitialSize
|
|
1697
|
+
) {
|
|
1542
1698
|
return;
|
|
1543
1699
|
}
|
|
1544
1700
|
|
|
@@ -1549,7 +1705,7 @@ export class WebInspectorElement extends LitElement {
|
|
|
1549
1705
|
const state = this.contextState.window;
|
|
1550
1706
|
|
|
1551
1707
|
// For docked states, only resize in the appropriate dimension
|
|
1552
|
-
if (this.dockMode ===
|
|
1708
|
+
if (this.dockMode === "docked-left") {
|
|
1553
1709
|
// Only resize width for left dock
|
|
1554
1710
|
state.size = this.clampWindowSize({
|
|
1555
1711
|
width: this.resizeInitialSize.width + deltaX,
|
|
@@ -1584,7 +1740,7 @@ export class WebInspectorElement extends LitElement {
|
|
|
1584
1740
|
}
|
|
1585
1741
|
|
|
1586
1742
|
// Only update anchor position for floating mode
|
|
1587
|
-
if (this.dockMode ===
|
|
1743
|
+
if (this.dockMode === "floating") {
|
|
1588
1744
|
this.updateAnchorFromPosition("window");
|
|
1589
1745
|
this.applyAnchorPosition("window");
|
|
1590
1746
|
}
|
|
@@ -1605,7 +1761,7 @@ export class WebInspectorElement extends LitElement {
|
|
|
1605
1761
|
}
|
|
1606
1762
|
|
|
1607
1763
|
// Only update anchor position for floating mode
|
|
1608
|
-
if (this.dockMode ===
|
|
1764
|
+
if (this.dockMode === "floating") {
|
|
1609
1765
|
this.updateAnchorFromPosition("window");
|
|
1610
1766
|
this.applyAnchorPosition("window");
|
|
1611
1767
|
}
|
|
@@ -1630,12 +1786,16 @@ export class WebInspectorElement extends LitElement {
|
|
|
1630
1786
|
};
|
|
1631
1787
|
|
|
1632
1788
|
private measureContext(context: ContextKey): void {
|
|
1633
|
-
const selector =
|
|
1634
|
-
|
|
1789
|
+
const selector =
|
|
1790
|
+
context === "window" ? ".inspector-window" : ".console-button";
|
|
1791
|
+
const element = this.renderRoot?.querySelector(
|
|
1792
|
+
selector,
|
|
1793
|
+
) as HTMLElement | null;
|
|
1635
1794
|
if (!element) {
|
|
1636
1795
|
return;
|
|
1637
1796
|
}
|
|
1638
|
-
const fallback =
|
|
1797
|
+
const fallback =
|
|
1798
|
+
context === "window" ? DEFAULT_WINDOW_SIZE : DEFAULT_BUTTON_SIZE;
|
|
1639
1799
|
updateSizeFromElement(this.contextState[context], element, fallback);
|
|
1640
1800
|
}
|
|
1641
1801
|
|
|
@@ -1667,18 +1827,30 @@ export class WebInspectorElement extends LitElement {
|
|
|
1667
1827
|
|
|
1668
1828
|
const viewport = this.getViewportSize();
|
|
1669
1829
|
keepPositionWithinViewport(this.contextState.window, viewport, EDGE_MARGIN);
|
|
1670
|
-
updateAnchorFromPositionHelper(
|
|
1830
|
+
updateAnchorFromPositionHelper(
|
|
1831
|
+
this.contextState.window,
|
|
1832
|
+
viewport,
|
|
1833
|
+
EDGE_MARGIN,
|
|
1834
|
+
);
|
|
1671
1835
|
this.updateHostTransform("window");
|
|
1672
1836
|
this.persistState();
|
|
1673
1837
|
}
|
|
1674
1838
|
|
|
1675
|
-
private constrainToViewport(
|
|
1839
|
+
private constrainToViewport(
|
|
1840
|
+
position: Position,
|
|
1841
|
+
context: ContextKey,
|
|
1842
|
+
): Position {
|
|
1676
1843
|
if (typeof window === "undefined") {
|
|
1677
1844
|
return position;
|
|
1678
1845
|
}
|
|
1679
1846
|
|
|
1680
1847
|
const viewport = this.getViewportSize();
|
|
1681
|
-
return constrainToViewport(
|
|
1848
|
+
return constrainToViewport(
|
|
1849
|
+
this.contextState[context],
|
|
1850
|
+
position,
|
|
1851
|
+
viewport,
|
|
1852
|
+
EDGE_MARGIN,
|
|
1853
|
+
);
|
|
1682
1854
|
}
|
|
1683
1855
|
|
|
1684
1856
|
private keepPositionWithinViewport(context: ContextKey): void {
|
|
@@ -1687,7 +1859,11 @@ export class WebInspectorElement extends LitElement {
|
|
|
1687
1859
|
}
|
|
1688
1860
|
|
|
1689
1861
|
const viewport = this.getViewportSize();
|
|
1690
|
-
keepPositionWithinViewport(
|
|
1862
|
+
keepPositionWithinViewport(
|
|
1863
|
+
this.contextState[context],
|
|
1864
|
+
viewport,
|
|
1865
|
+
EDGE_MARGIN,
|
|
1866
|
+
);
|
|
1691
1867
|
}
|
|
1692
1868
|
|
|
1693
1869
|
private getViewportSize(): Size {
|
|
@@ -1725,7 +1901,10 @@ export class WebInspectorElement extends LitElement {
|
|
|
1725
1901
|
|
|
1726
1902
|
private clampWindowSize(size: Size): Size {
|
|
1727
1903
|
// Use smaller minimum width when docked left
|
|
1728
|
-
const minWidth =
|
|
1904
|
+
const minWidth =
|
|
1905
|
+
this.dockMode === "docked-left"
|
|
1906
|
+
? MIN_WINDOW_WIDTH_DOCKED_LEFT
|
|
1907
|
+
: MIN_WINDOW_WIDTH;
|
|
1729
1908
|
|
|
1730
1909
|
if (typeof window === "undefined") {
|
|
1731
1910
|
return {
|
|
@@ -1735,7 +1914,13 @@ export class WebInspectorElement extends LitElement {
|
|
|
1735
1914
|
}
|
|
1736
1915
|
|
|
1737
1916
|
const viewport = this.getViewportSize();
|
|
1738
|
-
return clampSizeToViewport(
|
|
1917
|
+
return clampSizeToViewport(
|
|
1918
|
+
size,
|
|
1919
|
+
viewport,
|
|
1920
|
+
EDGE_MARGIN,
|
|
1921
|
+
minWidth,
|
|
1922
|
+
MIN_WINDOW_HEIGHT,
|
|
1923
|
+
);
|
|
1739
1924
|
}
|
|
1740
1925
|
|
|
1741
1926
|
private setDockMode(mode: DockMode): void {
|
|
@@ -1751,9 +1936,9 @@ export class WebInspectorElement extends LitElement {
|
|
|
1751
1936
|
|
|
1752
1937
|
this.dockMode = mode;
|
|
1753
1938
|
|
|
1754
|
-
if (mode !==
|
|
1939
|
+
if (mode !== "floating") {
|
|
1755
1940
|
// For docking, set the target size immediately so body margins are correct
|
|
1756
|
-
if (mode ===
|
|
1941
|
+
if (mode === "docked-left") {
|
|
1757
1942
|
this.contextState.window.size.width = DOCKED_LEFT_WIDTH;
|
|
1758
1943
|
}
|
|
1759
1944
|
|
|
@@ -1762,29 +1947,29 @@ export class WebInspectorElement extends LitElement {
|
|
|
1762
1947
|
} else {
|
|
1763
1948
|
// When floating, set size first then center
|
|
1764
1949
|
this.contextState.window.size = { ...DEFAULT_WINDOW_SIZE };
|
|
1765
|
-
this.centerContext(
|
|
1950
|
+
this.centerContext("window");
|
|
1766
1951
|
}
|
|
1767
1952
|
|
|
1768
1953
|
this.persistState();
|
|
1769
1954
|
this.requestUpdate();
|
|
1770
|
-
this.updateHostTransform(
|
|
1955
|
+
this.updateHostTransform("window");
|
|
1771
1956
|
}
|
|
1772
1957
|
|
|
1773
1958
|
private startHostTransition(duration = 300): void {
|
|
1774
|
-
this.setAttribute(
|
|
1959
|
+
this.setAttribute("data-transitioning", "true");
|
|
1775
1960
|
|
|
1776
1961
|
if (this.transitionTimeoutId !== null) {
|
|
1777
1962
|
clearTimeout(this.transitionTimeoutId);
|
|
1778
1963
|
}
|
|
1779
1964
|
|
|
1780
1965
|
this.transitionTimeoutId = setTimeout(() => {
|
|
1781
|
-
this.removeAttribute(
|
|
1966
|
+
this.removeAttribute("data-transitioning");
|
|
1782
1967
|
this.transitionTimeoutId = null;
|
|
1783
1968
|
}, duration);
|
|
1784
1969
|
}
|
|
1785
1970
|
|
|
1786
1971
|
private applyDockStyles(skipTransition = false): void {
|
|
1787
|
-
if (typeof document ===
|
|
1972
|
+
if (typeof document === "undefined" || !document.body) {
|
|
1788
1973
|
return;
|
|
1789
1974
|
}
|
|
1790
1975
|
|
|
@@ -1797,11 +1982,11 @@ export class WebInspectorElement extends LitElement {
|
|
|
1797
1982
|
|
|
1798
1983
|
// Apply transition to body for smooth animation (only when docking, not during resize or initial load)
|
|
1799
1984
|
if (!this.isResizing && !skipTransition) {
|
|
1800
|
-
document.body.style.transition =
|
|
1985
|
+
document.body.style.transition = "margin 300ms ease";
|
|
1801
1986
|
}
|
|
1802
1987
|
|
|
1803
1988
|
// Apply body margins with the actual window sizes
|
|
1804
|
-
if (this.dockMode ===
|
|
1989
|
+
if (this.dockMode === "docked-left") {
|
|
1805
1990
|
document.body.style.marginLeft = `${this.contextState.window.size.width}px`;
|
|
1806
1991
|
}
|
|
1807
1992
|
|
|
@@ -1809,20 +1994,20 @@ export class WebInspectorElement extends LitElement {
|
|
|
1809
1994
|
if (!this.isResizing && !skipTransition) {
|
|
1810
1995
|
setTimeout(() => {
|
|
1811
1996
|
if (document.body) {
|
|
1812
|
-
document.body.style.transition =
|
|
1997
|
+
document.body.style.transition = "";
|
|
1813
1998
|
}
|
|
1814
1999
|
}, 300);
|
|
1815
2000
|
}
|
|
1816
2001
|
}
|
|
1817
2002
|
|
|
1818
2003
|
private removeDockStyles(): void {
|
|
1819
|
-
if (typeof document ===
|
|
2004
|
+
if (typeof document === "undefined" || !document.body) {
|
|
1820
2005
|
return;
|
|
1821
2006
|
}
|
|
1822
2007
|
|
|
1823
2008
|
// Only add transition if not resizing
|
|
1824
2009
|
if (!this.isResizing) {
|
|
1825
|
-
document.body.style.transition =
|
|
2010
|
+
document.body.style.transition = "margin 300ms ease";
|
|
1826
2011
|
}
|
|
1827
2012
|
|
|
1828
2013
|
// Restore original margins if saved
|
|
@@ -1832,14 +2017,14 @@ export class WebInspectorElement extends LitElement {
|
|
|
1832
2017
|
this.previousBodyMargins = null;
|
|
1833
2018
|
} else {
|
|
1834
2019
|
// Reset to default if no previous values
|
|
1835
|
-
document.body.style.marginLeft =
|
|
1836
|
-
document.body.style.marginBottom =
|
|
2020
|
+
document.body.style.marginLeft = "";
|
|
2021
|
+
document.body.style.marginBottom = "";
|
|
1837
2022
|
}
|
|
1838
2023
|
|
|
1839
2024
|
// Clean up transition after animation completes
|
|
1840
2025
|
setTimeout(() => {
|
|
1841
2026
|
if (document.body) {
|
|
1842
|
-
document.body.style.transition =
|
|
2027
|
+
document.body.style.transition = "";
|
|
1843
2028
|
}
|
|
1844
2029
|
}, 300);
|
|
1845
2030
|
}
|
|
@@ -1850,7 +2035,7 @@ export class WebInspectorElement extends LitElement {
|
|
|
1850
2035
|
}
|
|
1851
2036
|
|
|
1852
2037
|
// For docked states, CSS handles positioning with fixed positioning
|
|
1853
|
-
if (this.isOpen && this.dockMode ===
|
|
2038
|
+
if (this.isOpen && this.dockMode === "docked-left") {
|
|
1854
2039
|
this.style.transform = `translate3d(0, 0, 0)`;
|
|
1855
2040
|
} else {
|
|
1856
2041
|
const { position } = this.contextState[context];
|
|
@@ -1870,7 +2055,11 @@ export class WebInspectorElement extends LitElement {
|
|
|
1870
2055
|
return;
|
|
1871
2056
|
}
|
|
1872
2057
|
const viewport = this.getViewportSize();
|
|
1873
|
-
updateAnchorFromPositionHelper(
|
|
2058
|
+
updateAnchorFromPositionHelper(
|
|
2059
|
+
this.contextState[context],
|
|
2060
|
+
viewport,
|
|
2061
|
+
EDGE_MARGIN,
|
|
2062
|
+
);
|
|
1874
2063
|
}
|
|
1875
2064
|
|
|
1876
2065
|
private snapButtonToCorner(): void {
|
|
@@ -1885,8 +2074,10 @@ export class WebInspectorElement extends LitElement {
|
|
|
1885
2074
|
const centerX = state.position.x + state.size.width / 2;
|
|
1886
2075
|
const centerY = state.position.y + state.size.height / 2;
|
|
1887
2076
|
|
|
1888
|
-
const horizontal: Anchor[
|
|
1889
|
-
|
|
2077
|
+
const horizontal: Anchor["horizontal"] =
|
|
2078
|
+
centerX < viewport.width / 2 ? "left" : "right";
|
|
2079
|
+
const vertical: Anchor["vertical"] =
|
|
2080
|
+
centerY < viewport.height / 2 ? "top" : "bottom";
|
|
1890
2081
|
|
|
1891
2082
|
// Set anchor to nearest corner
|
|
1892
2083
|
state.anchor = { horizontal, vertical };
|
|
@@ -1896,7 +2087,7 @@ export class WebInspectorElement extends LitElement {
|
|
|
1896
2087
|
|
|
1897
2088
|
// Apply the anchor position to snap to corner
|
|
1898
2089
|
this.startHostTransition();
|
|
1899
|
-
this.applyAnchorPosition(
|
|
2090
|
+
this.applyAnchorPosition("button");
|
|
1900
2091
|
}
|
|
1901
2092
|
|
|
1902
2093
|
private applyAnchorPosition(context: ContextKey): void {
|
|
@@ -1904,7 +2095,11 @@ export class WebInspectorElement extends LitElement {
|
|
|
1904
2095
|
return;
|
|
1905
2096
|
}
|
|
1906
2097
|
const viewport = this.getViewportSize();
|
|
1907
|
-
applyAnchorPositionHelper(
|
|
2098
|
+
applyAnchorPositionHelper(
|
|
2099
|
+
this.contextState[context],
|
|
2100
|
+
viewport,
|
|
2101
|
+
EDGE_MARGIN,
|
|
2102
|
+
);
|
|
1908
2103
|
this.updateHostTransform(context);
|
|
1909
2104
|
this.persistState();
|
|
1910
2105
|
}
|
|
@@ -1937,7 +2132,7 @@ export class WebInspectorElement extends LitElement {
|
|
|
1937
2132
|
this.persistState(); // Save the open state
|
|
1938
2133
|
|
|
1939
2134
|
// Apply docking styles if in docked mode
|
|
1940
|
-
if (this.dockMode !==
|
|
2135
|
+
if (this.dockMode !== "floating") {
|
|
1941
2136
|
this.applyDockStyles();
|
|
1942
2137
|
}
|
|
1943
2138
|
|
|
@@ -1945,7 +2140,7 @@ export class WebInspectorElement extends LitElement {
|
|
|
1945
2140
|
this.requestUpdate();
|
|
1946
2141
|
void this.updateComplete.then(() => {
|
|
1947
2142
|
this.measureContext("window");
|
|
1948
|
-
if (this.dockMode ===
|
|
2143
|
+
if (this.dockMode === "floating") {
|
|
1949
2144
|
if (this.hasCustomPosition.window) {
|
|
1950
2145
|
this.applyAnchorPosition("window");
|
|
1951
2146
|
} else {
|
|
@@ -1955,7 +2150,6 @@ export class WebInspectorElement extends LitElement {
|
|
|
1955
2150
|
// Update transform for docked position
|
|
1956
2151
|
this.updateHostTransform("window");
|
|
1957
2152
|
}
|
|
1958
|
-
|
|
1959
2153
|
});
|
|
1960
2154
|
}
|
|
1961
2155
|
|
|
@@ -1967,7 +2161,7 @@ export class WebInspectorElement extends LitElement {
|
|
|
1967
2161
|
this.isOpen = false;
|
|
1968
2162
|
|
|
1969
2163
|
// Remove docking styles when closing
|
|
1970
|
-
if (this.dockMode !==
|
|
2164
|
+
if (this.dockMode !== "floating") {
|
|
1971
2165
|
this.removeDockStyles();
|
|
1972
2166
|
}
|
|
1973
2167
|
|
|
@@ -2005,7 +2199,7 @@ export class WebInspectorElement extends LitElement {
|
|
|
2005
2199
|
}
|
|
2006
2200
|
|
|
2007
2201
|
private renderDockControls() {
|
|
2008
|
-
if (this.dockMode ===
|
|
2202
|
+
if (this.dockMode === "floating") {
|
|
2009
2203
|
// Show dock left button
|
|
2010
2204
|
return html`
|
|
2011
2205
|
<button
|
|
@@ -2013,7 +2207,7 @@ export class WebInspectorElement extends LitElement {
|
|
|
2013
2207
|
type="button"
|
|
2014
2208
|
aria-label="Dock to left"
|
|
2015
2209
|
title="Dock Left"
|
|
2016
|
-
@click=${() => this.handleDockClick(
|
|
2210
|
+
@click=${() => this.handleDockClick("docked-left")}
|
|
2017
2211
|
>
|
|
2018
2212
|
${this.renderIcon("PanelLeft")}
|
|
2019
2213
|
</button>
|
|
@@ -2026,7 +2220,7 @@ export class WebInspectorElement extends LitElement {
|
|
|
2026
2220
|
type="button"
|
|
2027
2221
|
aria-label="Float window"
|
|
2028
2222
|
title="Float"
|
|
2029
|
-
@click=${() => this.handleDockClick(
|
|
2223
|
+
@click=${() => this.handleDockClick("floating")}
|
|
2030
2224
|
>
|
|
2031
2225
|
${this.renderIcon("Maximize2")}
|
|
2032
2226
|
</button>
|
|
@@ -2035,16 +2229,16 @@ export class WebInspectorElement extends LitElement {
|
|
|
2035
2229
|
}
|
|
2036
2230
|
|
|
2037
2231
|
private getDockedWindowStyles(): Record<string, string> {
|
|
2038
|
-
if (this.dockMode ===
|
|
2232
|
+
if (this.dockMode === "docked-left") {
|
|
2039
2233
|
return {
|
|
2040
|
-
position:
|
|
2041
|
-
top:
|
|
2042
|
-
left:
|
|
2043
|
-
bottom:
|
|
2234
|
+
position: "fixed",
|
|
2235
|
+
top: "0",
|
|
2236
|
+
left: "0",
|
|
2237
|
+
bottom: "0",
|
|
2044
2238
|
width: `${Math.round(this.contextState.window.size.width)}px`,
|
|
2045
|
-
height:
|
|
2239
|
+
height: "100vh",
|
|
2046
2240
|
minWidth: `${MIN_WINDOW_WIDTH_DOCKED_LEFT}px`,
|
|
2047
|
-
borderRadius:
|
|
2241
|
+
borderRadius: "0",
|
|
2048
2242
|
};
|
|
2049
2243
|
}
|
|
2050
2244
|
// Default to floating styles
|
|
@@ -2060,19 +2254,37 @@ export class WebInspectorElement extends LitElement {
|
|
|
2060
2254
|
this.setDockMode(mode);
|
|
2061
2255
|
}
|
|
2062
2256
|
|
|
2063
|
-
private serializeAttributes(
|
|
2257
|
+
private serializeAttributes(
|
|
2258
|
+
attributes: Record<string, string | number | undefined>,
|
|
2259
|
+
): string {
|
|
2064
2260
|
return Object.entries(attributes)
|
|
2065
|
-
.filter(
|
|
2066
|
-
|
|
2261
|
+
.filter(
|
|
2262
|
+
([key, value]) =>
|
|
2263
|
+
key !== "key" &&
|
|
2264
|
+
value !== undefined &&
|
|
2265
|
+
value !== null &&
|
|
2266
|
+
value !== "",
|
|
2267
|
+
)
|
|
2268
|
+
.map(
|
|
2269
|
+
([key, value]) => `${key}="${String(value).replace(/"/g, """)}"`,
|
|
2270
|
+
)
|
|
2067
2271
|
.join(" ");
|
|
2068
2272
|
}
|
|
2069
2273
|
|
|
2070
|
-
private sanitizeForLogging(
|
|
2274
|
+
private sanitizeForLogging(
|
|
2275
|
+
value: unknown,
|
|
2276
|
+
depth = 0,
|
|
2277
|
+
seen = new WeakSet<object>(),
|
|
2278
|
+
): SanitizedValue {
|
|
2071
2279
|
if (value === undefined) {
|
|
2072
2280
|
return "[undefined]";
|
|
2073
2281
|
}
|
|
2074
2282
|
|
|
2075
|
-
if (
|
|
2283
|
+
if (
|
|
2284
|
+
value === null ||
|
|
2285
|
+
typeof value === "number" ||
|
|
2286
|
+
typeof value === "boolean"
|
|
2287
|
+
) {
|
|
2076
2288
|
return value;
|
|
2077
2289
|
}
|
|
2078
2290
|
|
|
@@ -2080,7 +2292,11 @@ export class WebInspectorElement extends LitElement {
|
|
|
2080
2292
|
return value;
|
|
2081
2293
|
}
|
|
2082
2294
|
|
|
2083
|
-
if (
|
|
2295
|
+
if (
|
|
2296
|
+
typeof value === "bigint" ||
|
|
2297
|
+
typeof value === "symbol" ||
|
|
2298
|
+
typeof value === "function"
|
|
2299
|
+
) {
|
|
2084
2300
|
return String(value);
|
|
2085
2301
|
}
|
|
2086
2302
|
|
|
@@ -2092,7 +2308,9 @@ export class WebInspectorElement extends LitElement {
|
|
|
2092
2308
|
if (depth >= 4) {
|
|
2093
2309
|
return "[Truncated depth]" as SanitizedValue;
|
|
2094
2310
|
}
|
|
2095
|
-
return value.map((item) =>
|
|
2311
|
+
return value.map((item) =>
|
|
2312
|
+
this.sanitizeForLogging(item, depth + 1, seen),
|
|
2313
|
+
);
|
|
2096
2314
|
}
|
|
2097
2315
|
|
|
2098
2316
|
if (typeof value === "object") {
|
|
@@ -2106,7 +2324,9 @@ export class WebInspectorElement extends LitElement {
|
|
|
2106
2324
|
}
|
|
2107
2325
|
|
|
2108
2326
|
const result: Record<string, SanitizedValue> = {};
|
|
2109
|
-
for (const [key, entry] of Object.entries(
|
|
2327
|
+
for (const [key, entry] of Object.entries(
|
|
2328
|
+
value as Record<string, unknown>,
|
|
2329
|
+
)) {
|
|
2110
2330
|
result[key] = this.sanitizeForLogging(entry, depth + 1, seen);
|
|
2111
2331
|
}
|
|
2112
2332
|
return result;
|
|
@@ -2115,10 +2335,14 @@ export class WebInspectorElement extends LitElement {
|
|
|
2115
2335
|
return String(value);
|
|
2116
2336
|
}
|
|
2117
2337
|
|
|
2118
|
-
private normalizeEventPayload(
|
|
2338
|
+
private normalizeEventPayload(
|
|
2339
|
+
_type: InspectorAgentEventType,
|
|
2340
|
+
payload: unknown,
|
|
2341
|
+
): SanitizedValue {
|
|
2119
2342
|
if (payload && typeof payload === "object" && "event" in payload) {
|
|
2120
2343
|
const { event, ...rest } = payload as Record<string, unknown>;
|
|
2121
|
-
const cleaned =
|
|
2344
|
+
const cleaned =
|
|
2345
|
+
Object.keys(rest).length === 0 ? event : { event, ...rest };
|
|
2122
2346
|
return this.sanitizeForLogging(cleaned);
|
|
2123
2347
|
}
|
|
2124
2348
|
|
|
@@ -2130,7 +2354,11 @@ export class WebInspectorElement extends LitElement {
|
|
|
2130
2354
|
return content;
|
|
2131
2355
|
}
|
|
2132
2356
|
|
|
2133
|
-
if (
|
|
2357
|
+
if (
|
|
2358
|
+
content &&
|
|
2359
|
+
typeof content === "object" &&
|
|
2360
|
+
"text" in (content as Record<string, unknown>)
|
|
2361
|
+
) {
|
|
2134
2362
|
const maybeText = (content as Record<string, unknown>).text;
|
|
2135
2363
|
if (typeof maybeText === "string") {
|
|
2136
2364
|
return maybeText;
|
|
@@ -2164,12 +2392,21 @@ export class WebInspectorElement extends LitElement {
|
|
|
2164
2392
|
}
|
|
2165
2393
|
const call = entry as Record<string, unknown>;
|
|
2166
2394
|
const fn = call.function as Record<string, unknown> | undefined;
|
|
2167
|
-
const functionName =
|
|
2168
|
-
|
|
2395
|
+
const functionName =
|
|
2396
|
+
typeof fn?.name === "string"
|
|
2397
|
+
? fn.name
|
|
2398
|
+
: typeof call.toolName === "string"
|
|
2399
|
+
? call.toolName
|
|
2400
|
+
: undefined;
|
|
2401
|
+
const args =
|
|
2402
|
+
fn && "arguments" in fn
|
|
2403
|
+
? (fn as Record<string, unknown>).arguments
|
|
2404
|
+
: call.arguments;
|
|
2169
2405
|
|
|
2170
2406
|
const normalized: InspectorToolCall = {
|
|
2171
2407
|
id: typeof call.id === "string" ? call.id : undefined,
|
|
2172
|
-
toolName:
|
|
2408
|
+
toolName:
|
|
2409
|
+
typeof call.toolName === "string" ? call.toolName : functionName,
|
|
2173
2410
|
status: typeof call.status === "string" ? call.status : undefined,
|
|
2174
2411
|
};
|
|
2175
2412
|
|
|
@@ -2199,7 +2436,10 @@ export class WebInspectorElement extends LitElement {
|
|
|
2199
2436
|
id: typeof raw.id === "string" ? raw.id : undefined,
|
|
2200
2437
|
role,
|
|
2201
2438
|
contentText,
|
|
2202
|
-
contentRaw:
|
|
2439
|
+
contentRaw:
|
|
2440
|
+
raw.content !== undefined
|
|
2441
|
+
? this.sanitizeForLogging(raw.content)
|
|
2442
|
+
: undefined,
|
|
2203
2443
|
toolCalls,
|
|
2204
2444
|
};
|
|
2205
2445
|
}
|
|
@@ -2223,12 +2463,18 @@ export class WebInspectorElement extends LitElement {
|
|
|
2223
2463
|
return {};
|
|
2224
2464
|
}
|
|
2225
2465
|
|
|
2226
|
-
const normalized: Record<string, { description?: string; value: unknown }> =
|
|
2466
|
+
const normalized: Record<string, { description?: string; value: unknown }> =
|
|
2467
|
+
{};
|
|
2227
2468
|
for (const [key, entry] of Object.entries(context)) {
|
|
2228
|
-
if (
|
|
2469
|
+
if (
|
|
2470
|
+
entry &&
|
|
2471
|
+
typeof entry === "object" &&
|
|
2472
|
+
"value" in (entry as Record<string, unknown>)
|
|
2473
|
+
) {
|
|
2229
2474
|
const candidate = entry as Record<string, unknown>;
|
|
2230
2475
|
const description =
|
|
2231
|
-
typeof candidate.description === "string" &&
|
|
2476
|
+
typeof candidate.description === "string" &&
|
|
2477
|
+
candidate.description.trim().length > 0
|
|
2232
2478
|
? candidate.description
|
|
2233
2479
|
: undefined;
|
|
2234
2480
|
normalized[key] = { description, value: candidate.value };
|
|
@@ -2262,12 +2508,19 @@ export class WebInspectorElement extends LitElement {
|
|
|
2262
2508
|
}
|
|
2263
2509
|
|
|
2264
2510
|
return html`
|
|
2265
|
-
<div
|
|
2266
|
-
|
|
2511
|
+
<div
|
|
2512
|
+
class="mx-4 my-3 flex items-start gap-2 rounded-md border border-amber-200 bg-amber-50 px-3 py-2 text-xs text-amber-800"
|
|
2513
|
+
>
|
|
2514
|
+
<span class="mt-0.5 shrink-0 text-amber-600"
|
|
2515
|
+
>${this.renderIcon("AlertTriangle")}</span
|
|
2516
|
+
>
|
|
2267
2517
|
<div class="space-y-1">
|
|
2268
|
-
<div class="font-semibold text-amber-900">
|
|
2518
|
+
<div class="font-semibold text-amber-900">
|
|
2519
|
+
CopilotKit core not attached
|
|
2520
|
+
</div>
|
|
2269
2521
|
<p class="text-[11px] leading-snug text-amber-800">
|
|
2270
|
-
Pass a live <code>CopilotKitCore</code> instance to
|
|
2522
|
+
Pass a live <code>CopilotKitCore</code> instance to
|
|
2523
|
+
<code><cpk-web-inspector></code> or expose it on
|
|
2271
2524
|
<code>window.__COPILOTKIT_CORE__</code> for auto-attach.
|
|
2272
2525
|
</p>
|
|
2273
2526
|
</div>
|
|
@@ -2275,23 +2528,30 @@ export class WebInspectorElement extends LitElement {
|
|
|
2275
2528
|
`;
|
|
2276
2529
|
}
|
|
2277
2530
|
|
|
2278
|
-
private getCoreStatusSummary(): {
|
|
2531
|
+
private getCoreStatusSummary(): {
|
|
2532
|
+
label: string;
|
|
2533
|
+
tone: string;
|
|
2534
|
+
description: string;
|
|
2535
|
+
} {
|
|
2279
2536
|
if (!this._core) {
|
|
2280
2537
|
return {
|
|
2281
2538
|
label: "Core not attached",
|
|
2282
2539
|
tone: "border border-amber-200 bg-amber-50 text-amber-800",
|
|
2283
|
-
description:
|
|
2540
|
+
description:
|
|
2541
|
+
"Pass a CopilotKitCore instance to <cpk-web-inspector> or enable auto-attach.",
|
|
2284
2542
|
};
|
|
2285
2543
|
}
|
|
2286
2544
|
|
|
2287
|
-
const status =
|
|
2545
|
+
const status =
|
|
2546
|
+
this.runtimeStatus ?? CopilotKitCoreRuntimeConnectionStatus.Disconnected;
|
|
2288
2547
|
const lastErrorMessage = this.lastCoreError?.message;
|
|
2289
2548
|
|
|
2290
2549
|
if (status === CopilotKitCoreRuntimeConnectionStatus.Error) {
|
|
2291
2550
|
return {
|
|
2292
2551
|
label: "Runtime error",
|
|
2293
2552
|
tone: "border border-rose-200 bg-rose-50 text-rose-700",
|
|
2294
|
-
description:
|
|
2553
|
+
description:
|
|
2554
|
+
lastErrorMessage ?? "CopilotKit runtime reported an error.",
|
|
2295
2555
|
};
|
|
2296
2556
|
}
|
|
2297
2557
|
|
|
@@ -2314,7 +2574,8 @@ export class WebInspectorElement extends LitElement {
|
|
|
2314
2574
|
return {
|
|
2315
2575
|
label: "Disconnected",
|
|
2316
2576
|
tone: "border border-gray-200 bg-gray-50 text-gray-700",
|
|
2317
|
-
description:
|
|
2577
|
+
description:
|
|
2578
|
+
lastErrorMessage ?? "Waiting for CopilotKit runtime to connect.",
|
|
2318
2579
|
};
|
|
2319
2580
|
}
|
|
2320
2581
|
|
|
@@ -2341,17 +2602,26 @@ export class WebInspectorElement extends LitElement {
|
|
|
2341
2602
|
private renderEventsTable() {
|
|
2342
2603
|
const events = this.getEventsForSelectedContext();
|
|
2343
2604
|
const filteredEvents = this.filterEvents(events);
|
|
2344
|
-
const selectedLabel =
|
|
2605
|
+
const selectedLabel =
|
|
2606
|
+
this.selectedContext === "all-agents"
|
|
2607
|
+
? "all agents"
|
|
2608
|
+
: `agent ${this.selectedContext}`;
|
|
2345
2609
|
|
|
2346
2610
|
if (events.length === 0) {
|
|
2347
2611
|
return html`
|
|
2348
|
-
<div
|
|
2612
|
+
<div
|
|
2613
|
+
class="flex h-full items-center justify-center px-4 py-8 text-center"
|
|
2614
|
+
>
|
|
2349
2615
|
<div class="max-w-md">
|
|
2350
|
-
<div
|
|
2616
|
+
<div
|
|
2617
|
+
class="mb-3 flex justify-center text-gray-300 [&>svg]:!h-8 [&>svg]:!w-8"
|
|
2618
|
+
>
|
|
2351
2619
|
${this.renderIcon("Zap")}
|
|
2352
2620
|
</div>
|
|
2353
2621
|
<p class="text-sm text-gray-600">No events yet</p>
|
|
2354
|
-
<p class="mt-2 text-xs text-gray-500">
|
|
2622
|
+
<p class="mt-2 text-xs text-gray-500">
|
|
2623
|
+
Trigger an agent run to see live activity.
|
|
2624
|
+
</p>
|
|
2355
2625
|
</div>
|
|
2356
2626
|
</div>
|
|
2357
2627
|
`;
|
|
@@ -2359,12 +2629,18 @@ export class WebInspectorElement extends LitElement {
|
|
|
2359
2629
|
|
|
2360
2630
|
if (filteredEvents.length === 0) {
|
|
2361
2631
|
return html`
|
|
2362
|
-
<div
|
|
2632
|
+
<div
|
|
2633
|
+
class="flex h-full items-center justify-center px-4 py-8 text-center"
|
|
2634
|
+
>
|
|
2363
2635
|
<div class="max-w-md space-y-3">
|
|
2364
|
-
<div
|
|
2636
|
+
<div
|
|
2637
|
+
class="flex justify-center text-gray-300 [&>svg]:!h-8 [&>svg]:!w-8"
|
|
2638
|
+
>
|
|
2365
2639
|
${this.renderIcon("Filter")}
|
|
2366
2640
|
</div>
|
|
2367
|
-
<p class="text-sm text-gray-600">
|
|
2641
|
+
<p class="text-sm text-gray-600">
|
|
2642
|
+
No events match the current filters.
|
|
2643
|
+
</p>
|
|
2368
2644
|
<div>
|
|
2369
2645
|
<button
|
|
2370
2646
|
type="button"
|
|
@@ -2382,7 +2658,9 @@ export class WebInspectorElement extends LitElement {
|
|
|
2382
2658
|
|
|
2383
2659
|
return html`
|
|
2384
2660
|
<div class="flex h-full flex-col">
|
|
2385
|
-
<div
|
|
2661
|
+
<div
|
|
2662
|
+
class="flex flex-col gap-1.5 border-b border-gray-200 bg-white px-4 py-2.5"
|
|
2663
|
+
>
|
|
2386
2664
|
<div class="flex flex-wrap items-center gap-2">
|
|
2387
2665
|
<div class="relative min-w-[200px] flex-1">
|
|
2388
2666
|
<input
|
|
@@ -2401,7 +2679,9 @@ export class WebInspectorElement extends LitElement {
|
|
|
2401
2679
|
<option value="all">All event types</option>
|
|
2402
2680
|
${AGENT_EVENT_TYPES.map(
|
|
2403
2681
|
(type) =>
|
|
2404
|
-
html`<option value=${type}
|
|
2682
|
+
html`<option value=${type}>
|
|
2683
|
+
${type.toLowerCase().replace(/_/g, " ")}
|
|
2684
|
+
</option>`,
|
|
2405
2685
|
)}
|
|
2406
2686
|
</select>
|
|
2407
2687
|
<div class="flex items-center gap-1 text-[11px]">
|
|
@@ -2412,7 +2692,8 @@ export class WebInspectorElement extends LitElement {
|
|
|
2412
2692
|
data-tooltip="Reset filters"
|
|
2413
2693
|
aria-label="Reset filters"
|
|
2414
2694
|
@click=${this.resetEventFilters}
|
|
2415
|
-
?disabled=${!this.eventFilterText &&
|
|
2695
|
+
?disabled=${!this.eventFilterText &&
|
|
2696
|
+
this.eventTypeFilter === "all"}
|
|
2416
2697
|
>
|
|
2417
2698
|
${this.renderIcon("RotateCw")}
|
|
2418
2699
|
</button>
|
|
@@ -2441,23 +2722,34 @@ export class WebInspectorElement extends LitElement {
|
|
|
2441
2722
|
</div>
|
|
2442
2723
|
</div>
|
|
2443
2724
|
<div class="text-[11px] text-gray-500">
|
|
2444
|
-
Showing ${filteredEvents.length} of
|
|
2725
|
+
Showing ${filteredEvents.length} of
|
|
2726
|
+
${events.length}${this.selectedContext === "all-agents"
|
|
2727
|
+
? ""
|
|
2728
|
+
: ` for ${selectedLabel}`}
|
|
2445
2729
|
</div>
|
|
2446
2730
|
</div>
|
|
2447
2731
|
<div class="relative h-full w-full overflow-y-auto overflow-x-hidden">
|
|
2448
2732
|
<table class="w-full table-fixed border-collapse text-xs box-border">
|
|
2449
2733
|
<thead class="sticky top-0 z-10">
|
|
2450
2734
|
<tr class="bg-white">
|
|
2451
|
-
<th
|
|
2735
|
+
<th
|
|
2736
|
+
class="border-b border-gray-200 bg-white px-3 py-2 text-left font-medium text-gray-900"
|
|
2737
|
+
>
|
|
2452
2738
|
Agent
|
|
2453
2739
|
</th>
|
|
2454
|
-
<th
|
|
2740
|
+
<th
|
|
2741
|
+
class="border-b border-gray-200 bg-white px-3 py-2 text-left font-medium text-gray-900"
|
|
2742
|
+
>
|
|
2455
2743
|
Time
|
|
2456
2744
|
</th>
|
|
2457
|
-
<th
|
|
2745
|
+
<th
|
|
2746
|
+
class="border-b border-gray-200 bg-white px-3 py-2 text-left font-medium text-gray-900"
|
|
2747
|
+
>
|
|
2458
2748
|
Event Type
|
|
2459
2749
|
</th>
|
|
2460
|
-
<th
|
|
2750
|
+
<th
|
|
2751
|
+
class="border-b border-gray-200 bg-white px-3 py-2 text-left font-medium text-gray-900"
|
|
2752
|
+
>
|
|
2461
2753
|
AG-UI Event
|
|
2462
2754
|
</th>
|
|
2463
2755
|
</tr>
|
|
@@ -2466,9 +2758,13 @@ export class WebInspectorElement extends LitElement {
|
|
|
2466
2758
|
${filteredEvents.map((event, index) => {
|
|
2467
2759
|
const rowBg = index % 2 === 0 ? "bg-white" : "bg-gray-50/50";
|
|
2468
2760
|
const badgeClasses = this.getEventBadgeClasses(event.type);
|
|
2469
|
-
const extractedEvent = this.extractEventFromPayload(
|
|
2470
|
-
|
|
2471
|
-
|
|
2761
|
+
const extractedEvent = this.extractEventFromPayload(
|
|
2762
|
+
event.payload,
|
|
2763
|
+
);
|
|
2764
|
+
const inlineEvent =
|
|
2765
|
+
this.stringifyPayload(extractedEvent, false) || "—";
|
|
2766
|
+
const prettyEvent =
|
|
2767
|
+
this.stringifyPayload(extractedEvent, true) || inlineEvent;
|
|
2472
2768
|
const isExpanded = this.expandedRows.has(event.id);
|
|
2473
2769
|
|
|
2474
2770
|
return html`
|
|
@@ -2476,10 +2772,16 @@ export class WebInspectorElement extends LitElement {
|
|
|
2476
2772
|
class="${rowBg} cursor-pointer transition hover:bg-blue-50/50"
|
|
2477
2773
|
@click=${() => this.toggleRowExpansion(event.id)}
|
|
2478
2774
|
>
|
|
2479
|
-
<td
|
|
2480
|
-
|
|
2775
|
+
<td
|
|
2776
|
+
class="border-l border-r border-b border-gray-200 px-3 py-2"
|
|
2777
|
+
>
|
|
2778
|
+
<span class="font-mono text-[11px] text-gray-600"
|
|
2779
|
+
>${event.agentId}</span
|
|
2780
|
+
>
|
|
2481
2781
|
</td>
|
|
2482
|
-
<td
|
|
2782
|
+
<td
|
|
2783
|
+
class="border-r border-b border-gray-200 px-3 py-2 font-mono text-[11px] text-gray-600"
|
|
2784
|
+
>
|
|
2483
2785
|
<span title=${new Date(event.timestamp).toLocaleString()}>
|
|
2484
2786
|
${new Date(event.timestamp).toLocaleTimeString()}
|
|
2485
2787
|
</span>
|
|
@@ -2487,17 +2789,25 @@ export class WebInspectorElement extends LitElement {
|
|
|
2487
2789
|
<td class="border-r border-b border-gray-200 px-3 py-2">
|
|
2488
2790
|
<span class=${badgeClasses}>${event.type}</span>
|
|
2489
2791
|
</td>
|
|
2490
|
-
<td
|
|
2792
|
+
<td
|
|
2793
|
+
class="border-r border-b border-gray-200 px-3 py-2 font-mono text-[10px] text-gray-600 ${isExpanded
|
|
2794
|
+
? ""
|
|
2795
|
+
: "truncate max-w-xs"}"
|
|
2796
|
+
>
|
|
2491
2797
|
${isExpanded
|
|
2492
2798
|
? html`
|
|
2493
2799
|
<div class="group relative">
|
|
2494
|
-
<pre
|
|
2800
|
+
<pre
|
|
2801
|
+
class="m-0 whitespace-pre-wrap break-words text-[10px] font-mono text-gray-600"
|
|
2802
|
+
>
|
|
2803
|
+
${prettyEvent}</pre
|
|
2804
|
+
>
|
|
2495
2805
|
<button
|
|
2496
|
-
class="absolute right-0 top-0 cursor-pointer rounded px-2 py-1 text-[10px] opacity-0 transition group-hover:opacity-100 ${
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2806
|
+
class="absolute right-0 top-0 cursor-pointer rounded px-2 py-1 text-[10px] opacity-0 transition group-hover:opacity-100 ${this.copiedEvents.has(
|
|
2807
|
+
event.id,
|
|
2808
|
+
)
|
|
2809
|
+
? "bg-green-100 text-green-700"
|
|
2810
|
+
: "bg-gray-100 text-gray-600 hover:bg-gray-200 hover:text-gray-900"}"
|
|
2501
2811
|
@click=${(e: Event) => {
|
|
2502
2812
|
e.stopPropagation();
|
|
2503
2813
|
this.copyToClipboard(prettyEvent, event.id);
|
|
@@ -2549,7 +2859,9 @@ export class WebInspectorElement extends LitElement {
|
|
|
2549
2859
|
this.flattenedEvents = [];
|
|
2550
2860
|
} else {
|
|
2551
2861
|
this.agentEvents.delete(this.selectedContext);
|
|
2552
|
-
this.flattenedEvents = this.flattenedEvents.filter(
|
|
2862
|
+
this.flattenedEvents = this.flattenedEvents.filter(
|
|
2863
|
+
(event) => event.agentId !== this.selectedContext,
|
|
2864
|
+
);
|
|
2553
2865
|
}
|
|
2554
2866
|
|
|
2555
2867
|
this.expandedRows.clear();
|
|
@@ -2576,13 +2888,19 @@ export class WebInspectorElement extends LitElement {
|
|
|
2576
2888
|
// Show message if "all-agents" is selected or no agents available
|
|
2577
2889
|
if (this.selectedContext === "all-agents") {
|
|
2578
2890
|
return html`
|
|
2579
|
-
<div
|
|
2891
|
+
<div
|
|
2892
|
+
class="flex h-full items-center justify-center px-4 py-8 text-center"
|
|
2893
|
+
>
|
|
2580
2894
|
<div class="max-w-md">
|
|
2581
|
-
<div
|
|
2895
|
+
<div
|
|
2896
|
+
class="mb-3 flex justify-center text-gray-300 [&>svg]:!h-8 [&>svg]:!w-8"
|
|
2897
|
+
>
|
|
2582
2898
|
${this.renderIcon("Bot")}
|
|
2583
2899
|
</div>
|
|
2584
2900
|
<p class="text-sm text-gray-600">No agent selected</p>
|
|
2585
|
-
<p class="mt-2 text-xs text-gray-500">
|
|
2901
|
+
<p class="mt-2 text-xs text-gray-500">
|
|
2902
|
+
Select an agent from the dropdown above to view details.
|
|
2903
|
+
</p>
|
|
2586
2904
|
</div>
|
|
2587
2905
|
</div>
|
|
2588
2906
|
`;
|
|
@@ -2606,19 +2924,34 @@ export class WebInspectorElement extends LitElement {
|
|
|
2606
2924
|
<div class="rounded-lg border border-gray-200 bg-white p-4">
|
|
2607
2925
|
<div class="flex items-start justify-between mb-4">
|
|
2608
2926
|
<div class="flex items-center gap-3">
|
|
2609
|
-
<div
|
|
2927
|
+
<div
|
|
2928
|
+
class="flex h-10 w-10 items-center justify-center rounded-lg bg-blue-100 text-blue-600"
|
|
2929
|
+
>
|
|
2610
2930
|
${this.renderIcon("Bot")}
|
|
2611
2931
|
</div>
|
|
2612
2932
|
<div>
|
|
2613
2933
|
<h3 class="font-semibold text-sm text-gray-900">${agentId}</h3>
|
|
2614
|
-
<span
|
|
2615
|
-
|
|
2934
|
+
<span
|
|
2935
|
+
class="inline-flex items-center gap-1.5 rounded-full px-2 py-0.5 text-xs font-medium ${statusColors[
|
|
2936
|
+
status
|
|
2937
|
+
]} relative -translate-y-[2px]"
|
|
2938
|
+
>
|
|
2939
|
+
<span
|
|
2940
|
+
class="h-1.5 w-1.5 rounded-full ${status === "running"
|
|
2941
|
+
? "bg-emerald-500 animate-pulse"
|
|
2942
|
+
: status === "error"
|
|
2943
|
+
? "bg-rose-500"
|
|
2944
|
+
: "bg-gray-400"}"
|
|
2945
|
+
></span>
|
|
2616
2946
|
${status.charAt(0).toUpperCase() + status.slice(1)}
|
|
2617
2947
|
</span>
|
|
2618
2948
|
</div>
|
|
2619
2949
|
</div>
|
|
2620
2950
|
${stats.lastActivity
|
|
2621
|
-
? html`<span class="text-xs text-gray-500"
|
|
2951
|
+
? html`<span class="text-xs text-gray-500"
|
|
2952
|
+
>Last activity:
|
|
2953
|
+
${new Date(stats.lastActivity).toLocaleTimeString()}</span
|
|
2954
|
+
>`
|
|
2622
2955
|
: nothing}
|
|
2623
2956
|
</div>
|
|
2624
2957
|
<div class="grid grid-cols-2 gap-4 md:grid-cols-4">
|
|
@@ -2628,20 +2961,36 @@ export class WebInspectorElement extends LitElement {
|
|
|
2628
2961
|
@click=${() => this.handleMenuSelect("ag-ui-events")}
|
|
2629
2962
|
title="View all events in AG-UI Events"
|
|
2630
2963
|
>
|
|
2631
|
-
<div class="truncate whitespace-nowrap text-xs text-gray-600">
|
|
2632
|
-
|
|
2964
|
+
<div class="truncate whitespace-nowrap text-xs text-gray-600">
|
|
2965
|
+
Total Events
|
|
2966
|
+
</div>
|
|
2967
|
+
<div class="text-lg font-semibold text-gray-900">
|
|
2968
|
+
${stats.totalEvents}
|
|
2969
|
+
</div>
|
|
2633
2970
|
</button>
|
|
2634
2971
|
<div class="rounded-md bg-gray-50 px-3 py-2 overflow-hidden">
|
|
2635
|
-
<div class="truncate whitespace-nowrap text-xs text-gray-600">
|
|
2636
|
-
|
|
2972
|
+
<div class="truncate whitespace-nowrap text-xs text-gray-600">
|
|
2973
|
+
Messages
|
|
2974
|
+
</div>
|
|
2975
|
+
<div class="text-lg font-semibold text-gray-900">
|
|
2976
|
+
${stats.messages}
|
|
2977
|
+
</div>
|
|
2637
2978
|
</div>
|
|
2638
2979
|
<div class="rounded-md bg-gray-50 px-3 py-2 overflow-hidden">
|
|
2639
|
-
<div class="truncate whitespace-nowrap text-xs text-gray-600">
|
|
2640
|
-
|
|
2980
|
+
<div class="truncate whitespace-nowrap text-xs text-gray-600">
|
|
2981
|
+
Tool Calls
|
|
2982
|
+
</div>
|
|
2983
|
+
<div class="text-lg font-semibold text-gray-900">
|
|
2984
|
+
${stats.toolCalls}
|
|
2985
|
+
</div>
|
|
2641
2986
|
</div>
|
|
2642
2987
|
<div class="rounded-md bg-gray-50 px-3 py-2 overflow-hidden">
|
|
2643
|
-
<div class="truncate whitespace-nowrap text-xs text-gray-600">
|
|
2644
|
-
|
|
2988
|
+
<div class="truncate whitespace-nowrap text-xs text-gray-600">
|
|
2989
|
+
Errors
|
|
2990
|
+
</div>
|
|
2991
|
+
<div class="text-lg font-semibold text-gray-900">
|
|
2992
|
+
${stats.errors}
|
|
2993
|
+
</div>
|
|
2645
2994
|
</div>
|
|
2646
2995
|
</div>
|
|
2647
2996
|
</div>
|
|
@@ -2654,12 +3003,18 @@ export class WebInspectorElement extends LitElement {
|
|
|
2654
3003
|
<div class="overflow-auto p-4">
|
|
2655
3004
|
${this.hasRenderableState(state)
|
|
2656
3005
|
? html`
|
|
2657
|
-
<pre
|
|
3006
|
+
<pre
|
|
3007
|
+
class="overflow-auto rounded-md bg-gray-50 p-3 text-xs text-gray-800 max-h-64"
|
|
3008
|
+
><code>${this.formatStateForDisplay(state)}</code></pre>
|
|
2658
3009
|
`
|
|
2659
3010
|
: html`
|
|
2660
|
-
<div
|
|
3011
|
+
<div
|
|
3012
|
+
class="flex h-40 items-center justify-center text-xs text-gray-500"
|
|
3013
|
+
>
|
|
2661
3014
|
<div class="flex items-center gap-2 text-gray-500">
|
|
2662
|
-
<span class="text-lg text-gray-400"
|
|
3015
|
+
<span class="text-lg text-gray-400"
|
|
3016
|
+
>${this.renderIcon("Database")}</span
|
|
3017
|
+
>
|
|
2663
3018
|
<span>State is empty</span>
|
|
2664
3019
|
</div>
|
|
2665
3020
|
</div>
|
|
@@ -2670,7 +3025,9 @@ export class WebInspectorElement extends LitElement {
|
|
|
2670
3025
|
<!-- Current Messages Section -->
|
|
2671
3026
|
<div class="rounded-lg border border-gray-200 bg-white">
|
|
2672
3027
|
<div class="border-b border-gray-200 px-4 py-3">
|
|
2673
|
-
<h4 class="text-sm font-semibold text-gray-900">
|
|
3028
|
+
<h4 class="text-sm font-semibold text-gray-900">
|
|
3029
|
+
Current Messages
|
|
3030
|
+
</h4>
|
|
2674
3031
|
</div>
|
|
2675
3032
|
<div class="overflow-auto">
|
|
2676
3033
|
${messages && messages.length > 0
|
|
@@ -2678,8 +3035,16 @@ export class WebInspectorElement extends LitElement {
|
|
|
2678
3035
|
<table class="w-full text-xs">
|
|
2679
3036
|
<thead class="bg-gray-50">
|
|
2680
3037
|
<tr>
|
|
2681
|
-
<th
|
|
2682
|
-
|
|
3038
|
+
<th
|
|
3039
|
+
class="px-4 py-2 text-left font-medium text-gray-700"
|
|
3040
|
+
>
|
|
3041
|
+
Role
|
|
3042
|
+
</th>
|
|
3043
|
+
<th
|
|
3044
|
+
class="px-4 py-2 text-left font-medium text-gray-700"
|
|
3045
|
+
>
|
|
3046
|
+
Content
|
|
3047
|
+
</th>
|
|
2683
3048
|
</tr>
|
|
2684
3049
|
</thead>
|
|
2685
3050
|
<tbody class="divide-y divide-gray-200">
|
|
@@ -2696,20 +3061,33 @@ export class WebInspectorElement extends LitElement {
|
|
|
2696
3061
|
const rawContent = msg.contentText ?? "";
|
|
2697
3062
|
const toolCalls = msg.toolCalls ?? [];
|
|
2698
3063
|
const hasContent = rawContent.trim().length > 0;
|
|
2699
|
-
const contentFallback =
|
|
3064
|
+
const contentFallback =
|
|
3065
|
+
toolCalls.length > 0 ? "Invoked tool call" : "—";
|
|
2700
3066
|
|
|
2701
3067
|
return html`
|
|
2702
3068
|
<tr>
|
|
2703
3069
|
<td class="px-4 py-2 align-top">
|
|
2704
|
-
<span
|
|
3070
|
+
<span
|
|
3071
|
+
class="inline-flex rounded px-2 py-0.5 text-[10px] font-medium ${roleColors[
|
|
3072
|
+
role
|
|
3073
|
+
] || roleColors.unknown}"
|
|
3074
|
+
>
|
|
2705
3075
|
${role}
|
|
2706
3076
|
</span>
|
|
2707
3077
|
</td>
|
|
2708
3078
|
<td class="px-4 py-2">
|
|
2709
3079
|
${hasContent
|
|
2710
|
-
? html`<div
|
|
2711
|
-
|
|
2712
|
-
|
|
3080
|
+
? html`<div
|
|
3081
|
+
class="max-w-2xl whitespace-pre-wrap break-words text-gray-700"
|
|
3082
|
+
>
|
|
3083
|
+
${rawContent}
|
|
3084
|
+
</div>`
|
|
3085
|
+
: html`<div
|
|
3086
|
+
class="text-xs italic text-gray-400"
|
|
3087
|
+
>
|
|
3088
|
+
${contentFallback}
|
|
3089
|
+
</div>`}
|
|
3090
|
+
${role === "assistant" && toolCalls.length > 0
|
|
2713
3091
|
? this.renderToolCallDetails(toolCalls)
|
|
2714
3092
|
: nothing}
|
|
2715
3093
|
</td>
|
|
@@ -2720,9 +3098,13 @@ export class WebInspectorElement extends LitElement {
|
|
|
2720
3098
|
</table>
|
|
2721
3099
|
`
|
|
2722
3100
|
: html`
|
|
2723
|
-
<div
|
|
3101
|
+
<div
|
|
3102
|
+
class="flex h-40 items-center justify-center text-xs text-gray-500"
|
|
3103
|
+
>
|
|
2724
3104
|
<div class="flex items-center gap-2 text-gray-500">
|
|
2725
|
-
<span class="text-lg text-gray-400"
|
|
3105
|
+
<span class="text-lg text-gray-400"
|
|
3106
|
+
>${this.renderIcon("MessageSquare")}</span
|
|
3107
|
+
>
|
|
2726
3108
|
<span>No messages available</span>
|
|
2727
3109
|
</div>
|
|
2728
3110
|
</div>
|
|
@@ -2735,21 +3117,29 @@ export class WebInspectorElement extends LitElement {
|
|
|
2735
3117
|
|
|
2736
3118
|
private renderContextDropdown() {
|
|
2737
3119
|
// Filter out "all-agents" when in agents view
|
|
2738
|
-
const filteredOptions =
|
|
2739
|
-
|
|
2740
|
-
|
|
3120
|
+
const filteredOptions =
|
|
3121
|
+
this.selectedMenu === "agents"
|
|
3122
|
+
? this.contextOptions.filter((opt) => opt.key !== "all-agents")
|
|
3123
|
+
: this.contextOptions;
|
|
2741
3124
|
|
|
2742
|
-
const selectedLabel =
|
|
3125
|
+
const selectedLabel =
|
|
3126
|
+
filteredOptions.find((opt) => opt.key === this.selectedContext)?.label ??
|
|
3127
|
+
"";
|
|
2743
3128
|
|
|
2744
3129
|
return html`
|
|
2745
|
-
<div
|
|
3130
|
+
<div
|
|
3131
|
+
class="relative z-40 min-w-0 flex-1"
|
|
3132
|
+
data-context-dropdown-root="true"
|
|
3133
|
+
>
|
|
2746
3134
|
<button
|
|
2747
3135
|
type="button"
|
|
2748
3136
|
class="relative z-40 flex w-full min-w-0 max-w-[240px] items-center gap-1.5 rounded-md border border-gray-200 px-2 py-1 text-xs font-medium text-gray-700 transition hover:border-gray-300 hover:bg-gray-50"
|
|
2749
3137
|
@pointerdown=${this.handleContextDropdownToggle}
|
|
2750
3138
|
>
|
|
2751
3139
|
<span class="truncate flex-1 text-left">${selectedLabel}</span>
|
|
2752
|
-
<span class="shrink-0 text-gray-400"
|
|
3140
|
+
<span class="shrink-0 text-gray-400"
|
|
3141
|
+
>${this.renderIcon("ChevronDown")}</span
|
|
3142
|
+
>
|
|
2753
3143
|
</button>
|
|
2754
3144
|
${this.contextMenuOpen
|
|
2755
3145
|
? html`
|
|
@@ -2765,9 +3155,16 @@ export class WebInspectorElement extends LitElement {
|
|
|
2765
3155
|
data-context-dropdown-root="true"
|
|
2766
3156
|
@click=${() => this.handleContextOptionSelect(option.key)}
|
|
2767
3157
|
>
|
|
2768
|
-
<span
|
|
3158
|
+
<span
|
|
3159
|
+
class="truncate ${option.key === this.selectedContext
|
|
3160
|
+
? "text-gray-900 font-medium"
|
|
3161
|
+
: "text-gray-600"}"
|
|
3162
|
+
>${option.label}</span
|
|
3163
|
+
>
|
|
2769
3164
|
${option.key === this.selectedContext
|
|
2770
|
-
? html`<span class="text-gray-500"
|
|
3165
|
+
? html`<span class="text-gray-500"
|
|
3166
|
+
>${this.renderIcon("Check")}</span
|
|
3167
|
+
>`
|
|
2771
3168
|
: nothing}
|
|
2772
3169
|
</button>
|
|
2773
3170
|
`,
|
|
@@ -2788,11 +3185,15 @@ export class WebInspectorElement extends LitElement {
|
|
|
2788
3185
|
|
|
2789
3186
|
// If switching to agents view and "all-agents" is selected, switch to default or first agent
|
|
2790
3187
|
if (key === "agents" && this.selectedContext === "all-agents") {
|
|
2791
|
-
const agentOptions = this.contextOptions.filter(
|
|
3188
|
+
const agentOptions = this.contextOptions.filter(
|
|
3189
|
+
(opt) => opt.key !== "all-agents",
|
|
3190
|
+
);
|
|
2792
3191
|
if (agentOptions.length > 0) {
|
|
2793
3192
|
// Try to find "default" agent first
|
|
2794
3193
|
const defaultAgent = agentOptions.find((opt) => opt.key === "default");
|
|
2795
|
-
this.selectedContext = defaultAgent
|
|
3194
|
+
this.selectedContext = defaultAgent
|
|
3195
|
+
? defaultAgent.key
|
|
3196
|
+
: agentOptions[0]!.key;
|
|
2796
3197
|
}
|
|
2797
3198
|
}
|
|
2798
3199
|
|
|
@@ -2826,7 +3227,9 @@ export class WebInspectorElement extends LitElement {
|
|
|
2826
3227
|
private renderToolsView() {
|
|
2827
3228
|
if (!this._core) {
|
|
2828
3229
|
return html`
|
|
2829
|
-
<div
|
|
3230
|
+
<div
|
|
3231
|
+
class="flex h-full items-center justify-center px-4 py-8 text-xs text-gray-500"
|
|
3232
|
+
>
|
|
2830
3233
|
No core instance available
|
|
2831
3234
|
</div>
|
|
2832
3235
|
`;
|
|
@@ -2837,28 +3240,38 @@ export class WebInspectorElement extends LitElement {
|
|
|
2837
3240
|
|
|
2838
3241
|
if (allTools.length === 0) {
|
|
2839
3242
|
return html`
|
|
2840
|
-
<div
|
|
3243
|
+
<div
|
|
3244
|
+
class="flex h-full items-center justify-center px-4 py-8 text-center"
|
|
3245
|
+
>
|
|
2841
3246
|
<div class="max-w-md">
|
|
2842
|
-
<div
|
|
3247
|
+
<div
|
|
3248
|
+
class="mb-3 flex justify-center text-gray-300 [&>svg]:!h-8 [&>svg]:!w-8"
|
|
3249
|
+
>
|
|
2843
3250
|
${this.renderIcon("Hammer")}
|
|
2844
3251
|
</div>
|
|
2845
3252
|
<p class="text-sm text-gray-600">No tools available</p>
|
|
2846
|
-
<p class="mt-2 text-xs text-gray-500">
|
|
3253
|
+
<p class="mt-2 text-xs text-gray-500">
|
|
3254
|
+
Tools will appear here once agents are configured with tool
|
|
3255
|
+
handlers or renderers.
|
|
3256
|
+
</p>
|
|
2847
3257
|
</div>
|
|
2848
3258
|
</div>
|
|
2849
3259
|
`;
|
|
2850
3260
|
}
|
|
2851
3261
|
|
|
2852
3262
|
// Filter tools by selected agent
|
|
2853
|
-
const filteredTools =
|
|
2854
|
-
|
|
2855
|
-
|
|
3263
|
+
const filteredTools =
|
|
3264
|
+
this.selectedContext === "all-agents"
|
|
3265
|
+
? allTools
|
|
3266
|
+
: allTools.filter(
|
|
3267
|
+
(tool) => !tool.agentId || tool.agentId === this.selectedContext,
|
|
3268
|
+
);
|
|
2856
3269
|
|
|
2857
3270
|
return html`
|
|
2858
3271
|
<div class="flex h-full flex-col overflow-hidden">
|
|
2859
3272
|
<div class="overflow-auto p-4">
|
|
2860
3273
|
<div class="space-y-3">
|
|
2861
|
-
${filteredTools.map(tool => this.renderToolCard(tool))}
|
|
3274
|
+
${filteredTools.map((tool) => this.renderToolCard(tool))}
|
|
2862
3275
|
</div>
|
|
2863
3276
|
</div>
|
|
2864
3277
|
</div>
|
|
@@ -2879,7 +3292,7 @@ export class WebInspectorElement extends LitElement {
|
|
|
2879
3292
|
name: coreTool.name,
|
|
2880
3293
|
description: coreTool.description,
|
|
2881
3294
|
parameters: coreTool.parameters,
|
|
2882
|
-
type:
|
|
3295
|
+
type: "handler",
|
|
2883
3296
|
});
|
|
2884
3297
|
}
|
|
2885
3298
|
|
|
@@ -2888,44 +3301,54 @@ export class WebInspectorElement extends LitElement {
|
|
|
2888
3301
|
if (!agent) continue;
|
|
2889
3302
|
|
|
2890
3303
|
// Try to extract tool handlers
|
|
2891
|
-
const handlers = (agent as { toolHandlers?: Record<string, unknown> })
|
|
2892
|
-
|
|
3304
|
+
const handlers = (agent as { toolHandlers?: Record<string, unknown> })
|
|
3305
|
+
.toolHandlers;
|
|
3306
|
+
if (handlers && typeof handlers === "object") {
|
|
2893
3307
|
for (const [toolName, handler] of Object.entries(handlers)) {
|
|
2894
|
-
if (handler && typeof handler ===
|
|
3308
|
+
if (handler && typeof handler === "object") {
|
|
2895
3309
|
const handlerObj = handler as Record<string, unknown>;
|
|
2896
3310
|
tools.push({
|
|
2897
3311
|
agentId,
|
|
2898
3312
|
name: toolName,
|
|
2899
3313
|
description:
|
|
2900
|
-
(typeof handlerObj.description === "string" &&
|
|
2901
|
-
|
|
3314
|
+
(typeof handlerObj.description === "string" &&
|
|
3315
|
+
handlerObj.description) ||
|
|
3316
|
+
(handlerObj.tool as { description?: string } | undefined)
|
|
3317
|
+
?.description,
|
|
2902
3318
|
parameters:
|
|
2903
3319
|
handlerObj.parameters ??
|
|
2904
|
-
(handlerObj.tool as { parameters?: unknown } | undefined)
|
|
2905
|
-
|
|
3320
|
+
(handlerObj.tool as { parameters?: unknown } | undefined)
|
|
3321
|
+
?.parameters,
|
|
3322
|
+
type: "handler",
|
|
2906
3323
|
});
|
|
2907
3324
|
}
|
|
2908
3325
|
}
|
|
2909
3326
|
}
|
|
2910
3327
|
|
|
2911
3328
|
// Try to extract tool renderers
|
|
2912
|
-
const renderers = (agent as { toolRenderers?: Record<string, unknown> })
|
|
2913
|
-
|
|
3329
|
+
const renderers = (agent as { toolRenderers?: Record<string, unknown> })
|
|
3330
|
+
.toolRenderers;
|
|
3331
|
+
if (renderers && typeof renderers === "object") {
|
|
2914
3332
|
for (const [toolName, renderer] of Object.entries(renderers)) {
|
|
2915
3333
|
// Don't duplicate if we already have it as a handler
|
|
2916
|
-
if (
|
|
2917
|
-
|
|
3334
|
+
if (
|
|
3335
|
+
!tools.some((t) => t.agentId === agentId && t.name === toolName)
|
|
3336
|
+
) {
|
|
3337
|
+
if (renderer && typeof renderer === "object") {
|
|
2918
3338
|
const rendererObj = renderer as Record<string, unknown>;
|
|
2919
3339
|
tools.push({
|
|
2920
3340
|
agentId,
|
|
2921
3341
|
name: toolName,
|
|
2922
3342
|
description:
|
|
2923
|
-
(typeof rendererObj.description === "string" &&
|
|
2924
|
-
|
|
3343
|
+
(typeof rendererObj.description === "string" &&
|
|
3344
|
+
rendererObj.description) ||
|
|
3345
|
+
(rendererObj.tool as { description?: string } | undefined)
|
|
3346
|
+
?.description,
|
|
2925
3347
|
parameters:
|
|
2926
3348
|
rendererObj.parameters ??
|
|
2927
|
-
(rendererObj.tool as { parameters?: unknown } | undefined)
|
|
2928
|
-
|
|
3349
|
+
(rendererObj.tool as { parameters?: unknown } | undefined)
|
|
3350
|
+
?.parameters,
|
|
3351
|
+
type: "renderer",
|
|
2929
3352
|
});
|
|
2930
3353
|
}
|
|
2931
3354
|
}
|
|
@@ -2954,13 +3377,20 @@ export class WebInspectorElement extends LitElement {
|
|
|
2954
3377
|
<button
|
|
2955
3378
|
type="button"
|
|
2956
3379
|
class="w-full px-4 py-3 text-left transition hover:bg-gray-50"
|
|
2957
|
-
@click=${() =>
|
|
3380
|
+
@click=${() =>
|
|
3381
|
+
this.toggleToolExpansion(`${tool.agentId}:${tool.name}`)}
|
|
2958
3382
|
>
|
|
2959
3383
|
<div class="flex items-start justify-between gap-3">
|
|
2960
3384
|
<div class="flex-1 min-w-0">
|
|
2961
3385
|
<div class="flex items-center gap-2 mb-1">
|
|
2962
|
-
<span class="font-mono text-sm font-semibold text-gray-900"
|
|
2963
|
-
|
|
3386
|
+
<span class="font-mono text-sm font-semibold text-gray-900"
|
|
3387
|
+
>${tool.name}</span
|
|
3388
|
+
>
|
|
3389
|
+
<span
|
|
3390
|
+
class="inline-flex items-center rounded-sm border px-1.5 py-0.5 text-[10px] font-medium ${typeColors[
|
|
3391
|
+
tool.type
|
|
3392
|
+
]}"
|
|
3393
|
+
>
|
|
2964
3394
|
${tool.type}
|
|
2965
3395
|
</span>
|
|
2966
3396
|
</div>
|
|
@@ -2972,15 +3402,26 @@ export class WebInspectorElement extends LitElement {
|
|
|
2972
3402
|
${schema.properties.length > 0
|
|
2973
3403
|
? html`
|
|
2974
3404
|
<span class="text-gray-300">•</span>
|
|
2975
|
-
<span
|
|
3405
|
+
<span
|
|
3406
|
+
>${schema.properties.length}
|
|
3407
|
+
parameter${schema.properties.length !== 1
|
|
3408
|
+
? "s"
|
|
3409
|
+
: ""}</span
|
|
3410
|
+
>
|
|
2976
3411
|
`
|
|
2977
3412
|
: nothing}
|
|
2978
3413
|
</div>
|
|
2979
3414
|
${tool.description
|
|
2980
|
-
? html`<p class="mt-2 text-xs text-gray-600"
|
|
3415
|
+
? html`<p class="mt-2 text-xs text-gray-600">
|
|
3416
|
+
${tool.description}
|
|
3417
|
+
</p>`
|
|
2981
3418
|
: nothing}
|
|
2982
3419
|
</div>
|
|
2983
|
-
<span
|
|
3420
|
+
<span
|
|
3421
|
+
class="shrink-0 text-gray-400 transition ${isExpanded
|
|
3422
|
+
? "rotate-180"
|
|
3423
|
+
: ""}"
|
|
3424
|
+
>
|
|
2984
3425
|
${this.renderIcon("ChevronDown")}
|
|
2985
3426
|
</span>
|
|
2986
3427
|
</div>
|
|
@@ -2991,50 +3432,88 @@ export class WebInspectorElement extends LitElement {
|
|
|
2991
3432
|
<div class="border-t border-gray-200 bg-gray-50/50 px-4 py-3">
|
|
2992
3433
|
${schema.properties.length > 0
|
|
2993
3434
|
? html`
|
|
2994
|
-
<h5 class="mb-3 text-xs font-semibold text-gray-700">
|
|
3435
|
+
<h5 class="mb-3 text-xs font-semibold text-gray-700">
|
|
3436
|
+
Parameters
|
|
3437
|
+
</h5>
|
|
2995
3438
|
<div class="space-y-3">
|
|
2996
|
-
${schema.properties.map(
|
|
2997
|
-
|
|
2998
|
-
<div
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3005
|
-
|
|
3006
|
-
|
|
3439
|
+
${schema.properties.map(
|
|
3440
|
+
(prop) => html`
|
|
3441
|
+
<div
|
|
3442
|
+
class="rounded-md border border-gray-200 bg-white p-3"
|
|
3443
|
+
>
|
|
3444
|
+
<div
|
|
3445
|
+
class="flex items-start justify-between gap-2 mb-1"
|
|
3446
|
+
>
|
|
3447
|
+
<span
|
|
3448
|
+
class="font-mono text-xs font-medium text-gray-900"
|
|
3449
|
+
>${prop.name}</span
|
|
3450
|
+
>
|
|
3451
|
+
<div class="flex items-center gap-1.5 shrink-0">
|
|
3452
|
+
${prop.required
|
|
3453
|
+
? html`<span
|
|
3454
|
+
class="text-[9px] rounded border border-rose-200 bg-rose-50 px-1 py-0.5 font-medium text-rose-700"
|
|
3455
|
+
>required</span
|
|
3456
|
+
>`
|
|
3457
|
+
: html`<span
|
|
3458
|
+
class="text-[9px] rounded border border-gray-200 bg-gray-50 px-1 py-0.5 font-medium text-gray-600"
|
|
3459
|
+
>optional</span
|
|
3460
|
+
>`}
|
|
3461
|
+
${prop.type
|
|
3462
|
+
? html`<span
|
|
3463
|
+
class="text-[9px] rounded border border-gray-200 bg-gray-50 px-1 py-0.5 font-mono text-gray-600"
|
|
3464
|
+
>${prop.type}</span
|
|
3465
|
+
>`
|
|
3466
|
+
: nothing}
|
|
3467
|
+
</div>
|
|
3007
3468
|
</div>
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
|
|
3013
|
-
|
|
3014
|
-
|
|
3015
|
-
<
|
|
3016
|
-
|
|
3017
|
-
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3023
|
-
|
|
3024
|
-
|
|
3025
|
-
${prop.enum.map(val => html`
|
|
3026
|
-
<code class="rounded border border-gray-200 bg-gray-50 px-1.5 py-0.5 text-[10px] font-mono text-gray-700">${JSON.stringify(val)}</code>
|
|
3027
|
-
`)}
|
|
3469
|
+
${prop.description
|
|
3470
|
+
? html`<p class="mt-1 text-xs text-gray-600">
|
|
3471
|
+
${prop.description}
|
|
3472
|
+
</p>`
|
|
3473
|
+
: nothing}
|
|
3474
|
+
${prop.defaultValue !== undefined
|
|
3475
|
+
? html`
|
|
3476
|
+
<div
|
|
3477
|
+
class="mt-2 flex items-center gap-1.5 text-[10px] text-gray-500"
|
|
3478
|
+
>
|
|
3479
|
+
<span>Default:</span>
|
|
3480
|
+
<code
|
|
3481
|
+
class="rounded bg-gray-100 px-1 py-0.5 font-mono"
|
|
3482
|
+
>${JSON.stringify(
|
|
3483
|
+
prop.defaultValue,
|
|
3484
|
+
)}</code
|
|
3485
|
+
>
|
|
3028
3486
|
</div>
|
|
3029
|
-
|
|
3030
|
-
|
|
3031
|
-
|
|
3032
|
-
|
|
3033
|
-
|
|
3487
|
+
`
|
|
3488
|
+
: nothing}
|
|
3489
|
+
${prop.enum && prop.enum.length > 0
|
|
3490
|
+
? html`
|
|
3491
|
+
<div class="mt-2">
|
|
3492
|
+
<span class="text-[10px] text-gray-500"
|
|
3493
|
+
>Allowed values:</span
|
|
3494
|
+
>
|
|
3495
|
+
<div class="mt-1 flex flex-wrap gap-1">
|
|
3496
|
+
${prop.enum.map(
|
|
3497
|
+
(val) => html`
|
|
3498
|
+
<code
|
|
3499
|
+
class="rounded border border-gray-200 bg-gray-50 px-1.5 py-0.5 text-[10px] font-mono text-gray-700"
|
|
3500
|
+
>${JSON.stringify(val)}</code
|
|
3501
|
+
>
|
|
3502
|
+
`,
|
|
3503
|
+
)}
|
|
3504
|
+
</div>
|
|
3505
|
+
</div>
|
|
3506
|
+
`
|
|
3507
|
+
: nothing}
|
|
3508
|
+
</div>
|
|
3509
|
+
`,
|
|
3510
|
+
)}
|
|
3034
3511
|
</div>
|
|
3035
3512
|
`
|
|
3036
3513
|
: html`
|
|
3037
|
-
<div
|
|
3514
|
+
<div
|
|
3515
|
+
class="flex items-center justify-center py-4 text-xs text-gray-500"
|
|
3516
|
+
>
|
|
3038
3517
|
<span>No parameters defined</span>
|
|
3039
3518
|
</div>
|
|
3040
3519
|
`}
|
|
@@ -3066,7 +3545,7 @@ export class WebInspectorElement extends LitElement {
|
|
|
3066
3545
|
}>;
|
|
3067
3546
|
} = { properties: [] };
|
|
3068
3547
|
|
|
3069
|
-
if (!parameters || typeof parameters !==
|
|
3548
|
+
if (!parameters || typeof parameters !== "object") {
|
|
3070
3549
|
return result;
|
|
3071
3550
|
}
|
|
3072
3551
|
|
|
@@ -3074,7 +3553,7 @@ export class WebInspectorElement extends LitElement {
|
|
|
3074
3553
|
const zodDef = (parameters as { _def?: Record<string, unknown> })._def;
|
|
3075
3554
|
if (zodDef && typeof zodDef === "object") {
|
|
3076
3555
|
// Handle Zod object schema
|
|
3077
|
-
if (zodDef.typeName ===
|
|
3556
|
+
if (zodDef.typeName === "ZodObject") {
|
|
3078
3557
|
const rawShape = zodDef.shape;
|
|
3079
3558
|
const shape =
|
|
3080
3559
|
typeof rawShape === "function"
|
|
@@ -3087,10 +3566,12 @@ export class WebInspectorElement extends LitElement {
|
|
|
3087
3566
|
const requiredKeys = new Set<string>();
|
|
3088
3567
|
|
|
3089
3568
|
// Get required fields
|
|
3090
|
-
if (zodDef.unknownKeys ===
|
|
3569
|
+
if (zodDef.unknownKeys === "strict" || !zodDef.catchall) {
|
|
3091
3570
|
Object.keys(shape || {}).forEach((key) => {
|
|
3092
3571
|
const candidate = (shape as Record<string, unknown>)[key];
|
|
3093
|
-
const fieldDef = (
|
|
3572
|
+
const fieldDef = (
|
|
3573
|
+
candidate as { _def?: Record<string, unknown> } | undefined
|
|
3574
|
+
)?._def;
|
|
3094
3575
|
if (fieldDef && !this.isZodOptional(candidate)) {
|
|
3095
3576
|
requiredKeys.add(key);
|
|
3096
3577
|
}
|
|
@@ -3111,11 +3592,13 @@ export class WebInspectorElement extends LitElement {
|
|
|
3111
3592
|
}
|
|
3112
3593
|
}
|
|
3113
3594
|
} else if (
|
|
3114
|
-
(parameters as { type?: string; properties?: Record<string, unknown> })
|
|
3595
|
+
(parameters as { type?: string; properties?: Record<string, unknown> })
|
|
3596
|
+
.type === "object" &&
|
|
3115
3597
|
(parameters as { properties?: Record<string, unknown> }).properties
|
|
3116
3598
|
) {
|
|
3117
3599
|
// Handle JSON Schema format
|
|
3118
|
-
const props = (parameters as { properties?: Record<string, unknown> })
|
|
3600
|
+
const props = (parameters as { properties?: Record<string, unknown> })
|
|
3601
|
+
.properties;
|
|
3119
3602
|
const required = new Set(
|
|
3120
3603
|
Array.isArray((parameters as { required?: string[] }).required)
|
|
3121
3604
|
? (parameters as { required?: string[] }).required
|
|
@@ -3127,7 +3610,8 @@ export class WebInspectorElement extends LitElement {
|
|
|
3127
3610
|
result.properties.push({
|
|
3128
3611
|
name: key,
|
|
3129
3612
|
type: prop.type as string | undefined,
|
|
3130
|
-
description:
|
|
3613
|
+
description:
|
|
3614
|
+
typeof prop.description === "string" ? prop.description : undefined,
|
|
3131
3615
|
required: required.has(key),
|
|
3132
3616
|
defaultValue: prop.default,
|
|
3133
3617
|
enum: Array.isArray(prop.enum) ? prop.enum : undefined,
|
|
@@ -3145,7 +3629,7 @@ export class WebInspectorElement extends LitElement {
|
|
|
3145
3629
|
const def = schema._def;
|
|
3146
3630
|
|
|
3147
3631
|
// Check if it's explicitly optional or nullable
|
|
3148
|
-
if (def.typeName ===
|
|
3632
|
+
if (def.typeName === "ZodOptional" || def.typeName === "ZodNullable") {
|
|
3149
3633
|
return true;
|
|
3150
3634
|
}
|
|
3151
3635
|
|
|
@@ -3177,39 +3661,51 @@ export class WebInspectorElement extends LitElement {
|
|
|
3177
3661
|
let def = currentSchema._def as Record<string, unknown>;
|
|
3178
3662
|
|
|
3179
3663
|
// Unwrap optional/nullable
|
|
3180
|
-
while (
|
|
3181
|
-
|
|
3182
|
-
|
|
3664
|
+
while (
|
|
3665
|
+
def.typeName === "ZodOptional" ||
|
|
3666
|
+
def.typeName === "ZodNullable" ||
|
|
3667
|
+
def.typeName === "ZodDefault"
|
|
3668
|
+
) {
|
|
3669
|
+
if (def.typeName === "ZodDefault" && def.defaultValue !== undefined) {
|
|
3670
|
+
info.defaultValue =
|
|
3671
|
+
typeof def.defaultValue === "function"
|
|
3672
|
+
? def.defaultValue()
|
|
3673
|
+
: def.defaultValue;
|
|
3183
3674
|
}
|
|
3184
|
-
currentSchema =
|
|
3675
|
+
currentSchema =
|
|
3676
|
+
(def.innerType as { _def?: Record<string, unknown> }) ?? currentSchema;
|
|
3185
3677
|
if (!currentSchema?._def) break;
|
|
3186
3678
|
def = currentSchema._def as Record<string, unknown>;
|
|
3187
3679
|
}
|
|
3188
3680
|
|
|
3189
3681
|
// Extract description
|
|
3190
|
-
info.description =
|
|
3682
|
+
info.description =
|
|
3683
|
+
typeof def.description === "string" ? def.description : undefined;
|
|
3191
3684
|
|
|
3192
|
-
const typeName =
|
|
3685
|
+
const typeName =
|
|
3686
|
+
typeof def.typeName === "string" ? def.typeName : undefined;
|
|
3193
3687
|
|
|
3194
3688
|
// Extract type
|
|
3195
3689
|
const typeMap: Record<string, string> = {
|
|
3196
|
-
ZodString:
|
|
3197
|
-
ZodNumber:
|
|
3198
|
-
ZodBoolean:
|
|
3199
|
-
ZodArray:
|
|
3200
|
-
ZodObject:
|
|
3201
|
-
ZodEnum:
|
|
3202
|
-
ZodLiteral:
|
|
3203
|
-
ZodUnion:
|
|
3204
|
-
ZodAny:
|
|
3205
|
-
ZodUnknown:
|
|
3690
|
+
ZodString: "string",
|
|
3691
|
+
ZodNumber: "number",
|
|
3692
|
+
ZodBoolean: "boolean",
|
|
3693
|
+
ZodArray: "array",
|
|
3694
|
+
ZodObject: "object",
|
|
3695
|
+
ZodEnum: "enum",
|
|
3696
|
+
ZodLiteral: "literal",
|
|
3697
|
+
ZodUnion: "union",
|
|
3698
|
+
ZodAny: "any",
|
|
3699
|
+
ZodUnknown: "unknown",
|
|
3206
3700
|
};
|
|
3207
|
-
info.type = typeName
|
|
3701
|
+
info.type = typeName
|
|
3702
|
+
? typeMap[typeName] || typeName.replace("Zod", "").toLowerCase()
|
|
3703
|
+
: undefined;
|
|
3208
3704
|
|
|
3209
3705
|
// Extract enum values
|
|
3210
|
-
if (typeName ===
|
|
3706
|
+
if (typeName === "ZodEnum" && Array.isArray(def.values)) {
|
|
3211
3707
|
info.enum = def.values as unknown[];
|
|
3212
|
-
} else if (typeName ===
|
|
3708
|
+
} else if (typeName === "ZodLiteral" && def.value !== undefined) {
|
|
3213
3709
|
info.enum = [def.value];
|
|
3214
3710
|
}
|
|
3215
3711
|
|
|
@@ -3230,13 +3726,19 @@ export class WebInspectorElement extends LitElement {
|
|
|
3230
3726
|
|
|
3231
3727
|
if (contextEntries.length === 0) {
|
|
3232
3728
|
return html`
|
|
3233
|
-
<div
|
|
3729
|
+
<div
|
|
3730
|
+
class="flex h-full items-center justify-center px-4 py-8 text-center"
|
|
3731
|
+
>
|
|
3234
3732
|
<div class="max-w-md">
|
|
3235
|
-
<div
|
|
3733
|
+
<div
|
|
3734
|
+
class="mb-3 flex justify-center text-gray-300 [&>svg]:!h-8 [&>svg]:!w-8"
|
|
3735
|
+
>
|
|
3236
3736
|
${this.renderIcon("FileText")}
|
|
3237
3737
|
</div>
|
|
3238
3738
|
<p class="text-sm text-gray-600">No context available</p>
|
|
3239
|
-
<p class="mt-2 text-xs text-gray-500">
|
|
3739
|
+
<p class="mt-2 text-xs text-gray-500">
|
|
3740
|
+
Context will appear here once added to CopilotKit.
|
|
3741
|
+
</p>
|
|
3240
3742
|
</div>
|
|
3241
3743
|
</div>
|
|
3242
3744
|
`;
|
|
@@ -3246,14 +3748,19 @@ export class WebInspectorElement extends LitElement {
|
|
|
3246
3748
|
<div class="flex h-full flex-col overflow-hidden">
|
|
3247
3749
|
<div class="overflow-auto p-4">
|
|
3248
3750
|
<div class="space-y-3">
|
|
3249
|
-
${contextEntries.map(([id, context]) =>
|
|
3751
|
+
${contextEntries.map(([id, context]) =>
|
|
3752
|
+
this.renderContextCard(id, context),
|
|
3753
|
+
)}
|
|
3250
3754
|
</div>
|
|
3251
3755
|
</div>
|
|
3252
3756
|
</div>
|
|
3253
3757
|
`;
|
|
3254
3758
|
}
|
|
3255
3759
|
|
|
3256
|
-
private renderContextCard(
|
|
3760
|
+
private renderContextCard(
|
|
3761
|
+
id: string,
|
|
3762
|
+
context: { description?: string; value: unknown },
|
|
3763
|
+
) {
|
|
3257
3764
|
const isExpanded = this.expandedContextItems.has(id);
|
|
3258
3765
|
const valuePreview = this.getContextValuePreview(context.value);
|
|
3259
3766
|
const hasValue = context.value !== undefined && context.value !== null;
|
|
@@ -3270,7 +3777,11 @@ export class WebInspectorElement extends LitElement {
|
|
|
3270
3777
|
<div class="flex-1 min-w-0">
|
|
3271
3778
|
<p class="text-sm font-medium text-gray-900 mb-1">${title}</p>
|
|
3272
3779
|
<div class="flex items-center gap-2 text-xs text-gray-500">
|
|
3273
|
-
<span
|
|
3780
|
+
<span
|
|
3781
|
+
class="font-mono truncate inline-block align-middle"
|
|
3782
|
+
style="max-width: 180px;"
|
|
3783
|
+
>${id}</span
|
|
3784
|
+
>
|
|
3274
3785
|
${hasValue
|
|
3275
3786
|
? html`
|
|
3276
3787
|
<span class="text-gray-300">•</span>
|
|
@@ -3279,7 +3790,11 @@ export class WebInspectorElement extends LitElement {
|
|
|
3279
3790
|
: nothing}
|
|
3280
3791
|
</div>
|
|
3281
3792
|
</div>
|
|
3282
|
-
<span
|
|
3793
|
+
<span
|
|
3794
|
+
class="shrink-0 text-gray-400 transition ${isExpanded
|
|
3795
|
+
? "rotate-180"
|
|
3796
|
+
: ""}"
|
|
3797
|
+
>
|
|
3283
3798
|
${this.renderIcon("ChevronDown")}
|
|
3284
3799
|
</span>
|
|
3285
3800
|
</div>
|
|
@@ -3290,12 +3805,17 @@ export class WebInspectorElement extends LitElement {
|
|
|
3290
3805
|
<div class="border-t border-gray-200 bg-gray-50/50 px-4 py-3">
|
|
3291
3806
|
<div class="mb-3">
|
|
3292
3807
|
<h5 class="mb-1 text-xs font-semibold text-gray-700">ID</h5>
|
|
3293
|
-
<code
|
|
3808
|
+
<code
|
|
3809
|
+
class="block rounded bg-white border border-gray-200 px-2 py-1 text-[10px] font-mono text-gray-600"
|
|
3810
|
+
>${id}</code
|
|
3811
|
+
>
|
|
3294
3812
|
</div>
|
|
3295
3813
|
${hasValue
|
|
3296
3814
|
? html`
|
|
3297
3815
|
<div class="mb-2 flex items-center justify-between gap-2">
|
|
3298
|
-
<h5 class="text-xs font-semibold text-gray-700">
|
|
3816
|
+
<h5 class="text-xs font-semibold text-gray-700">
|
|
3817
|
+
Value
|
|
3818
|
+
</h5>
|
|
3299
3819
|
<button
|
|
3300
3820
|
class="flex items-center gap-1 rounded-md border border-gray-200 bg-white px-2 py-1 text-[10px] font-medium text-gray-700 transition hover:bg-gray-50"
|
|
3301
3821
|
type="button"
|
|
@@ -3304,15 +3824,25 @@ export class WebInspectorElement extends LitElement {
|
|
|
3304
3824
|
void this.copyContextValue(context.value, id);
|
|
3305
3825
|
}}
|
|
3306
3826
|
>
|
|
3307
|
-
${this.copiedContextItems.has(id)
|
|
3827
|
+
${this.copiedContextItems.has(id)
|
|
3828
|
+
? "Copied"
|
|
3829
|
+
: "Copy JSON"}
|
|
3308
3830
|
</button>
|
|
3309
3831
|
</div>
|
|
3310
|
-
<div
|
|
3311
|
-
|
|
3832
|
+
<div
|
|
3833
|
+
class="rounded-md border border-gray-200 bg-white p-3"
|
|
3834
|
+
>
|
|
3835
|
+
<pre
|
|
3836
|
+
class="overflow-auto text-xs text-gray-800 max-h-96"
|
|
3837
|
+
><code>${this.formatContextValue(
|
|
3838
|
+
context.value,
|
|
3839
|
+
)}</code></pre>
|
|
3312
3840
|
</div>
|
|
3313
3841
|
`
|
|
3314
3842
|
: html`
|
|
3315
|
-
<div
|
|
3843
|
+
<div
|
|
3844
|
+
class="flex items-center justify-center py-4 text-xs text-gray-500"
|
|
3845
|
+
>
|
|
3316
3846
|
<span>No value available</span>
|
|
3317
3847
|
</div>
|
|
3318
3848
|
`}
|
|
@@ -3325,14 +3855,14 @@ export class WebInspectorElement extends LitElement {
|
|
|
3325
3855
|
|
|
3326
3856
|
private getContextValuePreview(value: unknown): string {
|
|
3327
3857
|
if (value === undefined || value === null) {
|
|
3328
|
-
return
|
|
3858
|
+
return "—";
|
|
3329
3859
|
}
|
|
3330
3860
|
|
|
3331
|
-
if (typeof value ===
|
|
3861
|
+
if (typeof value === "string") {
|
|
3332
3862
|
return value.length > 50 ? `${value.substring(0, 50)}...` : value;
|
|
3333
3863
|
}
|
|
3334
3864
|
|
|
3335
|
-
if (typeof value ===
|
|
3865
|
+
if (typeof value === "number" || typeof value === "boolean") {
|
|
3336
3866
|
return String(value);
|
|
3337
3867
|
}
|
|
3338
3868
|
|
|
@@ -3340,13 +3870,13 @@ export class WebInspectorElement extends LitElement {
|
|
|
3340
3870
|
return `Array(${value.length})`;
|
|
3341
3871
|
}
|
|
3342
3872
|
|
|
3343
|
-
if (typeof value ===
|
|
3873
|
+
if (typeof value === "object") {
|
|
3344
3874
|
const keys = Object.keys(value);
|
|
3345
|
-
return `Object with ${keys.length} key${keys.length !== 1 ?
|
|
3875
|
+
return `Object with ${keys.length} key${keys.length !== 1 ? "s" : ""}`;
|
|
3346
3876
|
}
|
|
3347
3877
|
|
|
3348
|
-
if (typeof value ===
|
|
3349
|
-
return
|
|
3878
|
+
if (typeof value === "function") {
|
|
3879
|
+
return "Function";
|
|
3350
3880
|
}
|
|
3351
3881
|
|
|
3352
3882
|
return String(value);
|
|
@@ -3354,14 +3884,14 @@ export class WebInspectorElement extends LitElement {
|
|
|
3354
3884
|
|
|
3355
3885
|
private formatContextValue(value: unknown): string {
|
|
3356
3886
|
if (value === undefined) {
|
|
3357
|
-
return
|
|
3887
|
+
return "undefined";
|
|
3358
3888
|
}
|
|
3359
3889
|
|
|
3360
3890
|
if (value === null) {
|
|
3361
|
-
return
|
|
3891
|
+
return "null";
|
|
3362
3892
|
}
|
|
3363
3893
|
|
|
3364
|
-
if (typeof value ===
|
|
3894
|
+
if (typeof value === "function") {
|
|
3365
3895
|
return value.toString();
|
|
3366
3896
|
}
|
|
3367
3897
|
|
|
@@ -3372,7 +3902,10 @@ export class WebInspectorElement extends LitElement {
|
|
|
3372
3902
|
}
|
|
3373
3903
|
}
|
|
3374
3904
|
|
|
3375
|
-
private async copyContextValue(
|
|
3905
|
+
private async copyContextValue(
|
|
3906
|
+
value: unknown,
|
|
3907
|
+
contextId: string,
|
|
3908
|
+
): Promise<void> {
|
|
3376
3909
|
if (typeof navigator === "undefined" || !navigator.clipboard?.writeText) {
|
|
3377
3910
|
console.warn("Clipboard API is not available in this environment.");
|
|
3378
3911
|
return;
|
|
@@ -3407,7 +3940,10 @@ export class WebInspectorElement extends LitElement {
|
|
|
3407
3940
|
}
|
|
3408
3941
|
|
|
3409
3942
|
const clickedDropdown = event.composedPath().some((node) => {
|
|
3410
|
-
return
|
|
3943
|
+
return (
|
|
3944
|
+
node instanceof HTMLElement &&
|
|
3945
|
+
node.dataset?.contextDropdownRoot === "true"
|
|
3946
|
+
);
|
|
3411
3947
|
});
|
|
3412
3948
|
|
|
3413
3949
|
if (!clickedDropdown) {
|
|
@@ -3444,9 +3980,13 @@ export class WebInspectorElement extends LitElement {
|
|
|
3444
3980
|
}
|
|
3445
3981
|
|
|
3446
3982
|
if (!this.announcementLoaded && !this.announcementMarkdown) {
|
|
3447
|
-
return html`<div
|
|
3983
|
+
return html`<div
|
|
3984
|
+
class="mx-4 my-3 rounded-xl border border-slate-200 bg-white px-4 py-3 text-sm text-slate-800 shadow-[0_12px_30px_rgba(15,23,42,0.12)]"
|
|
3985
|
+
>
|
|
3448
3986
|
<div class="flex items-center gap-2 font-semibold">
|
|
3449
|
-
<span
|
|
3987
|
+
<span
|
|
3988
|
+
class="inline-flex h-6 w-6 items-center justify-center rounded-md bg-slate-900 text-white shadow-sm"
|
|
3989
|
+
>
|
|
3450
3990
|
${this.renderIcon("Megaphone")}
|
|
3451
3991
|
</span>
|
|
3452
3992
|
<span>Loading latest announcement…</span>
|
|
@@ -3455,14 +3995,21 @@ export class WebInspectorElement extends LitElement {
|
|
|
3455
3995
|
}
|
|
3456
3996
|
|
|
3457
3997
|
if (this.announcementLoadError) {
|
|
3458
|
-
return html`<div
|
|
3998
|
+
return html`<div
|
|
3999
|
+
class="mx-4 my-3 rounded-xl border border-rose-200 bg-rose-50 px-4 py-3 text-sm text-rose-900 shadow-[0_12px_30px_rgba(15,23,42,0.12)]"
|
|
4000
|
+
>
|
|
3459
4001
|
<div class="flex items-center gap-2 font-semibold">
|
|
3460
|
-
<span
|
|
4002
|
+
<span
|
|
4003
|
+
class="inline-flex h-6 w-6 items-center justify-center rounded-md bg-rose-600 text-white shadow-sm"
|
|
4004
|
+
>
|
|
3461
4005
|
${this.renderIcon("Megaphone")}
|
|
3462
4006
|
</span>
|
|
3463
4007
|
<span>Announcement unavailable</span>
|
|
3464
4008
|
</div>
|
|
3465
|
-
<p class="mt-2 text-xs text-rose-800">
|
|
4009
|
+
<p class="mt-2 text-xs text-rose-800">
|
|
4010
|
+
We couldn’t load the latest notice. Please try opening the inspector
|
|
4011
|
+
again.
|
|
4012
|
+
</p>
|
|
3466
4013
|
</div>`;
|
|
3467
4014
|
}
|
|
3468
4015
|
|
|
@@ -3472,35 +4019,59 @@ export class WebInspectorElement extends LitElement {
|
|
|
3472
4019
|
|
|
3473
4020
|
const content = this.announcementHtml
|
|
3474
4021
|
? unsafeHTML(this.announcementHtml)
|
|
3475
|
-
: html`<pre class="whitespace-pre-wrap text-sm text-gray-900"
|
|
4022
|
+
: html`<pre class="whitespace-pre-wrap text-sm text-gray-900">
|
|
4023
|
+
${this.announcementMarkdown}</pre
|
|
4024
|
+
>`;
|
|
3476
4025
|
|
|
3477
|
-
return html`<div
|
|
3478
|
-
|
|
3479
|
-
|
|
4026
|
+
return html`<div
|
|
4027
|
+
class="mx-4 my-3 rounded-xl border border-slate-200 bg-white px-4 py-4 shadow-[0_12px_30px_rgba(15,23,42,0.12)]"
|
|
4028
|
+
>
|
|
4029
|
+
<div
|
|
4030
|
+
class="mb-3 flex items-center gap-2 text-sm font-semibold text-slate-900"
|
|
4031
|
+
>
|
|
4032
|
+
<span
|
|
4033
|
+
class="inline-flex h-7 w-7 items-center justify-center rounded-md bg-slate-900 text-white shadow-sm"
|
|
4034
|
+
>
|
|
3480
4035
|
${this.renderIcon("Megaphone")}
|
|
3481
4036
|
</span>
|
|
3482
4037
|
<span>Announcement</span>
|
|
3483
|
-
<button
|
|
4038
|
+
<button
|
|
4039
|
+
class="announcement-dismiss ml-auto"
|
|
4040
|
+
type="button"
|
|
4041
|
+
@click=${this.handleDismissAnnouncement}
|
|
4042
|
+
aria-label="Dismiss announcement"
|
|
4043
|
+
>
|
|
3484
4044
|
Dismiss
|
|
3485
4045
|
</button>
|
|
3486
4046
|
</div>
|
|
3487
|
-
<div class="announcement-content text-sm leading-relaxed text-gray-900"
|
|
4047
|
+
<div class="announcement-content text-sm leading-relaxed text-gray-900">
|
|
4048
|
+
${content}
|
|
4049
|
+
</div>
|
|
3488
4050
|
</div>`;
|
|
3489
4051
|
}
|
|
3490
4052
|
|
|
3491
4053
|
private ensureAnnouncementLoading(): void {
|
|
3492
|
-
if (
|
|
4054
|
+
if (
|
|
4055
|
+
this.announcementPromise ||
|
|
4056
|
+
typeof window === "undefined" ||
|
|
4057
|
+
typeof fetch === "undefined"
|
|
4058
|
+
) {
|
|
3493
4059
|
return;
|
|
3494
4060
|
}
|
|
3495
4061
|
this.announcementPromise = this.fetchAnnouncement();
|
|
3496
4062
|
}
|
|
3497
4063
|
|
|
3498
4064
|
private renderAnnouncementPreview() {
|
|
3499
|
-
if (
|
|
4065
|
+
if (
|
|
4066
|
+
!this.hasUnseenAnnouncement ||
|
|
4067
|
+
!this.showAnnouncementPreview ||
|
|
4068
|
+
!this.announcementPreviewText
|
|
4069
|
+
) {
|
|
3500
4070
|
return nothing;
|
|
3501
4071
|
}
|
|
3502
4072
|
|
|
3503
|
-
const side =
|
|
4073
|
+
const side =
|
|
4074
|
+
this.contextState.button.anchor.horizontal === "left" ? "right" : "left";
|
|
3504
4075
|
|
|
3505
4076
|
return html`<div
|
|
3506
4077
|
class="announcement-preview"
|
|
@@ -3535,9 +4106,12 @@ export class WebInspectorElement extends LitElement {
|
|
|
3535
4106
|
announcement?: unknown;
|
|
3536
4107
|
};
|
|
3537
4108
|
|
|
3538
|
-
const timestamp =
|
|
3539
|
-
|
|
3540
|
-
const
|
|
4109
|
+
const timestamp =
|
|
4110
|
+
typeof data?.timestamp === "string" ? data.timestamp : null;
|
|
4111
|
+
const previewText =
|
|
4112
|
+
typeof data?.previewText === "string" ? data.previewText : null;
|
|
4113
|
+
const markdown =
|
|
4114
|
+
typeof data?.announcement === "string" ? data.announcement : null;
|
|
3541
4115
|
|
|
3542
4116
|
if (!timestamp || !markdown) {
|
|
3543
4117
|
throw new Error("Malformed announcement payload");
|
|
@@ -3548,7 +4122,9 @@ export class WebInspectorElement extends LitElement {
|
|
|
3548
4122
|
this.announcementTimestamp = timestamp;
|
|
3549
4123
|
this.announcementPreviewText = previewText ?? "";
|
|
3550
4124
|
this.announcementMarkdown = markdown;
|
|
3551
|
-
this.hasUnseenAnnouncement =
|
|
4125
|
+
this.hasUnseenAnnouncement =
|
|
4126
|
+
(!storedTimestamp || storedTimestamp !== timestamp) &&
|
|
4127
|
+
!!this.announcementPreviewText;
|
|
3552
4128
|
this.showAnnouncementPreview = this.hasUnseenAnnouncement;
|
|
3553
4129
|
this.announcementHtml = await this.convertMarkdownToHtml(markdown);
|
|
3554
4130
|
this.announcementLoaded = true;
|
|
@@ -3561,7 +4137,9 @@ export class WebInspectorElement extends LitElement {
|
|
|
3561
4137
|
}
|
|
3562
4138
|
}
|
|
3563
4139
|
|
|
3564
|
-
private async convertMarkdownToHtml(
|
|
4140
|
+
private async convertMarkdownToHtml(
|
|
4141
|
+
markdown: string,
|
|
4142
|
+
): Promise<string | null> {
|
|
3565
4143
|
const renderer = new marked.Renderer();
|
|
3566
4144
|
renderer.link = (href, title, text) => {
|
|
3567
4145
|
const safeHref = this.escapeHtmlAttr(this.appendRefParam(href ?? ""));
|
|
@@ -3573,7 +4151,12 @@ export class WebInspectorElement extends LitElement {
|
|
|
3573
4151
|
|
|
3574
4152
|
private appendRefParam(href: string): string {
|
|
3575
4153
|
try {
|
|
3576
|
-
const url = new URL(
|
|
4154
|
+
const url = new URL(
|
|
4155
|
+
href,
|
|
4156
|
+
typeof window !== "undefined"
|
|
4157
|
+
? window.location.href
|
|
4158
|
+
: "https://copilotkit.ai",
|
|
4159
|
+
);
|
|
3577
4160
|
if (!url.searchParams.has("ref")) {
|
|
3578
4161
|
url.searchParams.append("ref", "cpk-inspector");
|
|
3579
4162
|
}
|
|
@@ -3633,7 +4216,9 @@ export class WebInspectorElement extends LitElement {
|
|
|
3633
4216
|
if (!this.announcementTimestamp) {
|
|
3634
4217
|
// If still loading, attempt once more after promise resolves; avoid infinite requeues
|
|
3635
4218
|
if (this.announcementPromise && !this.announcementLoaded) {
|
|
3636
|
-
void this.announcementPromise
|
|
4219
|
+
void this.announcementPromise
|
|
4220
|
+
.then(() => this.markAnnouncementSeen())
|
|
4221
|
+
.catch(() => undefined);
|
|
3637
4222
|
}
|
|
3638
4223
|
this.requestUpdate();
|
|
3639
4224
|
return;
|