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,352 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.runImageUnderstanding = runImageUnderstanding;
7
+ exports.resolveImageInputToUrl = resolveImageInputToUrl;
8
+ exports.resolveImageInput = resolveImageInput;
9
+ exports.imageDataUrlFromPath = imageDataUrlFromPath;
10
+ exports.imageDataUrlWithGeometryFromPath = imageDataUrlWithGeometryFromPath;
11
+ exports.buildImageGeometrySystemMessage = buildImageGeometrySystemMessage;
12
+ exports.parseImageUnderstandingText = parseImageUnderstandingText;
13
+ const fs_1 = require("fs");
14
+ const path_1 = __importDefault(require("path"));
15
+ const sharp_1 = __importDefault(require("sharp"));
16
+ const router_1 = require("../routing/router");
17
+ const scheduler_1 = require("../pools/scheduler");
18
+ const modelRegistry_1 = require("../providers/modelRegistry");
19
+ const DEFAULT_INSTRUCTION = "Analyze this image. Return OCR text, key objects, scene summary, and notable details.";
20
+ const MAX_IMAGE_PIXELS = 1080 * 720 - 1;
21
+ const RESIZE_QUALITY = 85;
22
+ async function runImageUnderstanding(paths, input, signal) {
23
+ const model = await resolveVisionTextModel(paths, input.model);
24
+ if (!model) {
25
+ throw typedError("no_vision_model", "No vision-capable text model available.");
26
+ }
27
+ const resolvedImage = await resolveImageInput(input);
28
+ const instruction = input.instruction?.trim() ? input.instruction : DEFAULT_INSTRUCTION;
29
+ const messages = [];
30
+ if (resolvedImage.imageGeometry) {
31
+ messages.push({
32
+ role: "system",
33
+ content: buildImageGeometrySystemMessage(resolvedImage.imageGeometry),
34
+ });
35
+ }
36
+ messages.push({
37
+ role: "user",
38
+ content: [
39
+ { type: "image_url", image_url: { url: resolvedImage.imageUrl } },
40
+ { type: "text", text: instruction },
41
+ ],
42
+ });
43
+ const payload = {
44
+ model,
45
+ stream: false,
46
+ messages,
47
+ };
48
+ if (typeof input.max_tokens === "number") {
49
+ payload.max_tokens = input.max_tokens;
50
+ }
51
+ if (typeof input.temperature === "number") {
52
+ payload.temperature = input.temperature;
53
+ }
54
+ const outcome = await (0, router_1.routeRequest)(paths, model, "/v1/chat/completions", payload, {}, signal, {
55
+ requiredInput: ["text", "image"],
56
+ requiredOutput: ["text"],
57
+ });
58
+ const responsePayload = await readBody(outcome.attempt.response);
59
+ const rawText = extractAssistantText(responsePayload.payload);
60
+ const analysis = parseImageUnderstandingText(rawText);
61
+ return {
62
+ model,
63
+ analysis,
64
+ raw_text: rawText,
65
+ image_geometry: resolvedImage.imageGeometry,
66
+ usage: {
67
+ prompt_tokens: responsePayload.usage?.prompt_tokens ?? 0,
68
+ completion_tokens: responsePayload.usage?.completion_tokens ?? 0,
69
+ total_tokens: responsePayload.usage?.total_tokens ?? 0,
70
+ },
71
+ };
72
+ }
73
+ async function resolveImageInputToUrl(input) {
74
+ const resolved = await resolveImageInput(input);
75
+ return resolved.imageUrl;
76
+ }
77
+ async function resolveImageInput(input) {
78
+ if (input.image_path) {
79
+ return imageDataUrlWithGeometryFromPath(input.image_path);
80
+ }
81
+ if (input.image_url && isValidImageUrl(input.image_url)) {
82
+ return { imageUrl: input.image_url };
83
+ }
84
+ throw typedError("invalid_request", "Exactly one image source is required: image_path or image_url.");
85
+ }
86
+ async function imageDataUrlFromPath(imagePath) {
87
+ const resolved = await imageDataUrlWithGeometryFromPath(imagePath);
88
+ return resolved.imageUrl;
89
+ }
90
+ async function imageDataUrlWithGeometryFromPath(imagePath) {
91
+ const abs = path_1.default.resolve(imagePath);
92
+ let data;
93
+ try {
94
+ data = await fs_1.promises.readFile(abs);
95
+ }
96
+ catch {
97
+ throw typedError("invalid_request", `image_path not readable: ${imagePath}`);
98
+ }
99
+ let mimeType = mimeFromExt(abs);
100
+ const image = (0, sharp_1.default)(data);
101
+ const meta = await image.metadata();
102
+ if (!meta.width || !meta.height) {
103
+ throw typedError("invalid_request", "Unable to read image dimensions.");
104
+ }
105
+ const originalWidth = meta.width;
106
+ const originalHeight = meta.height;
107
+ let uploadedWidth = originalWidth;
108
+ let uploadedHeight = originalHeight;
109
+ const area = meta.width * meta.height;
110
+ if (area > MAX_IMAGE_PIXELS) {
111
+ const scale = Math.sqrt(MAX_IMAGE_PIXELS / area);
112
+ const targetWidth = Math.max(1, Math.floor(meta.width * scale));
113
+ const targetHeight = Math.max(1, Math.floor(meta.height * scale));
114
+ uploadedWidth = targetWidth;
115
+ uploadedHeight = targetHeight;
116
+ let resized = image.resize(targetWidth, targetHeight, { fit: "fill" });
117
+ const format = (meta.format ?? "").toLowerCase();
118
+ if (format === "jpeg" || format === "jpg") {
119
+ resized = resized.jpeg({ quality: RESIZE_QUALITY });
120
+ mimeType = "image/jpeg";
121
+ }
122
+ else if (format === "png") {
123
+ resized = resized.png();
124
+ mimeType = "image/png";
125
+ }
126
+ else if (format === "webp") {
127
+ resized = resized.webp({ quality: RESIZE_QUALITY });
128
+ mimeType = "image/webp";
129
+ }
130
+ else {
131
+ resized = resized.png();
132
+ mimeType = "image/png";
133
+ }
134
+ data = await resized.toBuffer();
135
+ }
136
+ return {
137
+ imageUrl: `data:${mimeType};base64,${data.toString("base64")}`,
138
+ imageGeometry: {
139
+ original_width: originalWidth,
140
+ original_height: originalHeight,
141
+ uploaded_width: uploadedWidth,
142
+ uploaded_height: uploadedHeight,
143
+ scale_x: originalWidth / uploadedWidth,
144
+ scale_y: originalHeight / uploadedHeight,
145
+ resized: originalWidth !== uploadedWidth || originalHeight !== uploadedHeight,
146
+ },
147
+ };
148
+ }
149
+ function buildImageGeometrySystemMessage(imageGeometry) {
150
+ return [
151
+ "If you return coordinates or bounding boxes, express them in the original image pixel space.",
152
+ `Original image size: ${imageGeometry.original_width}x${imageGeometry.original_height}.`,
153
+ `Uploaded image size: ${imageGeometry.uploaded_width}x${imageGeometry.uploaded_height}.`,
154
+ `Scale factors from uploaded to original: x=${imageGeometry.scale_x}, y=${imageGeometry.scale_y}.`,
155
+ "Do not return coordinates in resized-image pixels.",
156
+ ].join(" ");
157
+ }
158
+ function parseImageUnderstandingText(rawText) {
159
+ const trimmed = rawText.trim();
160
+ const parsedJson = parseEmbeddedJson(trimmed);
161
+ if (parsedJson) {
162
+ return fromJsonAnalysis(parsedJson, trimmed);
163
+ }
164
+ const answer = trimmed || "No textual response returned.";
165
+ const lines = answer.split(/\r?\n/).map((line) => line.trim()).filter(Boolean);
166
+ return {
167
+ answer,
168
+ ocr_text: extractKeyValue(lines, "ocr_text") ?? extractKeyValue(lines, "ocr") ?? "",
169
+ objects: splitList(extractKeyValue(lines, "objects") ?? ""),
170
+ scene: extractKeyValue(lines, "scene") ?? "",
171
+ notable_details: splitList(extractKeyValue(lines, "notable_details") ?? extractKeyValue(lines, "notable details") ?? ""),
172
+ safety_notes: splitList(extractKeyValue(lines, "safety_notes") ?? extractKeyValue(lines, "safety notes") ?? ""),
173
+ };
174
+ }
175
+ async function resolveVisionTextModel(paths, requestedModel) {
176
+ if (requestedModel) {
177
+ return requestedModel;
178
+ }
179
+ const smart = await (0, scheduler_1.selectPoolCandidates)(paths, "smart", {
180
+ requiredInput: ["text", "image"],
181
+ requiredOutput: ["text"],
182
+ }, {
183
+ operation: "chat_completions",
184
+ stream: false,
185
+ });
186
+ if (smart && smart.candidates.length > 0) {
187
+ return "smart";
188
+ }
189
+ return (0, modelRegistry_1.pickBestProviderModelByCapabilities)(paths, { requiredInput: ["text", "image"], requiredOutput: ["text"] }, "llm");
190
+ }
191
+ async function readBody(response) {
192
+ const chunks = [];
193
+ for await (const chunk of response.body) {
194
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
195
+ }
196
+ const buffer = Buffer.concat(chunks);
197
+ const contentType = normalizeContentType(response.headers);
198
+ const rawText = buffer.toString("utf8");
199
+ let payload;
200
+ try {
201
+ payload = JSON.parse(rawText);
202
+ }
203
+ catch {
204
+ const status = typeof response.statusCode === "number" ? response.statusCode : 0;
205
+ const snippet = summarizeBodySnippet(rawText);
206
+ throw typedError("upstream_error", `Expected JSON from chat completion. status=${status} content-type=${contentType || "unknown"} body=${snippet}`);
207
+ }
208
+ return { payload, usage: payload.usage ?? null };
209
+ }
210
+ function extractAssistantText(payload) {
211
+ if (!payload || typeof payload !== "object") {
212
+ return "";
213
+ }
214
+ const choices = payload.choices;
215
+ if (!Array.isArray(choices) || choices.length === 0) {
216
+ return "";
217
+ }
218
+ const first = choices[0];
219
+ const content = first?.message?.content;
220
+ if (typeof content === "string") {
221
+ return content;
222
+ }
223
+ if (Array.isArray(content)) {
224
+ const texts = content
225
+ .map((part) => {
226
+ if (!part || typeof part !== "object")
227
+ return "";
228
+ const type = part.type;
229
+ if (type !== "text")
230
+ return "";
231
+ return part.text ?? "";
232
+ })
233
+ .filter(Boolean);
234
+ return texts.join("\n").trim();
235
+ }
236
+ return "";
237
+ }
238
+ function parseEmbeddedJson(text) {
239
+ const fencedMatch = text.match(/```(?:json)?\s*([\s\S]*?)\s*```/i);
240
+ const candidate = fencedMatch ? fencedMatch[1] : text;
241
+ try {
242
+ const parsed = JSON.parse(candidate);
243
+ return parsed && typeof parsed === "object" ? parsed : null;
244
+ }
245
+ catch {
246
+ return null;
247
+ }
248
+ }
249
+ function fromJsonAnalysis(json, fallbackRaw) {
250
+ const analysis = (json.analysis && typeof json.analysis === "object"
251
+ ? json.analysis
252
+ : json);
253
+ const answer = asString(analysis.answer) ??
254
+ asString(json.answer) ??
255
+ asString(json.raw_text) ??
256
+ asString(fallbackRaw) ??
257
+ "No textual response returned.";
258
+ return {
259
+ answer,
260
+ ocr_text: asString(analysis.ocr_text) ?? "",
261
+ objects: asStringArray(analysis.objects),
262
+ scene: asString(analysis.scene) ?? "",
263
+ notable_details: asStringArray(analysis.notable_details),
264
+ safety_notes: asStringArray(analysis.safety_notes),
265
+ };
266
+ }
267
+ function asString(value) {
268
+ if (typeof value === "string") {
269
+ const trimmed = value.trim();
270
+ return trimmed.length > 0 ? trimmed : null;
271
+ }
272
+ return null;
273
+ }
274
+ function asStringArray(value) {
275
+ if (!Array.isArray(value)) {
276
+ return [];
277
+ }
278
+ return value
279
+ .map((entry) => (typeof entry === "string" ? entry.trim() : ""))
280
+ .filter(Boolean);
281
+ }
282
+ function splitList(value) {
283
+ if (!value)
284
+ return [];
285
+ return value
286
+ .split(/[,\n]/)
287
+ .map((item) => item.replace(/^[-*]\s*/, "").trim())
288
+ .filter(Boolean);
289
+ }
290
+ function extractKeyValue(lines, key) {
291
+ const pattern = new RegExp(`^${escapeRegExp(key)}\\s*:\\s*(.+)$`, "i");
292
+ for (const line of lines) {
293
+ const match = line.match(pattern);
294
+ if (match) {
295
+ return match[1].trim();
296
+ }
297
+ }
298
+ return null;
299
+ }
300
+ function escapeRegExp(value) {
301
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
302
+ }
303
+ function isValidImageUrl(url) {
304
+ if (url.startsWith("data:")) {
305
+ return /^data:[^;]+;base64,/i.test(url);
306
+ }
307
+ try {
308
+ const parsed = new URL(url);
309
+ return parsed.protocol === "http:" || parsed.protocol === "https:";
310
+ }
311
+ catch {
312
+ return false;
313
+ }
314
+ }
315
+ function normalizeContentType(headers) {
316
+ const ct = headers["content-type"] ?? headers["Content-Type"];
317
+ if (Array.isArray(ct))
318
+ return ct.join(", ");
319
+ return ct ?? "";
320
+ }
321
+ function summarizeBodySnippet(body) {
322
+ const trimmed = body.replace(/\s+/g, " ").trim();
323
+ if (!trimmed) {
324
+ return "<empty>";
325
+ }
326
+ const max = 1024;
327
+ if (trimmed.length <= max) {
328
+ return trimmed;
329
+ }
330
+ return `${trimmed.slice(0, max)}…`;
331
+ }
332
+ function mimeFromExt(filePath) {
333
+ const ext = path_1.default.extname(filePath).slice(1).toLowerCase();
334
+ const map = {
335
+ png: "image/png",
336
+ jpg: "image/jpeg",
337
+ jpeg: "image/jpeg",
338
+ gif: "image/gif",
339
+ webp: "image/webp",
340
+ bmp: "image/bmp",
341
+ svg: "image/svg+xml",
342
+ tif: "image/tiff",
343
+ tiff: "image/tiff",
344
+ };
345
+ return map[ext] ?? "application/octet-stream";
346
+ }
347
+ function typedError(type, message) {
348
+ const error = new Error(message);
349
+ error.type = type;
350
+ error.retryable = false;
351
+ return error;
352
+ }
@@ -0,0 +1,79 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.resolveVideoGenerationModel = resolveVideoGenerationModel;
4
+ exports.runVideoGeneration = runVideoGeneration;
5
+ const router_1 = require("../routing/router");
6
+ const scheduler_1 = require("../pools/scheduler");
7
+ const modelRegistry_1 = require("../providers/modelRegistry");
8
+ async function resolveVideoGenerationModel(paths, requestedModel) {
9
+ if (requestedModel) {
10
+ return requestedModel;
11
+ }
12
+ return pickDefaultVideoModel(paths);
13
+ }
14
+ async function runVideoGeneration(paths, request, headers, signal) {
15
+ const model = await resolveVideoGenerationModel(paths, request.model);
16
+ if (!model) {
17
+ const error = new Error("No video generation model available. Add or enable a provider model.");
18
+ error.type = "no_video_model";
19
+ error.retryable = false;
20
+ throw error;
21
+ }
22
+ const outcome = await (0, router_1.routeRequest)(paths, model, "/v1/videos/generations", { ...request, model }, headers, signal, {
23
+ endpointType: "video",
24
+ requiredInput: ["text"],
25
+ requiredOutput: ["video"],
26
+ });
27
+ const body = await readBody(outcome.attempt.response);
28
+ return {
29
+ model,
30
+ statusCode: outcome.attempt.response.statusCode,
31
+ headers: outcome.attempt.response.headers,
32
+ payload: body.payload,
33
+ route: {
34
+ endpointId: outcome.attempt.endpoint.id,
35
+ endpointName: outcome.attempt.endpoint.name,
36
+ upstreamModel: outcome.attempt.upstreamModel,
37
+ },
38
+ };
39
+ }
40
+ async function pickDefaultVideoModel(paths) {
41
+ const smart = await (0, scheduler_1.selectPoolCandidates)(paths, "smart", {
42
+ requiredInput: ["text"],
43
+ requiredOutput: ["video"],
44
+ }, {
45
+ operation: "video_generations",
46
+ stream: false,
47
+ });
48
+ if (smart && smart.candidates.length > 0) {
49
+ return "smart";
50
+ }
51
+ const byCapabilities = await (0, modelRegistry_1.pickBestProviderModelByCapabilities)(paths, { requiredInput: ["text"], requiredOutput: ["video"] }, "video");
52
+ if (byCapabilities) {
53
+ return byCapabilities;
54
+ }
55
+ return null;
56
+ }
57
+ async function readBody(response) {
58
+ const chunks = [];
59
+ for await (const chunk of response.body) {
60
+ chunks.push(Buffer.isBuffer(chunk) ? chunk : Buffer.from(chunk));
61
+ }
62
+ const buffer = Buffer.concat(chunks);
63
+ const contentType = normalizeContentType(response.headers);
64
+ if (contentType.includes("application/json")) {
65
+ try {
66
+ return { payload: JSON.parse(buffer.toString("utf8")) };
67
+ }
68
+ catch {
69
+ return { payload: buffer };
70
+ }
71
+ }
72
+ return { payload: buffer };
73
+ }
74
+ function normalizeContentType(headers) {
75
+ const ct = headers["content-type"] ?? headers["Content-Type"];
76
+ if (Array.isArray(ct))
77
+ return ct.join(", ");
78
+ return ct ?? "";
79
+ }