waypoi 0.0.0
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/.github/instructions/ui.instructions.md +42 -0
- package/.github/workflows/ci.yml +35 -0
- package/.github/workflows/publish.yml +71 -0
- package/.github/workflows/release.yml +48 -0
- package/.playwright-mcp/console-2026-04-04T01-41-10-746Z.log +2 -0
- package/.playwright-mcp/console-2026-04-04T01-41-28-799Z.log +3 -0
- package/.playwright-mcp/console-2026-04-05T02-26-51-909Z.log +76 -0
- package/.playwright-mcp/page-2026-04-04T01-41-10-816Z.yml +1 -0
- package/.playwright-mcp/page-2026-04-04T01-41-29-141Z.yml +77 -0
- package/.playwright-mcp/page-2026-04-04T01-41-42-633Z.yml +190 -0
- package/.playwright-mcp/page-2026-04-04T01-42-03-929Z.yml +262 -0
- package/.playwright-mcp/page-2026-04-04T02-12-54-813Z.yml +6 -0
- package/.playwright-mcp/page-2026-04-04T02-14-58-600Z.yml +190 -0
- package/.playwright-mcp/page-2026-04-04T02-15-03-923Z.yml +190 -0
- package/.playwright-mcp/page-2026-04-04T02-15-07-426Z.yml +190 -0
- package/.playwright-mcp/page-2026-04-04T02-15-25-729Z.yml +262 -0
- package/.playwright-mcp/page-2026-04-04T02-16-22-984Z.yml +262 -0
- package/.playwright-mcp/page-2026-04-04T02-17-00-599Z.yml +190 -0
- package/.playwright-mcp/page-2026-04-04T02-17-50-874Z.yml +190 -0
- package/.playwright-mcp/page-2026-04-05T02-26-55-570Z.yml +6 -0
- package/AGENTS.md +48 -0
- package/CHANGELOG.md +131 -0
- package/README.md +552 -0
- package/assets/agent-mode.png +0 -0
- package/assets/categorize.png +0 -0
- package/assets/dashboard.png +0 -0
- package/assets/endpoint-proxy.png +0 -0
- package/assets/icon.png +0 -0
- package/assets/mcp-generate-image.png +0 -0
- package/assets/mcp-understand-image.png +0 -0
- package/assets/peek-token-flow.png +0 -0
- package/assets/playground.png +0 -0
- package/assets/sankey.png +0 -0
- package/cli/index.ts +2805 -0
- package/cli/legacyRewrite.ts +108 -0
- package/cli/modelRef.ts +24 -0
- package/dist/cli/index.js +2536 -0
- package/dist/cli/legacyRewrite.js +92 -0
- package/dist/cli/modelRef.js +20 -0
- package/dist/src/benchmark/artifacts.js +131 -0
- package/dist/src/benchmark/capabilityClassifier.js +81 -0
- package/dist/src/benchmark/capabilityStore.js +144 -0
- package/dist/src/benchmark/config.js +238 -0
- package/dist/src/benchmark/gates.js +118 -0
- package/dist/src/benchmark/jobs.js +252 -0
- package/dist/src/benchmark/runner.js +1847 -0
- package/dist/src/benchmark/schema.js +353 -0
- package/dist/src/benchmark/suites.js +314 -0
- package/dist/src/benchmark/tinyQaDataset.js +422 -0
- package/dist/src/benchmark/types.js +25 -0
- package/dist/src/config.js +47 -0
- package/dist/src/index.js +178 -0
- package/dist/src/mcp/client.js +215 -0
- package/dist/src/mcp/discovery.js +226 -0
- package/dist/src/mcp/policy.js +65 -0
- package/dist/src/mcp/registry.js +129 -0
- package/dist/src/mcp/service.js +460 -0
- package/dist/src/middleware/auth.js +179 -0
- package/dist/src/middleware/requestCapture.js +192 -0
- package/dist/src/middleware/requestStats.js +118 -0
- package/dist/src/pools/builder.js +132 -0
- package/dist/src/pools/repository.js +69 -0
- package/dist/src/pools/scheduler.js +360 -0
- package/dist/src/pools/types.js +2 -0
- package/dist/src/protocols/adapters/dashscope.js +267 -0
- package/dist/src/protocols/adapters/inferenceV2.js +346 -0
- package/dist/src/protocols/adapters/openai.js +27 -0
- package/dist/src/protocols/registry.js +99 -0
- package/dist/src/protocols/types.js +2 -0
- package/dist/src/providers/health.js +153 -0
- package/dist/src/providers/importer.js +289 -0
- package/dist/src/providers/modelRegistry.js +313 -0
- package/dist/src/providers/repository.js +361 -0
- package/dist/src/providers/types.js +2 -0
- package/dist/src/routes/admin.js +531 -0
- package/dist/src/routes/audio.js +295 -0
- package/dist/src/routes/chat.js +240 -0
- package/dist/src/routes/embeddings.js +157 -0
- package/dist/src/routes/images.js +288 -0
- package/dist/src/routes/mcp.js +256 -0
- package/dist/src/routes/mcpService.js +100 -0
- package/dist/src/routes/models.js +48 -0
- package/dist/src/routes/responses.js +711 -0
- package/dist/src/routes/sessions.js +450 -0
- package/dist/src/routes/stats.js +270 -0
- package/dist/src/routes/ui.js +97 -0
- package/dist/src/routes/videos.js +107 -0
- package/dist/src/routing/router.js +338 -0
- package/dist/src/services/imageGeneration.js +280 -0
- package/dist/src/services/imageUnderstanding.js +352 -0
- package/dist/src/services/videoGeneration.js +79 -0
- package/dist/src/storage/captureRepository.js +1591 -0
- package/dist/src/storage/files.js +157 -0
- package/dist/src/storage/imageCache.js +346 -0
- package/dist/src/storage/repositories.js +388 -0
- package/dist/src/storage/sessionRepository.js +370 -0
- package/dist/src/storage/statsRepository.js +204 -0
- package/dist/src/transport/httpClient.js +126 -0
- package/dist/src/types.js +2 -0
- package/dist/src/utils/messageMedia.js +285 -0
- package/dist/src/utils/modelCapabilities.js +108 -0
- package/dist/src/utils/modelDiscovery.js +170 -0
- package/dist/src/version.js +5 -0
- package/dist/src/workers/captureRetention.js +25 -0
- package/dist/src/workers/configWatcher.js +91 -0
- package/dist/src/workers/healthChecker.js +21 -0
- package/dist/src/workers/statsRotation.js +41 -0
- package/docs/LLM/output_schema.md +312 -0
- package/docs/benchmark.md +208 -0
- package/docs/mcp-guidelines.md +125 -0
- package/docs/mcp-service.md +178 -0
- package/docs/opencode.md +86 -0
- package/docs/providers.md +79 -0
- package/examples/benchmark.config.yaml +28 -0
- package/examples/providers/alibaba-dashscope.yaml +88 -0
- package/examples/providers/alibaba-llm.yaml +64 -0
- package/examples/providers/alibaba-registry.yaml +7 -0
- package/examples/providers/inference-v2-ray.yaml +29 -0
- package/examples/scenarios/assets/omni-call-sample.wav +0 -0
- package/examples/scenarios/custom.jsonl +5 -0
- package/examples/scenarios/custom.yaml +40 -0
- package/model-form-v2.png +0 -0
- package/package.json +66 -0
- package/provider-form-v2.png +0 -0
- package/provider-form.png +0 -0
- package/scripts/manual-test.sh +11 -0
- package/scripts/version-from-git.js +23 -0
- package/src/benchmark/artifacts.ts +149 -0
- package/src/benchmark/capabilityClassifier.ts +99 -0
- package/src/benchmark/capabilityStore.ts +174 -0
- package/src/benchmark/config.ts +337 -0
- package/src/benchmark/gates.ts +164 -0
- package/src/benchmark/jobs.ts +312 -0
- package/src/benchmark/runner.ts +2519 -0
- package/src/benchmark/schema.ts +443 -0
- package/src/benchmark/suites.ts +323 -0
- package/src/benchmark/tinyQaDataset.ts +428 -0
- package/src/benchmark/types.ts +442 -0
- package/src/config.ts +44 -0
- package/src/index.ts +195 -0
- package/src/mcp/client.ts +305 -0
- package/src/mcp/discovery.ts +266 -0
- package/src/mcp/policy.ts +105 -0
- package/src/mcp/registry.ts +164 -0
- package/src/mcp/service.ts +611 -0
- package/src/middleware/auth.ts +251 -0
- package/src/middleware/requestCapture.ts +245 -0
- package/src/middleware/requestStats.ts +163 -0
- package/src/pools/builder.ts +159 -0
- package/src/pools/repository.ts +71 -0
- package/src/pools/scheduler.ts +425 -0
- package/src/pools/types.ts +117 -0
- package/src/protocols/adapters/dashscope.ts +335 -0
- package/src/protocols/adapters/inferenceV2.ts +428 -0
- package/src/protocols/adapters/openai.ts +32 -0
- package/src/protocols/registry.ts +117 -0
- package/src/protocols/types.ts +81 -0
- package/src/providers/health.ts +207 -0
- package/src/providers/importer.ts +402 -0
- package/src/providers/modelRegistry.ts +415 -0
- package/src/providers/repository.ts +439 -0
- package/src/providers/types.ts +113 -0
- package/src/routes/admin.ts +666 -0
- package/src/routes/audio.ts +372 -0
- package/src/routes/chat.ts +301 -0
- package/src/routes/embeddings.ts +197 -0
- package/src/routes/images.ts +356 -0
- package/src/routes/mcp.ts +320 -0
- package/src/routes/mcpService.ts +114 -0
- package/src/routes/models.ts +50 -0
- package/src/routes/responses.ts +872 -0
- package/src/routes/sessions.ts +558 -0
- package/src/routes/stats.ts +312 -0
- package/src/routes/ui.ts +96 -0
- package/src/routes/videos.ts +132 -0
- package/src/routing/router.ts +501 -0
- package/src/services/imageGeneration.ts +396 -0
- package/src/services/imageUnderstanding.ts +449 -0
- package/src/services/videoGeneration.ts +127 -0
- package/src/storage/captureRepository.ts +1835 -0
- package/src/storage/files.ts +178 -0
- package/src/storage/imageCache.ts +405 -0
- package/src/storage/repositories.ts +494 -0
- package/src/storage/sessionRepository.ts +419 -0
- package/src/storage/statsRepository.ts +238 -0
- package/src/transport/httpClient.ts +145 -0
- package/src/types.ts +322 -0
- package/src/utils/messageMedia.ts +293 -0
- package/src/utils/modelCapabilities.ts +161 -0
- package/src/utils/modelDiscovery.ts +203 -0
- package/src/workers/captureRetention.ts +25 -0
- package/src/workers/configWatcher.ts +115 -0
- package/src/workers/healthChecker.ts +22 -0
- package/src/workers/statsRotation.ts +49 -0
- package/tests/benchmarkAdminRoutes.test.ts +82 -0
- package/tests/benchmarkBasics.test.ts +116 -0
- package/tests/captureAdminRoutes.test.ts +420 -0
- package/tests/captureRepository.test.ts +797 -0
- package/tests/cliLegacyRewrite.test.ts +45 -0
- package/tests/imageGeneration.service.test.ts +107 -0
- package/tests/imageUnderstanding.service.test.ts +123 -0
- package/tests/mcpPolicy.test.ts +105 -0
- package/tests/mcpService.test.ts +1245 -0
- package/tests/modelRef.test.ts +23 -0
- package/tests/modelsRoutes.test.ts +154 -0
- package/tests/sessionMediaCache.test.ts +167 -0
- package/tests/statsRoutes.test.ts +323 -0
- package/tsconfig.json +15 -0
- package/ui/index.html +16 -0
- package/ui/package-lock.json +8521 -0
- package/ui/package.json +52 -0
- package/ui/postcss.config.js +6 -0
- package/ui/public/assets/apple-touch-icon.png +0 -0
- package/ui/public/assets/favicon-16.png +0 -0
- package/ui/public/assets/favicon-32.png +0 -0
- package/ui/public/assets/icon-192.png +0 -0
- package/ui/public/assets/icon-512.png +0 -0
- package/ui/src/App.tsx +27 -0
- package/ui/src/api/client.ts +1503 -0
- package/ui/src/components/EndpointUsageGuide.tsx +361 -0
- package/ui/src/components/Layout.tsx +124 -0
- package/ui/src/components/MessageContent.tsx +365 -0
- package/ui/src/components/ToolCallMessage.tsx +179 -0
- package/ui/src/components/ToolPicker.tsx +442 -0
- package/ui/src/components/messageContentParser.test.ts +41 -0
- package/ui/src/components/messageContentParser.ts +73 -0
- package/ui/src/components/thinkingPreview.test.ts +27 -0
- package/ui/src/components/thinkingPreview.ts +15 -0
- package/ui/src/components/toMermaidSankey.test.ts +78 -0
- package/ui/src/components/toMermaidSankey.ts +56 -0
- package/ui/src/components/ui/button.tsx +58 -0
- package/ui/src/components/ui/input.tsx +21 -0
- package/ui/src/components/ui/textarea.tsx +21 -0
- package/ui/src/lib/utils.ts +6 -0
- package/ui/src/main.tsx +9 -0
- package/ui/src/pages/AgentPlayground.tsx +2010 -0
- package/ui/src/pages/Benchmark.tsx +988 -0
- package/ui/src/pages/Dashboard.tsx +581 -0
- package/ui/src/pages/Peek.tsx +962 -0
- package/ui/src/pages/Settings.tsx +2013 -0
- package/ui/src/pages/agentPlaygroundPayload.test.ts +109 -0
- package/ui/src/pages/agentPlaygroundPayload.ts +97 -0
- package/ui/src/pages/agentThinkingContent.test.ts +50 -0
- package/ui/src/pages/agentThinkingContent.ts +57 -0
- package/ui/src/pages/dashboardTokenUsage.test.ts +66 -0
- package/ui/src/pages/dashboardTokenUsage.ts +36 -0
- package/ui/src/pages/imageUpload.test.ts +39 -0
- package/ui/src/pages/imageUpload.ts +71 -0
- package/ui/src/pages/peekFilters.test.ts +29 -0
- package/ui/src/pages/peekFilters.ts +13 -0
- package/ui/src/pages/peekMedia.test.ts +58 -0
- package/ui/src/pages/peekMedia.ts +148 -0
- package/ui/src/pages/sessionAutoTitle.test.ts +128 -0
- package/ui/src/pages/sessionAutoTitle.ts +106 -0
- package/ui/src/stores/settings.ts +58 -0
- package/ui/src/styles/globals.css +223 -0
- package/ui/src/vite-env.d.ts +8 -0
- package/ui/tailwind.config.js +106 -0
- package/ui/tsconfig.json +32 -0
- package/ui/vite.config.ts +37 -0
|
@@ -0,0 +1,439 @@
|
|
|
1
|
+
import { StoragePaths, readJsonFile, writeJsonFile } from "../storage/files";
|
|
2
|
+
import { ProviderModelRecord, ProviderRecord, ProviderStoreFile } from "./types";
|
|
3
|
+
|
|
4
|
+
const CURRENT_VERSION = 3;
|
|
5
|
+
|
|
6
|
+
export interface ModelRefResolution {
|
|
7
|
+
provider: ProviderRecord;
|
|
8
|
+
model: ProviderModelRecord;
|
|
9
|
+
modelIndex: number;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
function defaultStore(): ProviderStoreFile {
|
|
13
|
+
return {
|
|
14
|
+
version: CURRENT_VERSION,
|
|
15
|
+
updatedAt: new Date().toISOString(),
|
|
16
|
+
providers: [],
|
|
17
|
+
};
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export function canonicalProviderModelId(providerId: string, modelId: string): string {
|
|
21
|
+
return `${providerId}/${modelId}`;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export async function loadProviderStore(paths: StoragePaths): Promise<ProviderStoreFile> {
|
|
25
|
+
const store = await readJsonFile<ProviderStoreFile>(paths.providersPath, defaultStore());
|
|
26
|
+
if (!Array.isArray(store.providers)) {
|
|
27
|
+
return defaultStore();
|
|
28
|
+
}
|
|
29
|
+
const providers = store.providers.map(normalizeProviderRecord);
|
|
30
|
+
return {
|
|
31
|
+
version: Number.isFinite(store.version) ? store.version : CURRENT_VERSION,
|
|
32
|
+
updatedAt: typeof store.updatedAt === "string" ? store.updatedAt : new Date().toISOString(),
|
|
33
|
+
providers,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
export async function saveProviderStore(paths: StoragePaths, providers: ProviderRecord[]): Promise<void> {
|
|
38
|
+
const next: ProviderStoreFile = {
|
|
39
|
+
version: CURRENT_VERSION,
|
|
40
|
+
updatedAt: new Date().toISOString(),
|
|
41
|
+
providers: providers.map(normalizeProviderRecord),
|
|
42
|
+
};
|
|
43
|
+
await writeJsonFile(paths.providersPath, next);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export async function listProviders(paths: StoragePaths): Promise<ProviderRecord[]> {
|
|
47
|
+
const store = await loadProviderStore(paths);
|
|
48
|
+
return [...store.providers].sort((a, b) => a.id.localeCompare(b.id));
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export async function getProviderById(paths: StoragePaths, providerId: string): Promise<ProviderRecord | null> {
|
|
52
|
+
const providers = await listProviders(paths);
|
|
53
|
+
return providers.find((provider) => provider.id === providerId) ?? null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export async function setProviderEnabled(
|
|
57
|
+
paths: StoragePaths,
|
|
58
|
+
providerId: string,
|
|
59
|
+
enabled: boolean
|
|
60
|
+
): Promise<ProviderRecord | null> {
|
|
61
|
+
const store = await loadProviderStore(paths);
|
|
62
|
+
const index = store.providers.findIndex((provider) => provider.id === providerId);
|
|
63
|
+
if (index === -1) {
|
|
64
|
+
return null;
|
|
65
|
+
}
|
|
66
|
+
const updated: ProviderRecord = {
|
|
67
|
+
...store.providers[index],
|
|
68
|
+
enabled,
|
|
69
|
+
};
|
|
70
|
+
store.providers[index] = normalizeProviderRecord(updated);
|
|
71
|
+
await saveProviderStore(paths, store.providers);
|
|
72
|
+
return store.providers[index];
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export async function upsertProviders(paths: StoragePaths, providers: ProviderRecord[]): Promise<void> {
|
|
76
|
+
const existing = await loadProviderStore(paths);
|
|
77
|
+
const byId = new Map(existing.providers.map((provider) => [provider.id, normalizeProviderRecord(provider)]));
|
|
78
|
+
|
|
79
|
+
for (const provider of providers) {
|
|
80
|
+
const normalized = normalizeProviderRecord(provider);
|
|
81
|
+
const prev = byId.get(provider.id);
|
|
82
|
+
if (!prev) {
|
|
83
|
+
byId.set(provider.id, normalized);
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
const mergedByModelId = new Map(prev.models.map((model) => [model.providerModelId, model]));
|
|
88
|
+
for (const model of normalized.models) {
|
|
89
|
+
const previousModel = mergedByModelId.get(model.providerModelId);
|
|
90
|
+
mergedByModelId.set(model.providerModelId, normalizeProviderModelRecord({
|
|
91
|
+
...model,
|
|
92
|
+
enabled: previousModel?.enabled ?? model.enabled,
|
|
93
|
+
apiKey: model.apiKey ?? previousModel?.apiKey,
|
|
94
|
+
aliases: model.aliases?.length ? model.aliases : previousModel?.aliases,
|
|
95
|
+
}));
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
byId.set(provider.id, normalizeProviderRecord({
|
|
99
|
+
...normalized,
|
|
100
|
+
enabled: prev.enabled,
|
|
101
|
+
apiKey: normalized.apiKey ?? prev.apiKey,
|
|
102
|
+
insecureTls: provider.insecureTls ?? prev.insecureTls,
|
|
103
|
+
autoInsecureTlsDomains:
|
|
104
|
+
provider.autoInsecureTlsDomains ?? prev.autoInsecureTlsDomains,
|
|
105
|
+
models: Array.from(mergedByModelId.values()),
|
|
106
|
+
}));
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
await saveProviderStore(paths, Array.from(byId.values()));
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
export async function upsertProvider(paths: StoragePaths, provider: ProviderRecord): Promise<ProviderRecord> {
|
|
113
|
+
const existing = await loadProviderStore(paths);
|
|
114
|
+
const index = existing.providers.findIndex((entry) => entry.id === provider.id);
|
|
115
|
+
if (index === -1) {
|
|
116
|
+
const normalized = normalizeProviderRecord(provider);
|
|
117
|
+
existing.providers.push(normalized);
|
|
118
|
+
await saveProviderStore(paths, existing.providers);
|
|
119
|
+
return normalized;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
const prev = normalizeProviderRecord(existing.providers[index]);
|
|
123
|
+
const next = normalizeProviderRecord({
|
|
124
|
+
...provider,
|
|
125
|
+
enabled: prev.enabled,
|
|
126
|
+
apiKey: provider.apiKey ?? prev.apiKey,
|
|
127
|
+
insecureTls: provider.insecureTls ?? prev.insecureTls,
|
|
128
|
+
autoInsecureTlsDomains:
|
|
129
|
+
provider.autoInsecureTlsDomains ?? prev.autoInsecureTlsDomains,
|
|
130
|
+
});
|
|
131
|
+
existing.providers[index] = next;
|
|
132
|
+
await saveProviderStore(paths, existing.providers);
|
|
133
|
+
return next;
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
export async function updateProvider(
|
|
137
|
+
paths: StoragePaths,
|
|
138
|
+
providerId: string,
|
|
139
|
+
patch: Partial<ProviderRecord>
|
|
140
|
+
): Promise<ProviderRecord | null> {
|
|
141
|
+
const store = await loadProviderStore(paths);
|
|
142
|
+
const index = store.providers.findIndex((provider) => provider.id === providerId);
|
|
143
|
+
if (index === -1) {
|
|
144
|
+
return null;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const current = normalizeProviderRecord(store.providers[index]);
|
|
148
|
+
const updated = normalizeProviderRecord({
|
|
149
|
+
...current,
|
|
150
|
+
...patch,
|
|
151
|
+
id: providerId,
|
|
152
|
+
models: patch.models ?? current.models,
|
|
153
|
+
});
|
|
154
|
+
store.providers[index] = updated;
|
|
155
|
+
await saveProviderStore(paths, store.providers);
|
|
156
|
+
return updated;
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export async function deleteProvider(
|
|
160
|
+
paths: StoragePaths,
|
|
161
|
+
providerId: string
|
|
162
|
+
): Promise<ProviderRecord | null> {
|
|
163
|
+
const store = await loadProviderStore(paths);
|
|
164
|
+
const index = store.providers.findIndex((provider) => provider.id === providerId);
|
|
165
|
+
if (index === -1) {
|
|
166
|
+
return null;
|
|
167
|
+
}
|
|
168
|
+
const [removed] = store.providers.splice(index, 1);
|
|
169
|
+
await saveProviderStore(paths, store.providers);
|
|
170
|
+
return normalizeProviderRecord(removed);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
export async function listProviderModels(paths: StoragePaths, providerId: string): Promise<ProviderModelRecord[] | null> {
|
|
174
|
+
const provider = await getProviderById(paths, providerId);
|
|
175
|
+
if (!provider) {
|
|
176
|
+
return null;
|
|
177
|
+
}
|
|
178
|
+
return [...provider.models].sort((a, b) => a.modelId.localeCompare(b.modelId));
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
export async function getProviderModel(
|
|
182
|
+
paths: StoragePaths,
|
|
183
|
+
providerId: string,
|
|
184
|
+
modelRef: string
|
|
185
|
+
): Promise<ProviderModelRecord | null> {
|
|
186
|
+
const resolved = await resolveProviderModelRef(paths, providerId, modelRef);
|
|
187
|
+
if (!resolved) {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
return resolved.model;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export async function resolveProviderModelRef(
|
|
194
|
+
paths: StoragePaths,
|
|
195
|
+
providerId: string,
|
|
196
|
+
modelRef: string
|
|
197
|
+
): Promise<ModelRefResolution | null> {
|
|
198
|
+
const provider = await getProviderById(paths, providerId);
|
|
199
|
+
if (!provider) {
|
|
200
|
+
return null;
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
const normalizedRef = modelRef.trim();
|
|
204
|
+
const candidates = provider.models
|
|
205
|
+
.map((model, modelIndex) => ({ model, modelIndex }))
|
|
206
|
+
.filter(({ model }) => {
|
|
207
|
+
if (model.providerModelId === normalizedRef) {
|
|
208
|
+
return true;
|
|
209
|
+
}
|
|
210
|
+
if (canonicalProviderModelId(providerId, model.modelId) === normalizedRef) {
|
|
211
|
+
return true;
|
|
212
|
+
}
|
|
213
|
+
if (model.modelId === normalizedRef) {
|
|
214
|
+
return true;
|
|
215
|
+
}
|
|
216
|
+
return Boolean(model.aliases?.includes(normalizedRef));
|
|
217
|
+
});
|
|
218
|
+
|
|
219
|
+
if (candidates.length !== 1) {
|
|
220
|
+
return null;
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
return {
|
|
224
|
+
provider,
|
|
225
|
+
model: candidates[0].model,
|
|
226
|
+
modelIndex: candidates[0].modelIndex,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export async function upsertProviderModel(
|
|
231
|
+
paths: StoragePaths,
|
|
232
|
+
providerId: string,
|
|
233
|
+
model: ProviderModelRecord
|
|
234
|
+
): Promise<{ provider: ProviderRecord; created: boolean } | null> {
|
|
235
|
+
const store = await loadProviderStore(paths);
|
|
236
|
+
const providerIndex = store.providers.findIndex((provider) => provider.id === providerId);
|
|
237
|
+
if (providerIndex === -1) {
|
|
238
|
+
return null;
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
const provider = normalizeProviderRecord(store.providers[providerIndex]);
|
|
242
|
+
const normalizedModel = normalizeProviderModelRecord({
|
|
243
|
+
...model,
|
|
244
|
+
providerId,
|
|
245
|
+
});
|
|
246
|
+
const modelIndex = provider.models.findIndex(
|
|
247
|
+
(entry) => entry.providerModelId === normalizedModel.providerModelId
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
if (modelIndex === -1) {
|
|
251
|
+
provider.models.push(normalizedModel);
|
|
252
|
+
store.providers[providerIndex] = provider;
|
|
253
|
+
await saveProviderStore(paths, store.providers);
|
|
254
|
+
return { provider, created: true };
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
provider.models[modelIndex] = {
|
|
258
|
+
...provider.models[modelIndex],
|
|
259
|
+
...normalizedModel,
|
|
260
|
+
providerId,
|
|
261
|
+
};
|
|
262
|
+
store.providers[providerIndex] = provider;
|
|
263
|
+
await saveProviderStore(paths, store.providers);
|
|
264
|
+
return { provider, created: false };
|
|
265
|
+
}
|
|
266
|
+
|
|
267
|
+
export async function updateProviderModel(
|
|
268
|
+
paths: StoragePaths,
|
|
269
|
+
providerId: string,
|
|
270
|
+
modelRef: string,
|
|
271
|
+
patch: Partial<ProviderModelRecord>
|
|
272
|
+
): Promise<ProviderModelRecord | null> {
|
|
273
|
+
const store = await loadProviderStore(paths);
|
|
274
|
+
const providerIndex = store.providers.findIndex((provider) => provider.id === providerId);
|
|
275
|
+
if (providerIndex === -1) {
|
|
276
|
+
return null;
|
|
277
|
+
}
|
|
278
|
+
const provider = normalizeProviderRecord(store.providers[providerIndex]);
|
|
279
|
+
const matchingIndexes = provider.models.flatMap((model, index) => {
|
|
280
|
+
if (model.providerModelId === modelRef) {
|
|
281
|
+
return [index];
|
|
282
|
+
}
|
|
283
|
+
if (model.modelId === modelRef) {
|
|
284
|
+
return [index];
|
|
285
|
+
}
|
|
286
|
+
if (model.aliases?.includes(modelRef)) {
|
|
287
|
+
return [index];
|
|
288
|
+
}
|
|
289
|
+
return [];
|
|
290
|
+
});
|
|
291
|
+
if (matchingIndexes.length !== 1) {
|
|
292
|
+
return null;
|
|
293
|
+
}
|
|
294
|
+
const modelIndex = matchingIndexes[0];
|
|
295
|
+
|
|
296
|
+
const updated = normalizeProviderModelRecord({
|
|
297
|
+
...provider.models[modelIndex],
|
|
298
|
+
...patch,
|
|
299
|
+
providerId,
|
|
300
|
+
});
|
|
301
|
+
provider.models[modelIndex] = updated;
|
|
302
|
+
store.providers[providerIndex] = provider;
|
|
303
|
+
await saveProviderStore(paths, store.providers);
|
|
304
|
+
return updated;
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
export async function deleteProviderModel(
|
|
308
|
+
paths: StoragePaths,
|
|
309
|
+
providerId: string,
|
|
310
|
+
modelRef: string
|
|
311
|
+
): Promise<ProviderModelRecord | null> {
|
|
312
|
+
const store = await loadProviderStore(paths);
|
|
313
|
+
const providerIndex = store.providers.findIndex((provider) => provider.id === providerId);
|
|
314
|
+
if (providerIndex === -1) {
|
|
315
|
+
return null;
|
|
316
|
+
}
|
|
317
|
+
const provider = normalizeProviderRecord(store.providers[providerIndex]);
|
|
318
|
+
const matchingIndexes = provider.models.flatMap((model, index) => {
|
|
319
|
+
if (model.providerModelId === modelRef) {
|
|
320
|
+
return [index];
|
|
321
|
+
}
|
|
322
|
+
if (model.modelId === modelRef) {
|
|
323
|
+
return [index];
|
|
324
|
+
}
|
|
325
|
+
if (model.aliases?.includes(modelRef)) {
|
|
326
|
+
return [index];
|
|
327
|
+
}
|
|
328
|
+
return [];
|
|
329
|
+
});
|
|
330
|
+
if (matchingIndexes.length !== 1) {
|
|
331
|
+
return null;
|
|
332
|
+
}
|
|
333
|
+
const modelIndex = matchingIndexes[0];
|
|
334
|
+
|
|
335
|
+
const [removed] = provider.models.splice(modelIndex, 1);
|
|
336
|
+
store.providers[providerIndex] = provider;
|
|
337
|
+
await saveProviderStore(paths, store.providers);
|
|
338
|
+
return removed;
|
|
339
|
+
}
|
|
340
|
+
|
|
341
|
+
export async function setProviderModelEnabled(
|
|
342
|
+
paths: StoragePaths,
|
|
343
|
+
providerId: string,
|
|
344
|
+
modelRef: string,
|
|
345
|
+
enabled: boolean
|
|
346
|
+
): Promise<ProviderModelRecord | null> {
|
|
347
|
+
return updateProviderModel(paths, providerId, modelRef, { enabled });
|
|
348
|
+
}
|
|
349
|
+
|
|
350
|
+
export async function setProviderModelApiKey(
|
|
351
|
+
paths: StoragePaths,
|
|
352
|
+
providerId: string,
|
|
353
|
+
modelRef: string,
|
|
354
|
+
apiKey: string | undefined
|
|
355
|
+
): Promise<ProviderModelRecord | null> {
|
|
356
|
+
return updateProviderModel(paths, providerId, modelRef, { apiKey });
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
export async function setProviderModelInsecureTls(
|
|
360
|
+
paths: StoragePaths,
|
|
361
|
+
providerId: string,
|
|
362
|
+
modelRef: string,
|
|
363
|
+
insecureTls: boolean | undefined
|
|
364
|
+
): Promise<ProviderModelRecord | null> {
|
|
365
|
+
return updateProviderModel(paths, providerId, modelRef, { insecureTls });
|
|
366
|
+
}
|
|
367
|
+
|
|
368
|
+
export function getEffectiveModelInsecureTls(
|
|
369
|
+
provider: Pick<ProviderRecord, "insecureTls">,
|
|
370
|
+
model: Pick<ProviderModelRecord, "insecureTls">
|
|
371
|
+
): boolean {
|
|
372
|
+
return model.insecureTls ?? provider.insecureTls ?? false;
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function normalizeProviderRecord(provider: ProviderRecord): ProviderRecord {
|
|
376
|
+
const models = Array.isArray(provider.models) ? provider.models.map((model) => normalizeProviderModelRecord({
|
|
377
|
+
...model,
|
|
378
|
+
providerId: provider.id,
|
|
379
|
+
})) : [];
|
|
380
|
+
return {
|
|
381
|
+
...provider,
|
|
382
|
+
id: provider.id,
|
|
383
|
+
insecureTls: provider.insecureTls === true,
|
|
384
|
+
autoInsecureTlsDomains: normalizeDomainSuffixes(provider.autoInsecureTlsDomains),
|
|
385
|
+
models,
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
|
|
389
|
+
function normalizeProviderModelRecord(model: ProviderModelRecord): ProviderModelRecord {
|
|
390
|
+
const aliases = normalizeAliases(model.aliases);
|
|
391
|
+
const providerId = model.providerId;
|
|
392
|
+
const modelId = model.modelId.trim();
|
|
393
|
+
return {
|
|
394
|
+
...model,
|
|
395
|
+
providerId,
|
|
396
|
+
modelId,
|
|
397
|
+
providerModelId: model.providerModelId || canonicalProviderModelId(providerId, modelId),
|
|
398
|
+
aliases,
|
|
399
|
+
enabled: model.enabled ?? true,
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
function normalizeAliases(aliases: string[] | undefined): string[] {
|
|
404
|
+
if (!Array.isArray(aliases)) {
|
|
405
|
+
return [];
|
|
406
|
+
}
|
|
407
|
+
const dedup = new Set<string>();
|
|
408
|
+
for (const alias of aliases) {
|
|
409
|
+
const normalized = alias.trim();
|
|
410
|
+
if (normalized) {
|
|
411
|
+
dedup.add(normalized);
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
return Array.from(dedup);
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
export function normalizeDomainSuffixes(domains: string[] | undefined): string[] {
|
|
418
|
+
if (!Array.isArray(domains)) {
|
|
419
|
+
return [];
|
|
420
|
+
}
|
|
421
|
+
const dedup = new Set<string>();
|
|
422
|
+
for (const domain of domains) {
|
|
423
|
+
let normalized = domain.trim().toLowerCase();
|
|
424
|
+
if (!normalized) {
|
|
425
|
+
continue;
|
|
426
|
+
}
|
|
427
|
+
if (normalized.startsWith("*.")) {
|
|
428
|
+
normalized = normalized.slice(2);
|
|
429
|
+
}
|
|
430
|
+
if (normalized.startsWith(".")) {
|
|
431
|
+
normalized = normalized.slice(1);
|
|
432
|
+
}
|
|
433
|
+
if (!normalized) {
|
|
434
|
+
continue;
|
|
435
|
+
}
|
|
436
|
+
dedup.add(normalized);
|
|
437
|
+
}
|
|
438
|
+
return Array.from(dedup);
|
|
439
|
+
}
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
import { EndpointType, ModelCapabilities, ModelModality } from "../types";
|
|
2
|
+
|
|
3
|
+
export type ProviderProtocol = "openai" | "inference_v2" | "dashscope" | "unknown";
|
|
4
|
+
|
|
5
|
+
export type ProviderAuthType = "bearer" | "query" | "header" | "none";
|
|
6
|
+
|
|
7
|
+
export interface ProviderAuthConfig {
|
|
8
|
+
type: ProviderAuthType;
|
|
9
|
+
keyParam?: string;
|
|
10
|
+
headerName?: string;
|
|
11
|
+
keyPrefix?: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface ProviderProtocolConfig {
|
|
15
|
+
router?: string;
|
|
16
|
+
responseTextPaths?: string[];
|
|
17
|
+
[key: string]: unknown;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
export interface ProviderLimits {
|
|
21
|
+
requests?: {
|
|
22
|
+
perMinute?: number;
|
|
23
|
+
perHour?: number;
|
|
24
|
+
perDay?: number;
|
|
25
|
+
perWeek?: number;
|
|
26
|
+
perMonth?: number;
|
|
27
|
+
};
|
|
28
|
+
tokens?: {
|
|
29
|
+
perMinute?: number;
|
|
30
|
+
perHour?: number;
|
|
31
|
+
perDay?: number;
|
|
32
|
+
perWeek?: number;
|
|
33
|
+
perMonth?: number;
|
|
34
|
+
};
|
|
35
|
+
concurrent?: number;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface ProviderModelRecord {
|
|
39
|
+
providerModelId: string;
|
|
40
|
+
providerId: string;
|
|
41
|
+
modelId: string;
|
|
42
|
+
upstreamModel: string;
|
|
43
|
+
baseUrl?: string;
|
|
44
|
+
apiKey?: string;
|
|
45
|
+
insecureTls?: boolean;
|
|
46
|
+
enabled?: boolean;
|
|
47
|
+
aliases?: string[];
|
|
48
|
+
free: boolean;
|
|
49
|
+
modalities: string[];
|
|
50
|
+
capabilities: ModelCapabilities;
|
|
51
|
+
endpointType: EndpointType;
|
|
52
|
+
benchmark?: {
|
|
53
|
+
livebench?: number;
|
|
54
|
+
};
|
|
55
|
+
limits?: ProviderLimits;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface ProviderRecord {
|
|
59
|
+
id: string;
|
|
60
|
+
name: string;
|
|
61
|
+
description?: string;
|
|
62
|
+
docs?: string;
|
|
63
|
+
protocol: ProviderProtocol;
|
|
64
|
+
protocolRaw?: string;
|
|
65
|
+
protocolConfig?: ProviderProtocolConfig;
|
|
66
|
+
baseUrl: string;
|
|
67
|
+
insecureTls?: boolean;
|
|
68
|
+
autoInsecureTlsDomains?: string[];
|
|
69
|
+
enabled: boolean;
|
|
70
|
+
supportsRouting: boolean;
|
|
71
|
+
auth?: ProviderAuthConfig;
|
|
72
|
+
envVar?: string;
|
|
73
|
+
apiKey?: string;
|
|
74
|
+
limits?: ProviderLimits;
|
|
75
|
+
models: ProviderModelRecord[];
|
|
76
|
+
warnings?: string[];
|
|
77
|
+
importedAt: string;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
export interface ProviderStoreFile {
|
|
81
|
+
version: number;
|
|
82
|
+
updatedAt: string;
|
|
83
|
+
providers: ProviderRecord[];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface ProviderRegistryEntry {
|
|
87
|
+
id: string;
|
|
88
|
+
name?: string;
|
|
89
|
+
file: string;
|
|
90
|
+
protocol?: string;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
export interface ProviderImportOptions {
|
|
94
|
+
registryPath: string;
|
|
95
|
+
envFilePath?: string;
|
|
96
|
+
overwriteAuth?: boolean;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export interface ProviderImportResult {
|
|
100
|
+
importedProviders: number;
|
|
101
|
+
importedModels: number;
|
|
102
|
+
warnings: string[];
|
|
103
|
+
providers: ProviderRecord[];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export interface EnvMap {
|
|
107
|
+
[key: string]: string;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
export interface ProviderCapabilityRequirements {
|
|
111
|
+
requiredInput: ModelModality[];
|
|
112
|
+
requiredOutput: ModelModality[];
|
|
113
|
+
}
|