@plasius/ai 1.1.4 → 1.1.6

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 (98) hide show
  1. package/CHANGELOG.md +22 -2
  2. package/README.md +101 -2
  3. package/dist/components/pixelverse/balance.d.ts +6 -2
  4. package/dist/components/pixelverse/balance.d.ts.map +1 -1
  5. package/dist/components/pixelverse/balance.js +13 -23
  6. package/dist/components/pixelverse/index.d.ts +1 -1
  7. package/dist/components/pixelverse/index.d.ts.map +1 -1
  8. package/dist/components/pixelverse/index.js +1 -1
  9. package/dist/components/pixelverse/video-generation-editor.d.ts +10 -0
  10. package/dist/components/pixelverse/video-generation-editor.d.ts.map +1 -0
  11. package/dist/components/pixelverse/video-generation-editor.js +79 -0
  12. package/dist/platform/adapter-platform.d.ts +60 -0
  13. package/dist/platform/adapter-platform.d.ts.map +1 -0
  14. package/dist/platform/adapter-platform.js +222 -0
  15. package/dist/platform/gemini-adapter.d.ts +15 -0
  16. package/dist/platform/gemini-adapter.d.ts.map +1 -0
  17. package/dist/platform/gemini-adapter.js +293 -0
  18. package/dist/platform/http-resilience.d.ts +19 -0
  19. package/dist/platform/http-resilience.d.ts.map +1 -0
  20. package/dist/platform/http-resilience.js +126 -0
  21. package/dist/platform/index.d.ts +22 -1
  22. package/dist/platform/index.d.ts.map +1 -1
  23. package/dist/platform/index.js +24 -0
  24. package/dist/platform/openai-adapter.d.ts +24 -0
  25. package/dist/platform/openai-adapter.d.ts.map +1 -0
  26. package/dist/platform/openai-adapter.js +398 -0
  27. package/dist/platform/video-provider-adapter.d.ts +54 -0
  28. package/dist/platform/video-provider-adapter.d.ts.map +1 -0
  29. package/dist/platform/video-provider-adapter.js +165 -0
  30. package/dist/platform/video-provider-platform.d.ts +13 -0
  31. package/dist/platform/video-provider-platform.d.ts.map +1 -0
  32. package/dist/platform/video-provider-platform.js +102 -0
  33. package/dist-cjs/components/pixelverse/balance.d.ts +6 -2
  34. package/dist-cjs/components/pixelverse/balance.d.ts.map +1 -1
  35. package/dist-cjs/components/pixelverse/balance.js +13 -23
  36. package/dist-cjs/components/pixelverse/index.d.ts +1 -1
  37. package/dist-cjs/components/pixelverse/index.d.ts.map +1 -1
  38. package/dist-cjs/components/pixelverse/index.js +1 -1
  39. package/dist-cjs/components/pixelverse/video-generation-editor.d.ts +10 -0
  40. package/dist-cjs/components/pixelverse/video-generation-editor.d.ts.map +1 -0
  41. package/dist-cjs/components/pixelverse/video-generation-editor.js +85 -0
  42. package/dist-cjs/platform/adapter-platform.d.ts +60 -0
  43. package/dist-cjs/platform/adapter-platform.d.ts.map +1 -0
  44. package/dist-cjs/platform/adapter-platform.js +225 -0
  45. package/dist-cjs/platform/gemini-adapter.d.ts +15 -0
  46. package/dist-cjs/platform/gemini-adapter.d.ts.map +1 -0
  47. package/dist-cjs/platform/gemini-adapter.js +296 -0
  48. package/dist-cjs/platform/http-resilience.d.ts +19 -0
  49. package/dist-cjs/platform/http-resilience.d.ts.map +1 -0
  50. package/dist-cjs/platform/http-resilience.js +129 -0
  51. package/dist-cjs/platform/index.d.ts +22 -1
  52. package/dist-cjs/platform/index.d.ts.map +1 -1
  53. package/dist-cjs/platform/index.js +30 -1
  54. package/dist-cjs/platform/openai-adapter.d.ts +24 -0
  55. package/dist-cjs/platform/openai-adapter.d.ts.map +1 -0
  56. package/dist-cjs/platform/openai-adapter.js +401 -0
  57. package/dist-cjs/platform/video-provider-adapter.d.ts +54 -0
  58. package/dist-cjs/platform/video-provider-adapter.d.ts.map +1 -0
  59. package/dist-cjs/platform/video-provider-adapter.js +168 -0
  60. package/dist-cjs/platform/video-provider-platform.d.ts +13 -0
  61. package/dist-cjs/platform/video-provider-platform.d.ts.map +1 -0
  62. package/dist-cjs/platform/video-provider-platform.js +105 -0
  63. package/docs/api-reference.md +59 -0
  64. package/docs/architecture.md +5 -1
  65. package/docs/providers.md +24 -6
  66. package/package.json +6 -6
  67. package/src/components/pixelverse/balance.tsx +22 -35
  68. package/src/components/pixelverse/index.ts +1 -1
  69. package/src/components/pixelverse/video-generation-editor.tsx +164 -0
  70. package/src/platform/adapter-platform.ts +440 -0
  71. package/src/platform/gemini-adapter.ts +391 -0
  72. package/src/platform/http-resilience.ts +198 -0
  73. package/src/platform/index.ts +68 -0
  74. package/src/platform/openai-adapter.ts +552 -0
  75. package/src/platform/video-provider-adapter.ts +303 -0
  76. package/src/platform/video-provider-platform.ts +208 -0
  77. package/dist/components/pixelverse/pixelverseeditor.d.ts +0 -16
  78. package/dist/components/pixelverse/pixelverseeditor.d.ts.map +0 -1
  79. package/dist/components/pixelverse/pixelverseeditor.js +0 -21
  80. package/dist/platform/openai.d.ts +0 -8
  81. package/dist/platform/openai.d.ts.map +0 -1
  82. package/dist/platform/openai.js +0 -61
  83. package/dist/platform/pixelverse.d.ts +0 -6
  84. package/dist/platform/pixelverse.d.ts.map +0 -1
  85. package/dist/platform/pixelverse.js +0 -196
  86. package/dist-cjs/components/pixelverse/pixelverseeditor.d.ts +0 -16
  87. package/dist-cjs/components/pixelverse/pixelverseeditor.d.ts.map +0 -1
  88. package/dist-cjs/components/pixelverse/pixelverseeditor.js +0 -27
  89. package/dist-cjs/platform/openai.d.ts +0 -8
  90. package/dist-cjs/platform/openai.d.ts.map +0 -1
  91. package/dist-cjs/platform/openai.js +0 -67
  92. package/dist-cjs/platform/pixelverse.d.ts +0 -6
  93. package/dist-cjs/platform/pixelverse.d.ts.map +0 -1
  94. package/dist-cjs/platform/pixelverse.js +0 -199
  95. package/src/components/pixelverse/pixelverseeditor.mocule.css +0 -0
  96. package/src/components/pixelverse/pixelverseeditor.tsx +0 -74
  97. package/src/platform/openai.ts +0 -123
  98. package/src/platform/pixelverse.ts +0 -309
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gemini-adapter.d.ts","sourceRoot":"","sources":["../../src/platform/gemini-adapter.ts"],"names":[],"mappings":"AAEA,OAAO,EAKL,KAAK,mBAAmB,EAKzB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAmB,KAAK,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAE9E,MAAM,WAAW,oBAAoB;IACnC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;IACvB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,aAAa,CAAC,EAAE;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;CACH;AAkLD,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,oBAAyB,GACjC,mBAAmB,CAyLrB"}
@@ -0,0 +1,293 @@
1
+ import { performance } from "node:perf_hooks";
2
+ import { AICapability, } from "./index.js";
3
+ import { fetchWithPolicy } from "./http-resilience.js";
4
+ function normalizeBaseUrl(baseUrl) {
5
+ const normalized = (baseUrl ?? "https://generativelanguage.googleapis.com/v1beta").trim();
6
+ return normalized.endsWith("/") ? normalized.slice(0, -1) : normalized;
7
+ }
8
+ function resolveFetch(fetchFn) {
9
+ const resolved = fetchFn ?? (typeof fetch !== "undefined" ? fetch : undefined);
10
+ if (!resolved) {
11
+ throw new Error("No fetch implementation available for Gemini adapter.");
12
+ }
13
+ return resolved;
14
+ }
15
+ function asRecord(value) {
16
+ return value && typeof value === "object" ? value : {};
17
+ }
18
+ function asString(value) {
19
+ return typeof value === "string" && value.length > 0 ? value : undefined;
20
+ }
21
+ async function parseResponseBody(response) {
22
+ const contentType = response.headers.get("content-type") ?? "";
23
+ if (contentType.includes("application/json")) {
24
+ return await response.json();
25
+ }
26
+ const text = await response.text();
27
+ if (!text) {
28
+ return undefined;
29
+ }
30
+ try {
31
+ return JSON.parse(text);
32
+ }
33
+ catch {
34
+ return text;
35
+ }
36
+ }
37
+ function resolveErrorMessage(body, fallback) {
38
+ const payload = asRecord(body);
39
+ const nestedError = asRecord(payload.error);
40
+ return (asString(nestedError.message) ??
41
+ asString(payload.message) ??
42
+ asString(payload.error) ??
43
+ fallback);
44
+ }
45
+ function requireApiKey(apiKey) {
46
+ const trimmed = apiKey.trim();
47
+ if (!trimmed) {
48
+ throw new Error("Gemini API key is required.");
49
+ }
50
+ return trimmed;
51
+ }
52
+ function createBaseCompletion(type, model, requestor, durationMs, usage) {
53
+ return {
54
+ partitionKey: requestor,
55
+ id: crypto.randomUUID(),
56
+ type,
57
+ model,
58
+ createdAt: new Date().toISOString(),
59
+ durationMs,
60
+ usage: usage ?? {},
61
+ };
62
+ }
63
+ function extractGeminiText(body) {
64
+ const root = asRecord(body);
65
+ const candidates = Array.isArray(root.candidates) ? root.candidates : [];
66
+ const first = candidates[0] && typeof candidates[0] === "object" ? asRecord(candidates[0]) : {};
67
+ const content = asRecord(first.content);
68
+ const parts = Array.isArray(content.parts) ? content.parts : [];
69
+ const text = parts
70
+ .map((part) => {
71
+ const maybePart = asRecord(part);
72
+ return asString(maybePart.text) ?? "";
73
+ })
74
+ .join("")
75
+ .trim();
76
+ if (!text) {
77
+ throw new Error("Gemini response did not contain text output.");
78
+ }
79
+ return text;
80
+ }
81
+ function extractGeminiUsage(body) {
82
+ const root = asRecord(body);
83
+ const usageMetadata = asRecord(root.usageMetadata);
84
+ const promptTokenCount = usageMetadata.promptTokenCount;
85
+ const candidatesTokenCount = usageMetadata.candidatesTokenCount;
86
+ const totalTokenCount = usageMetadata.totalTokenCount;
87
+ const usage = {};
88
+ if (typeof promptTokenCount === "number") {
89
+ usage.inputTokens = promptTokenCount;
90
+ }
91
+ if (typeof candidatesTokenCount === "number") {
92
+ usage.outputTokens = candidatesTokenCount;
93
+ }
94
+ if (typeof totalTokenCount === "number") {
95
+ usage.totalTokens = totalTokenCount;
96
+ }
97
+ return Object.keys(usage).length > 0 ? usage : undefined;
98
+ }
99
+ function extractGeminiImage(body) {
100
+ const root = asRecord(body);
101
+ const predictions = Array.isArray(root.predictions) ? root.predictions : [];
102
+ const firstPrediction = predictions[0] && typeof predictions[0] === "object"
103
+ ? asRecord(predictions[0])
104
+ : {};
105
+ const bytesBase64Encoded = asString(firstPrediction.bytesBase64Encoded) ??
106
+ asString(asRecord(firstPrediction.image).bytesBase64Encoded);
107
+ if (!bytesBase64Encoded) {
108
+ throw new Error("Gemini image response did not contain base64 image bytes.");
109
+ }
110
+ const mimeType = asString(firstPrediction.mimeType) ??
111
+ asString(asRecord(firstPrediction.image).mimeType) ??
112
+ "image/png";
113
+ return new URL(`data:${mimeType};base64,${bytesBase64Encoded}`);
114
+ }
115
+ function parseGeneratedModel(text) {
116
+ const trimmed = text.trim();
117
+ if (!trimmed) {
118
+ return {
119
+ modelId: crypto.randomUUID(),
120
+ };
121
+ }
122
+ try {
123
+ const parsed = JSON.parse(trimmed);
124
+ const root = asRecord(parsed);
125
+ const modelId = asString(root.modelId);
126
+ const artifactUrl = asString(root.artifactUrl);
127
+ if (modelId) {
128
+ return {
129
+ modelId,
130
+ artifactUrl: artifactUrl ? new URL(artifactUrl) : undefined,
131
+ };
132
+ }
133
+ }
134
+ catch {
135
+ // Fallback below.
136
+ }
137
+ return {
138
+ modelId: trimmed,
139
+ };
140
+ }
141
+ function withApiKey(path, apiKey) {
142
+ const delimiter = path.includes("?") ? "&" : "?";
143
+ return `${path}${delimiter}key=${encodeURIComponent(apiKey)}`;
144
+ }
145
+ export function createGeminiAdapter(options = {}) {
146
+ const providerId = (options.id ?? "gemini").trim() || "gemini";
147
+ const baseUrl = normalizeBaseUrl(options.baseUrl);
148
+ const fetcher = resolveFetch(options.fetchFn);
149
+ const chatWithAI = async (request) => {
150
+ const startedAt = performance.now();
151
+ const apiKey = requireApiKey(request.apiKey);
152
+ const resolvedModel = request.model || options.defaultModels?.chat || "gemini-2.0-flash";
153
+ const response = await fetchWithPolicy({
154
+ url: withApiKey(`${baseUrl}/models/${resolvedModel}:generateContent`, apiKey),
155
+ operation: "Gemini chat request",
156
+ fetchFn: fetcher,
157
+ policy: options.httpPolicy,
158
+ createRequestInit: () => ({
159
+ method: "POST",
160
+ headers: {
161
+ "Content-Type": "application/json",
162
+ "X-Request-Id": request.traceId,
163
+ "X-Plasius-Client": "@plasius/ai/gemini-adapter",
164
+ },
165
+ body: JSON.stringify({
166
+ contents: [
167
+ {
168
+ role: "user",
169
+ parts: [{ text: request.input }],
170
+ },
171
+ ],
172
+ ...(request.context
173
+ ? {
174
+ systemInstruction: {
175
+ parts: [{ text: request.context }],
176
+ },
177
+ }
178
+ : {}),
179
+ }),
180
+ }),
181
+ });
182
+ const body = await parseResponseBody(response);
183
+ if (!response.ok) {
184
+ throw new Error(resolveErrorMessage(body, `Gemini chat request failed (${response.status} ${response.statusText}).`));
185
+ }
186
+ const message = extractGeminiText(body);
187
+ const usage = extractGeminiUsage(body);
188
+ const durationMs = performance.now() - startedAt;
189
+ const base = createBaseCompletion("chat", resolvedModel, request.userId, durationMs, usage);
190
+ return {
191
+ ...base,
192
+ message,
193
+ outputUser: "assistant",
194
+ };
195
+ };
196
+ const generateImage = async (request) => {
197
+ const startedAt = performance.now();
198
+ const apiKey = requireApiKey(request.apiKey);
199
+ const resolvedModel = request.model || options.defaultModels?.image || "imagen-3.0-generate-002";
200
+ const combinedPrompt = request.context
201
+ ? `${request.context}\n\n${request.input}`
202
+ : request.input;
203
+ const response = await fetchWithPolicy({
204
+ url: withApiKey(`${baseUrl}/models/${resolvedModel}:predict`, apiKey),
205
+ operation: "Gemini image generation",
206
+ fetchFn: fetcher,
207
+ policy: options.httpPolicy,
208
+ createRequestInit: () => ({
209
+ method: "POST",
210
+ headers: {
211
+ "Content-Type": "application/json",
212
+ "X-Request-Id": request.traceId,
213
+ "X-Plasius-Client": "@plasius/ai/gemini-adapter",
214
+ },
215
+ body: JSON.stringify({
216
+ instances: [{ prompt: combinedPrompt }],
217
+ parameters: { sampleCount: 1 },
218
+ }),
219
+ }),
220
+ });
221
+ const body = await parseResponseBody(response);
222
+ if (!response.ok) {
223
+ throw new Error(resolveErrorMessage(body, `Gemini image generation failed (${response.status} ${response.statusText}).`));
224
+ }
225
+ const url = extractGeminiImage(body);
226
+ const durationMs = performance.now() - startedAt;
227
+ const base = createBaseCompletion("image", resolvedModel, request.userId, durationMs);
228
+ return {
229
+ ...base,
230
+ url,
231
+ };
232
+ };
233
+ const generateModel = async (request) => {
234
+ const startedAt = performance.now();
235
+ const apiKey = requireApiKey(request.apiKey);
236
+ const resolvedModel = request.model || options.defaultModels?.model || "gemini-2.0-flash";
237
+ const systemInstruction = [
238
+ request.context,
239
+ "Return JSON only with fields modelId (string) and optional artifactUrl (string URL).",
240
+ ]
241
+ .filter(Boolean)
242
+ .join("\n");
243
+ const response = await fetchWithPolicy({
244
+ url: withApiKey(`${baseUrl}/models/${resolvedModel}:generateContent`, apiKey),
245
+ operation: "Gemini model generation",
246
+ fetchFn: fetcher,
247
+ policy: options.httpPolicy,
248
+ createRequestInit: () => ({
249
+ method: "POST",
250
+ headers: {
251
+ "Content-Type": "application/json",
252
+ "X-Request-Id": request.traceId,
253
+ "X-Plasius-Client": "@plasius/ai/gemini-adapter",
254
+ },
255
+ body: JSON.stringify({
256
+ contents: [
257
+ {
258
+ role: "user",
259
+ parts: [{ text: request.input }],
260
+ },
261
+ ],
262
+ generationConfig: {
263
+ responseMimeType: "application/json",
264
+ },
265
+ systemInstruction: {
266
+ parts: [{ text: systemInstruction }],
267
+ },
268
+ }),
269
+ }),
270
+ });
271
+ const body = await parseResponseBody(response);
272
+ if (!response.ok) {
273
+ throw new Error(resolveErrorMessage(body, `Gemini model generation failed (${response.status} ${response.statusText}).`));
274
+ }
275
+ const text = extractGeminiText(body);
276
+ const parsed = parseGeneratedModel(text);
277
+ const usage = extractGeminiUsage(body);
278
+ const durationMs = performance.now() - startedAt;
279
+ const base = createBaseCompletion("model", resolvedModel, request.userId, durationMs, usage);
280
+ return {
281
+ ...base,
282
+ modelId: parsed.modelId,
283
+ artifactUrl: parsed.artifactUrl,
284
+ };
285
+ };
286
+ return {
287
+ id: providerId,
288
+ capabilities: [AICapability.Chat, AICapability.Image, AICapability.Model],
289
+ chatWithAI,
290
+ generateImage,
291
+ generateModel,
292
+ };
293
+ }
@@ -0,0 +1,19 @@
1
+ export interface HttpClientPolicy {
2
+ maxAttempts?: number;
3
+ timeoutMs?: number;
4
+ baseDelayMs?: number;
5
+ maxDelayMs?: number;
6
+ jitterRatio?: number;
7
+ respectRetryAfter?: boolean;
8
+ retryableMethods?: string[];
9
+ retryableStatusCodes?: number[];
10
+ }
11
+ export interface FetchWithPolicyOptions {
12
+ url: string;
13
+ operation: string;
14
+ fetchFn: typeof fetch;
15
+ policy?: HttpClientPolicy;
16
+ createRequestInit: () => RequestInit | Promise<RequestInit>;
17
+ }
18
+ export declare function fetchWithPolicy(options: FetchWithPolicyOptions): Promise<Response>;
19
+ //# sourceMappingURL=http-resilience.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http-resilience.d.ts","sourceRoot":"","sources":["../../src/platform/http-resilience.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,gBAAgB;IAC/B,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,oBAAoB,CAAC,EAAE,MAAM,EAAE,CAAC;CACjC;AAED,MAAM,WAAW,sBAAsB;IACrC,GAAG,EAAE,MAAM,CAAC;IACZ,SAAS,EAAE,MAAM,CAAC;IAClB,OAAO,EAAE,OAAO,KAAK,CAAC;IACtB,MAAM,CAAC,EAAE,gBAAgB,CAAC;IAC1B,iBAAiB,EAAE,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,CAAC,CAAC;CAC7D;AA0GD,wBAAsB,eAAe,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,QAAQ,CAAC,CA0ExF"}
@@ -0,0 +1,126 @@
1
+ const DEFAULT_RETRYABLE_STATUS_CODES = [408, 409, 425, 429, 500, 502, 503, 504];
2
+ const DEFAULT_RETRYABLE_METHODS = ["GET", "HEAD", "OPTIONS", "PUT", "DELETE", "POST"];
3
+ function normalizePolicy(policy) {
4
+ return {
5
+ maxAttempts: Math.max(1, policy?.maxAttempts ?? 3),
6
+ timeoutMs: Math.max(1, policy?.timeoutMs ?? 30000),
7
+ baseDelayMs: Math.max(0, policy?.baseDelayMs ?? 250),
8
+ maxDelayMs: Math.max(0, policy?.maxDelayMs ?? 4000),
9
+ jitterRatio: Math.max(0, policy?.jitterRatio ?? 0.2),
10
+ respectRetryAfter: policy?.respectRetryAfter ?? true,
11
+ retryableMethods: policy?.retryableMethods?.map((method) => method.toUpperCase()) ??
12
+ DEFAULT_RETRYABLE_METHODS,
13
+ retryableStatusCodes: policy?.retryableStatusCodes ?? DEFAULT_RETRYABLE_STATUS_CODES,
14
+ };
15
+ }
16
+ function parseRetryAfterMs(header) {
17
+ if (!header) {
18
+ return undefined;
19
+ }
20
+ const asNumber = Number(header);
21
+ if (Number.isFinite(asNumber)) {
22
+ return Math.max(0, Math.round(asNumber * 1000));
23
+ }
24
+ const asDate = Date.parse(header);
25
+ if (Number.isFinite(asDate)) {
26
+ return Math.max(0, asDate - Date.now());
27
+ }
28
+ return undefined;
29
+ }
30
+ function computeBackoffDelayMs(retryIndex, baseDelayMs, maxDelayMs, jitterRatio) {
31
+ const exponent = Math.max(0, retryIndex - 1);
32
+ const cappedExponential = Math.min(maxDelayMs, baseDelayMs * 2 ** exponent);
33
+ if (cappedExponential === 0) {
34
+ return 0;
35
+ }
36
+ const jitter = cappedExponential * jitterRatio * Math.random();
37
+ return Math.round(cappedExponential + jitter);
38
+ }
39
+ async function sleep(ms) {
40
+ if (ms <= 0) {
41
+ return;
42
+ }
43
+ await new Promise((resolve) => setTimeout(resolve, ms));
44
+ }
45
+ function isAbortError(error) {
46
+ return error instanceof DOMException && error.name === "AbortError";
47
+ }
48
+ function isRetryableError(error) {
49
+ return error instanceof TypeError || isAbortError(error);
50
+ }
51
+ async function fetchWithTimeout(fetchFn, url, init, timeoutMs) {
52
+ const externalSignal = init.signal ?? null;
53
+ if (externalSignal?.aborted) {
54
+ throw externalSignal.reason;
55
+ }
56
+ const controller = new AbortController();
57
+ const timeout = setTimeout(() => {
58
+ controller.abort(new Error(`Request timed out after ${timeoutMs}ms.`));
59
+ }, timeoutMs);
60
+ const abortRelay = () => {
61
+ controller.abort(externalSignal?.reason);
62
+ };
63
+ if (externalSignal) {
64
+ externalSignal.addEventListener("abort", abortRelay, { once: true });
65
+ }
66
+ try {
67
+ return await fetchFn(url, {
68
+ ...init,
69
+ signal: controller.signal,
70
+ });
71
+ }
72
+ finally {
73
+ clearTimeout(timeout);
74
+ if (externalSignal) {
75
+ externalSignal.removeEventListener("abort", abortRelay);
76
+ }
77
+ }
78
+ }
79
+ export async function fetchWithPolicy(options) {
80
+ const policy = normalizePolicy(options.policy);
81
+ let lastError;
82
+ for (let attempt = 1; attempt <= policy.maxAttempts; attempt += 1) {
83
+ const requestInit = await options.createRequestInit();
84
+ const method = (requestInit.method ?? "GET").toUpperCase();
85
+ try {
86
+ const response = await fetchWithTimeout(options.fetchFn, options.url, requestInit, policy.timeoutMs);
87
+ if (response.ok || attempt >= policy.maxAttempts) {
88
+ return response;
89
+ }
90
+ const canRetryMethod = policy.retryableMethods.includes(method);
91
+ const canRetryStatus = policy.retryableStatusCodes.includes(response.status);
92
+ if (!canRetryMethod || !canRetryStatus) {
93
+ return response;
94
+ }
95
+ const retryAfterMs = policy.respectRetryAfter
96
+ ? parseRetryAfterMs(response.headers.get("retry-after"))
97
+ : undefined;
98
+ const backoffMs = computeBackoffDelayMs(attempt, policy.baseDelayMs, policy.maxDelayMs, policy.jitterRatio);
99
+ const delayMs = Math.max(retryAfterMs ?? 0, backoffMs);
100
+ try {
101
+ await response.body?.cancel();
102
+ }
103
+ catch {
104
+ // Ignore cancellation errors and continue retry flow.
105
+ }
106
+ await sleep(delayMs);
107
+ continue;
108
+ }
109
+ catch (error) {
110
+ lastError = error;
111
+ const canRetryMethod = policy.retryableMethods.includes(method);
112
+ const externalAborted = requestInit.signal?.aborted ?? false;
113
+ const shouldRetry = attempt < policy.maxAttempts &&
114
+ canRetryMethod &&
115
+ !externalAborted &&
116
+ isRetryableError(error);
117
+ if (!shouldRetry) {
118
+ throw error;
119
+ }
120
+ const delayMs = computeBackoffDelayMs(attempt, policy.baseDelayMs, policy.maxDelayMs, policy.jitterRatio);
121
+ await sleep(delayMs);
122
+ }
123
+ }
124
+ throw (lastError ??
125
+ new Error(`${options.operation} failed without a recoverable response.`));
126
+ }
@@ -49,6 +49,14 @@ export declare const videoCompletionSchema: import("@plasius/schema").Schema<{
49
49
  export interface VideoCompletion extends Completion {
50
50
  url: URL;
51
51
  }
52
+ export declare const modelCompletionSchema: import("@plasius/schema").Schema<{
53
+ modelId: FieldBuilder<string, string>;
54
+ artifactUrl: FieldBuilder<URL, string>;
55
+ }>;
56
+ export interface ModelCompletion extends Completion {
57
+ modelId: string;
58
+ artifactUrl?: URL;
59
+ }
52
60
  export declare const balanceCompletionSchema: import("@plasius/schema").Schema<{
53
61
  balance: FieldBuilder<number, number>;
54
62
  }>;
@@ -61,7 +69,8 @@ export declare enum AICapability {
61
69
  Speech = 2,
62
70
  Image = 3,
63
71
  Video = 4,
64
- Balance = 5
72
+ Balance = 5,
73
+ Model = 6
65
74
  }
66
75
  export interface AIPlatform {
67
76
  canHandle?: (userId: string, capabilities: AICapability[]) => Promise<boolean>;
@@ -70,7 +79,19 @@ export interface AIPlatform {
70
79
  transcribeSpeech: (userId: string, input: Buffer, context: string, model: string) => Promise<TextCompletion>;
71
80
  generateImage: (userId: string, input: string, context: string, model: string) => Promise<ImageCompletion>;
72
81
  produceVideo: (userId: string, imput: string, image: URL, context: string, model: string) => Promise<VideoCompletion>;
82
+ generateModel: (userId: string, input: string, context: string, model: string) => Promise<ModelCompletion>;
73
83
  checkBalance: (userId: string) => Promise<BalanceCompletion>;
74
84
  currentBalance: number;
75
85
  }
86
+ export type { HttpClientPolicy, } from "./http-resilience.js";
87
+ export type { ProviderBalance, VideoGenerationRequest, VideoGenerationResult, VideoJobResult, VideoJobState, VideoProviderAdapter, VideoProviderRequestContext, } from "./video-provider-adapter.js";
88
+ export { createHttpVideoProviderAdapter } from "./video-provider-adapter.js";
89
+ export type { AdapterBalanceRequest, AdapterChatRequest, AdapterGenerateImageRequest, AdapterGenerateModelRequest, AdapterPlatformProps, AdapterRequestContext, AdapterSynthesizeSpeechRequest, AdapterTranscribeSpeechRequest, AdapterVideoRequest, AICapabilityAdapter, } from "./adapter-platform.js";
90
+ export { createAdapterPlatform } from "./adapter-platform.js";
91
+ export type { VideoProviderPlatformProps } from "./video-provider-platform.js";
92
+ export { createVideoProviderPlatform } from "./video-provider-platform.js";
93
+ export type { OpenAIAdapterOptions } from "./openai-adapter.js";
94
+ export { createOpenAIAdapter } from "./openai-adapter.js";
95
+ export type { GeminiAdapterOptions } from "./gemini-adapter.js";
96
+ export { createGeminiAdapter } from "./gemini-adapter.js";
76
97
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/platform/index.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAe,MAAM,iBAAiB,CAAC;AAEjE,eAAO,MAAM,gBAAgB;;;;;;;;EA0C5B,CAAC;AAEF,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,UAAU,EAAE,MAAM,CAAC;IACnB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAChC;AAED,eAAO,MAAM,oBAAoB;;;EAmBhC,CAAC;AAEF,MAAM,WAAW,cAAe,SAAQ,UAAU;IAChD,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,eAAO,MAAM,oBAAoB;;EAehC,CAAC;AAEF,MAAM,WAAW,cAAe,SAAQ,UAAU;IAChD,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,eAAO,MAAM,qBAAqB;;EAgBjC,CAAC;AAEF,MAAM,WAAW,eAAgB,SAAQ,UAAU;IACjD,GAAG,EAAE,GAAG,CAAC;CACV;AAED,eAAO,MAAM,sBAAsB;;EAgBlC,CAAC;AAEF,MAAM,WAAW,gBAAiB,SAAQ,UAAU;IAClD,GAAG,EAAE,GAAG,CAAC;CACV;AAED,eAAO,MAAM,qBAAqB;;EAgBjC,CAAC;AAEF,MAAM,WAAW,eAAgB,SAAQ,UAAU;IACjD,GAAG,EAAE,GAAG,CAAC;CACV;AAED,eAAO,MAAM,uBAAuB;;EAYnC,CAAC;AAEF,MAAM,WAAW,iBAAkB,SAAQ,UAAU;IACnD,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,oBAAY,YAAY;IACtB,IAAI,IAAA;IACJ,IAAI,IAAA;IACJ,MAAM,IAAA;IACN,KAAK,IAAA;IACL,KAAK,IAAA;IACL,OAAO,IAAA;CACR;AAED,MAAM,WAAW,UAAU;IACzB,SAAS,CAAC,EAAE,CACV,MAAM,EAAE,MAAM,EACd,YAAY,EAAE,YAAY,EAAE,KACzB,OAAO,CAAC,OAAO,CAAC,CAAC;IACtB,UAAU,EAAE,CACV,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,KACV,OAAO,CAAC,cAAc,CAAC,CAAC;IAC7B,gBAAgB,EAAE,CAChB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,KACV,OAAO,CAAC,gBAAgB,CAAC,CAAC;IAC/B,gBAAgB,EAAE,CAChB,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,KACV,OAAO,CAAC,cAAc,CAAC,CAAC;IAC7B,aAAa,EAAE,CACb,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,KACV,OAAO,CAAC,eAAe,CAAC,CAAC;IAC9B,YAAY,EAAE,CACZ,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,KAAK,EAAE,GAAG,EACV,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,KACV,OAAO,CAAC,eAAe,CAAC,CAAC;IAC9B,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,iBAAiB,CAAC,CAAC;IAC7D,cAAc,EAAE,MAAM,CAAC;CACxB"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/platform/index.ts"],"names":[],"mappings":"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"}
@@ -105,6 +105,24 @@ export const videoCompletionSchema = createSchema({
105
105
  return true;
106
106
  },
107
107
  });
108
+ export const modelCompletionSchema = createSchema({
109
+ modelId: field
110
+ .string()
111
+ .description("Identifier for the generated model")
112
+ .version("1.0"),
113
+ artifactUrl: field
114
+ .string()
115
+ .description("Optional URL to a generated model artifact")
116
+ .version("1.0")
117
+ .optional()
118
+ .as(),
119
+ }, "modelCompletion", {
120
+ version: "1.0",
121
+ table: "completions",
122
+ schemaValidator: () => {
123
+ return true;
124
+ },
125
+ });
108
126
  export const balanceCompletionSchema = createSchema({
109
127
  balance: field.number().description("Current balance").version("1.0"),
110
128
  }, "balanceCompletion", {
@@ -122,4 +140,10 @@ export var AICapability;
122
140
  AICapability[AICapability["Image"] = 3] = "Image";
123
141
  AICapability[AICapability["Video"] = 4] = "Video";
124
142
  AICapability[AICapability["Balance"] = 5] = "Balance";
143
+ AICapability[AICapability["Model"] = 6] = "Model";
125
144
  })(AICapability || (AICapability = {}));
145
+ export { createHttpVideoProviderAdapter } from "./video-provider-adapter.js";
146
+ export { createAdapterPlatform } from "./adapter-platform.js";
147
+ export { createVideoProviderPlatform } from "./video-provider-platform.js";
148
+ export { createOpenAIAdapter } from "./openai-adapter.js";
149
+ export { createGeminiAdapter } from "./gemini-adapter.js";
@@ -0,0 +1,24 @@
1
+ import { type AICapabilityAdapter } from "./index.js";
2
+ import { type HttpClientPolicy } from "./http-resilience.js";
3
+ export interface OpenAIAdapterOptions {
4
+ id?: string;
5
+ baseUrl?: string;
6
+ fetchFn?: typeof fetch;
7
+ httpPolicy?: HttpClientPolicy;
8
+ defaultModels?: {
9
+ chat?: string;
10
+ speech?: string;
11
+ transcription?: string;
12
+ image?: string;
13
+ model?: string;
14
+ };
15
+ speech?: {
16
+ voice?: string;
17
+ format?: "mp3" | "wav" | "opus" | "aac" | "flac" | "pcm";
18
+ };
19
+ image?: {
20
+ size?: string;
21
+ };
22
+ }
23
+ export declare function createOpenAIAdapter(options?: OpenAIAdapterOptions): AICapabilityAdapter;
24
+ //# sourceMappingURL=openai-adapter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"openai-adapter.d.ts","sourceRoot":"","sources":["../../src/platform/openai-adapter.ts"],"names":[],"mappings":"AAEA,OAAO,EAEL,KAAK,mBAAmB,EAczB,MAAM,YAAY,CAAC;AACpB,OAAO,EAAmB,KAAK,gBAAgB,EAAE,MAAM,sBAAsB,CAAC;AAU9E,MAAM,WAAW,oBAAoB;IACnC,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,OAAO,CAAC,EAAE,OAAO,KAAK,CAAC;IACvB,UAAU,CAAC,EAAE,gBAAgB,CAAC;IAC9B,aAAa,CAAC,EAAE;QACd,IAAI,CAAC,EAAE,MAAM,CAAC;QACd,MAAM,CAAC,EAAE,MAAM,CAAC;QAChB,aAAa,CAAC,EAAE,MAAM,CAAC;QACvB,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,MAAM,CAAC;KAChB,CAAC;IACF,MAAM,CAAC,EAAE;QACP,KAAK,CAAC,EAAE,MAAM,CAAC;QACf,MAAM,CAAC,EAAE,KAAK,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,MAAM,GAAG,KAAK,CAAC;KAC1D,CAAC;IACF,KAAK,CAAC,EAAE;QACN,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;CACH;AA0LD,wBAAgB,mBAAmB,CACjC,OAAO,GAAE,oBAAyB,GACjC,mBAAmB,CA2TrB"}