@tonyclaw/agent-inspector 3.0.24 → 3.0.26
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/.output/nitro.json +1 -1
- package/.output/public/assets/{CompareDrawer-BC52FYwn.js → CompareDrawer-SZRUDQc9.js} +1 -1
- package/.output/public/assets/ProxyViewerContainer-BJvwOrSi.js +4234 -0
- package/.output/public/assets/{ReplayDialog-BcKsarKt.js → ReplayDialog-DgfmqiM3.js} +1 -1
- package/.output/public/assets/{RequestAnatomy-DR0uGpCj.js → RequestAnatomy-CS6c7Qfn.js} +1 -1
- package/.output/public/assets/{ResponseView-kxAAPfmn.js → ResponseView-C0Ri_5gm.js} +2 -2
- package/.output/public/assets/{StreamingChunkSequence-YQR0PjQj.js → StreamingChunkSequence-7dYcHWyZ.js} +1 -1
- package/.output/public/assets/{_sessionId-DRl-Y9om.js → _sessionId-D-V84cgw.js} +1 -1
- package/.output/public/assets/{index-CQbrc-hi.js → index-CSIL7-MK.js} +3 -3
- package/.output/public/assets/index-CmeF5XXS.css +1 -0
- package/.output/public/assets/{index-CcSIBI4L.js → index-DgFWCxOs.js} +1 -1
- package/.output/public/assets/{index-ZrMgyEZV.js → index-DrVJsks2.js} +1 -1
- package/.output/public/assets/{json-viewer-CS5pwnEA.js → json-viewer-C9Ji3gYN.js} +1 -1
- package/.output/server/_libs/lucide-react.mjs +245 -217
- package/.output/server/_libs/three.mjs +26016 -0
- package/.output/server/{_sessionId-BLk2xPkR.mjs → _sessionId-BQ6YQOO1.mjs} +7 -6
- package/.output/server/_ssr/{CompareDrawer-Cw7Dseo3.mjs → CompareDrawer-CqNzIeMR.mjs} +8 -7
- package/.output/server/_ssr/{ProxyViewerContainer-D8SB0zyQ.mjs → ProxyViewerContainer-CMC7Vsbw.mjs} +1164 -405
- package/.output/server/_ssr/{ReplayDialog-B-YMhZkE.mjs → ReplayDialog-D9p_LaTr.mjs} +9 -8
- package/.output/server/_ssr/{RequestAnatomy-a9d8UTYZ.mjs → RequestAnatomy-B4ge3qNZ.mjs} +8 -7
- package/.output/server/_ssr/{ResponseView-PzaZS4CN.mjs → ResponseView-BCqMKApI.mjs} +8 -7
- package/.output/server/_ssr/{StreamingChunkSequence-C21_TCXk.mjs → StreamingChunkSequence-BA4zTLE4.mjs} +8 -7
- package/.output/server/_ssr/{index-CrCeNP7H.mjs → index-CzxhDjlq.mjs} +7 -6
- package/.output/server/_ssr/index.mjs +2 -2
- package/.output/server/_ssr/{json-viewer-Di2gxs9H.mjs → json-viewer-B3qV6iEJ.mjs} +8 -7
- package/.output/server/_ssr/{router-BJzdUbcH.mjs → router-CZe_R31M.mjs} +4 -4
- package/.output/server/{_tanstack-start-manifest_v-CGBTdAYC.mjs → _tanstack-start-manifest_v-B50VTLrH.mjs} +1 -1
- package/.output/server/index.mjs +68 -68
- package/package.json +3 -1
- package/src/components/ProxyViewer.tsx +2 -280
- package/src/components/inspector-pet/InspectorPet.tsx +405 -0
- package/src/components/inspector-pet/InspectorPetCrab3D.tsx +455 -0
- package/src/components/inspector-pet/inspectorPetLogic.ts +258 -0
- package/src/components/providers/ProviderForm.tsx +238 -163
- package/src/components/providers/ProvidersPanel.tsx +16 -6
- package/src/components/providers/providerFormCapabilities.ts +36 -0
- package/styles/globals.css +64 -28
- package/.output/public/assets/ProxyViewerContainer-WuChOrSS.js +0 -127
- package/.output/public/assets/index-DQeXi4Rv.css +0 -1
package/.output/server/_ssr/{ProxyViewerContainer-D8SB0zyQ.mjs → ProxyViewerContainer-CMC7Vsbw.mjs}
RENAMED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { r as reactExports, j as jsxRuntimeExports, R as React } from "../_libs/react.mjs";
|
|
2
|
-
import { C as CapturedLogSchema, z as DeleteInspectorGroupsResponseSchema, D as DEFAULT_CAPTURE_MODE, a as DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS, b as DEFAULT_PROVIDER_TEST_TIMEOUT_SECONDS, c as DEFAULT_TIME_DISPLAY_FORMAT, d as RuntimeConfigSchema, g as readStoredUiScalePreference, h as persistUiScalePreference, i as applyUiScalePreference, w as extractStopReason, p as packageJson, P as ProviderConfigSchema, U as UI_SCALE_STORAGE_KEY, j as normalizeUiScalePreference, q as apiFormatForPath, B as GroupEvidenceExportResultSchema, E as DeleteInspectorGroupResponseSchema, $ as PiAgentResponseSchema, v as isTurnBoundary, r as readStoredThemeMode, e as applyThemeMode, f as persistThemeMode, a2 as formatUiScale, x as AlertSummarySchema, y as AlertListResponseSchema, I as InspectorGroupsListResponseSchema, G as GroupEvidenceReadResponseSchema, V as createPendingProviderTestResults, W as ProviderTestResultsSchema, X as createFailedProviderTestResults, Y as MAX_SLOW_RESPONSE_THRESHOLD_SECONDS, Z as MAX_PROVIDER_TEST_TIMEOUT_SECONDS, _ as TimeDisplayFormatSchema, T as THEME_MODE_STORAGE_KEY, n as normalizeThemeMode,
|
|
2
|
+
import { C as CapturedLogSchema, z as DeleteInspectorGroupsResponseSchema, D as DEFAULT_CAPTURE_MODE, a as DEFAULT_SLOW_RESPONSE_THRESHOLD_SECONDS, b as DEFAULT_PROVIDER_TEST_TIMEOUT_SECONDS, c as DEFAULT_TIME_DISPLAY_FORMAT, d as RuntimeConfigSchema, g as readStoredUiScalePreference, h as persistUiScalePreference, i as applyUiScalePreference, w as extractStopReason, p as packageJson, P as ProviderConfigSchema, U as UI_SCALE_STORAGE_KEY, j as normalizeUiScalePreference, q as apiFormatForPath, B as GroupEvidenceExportResultSchema, E as DeleteInspectorGroupResponseSchema, $ as PiAgentResponseSchema, v as isTurnBoundary, r as readStoredThemeMode, e as applyThemeMode, f as persistThemeMode, a2 as formatUiScale, x as AlertSummarySchema, y as AlertListResponseSchema, I as InspectorGroupsListResponseSchema, G as GroupEvidenceReadResponseSchema, V as createPendingProviderTestResults, W as ProviderTestResultsSchema, X as createFailedProviderTestResults, Y as MAX_SLOW_RESPONSE_THRESHOLD_SECONDS, Z as MAX_PROVIDER_TEST_TIMEOUT_SECONDS, _ as TimeDisplayFormatSchema, T as THEME_MODE_STORAGE_KEY, n as normalizeThemeMode, M as PATH_V1_MESSAGES, N as PATH_V1_CHAT_COMPLETIONS, Q as PATH_V1_RESPONSES, H as maskApiKey, F as providerHasContextMetadata, l as parseOpenAIResponse, m as parseOpenAIResponsesResponse, O as OpenAIRequestSchema, o as OpenAIResponsesRequestSchema, A as AnthropicResponseSchema$1, k as AnthropicRequestSchema, s as safeGetOwnProperty, a0 as resolveProviderContextWindow, t as getSessionPath, J as findProviderModelMetadata, S as previewUpstreamUrl, K as KnowledgeCandidateSchema, a1 as isPlainRecord, u as stripClaudeCodeBillingHeader, L as LogBodyChunkSchema } from "./router-CZe_R31M.mjs";
|
|
3
3
|
import { u as useSWR, a as useSWRConfig } from "../_libs/swr.mjs";
|
|
4
4
|
import { J as JSZip } from "../_libs/jszip.mjs";
|
|
5
5
|
import { c as clsx } from "../_libs/clsx.mjs";
|
|
@@ -7,7 +7,9 @@ import { t as twMerge } from "../_libs/tailwind-merge.mjs";
|
|
|
7
7
|
import { c as cva } from "../_libs/class-variance-authority.mjs";
|
|
8
8
|
import { u as useWindowVirtualizer, a as useVirtualizer } from "../_libs/tanstack__react-virtual.mjs";
|
|
9
9
|
import { d as diffJson, a as diffLines } from "../_libs/diff.mjs";
|
|
10
|
-
import {
|
|
10
|
+
import { r as reactDomExports } from "../_libs/react-dom.mjs";
|
|
11
|
+
import { W as WebGLRenderer, S as SRGBColorSpace, A as ACESFilmicToneMapping, a as Scene, O as OrthographicCamera, M as MeshPhysicalMaterial, C as Color, G as Group, b as Mesh, c as CircleGeometry, d as MeshBasicMaterial, e as SphereGeometry, f as AmbientLight, H as HemisphereLight, D as DirectionalLight, P as PointLight, V as Vector3, g as CylinderGeometry } from "../_libs/three.mjs";
|
|
12
|
+
import { T as TriangleAlert, C as CircleCheck, X, I as Info, a as ChevronDown, b as Check, P as PanelRightOpen, c as PanelRightClose, S as Search, U as Upload, D as Download, F as FileBraces, R as RefreshCw, d as Trash2, H as Heart, e as Pause, f as Play, g as Plus, B as BrainCircuit, L as LoaderCircle, h as Send, A as ArrowLeft, i as ChevronUp, j as Copy, k as ChevronsLeft, l as ChevronLeft, m as ChevronRight, n as ChevronsRight, o as Clapperboard, p as Flag, q as Siren, r as Timer, G as Gauge, s as Sun, E as Eye, M as Moon, t as ALargeSmall, u as Layers, v as FlaskConical, w as Sparkles, x as Activity, y as Beaker, N as Network, z as Terminal, J as Settings, K as Monitor, O as Rocket, Q as PackageCheck, V as History, W as Scan, Y as CircleAlert, Z as ArrowUpRight, _ as ArrowDownRight, $ as Cpu, a0 as FolderOpen, a1 as Bell, a2 as Clock3, a3 as ShieldAlert, a4 as EyeOff, a5 as ExternalLink, a6 as Clock, a7 as RotateCw, a8 as Pencil, a9 as MessageSquare, aa as Zap, ab as Wrench, ac as Brain, ad as CircleCheckBig, ae as Minus, af as CircleX, ag as ShieldCheck, ah as Save, ai as FileSearch, aj as CloudUpload, ak as CircleQuestionMark, al as Server, am as Lock, an as Wifi, ao as WifiOff, ap as OctagonAlert, aq as Radio, ar as Globe, as as FileTerminal, at as ChevronsUp, au as ChevronsDown, av as FileDiff, aw as RotateCcw, ax as GitCompareArrows, ay as ArrowUp, az as ArrowDown, aA as Ellipsis, aB as CodeXml, aC as Blocks, aD as MousePointerClick, aE as FileText, aF as Rows3, aG as Columns2 } from "../_libs/lucide-react.mjs";
|
|
11
13
|
import { u as union, o as object, e as array, l as literal, n as number, d as boolean, b as string, _ as _enum } from "../_libs/zod.mjs";
|
|
12
14
|
import { S as Select$1, a as SelectTrigger$1, b as SelectIcon, c as SelectValue$1, d as SelectPortal, e as SelectContent$1, f as SelectViewport, g as SelectItem$1, h as SelectItemIndicator, i as SelectItemText, j as SelectScrollUpButton$1, k as SelectScrollDownButton$1 } from "../_libs/radix-ui__react-select.mjs";
|
|
13
15
|
import { D as Dialog$1, a as DialogContent$1, b as DialogClose, c as DialogTitle$1, d as DialogDescription$1, e as DialogPortal$1, f as DialogOverlay$1, g as DialogTrigger$1 } from "../_libs/radix-ui__react-dialog.mjs";
|
|
@@ -2525,27 +2527,27 @@ function useCopyFeedback(text) {
|
|
|
2525
2527
|
return { copied, copy };
|
|
2526
2528
|
}
|
|
2527
2529
|
const LazyCompareDrawer = reactExports.lazy(
|
|
2528
|
-
() => import("./CompareDrawer-
|
|
2530
|
+
() => import("./CompareDrawer-CqNzIeMR.mjs").then((m) => ({ default: m.CompareDrawer }))
|
|
2529
2531
|
);
|
|
2530
2532
|
const LazyReplayDialog = reactExports.lazy(
|
|
2531
|
-
() => import("./ReplayDialog-
|
|
2533
|
+
() => import("./ReplayDialog-D9p_LaTr.mjs").then((m) => ({ default: m.ReplayDialog }))
|
|
2532
2534
|
);
|
|
2533
2535
|
const LazyRequestAnatomy = reactExports.lazy(
|
|
2534
|
-
() => import("./RequestAnatomy-
|
|
2536
|
+
() => import("./RequestAnatomy-B4ge3qNZ.mjs").then((m) => ({ default: m.RequestAnatomy }))
|
|
2535
2537
|
);
|
|
2536
2538
|
const LazyResponseView = reactExports.lazy(
|
|
2537
|
-
() => import("./ResponseView-
|
|
2539
|
+
() => import("./ResponseView-BCqMKApI.mjs").then((m) => ({ default: m.ResponseView }))
|
|
2538
2540
|
);
|
|
2539
2541
|
const LazyStreamingChunkSequence = reactExports.lazy(
|
|
2540
|
-
() => import("./StreamingChunkSequence-
|
|
2542
|
+
() => import("./StreamingChunkSequence-BA4zTLE4.mjs").then((m) => ({
|
|
2541
2543
|
default: m.StreamingChunkSequence
|
|
2542
2544
|
}))
|
|
2543
2545
|
);
|
|
2544
2546
|
const LazyJsonViewer = reactExports.lazy(
|
|
2545
|
-
() => import("./json-viewer-
|
|
2547
|
+
() => import("./json-viewer-B3qV6iEJ.mjs").then((m) => ({ default: m.JsonViewer }))
|
|
2546
2548
|
);
|
|
2547
2549
|
const LazyJsonViewerFromString = reactExports.lazy(
|
|
2548
|
-
() => import("./json-viewer-
|
|
2550
|
+
() => import("./json-viewer-B3qV6iEJ.mjs").then((m) => ({ default: m.JsonViewerFromString }))
|
|
2549
2551
|
);
|
|
2550
2552
|
const HIGHLIGHT_DURATION_MS = 1200;
|
|
2551
2553
|
const MAX_HIGHLIGHT_ATTEMPTS = 12;
|
|
@@ -8935,7 +8937,7 @@ function ProviderTestPill({
|
|
|
8935
8937
|
testResults,
|
|
8936
8938
|
isTesting
|
|
8937
8939
|
}) {
|
|
8938
|
-
const
|
|
8940
|
+
const hasEndpoint2 = providerHasEndpoint$1(provider.anthropicBaseUrl) || providerHasEndpoint$1(provider.openaiBaseUrl) || providerHasEndpoint$1(provider.openaiResponsesBaseUrl);
|
|
8939
8941
|
const summary = summarizeProviderTestResults(provider, testResults);
|
|
8940
8942
|
if (isTesting) {
|
|
8941
8943
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "inline-flex items-center gap-1 rounded border border-cyan-300/25 bg-cyan-300/[0.08] px-2 py-1 text-xs text-cyan-100", children: [
|
|
@@ -8943,7 +8945,7 @@ function ProviderTestPill({
|
|
|
8943
8945
|
"Testing"
|
|
8944
8946
|
] });
|
|
8945
8947
|
}
|
|
8946
|
-
if (!
|
|
8948
|
+
if (!hasEndpoint2) {
|
|
8947
8949
|
return /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "rounded border border-border/70 bg-muted/20 px-2 py-1 text-xs text-muted-foreground", children: "No endpoint" });
|
|
8948
8950
|
}
|
|
8949
8951
|
if (testResults === void 0 || summary.total === 0) {
|
|
@@ -9254,6 +9256,25 @@ function ProviderCard({
|
|
|
9254
9256
|
}
|
|
9255
9257
|
);
|
|
9256
9258
|
}
|
|
9259
|
+
function hasEndpoint(value) {
|
|
9260
|
+
return value !== void 0 && value.trim() !== "";
|
|
9261
|
+
}
|
|
9262
|
+
function deriveProviderCapabilities(provider) {
|
|
9263
|
+
const anthropic = hasEndpoint(provider?.anthropicBaseUrl);
|
|
9264
|
+
const openaiChat = hasEndpoint(provider?.openaiBaseUrl);
|
|
9265
|
+
const openaiResponses = hasEndpoint(provider?.openaiResponsesBaseUrl);
|
|
9266
|
+
return {
|
|
9267
|
+
anthropic,
|
|
9268
|
+
openai: openaiChat || openaiResponses,
|
|
9269
|
+
openaiChat,
|
|
9270
|
+
openaiResponses
|
|
9271
|
+
};
|
|
9272
|
+
}
|
|
9273
|
+
function endpointForCapability(enabled, value, clearWhenDisabled) {
|
|
9274
|
+
if (!enabled) return clearWhenDisabled ? "" : void 0;
|
|
9275
|
+
const trimmed = value.trim();
|
|
9276
|
+
return trimmed === "" ? void 0 : trimmed;
|
|
9277
|
+
}
|
|
9257
9278
|
const ZHIPU_PROVIDER_KEYWORDS = ["zhipu", "zhipuai", "bigmodel", "z.ai", "zai", "glm"];
|
|
9258
9279
|
const ZHIPU_CODING_PROVIDER_KEYWORDS = [
|
|
9259
9280
|
"zhipu coding",
|
|
@@ -9477,6 +9498,7 @@ function EndpointUrlPreview({
|
|
|
9477
9498
|
] });
|
|
9478
9499
|
}
|
|
9479
9500
|
function ProviderForm({ provider, onSubmit, onCancel }) {
|
|
9501
|
+
const initialCapabilities = deriveProviderCapabilities(provider);
|
|
9480
9502
|
const [name, setName] = reactExports.useState(provider?.name ?? "");
|
|
9481
9503
|
const [apiKey, setApiKey] = reactExports.useState(provider?.apiKey ?? "");
|
|
9482
9504
|
const [showApiKey, setShowApiKey] = reactExports.useState(false);
|
|
@@ -9491,7 +9513,12 @@ function ProviderForm({ provider, onSubmit, onCancel }) {
|
|
|
9491
9513
|
initialModels !== void 0 && initialModels.length > 0 ? initialModels : [""]
|
|
9492
9514
|
)
|
|
9493
9515
|
);
|
|
9494
|
-
const [
|
|
9516
|
+
const [supportsAnthropic, setSupportsAnthropic] = reactExports.useState(initialCapabilities.anthropic);
|
|
9517
|
+
const [supportsOpenai, setSupportsOpenai] = reactExports.useState(initialCapabilities.openai);
|
|
9518
|
+
const [supportsOpenaiChat, setSupportsOpenaiChat] = reactExports.useState(initialCapabilities.openaiChat);
|
|
9519
|
+
const [supportsOpenaiResponses, setSupportsOpenaiResponses] = reactExports.useState(
|
|
9520
|
+
initialCapabilities.openaiResponses
|
|
9521
|
+
);
|
|
9495
9522
|
const [anthropicBaseUrl, setAnthropicBaseUrl] = reactExports.useState(
|
|
9496
9523
|
stripEndpointSuffix(provider?.anthropicBaseUrl, ANTHROPIC_MESSAGES_ENDPOINT)
|
|
9497
9524
|
);
|
|
@@ -9545,6 +9572,11 @@ function ProviderForm({ provider, onSubmit, onCancel }) {
|
|
|
9545
9572
|
const nextModels = (provider.models?.length ?? 0) > 0 ? provider.models : [""];
|
|
9546
9573
|
setModels(nextModels);
|
|
9547
9574
|
setModelMetadataDrafts(createMetadataDrafts(provider, nextModels));
|
|
9575
|
+
const nextCapabilities = deriveProviderCapabilities(provider);
|
|
9576
|
+
setSupportsAnthropic(nextCapabilities.anthropic);
|
|
9577
|
+
setSupportsOpenai(nextCapabilities.openai);
|
|
9578
|
+
setSupportsOpenaiChat(nextCapabilities.openaiChat);
|
|
9579
|
+
setSupportsOpenaiResponses(nextCapabilities.openaiResponses);
|
|
9548
9580
|
setAnthropicBaseUrl(
|
|
9549
9581
|
stripEndpointSuffix(provider.anthropicBaseUrl, ANTHROPIC_MESSAGES_ENDPOINT)
|
|
9550
9582
|
);
|
|
@@ -9602,14 +9634,32 @@ function ProviderForm({ provider, onSubmit, onCancel }) {
|
|
|
9602
9634
|
if (models.length === 0 || models.every((m) => !m.trim())) {
|
|
9603
9635
|
newErrors.models = "At least one model is required";
|
|
9604
9636
|
}
|
|
9605
|
-
if (
|
|
9606
|
-
newErrors.
|
|
9637
|
+
if (!supportsAnthropic && !supportsOpenai) {
|
|
9638
|
+
newErrors.capabilities = "Select at least one API capability";
|
|
9607
9639
|
}
|
|
9608
|
-
if (
|
|
9609
|
-
newErrors.
|
|
9640
|
+
if (supportsOpenai && !supportsOpenaiChat && !supportsOpenaiResponses) {
|
|
9641
|
+
newErrors.openaiCapabilities = "Select Chat Completions, Responses, or both";
|
|
9610
9642
|
}
|
|
9611
|
-
if (
|
|
9612
|
-
|
|
9643
|
+
if (supportsAnthropic) {
|
|
9644
|
+
if (anthropicBaseUrl.trim() === "") {
|
|
9645
|
+
newErrors.anthropicBaseUrl = "Anthropic base URL is required";
|
|
9646
|
+
} else if (!isValidUrl(anthropicBaseUrl.trim())) {
|
|
9647
|
+
newErrors.anthropicBaseUrl = "Invalid URL format";
|
|
9648
|
+
}
|
|
9649
|
+
}
|
|
9650
|
+
if (supportsOpenai && supportsOpenaiChat) {
|
|
9651
|
+
if (openaiBaseUrl.trim() === "") {
|
|
9652
|
+
newErrors.openaiBaseUrl = "OpenAI Chat base URL is required";
|
|
9653
|
+
} else if (!isValidUrl(openaiBaseUrl.trim())) {
|
|
9654
|
+
newErrors.openaiBaseUrl = "Invalid URL format";
|
|
9655
|
+
}
|
|
9656
|
+
}
|
|
9657
|
+
if (supportsOpenai && supportsOpenaiResponses) {
|
|
9658
|
+
if (openaiResponsesBaseUrl.trim() === "") {
|
|
9659
|
+
newErrors.openaiResponsesBaseUrl = "OpenAI Responses base URL is required";
|
|
9660
|
+
} else if (!isValidUrl(openaiResponsesBaseUrl.trim())) {
|
|
9661
|
+
newErrors.openaiResponsesBaseUrl = "Invalid URL format";
|
|
9662
|
+
}
|
|
9613
9663
|
}
|
|
9614
9664
|
if (modelMetadataUrl.trim() && !isValidUrl(modelMetadataUrl.trim())) {
|
|
9615
9665
|
newErrors.modelMetadataUrl = "Invalid URL format";
|
|
@@ -9627,9 +9677,6 @@ function ProviderForm({ provider, onSubmit, onCancel }) {
|
|
|
9627
9677
|
newErrors[`modelMetadata.${index}.outputLimit`] = "Output limit should not exceed context window";
|
|
9628
9678
|
}
|
|
9629
9679
|
});
|
|
9630
|
-
if (!anthropicBaseUrl.trim() && !openaiBaseUrl.trim() && !openaiResponsesBaseUrl.trim()) {
|
|
9631
|
-
newErrors.format = "At least one format URL (Anthropic or OpenAI) is required";
|
|
9632
|
-
}
|
|
9633
9680
|
setErrors(newErrors);
|
|
9634
9681
|
return Object.keys(newErrors).length === 0;
|
|
9635
9682
|
}
|
|
@@ -9736,14 +9783,27 @@ function ProviderForm({ provider, onSubmit, onCancel }) {
|
|
|
9736
9783
|
e.preventDefault();
|
|
9737
9784
|
if (!validate()) return;
|
|
9738
9785
|
setIsSubmitting(true);
|
|
9786
|
+
const clearDisabledEndpoints = provider !== void 0;
|
|
9739
9787
|
try {
|
|
9740
9788
|
onSubmit({
|
|
9741
9789
|
name: name.trim(),
|
|
9742
9790
|
apiKey: apiKey.trim(),
|
|
9743
9791
|
models: models.map((m) => m.trim()).filter((m) => m !== ""),
|
|
9744
|
-
anthropicBaseUrl:
|
|
9745
|
-
|
|
9746
|
-
|
|
9792
|
+
anthropicBaseUrl: endpointForCapability(
|
|
9793
|
+
supportsAnthropic,
|
|
9794
|
+
anthropicBaseUrl,
|
|
9795
|
+
clearDisabledEndpoints
|
|
9796
|
+
),
|
|
9797
|
+
openaiBaseUrl: endpointForCapability(
|
|
9798
|
+
supportsOpenai && supportsOpenaiChat,
|
|
9799
|
+
openaiBaseUrl,
|
|
9800
|
+
clearDisabledEndpoints
|
|
9801
|
+
),
|
|
9802
|
+
openaiResponsesBaseUrl: endpointForCapability(
|
|
9803
|
+
supportsOpenai && supportsOpenaiResponses,
|
|
9804
|
+
openaiResponsesBaseUrl,
|
|
9805
|
+
clearDisabledEndpoints
|
|
9806
|
+
),
|
|
9747
9807
|
apiDocsUrl: apiDocsUrl.trim() || void 0,
|
|
9748
9808
|
modelMetadataUrl: modelMetadataUrl.trim() || void 0,
|
|
9749
9809
|
modelMetadata: buildModelMetadata(),
|
|
@@ -9772,6 +9832,205 @@ function ProviderForm({ provider, onSubmit, onCancel }) {
|
|
|
9772
9832
|
),
|
|
9773
9833
|
errors.name !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-destructive", children: errors.name })
|
|
9774
9834
|
] }),
|
|
9835
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("fieldset", { className: "space-y-3", children: [
|
|
9836
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("legend", { className: "text-sm font-medium", children: [
|
|
9837
|
+
"Capabilities ",
|
|
9838
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-destructive", children: "*" })
|
|
9839
|
+
] }),
|
|
9840
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "divide-y divide-border overflow-hidden rounded-md border border-border", children: [
|
|
9841
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: supportsOpenai ? "bg-primary/[0.04] px-3 py-3" : "px-3 py-3", children: [
|
|
9842
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
9843
|
+
"label",
|
|
9844
|
+
{
|
|
9845
|
+
htmlFor: "provider-capability-openai",
|
|
9846
|
+
className: "flex cursor-pointer items-start gap-3",
|
|
9847
|
+
children: [
|
|
9848
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
9849
|
+
"input",
|
|
9850
|
+
{
|
|
9851
|
+
id: "provider-capability-openai",
|
|
9852
|
+
type: "checkbox",
|
|
9853
|
+
checked: supportsOpenai,
|
|
9854
|
+
onChange: (event) => setSupportsOpenai(event.target.checked),
|
|
9855
|
+
className: "mt-0.5 size-4 shrink-0 accent-primary"
|
|
9856
|
+
}
|
|
9857
|
+
),
|
|
9858
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "min-w-0", children: [
|
|
9859
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "block text-sm font-medium", children: "OpenAI" }),
|
|
9860
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "block text-xs text-muted-foreground", children: "Chat Completions and Responses" })
|
|
9861
|
+
] })
|
|
9862
|
+
]
|
|
9863
|
+
}
|
|
9864
|
+
),
|
|
9865
|
+
supportsOpenai && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "ml-7 mt-3 flex flex-wrap gap-x-5 gap-y-2 border-t border-border/70 pt-3", children: [
|
|
9866
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
9867
|
+
"label",
|
|
9868
|
+
{
|
|
9869
|
+
htmlFor: "provider-capability-openai-chat",
|
|
9870
|
+
className: "flex cursor-pointer items-center gap-2 text-sm",
|
|
9871
|
+
children: [
|
|
9872
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
9873
|
+
"input",
|
|
9874
|
+
{
|
|
9875
|
+
id: "provider-capability-openai-chat",
|
|
9876
|
+
type: "checkbox",
|
|
9877
|
+
checked: supportsOpenaiChat,
|
|
9878
|
+
onChange: (event) => setSupportsOpenaiChat(event.target.checked),
|
|
9879
|
+
className: "size-4 shrink-0 accent-primary"
|
|
9880
|
+
}
|
|
9881
|
+
),
|
|
9882
|
+
"Chat Completions"
|
|
9883
|
+
]
|
|
9884
|
+
}
|
|
9885
|
+
),
|
|
9886
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
9887
|
+
"label",
|
|
9888
|
+
{
|
|
9889
|
+
htmlFor: "provider-capability-openai-responses",
|
|
9890
|
+
className: "flex cursor-pointer items-center gap-2 text-sm",
|
|
9891
|
+
children: [
|
|
9892
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
9893
|
+
"input",
|
|
9894
|
+
{
|
|
9895
|
+
id: "provider-capability-openai-responses",
|
|
9896
|
+
type: "checkbox",
|
|
9897
|
+
checked: supportsOpenaiResponses,
|
|
9898
|
+
onChange: (event) => setSupportsOpenaiResponses(event.target.checked),
|
|
9899
|
+
className: "size-4 shrink-0 accent-primary"
|
|
9900
|
+
}
|
|
9901
|
+
),
|
|
9902
|
+
"Responses"
|
|
9903
|
+
]
|
|
9904
|
+
}
|
|
9905
|
+
)
|
|
9906
|
+
] }),
|
|
9907
|
+
errors.openaiCapabilities !== void 0 && supportsOpenai && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "ml-7 mt-2 text-xs text-destructive", children: errors.openaiCapabilities })
|
|
9908
|
+
] }),
|
|
9909
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
9910
|
+
"label",
|
|
9911
|
+
{
|
|
9912
|
+
htmlFor: "provider-capability-anthropic",
|
|
9913
|
+
className: `flex cursor-pointer items-start gap-3 px-3 py-3 ${supportsAnthropic ? "bg-primary/[0.04]" : ""}`,
|
|
9914
|
+
children: [
|
|
9915
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
9916
|
+
"input",
|
|
9917
|
+
{
|
|
9918
|
+
id: "provider-capability-anthropic",
|
|
9919
|
+
type: "checkbox",
|
|
9920
|
+
checked: supportsAnthropic,
|
|
9921
|
+
onChange: (event) => setSupportsAnthropic(event.target.checked),
|
|
9922
|
+
className: "mt-0.5 size-4 shrink-0 accent-primary"
|
|
9923
|
+
}
|
|
9924
|
+
),
|
|
9925
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "min-w-0", children: [
|
|
9926
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "block text-sm font-medium", children: "Anthropic" }),
|
|
9927
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "block text-xs text-muted-foreground", children: "Messages" })
|
|
9928
|
+
] })
|
|
9929
|
+
]
|
|
9930
|
+
}
|
|
9931
|
+
)
|
|
9932
|
+
] }),
|
|
9933
|
+
errors.capabilities !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-destructive", children: errors.capabilities })
|
|
9934
|
+
] }),
|
|
9935
|
+
(supportsAnthropic || supportsOpenai && (supportsOpenaiChat || supportsOpenaiResponses)) && /* @__PURE__ */ jsxRuntimeExports.jsxs("section", { className: "space-y-5 border-l border-border pl-4", "aria-label": "API endpoints", children: [
|
|
9936
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("h3", { className: "text-sm font-medium", children: "Endpoint Configuration" }),
|
|
9937
|
+
supportsAnthropic && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
|
|
9938
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("label", { htmlFor: "provider-anthropic-base-url", className: "text-sm font-medium", children: [
|
|
9939
|
+
"Anthropic Messages Base URL ",
|
|
9940
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-destructive", children: "*" })
|
|
9941
|
+
] }),
|
|
9942
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-input bg-background hover:bg-accent hover:text-accent-foreground flex min-w-0 overflow-hidden rounded-md focus-within:border-ring focus-within:outline-ring focus-within:ring-[3px]", children: [
|
|
9943
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
9944
|
+
"input",
|
|
9945
|
+
{
|
|
9946
|
+
id: "provider-anthropic-base-url",
|
|
9947
|
+
type: "text",
|
|
9948
|
+
value: anthropicBaseUrl,
|
|
9949
|
+
onChange: (event) => {
|
|
9950
|
+
setManualAnthropicUrlOverride(true);
|
|
9951
|
+
setAnthropicBaseUrl(event.target.value);
|
|
9952
|
+
},
|
|
9953
|
+
placeholder: "https://api.anthropic.com",
|
|
9954
|
+
className: "min-w-0 flex-1 bg-transparent px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50"
|
|
9955
|
+
}
|
|
9956
|
+
),
|
|
9957
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 select-none border-l border-white/10 bg-white/[0.04] px-3 py-2 font-mono text-xs text-muted-foreground", children: ANTHROPIC_MESSAGES_ENDPOINT })
|
|
9958
|
+
] }),
|
|
9959
|
+
errors.anthropicBaseUrl !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-destructive", children: errors.anthropicBaseUrl }),
|
|
9960
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
9961
|
+
EndpointUrlPreview,
|
|
9962
|
+
{
|
|
9963
|
+
baseUrl: anthropicBaseUrl,
|
|
9964
|
+
endpoint: ANTHROPIC_MESSAGES_ENDPOINT,
|
|
9965
|
+
providerName: name
|
|
9966
|
+
}
|
|
9967
|
+
)
|
|
9968
|
+
] }),
|
|
9969
|
+
supportsOpenai && supportsOpenaiChat && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
|
|
9970
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("label", { htmlFor: "provider-openai-base-url", className: "text-sm font-medium", children: [
|
|
9971
|
+
"OpenAI Chat Base URL ",
|
|
9972
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-destructive", children: "*" })
|
|
9973
|
+
] }),
|
|
9974
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-input bg-background hover:bg-accent hover:text-accent-foreground flex min-w-0 overflow-hidden rounded-md focus-within:border-ring focus-within:outline-ring focus-within:ring-[3px]", children: [
|
|
9975
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
9976
|
+
"input",
|
|
9977
|
+
{
|
|
9978
|
+
id: "provider-openai-base-url",
|
|
9979
|
+
type: "text",
|
|
9980
|
+
value: openaiBaseUrl,
|
|
9981
|
+
onChange: (event) => {
|
|
9982
|
+
setManualOpenaiUrlOverride(true);
|
|
9983
|
+
setOpenaiBaseUrl(event.target.value);
|
|
9984
|
+
},
|
|
9985
|
+
placeholder: "https://api.openai.com",
|
|
9986
|
+
className: "min-w-0 flex-1 bg-transparent px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50"
|
|
9987
|
+
}
|
|
9988
|
+
),
|
|
9989
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 select-none border-l border-white/10 bg-white/[0.04] px-3 py-2 font-mono text-xs text-muted-foreground", children: OPENAI_CHAT_COMPLETIONS_ENDPOINT })
|
|
9990
|
+
] }),
|
|
9991
|
+
errors.openaiBaseUrl !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-destructive", children: errors.openaiBaseUrl }),
|
|
9992
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
9993
|
+
EndpointUrlPreview,
|
|
9994
|
+
{
|
|
9995
|
+
baseUrl: openaiBaseUrl,
|
|
9996
|
+
endpoint: OPENAI_CHAT_COMPLETIONS_ENDPOINT,
|
|
9997
|
+
providerName: name
|
|
9998
|
+
}
|
|
9999
|
+
)
|
|
10000
|
+
] }),
|
|
10001
|
+
supportsOpenai && supportsOpenaiResponses && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
|
|
10002
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("label", { htmlFor: "provider-openai-responses-base-url", className: "text-sm font-medium", children: [
|
|
10003
|
+
"OpenAI Responses Base URL ",
|
|
10004
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "text-destructive", children: "*" })
|
|
10005
|
+
] }),
|
|
10006
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-input bg-background hover:bg-accent hover:text-accent-foreground flex min-w-0 overflow-hidden rounded-md focus-within:border-ring focus-within:outline-ring focus-within:ring-[3px]", children: [
|
|
10007
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
10008
|
+
"input",
|
|
10009
|
+
{
|
|
10010
|
+
id: "provider-openai-responses-base-url",
|
|
10011
|
+
type: "text",
|
|
10012
|
+
value: openaiResponsesBaseUrl,
|
|
10013
|
+
onChange: (event) => {
|
|
10014
|
+
setManualOpenaiResponsesUrlOverride(true);
|
|
10015
|
+
setOpenaiResponsesBaseUrl(event.target.value);
|
|
10016
|
+
},
|
|
10017
|
+
placeholder: "https://api.openai.com",
|
|
10018
|
+
className: "min-w-0 flex-1 bg-transparent px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50"
|
|
10019
|
+
}
|
|
10020
|
+
),
|
|
10021
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 select-none border-l border-white/10 bg-white/[0.04] px-3 py-2 font-mono text-xs text-muted-foreground", children: OPENAI_RESPONSES_ENDPOINT })
|
|
10022
|
+
] }),
|
|
10023
|
+
errors.openaiResponsesBaseUrl !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-destructive", children: errors.openaiResponsesBaseUrl }),
|
|
10024
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
10025
|
+
EndpointUrlPreview,
|
|
10026
|
+
{
|
|
10027
|
+
baseUrl: openaiResponsesBaseUrl,
|
|
10028
|
+
endpoint: OPENAI_RESPONSES_ENDPOINT,
|
|
10029
|
+
providerName: name
|
|
10030
|
+
}
|
|
10031
|
+
)
|
|
10032
|
+
] })
|
|
10033
|
+
] }),
|
|
9775
10034
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
|
|
9776
10035
|
/* @__PURE__ */ jsxRuntimeExports.jsx("label", { htmlFor: "provider-source", className: "text-sm font-medium", children: "Token Source" }),
|
|
9777
10036
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
@@ -10025,127 +10284,6 @@ function ProviderForm({ provider, onSubmit, onCancel }) {
|
|
|
10025
10284
|
),
|
|
10026
10285
|
errors.models !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-destructive", children: errors.models })
|
|
10027
10286
|
] }),
|
|
10028
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
|
|
10029
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-border bg-muted/40 flex gap-1 rounded-[8px] p-1", children: [
|
|
10030
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
10031
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
10032
|
-
"button",
|
|
10033
|
-
{
|
|
10034
|
-
type: "button",
|
|
10035
|
-
onClick: () => setActiveTab("anthropic"),
|
|
10036
|
-
className: `px-3 py-2 text-sm font-medium border-b-2 transition-colors ${activeTab === "anthropic" ? "border-primary text-primary" : "border-transparent text-muted-foreground hover:text-foreground"}`,
|
|
10037
|
-
children: "Anthropic Format"
|
|
10038
|
-
}
|
|
10039
|
-
) }),
|
|
10040
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "Anthropic Messages API format" })
|
|
10041
|
-
] }) }),
|
|
10042
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipProvider, { children: /* @__PURE__ */ jsxRuntimeExports.jsxs(Tooltip, { children: [
|
|
10043
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipTrigger, { asChild: true, children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
10044
|
-
"button",
|
|
10045
|
-
{
|
|
10046
|
-
type: "button",
|
|
10047
|
-
onClick: () => setActiveTab("openai"),
|
|
10048
|
-
className: `px-3 py-2 text-sm font-medium border-b-2 transition-colors ${activeTab === "openai" ? "border-primary text-primary" : "border-transparent text-muted-foreground hover:text-foreground"}`,
|
|
10049
|
-
children: "OpenAI Format"
|
|
10050
|
-
}
|
|
10051
|
-
) }),
|
|
10052
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(TooltipContent, { children: "OpenAI Chat Completions API format" })
|
|
10053
|
-
] }) })
|
|
10054
|
-
] }),
|
|
10055
|
-
errors.format !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-destructive", children: errors.format })
|
|
10056
|
-
] }),
|
|
10057
|
-
activeTab === "anthropic" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
|
|
10058
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("label", { htmlFor: "provider-anthropic-base-url", className: "text-sm font-medium", children: "Anthropic Base URL" }),
|
|
10059
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-input bg-background hover:bg-accent hover:text-accent-foreground flex min-w-0 overflow-hidden rounded-md focus-within:border-ring focus-within:outline-ring focus-within:ring-[3px]", children: [
|
|
10060
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
10061
|
-
"input",
|
|
10062
|
-
{
|
|
10063
|
-
id: "provider-anthropic-base-url",
|
|
10064
|
-
type: "text",
|
|
10065
|
-
value: anthropicBaseUrl,
|
|
10066
|
-
onChange: (e) => {
|
|
10067
|
-
setManualAnthropicUrlOverride(true);
|
|
10068
|
-
setAnthropicBaseUrl(e.target.value);
|
|
10069
|
-
},
|
|
10070
|
-
placeholder: "https://api.anthropic.com",
|
|
10071
|
-
className: "min-w-0 flex-1 bg-transparent px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50"
|
|
10072
|
-
}
|
|
10073
|
-
),
|
|
10074
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 select-none border-l border-white/10 bg-white/[0.04] px-3 py-2 font-mono text-xs text-muted-foreground", children: ANTHROPIC_MESSAGES_ENDPOINT })
|
|
10075
|
-
] }),
|
|
10076
|
-
errors.anthropicBaseUrl !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-destructive", children: errors.anthropicBaseUrl }),
|
|
10077
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
10078
|
-
EndpointUrlPreview,
|
|
10079
|
-
{
|
|
10080
|
-
baseUrl: anthropicBaseUrl,
|
|
10081
|
-
endpoint: ANTHROPIC_MESSAGES_ENDPOINT,
|
|
10082
|
-
providerName: name
|
|
10083
|
-
}
|
|
10084
|
-
),
|
|
10085
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground", children: "Anthropic-compatible base URL. Leave empty if this provider does not support Anthropic format." })
|
|
10086
|
-
] }),
|
|
10087
|
-
activeTab === "openai" && /* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-4", children: [
|
|
10088
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
|
|
10089
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("label", { htmlFor: "provider-openai-base-url", className: "text-sm font-medium", children: "OpenAI Chat Base URL" }),
|
|
10090
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-input bg-background hover:bg-accent hover:text-accent-foreground flex min-w-0 overflow-hidden rounded-md focus-within:border-ring focus-within:outline-ring focus-within:ring-[3px]", children: [
|
|
10091
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
10092
|
-
"input",
|
|
10093
|
-
{
|
|
10094
|
-
id: "provider-openai-base-url",
|
|
10095
|
-
type: "text",
|
|
10096
|
-
value: openaiBaseUrl,
|
|
10097
|
-
onChange: (e) => {
|
|
10098
|
-
setManualOpenaiUrlOverride(true);
|
|
10099
|
-
setOpenaiBaseUrl(e.target.value);
|
|
10100
|
-
},
|
|
10101
|
-
placeholder: "https://api.openai.com",
|
|
10102
|
-
className: "min-w-0 flex-1 bg-transparent px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50"
|
|
10103
|
-
}
|
|
10104
|
-
),
|
|
10105
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 select-none border-l border-white/10 bg-white/[0.04] px-3 py-2 font-mono text-xs text-muted-foreground", children: OPENAI_CHAT_COMPLETIONS_ENDPOINT })
|
|
10106
|
-
] }),
|
|
10107
|
-
errors.openaiBaseUrl !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-destructive", children: errors.openaiBaseUrl }),
|
|
10108
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
10109
|
-
EndpointUrlPreview,
|
|
10110
|
-
{
|
|
10111
|
-
baseUrl: openaiBaseUrl,
|
|
10112
|
-
endpoint: OPENAI_CHAT_COMPLETIONS_ENDPOINT,
|
|
10113
|
-
providerName: name
|
|
10114
|
-
}
|
|
10115
|
-
),
|
|
10116
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground", children: "OpenAI Chat Completions-compatible base URL. Leave empty if this provider only supports the Responses API." })
|
|
10117
|
-
] }),
|
|
10118
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
|
|
10119
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("label", { htmlFor: "provider-openai-responses-base-url", className: "text-sm font-medium", children: "OpenAI Responses Base URL" }),
|
|
10120
|
-
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "border border-input bg-background hover:bg-accent hover:text-accent-foreground flex min-w-0 overflow-hidden rounded-md focus-within:border-ring focus-within:outline-ring focus-within:ring-[3px]", children: [
|
|
10121
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
10122
|
-
"input",
|
|
10123
|
-
{
|
|
10124
|
-
id: "provider-openai-responses-base-url",
|
|
10125
|
-
type: "text",
|
|
10126
|
-
value: openaiResponsesBaseUrl,
|
|
10127
|
-
onChange: (e) => {
|
|
10128
|
-
setManualOpenaiResponsesUrlOverride(true);
|
|
10129
|
-
setOpenaiResponsesBaseUrl(e.target.value);
|
|
10130
|
-
},
|
|
10131
|
-
placeholder: "https://api.openai.com",
|
|
10132
|
-
className: "min-w-0 flex-1 bg-transparent px-3 py-2 text-sm placeholder:text-muted-foreground focus-visible:outline-none disabled:cursor-not-allowed disabled:opacity-50"
|
|
10133
|
-
}
|
|
10134
|
-
),
|
|
10135
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "shrink-0 select-none border-l border-white/10 bg-white/[0.04] px-3 py-2 font-mono text-xs text-muted-foreground", children: OPENAI_RESPONSES_ENDPOINT })
|
|
10136
|
-
] }),
|
|
10137
|
-
errors.openaiResponsesBaseUrl !== void 0 && /* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-destructive", children: errors.openaiResponsesBaseUrl }),
|
|
10138
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
10139
|
-
EndpointUrlPreview,
|
|
10140
|
-
{
|
|
10141
|
-
baseUrl: openaiResponsesBaseUrl,
|
|
10142
|
-
endpoint: OPENAI_RESPONSES_ENDPOINT,
|
|
10143
|
-
providerName: name
|
|
10144
|
-
}
|
|
10145
|
-
),
|
|
10146
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("p", { className: "text-xs text-muted-foreground", children: "Optional Responses-compatible base URL. Set only when the provider supports the Responses API." })
|
|
10147
|
-
] })
|
|
10148
|
-
] }),
|
|
10149
10287
|
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "space-y-2", children: [
|
|
10150
10288
|
/* @__PURE__ */ jsxRuntimeExports.jsx("label", { htmlFor: "provider-api-docs-url", className: "text-sm font-medium", children: "API Docs URL" }),
|
|
10151
10289
|
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
@@ -10191,14 +10329,21 @@ const PROVIDER_DELETE_TIMEOUT_MS = 1e4;
|
|
|
10191
10329
|
const PROVIDER_EXPORT_TIMEOUT_MS = 2e4;
|
|
10192
10330
|
const PROVIDER_IMPORT_TIMEOUT_MS = 2e4;
|
|
10193
10331
|
const PROVIDER_METADATA_TIMEOUT_MS = 3e4;
|
|
10194
|
-
function
|
|
10332
|
+
function endpointPayloadValue(value, preserveEmptyEndpoints) {
|
|
10333
|
+
if ((value?.length ?? 0) > 0) return value;
|
|
10334
|
+
return preserveEmptyEndpoints && value !== void 0 ? "" : void 0;
|
|
10335
|
+
}
|
|
10336
|
+
function createProviderPayload(data, preserveEmptyEndpoints = false) {
|
|
10195
10337
|
return {
|
|
10196
10338
|
name: data.name,
|
|
10197
10339
|
apiKey: data.apiKey,
|
|
10198
10340
|
models: data.models,
|
|
10199
|
-
anthropicBaseUrl: (data.anthropicBaseUrl
|
|
10200
|
-
openaiBaseUrl: (data.openaiBaseUrl
|
|
10201
|
-
openaiResponsesBaseUrl: (
|
|
10341
|
+
anthropicBaseUrl: endpointPayloadValue(data.anthropicBaseUrl, preserveEmptyEndpoints),
|
|
10342
|
+
openaiBaseUrl: endpointPayloadValue(data.openaiBaseUrl, preserveEmptyEndpoints),
|
|
10343
|
+
openaiResponsesBaseUrl: endpointPayloadValue(
|
|
10344
|
+
data.openaiResponsesBaseUrl,
|
|
10345
|
+
preserveEmptyEndpoints
|
|
10346
|
+
),
|
|
10202
10347
|
apiDocsUrl: (data.apiDocsUrl?.length ?? 0) > 0 ? data.apiDocsUrl : void 0,
|
|
10203
10348
|
modelMetadataUrl: (data.modelMetadataUrl?.length ?? 0) > 0 ? data.modelMetadataUrl : void 0,
|
|
10204
10349
|
modelMetadata: data.modelMetadata,
|
|
@@ -10481,7 +10626,7 @@ function ProvidersPanel({
|
|
|
10481
10626
|
{
|
|
10482
10627
|
method: "PUT",
|
|
10483
10628
|
headers: { "Content-Type": "application/json" },
|
|
10484
|
-
body: JSON.stringify(createProviderPayload(data))
|
|
10629
|
+
body: JSON.stringify(createProviderPayload(data, true))
|
|
10485
10630
|
},
|
|
10486
10631
|
() => "Failed to update provider"
|
|
10487
10632
|
);
|
|
@@ -12134,20 +12279,878 @@ function AgentLabDialog({ currentSessionId, logCount }) {
|
|
|
12134
12279
|
] })
|
|
12135
12280
|
] });
|
|
12136
12281
|
}
|
|
12137
|
-
const
|
|
12138
|
-
|
|
12139
|
-
|
|
12282
|
+
const INSPECTOR_PET_SIZE = 112;
|
|
12283
|
+
const INSPECTOR_PET_MARGIN = 14;
|
|
12284
|
+
const INSPECTOR_PET_EDGE_GAP = 20;
|
|
12285
|
+
const INSPECTOR_PET_MIN_STEP = 36;
|
|
12286
|
+
const INSPECTOR_PET_MAX_STEP = 92;
|
|
12287
|
+
const INSPECTOR_PET_SLEEP_AFTER_MS = 45e3;
|
|
12288
|
+
const INSPECTOR_PET_PANEL_WIDTH = 192;
|
|
12289
|
+
const INSPECTOR_PET_PANEL_HEIGHT = 68;
|
|
12290
|
+
const INSPECTOR_PET_PANEL_GAP = 10;
|
|
12291
|
+
const INSPECTOR_PET_VERTICAL_SAFE_MARGIN = 78;
|
|
12292
|
+
function viewportScale(viewport) {
|
|
12293
|
+
const scale = viewport.scale ?? 1;
|
|
12294
|
+
return Number.isFinite(scale) && scale > 0 ? scale : 1;
|
|
12295
|
+
}
|
|
12296
|
+
function scaledMetric(value, viewport) {
|
|
12297
|
+
return value * viewportScale(viewport);
|
|
12298
|
+
}
|
|
12299
|
+
function clampUnit(value) {
|
|
12300
|
+
return Math.min(Math.max(value, 0), 1);
|
|
12301
|
+
}
|
|
12302
|
+
function maximumPetX(viewport) {
|
|
12303
|
+
const edgeGap = scaledMetric(INSPECTOR_PET_EDGE_GAP, viewport);
|
|
12304
|
+
return Math.max(edgeGap, viewport.width - scaledMetric(INSPECTOR_PET_SIZE, viewport) - edgeGap);
|
|
12305
|
+
}
|
|
12306
|
+
function maximumPetY(viewport) {
|
|
12307
|
+
const edgeGap = scaledMetric(INSPECTOR_PET_EDGE_GAP, viewport);
|
|
12308
|
+
return Math.max(edgeGap, viewport.height - scaledMetric(INSPECTOR_PET_SIZE, viewport) - edgeGap);
|
|
12309
|
+
}
|
|
12310
|
+
function clampInspectorPetPosition(position, viewport) {
|
|
12311
|
+
const edgeGap = scaledMetric(INSPECTOR_PET_EDGE_GAP, viewport);
|
|
12312
|
+
return {
|
|
12313
|
+
x: Math.min(Math.max(position.x, edgeGap), maximumPetX(viewport)),
|
|
12314
|
+
y: Math.min(Math.max(position.y, edgeGap), maximumPetY(viewport))
|
|
12315
|
+
};
|
|
12140
12316
|
}
|
|
12141
|
-
function
|
|
12142
|
-
|
|
12143
|
-
|
|
12317
|
+
function nearestInspectorPetEdge(position, viewport) {
|
|
12318
|
+
const clamped = clampInspectorPetPosition(position, viewport);
|
|
12319
|
+
const edgeGap = scaledMetric(INSPECTOR_PET_EDGE_GAP, viewport);
|
|
12320
|
+
const distances = [
|
|
12321
|
+
{ edge: "left", distance: clamped.x - edgeGap },
|
|
12322
|
+
{ edge: "right", distance: maximumPetX(viewport) - clamped.x },
|
|
12323
|
+
{ edge: "top", distance: clamped.y - edgeGap },
|
|
12324
|
+
{ edge: "bottom", distance: maximumPetY(viewport) - clamped.y }
|
|
12325
|
+
];
|
|
12326
|
+
return distances.reduce((best, current) => current.distance < best.distance ? current : best).edge;
|
|
12327
|
+
}
|
|
12328
|
+
function snapInspectorPetToEdge(position, viewport) {
|
|
12329
|
+
const clamped = clampInspectorPetPosition(position, viewport);
|
|
12330
|
+
const edge = nearestInspectorPetEdge(clamped, viewport);
|
|
12331
|
+
const edgeGap = scaledMetric(INSPECTOR_PET_EDGE_GAP, viewport);
|
|
12332
|
+
switch (edge) {
|
|
12333
|
+
case "left":
|
|
12334
|
+
return { x: edgeGap, y: clamped.y };
|
|
12335
|
+
case "right":
|
|
12336
|
+
return { x: maximumPetX(viewport), y: clamped.y };
|
|
12337
|
+
case "top":
|
|
12338
|
+
return { x: clamped.x, y: edgeGap };
|
|
12339
|
+
case "bottom":
|
|
12340
|
+
return { x: clamped.x, y: maximumPetY(viewport) };
|
|
12341
|
+
}
|
|
12342
|
+
}
|
|
12343
|
+
function randomInspectorPetEdgePosition(viewport, positionSample) {
|
|
12344
|
+
const maxX = maximumPetX(viewport);
|
|
12345
|
+
const maxY = maximumPetY(viewport);
|
|
12346
|
+
const edgeGap = scaledMetric(INSPECTOR_PET_EDGE_GAP, viewport);
|
|
12347
|
+
return {
|
|
12348
|
+
x: edgeGap + clampUnit(positionSample) * (maxX - edgeGap),
|
|
12349
|
+
y: maxY
|
|
12350
|
+
};
|
|
12351
|
+
}
|
|
12352
|
+
function nextInspectorPetWalkingPosition(position, viewport, stepSample, directionSample) {
|
|
12353
|
+
const clamped = snapInspectorPetToEdge(position, viewport);
|
|
12354
|
+
const step = scaledMetric(INSPECTOR_PET_MIN_STEP, viewport) + clampUnit(stepSample) * scaledMetric(INSPECTOR_PET_MAX_STEP - INSPECTOR_PET_MIN_STEP, viewport);
|
|
12355
|
+
const direction = directionSample >= 0.5 ? 1 : -1;
|
|
12356
|
+
const edge = nearestInspectorPetEdge(clamped, viewport);
|
|
12357
|
+
const maxX = maximumPetX(viewport);
|
|
12358
|
+
const maxY = maximumPetY(viewport);
|
|
12359
|
+
const edgeGap = scaledMetric(INSPECTOR_PET_EDGE_GAP, viewport);
|
|
12360
|
+
const minimumSafeY = Math.min(scaledMetric(INSPECTOR_PET_VERTICAL_SAFE_MARGIN, viewport), maxY);
|
|
12361
|
+
switch (edge) {
|
|
12362
|
+
case "left":
|
|
12363
|
+
return {
|
|
12364
|
+
x: edgeGap,
|
|
12365
|
+
y: Math.min(Math.max(clamped.y + step * direction, minimumSafeY), maxY)
|
|
12366
|
+
};
|
|
12367
|
+
case "right":
|
|
12368
|
+
return {
|
|
12369
|
+
x: maxX,
|
|
12370
|
+
y: Math.min(Math.max(clamped.y + step * direction, minimumSafeY), maxY)
|
|
12371
|
+
};
|
|
12372
|
+
case "top":
|
|
12373
|
+
return {
|
|
12374
|
+
x: Math.min(Math.max(clamped.x + step * direction, edgeGap), maxX),
|
|
12375
|
+
y: edgeGap
|
|
12376
|
+
};
|
|
12377
|
+
case "bottom":
|
|
12378
|
+
return {
|
|
12379
|
+
x: Math.min(Math.max(clamped.x + step * direction, edgeGap), maxX),
|
|
12380
|
+
y: maxY
|
|
12381
|
+
};
|
|
12144
12382
|
}
|
|
12145
|
-
|
|
12146
|
-
|
|
12383
|
+
}
|
|
12384
|
+
function inspectorPetPanelPosition(position, viewport) {
|
|
12385
|
+
const edge = nearestInspectorPetEdge(position, viewport);
|
|
12386
|
+
const petSize = scaledMetric(INSPECTOR_PET_SIZE, viewport);
|
|
12387
|
+
const panelWidth = scaledMetric(INSPECTOR_PET_PANEL_WIDTH, viewport);
|
|
12388
|
+
const panelHeight = scaledMetric(INSPECTOR_PET_PANEL_HEIGHT, viewport);
|
|
12389
|
+
const panelGap = scaledMetric(INSPECTOR_PET_PANEL_GAP, viewport);
|
|
12390
|
+
const margin = scaledMetric(INSPECTOR_PET_MARGIN, viewport);
|
|
12391
|
+
let x = position.x + petSize / 2 - panelWidth / 2;
|
|
12392
|
+
let y = position.y + petSize / 2 - panelHeight / 2;
|
|
12393
|
+
switch (edge) {
|
|
12394
|
+
case "left":
|
|
12395
|
+
x = position.x + petSize + panelGap;
|
|
12396
|
+
break;
|
|
12397
|
+
case "right":
|
|
12398
|
+
x = position.x - panelWidth - panelGap;
|
|
12399
|
+
break;
|
|
12400
|
+
case "top":
|
|
12401
|
+
y = position.y + petSize + panelGap;
|
|
12402
|
+
break;
|
|
12403
|
+
case "bottom":
|
|
12404
|
+
y = position.y - panelHeight - panelGap;
|
|
12405
|
+
break;
|
|
12147
12406
|
}
|
|
12148
|
-
return
|
|
12407
|
+
return {
|
|
12408
|
+
x: Math.min(Math.max(x, margin), Math.max(margin, viewport.width - panelWidth - margin)),
|
|
12409
|
+
y: Math.min(Math.max(y, margin), Math.max(margin, viewport.height - panelHeight - margin))
|
|
12410
|
+
};
|
|
12149
12411
|
}
|
|
12150
|
-
function
|
|
12412
|
+
function latestCapturedLog(logs) {
|
|
12413
|
+
let latest = null;
|
|
12414
|
+
for (const log of logs) {
|
|
12415
|
+
if (latest === null || log.id > latest.id) latest = log;
|
|
12416
|
+
}
|
|
12417
|
+
return latest;
|
|
12418
|
+
}
|
|
12419
|
+
function logNeedsAttention(log) {
|
|
12420
|
+
const hasHttpError = log.responseStatus !== null && log.responseStatus >= 400;
|
|
12421
|
+
const hasStreamError = log.error !== null && log.error !== void 0 && log.error !== "";
|
|
12422
|
+
return hasHttpError || hasStreamError;
|
|
12423
|
+
}
|
|
12424
|
+
function resolveInspectorPetStatus(logs, nowMs) {
|
|
12425
|
+
const pendingCount = logs.filter((log) => log.responseStatus === null).length;
|
|
12426
|
+
const capturedCount = logs.length;
|
|
12427
|
+
if (pendingCount > 0) {
|
|
12428
|
+
return {
|
|
12429
|
+
mood: "active",
|
|
12430
|
+
label: `${String(pendingCount)} request${pendingCount === 1 ? "" : "s"} in flight`,
|
|
12431
|
+
pendingCount,
|
|
12432
|
+
capturedCount
|
|
12433
|
+
};
|
|
12434
|
+
}
|
|
12435
|
+
const latest = latestCapturedLog(logs);
|
|
12436
|
+
if (latest !== null && logNeedsAttention(latest)) {
|
|
12437
|
+
return {
|
|
12438
|
+
mood: "attention",
|
|
12439
|
+
label: "Latest request needs attention",
|
|
12440
|
+
pendingCount,
|
|
12441
|
+
capturedCount
|
|
12442
|
+
};
|
|
12443
|
+
}
|
|
12444
|
+
if (latest === null) {
|
|
12445
|
+
return {
|
|
12446
|
+
mood: "idle",
|
|
12447
|
+
label: "Waiting for traffic",
|
|
12448
|
+
pendingCount,
|
|
12449
|
+
capturedCount
|
|
12450
|
+
};
|
|
12451
|
+
}
|
|
12452
|
+
const latestTimestamp = Date.parse(latest.timestamp);
|
|
12453
|
+
if (Number.isFinite(latestTimestamp) && nowMs - latestTimestamp >= INSPECTOR_PET_SLEEP_AFTER_MS) {
|
|
12454
|
+
return {
|
|
12455
|
+
mood: "sleeping",
|
|
12456
|
+
label: "All quiet",
|
|
12457
|
+
pendingCount,
|
|
12458
|
+
capturedCount
|
|
12459
|
+
};
|
|
12460
|
+
}
|
|
12461
|
+
return {
|
|
12462
|
+
mood: "idle",
|
|
12463
|
+
label: "Watching the session",
|
|
12464
|
+
pendingCount,
|
|
12465
|
+
capturedCount
|
|
12466
|
+
};
|
|
12467
|
+
}
|
|
12468
|
+
function createRod(start, end, radius, material) {
|
|
12469
|
+
const direction = end.clone().sub(start);
|
|
12470
|
+
const length = direction.length();
|
|
12471
|
+
const rod = new Mesh(new CylinderGeometry(radius, radius * 0.9, length, 12), material);
|
|
12472
|
+
rod.position.copy(start.clone().add(end).multiplyScalar(0.5));
|
|
12473
|
+
rod.quaternion.setFromUnitVectors(new Vector3(0, 1, 0), direction.normalize());
|
|
12474
|
+
return rod;
|
|
12475
|
+
}
|
|
12476
|
+
function addClaw(root, side, shellMaterial, accentMaterial) {
|
|
12477
|
+
const clawScale = side < 0 ? 1.5 : 0.68;
|
|
12478
|
+
const clawGroup = new Group();
|
|
12479
|
+
const pincers = [];
|
|
12480
|
+
root.add(clawGroup);
|
|
12481
|
+
const shoulder = new Vector3(side * 1.2, 0.25, -0.05);
|
|
12482
|
+
const wrist = new Vector3(side * (1.65 + clawScale * 0.18), 0.5, 0);
|
|
12483
|
+
const arm = createRod(shoulder, wrist, 0.16 * clawScale, accentMaterial);
|
|
12484
|
+
clawGroup.add(arm);
|
|
12485
|
+
const palm = new Mesh(new SphereGeometry(0.55, 24, 16), shellMaterial);
|
|
12486
|
+
palm.position.set(side * (1.95 + clawScale * 0.16), 0.62, 0.05);
|
|
12487
|
+
palm.scale.set(1.05 * clawScale, 0.72 * clawScale, 0.55 * clawScale);
|
|
12488
|
+
clawGroup.add(palm);
|
|
12489
|
+
for (const pincerDirection of [-1, 1]) {
|
|
12490
|
+
const pincer = new Mesh(new SphereGeometry(0.36, 20, 14), accentMaterial);
|
|
12491
|
+
pincer.position.set(
|
|
12492
|
+
side * (2.22 + clawScale * 0.26),
|
|
12493
|
+
0.62 + pincerDirection * 0.24 * clawScale,
|
|
12494
|
+
0.08
|
|
12495
|
+
);
|
|
12496
|
+
pincer.scale.set(1.05 * clawScale, 0.34 * clawScale, 0.42 * clawScale);
|
|
12497
|
+
pincer.rotation.z = pincerDirection * side * 0.42;
|
|
12498
|
+
clawGroup.add(pincer);
|
|
12499
|
+
pincers.push({
|
|
12500
|
+
direction: pincerDirection,
|
|
12501
|
+
mesh: pincer,
|
|
12502
|
+
restRotationZ: pincer.rotation.z,
|
|
12503
|
+
restY: pincer.position.y
|
|
12504
|
+
});
|
|
12505
|
+
}
|
|
12506
|
+
return { group: clawGroup, pincers, scale: clawScale };
|
|
12507
|
+
}
|
|
12508
|
+
function pinchPulse(cycleTime, start, duration) {
|
|
12509
|
+
const progress = (cycleTime - start) / duration;
|
|
12510
|
+
if (progress <= 0 || progress >= 1) return 0;
|
|
12511
|
+
return Math.sin(progress * Math.PI);
|
|
12512
|
+
}
|
|
12513
|
+
function dominantClawGrip(elapsed) {
|
|
12514
|
+
const cycleTime = elapsed % 6.8;
|
|
12515
|
+
return Math.max(pinchPulse(cycleTime, 0.72, 0.82), pinchPulse(cycleTime, 1.72, 0.68));
|
|
12516
|
+
}
|
|
12517
|
+
function addEyes(root, shellMaterial, eyeMaterial) {
|
|
12518
|
+
const eyes = [];
|
|
12519
|
+
for (const side of [-1, 1]) {
|
|
12520
|
+
const stalkStart = new Vector3(side * 0.48, 0.68, 0.05);
|
|
12521
|
+
const stalkEnd = new Vector3(side * 0.1, 0.82, 0.07);
|
|
12522
|
+
const eyeGroup = new Group();
|
|
12523
|
+
eyeGroup.position.copy(stalkStart);
|
|
12524
|
+
eyeGroup.add(createRod(new Vector3(0, 0, 0), stalkEnd, 0.1, shellMaterial));
|
|
12525
|
+
const eye = new Mesh(new SphereGeometry(0.24, 20, 16), eyeMaterial);
|
|
12526
|
+
eye.position.copy(stalkEnd);
|
|
12527
|
+
eye.scale.set(1, 1, 0.85);
|
|
12528
|
+
eyeGroup.add(eye);
|
|
12529
|
+
const pupil = new Mesh(
|
|
12530
|
+
new SphereGeometry(0.105, 16, 12),
|
|
12531
|
+
new MeshPhysicalMaterial({ color: 1120295, roughness: 0.25 })
|
|
12532
|
+
);
|
|
12533
|
+
const pupilRest = new Vector3(stalkEnd.x, stalkEnd.y, stalkEnd.z + 0.2);
|
|
12534
|
+
pupil.position.copy(pupilRest);
|
|
12535
|
+
eyeGroup.add(pupil);
|
|
12536
|
+
root.add(eyeGroup);
|
|
12537
|
+
eyes.push({
|
|
12538
|
+
group: eyeGroup,
|
|
12539
|
+
phase: side < 0 ? 0 : Math.PI / 3,
|
|
12540
|
+
pupil,
|
|
12541
|
+
pupilRest
|
|
12542
|
+
});
|
|
12543
|
+
}
|
|
12544
|
+
return eyes;
|
|
12545
|
+
}
|
|
12546
|
+
function addLegs(root, legMaterial) {
|
|
12547
|
+
const legs = [];
|
|
12548
|
+
for (const side of [-1, 1]) {
|
|
12549
|
+
for (let index = 0; index < 4; index += 1) {
|
|
12550
|
+
const leg = new Group();
|
|
12551
|
+
const baseY = -0.3 - index * 0.22;
|
|
12552
|
+
leg.position.set(side * (0.8 + index * 0.12), baseY, -0.18);
|
|
12553
|
+
leg.add(
|
|
12554
|
+
createRod(
|
|
12555
|
+
new Vector3(0, 0, 0),
|
|
12556
|
+
new Vector3(side * (0.62 + index * 0.06), -0.34, 0),
|
|
12557
|
+
0.095,
|
|
12558
|
+
legMaterial
|
|
12559
|
+
)
|
|
12560
|
+
);
|
|
12561
|
+
leg.add(
|
|
12562
|
+
createRod(
|
|
12563
|
+
new Vector3(side * (0.58 + index * 0.06), -0.31, 0),
|
|
12564
|
+
new Vector3(side * (1.02 + index * 0.08), -0.88 + index * 0.07, 0.04),
|
|
12565
|
+
0.075,
|
|
12566
|
+
legMaterial
|
|
12567
|
+
)
|
|
12568
|
+
);
|
|
12569
|
+
root.add(leg);
|
|
12570
|
+
legs.push({ group: leg, phase: index * Math.PI + (side > 0 ? Math.PI / 2 : 0), side });
|
|
12571
|
+
}
|
|
12572
|
+
}
|
|
12573
|
+
return legs;
|
|
12574
|
+
}
|
|
12575
|
+
function createCrabScene(scene) {
|
|
12576
|
+
const shellMaterial = new MeshPhysicalMaterial({
|
|
12577
|
+
color: 16096779,
|
|
12578
|
+
roughness: 0.34,
|
|
12579
|
+
metalness: 0.04,
|
|
12580
|
+
clearcoat: 0.78,
|
|
12581
|
+
clearcoatRoughness: 0.18,
|
|
12582
|
+
emissive: new Color(0),
|
|
12583
|
+
emissiveIntensity: 0
|
|
12584
|
+
});
|
|
12585
|
+
const accentMaterial = new MeshPhysicalMaterial({
|
|
12586
|
+
color: 16486972,
|
|
12587
|
+
roughness: 0.42,
|
|
12588
|
+
metalness: 0.02,
|
|
12589
|
+
clearcoat: 0.52,
|
|
12590
|
+
clearcoatRoughness: 0.28
|
|
12591
|
+
});
|
|
12592
|
+
const legMaterial = new MeshPhysicalMaterial({
|
|
12593
|
+
color: 14251782,
|
|
12594
|
+
roughness: 0.48,
|
|
12595
|
+
clearcoat: 0.35,
|
|
12596
|
+
clearcoatRoughness: 0.35
|
|
12597
|
+
});
|
|
12598
|
+
const eyeMaterial = new MeshPhysicalMaterial({
|
|
12599
|
+
color: 16776171,
|
|
12600
|
+
roughness: 0.22,
|
|
12601
|
+
clearcoat: 0.8,
|
|
12602
|
+
clearcoatRoughness: 0.12
|
|
12603
|
+
});
|
|
12604
|
+
const root = new Group();
|
|
12605
|
+
root.rotation.x = -0.12;
|
|
12606
|
+
root.rotation.y = -0.08;
|
|
12607
|
+
root.scale.setScalar(1.08);
|
|
12608
|
+
scene.add(root);
|
|
12609
|
+
const shadow = new Mesh(
|
|
12610
|
+
new CircleGeometry(1.65, 40),
|
|
12611
|
+
new MeshBasicMaterial({ color: 1120295, transparent: true, opacity: 0.16, depthWrite: false })
|
|
12612
|
+
);
|
|
12613
|
+
shadow.position.set(0, -1.33, -0.65);
|
|
12614
|
+
shadow.scale.set(1.4, 0.34, 1);
|
|
12615
|
+
root.add(shadow);
|
|
12616
|
+
const body = new Mesh(new SphereGeometry(1, 36, 24), shellMaterial);
|
|
12617
|
+
body.position.set(0, 0.02, 0);
|
|
12618
|
+
body.scale.set(1.58, 0.92, 0.68);
|
|
12619
|
+
root.add(body);
|
|
12620
|
+
const lowerShell = new Mesh(new SphereGeometry(0.92, 28, 20), accentMaterial);
|
|
12621
|
+
lowerShell.position.set(0, -0.48, 0.22);
|
|
12622
|
+
lowerShell.scale.set(1.28, 0.42, 0.56);
|
|
12623
|
+
root.add(lowerShell);
|
|
12624
|
+
const dominantClaw = addClaw(root, -1, shellMaterial, accentMaterial);
|
|
12625
|
+
addClaw(root, 1, shellMaterial, accentMaterial);
|
|
12626
|
+
const eyes = addEyes(root, shellMaterial, eyeMaterial);
|
|
12627
|
+
const legs = addLegs(root, legMaterial);
|
|
12628
|
+
scene.add(new AmbientLight(16775149, 1.65));
|
|
12629
|
+
scene.add(new HemisphereLight(16775149, 1515571, 2.15));
|
|
12630
|
+
const keyLight = new DirectionalLight(16777215, 3.6);
|
|
12631
|
+
keyLight.position.set(3.5, 4.5, 6);
|
|
12632
|
+
scene.add(keyLight);
|
|
12633
|
+
const fillLight = new DirectionalLight(16498468, 1.35);
|
|
12634
|
+
fillLight.position.set(-4, 1.5, 4);
|
|
12635
|
+
scene.add(fillLight);
|
|
12636
|
+
const rimLight = new PointLight(16096779, 1.8, 12, 2);
|
|
12637
|
+
rimLight.position.set(0, 1.8, 4.5);
|
|
12638
|
+
scene.add(rimLight);
|
|
12639
|
+
return { bodyMaterial: shellMaterial, dominantClaw, eyes, legs, rimLight, root };
|
|
12640
|
+
}
|
|
12641
|
+
function moodColor(mood) {
|
|
12642
|
+
switch (mood) {
|
|
12643
|
+
case "active":
|
|
12644
|
+
return 2282478;
|
|
12645
|
+
case "attention":
|
|
12646
|
+
return 15680580;
|
|
12647
|
+
case "idle":
|
|
12648
|
+
return 16096779;
|
|
12649
|
+
case "sleeping":
|
|
12650
|
+
return 9741240;
|
|
12651
|
+
}
|
|
12652
|
+
}
|
|
12653
|
+
function isDisposableMesh(object2) {
|
|
12654
|
+
return object2 instanceof Mesh;
|
|
12655
|
+
}
|
|
12656
|
+
function disposeScene(scene) {
|
|
12657
|
+
const materials = /* @__PURE__ */ new Set();
|
|
12658
|
+
scene.traverse((object2) => {
|
|
12659
|
+
if (!isDisposableMesh(object2)) return;
|
|
12660
|
+
object2.geometry.dispose();
|
|
12661
|
+
const material = object2.material;
|
|
12662
|
+
if (Array.isArray(material)) {
|
|
12663
|
+
for (const item of material) materials.add(item);
|
|
12664
|
+
return;
|
|
12665
|
+
}
|
|
12666
|
+
materials.add(material);
|
|
12667
|
+
});
|
|
12668
|
+
for (const material of materials) material.dispose();
|
|
12669
|
+
}
|
|
12670
|
+
function InspectorPetCrab3D({
|
|
12671
|
+
mood,
|
|
12672
|
+
moving,
|
|
12673
|
+
reduceMotion
|
|
12674
|
+
}) {
|
|
12675
|
+
const canvasRef = reactExports.useRef(null);
|
|
12676
|
+
const moodRef = reactExports.useRef(mood);
|
|
12677
|
+
const movingRef = reactExports.useRef(moving);
|
|
12678
|
+
const reduceMotionRef = reactExports.useRef(reduceMotion);
|
|
12679
|
+
const [renderFailed, setRenderFailed] = reactExports.useState(false);
|
|
12680
|
+
reactExports.useEffect(() => {
|
|
12681
|
+
moodRef.current = mood;
|
|
12682
|
+
}, [mood]);
|
|
12683
|
+
reactExports.useEffect(() => {
|
|
12684
|
+
movingRef.current = moving;
|
|
12685
|
+
}, [moving]);
|
|
12686
|
+
reactExports.useEffect(() => {
|
|
12687
|
+
reduceMotionRef.current = reduceMotion;
|
|
12688
|
+
}, [reduceMotion]);
|
|
12689
|
+
reactExports.useEffect(() => {
|
|
12690
|
+
const canvas = canvasRef.current;
|
|
12691
|
+
if (canvas === null) return void 0;
|
|
12692
|
+
let renderer;
|
|
12693
|
+
try {
|
|
12694
|
+
renderer = new WebGLRenderer({
|
|
12695
|
+
alpha: true,
|
|
12696
|
+
antialias: true,
|
|
12697
|
+
canvas,
|
|
12698
|
+
powerPreference: "low-power",
|
|
12699
|
+
preserveDrawingBuffer: true
|
|
12700
|
+
});
|
|
12701
|
+
} catch {
|
|
12702
|
+
setRenderFailed(true);
|
|
12703
|
+
return void 0;
|
|
12704
|
+
}
|
|
12705
|
+
renderer.setClearColor(0, 0);
|
|
12706
|
+
renderer.outputColorSpace = SRGBColorSpace;
|
|
12707
|
+
renderer.toneMapping = ACESFilmicToneMapping;
|
|
12708
|
+
renderer.toneMappingExposure = 1.18;
|
|
12709
|
+
const scene = new Scene();
|
|
12710
|
+
const camera = new OrthographicCamera(-3.65, 3.65, 3.65, -3.65, 0.1, 20);
|
|
12711
|
+
camera.position.set(0, 0.05, 8);
|
|
12712
|
+
camera.lookAt(0, 0, 0);
|
|
12713
|
+
const parts = createCrabScene(scene);
|
|
12714
|
+
const startedAt = window.performance.now();
|
|
12715
|
+
let lastFrameAt = 0;
|
|
12716
|
+
const renderFrame = (timestamp) => {
|
|
12717
|
+
if (timestamp - lastFrameAt < 32) return;
|
|
12718
|
+
lastFrameAt = timestamp;
|
|
12719
|
+
const elapsed = (timestamp - startedAt) / 1e3;
|
|
12720
|
+
const motionAllowed = !reduceMotionRef.current;
|
|
12721
|
+
const gait = movingRef.current ? 1 : moodRef.current === "active" ? 0.42 : 0;
|
|
12722
|
+
const idleMotion = motionAllowed ? Math.sin(elapsed * 0.85) : 0;
|
|
12723
|
+
const stepMotion = motionAllowed ? Math.sin(elapsed * 3.4) : 0;
|
|
12724
|
+
const clawGrip = motionAllowed ? dominantClawGrip(elapsed) : 0;
|
|
12725
|
+
parts.root.position.y = idleMotion * 0.035 + Math.abs(stepMotion) * 0.055 * gait;
|
|
12726
|
+
parts.root.rotation.y = -0.08 + idleMotion * 0.055;
|
|
12727
|
+
parts.root.rotation.z = stepMotion * 0.028 * gait;
|
|
12728
|
+
parts.dominantClaw.group.rotation.z = -clawGrip * 0.035;
|
|
12729
|
+
for (const pincer of parts.dominantClaw.pincers) {
|
|
12730
|
+
pincer.mesh.position.y = pincer.restY - pincer.direction * parts.dominantClaw.scale * 0.16 * clawGrip;
|
|
12731
|
+
pincer.mesh.rotation.z = pincer.restRotationZ * (1 - clawGrip * 0.72);
|
|
12732
|
+
}
|
|
12733
|
+
for (const leg of parts.legs) {
|
|
12734
|
+
leg.group.rotation.z = motionAllowed && gait > 0 ? Math.sin(elapsed * 4.25 + leg.phase) * 0.2 * leg.side * gait : 0;
|
|
12735
|
+
leg.group.rotation.x = motionAllowed && gait > 0 ? stepMotion * 0.045 * gait : 0;
|
|
12736
|
+
}
|
|
12737
|
+
for (const eye of parts.eyes) {
|
|
12738
|
+
const gaze = motionAllowed ? Math.sin(elapsed * 0.72 + eye.phase) : 0;
|
|
12739
|
+
const lift = motionAllowed ? Math.cos(elapsed * 0.9 + eye.phase) : 0;
|
|
12740
|
+
eye.group.rotation.z = gaze * 0.075;
|
|
12741
|
+
eye.group.rotation.x = lift * 0.025;
|
|
12742
|
+
eye.pupil.position.set(
|
|
12743
|
+
eye.pupilRest.x + gaze * 0.055,
|
|
12744
|
+
eye.pupilRest.y + lift * 0.025,
|
|
12745
|
+
eye.pupilRest.z
|
|
12746
|
+
);
|
|
12747
|
+
}
|
|
12748
|
+
const color = moodColor(moodRef.current);
|
|
12749
|
+
parts.rimLight.color.setHex(color);
|
|
12750
|
+
parts.rimLight.intensity = moodRef.current === "attention" ? 3.2 : 1.8;
|
|
12751
|
+
parts.bodyMaterial.emissive.setHex(color);
|
|
12752
|
+
parts.bodyMaterial.emissiveIntensity = moodRef.current === "active" ? 0.12 : 0.035;
|
|
12753
|
+
renderer.render(scene, camera);
|
|
12754
|
+
};
|
|
12755
|
+
const resize = () => {
|
|
12756
|
+
const width = Math.max(canvas.clientWidth, 1);
|
|
12757
|
+
const height = Math.max(canvas.clientHeight, 1);
|
|
12758
|
+
renderer.setDrawingBufferSize(width, height, Math.min(window.devicePixelRatio, 2));
|
|
12759
|
+
renderer.render(scene, camera);
|
|
12760
|
+
};
|
|
12761
|
+
const resizeObserver = typeof ResizeObserver === "undefined" ? null : new ResizeObserver(resize);
|
|
12762
|
+
if (resizeObserver === null) {
|
|
12763
|
+
window.addEventListener("resize", resize);
|
|
12764
|
+
} else {
|
|
12765
|
+
resizeObserver.observe(canvas);
|
|
12766
|
+
}
|
|
12767
|
+
resize();
|
|
12768
|
+
const handleContextLost = (event) => {
|
|
12769
|
+
event.preventDefault();
|
|
12770
|
+
setRenderFailed(true);
|
|
12771
|
+
};
|
|
12772
|
+
canvas.addEventListener("webglcontextlost", handleContextLost);
|
|
12773
|
+
renderer.setAnimationLoop(renderFrame);
|
|
12774
|
+
return () => {
|
|
12775
|
+
renderer.setAnimationLoop(null);
|
|
12776
|
+
if (resizeObserver === null) {
|
|
12777
|
+
window.removeEventListener("resize", resize);
|
|
12778
|
+
} else {
|
|
12779
|
+
resizeObserver.disconnect();
|
|
12780
|
+
}
|
|
12781
|
+
canvas.removeEventListener("webglcontextlost", handleContextLost);
|
|
12782
|
+
disposeScene(scene);
|
|
12783
|
+
renderer.dispose();
|
|
12784
|
+
};
|
|
12785
|
+
}, []);
|
|
12786
|
+
return /* @__PURE__ */ jsxRuntimeExports.jsxs("span", { className: "relative flex size-24 items-center justify-center", "aria-hidden": "true", children: [
|
|
12787
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
12788
|
+
"canvas",
|
|
12789
|
+
{
|
|
12790
|
+
ref: canvasRef,
|
|
12791
|
+
className: renderFailed ? "hidden" : "block size-full bg-transparent",
|
|
12792
|
+
"data-inspector-pet-canvas": "true"
|
|
12793
|
+
}
|
|
12794
|
+
),
|
|
12795
|
+
renderFailed && /* @__PURE__ */ jsxRuntimeExports.jsx(CrabLogo, { className: "size-22 text-amber-500 drop-shadow-[0_0_18px_rgba(245,158,11,0.28)]" })
|
|
12796
|
+
] });
|
|
12797
|
+
}
|
|
12798
|
+
const INSPECTOR_PET_ROAMING_STORAGE_KEY = "agent-inspector.pet.roaming";
|
|
12799
|
+
const INSPECTOR_PET_MIN_PAUSE_MS = 11e3;
|
|
12800
|
+
const INSPECTOR_PET_PAUSE_WINDOW_MS = 9e3;
|
|
12801
|
+
const INSPECTOR_PET_SCUTTLE_MS = 7200;
|
|
12802
|
+
const INSPECTOR_PET_PANEL_DISMISS_MS = 6e3;
|
|
12803
|
+
const INSPECTOR_PET_REACTION_MS = 760;
|
|
12804
|
+
const INSPECTOR_PET_DRAG_THRESHOLD = 4;
|
|
12805
|
+
const INSPECTOR_PET_TOP_LAYER_Z_INDEX = 2147483647;
|
|
12806
|
+
function readViewport() {
|
|
12807
|
+
if (typeof window === "undefined") return { width: 1280, height: 720, scale: 1 };
|
|
12808
|
+
const rawScale = window.getComputedStyle(document.documentElement).getPropertyValue("--inspector-ui-scale");
|
|
12809
|
+
const parsedScale = Number.parseFloat(rawScale);
|
|
12810
|
+
const scale = Number.isFinite(parsedScale) && parsedScale > 0 ? parsedScale : 1;
|
|
12811
|
+
return {
|
|
12812
|
+
width: Math.max(window.innerWidth, INSPECTOR_PET_MARGIN * 2),
|
|
12813
|
+
height: Math.max(window.innerHeight, INSPECTOR_PET_MARGIN * 2),
|
|
12814
|
+
scale
|
|
12815
|
+
};
|
|
12816
|
+
}
|
|
12817
|
+
function readStoredRoaming() {
|
|
12818
|
+
if (typeof window === "undefined") return true;
|
|
12819
|
+
try {
|
|
12820
|
+
return window.localStorage.getItem(INSPECTOR_PET_ROAMING_STORAGE_KEY) !== "0";
|
|
12821
|
+
} catch {
|
|
12822
|
+
return true;
|
|
12823
|
+
}
|
|
12824
|
+
}
|
|
12825
|
+
function moodDotClass(mood) {
|
|
12826
|
+
switch (mood) {
|
|
12827
|
+
case "active":
|
|
12828
|
+
return "bg-cyan-400 shadow-[0_0_9px_rgba(34,211,238,0.65)]";
|
|
12829
|
+
case "attention":
|
|
12830
|
+
return "bg-red-500 shadow-[0_0_9px_rgba(239,68,68,0.55)]";
|
|
12831
|
+
case "idle":
|
|
12832
|
+
return "bg-amber-400 shadow-[0_0_8px_rgba(251,191,36,0.45)]";
|
|
12833
|
+
case "sleeping":
|
|
12834
|
+
return "bg-muted-foreground/45";
|
|
12835
|
+
}
|
|
12836
|
+
}
|
|
12837
|
+
function moodMotionClass(mood) {
|
|
12838
|
+
switch (mood) {
|
|
12839
|
+
case "active":
|
|
12840
|
+
return "inspector-pet-active";
|
|
12841
|
+
case "attention":
|
|
12842
|
+
return "inspector-pet-attention";
|
|
12843
|
+
case "idle":
|
|
12844
|
+
return "";
|
|
12845
|
+
case "sleeping":
|
|
12846
|
+
return "inspector-pet-sleeping";
|
|
12847
|
+
}
|
|
12848
|
+
}
|
|
12849
|
+
function InspectorPet({ logs }) {
|
|
12850
|
+
const [portalHost, setPortalHost] = reactExports.useState(null);
|
|
12851
|
+
const [viewport, setViewport] = reactExports.useState(readViewport);
|
|
12852
|
+
const [position, setPosition] = reactExports.useState({
|
|
12853
|
+
x: INSPECTOR_PET_MARGIN,
|
|
12854
|
+
y: INSPECTOR_PET_MARGIN
|
|
12855
|
+
});
|
|
12856
|
+
const [clockMs, setClockMs] = reactExports.useState(() => Date.now());
|
|
12857
|
+
const [scuttling, setScuttling] = reactExports.useState(false);
|
|
12858
|
+
const [panelTick, setPanelTick] = reactExports.useState(0);
|
|
12859
|
+
const [panelVisible, setPanelVisible] = reactExports.useState(false);
|
|
12860
|
+
const [reactionTick, setReactionTick] = reactExports.useState(0);
|
|
12861
|
+
const [reactionVisible, setReactionVisible] = reactExports.useState(false);
|
|
12862
|
+
const [dragging, setDragging] = reactExports.useState(false);
|
|
12863
|
+
const [roaming, setRoaming] = reactExports.useState(readStoredRoaming);
|
|
12864
|
+
const [reduceMotion, setReduceMotion] = reactExports.useState(false);
|
|
12865
|
+
const dragStateRef = reactExports.useRef(null);
|
|
12866
|
+
const dragOccurredRef = reactExports.useRef(false);
|
|
12867
|
+
const status = reactExports.useMemo(() => resolveInspectorPetStatus(logs, clockMs), [clockMs, logs]);
|
|
12868
|
+
const panelPosition = reactExports.useMemo(
|
|
12869
|
+
() => inspectorPetPanelPosition(position, viewport),
|
|
12870
|
+
[position, viewport]
|
|
12871
|
+
);
|
|
12872
|
+
reactExports.useEffect(() => setPortalHost(document.body), []);
|
|
12873
|
+
reactExports.useEffect(() => {
|
|
12874
|
+
const nextViewport = readViewport();
|
|
12875
|
+
setViewport(nextViewport);
|
|
12876
|
+
setPosition(randomInspectorPetEdgePosition(nextViewport, Math.random()));
|
|
12877
|
+
}, []);
|
|
12878
|
+
reactExports.useEffect(() => {
|
|
12879
|
+
const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
12880
|
+
const handleChange = (event) => setReduceMotion(event.matches);
|
|
12881
|
+
setReduceMotion(mediaQuery.matches);
|
|
12882
|
+
mediaQuery.addEventListener("change", handleChange);
|
|
12883
|
+
return () => mediaQuery.removeEventListener("change", handleChange);
|
|
12884
|
+
}, []);
|
|
12885
|
+
reactExports.useEffect(() => {
|
|
12886
|
+
const intervalId = window.setInterval(() => setClockMs(Date.now()), 15e3);
|
|
12887
|
+
return () => window.clearInterval(intervalId);
|
|
12888
|
+
}, []);
|
|
12889
|
+
reactExports.useEffect(() => {
|
|
12890
|
+
try {
|
|
12891
|
+
window.localStorage.setItem(INSPECTOR_PET_ROAMING_STORAGE_KEY, roaming ? "1" : "0");
|
|
12892
|
+
} catch {
|
|
12893
|
+
}
|
|
12894
|
+
}, [roaming]);
|
|
12895
|
+
reactExports.useEffect(() => {
|
|
12896
|
+
if (!roaming || dragging || reduceMotion) return void 0;
|
|
12897
|
+
let pauseTimeoutId = null;
|
|
12898
|
+
let scuttleTimeoutId = null;
|
|
12899
|
+
const scheduleScuttle = () => {
|
|
12900
|
+
const delay = INSPECTOR_PET_MIN_PAUSE_MS + Math.random() * INSPECTOR_PET_PAUSE_WINDOW_MS;
|
|
12901
|
+
pauseTimeoutId = window.setTimeout(() => {
|
|
12902
|
+
setScuttling(true);
|
|
12903
|
+
setPosition(
|
|
12904
|
+
(current) => nextInspectorPetWalkingPosition(current, viewport, Math.random(), Math.random())
|
|
12905
|
+
);
|
|
12906
|
+
scuttleTimeoutId = window.setTimeout(() => {
|
|
12907
|
+
setScuttling(false);
|
|
12908
|
+
scheduleScuttle();
|
|
12909
|
+
}, INSPECTOR_PET_SCUTTLE_MS);
|
|
12910
|
+
}, delay);
|
|
12911
|
+
};
|
|
12912
|
+
scheduleScuttle();
|
|
12913
|
+
return () => {
|
|
12914
|
+
if (pauseTimeoutId !== null) window.clearTimeout(pauseTimeoutId);
|
|
12915
|
+
if (scuttleTimeoutId !== null) window.clearTimeout(scuttleTimeoutId);
|
|
12916
|
+
};
|
|
12917
|
+
}, [dragging, reduceMotion, roaming, viewport]);
|
|
12918
|
+
reactExports.useEffect(() => {
|
|
12919
|
+
const handleResize = () => {
|
|
12920
|
+
const nextViewport = readViewport();
|
|
12921
|
+
setScuttling(false);
|
|
12922
|
+
setViewport(nextViewport);
|
|
12923
|
+
setPosition((current) => snapInspectorPetToEdge(current, nextViewport));
|
|
12924
|
+
};
|
|
12925
|
+
window.addEventListener("resize", handleResize);
|
|
12926
|
+
return () => window.removeEventListener("resize", handleResize);
|
|
12927
|
+
}, []);
|
|
12928
|
+
reactExports.useEffect(() => {
|
|
12929
|
+
if (!panelVisible) return void 0;
|
|
12930
|
+
const timeoutId = window.setTimeout(
|
|
12931
|
+
() => setPanelVisible(false),
|
|
12932
|
+
INSPECTOR_PET_PANEL_DISMISS_MS
|
|
12933
|
+
);
|
|
12934
|
+
return () => window.clearTimeout(timeoutId);
|
|
12935
|
+
}, [panelTick, panelVisible]);
|
|
12936
|
+
reactExports.useEffect(() => {
|
|
12937
|
+
if (!reactionVisible) return void 0;
|
|
12938
|
+
const timeoutId = window.setTimeout(() => setReactionVisible(false), INSPECTOR_PET_REACTION_MS);
|
|
12939
|
+
return () => window.clearTimeout(timeoutId);
|
|
12940
|
+
}, [reactionTick, reactionVisible]);
|
|
12941
|
+
const handlePet = reactExports.useCallback(() => {
|
|
12942
|
+
if (dragOccurredRef.current) {
|
|
12943
|
+
dragOccurredRef.current = false;
|
|
12944
|
+
return;
|
|
12945
|
+
}
|
|
12946
|
+
setClockMs(Date.now());
|
|
12947
|
+
setPanelTick((current) => current + 1);
|
|
12948
|
+
setPanelVisible(true);
|
|
12949
|
+
setReactionTick((current) => current + 1);
|
|
12950
|
+
setReactionVisible(true);
|
|
12951
|
+
}, []);
|
|
12952
|
+
const handlePointerDown = reactExports.useCallback((event) => {
|
|
12953
|
+
const rect = event.currentTarget.getBoundingClientRect();
|
|
12954
|
+
dragOccurredRef.current = false;
|
|
12955
|
+
dragStateRef.current = {
|
|
12956
|
+
pointerId: event.pointerId,
|
|
12957
|
+
offsetX: event.clientX - rect.left,
|
|
12958
|
+
offsetY: event.clientY - rect.top,
|
|
12959
|
+
startX: event.clientX,
|
|
12960
|
+
startY: event.clientY,
|
|
12961
|
+
moved: false
|
|
12962
|
+
};
|
|
12963
|
+
event.currentTarget.setPointerCapture(event.pointerId);
|
|
12964
|
+
setScuttling(false);
|
|
12965
|
+
setPanelVisible(false);
|
|
12966
|
+
setDragging(true);
|
|
12967
|
+
}, []);
|
|
12968
|
+
const handlePointerMove = reactExports.useCallback(
|
|
12969
|
+
(event) => {
|
|
12970
|
+
const dragState = dragStateRef.current;
|
|
12971
|
+
if (dragState === null || dragState.pointerId !== event.pointerId) return;
|
|
12972
|
+
const moved = dragState.moved || Math.abs(event.clientX - dragState.startX) >= INSPECTOR_PET_DRAG_THRESHOLD || Math.abs(event.clientY - dragState.startY) >= INSPECTOR_PET_DRAG_THRESHOLD;
|
|
12973
|
+
dragState.moved = moved;
|
|
12974
|
+
dragOccurredRef.current = moved;
|
|
12975
|
+
setPosition(
|
|
12976
|
+
clampInspectorPetPosition(
|
|
12977
|
+
{
|
|
12978
|
+
x: event.clientX - dragState.offsetX,
|
|
12979
|
+
y: event.clientY - dragState.offsetY
|
|
12980
|
+
},
|
|
12981
|
+
viewport
|
|
12982
|
+
)
|
|
12983
|
+
);
|
|
12984
|
+
},
|
|
12985
|
+
[viewport]
|
|
12986
|
+
);
|
|
12987
|
+
const handlePointerUp = reactExports.useCallback(
|
|
12988
|
+
(event) => {
|
|
12989
|
+
const dragState = dragStateRef.current;
|
|
12990
|
+
if (dragState === null || dragState.pointerId !== event.pointerId) return;
|
|
12991
|
+
if (event.currentTarget.hasPointerCapture(event.pointerId)) {
|
|
12992
|
+
event.currentTarget.releasePointerCapture(event.pointerId);
|
|
12993
|
+
}
|
|
12994
|
+
dragOccurredRef.current = dragState.moved;
|
|
12995
|
+
dragStateRef.current = null;
|
|
12996
|
+
setDragging(false);
|
|
12997
|
+
setPosition((current) => snapInspectorPetToEdge(current, viewport));
|
|
12998
|
+
},
|
|
12999
|
+
[viewport]
|
|
13000
|
+
);
|
|
13001
|
+
const handlePointerCancel = reactExports.useCallback((event) => {
|
|
13002
|
+
if (event.currentTarget.hasPointerCapture(event.pointerId)) {
|
|
13003
|
+
event.currentTarget.releasePointerCapture(event.pointerId);
|
|
13004
|
+
}
|
|
13005
|
+
dragStateRef.current = null;
|
|
13006
|
+
dragOccurredRef.current = false;
|
|
13007
|
+
setDragging(false);
|
|
13008
|
+
}, []);
|
|
13009
|
+
const handleToggleRoaming = reactExports.useCallback(() => {
|
|
13010
|
+
setScuttling(false);
|
|
13011
|
+
setRoaming((current) => !current);
|
|
13012
|
+
}, []);
|
|
13013
|
+
const petStyle = reactExports.useMemo(
|
|
13014
|
+
() => ({
|
|
13015
|
+
transform: `translate3d(${String(position.x)}px, ${String(position.y)}px, 0) scale(${dragging ? "1.04" : "1"})`,
|
|
13016
|
+
transition: dragging ? "none" : scuttling ? `transform ${String(INSPECTOR_PET_SCUTTLE_MS)}ms cubic-bezier(0.22, 0.72, 0.32, 1)` : "transform 900ms cubic-bezier(0.22, 0.72, 0.32, 1)",
|
|
13017
|
+
touchAction: "none"
|
|
13018
|
+
}),
|
|
13019
|
+
[dragging, position.x, position.y, scuttling]
|
|
13020
|
+
);
|
|
13021
|
+
const panelStyle = reactExports.useMemo(
|
|
13022
|
+
() => ({ left: panelPosition.x, top: panelPosition.y }),
|
|
13023
|
+
[panelPosition.x, panelPosition.y]
|
|
13024
|
+
);
|
|
13025
|
+
const roamingLabel = roaming ? "Pause pet roaming" : "Resume pet roaming";
|
|
13026
|
+
if (portalHost === null) return /* @__PURE__ */ jsxRuntimeExports.jsx(jsxRuntimeExports.Fragment, {});
|
|
13027
|
+
return reactDomExports.createPortal(
|
|
13028
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
13029
|
+
"div",
|
|
13030
|
+
{
|
|
13031
|
+
className: "pointer-events-none fixed inset-0 isolate",
|
|
13032
|
+
style: { zIndex: INSPECTOR_PET_TOP_LAYER_Z_INDEX },
|
|
13033
|
+
"data-inspector-pet-layer": "true",
|
|
13034
|
+
children: [
|
|
13035
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
13036
|
+
"button",
|
|
13037
|
+
{
|
|
13038
|
+
type: "button",
|
|
13039
|
+
className: cn(
|
|
13040
|
+
"pointer-events-auto fixed left-0 top-0 z-10 flex size-28 items-center justify-center bg-transparent text-foreground outline-none transition-[filter,opacity] duration-200 hover:opacity-95 hover:drop-shadow-[0_0_28px_rgba(245,158,11,0.32)] focus-visible:drop-shadow-[0_0_14px_rgba(251,191,36,0.72)]",
|
|
13041
|
+
dragging ? "cursor-grabbing" : "cursor-grab"
|
|
13042
|
+
),
|
|
13043
|
+
style: petStyle,
|
|
13044
|
+
"data-pet-mood": status.mood,
|
|
13045
|
+
"data-pet-moving": scuttling ? "true" : "false",
|
|
13046
|
+
onClick: handlePet,
|
|
13047
|
+
onPointerDown: handlePointerDown,
|
|
13048
|
+
onPointerMove: handlePointerMove,
|
|
13049
|
+
onPointerUp: handlePointerUp,
|
|
13050
|
+
onPointerCancel: handlePointerCancel,
|
|
13051
|
+
"aria-label": `Inspector pet: ${status.label}`,
|
|
13052
|
+
title: status.label,
|
|
13053
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
13054
|
+
"span",
|
|
13055
|
+
{
|
|
13056
|
+
className: cn(
|
|
13057
|
+
"relative z-10 flex size-24 items-center justify-center",
|
|
13058
|
+
reactionVisible && "inspector-pet-patted"
|
|
13059
|
+
),
|
|
13060
|
+
"aria-hidden": "true",
|
|
13061
|
+
children: [
|
|
13062
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
13063
|
+
"span",
|
|
13064
|
+
{
|
|
13065
|
+
className: cn(
|
|
13066
|
+
"relative flex size-24 items-center justify-center",
|
|
13067
|
+
moodMotionClass(status.mood)
|
|
13068
|
+
),
|
|
13069
|
+
children: /* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "relative flex size-24 items-center justify-center", children: /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
13070
|
+
InspectorPetCrab3D,
|
|
13071
|
+
{
|
|
13072
|
+
mood: status.mood,
|
|
13073
|
+
moving: scuttling && !dragging,
|
|
13074
|
+
reduceMotion
|
|
13075
|
+
}
|
|
13076
|
+
) })
|
|
13077
|
+
}
|
|
13078
|
+
),
|
|
13079
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
13080
|
+
"span",
|
|
13081
|
+
{
|
|
13082
|
+
className: cn(
|
|
13083
|
+
"absolute right-0 top-2 size-3 rounded-full border border-background/90",
|
|
13084
|
+
moodDotClass(status.mood),
|
|
13085
|
+
status.mood === "active" && !reduceMotion && "animate-pulse"
|
|
13086
|
+
)
|
|
13087
|
+
}
|
|
13088
|
+
),
|
|
13089
|
+
reactionVisible && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
13090
|
+
Heart,
|
|
13091
|
+
{
|
|
13092
|
+
className: "inspector-pet-heart absolute -right-2 -top-3 size-5 fill-amber-400 text-amber-400"
|
|
13093
|
+
},
|
|
13094
|
+
reactionTick
|
|
13095
|
+
)
|
|
13096
|
+
]
|
|
13097
|
+
}
|
|
13098
|
+
)
|
|
13099
|
+
}
|
|
13100
|
+
),
|
|
13101
|
+
panelVisible && /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
13102
|
+
"div",
|
|
13103
|
+
{
|
|
13104
|
+
className: "pointer-events-auto fixed z-20 w-48 rounded-md border border-border/80 bg-popover/95 px-3 py-2 text-popover-foreground shadow-[0_14px_34px_rgba(0,0,0,0.28)] backdrop-blur",
|
|
13105
|
+
style: panelStyle,
|
|
13106
|
+
role: "status",
|
|
13107
|
+
"aria-live": "polite",
|
|
13108
|
+
children: [
|
|
13109
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "flex min-w-0 items-center gap-2", children: [
|
|
13110
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: cn("size-2 shrink-0 rounded-full", moodDotClass(status.mood)) }),
|
|
13111
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "min-w-0 flex-1 truncate text-xs font-medium", children: status.label }),
|
|
13112
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
13113
|
+
"button",
|
|
13114
|
+
{
|
|
13115
|
+
type: "button",
|
|
13116
|
+
className: "inline-flex size-6 shrink-0 items-center justify-center rounded text-muted-foreground transition-colors hover:bg-muted hover:text-foreground focus-visible:ring-1 focus-visible:ring-ring focus-visible:outline-none",
|
|
13117
|
+
onClick: handleToggleRoaming,
|
|
13118
|
+
"aria-label": roamingLabel,
|
|
13119
|
+
title: roamingLabel,
|
|
13120
|
+
children: roaming ? /* @__PURE__ */ jsxRuntimeExports.jsx(Pause, { className: "size-3.5" }) : /* @__PURE__ */ jsxRuntimeExports.jsx(Play, { className: "size-3.5" })
|
|
13121
|
+
}
|
|
13122
|
+
)
|
|
13123
|
+
] }),
|
|
13124
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("div", { className: "mt-1 flex items-center justify-between gap-3 font-mono text-[10px] text-muted-foreground", children: [
|
|
13125
|
+
/* @__PURE__ */ jsxRuntimeExports.jsxs("span", { children: [
|
|
13126
|
+
String(status.capturedCount),
|
|
13127
|
+
" captured"
|
|
13128
|
+
] }),
|
|
13129
|
+
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { children: status.pendingCount > 0 ? `${String(status.pendingCount)} active` : scuttling ? "Scuttling" : roaming ? "Resting" : "Paused" })
|
|
13130
|
+
] })
|
|
13131
|
+
]
|
|
13132
|
+
}
|
|
13133
|
+
)
|
|
13134
|
+
]
|
|
13135
|
+
}
|
|
13136
|
+
),
|
|
13137
|
+
portalHost
|
|
13138
|
+
);
|
|
13139
|
+
}
|
|
13140
|
+
const DEFAULT_QUESTION = "Analyze the current Inspector session. What looks abnormal, slow, or likely to hang?";
|
|
13141
|
+
function providerSupportsPiAgent(provider) {
|
|
13142
|
+
return provider.openaiResponsesBaseUrl !== void 0 || provider.openaiBaseUrl !== void 0 || provider.anthropicBaseUrl !== void 0;
|
|
13143
|
+
}
|
|
13144
|
+
function providerProtocolLabel(provider) {
|
|
13145
|
+
if (provider.openaiResponsesBaseUrl !== void 0 && provider.openaiResponsesBaseUrl !== "") {
|
|
13146
|
+
return "Responses";
|
|
13147
|
+
}
|
|
13148
|
+
if (provider.openaiBaseUrl !== void 0 && provider.openaiBaseUrl !== "") {
|
|
13149
|
+
return "Chat";
|
|
13150
|
+
}
|
|
13151
|
+
return "Anthropic";
|
|
13152
|
+
}
|
|
13153
|
+
function sortProviderBySource(providers) {
|
|
12151
13154
|
return providers.toSorted((left, right) => {
|
|
12152
13155
|
const leftCompanyRank = left.source === "company" ? 0 : 1;
|
|
12153
13156
|
const rightCompanyRank = right.source === "company" ? 0 : 1;
|
|
@@ -14561,256 +15564,12 @@ function BrandHeader({
|
|
|
14561
15564
|
] })
|
|
14562
15565
|
] });
|
|
14563
15566
|
}
|
|
14564
|
-
const FLOATING_LOGO_SIZE = 56;
|
|
14565
|
-
const FLOATING_LOGO_MARGIN = 14;
|
|
14566
|
-
const FLOATING_LOGO_MIN_DRIFT_MS = 5200;
|
|
14567
|
-
const FLOATING_LOGO_DRIFT_WINDOW_MS = 2400;
|
|
14568
|
-
const FLOATING_LOGO_MIN_STEP = 72;
|
|
14569
|
-
const FLOATING_LOGO_MAX_STEP = 156;
|
|
14570
15567
|
const DETAILS_PANEL_COLLAPSED_STORAGE_KEY = "agent-inspector.detailsPanelCollapsed";
|
|
14571
15568
|
function readStoredDetailsPanelCollapsed() {
|
|
14572
15569
|
if (typeof window === "undefined") return true;
|
|
14573
15570
|
const stored = window.localStorage.getItem(DETAILS_PANEL_COLLAPSED_STORAGE_KEY);
|
|
14574
15571
|
return stored === null || stored === "1";
|
|
14575
15572
|
}
|
|
14576
|
-
function clampFloatingLogoPosition(position) {
|
|
14577
|
-
const maxX = Math.max(
|
|
14578
|
-
FLOATING_LOGO_MARGIN,
|
|
14579
|
-
window.innerWidth - FLOATING_LOGO_SIZE - FLOATING_LOGO_MARGIN
|
|
14580
|
-
);
|
|
14581
|
-
const maxY = Math.max(
|
|
14582
|
-
FLOATING_LOGO_MARGIN,
|
|
14583
|
-
window.innerHeight - FLOATING_LOGO_SIZE - FLOATING_LOGO_MARGIN
|
|
14584
|
-
);
|
|
14585
|
-
return {
|
|
14586
|
-
x: Math.min(Math.max(position.x, FLOATING_LOGO_MARGIN), maxX),
|
|
14587
|
-
y: Math.min(Math.max(position.y, FLOATING_LOGO_MARGIN), maxY)
|
|
14588
|
-
};
|
|
14589
|
-
}
|
|
14590
|
-
function snapFloatingLogoToEdge(position) {
|
|
14591
|
-
const clamped = clampFloatingLogoPosition(position);
|
|
14592
|
-
const maxX = Math.max(
|
|
14593
|
-
FLOATING_LOGO_MARGIN,
|
|
14594
|
-
window.innerWidth - FLOATING_LOGO_SIZE - FLOATING_LOGO_MARGIN
|
|
14595
|
-
);
|
|
14596
|
-
const maxY = Math.max(
|
|
14597
|
-
FLOATING_LOGO_MARGIN,
|
|
14598
|
-
window.innerHeight - FLOATING_LOGO_SIZE - FLOATING_LOGO_MARGIN
|
|
14599
|
-
);
|
|
14600
|
-
const leftDistance = clamped.x - FLOATING_LOGO_MARGIN;
|
|
14601
|
-
const rightDistance = maxX - clamped.x;
|
|
14602
|
-
const topDistance = clamped.y - FLOATING_LOGO_MARGIN;
|
|
14603
|
-
const bottomDistance = maxY - clamped.y;
|
|
14604
|
-
const nearestDistance = Math.min(leftDistance, rightDistance, topDistance, bottomDistance);
|
|
14605
|
-
if (nearestDistance === leftDistance) return { x: FLOATING_LOGO_MARGIN, y: clamped.y };
|
|
14606
|
-
if (nearestDistance === rightDistance) return { x: maxX, y: clamped.y };
|
|
14607
|
-
if (nearestDistance === topDistance) return { x: clamped.x, y: FLOATING_LOGO_MARGIN };
|
|
14608
|
-
return { x: clamped.x, y: maxY };
|
|
14609
|
-
}
|
|
14610
|
-
function randomFloatingLogoEdgePosition() {
|
|
14611
|
-
const maxX = Math.max(
|
|
14612
|
-
FLOATING_LOGO_MARGIN,
|
|
14613
|
-
window.innerWidth - FLOATING_LOGO_SIZE - FLOATING_LOGO_MARGIN
|
|
14614
|
-
);
|
|
14615
|
-
const maxY = Math.max(
|
|
14616
|
-
FLOATING_LOGO_MARGIN,
|
|
14617
|
-
window.innerHeight - FLOATING_LOGO_SIZE - FLOATING_LOGO_MARGIN
|
|
14618
|
-
);
|
|
14619
|
-
const randomX = FLOATING_LOGO_MARGIN + Math.random() * (maxX - FLOATING_LOGO_MARGIN);
|
|
14620
|
-
const randomY = FLOATING_LOGO_MARGIN + Math.random() * (maxY - FLOATING_LOGO_MARGIN);
|
|
14621
|
-
const edgeIndex = Math.floor(Math.random() * 4);
|
|
14622
|
-
switch (edgeIndex) {
|
|
14623
|
-
case 0:
|
|
14624
|
-
return { x: FLOATING_LOGO_MARGIN, y: randomY };
|
|
14625
|
-
case 1:
|
|
14626
|
-
return { x: maxX, y: randomY };
|
|
14627
|
-
case 2:
|
|
14628
|
-
return { x: randomX, y: FLOATING_LOGO_MARGIN };
|
|
14629
|
-
case 3:
|
|
14630
|
-
return { x: randomX, y: maxY };
|
|
14631
|
-
default:
|
|
14632
|
-
return { x: maxX, y: FLOATING_LOGO_MARGIN };
|
|
14633
|
-
}
|
|
14634
|
-
}
|
|
14635
|
-
function nearestFloatingLogoEdge(position) {
|
|
14636
|
-
const clamped = clampFloatingLogoPosition(position);
|
|
14637
|
-
const maxX = Math.max(
|
|
14638
|
-
FLOATING_LOGO_MARGIN,
|
|
14639
|
-
window.innerWidth - FLOATING_LOGO_SIZE - FLOATING_LOGO_MARGIN
|
|
14640
|
-
);
|
|
14641
|
-
const maxY = Math.max(
|
|
14642
|
-
FLOATING_LOGO_MARGIN,
|
|
14643
|
-
window.innerHeight - FLOATING_LOGO_SIZE - FLOATING_LOGO_MARGIN
|
|
14644
|
-
);
|
|
14645
|
-
const distances = [
|
|
14646
|
-
{ edge: "left", distance: clamped.x - FLOATING_LOGO_MARGIN },
|
|
14647
|
-
{ edge: "right", distance: maxX - clamped.x },
|
|
14648
|
-
{ edge: "top", distance: clamped.y - FLOATING_LOGO_MARGIN },
|
|
14649
|
-
{ edge: "bottom", distance: maxY - clamped.y }
|
|
14650
|
-
];
|
|
14651
|
-
return distances.reduce((best, current) => current.distance < best.distance ? current : best).edge;
|
|
14652
|
-
}
|
|
14653
|
-
function nextFloatingLogoWalkingPosition(position) {
|
|
14654
|
-
const clamped = snapFloatingLogoToEdge(position);
|
|
14655
|
-
const maxX = Math.max(
|
|
14656
|
-
FLOATING_LOGO_MARGIN,
|
|
14657
|
-
window.innerWidth - FLOATING_LOGO_SIZE - FLOATING_LOGO_MARGIN
|
|
14658
|
-
);
|
|
14659
|
-
const maxY = Math.max(
|
|
14660
|
-
FLOATING_LOGO_MARGIN,
|
|
14661
|
-
window.innerHeight - FLOATING_LOGO_SIZE - FLOATING_LOGO_MARGIN
|
|
14662
|
-
);
|
|
14663
|
-
const step = FLOATING_LOGO_MIN_STEP + Math.random() * (FLOATING_LOGO_MAX_STEP - FLOATING_LOGO_MIN_STEP);
|
|
14664
|
-
const direction = Math.random() > 0.5 ? 1 : -1;
|
|
14665
|
-
const edge = nearestFloatingLogoEdge(clamped);
|
|
14666
|
-
switch (edge) {
|
|
14667
|
-
case "left": {
|
|
14668
|
-
const nextY = clamped.y + step * direction;
|
|
14669
|
-
if (nextY <= FLOATING_LOGO_MARGIN)
|
|
14670
|
-
return { x: FLOATING_LOGO_MARGIN, y: FLOATING_LOGO_MARGIN };
|
|
14671
|
-
if (nextY >= maxY) return { x: FLOATING_LOGO_MARGIN, y: maxY };
|
|
14672
|
-
return { x: FLOATING_LOGO_MARGIN, y: nextY };
|
|
14673
|
-
}
|
|
14674
|
-
case "right": {
|
|
14675
|
-
const nextY = clamped.y + step * direction;
|
|
14676
|
-
if (nextY <= FLOATING_LOGO_MARGIN) return { x: maxX, y: FLOATING_LOGO_MARGIN };
|
|
14677
|
-
if (nextY >= maxY) return { x: maxX, y: maxY };
|
|
14678
|
-
return { x: maxX, y: nextY };
|
|
14679
|
-
}
|
|
14680
|
-
case "top": {
|
|
14681
|
-
const nextX = clamped.x + step * direction;
|
|
14682
|
-
if (nextX <= FLOATING_LOGO_MARGIN)
|
|
14683
|
-
return { x: FLOATING_LOGO_MARGIN, y: FLOATING_LOGO_MARGIN };
|
|
14684
|
-
if (nextX >= maxX) return { x: maxX, y: FLOATING_LOGO_MARGIN };
|
|
14685
|
-
return { x: nextX, y: FLOATING_LOGO_MARGIN };
|
|
14686
|
-
}
|
|
14687
|
-
case "bottom": {
|
|
14688
|
-
const nextX = clamped.x + step * direction;
|
|
14689
|
-
if (nextX <= FLOATING_LOGO_MARGIN) return { x: FLOATING_LOGO_MARGIN, y: maxY };
|
|
14690
|
-
if (nextX >= maxX) return { x: maxX, y: maxY };
|
|
14691
|
-
return { x: nextX, y: maxY };
|
|
14692
|
-
}
|
|
14693
|
-
}
|
|
14694
|
-
}
|
|
14695
|
-
function FloatingInspectorLogo() {
|
|
14696
|
-
const [position, setPosition] = reactExports.useState({
|
|
14697
|
-
x: FLOATING_LOGO_MARGIN,
|
|
14698
|
-
y: FLOATING_LOGO_MARGIN
|
|
14699
|
-
});
|
|
14700
|
-
const [motionTick, setMotionTick] = reactExports.useState(0);
|
|
14701
|
-
const [dragging, setDragging] = reactExports.useState(false);
|
|
14702
|
-
const dragStateRef = reactExports.useRef(null);
|
|
14703
|
-
reactExports.useEffect(() => {
|
|
14704
|
-
setPosition(randomFloatingLogoEdgePosition());
|
|
14705
|
-
}, []);
|
|
14706
|
-
reactExports.useEffect(() => {
|
|
14707
|
-
if (dragging) return void 0;
|
|
14708
|
-
let timeoutId = null;
|
|
14709
|
-
const scheduleDrift = () => {
|
|
14710
|
-
const delay = FLOATING_LOGO_MIN_DRIFT_MS + Math.random() * FLOATING_LOGO_DRIFT_WINDOW_MS;
|
|
14711
|
-
timeoutId = window.setTimeout(() => {
|
|
14712
|
-
setMotionTick((current) => current + 1);
|
|
14713
|
-
setPosition((current) => nextFloatingLogoWalkingPosition(current));
|
|
14714
|
-
scheduleDrift();
|
|
14715
|
-
}, delay);
|
|
14716
|
-
};
|
|
14717
|
-
scheduleDrift();
|
|
14718
|
-
return () => {
|
|
14719
|
-
if (timeoutId !== null) {
|
|
14720
|
-
window.clearTimeout(timeoutId);
|
|
14721
|
-
}
|
|
14722
|
-
};
|
|
14723
|
-
}, [dragging]);
|
|
14724
|
-
reactExports.useEffect(() => {
|
|
14725
|
-
const handleResize = () => {
|
|
14726
|
-
setPosition((current) => snapFloatingLogoToEdge(current));
|
|
14727
|
-
};
|
|
14728
|
-
window.addEventListener("resize", handleResize);
|
|
14729
|
-
return () => window.removeEventListener("resize", handleResize);
|
|
14730
|
-
}, []);
|
|
14731
|
-
const handlePointerDown = reactExports.useCallback((event) => {
|
|
14732
|
-
const rect = event.currentTarget.getBoundingClientRect();
|
|
14733
|
-
dragStateRef.current = {
|
|
14734
|
-
pointerId: event.pointerId,
|
|
14735
|
-
offsetX: event.clientX - rect.left,
|
|
14736
|
-
offsetY: event.clientY - rect.top
|
|
14737
|
-
};
|
|
14738
|
-
event.currentTarget.setPointerCapture(event.pointerId);
|
|
14739
|
-
setDragging(true);
|
|
14740
|
-
}, []);
|
|
14741
|
-
const handlePointerMove = reactExports.useCallback((event) => {
|
|
14742
|
-
const dragState = dragStateRef.current;
|
|
14743
|
-
if (dragState === null || dragState.pointerId !== event.pointerId) return;
|
|
14744
|
-
setPosition(
|
|
14745
|
-
clampFloatingLogoPosition({
|
|
14746
|
-
x: event.clientX - dragState.offsetX,
|
|
14747
|
-
y: event.clientY - dragState.offsetY
|
|
14748
|
-
})
|
|
14749
|
-
);
|
|
14750
|
-
}, []);
|
|
14751
|
-
const handlePointerUp = reactExports.useCallback((event) => {
|
|
14752
|
-
const dragState = dragStateRef.current;
|
|
14753
|
-
if (dragState === null || dragState.pointerId !== event.pointerId) return;
|
|
14754
|
-
if (event.currentTarget.hasPointerCapture(event.pointerId)) {
|
|
14755
|
-
event.currentTarget.releasePointerCapture(event.pointerId);
|
|
14756
|
-
}
|
|
14757
|
-
dragStateRef.current = null;
|
|
14758
|
-
setDragging(false);
|
|
14759
|
-
setPosition((current) => snapFloatingLogoToEdge(current));
|
|
14760
|
-
}, []);
|
|
14761
|
-
const style = reactExports.useMemo(
|
|
14762
|
-
() => ({
|
|
14763
|
-
transform: `translate3d(${position.x}px, ${position.y}px, 0) rotate(${motionTick % 2 === 0 ? "-4deg" : "5deg"}) scale(${dragging ? "1.08" : "1"})`,
|
|
14764
|
-
transition: dragging ? "none" : "transform 4800ms cubic-bezier(0.33, 1, 0.68, 1)",
|
|
14765
|
-
touchAction: "none"
|
|
14766
|
-
}),
|
|
14767
|
-
[dragging, motionTick, position.x, position.y]
|
|
14768
|
-
);
|
|
14769
|
-
return /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14770
|
-
"button",
|
|
14771
|
-
{
|
|
14772
|
-
type: "button",
|
|
14773
|
-
className: cn(
|
|
14774
|
-
"fixed left-0 top-0 z-40 flex size-14 items-center justify-center rounded-full bg-transparent text-foreground outline-none transition-[filter,opacity] duration-200 hover:opacity-95 hover:drop-shadow-[0_0_24px_rgba(245,158,11,0.36)] focus-visible:ring-1 focus-visible:ring-amber-300/55",
|
|
14775
|
-
dragging ? "cursor-grabbing" : "cursor-grab"
|
|
14776
|
-
),
|
|
14777
|
-
style,
|
|
14778
|
-
onPointerDown: handlePointerDown,
|
|
14779
|
-
onPointerMove: handlePointerMove,
|
|
14780
|
-
onPointerUp: handlePointerUp,
|
|
14781
|
-
onPointerCancel: handlePointerUp,
|
|
14782
|
-
"aria-label": "Floating Inspector logo",
|
|
14783
|
-
title: "Drag Inspector logo",
|
|
14784
|
-
children: /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
14785
|
-
"span",
|
|
14786
|
-
{
|
|
14787
|
-
className: cn(
|
|
14788
|
-
"relative flex size-12 items-center justify-center",
|
|
14789
|
-
!dragging && "floating-crab-body"
|
|
14790
|
-
),
|
|
14791
|
-
"aria-hidden": "true",
|
|
14792
|
-
children: [
|
|
14793
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx(CrabLogo, { className: "relative z-10 size-11 text-amber-500 drop-shadow-[0_0_15px_rgba(245,158,11,0.30)]" }),
|
|
14794
|
-
/* @__PURE__ */ jsxRuntimeExports.jsx("span", { className: "pointer-events-none absolute inset-x-0 bottom-0 z-0 flex items-end justify-center gap-1 text-amber-400/80", children: [0, 1, 2, 3, 4, 5].map((leg) => /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
14795
|
-
"span",
|
|
14796
|
-
{
|
|
14797
|
-
className: cn(
|
|
14798
|
-
"floating-crab-leg h-2 w-0.5 rounded-full bg-current shadow-[0_0_7px_rgba(245,158,11,0.24)]",
|
|
14799
|
-
leg < 3 ? "floating-crab-leg-left" : "floating-crab-leg-right",
|
|
14800
|
-
dragging && "animate-none"
|
|
14801
|
-
),
|
|
14802
|
-
style: {
|
|
14803
|
-
animationDelay: `${leg % 2 === 0 ? 0 : 180}ms`
|
|
14804
|
-
}
|
|
14805
|
-
},
|
|
14806
|
-
leg
|
|
14807
|
-
)) })
|
|
14808
|
-
]
|
|
14809
|
-
}
|
|
14810
|
-
)
|
|
14811
|
-
}
|
|
14812
|
-
);
|
|
14813
|
-
}
|
|
14814
15573
|
function SessionContextLogButton({ label, logId }) {
|
|
14815
15574
|
return /* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
14816
15575
|
"button",
|
|
@@ -15379,7 +16138,7 @@ function ProxyViewer({
|
|
|
15379
16138
|
]
|
|
15380
16139
|
}
|
|
15381
16140
|
),
|
|
15382
|
-
detailsPanelCollapsed && /* @__PURE__ */ jsxRuntimeExports.jsx(
|
|
16141
|
+
detailsPanelCollapsed && /* @__PURE__ */ jsxRuntimeExports.jsx(InspectorPet, { logs }),
|
|
15383
16142
|
/* @__PURE__ */ jsxRuntimeExports.jsxs(
|
|
15384
16143
|
"div",
|
|
15385
16144
|
{
|