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.
Files changed (260) hide show
  1. package/.github/instructions/ui.instructions.md +42 -0
  2. package/.github/workflows/ci.yml +35 -0
  3. package/.github/workflows/publish.yml +71 -0
  4. package/.github/workflows/release.yml +48 -0
  5. package/.playwright-mcp/console-2026-04-04T01-41-10-746Z.log +2 -0
  6. package/.playwright-mcp/console-2026-04-04T01-41-28-799Z.log +3 -0
  7. package/.playwright-mcp/console-2026-04-05T02-26-51-909Z.log +76 -0
  8. package/.playwright-mcp/page-2026-04-04T01-41-10-816Z.yml +1 -0
  9. package/.playwright-mcp/page-2026-04-04T01-41-29-141Z.yml +77 -0
  10. package/.playwright-mcp/page-2026-04-04T01-41-42-633Z.yml +190 -0
  11. package/.playwright-mcp/page-2026-04-04T01-42-03-929Z.yml +262 -0
  12. package/.playwright-mcp/page-2026-04-04T02-12-54-813Z.yml +6 -0
  13. package/.playwright-mcp/page-2026-04-04T02-14-58-600Z.yml +190 -0
  14. package/.playwright-mcp/page-2026-04-04T02-15-03-923Z.yml +190 -0
  15. package/.playwright-mcp/page-2026-04-04T02-15-07-426Z.yml +190 -0
  16. package/.playwright-mcp/page-2026-04-04T02-15-25-729Z.yml +262 -0
  17. package/.playwright-mcp/page-2026-04-04T02-16-22-984Z.yml +262 -0
  18. package/.playwright-mcp/page-2026-04-04T02-17-00-599Z.yml +190 -0
  19. package/.playwright-mcp/page-2026-04-04T02-17-50-874Z.yml +190 -0
  20. package/.playwright-mcp/page-2026-04-05T02-26-55-570Z.yml +6 -0
  21. package/AGENTS.md +48 -0
  22. package/CHANGELOG.md +131 -0
  23. package/README.md +552 -0
  24. package/assets/agent-mode.png +0 -0
  25. package/assets/categorize.png +0 -0
  26. package/assets/dashboard.png +0 -0
  27. package/assets/endpoint-proxy.png +0 -0
  28. package/assets/icon.png +0 -0
  29. package/assets/mcp-generate-image.png +0 -0
  30. package/assets/mcp-understand-image.png +0 -0
  31. package/assets/peek-token-flow.png +0 -0
  32. package/assets/playground.png +0 -0
  33. package/assets/sankey.png +0 -0
  34. package/cli/index.ts +2805 -0
  35. package/cli/legacyRewrite.ts +108 -0
  36. package/cli/modelRef.ts +24 -0
  37. package/dist/cli/index.js +2536 -0
  38. package/dist/cli/legacyRewrite.js +92 -0
  39. package/dist/cli/modelRef.js +20 -0
  40. package/dist/src/benchmark/artifacts.js +131 -0
  41. package/dist/src/benchmark/capabilityClassifier.js +81 -0
  42. package/dist/src/benchmark/capabilityStore.js +144 -0
  43. package/dist/src/benchmark/config.js +238 -0
  44. package/dist/src/benchmark/gates.js +118 -0
  45. package/dist/src/benchmark/jobs.js +252 -0
  46. package/dist/src/benchmark/runner.js +1847 -0
  47. package/dist/src/benchmark/schema.js +353 -0
  48. package/dist/src/benchmark/suites.js +314 -0
  49. package/dist/src/benchmark/tinyQaDataset.js +422 -0
  50. package/dist/src/benchmark/types.js +25 -0
  51. package/dist/src/config.js +47 -0
  52. package/dist/src/index.js +178 -0
  53. package/dist/src/mcp/client.js +215 -0
  54. package/dist/src/mcp/discovery.js +226 -0
  55. package/dist/src/mcp/policy.js +65 -0
  56. package/dist/src/mcp/registry.js +129 -0
  57. package/dist/src/mcp/service.js +460 -0
  58. package/dist/src/middleware/auth.js +179 -0
  59. package/dist/src/middleware/requestCapture.js +192 -0
  60. package/dist/src/middleware/requestStats.js +118 -0
  61. package/dist/src/pools/builder.js +132 -0
  62. package/dist/src/pools/repository.js +69 -0
  63. package/dist/src/pools/scheduler.js +360 -0
  64. package/dist/src/pools/types.js +2 -0
  65. package/dist/src/protocols/adapters/dashscope.js +267 -0
  66. package/dist/src/protocols/adapters/inferenceV2.js +346 -0
  67. package/dist/src/protocols/adapters/openai.js +27 -0
  68. package/dist/src/protocols/registry.js +99 -0
  69. package/dist/src/protocols/types.js +2 -0
  70. package/dist/src/providers/health.js +153 -0
  71. package/dist/src/providers/importer.js +289 -0
  72. package/dist/src/providers/modelRegistry.js +313 -0
  73. package/dist/src/providers/repository.js +361 -0
  74. package/dist/src/providers/types.js +2 -0
  75. package/dist/src/routes/admin.js +531 -0
  76. package/dist/src/routes/audio.js +295 -0
  77. package/dist/src/routes/chat.js +240 -0
  78. package/dist/src/routes/embeddings.js +157 -0
  79. package/dist/src/routes/images.js +288 -0
  80. package/dist/src/routes/mcp.js +256 -0
  81. package/dist/src/routes/mcpService.js +100 -0
  82. package/dist/src/routes/models.js +48 -0
  83. package/dist/src/routes/responses.js +711 -0
  84. package/dist/src/routes/sessions.js +450 -0
  85. package/dist/src/routes/stats.js +270 -0
  86. package/dist/src/routes/ui.js +97 -0
  87. package/dist/src/routes/videos.js +107 -0
  88. package/dist/src/routing/router.js +338 -0
  89. package/dist/src/services/imageGeneration.js +280 -0
  90. package/dist/src/services/imageUnderstanding.js +352 -0
  91. package/dist/src/services/videoGeneration.js +79 -0
  92. package/dist/src/storage/captureRepository.js +1591 -0
  93. package/dist/src/storage/files.js +157 -0
  94. package/dist/src/storage/imageCache.js +346 -0
  95. package/dist/src/storage/repositories.js +388 -0
  96. package/dist/src/storage/sessionRepository.js +370 -0
  97. package/dist/src/storage/statsRepository.js +204 -0
  98. package/dist/src/transport/httpClient.js +126 -0
  99. package/dist/src/types.js +2 -0
  100. package/dist/src/utils/messageMedia.js +285 -0
  101. package/dist/src/utils/modelCapabilities.js +108 -0
  102. package/dist/src/utils/modelDiscovery.js +170 -0
  103. package/dist/src/version.js +5 -0
  104. package/dist/src/workers/captureRetention.js +25 -0
  105. package/dist/src/workers/configWatcher.js +91 -0
  106. package/dist/src/workers/healthChecker.js +21 -0
  107. package/dist/src/workers/statsRotation.js +41 -0
  108. package/docs/LLM/output_schema.md +312 -0
  109. package/docs/benchmark.md +208 -0
  110. package/docs/mcp-guidelines.md +125 -0
  111. package/docs/mcp-service.md +178 -0
  112. package/docs/opencode.md +86 -0
  113. package/docs/providers.md +79 -0
  114. package/examples/benchmark.config.yaml +28 -0
  115. package/examples/providers/alibaba-dashscope.yaml +88 -0
  116. package/examples/providers/alibaba-llm.yaml +64 -0
  117. package/examples/providers/alibaba-registry.yaml +7 -0
  118. package/examples/providers/inference-v2-ray.yaml +29 -0
  119. package/examples/scenarios/assets/omni-call-sample.wav +0 -0
  120. package/examples/scenarios/custom.jsonl +5 -0
  121. package/examples/scenarios/custom.yaml +40 -0
  122. package/model-form-v2.png +0 -0
  123. package/package.json +66 -0
  124. package/provider-form-v2.png +0 -0
  125. package/provider-form.png +0 -0
  126. package/scripts/manual-test.sh +11 -0
  127. package/scripts/version-from-git.js +23 -0
  128. package/src/benchmark/artifacts.ts +149 -0
  129. package/src/benchmark/capabilityClassifier.ts +99 -0
  130. package/src/benchmark/capabilityStore.ts +174 -0
  131. package/src/benchmark/config.ts +337 -0
  132. package/src/benchmark/gates.ts +164 -0
  133. package/src/benchmark/jobs.ts +312 -0
  134. package/src/benchmark/runner.ts +2519 -0
  135. package/src/benchmark/schema.ts +443 -0
  136. package/src/benchmark/suites.ts +323 -0
  137. package/src/benchmark/tinyQaDataset.ts +428 -0
  138. package/src/benchmark/types.ts +442 -0
  139. package/src/config.ts +44 -0
  140. package/src/index.ts +195 -0
  141. package/src/mcp/client.ts +305 -0
  142. package/src/mcp/discovery.ts +266 -0
  143. package/src/mcp/policy.ts +105 -0
  144. package/src/mcp/registry.ts +164 -0
  145. package/src/mcp/service.ts +611 -0
  146. package/src/middleware/auth.ts +251 -0
  147. package/src/middleware/requestCapture.ts +245 -0
  148. package/src/middleware/requestStats.ts +163 -0
  149. package/src/pools/builder.ts +159 -0
  150. package/src/pools/repository.ts +71 -0
  151. package/src/pools/scheduler.ts +425 -0
  152. package/src/pools/types.ts +117 -0
  153. package/src/protocols/adapters/dashscope.ts +335 -0
  154. package/src/protocols/adapters/inferenceV2.ts +428 -0
  155. package/src/protocols/adapters/openai.ts +32 -0
  156. package/src/protocols/registry.ts +117 -0
  157. package/src/protocols/types.ts +81 -0
  158. package/src/providers/health.ts +207 -0
  159. package/src/providers/importer.ts +402 -0
  160. package/src/providers/modelRegistry.ts +415 -0
  161. package/src/providers/repository.ts +439 -0
  162. package/src/providers/types.ts +113 -0
  163. package/src/routes/admin.ts +666 -0
  164. package/src/routes/audio.ts +372 -0
  165. package/src/routes/chat.ts +301 -0
  166. package/src/routes/embeddings.ts +197 -0
  167. package/src/routes/images.ts +356 -0
  168. package/src/routes/mcp.ts +320 -0
  169. package/src/routes/mcpService.ts +114 -0
  170. package/src/routes/models.ts +50 -0
  171. package/src/routes/responses.ts +872 -0
  172. package/src/routes/sessions.ts +558 -0
  173. package/src/routes/stats.ts +312 -0
  174. package/src/routes/ui.ts +96 -0
  175. package/src/routes/videos.ts +132 -0
  176. package/src/routing/router.ts +501 -0
  177. package/src/services/imageGeneration.ts +396 -0
  178. package/src/services/imageUnderstanding.ts +449 -0
  179. package/src/services/videoGeneration.ts +127 -0
  180. package/src/storage/captureRepository.ts +1835 -0
  181. package/src/storage/files.ts +178 -0
  182. package/src/storage/imageCache.ts +405 -0
  183. package/src/storage/repositories.ts +494 -0
  184. package/src/storage/sessionRepository.ts +419 -0
  185. package/src/storage/statsRepository.ts +238 -0
  186. package/src/transport/httpClient.ts +145 -0
  187. package/src/types.ts +322 -0
  188. package/src/utils/messageMedia.ts +293 -0
  189. package/src/utils/modelCapabilities.ts +161 -0
  190. package/src/utils/modelDiscovery.ts +203 -0
  191. package/src/workers/captureRetention.ts +25 -0
  192. package/src/workers/configWatcher.ts +115 -0
  193. package/src/workers/healthChecker.ts +22 -0
  194. package/src/workers/statsRotation.ts +49 -0
  195. package/tests/benchmarkAdminRoutes.test.ts +82 -0
  196. package/tests/benchmarkBasics.test.ts +116 -0
  197. package/tests/captureAdminRoutes.test.ts +420 -0
  198. package/tests/captureRepository.test.ts +797 -0
  199. package/tests/cliLegacyRewrite.test.ts +45 -0
  200. package/tests/imageGeneration.service.test.ts +107 -0
  201. package/tests/imageUnderstanding.service.test.ts +123 -0
  202. package/tests/mcpPolicy.test.ts +105 -0
  203. package/tests/mcpService.test.ts +1245 -0
  204. package/tests/modelRef.test.ts +23 -0
  205. package/tests/modelsRoutes.test.ts +154 -0
  206. package/tests/sessionMediaCache.test.ts +167 -0
  207. package/tests/statsRoutes.test.ts +323 -0
  208. package/tsconfig.json +15 -0
  209. package/ui/index.html +16 -0
  210. package/ui/package-lock.json +8521 -0
  211. package/ui/package.json +52 -0
  212. package/ui/postcss.config.js +6 -0
  213. package/ui/public/assets/apple-touch-icon.png +0 -0
  214. package/ui/public/assets/favicon-16.png +0 -0
  215. package/ui/public/assets/favicon-32.png +0 -0
  216. package/ui/public/assets/icon-192.png +0 -0
  217. package/ui/public/assets/icon-512.png +0 -0
  218. package/ui/src/App.tsx +27 -0
  219. package/ui/src/api/client.ts +1503 -0
  220. package/ui/src/components/EndpointUsageGuide.tsx +361 -0
  221. package/ui/src/components/Layout.tsx +124 -0
  222. package/ui/src/components/MessageContent.tsx +365 -0
  223. package/ui/src/components/ToolCallMessage.tsx +179 -0
  224. package/ui/src/components/ToolPicker.tsx +442 -0
  225. package/ui/src/components/messageContentParser.test.ts +41 -0
  226. package/ui/src/components/messageContentParser.ts +73 -0
  227. package/ui/src/components/thinkingPreview.test.ts +27 -0
  228. package/ui/src/components/thinkingPreview.ts +15 -0
  229. package/ui/src/components/toMermaidSankey.test.ts +78 -0
  230. package/ui/src/components/toMermaidSankey.ts +56 -0
  231. package/ui/src/components/ui/button.tsx +58 -0
  232. package/ui/src/components/ui/input.tsx +21 -0
  233. package/ui/src/components/ui/textarea.tsx +21 -0
  234. package/ui/src/lib/utils.ts +6 -0
  235. package/ui/src/main.tsx +9 -0
  236. package/ui/src/pages/AgentPlayground.tsx +2010 -0
  237. package/ui/src/pages/Benchmark.tsx +988 -0
  238. package/ui/src/pages/Dashboard.tsx +581 -0
  239. package/ui/src/pages/Peek.tsx +962 -0
  240. package/ui/src/pages/Settings.tsx +2013 -0
  241. package/ui/src/pages/agentPlaygroundPayload.test.ts +109 -0
  242. package/ui/src/pages/agentPlaygroundPayload.ts +97 -0
  243. package/ui/src/pages/agentThinkingContent.test.ts +50 -0
  244. package/ui/src/pages/agentThinkingContent.ts +57 -0
  245. package/ui/src/pages/dashboardTokenUsage.test.ts +66 -0
  246. package/ui/src/pages/dashboardTokenUsage.ts +36 -0
  247. package/ui/src/pages/imageUpload.test.ts +39 -0
  248. package/ui/src/pages/imageUpload.ts +71 -0
  249. package/ui/src/pages/peekFilters.test.ts +29 -0
  250. package/ui/src/pages/peekFilters.ts +13 -0
  251. package/ui/src/pages/peekMedia.test.ts +58 -0
  252. package/ui/src/pages/peekMedia.ts +148 -0
  253. package/ui/src/pages/sessionAutoTitle.test.ts +128 -0
  254. package/ui/src/pages/sessionAutoTitle.ts +106 -0
  255. package/ui/src/stores/settings.ts +58 -0
  256. package/ui/src/styles/globals.css +223 -0
  257. package/ui/src/vite-env.d.ts +8 -0
  258. package/ui/tailwind.config.js +106 -0
  259. package/ui/tsconfig.json +32 -0
  260. package/ui/vite.config.ts +37 -0
@@ -0,0 +1,145 @@
1
+ import { Agent, request } from "undici";
2
+ import { EndpointDoc, UpstreamError, UpstreamResult } from "../types";
3
+
4
+ const RETRYABLE_STATUSES = new Set([429, 500, 502, 503, 504]);
5
+ const TLS_VERIFY_ERROR_CODES = new Set([
6
+ "UNABLE_TO_VERIFY_LEAF_SIGNATURE",
7
+ "SELF_SIGNED_CERT_IN_CHAIN",
8
+ "DEPTH_ZERO_SELF_SIGNED_CERT",
9
+ "CERT_HAS_EXPIRED",
10
+ "UNABLE_TO_GET_ISSUER_CERT_LOCALLY",
11
+ "ERR_TLS_CERT_ALTNAME_INVALID",
12
+ "ERR_TLS_CERT_SIGNATURE_ALGORITHM_UNSUPPORTED",
13
+ ]);
14
+
15
+ export async function proxyUpstream(
16
+ endpoint: EndpointDoc,
17
+ path: string,
18
+ payload: unknown,
19
+ headers: Record<string, string | string[] | undefined>,
20
+ timeoutMs: number,
21
+ signal: AbortSignal,
22
+ options?: {
23
+ skipDefaultAuth?: boolean;
24
+ }
25
+ ): Promise<UpstreamResult> {
26
+ const url = new URL(path, endpoint.baseUrl).toString();
27
+ const dispatcher = endpoint.insecureTls
28
+ ? new Agent({ connect: { rejectUnauthorized: false } })
29
+ : undefined;
30
+
31
+ const requestHeaders: Record<string, string> = {
32
+ "content-type": "application/json",
33
+ accept: "application/json",
34
+ ...filterHeaders(headers)
35
+ };
36
+ if (endpoint.apiKey && !options?.skipDefaultAuth && !requestHeaders.authorization) {
37
+ requestHeaders.authorization = `Bearer ${endpoint.apiKey}`;
38
+ }
39
+
40
+ const response = await request(url, {
41
+ method: "POST",
42
+ body: JSON.stringify(payload),
43
+ headers: requestHeaders,
44
+ dispatcher,
45
+ signal,
46
+ headersTimeout: timeoutMs,
47
+ bodyTimeout: timeoutMs
48
+ });
49
+
50
+ return {
51
+ statusCode: response.statusCode,
52
+ headers: response.headers as Record<string, string | string[]>,
53
+ body: response.body
54
+ };
55
+ }
56
+
57
+ export function classifyUpstreamError(error: unknown): UpstreamError {
58
+ if (error instanceof Error) {
59
+ const err = error as UpstreamError;
60
+ if (typeof err.type === "string" && typeof err.retryable === "boolean") {
61
+ return err;
62
+ }
63
+ const code = (err as NodeJS.ErrnoException).code;
64
+ if (isTlsVerifyError(err, code)) {
65
+ err.type = "tls_verify_failed";
66
+ err.retryable = true;
67
+ return err;
68
+ }
69
+ // Connection errors
70
+ if (code === "ECONNREFUSED" || code === "ECONNRESET" || code === "ETIMEDOUT" || code === "ENOTFOUND") {
71
+ err.type = "connection";
72
+ err.retryable = true;
73
+ return err;
74
+ }
75
+ // Undici timeout errors
76
+ if (code === "UND_ERR_HEADERS_TIMEOUT" || code === "UND_ERR_BODY_TIMEOUT" || code === "UND_ERR_CONNECT_TIMEOUT") {
77
+ err.type = "timeout";
78
+ err.retryable = true;
79
+ return err;
80
+ }
81
+ if (err.name === "AbortError") {
82
+ err.type = "timeout";
83
+ err.retryable = true;
84
+ return err;
85
+ }
86
+ // Socket/stream errors during transfer
87
+ if (code === "ERR_STREAM_PREMATURE_CLOSE" || code === "EPIPE" || code === "ECONNABORTED") {
88
+ err.type = "stream_error";
89
+ err.retryable = true;
90
+ return err;
91
+ }
92
+ err.type = "unknown";
93
+ err.retryable = false;
94
+ return err;
95
+ }
96
+ const fallback = new Error("Unknown upstream error") as UpstreamError;
97
+ fallback.type = "unknown";
98
+ fallback.retryable = false;
99
+ return fallback;
100
+ }
101
+
102
+ function isTlsVerifyError(error: Error, code: string | undefined): boolean {
103
+ if (code && TLS_VERIFY_ERROR_CODES.has(code)) {
104
+ return true;
105
+ }
106
+ const message = error.message.toLowerCase();
107
+ return (
108
+ message.includes("unable to verify the first certificate") ||
109
+ message.includes("self-signed certificate") ||
110
+ message.includes("certificate verify failed")
111
+ );
112
+ }
113
+
114
+ export function classifyHttpStatus(statusCode: number): { retryable: boolean; type: string } {
115
+ if (statusCode === 429) {
116
+ return { retryable: true, type: "rate_limited" };
117
+ }
118
+ if (RETRYABLE_STATUSES.has(statusCode)) {
119
+ return { retryable: true, type: "upstream_5xx" };
120
+ }
121
+ if ([400, 401, 403].includes(statusCode)) {
122
+ return { retryable: false, type: "upstream_4xx" };
123
+ }
124
+ if (statusCode >= 400) {
125
+ return { retryable: false, type: "upstream_4xx" };
126
+ }
127
+ return { retryable: false, type: "ok" };
128
+ }
129
+
130
+ function filterHeaders(
131
+ headers: Record<string, string | string[] | undefined>
132
+ ): Record<string, string> {
133
+ const filtered: Record<string, string> = {};
134
+ for (const [key, value] of Object.entries(headers)) {
135
+ if (!value) {
136
+ continue;
137
+ }
138
+ const lower = key.toLowerCase();
139
+ if (lower === "host" || lower === "content-length") {
140
+ continue;
141
+ }
142
+ filtered[lower] = Array.isArray(value) ? value.join(", ") : value;
143
+ }
144
+ return filtered;
145
+ }
package/src/types.ts ADDED
@@ -0,0 +1,322 @@
1
+ export type HealthStatus = "up" | "down";
2
+ export type EndpointType = "llm" | "diffusion" | "audio" | "embedding" | "video";
3
+ export type ModelModality = "text" | "image" | "audio" | "embedding" | "video";
4
+
5
+ export interface ModelCapabilities {
6
+ input: ModelModality[];
7
+ output: ModelModality[];
8
+ supportsTools?: boolean;
9
+ supportsStreaming?: boolean;
10
+ source?: "configured" | "inferred";
11
+ }
12
+
13
+ export interface ModelMapping {
14
+ publicName: string;
15
+ upstreamModel: string;
16
+ capabilities?: ModelCapabilities;
17
+ }
18
+
19
+ export interface EndpointHealth {
20
+ status: HealthStatus;
21
+ lastCheckedAt?: Date;
22
+ lastSuccessAt?: Date;
23
+ lastFailureAt?: Date;
24
+ consecutiveFailures: number;
25
+ downUntil?: Date;
26
+ latencyMsEwma?: number;
27
+ }
28
+
29
+ export interface ProviderModelHealth {
30
+ status: HealthStatus;
31
+ lastCheckedAt?: Date;
32
+ lastSuccessAt?: Date;
33
+ lastFailureAt?: Date;
34
+ consecutiveFailures: number;
35
+ latencyMsEwma?: number;
36
+ lastStatusCode?: number;
37
+ lastError?: string;
38
+ }
39
+
40
+ export interface EndpointLimits {
41
+ timeoutMs?: number;
42
+ maxConcurrent?: number;
43
+ }
44
+
45
+ export interface EndpointDoc {
46
+ id: string;
47
+ name: string;
48
+ baseUrl: string;
49
+ apiKey?: string;
50
+ disabled?: boolean;
51
+ insecureTls: boolean;
52
+ priority: number;
53
+ weight?: number;
54
+ type: EndpointType;
55
+ models: ModelMapping[];
56
+ health: EndpointHealth;
57
+ limits?: EndpointLimits;
58
+ createdAt: Date;
59
+ updatedAt: Date;
60
+ }
61
+
62
+ export interface RequestLog {
63
+ requestId: string;
64
+ ts: Date;
65
+ route: {
66
+ publicModel: string;
67
+ endpointId?: string;
68
+ endpointName?: string;
69
+ upstreamModel?: string;
70
+ };
71
+ request: {
72
+ stream: boolean;
73
+ maxTokens?: number;
74
+ };
75
+ result: {
76
+ statusCode?: number;
77
+ latencyMs?: number;
78
+ errorType?: string;
79
+ errorMessage?: string;
80
+ totalTokens?: number | null;
81
+ };
82
+ }
83
+
84
+ export interface UpstreamResult {
85
+ statusCode: number;
86
+ headers: Record<string, string | string[]>;
87
+ body: NodeJS.ReadableStream;
88
+ rawBody?: Buffer;
89
+ }
90
+
91
+ export interface UpstreamError extends Error {
92
+ type: string;
93
+ statusCode?: number;
94
+ retryable: boolean;
95
+ triedModels?: string[];
96
+ poolId?: string;
97
+ }
98
+
99
+ // ========================================
100
+ // Image Generation Types
101
+ // ========================================
102
+
103
+ export interface ImageGenerationRequest {
104
+ model?: string;
105
+ prompt: string;
106
+ image_url?: string;
107
+ n?: number;
108
+ size?: string;
109
+ quality?: string;
110
+ style?: string;
111
+ response_format?: "url" | "b64_json";
112
+ user?: string;
113
+ }
114
+
115
+ export interface ImageObject {
116
+ url?: string;
117
+ b64_json?: string;
118
+ revised_prompt?: string;
119
+ }
120
+
121
+ export interface ImageGenerationResponse {
122
+ created: number;
123
+ data: ImageObject[];
124
+ }
125
+
126
+ // ========================================
127
+ // Audio Types
128
+ // ========================================
129
+
130
+ export interface AudioTranscriptionRequest {
131
+ file: Buffer;
132
+ model: string;
133
+ language?: string;
134
+ prompt?: string;
135
+ response_format?: "json" | "text" | "srt" | "verbose_json" | "vtt";
136
+ temperature?: number;
137
+ timestamp_granularities?: Array<"word" | "segment">;
138
+ }
139
+
140
+ export interface AudioTranscriptionResponse {
141
+ text: string;
142
+ task?: string;
143
+ language?: string;
144
+ duration?: number;
145
+ words?: Array<{ word: string; start: number; end: number }>;
146
+ segments?: Array<{
147
+ id: number;
148
+ seek: number;
149
+ start: number;
150
+ end: number;
151
+ text: string;
152
+ tokens: number[];
153
+ temperature: number;
154
+ avg_logprob: number;
155
+ compression_ratio: number;
156
+ no_speech_prob: number;
157
+ }>;
158
+ }
159
+
160
+ export interface AudioSpeechRequest {
161
+ model: string;
162
+ input: string;
163
+ voice: string;
164
+ response_format?: "mp3" | "opus" | "aac" | "flac" | "wav" | "pcm";
165
+ speed?: number;
166
+ }
167
+
168
+ // ========================================
169
+ // Responses API Types (Shim)
170
+ // ========================================
171
+
172
+ export interface ResponsesApiRequest {
173
+ model: string;
174
+ input: string | Array<{ role: string; content: string }>;
175
+ instructions?: string;
176
+ tools?: unknown[];
177
+ tool_choice?: unknown;
178
+ temperature?: number;
179
+ top_p?: number;
180
+ max_tokens?: number;
181
+ presence_penalty?: number;
182
+ frequency_penalty?: number;
183
+ seed?: number;
184
+ stop?: string | string[];
185
+ stream?: boolean;
186
+ [key: string]: unknown;
187
+ }
188
+
189
+ // ========================================
190
+ // Statistics Types
191
+ // ========================================
192
+
193
+ export interface RequestStats {
194
+ requestId: string;
195
+ timestamp: Date;
196
+ route: string;
197
+ method: string;
198
+ publicModel?: string;
199
+ endpointId?: string;
200
+ endpointName?: string;
201
+ upstreamModel?: string;
202
+ requestBytes: number;
203
+ responseBytes: number;
204
+ latencyMs: number;
205
+ statusCode: number;
206
+ errorType?: string;
207
+ totalTokens?: number | null;
208
+ promptTokens?: number | null;
209
+ completionTokens?: number | null;
210
+ }
211
+
212
+ export interface StatsAggregation {
213
+ window: string;
214
+ total: number;
215
+ success: number;
216
+ errors: number;
217
+ avgLatencyMs: number | null;
218
+ p50LatencyMs: number | null;
219
+ p95LatencyMs: number | null;
220
+ p99LatencyMs: number | null;
221
+ totalTokens: number;
222
+ tokensPerHour: number | null;
223
+ byModel: Record<string, { count: number; avgLatencyMs: number; tokens: number }>;
224
+ byEndpoint: Record<string, { count: number; avgLatencyMs: number; tokens: number; errors: number }>;
225
+ }
226
+
227
+ // ========================================
228
+ // Session Types (for Playground)
229
+ // ========================================
230
+
231
+ export interface ChatMessage {
232
+ id: string;
233
+ role: "user" | "assistant" | "system" | "tool";
234
+ content: string | ChatContentPart[] | null;
235
+ name?: string;
236
+ tool_calls?: Array<{
237
+ id: string;
238
+ type: "function";
239
+ function: { name: string; arguments: string };
240
+ }>;
241
+ tool_call_id?: string;
242
+ // Image references (data URLs in legacy sessions, cache URLs in v2+ sessions)
243
+ images?: string[];
244
+ // Model that produced this message (assistant messages only)
245
+ model?: string;
246
+ createdAt: Date;
247
+ }
248
+
249
+ export type ChatContentPart =
250
+ | { type: "text"; text: string }
251
+ | { type: "image_url"; image_url: { url: string } }
252
+ | { type: "input_audio"; input_audio: { url?: string; data?: string; format?: string } }
253
+ | { type: "audio"; audio: { url?: string; data?: string; format?: string } };
254
+
255
+ export interface ChatSession {
256
+ id: string;
257
+ name: string;
258
+ model?: string;
259
+ titleStatus?: "pending" | "generated" | "manual" | "failed";
260
+ titleUpdatedAt?: Date;
261
+ // Storage schema version:
262
+ // 1 = legacy sessions (inline data URLs)
263
+ // 2 = cache-backed image references
264
+ storageVersion: number;
265
+ messages: ChatMessage[];
266
+ createdAt: Date;
267
+ updatedAt: Date;
268
+ }
269
+
270
+ // ========================================
271
+ // MCP Types
272
+ // ========================================
273
+
274
+ export interface McpServer {
275
+ id: string;
276
+ name: string;
277
+ url: string;
278
+ enabled: boolean;
279
+ status: "connected" | "disconnected" | "error" | "unknown";
280
+ toolCount?: number;
281
+ lastConnectedAt?: Date;
282
+ lastError?: string;
283
+ createdAt: Date;
284
+ updatedAt: Date;
285
+ }
286
+
287
+ export interface McpTool {
288
+ name: string;
289
+ description?: string;
290
+ inputSchema: Record<string, unknown>;
291
+ }
292
+
293
+ // ========================================
294
+ // Video Generation Types
295
+ // ========================================
296
+
297
+ export interface VideoGenerationRequest {
298
+ model?: string;
299
+ prompt: string;
300
+ negative_prompt?: string;
301
+ image_url?: string;
302
+ audio_url?: string;
303
+ duration?: number;
304
+ resolution?: string;
305
+ n?: number;
306
+ seed?: number;
307
+ watermark?: boolean;
308
+ prompt_extend?: boolean;
309
+ response_format?: "url" | "b64_json";
310
+ user?: string;
311
+ }
312
+
313
+ export interface VideoObject {
314
+ url?: string;
315
+ b64_json?: string;
316
+ revised_prompt?: string;
317
+ }
318
+
319
+ export interface VideoGenerationResponse {
320
+ created: number;
321
+ data: VideoObject[];
322
+ }