anygate 0.5.7 → 0.5.9
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/README.md +2 -2
- package/dist/chunk-6AFYEDSU.js +6934 -0
- package/dist/chunk-6AFYEDSU.js.map +1 -0
- package/dist/chunk-72WNE2IK.js +43 -0
- package/dist/chunk-P36O5B7N.js +168 -0
- package/dist/chunk-P36O5B7N.js.map +1 -0
- package/dist/{chunk-BCPX3QLK.js → chunk-PJ3L2TW7.js} +6810 -6628
- package/dist/chunk-PJ3L2TW7.js.map +1 -0
- package/dist/cli.js +11456 -11079
- package/dist/cli.js.map +1 -1
- package/dist/{command-E7O6ZQWJ.js → command-5BWYQP5G.js} +333 -19
- package/dist/command-5BWYQP5G.js.map +1 -0
- package/dist/constants-5RN2WJSS.js +29 -0
- package/dist/constants-5RN2WJSS.js.map +1 -0
- package/dist/provider-templates-MNJZTG3Z.js +25 -0
- package/dist/provider-templates-MNJZTG3Z.js.map +1 -0
- package/dist/registry/data/providers/go.json +10 -0
- package/dist/registry/data/providers/zen.json +10 -0
- package/dist/registry/data/templates/anthropic.json +13 -0
- package/dist/registry/data/templates/antigravity.json +15 -0
- package/dist/registry/data/templates/azure.json +11 -0
- package/dist/registry/data/templates/bedrock.json +11 -0
- package/dist/registry/data/templates/cerebras.json +13 -0
- package/dist/registry/data/templates/claude-code.json +15 -0
- package/dist/registry/data/templates/cohere.json +10 -0
- package/dist/registry/data/templates/deepinfra.json +13 -0
- package/dist/registry/data/templates/deepseek.json +13 -0
- package/dist/registry/data/templates/fireworks.json +13 -0
- package/dist/registry/data/templates/github-copilot.json +16 -0
- package/dist/registry/data/templates/go.json +13 -0
- package/dist/registry/data/templates/groq.json +13 -0
- package/dist/registry/data/templates/kilo.json +15 -0
- package/dist/registry/data/templates/lmstudio.json +14 -0
- package/dist/registry/data/templates/mistral.json +13 -0
- package/dist/registry/data/templates/nvidia.json +13 -0
- package/dist/registry/data/templates/ollama.json +14 -0
- package/dist/registry/data/templates/openai-oauth.json +13 -0
- package/dist/registry/data/templates/opencode-cloud.json +13 -0
- package/dist/registry/data/templates/openrouter.json +13 -0
- package/dist/registry/data/templates/ovh.json +13 -0
- package/dist/registry/data/templates/perplexity.json +13 -0
- package/dist/registry/data/templates/sambanova.json +12 -0
- package/dist/registry/data/templates/scaleway.json +13 -0
- package/dist/registry/data/templates/togetherai.json +13 -0
- package/dist/registry/data/templates/venice.json +13 -0
- package/dist/registry/data/templates/vertex.json +11 -0
- package/dist/registry/data/templates/xai-oauth.json +13 -0
- package/dist/registry/data/templates/xai.json +13 -0
- package/dist/registry/data/templates/zen.json +13 -0
- package/dist/ui/dist/assets/index-DWAOH_B3.css +1 -0
- package/dist/ui/dist/assets/index-gjYfrAXg.js +6 -0
- package/dist/ui/dist/index.html +2 -2
- package/package.json +3 -3
- package/dist/chunk-BCPX3QLK.js.map +0 -1
- package/dist/chunk-VKROC37K.js +0 -390
- package/dist/chunk-VKROC37K.js.map +0 -1
- package/dist/command-E7O6ZQWJ.js.map +0 -1
- package/dist/provider-templates-TWR5XSYI.js +0 -18
- package/dist/ui/dist/assets/index-3sdSv_1I.js +0 -5
- package/dist/ui/dist/assets/index-C4xd3r4v.css +0 -1
- /package/dist/{provider-templates-TWR5XSYI.js.map → chunk-72WNE2IK.js.map} +0 -0
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import {
|
|
3
|
-
BACKENDS,
|
|
4
|
-
MAX_MODEL_CATALOG,
|
|
5
3
|
addCustomEndpointProvider,
|
|
6
4
|
addProviderFromTemplate,
|
|
7
5
|
aggregateAnalytics,
|
|
@@ -31,6 +29,8 @@ import {
|
|
|
31
29
|
getServerMaskGatewayIds,
|
|
32
30
|
getUiDebugLogPath,
|
|
33
31
|
guiCallbackRedirectUri,
|
|
32
|
+
init_config,
|
|
33
|
+
init_paths,
|
|
34
34
|
loadPreferences,
|
|
35
35
|
loadRegistry,
|
|
36
36
|
loadServerModels,
|
|
@@ -66,15 +66,22 @@ import {
|
|
|
66
66
|
summarizeServerProviders,
|
|
67
67
|
validateCustomEndpointUrl,
|
|
68
68
|
writeSecureLogLine
|
|
69
|
-
} from "./chunk-
|
|
69
|
+
} from "./chunk-PJ3L2TW7.js";
|
|
70
|
+
import {
|
|
71
|
+
BACKENDS,
|
|
72
|
+
MAX_MODEL_CATALOG
|
|
73
|
+
} from "./chunk-P36O5B7N.js";
|
|
70
74
|
import {
|
|
71
75
|
getTemplateById,
|
|
72
|
-
|
|
76
|
+
listSupportedTemplates,
|
|
73
77
|
listVisibleOAuthTemplates
|
|
74
|
-
} from "./chunk-
|
|
78
|
+
} from "./chunk-6AFYEDSU.js";
|
|
79
|
+
import "./chunk-72WNE2IK.js";
|
|
75
80
|
|
|
76
81
|
// src/ui/command.ts
|
|
82
|
+
init_paths();
|
|
77
83
|
import { createServer } from "http";
|
|
84
|
+
import { execSync } from "child_process";
|
|
78
85
|
import { readFileSync, readdirSync, writeFileSync as writeFileSync2, unlinkSync, existsSync as existsSync3, mkdirSync } from "fs";
|
|
79
86
|
import { join as join2 } from "path";
|
|
80
87
|
import { fileURLToPath } from "url";
|
|
@@ -82,7 +89,8 @@ import { dirname } from "path";
|
|
|
82
89
|
import pc from "picocolors";
|
|
83
90
|
import * as p from "@clack/prompts";
|
|
84
91
|
|
|
85
|
-
// src/
|
|
92
|
+
// src/apps/shared/native-launcher.ts
|
|
93
|
+
init_config();
|
|
86
94
|
import { chmodSync, existsSync, mkdtempSync, writeFileSync } from "fs";
|
|
87
95
|
import { homedir } from "os";
|
|
88
96
|
import { tmpdir } from "os";
|
|
@@ -347,12 +355,14 @@ function getSupportedApps() {
|
|
|
347
355
|
}
|
|
348
356
|
|
|
349
357
|
// src/ui/api.ts
|
|
358
|
+
init_config();
|
|
350
359
|
import { exec } from "child_process";
|
|
351
360
|
import { promisify } from "util";
|
|
352
361
|
import { existsSync as existsSync2, statSync } from "fs";
|
|
353
362
|
import { randomUUID } from "crypto";
|
|
354
363
|
|
|
355
364
|
// src/ui/server-control.ts
|
|
365
|
+
init_config();
|
|
356
366
|
var running = null;
|
|
357
367
|
var startInFlight = null;
|
|
358
368
|
var SAVED_PASSWORD_CACHE_TTL_MS = 3e4;
|
|
@@ -581,6 +591,8 @@ function handleUiApiRequest(req, res, opts = {}) {
|
|
|
581
591
|
handlePostConfig(req, res);
|
|
582
592
|
} else if (url === "/api/models" && req.method === "GET") {
|
|
583
593
|
handleGetModels(res);
|
|
594
|
+
} else if (url === "/api/models/test" && req.method === "POST") {
|
|
595
|
+
handleTestModel(req, res);
|
|
584
596
|
} else if (url === "/api/keys" && req.method === "POST") {
|
|
585
597
|
handlePostKeys(req, res);
|
|
586
598
|
} else if (url === "/api/providers/refresh" && req.method === "POST") {
|
|
@@ -595,11 +607,11 @@ function handleUiApiRequest(req, res, opts = {}) {
|
|
|
595
607
|
handleAddCustomProvider(req, res);
|
|
596
608
|
} else if (url === "/api/providers/delete" && req.method === "POST") {
|
|
597
609
|
handleDeleteProvider(req, res);
|
|
598
|
-
} else if (url === "/api/providers/
|
|
610
|
+
} else if (url === "/api/providers/auth/start" && req.method === "POST") {
|
|
599
611
|
handleOAuthStart(req, res);
|
|
600
|
-
} else if (url.startsWith("/api/providers/
|
|
612
|
+
} else if (url.startsWith("/api/providers/auth/status") && req.method === "GET") {
|
|
601
613
|
handleOAuthStatus(req, res);
|
|
602
|
-
} else if (url.startsWith("/
|
|
614
|
+
} else if (url.startsWith("/auth/callback") && req.method === "GET") {
|
|
603
615
|
handleOAuthCallback(req, res);
|
|
604
616
|
} else if (url === "/api/apps" && req.method === "GET") {
|
|
605
617
|
handleGetApps(res);
|
|
@@ -705,6 +717,294 @@ async function handleGetModels(res) {
|
|
|
705
717
|
sendCatalogFetchError(res, err, "Model fetch");
|
|
706
718
|
}
|
|
707
719
|
}
|
|
720
|
+
var TEST_TIMEOUT_MS = 3e4;
|
|
721
|
+
var TEST_DEFAULT_PROMPT = "Reply with a single word: pong";
|
|
722
|
+
var TEST_MAX_SAMPLE = 400;
|
|
723
|
+
async function handleTestModel(req, res) {
|
|
724
|
+
let body;
|
|
725
|
+
try {
|
|
726
|
+
body = JSON.parse(await readBody(req));
|
|
727
|
+
} catch {
|
|
728
|
+
sendJson(res, 400, { error: "Invalid JSON body" });
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
731
|
+
const { providerId, modelId, prompt } = body;
|
|
732
|
+
if (!providerId || typeof providerId !== "string") {
|
|
733
|
+
sendJson(res, 400, { error: "providerId required" });
|
|
734
|
+
return;
|
|
735
|
+
}
|
|
736
|
+
if (!modelId || typeof modelId !== "string") {
|
|
737
|
+
sendJson(res, 400, { error: "modelId required" });
|
|
738
|
+
return;
|
|
739
|
+
}
|
|
740
|
+
try {
|
|
741
|
+
const catalog = await fetchModelsWithTimeout();
|
|
742
|
+
const provider = catalog.find((p2) => p2.id === providerId);
|
|
743
|
+
if (!provider) {
|
|
744
|
+
sendJson(res, 200, {
|
|
745
|
+
ok: false,
|
|
746
|
+
providerId,
|
|
747
|
+
modelId,
|
|
748
|
+
format: "unknown",
|
|
749
|
+
connectMs: null,
|
|
750
|
+
ttftMs: null,
|
|
751
|
+
totalMs: null,
|
|
752
|
+
tokens: 0,
|
|
753
|
+
tokensPerSec: null,
|
|
754
|
+
streamStability: "n/a",
|
|
755
|
+
sample: "",
|
|
756
|
+
error: `Provider "${providerId}" not found in catalog`,
|
|
757
|
+
errorHint: "Connect or enable the provider in Providers & Keys first."
|
|
758
|
+
});
|
|
759
|
+
return;
|
|
760
|
+
}
|
|
761
|
+
const model = provider.models.find((m) => m.id === modelId);
|
|
762
|
+
if (!model) {
|
|
763
|
+
sendJson(res, 200, {
|
|
764
|
+
ok: false,
|
|
765
|
+
providerId,
|
|
766
|
+
modelId,
|
|
767
|
+
format: "unknown",
|
|
768
|
+
connectMs: null,
|
|
769
|
+
ttftMs: null,
|
|
770
|
+
totalMs: null,
|
|
771
|
+
tokens: 0,
|
|
772
|
+
tokensPerSec: null,
|
|
773
|
+
streamStability: "n/a",
|
|
774
|
+
sample: "",
|
|
775
|
+
error: `Model "${modelId}" not found on provider "${providerId}"`,
|
|
776
|
+
errorHint: "Pick a model that belongs to the selected provider."
|
|
777
|
+
});
|
|
778
|
+
return;
|
|
779
|
+
}
|
|
780
|
+
const registry = loadRegistry();
|
|
781
|
+
const registryProvider = registry.providers.find((p2) => p2.id === providerId);
|
|
782
|
+
let apiKey = provider.apiKey ?? null;
|
|
783
|
+
if (registryProvider?.authRef) {
|
|
784
|
+
apiKey = await resolveProviderCredential(providerId, registryProvider.authRef);
|
|
785
|
+
}
|
|
786
|
+
const format = model.modelFormat === "anthropic" || model.modelFormat === "openai" ? model.modelFormat : "unsupported";
|
|
787
|
+
const upstreamModelId = model.upstreamModelId || model.id;
|
|
788
|
+
const userPrompt = typeof prompt === "string" && prompt.trim() ? prompt : TEST_DEFAULT_PROMPT;
|
|
789
|
+
let upstreamUrl;
|
|
790
|
+
const headers = { "Content-Type": "application/json" };
|
|
791
|
+
let requestBody;
|
|
792
|
+
if (model.modelFormat === "anthropic") {
|
|
793
|
+
const base = (model.baseUrl || "").replace(/\/v1\/?$/, "");
|
|
794
|
+
if (!base) {
|
|
795
|
+
sendJson(res, 200, failNoEndpoint(providerId, modelId, format));
|
|
796
|
+
return;
|
|
797
|
+
}
|
|
798
|
+
upstreamUrl = `${base.replace(/\/$/, "")}/v1/messages`;
|
|
799
|
+
headers["x-api-key"] = apiKey ?? "";
|
|
800
|
+
headers["anthropic-version"] = "2023-06-01";
|
|
801
|
+
requestBody = {
|
|
802
|
+
model: upstreamModelId,
|
|
803
|
+
max_tokens: 256,
|
|
804
|
+
stream: true,
|
|
805
|
+
messages: [{ role: "user", content: userPrompt }]
|
|
806
|
+
};
|
|
807
|
+
} else if (model.modelFormat === "openai") {
|
|
808
|
+
const completionsUrl = model.completionsUrl || (model.apiBaseUrl ? `${model.apiBaseUrl.replace(/\/$/, "")}/chat/completions` : "");
|
|
809
|
+
if (!completionsUrl) {
|
|
810
|
+
sendJson(res, 200, failNoEndpoint(providerId, modelId, format));
|
|
811
|
+
return;
|
|
812
|
+
}
|
|
813
|
+
upstreamUrl = completionsUrl;
|
|
814
|
+
headers["Authorization"] = `Bearer ${apiKey ?? ""}`;
|
|
815
|
+
requestBody = {
|
|
816
|
+
model: upstreamModelId,
|
|
817
|
+
stream: true,
|
|
818
|
+
messages: [{ role: "user", content: userPrompt }]
|
|
819
|
+
};
|
|
820
|
+
} else {
|
|
821
|
+
sendJson(res, 200, {
|
|
822
|
+
ok: false,
|
|
823
|
+
providerId,
|
|
824
|
+
modelId,
|
|
825
|
+
format: "unsupported",
|
|
826
|
+
connectMs: null,
|
|
827
|
+
ttftMs: null,
|
|
828
|
+
totalMs: null,
|
|
829
|
+
tokens: 0,
|
|
830
|
+
tokensPerSec: null,
|
|
831
|
+
streamStability: "n/a",
|
|
832
|
+
sample: "",
|
|
833
|
+
error: `Model format "${model.modelFormat}" is not directly testable from the UI`,
|
|
834
|
+
errorHint: "This provider routes through anygate's SDK adapter. Use the CLI or Server gateway to exercise it."
|
|
835
|
+
});
|
|
836
|
+
return;
|
|
837
|
+
}
|
|
838
|
+
for (const [k, v] of Object.entries(provider.headers ?? {})) {
|
|
839
|
+
if (!(k.toLowerCase() in headers)) headers[k] = v;
|
|
840
|
+
}
|
|
841
|
+
const controller = new AbortController();
|
|
842
|
+
const timeout = setTimeout(() => controller.abort(), TEST_TIMEOUT_MS);
|
|
843
|
+
const t0 = performance.now();
|
|
844
|
+
let connectMs = null;
|
|
845
|
+
let ttftMs = null;
|
|
846
|
+
let totalMs = null;
|
|
847
|
+
let tokens = 0;
|
|
848
|
+
const gaps = [];
|
|
849
|
+
let lastChunkT = null;
|
|
850
|
+
let sample = "";
|
|
851
|
+
try {
|
|
852
|
+
const upstream = await fetch(upstreamUrl, {
|
|
853
|
+
method: "POST",
|
|
854
|
+
headers,
|
|
855
|
+
body: JSON.stringify(requestBody),
|
|
856
|
+
signal: controller.signal
|
|
857
|
+
});
|
|
858
|
+
connectMs = Math.round(performance.now() - t0);
|
|
859
|
+
if (!upstream.ok || !upstream.body) {
|
|
860
|
+
const snippet = upstream.body ? (await upstream.text()).slice(0, 240) : "";
|
|
861
|
+
clearTimeout(timeout);
|
|
862
|
+
sendJson(res, 200, {
|
|
863
|
+
ok: false,
|
|
864
|
+
providerId,
|
|
865
|
+
modelId,
|
|
866
|
+
format,
|
|
867
|
+
connectMs,
|
|
868
|
+
ttftMs: null,
|
|
869
|
+
totalMs: Math.round(performance.now() - t0),
|
|
870
|
+
tokens: 0,
|
|
871
|
+
tokensPerSec: null,
|
|
872
|
+
streamStability: "n/a",
|
|
873
|
+
sample: snippet,
|
|
874
|
+
error: `Upstream responded ${upstream.status} ${upstream.statusText}`,
|
|
875
|
+
errorHint: upstream.status === 401 ? "API key missing or rejected \u2014 add/refresh the key in Providers & Keys." : upstream.status === 404 ? "Endpoint not found \u2014 the provider base URL may be wrong." : "Check the provider key and base URL."
|
|
876
|
+
});
|
|
877
|
+
return;
|
|
878
|
+
}
|
|
879
|
+
const reader = upstream.body.getReader();
|
|
880
|
+
const decoder = new TextDecoder();
|
|
881
|
+
let buffer = "";
|
|
882
|
+
while (true) {
|
|
883
|
+
const { done, value } = await reader.read();
|
|
884
|
+
if (done) break;
|
|
885
|
+
const chunk = decoder.decode(value, { stream: true });
|
|
886
|
+
if (!chunk) continue;
|
|
887
|
+
const now = performance.now();
|
|
888
|
+
const delta = now - t0;
|
|
889
|
+
if (ttftMs === null) ttftMs = Math.round(delta);
|
|
890
|
+
if (lastChunkT !== null) gaps.push(now - lastChunkT);
|
|
891
|
+
lastChunkT = now;
|
|
892
|
+
buffer += chunk;
|
|
893
|
+
if (model.modelFormat === "anthropic") {
|
|
894
|
+
const lines = buffer.split("\n");
|
|
895
|
+
buffer = lines.pop() ?? "";
|
|
896
|
+
for (const line of lines) {
|
|
897
|
+
const trimmed = line.trim();
|
|
898
|
+
if (!trimmed.startsWith("data:")) continue;
|
|
899
|
+
const data = trimmed.slice(5).trim();
|
|
900
|
+
if (data === "[DONE]") continue;
|
|
901
|
+
try {
|
|
902
|
+
const evt = JSON.parse(data);
|
|
903
|
+
if (evt.type === "content_block_delta" && evt.delta?.type === "text_delta") {
|
|
904
|
+
tokens++;
|
|
905
|
+
if (sample.length < TEST_MAX_SAMPLE) sample += evt.delta.text;
|
|
906
|
+
}
|
|
907
|
+
} catch {
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
} else {
|
|
911
|
+
const lines = buffer.split("\n");
|
|
912
|
+
buffer = lines.pop() ?? "";
|
|
913
|
+
for (const line of lines) {
|
|
914
|
+
const trimmed = line.trim();
|
|
915
|
+
if (!trimmed.startsWith("data:")) continue;
|
|
916
|
+
const data = trimmed.slice(5).trim();
|
|
917
|
+
if (data === "[DONE]") continue;
|
|
918
|
+
try {
|
|
919
|
+
const evt = JSON.parse(data);
|
|
920
|
+
const piece = evt.choices?.[0]?.delta?.content;
|
|
921
|
+
if (typeof piece === "string" && piece) {
|
|
922
|
+
tokens++;
|
|
923
|
+
if (sample.length < TEST_MAX_SAMPLE) sample += piece;
|
|
924
|
+
}
|
|
925
|
+
} catch {
|
|
926
|
+
}
|
|
927
|
+
}
|
|
928
|
+
}
|
|
929
|
+
}
|
|
930
|
+
totalMs = Math.round(performance.now() - t0);
|
|
931
|
+
clearTimeout(timeout);
|
|
932
|
+
const tokensPerSec = tokens > 0 && ttftMs !== null ? Math.round(tokens / (totalMs - ttftMs + 1) * 1e3 * 10) / 10 : null;
|
|
933
|
+
const streamStability = computeStability(gaps);
|
|
934
|
+
sendJson(res, 200, {
|
|
935
|
+
ok: true,
|
|
936
|
+
providerId,
|
|
937
|
+
modelId,
|
|
938
|
+
format,
|
|
939
|
+
connectMs,
|
|
940
|
+
ttftMs,
|
|
941
|
+
totalMs,
|
|
942
|
+
tokens,
|
|
943
|
+
tokensPerSec,
|
|
944
|
+
streamStability,
|
|
945
|
+
sample: sample.trim()
|
|
946
|
+
});
|
|
947
|
+
} catch (fetchErr) {
|
|
948
|
+
clearTimeout(timeout);
|
|
949
|
+
const aborted = fetchErr instanceof Error && fetchErr.name === "AbortError";
|
|
950
|
+
sendJson(res, 200, {
|
|
951
|
+
ok: false,
|
|
952
|
+
providerId,
|
|
953
|
+
modelId,
|
|
954
|
+
format,
|
|
955
|
+
connectMs,
|
|
956
|
+
ttftMs,
|
|
957
|
+
totalMs: Math.round(performance.now() - t0),
|
|
958
|
+
tokens,
|
|
959
|
+
tokensPerSec: null,
|
|
960
|
+
streamStability: gaps.length ? computeStability(gaps) : "n/a",
|
|
961
|
+
sample,
|
|
962
|
+
error: aborted ? `Request timed out after ${TEST_TIMEOUT_MS / 1e3}s` : String(fetchErr),
|
|
963
|
+
errorHint: aborted ? "The endpoint did not respond in time \u2014 it may be slow, down, or the URL is unreachable." : "Network-level failure reaching the provider endpoint."
|
|
964
|
+
});
|
|
965
|
+
}
|
|
966
|
+
} catch (err) {
|
|
967
|
+
sendJson(res, 500, {
|
|
968
|
+
ok: false,
|
|
969
|
+
providerId,
|
|
970
|
+
modelId,
|
|
971
|
+
format: "unknown",
|
|
972
|
+
connectMs: null,
|
|
973
|
+
ttftMs: null,
|
|
974
|
+
totalMs: null,
|
|
975
|
+
tokens: 0,
|
|
976
|
+
tokensPerSec: null,
|
|
977
|
+
streamStability: "n/a",
|
|
978
|
+
sample: "",
|
|
979
|
+
error: String(err)
|
|
980
|
+
});
|
|
981
|
+
}
|
|
982
|
+
}
|
|
983
|
+
function failNoEndpoint(providerId, modelId, format) {
|
|
984
|
+
return {
|
|
985
|
+
ok: false,
|
|
986
|
+
providerId,
|
|
987
|
+
modelId,
|
|
988
|
+
format,
|
|
989
|
+
connectMs: null,
|
|
990
|
+
ttftMs: null,
|
|
991
|
+
totalMs: null,
|
|
992
|
+
tokens: 0,
|
|
993
|
+
tokensPerSec: null,
|
|
994
|
+
streamStability: "n/a",
|
|
995
|
+
sample: "",
|
|
996
|
+
error: "No usable upstream endpoint for this model",
|
|
997
|
+
errorHint: "The provider is missing a base URL / completions URL. Re-add or refresh it in Providers & Keys."
|
|
998
|
+
};
|
|
999
|
+
}
|
|
1000
|
+
function computeStability(gaps) {
|
|
1001
|
+
if (gaps.length < 3) return "steady";
|
|
1002
|
+
const mean = gaps.reduce((a, b) => a + b, 0) / gaps.length;
|
|
1003
|
+
if (mean === 0) return "steady";
|
|
1004
|
+
const variance = gaps.reduce((a, b) => a + (b - mean) ** 2, 0) / gaps.length;
|
|
1005
|
+
const cv = Math.sqrt(variance) / mean;
|
|
1006
|
+
return cv > 1.2 ? "intermittent" : "steady";
|
|
1007
|
+
}
|
|
708
1008
|
async function handlePostKeys(req, res) {
|
|
709
1009
|
try {
|
|
710
1010
|
const body = JSON.parse(await readBody(req));
|
|
@@ -735,7 +1035,7 @@ var CUSTOM_TEMPLATES = [
|
|
|
735
1035
|
function handleGetTemplates(res) {
|
|
736
1036
|
const registry = loadRegistry();
|
|
737
1037
|
const configured = new Set(registry.providers.map((p2) => p2.id));
|
|
738
|
-
const apiTemplates =
|
|
1038
|
+
const apiTemplates = listSupportedTemplates().map((t) => ({
|
|
739
1039
|
id: t.id,
|
|
740
1040
|
name: t.name,
|
|
741
1041
|
signupUrl: t.signupUrl ?? null,
|
|
@@ -797,8 +1097,8 @@ async function handleAddProvider(req, res) {
|
|
|
797
1097
|
sendJson(res, 400, { error: "templateId required" });
|
|
798
1098
|
return;
|
|
799
1099
|
}
|
|
800
|
-
const { listSupportedTemplates } = await import("./provider-templates-
|
|
801
|
-
const template =
|
|
1100
|
+
const { listSupportedTemplates: listSupportedTemplates2 } = await import("./provider-templates-MNJZTG3Z.js");
|
|
1101
|
+
const template = listSupportedTemplates2().find((t) => t.id === templateId);
|
|
802
1102
|
if (!template) {
|
|
803
1103
|
sendJson(res, 404, { error: `Template '${templateId}' not found` });
|
|
804
1104
|
return;
|
|
@@ -1323,7 +1623,7 @@ async function handleBrowseFolder(res) {
|
|
|
1323
1623
|
|
|
1324
1624
|
// src/ui/command.ts
|
|
1325
1625
|
var __dirname = dirname(fileURLToPath(import.meta.url));
|
|
1326
|
-
var PUBLIC_DIR = join2(__dirname, "
|
|
1626
|
+
var PUBLIC_DIR = join2(__dirname, "app", "dist");
|
|
1327
1627
|
var LOCK_FILE = join2(getAppHome(), "ui.lock");
|
|
1328
1628
|
var MIME = {
|
|
1329
1629
|
".html": "text/html; charset=utf-8",
|
|
@@ -1374,15 +1674,29 @@ function checkExistingServer() {
|
|
|
1374
1674
|
if (!existsSync3(LOCK_FILE)) return null;
|
|
1375
1675
|
try {
|
|
1376
1676
|
const { pid, port } = JSON.parse(readFileSync(LOCK_FILE, "utf8"));
|
|
1377
|
-
process.
|
|
1378
|
-
|
|
1677
|
+
const isWindows2 = process.platform === "win32";
|
|
1678
|
+
let processExists = false;
|
|
1679
|
+
if (isWindows2) {
|
|
1680
|
+
try {
|
|
1681
|
+
const output = execSync(`tasklist /FI "PID eq ${pid}"`, { encoding: "utf8", stdio: ["pipe", "pipe", "ignore"] });
|
|
1682
|
+
processExists = output.includes(String(pid));
|
|
1683
|
+
} catch {
|
|
1684
|
+
processExists = false;
|
|
1685
|
+
}
|
|
1686
|
+
} else {
|
|
1687
|
+
process.kill(pid, 0);
|
|
1688
|
+
processExists = true;
|
|
1689
|
+
}
|
|
1690
|
+
if (processExists) {
|
|
1691
|
+
return `http://127.0.0.1:${port}`;
|
|
1692
|
+
}
|
|
1379
1693
|
} catch {
|
|
1380
|
-
removeLock();
|
|
1381
|
-
return null;
|
|
1382
1694
|
}
|
|
1695
|
+
removeLock();
|
|
1696
|
+
return null;
|
|
1383
1697
|
}
|
|
1384
1698
|
function isUiApiRoute(url) {
|
|
1385
|
-
return url.startsWith("/api/") || url.startsWith("/
|
|
1699
|
+
return url.startsWith("/api/") || url.startsWith("/auth/callback");
|
|
1386
1700
|
}
|
|
1387
1701
|
function formatUiServerLifecycleMessage(event) {
|
|
1388
1702
|
if (event.type === "stopped") return "\u25C7 Server Gateway stopped";
|
|
@@ -1507,4 +1821,4 @@ export {
|
|
|
1507
1821
|
resolveUiShutdownDecision,
|
|
1508
1822
|
runUiCommand
|
|
1509
1823
|
};
|
|
1510
|
-
//# sourceMappingURL=command-
|
|
1824
|
+
//# sourceMappingURL=command-5BWYQP5G.js.map
|