whale-code 6.4.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/README.md +95 -0
- package/bin/swag-agent.js +9 -0
- package/bin/swagmanager-mcp.js +321 -0
- package/dist/cli/app.d.ts +26 -0
- package/dist/cli/app.js +64 -0
- package/dist/cli/chat/AgentSelector.d.ts +14 -0
- package/dist/cli/chat/AgentSelector.js +14 -0
- package/dist/cli/chat/ChatApp.d.ts +9 -0
- package/dist/cli/chat/ChatApp.js +267 -0
- package/dist/cli/chat/ChatInput.d.ts +39 -0
- package/dist/cli/chat/ChatInput.js +509 -0
- package/dist/cli/chat/MarkdownText.d.ts +10 -0
- package/dist/cli/chat/MarkdownText.js +20 -0
- package/dist/cli/chat/MessageList.d.ts +37 -0
- package/dist/cli/chat/MessageList.js +80 -0
- package/dist/cli/chat/ModelSelector.d.ts +20 -0
- package/dist/cli/chat/ModelSelector.js +73 -0
- package/dist/cli/chat/RewindViewer.d.ts +26 -0
- package/dist/cli/chat/RewindViewer.js +185 -0
- package/dist/cli/chat/StoreSelector.d.ts +14 -0
- package/dist/cli/chat/StoreSelector.js +24 -0
- package/dist/cli/chat/StreamingText.d.ts +12 -0
- package/dist/cli/chat/StreamingText.js +12 -0
- package/dist/cli/chat/SubagentPanel.d.ts +45 -0
- package/dist/cli/chat/SubagentPanel.js +110 -0
- package/dist/cli/chat/TeamPanel.d.ts +21 -0
- package/dist/cli/chat/TeamPanel.js +42 -0
- package/dist/cli/chat/ToolIndicator.d.ts +25 -0
- package/dist/cli/chat/ToolIndicator.js +436 -0
- package/dist/cli/chat/hooks/useAgentLoop.d.ts +39 -0
- package/dist/cli/chat/hooks/useAgentLoop.js +382 -0
- package/dist/cli/chat/hooks/useSlashCommands.d.ts +37 -0
- package/dist/cli/chat/hooks/useSlashCommands.js +387 -0
- package/dist/cli/commands/config-cmd.d.ts +10 -0
- package/dist/cli/commands/config-cmd.js +99 -0
- package/dist/cli/commands/doctor.d.ts +14 -0
- package/dist/cli/commands/doctor.js +172 -0
- package/dist/cli/commands/init.d.ts +16 -0
- package/dist/cli/commands/init.js +278 -0
- package/dist/cli/commands/mcp.d.ts +12 -0
- package/dist/cli/commands/mcp.js +162 -0
- package/dist/cli/login/LoginApp.d.ts +7 -0
- package/dist/cli/login/LoginApp.js +157 -0
- package/dist/cli/print-mode.d.ts +31 -0
- package/dist/cli/print-mode.js +202 -0
- package/dist/cli/serve-mode.d.ts +37 -0
- package/dist/cli/serve-mode.js +636 -0
- package/dist/cli/services/agent-definitions.d.ts +25 -0
- package/dist/cli/services/agent-definitions.js +91 -0
- package/dist/cli/services/agent-events.d.ts +178 -0
- package/dist/cli/services/agent-events.js +175 -0
- package/dist/cli/services/agent-loop.d.ts +90 -0
- package/dist/cli/services/agent-loop.js +762 -0
- package/dist/cli/services/agent-worker-base.d.ts +97 -0
- package/dist/cli/services/agent-worker-base.js +220 -0
- package/dist/cli/services/auth-service.d.ts +30 -0
- package/dist/cli/services/auth-service.js +160 -0
- package/dist/cli/services/background-processes.d.ts +126 -0
- package/dist/cli/services/background-processes.js +318 -0
- package/dist/cli/services/browser-auth.d.ts +24 -0
- package/dist/cli/services/browser-auth.js +180 -0
- package/dist/cli/services/claude-md-loader.d.ts +16 -0
- package/dist/cli/services/claude-md-loader.js +58 -0
- package/dist/cli/services/config-store.d.ts +47 -0
- package/dist/cli/services/config-store.js +79 -0
- package/dist/cli/services/debug-log.d.ts +10 -0
- package/dist/cli/services/debug-log.js +52 -0
- package/dist/cli/services/error-logger.d.ts +58 -0
- package/dist/cli/services/error-logger.js +269 -0
- package/dist/cli/services/file-history.d.ts +21 -0
- package/dist/cli/services/file-history.js +83 -0
- package/dist/cli/services/format-server-response.d.ts +16 -0
- package/dist/cli/services/format-server-response.js +440 -0
- package/dist/cli/services/git-context.d.ts +11 -0
- package/dist/cli/services/git-context.js +66 -0
- package/dist/cli/services/hooks.d.ts +85 -0
- package/dist/cli/services/hooks.js +258 -0
- package/dist/cli/services/interactive-tools.d.ts +125 -0
- package/dist/cli/services/interactive-tools.js +260 -0
- package/dist/cli/services/keybinding-manager.d.ts +52 -0
- package/dist/cli/services/keybinding-manager.js +115 -0
- package/dist/cli/services/local-tools.d.ts +22 -0
- package/dist/cli/services/local-tools.js +697 -0
- package/dist/cli/services/lsp-manager.d.ts +18 -0
- package/dist/cli/services/lsp-manager.js +717 -0
- package/dist/cli/services/mcp-client.d.ts +48 -0
- package/dist/cli/services/mcp-client.js +157 -0
- package/dist/cli/services/memory-manager.d.ts +16 -0
- package/dist/cli/services/memory-manager.js +57 -0
- package/dist/cli/services/model-manager.d.ts +18 -0
- package/dist/cli/services/model-manager.js +71 -0
- package/dist/cli/services/model-router.d.ts +26 -0
- package/dist/cli/services/model-router.js +149 -0
- package/dist/cli/services/permission-modes.d.ts +13 -0
- package/dist/cli/services/permission-modes.js +43 -0
- package/dist/cli/services/rewind.d.ts +84 -0
- package/dist/cli/services/rewind.js +194 -0
- package/dist/cli/services/ripgrep.d.ts +28 -0
- package/dist/cli/services/ripgrep.js +138 -0
- package/dist/cli/services/sandbox.d.ts +29 -0
- package/dist/cli/services/sandbox.js +97 -0
- package/dist/cli/services/server-tools.d.ts +61 -0
- package/dist/cli/services/server-tools.js +543 -0
- package/dist/cli/services/session-persistence.d.ts +23 -0
- package/dist/cli/services/session-persistence.js +99 -0
- package/dist/cli/services/subagent-worker.d.ts +19 -0
- package/dist/cli/services/subagent-worker.js +41 -0
- package/dist/cli/services/subagent.d.ts +47 -0
- package/dist/cli/services/subagent.js +647 -0
- package/dist/cli/services/system-prompt.d.ts +7 -0
- package/dist/cli/services/system-prompt.js +198 -0
- package/dist/cli/services/team-lead.d.ts +73 -0
- package/dist/cli/services/team-lead.js +512 -0
- package/dist/cli/services/team-state.d.ts +77 -0
- package/dist/cli/services/team-state.js +398 -0
- package/dist/cli/services/teammate.d.ts +31 -0
- package/dist/cli/services/teammate.js +689 -0
- package/dist/cli/services/telemetry.d.ts +61 -0
- package/dist/cli/services/telemetry.js +209 -0
- package/dist/cli/services/tools/agent-tools.d.ts +14 -0
- package/dist/cli/services/tools/agent-tools.js +347 -0
- package/dist/cli/services/tools/file-ops.d.ts +15 -0
- package/dist/cli/services/tools/file-ops.js +487 -0
- package/dist/cli/services/tools/search-tools.d.ts +8 -0
- package/dist/cli/services/tools/search-tools.js +186 -0
- package/dist/cli/services/tools/shell-exec.d.ts +10 -0
- package/dist/cli/services/tools/shell-exec.js +168 -0
- package/dist/cli/services/tools/task-manager.d.ts +28 -0
- package/dist/cli/services/tools/task-manager.js +209 -0
- package/dist/cli/services/tools/web-tools.d.ts +11 -0
- package/dist/cli/services/tools/web-tools.js +395 -0
- package/dist/cli/setup/SetupApp.d.ts +9 -0
- package/dist/cli/setup/SetupApp.js +191 -0
- package/dist/cli/shared/MatrixIntro.d.ts +4 -0
- package/dist/cli/shared/MatrixIntro.js +83 -0
- package/dist/cli/shared/Theme.d.ts +74 -0
- package/dist/cli/shared/Theme.js +127 -0
- package/dist/cli/shared/WhaleBanner.d.ts +10 -0
- package/dist/cli/shared/WhaleBanner.js +12 -0
- package/dist/cli/shared/markdown.d.ts +21 -0
- package/dist/cli/shared/markdown.js +756 -0
- package/dist/cli/status/StatusApp.d.ts +4 -0
- package/dist/cli/status/StatusApp.js +105 -0
- package/dist/cli/stores/StoreApp.d.ts +7 -0
- package/dist/cli/stores/StoreApp.js +81 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +538 -0
- package/dist/local-agent/connection.d.ts +48 -0
- package/dist/local-agent/connection.js +332 -0
- package/dist/local-agent/discovery.d.ts +18 -0
- package/dist/local-agent/discovery.js +146 -0
- package/dist/local-agent/executor.d.ts +34 -0
- package/dist/local-agent/executor.js +241 -0
- package/dist/local-agent/index.d.ts +14 -0
- package/dist/local-agent/index.js +198 -0
- package/dist/node/adapters/base.d.ts +35 -0
- package/dist/node/adapters/base.js +10 -0
- package/dist/node/adapters/discord.d.ts +29 -0
- package/dist/node/adapters/discord.js +299 -0
- package/dist/node/adapters/email.d.ts +23 -0
- package/dist/node/adapters/email.js +218 -0
- package/dist/node/adapters/imessage.d.ts +17 -0
- package/dist/node/adapters/imessage.js +118 -0
- package/dist/node/adapters/slack.d.ts +26 -0
- package/dist/node/adapters/slack.js +259 -0
- package/dist/node/adapters/sms.d.ts +23 -0
- package/dist/node/adapters/sms.js +161 -0
- package/dist/node/adapters/telegram.d.ts +17 -0
- package/dist/node/adapters/telegram.js +101 -0
- package/dist/node/adapters/webchat.d.ts +27 -0
- package/dist/node/adapters/webchat.js +160 -0
- package/dist/node/adapters/whatsapp.d.ts +28 -0
- package/dist/node/adapters/whatsapp.js +230 -0
- package/dist/node/cli.d.ts +2 -0
- package/dist/node/cli.js +325 -0
- package/dist/node/config.d.ts +17 -0
- package/dist/node/config.js +31 -0
- package/dist/node/runtime.d.ts +50 -0
- package/dist/node/runtime.js +351 -0
- package/dist/server/handlers/__test-utils__/mock-supabase.d.ts +11 -0
- package/dist/server/handlers/__test-utils__/mock-supabase.js +393 -0
- package/dist/server/handlers/analytics.d.ts +17 -0
- package/dist/server/handlers/analytics.js +266 -0
- package/dist/server/handlers/api-keys.d.ts +6 -0
- package/dist/server/handlers/api-keys.js +221 -0
- package/dist/server/handlers/billing.d.ts +33 -0
- package/dist/server/handlers/billing.js +272 -0
- package/dist/server/handlers/browser.d.ts +10 -0
- package/dist/server/handlers/browser.js +517 -0
- package/dist/server/handlers/catalog.d.ts +99 -0
- package/dist/server/handlers/catalog.js +976 -0
- package/dist/server/handlers/comms.d.ts +254 -0
- package/dist/server/handlers/comms.js +588 -0
- package/dist/server/handlers/creations.d.ts +6 -0
- package/dist/server/handlers/creations.js +479 -0
- package/dist/server/handlers/crm.d.ts +89 -0
- package/dist/server/handlers/crm.js +538 -0
- package/dist/server/handlers/discovery.d.ts +6 -0
- package/dist/server/handlers/discovery.js +288 -0
- package/dist/server/handlers/embeddings.d.ts +92 -0
- package/dist/server/handlers/embeddings.js +197 -0
- package/dist/server/handlers/enrichment.d.ts +8 -0
- package/dist/server/handlers/enrichment.js +768 -0
- package/dist/server/handlers/image-gen.d.ts +6 -0
- package/dist/server/handlers/image-gen.js +409 -0
- package/dist/server/handlers/inventory.d.ts +319 -0
- package/dist/server/handlers/inventory.js +447 -0
- package/dist/server/handlers/kali.d.ts +10 -0
- package/dist/server/handlers/kali.js +210 -0
- package/dist/server/handlers/llm-providers.d.ts +6 -0
- package/dist/server/handlers/llm-providers.js +673 -0
- package/dist/server/handlers/local-agent.d.ts +6 -0
- package/dist/server/handlers/local-agent.js +118 -0
- package/dist/server/handlers/meta-ads.d.ts +111 -0
- package/dist/server/handlers/meta-ads.js +2279 -0
- package/dist/server/handlers/nodes.d.ts +33 -0
- package/dist/server/handlers/nodes.js +699 -0
- package/dist/server/handlers/operations.d.ts +138 -0
- package/dist/server/handlers/operations.js +131 -0
- package/dist/server/handlers/platform.d.ts +23 -0
- package/dist/server/handlers/platform.js +227 -0
- package/dist/server/handlers/supply-chain.d.ts +19 -0
- package/dist/server/handlers/supply-chain.js +327 -0
- package/dist/server/handlers/transcription.d.ts +17 -0
- package/dist/server/handlers/transcription.js +121 -0
- package/dist/server/handlers/video-gen.d.ts +6 -0
- package/dist/server/handlers/video-gen.js +466 -0
- package/dist/server/handlers/voice.d.ts +8 -0
- package/dist/server/handlers/voice.js +1146 -0
- package/dist/server/handlers/workflow-steps.d.ts +86 -0
- package/dist/server/handlers/workflow-steps.js +2349 -0
- package/dist/server/handlers/workflows.d.ts +7 -0
- package/dist/server/handlers/workflows.js +989 -0
- package/dist/server/index.d.ts +1 -0
- package/dist/server/index.js +2427 -0
- package/dist/server/lib/batch-client.d.ts +80 -0
- package/dist/server/lib/batch-client.js +467 -0
- package/dist/server/lib/code-worker-pool.d.ts +31 -0
- package/dist/server/lib/code-worker-pool.js +224 -0
- package/dist/server/lib/code-worker.d.ts +1 -0
- package/dist/server/lib/code-worker.js +188 -0
- package/dist/server/lib/compaction-service.d.ts +32 -0
- package/dist/server/lib/compaction-service.js +162 -0
- package/dist/server/lib/logger.d.ts +19 -0
- package/dist/server/lib/logger.js +46 -0
- package/dist/server/lib/otel.d.ts +38 -0
- package/dist/server/lib/otel.js +126 -0
- package/dist/server/lib/pg-rate-limiter.d.ts +21 -0
- package/dist/server/lib/pg-rate-limiter.js +86 -0
- package/dist/server/lib/prompt-sanitizer.d.ts +37 -0
- package/dist/server/lib/prompt-sanitizer.js +177 -0
- package/dist/server/lib/provider-capabilities.d.ts +85 -0
- package/dist/server/lib/provider-capabilities.js +190 -0
- package/dist/server/lib/provider-failover.d.ts +74 -0
- package/dist/server/lib/provider-failover.js +210 -0
- package/dist/server/lib/rate-limiter.d.ts +39 -0
- package/dist/server/lib/rate-limiter.js +147 -0
- package/dist/server/lib/server-agent-loop.d.ts +107 -0
- package/dist/server/lib/server-agent-loop.js +667 -0
- package/dist/server/lib/server-subagent.d.ts +78 -0
- package/dist/server/lib/server-subagent.js +203 -0
- package/dist/server/lib/session-checkpoint.d.ts +51 -0
- package/dist/server/lib/session-checkpoint.js +145 -0
- package/dist/server/lib/ssrf-guard.d.ts +13 -0
- package/dist/server/lib/ssrf-guard.js +240 -0
- package/dist/server/lib/supabase-client.d.ts +7 -0
- package/dist/server/lib/supabase-client.js +78 -0
- package/dist/server/lib/template-resolver.d.ts +31 -0
- package/dist/server/lib/template-resolver.js +215 -0
- package/dist/server/lib/utils.d.ts +16 -0
- package/dist/server/lib/utils.js +147 -0
- package/dist/server/local-agent-gateway.d.ts +82 -0
- package/dist/server/local-agent-gateway.js +426 -0
- package/dist/server/providers/anthropic.d.ts +20 -0
- package/dist/server/providers/anthropic.js +199 -0
- package/dist/server/providers/bedrock.d.ts +20 -0
- package/dist/server/providers/bedrock.js +194 -0
- package/dist/server/providers/gemini.d.ts +24 -0
- package/dist/server/providers/gemini.js +486 -0
- package/dist/server/providers/openai.d.ts +24 -0
- package/dist/server/providers/openai.js +522 -0
- package/dist/server/providers/registry.d.ts +32 -0
- package/dist/server/providers/registry.js +58 -0
- package/dist/server/providers/shared.d.ts +32 -0
- package/dist/server/providers/shared.js +124 -0
- package/dist/server/providers/types.d.ts +92 -0
- package/dist/server/providers/types.js +12 -0
- package/dist/server/proxy-handlers.d.ts +6 -0
- package/dist/server/proxy-handlers.js +89 -0
- package/dist/server/tool-router.d.ts +149 -0
- package/dist/server/tool-router.js +803 -0
- package/dist/server/validation.d.ts +24 -0
- package/dist/server/validation.js +301 -0
- package/dist/server/worker.d.ts +19 -0
- package/dist/server/worker.js +201 -0
- package/dist/setup.d.ts +8 -0
- package/dist/setup.js +181 -0
- package/dist/shared/agent-core.d.ts +157 -0
- package/dist/shared/agent-core.js +534 -0
- package/dist/shared/anthropic-types.d.ts +105 -0
- package/dist/shared/anthropic-types.js +7 -0
- package/dist/shared/api-client.d.ts +90 -0
- package/dist/shared/api-client.js +379 -0
- package/dist/shared/constants.d.ts +33 -0
- package/dist/shared/constants.js +80 -0
- package/dist/shared/sse-parser.d.ts +26 -0
- package/dist/shared/sse-parser.js +259 -0
- package/dist/shared/tool-dispatch.d.ts +52 -0
- package/dist/shared/tool-dispatch.js +191 -0
- package/dist/shared/types.d.ts +72 -0
- package/dist/shared/types.js +7 -0
- package/dist/updater.d.ts +25 -0
- package/dist/updater.js +140 -0
- package/dist/webchat/widget.d.ts +0 -0
- package/dist/webchat/widget.js +397 -0
- package/package.json +95 -0
- package/src/cli/services/builtin-skills/commit.md +19 -0
- package/src/cli/services/builtin-skills/review-pr.md +21 -0
- package/src/cli/services/builtin-skills/review.md +18 -0
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
// server/handlers/image-gen.ts — Multi-provider image generation with batch/parallel support
|
|
2
|
+
// Providers: OpenAI (DALL-E 3), Google (Imagen 3), Gemini (native image generation)
|
|
3
|
+
// Auto-uploads to Supabase storage and inserts into store_media table
|
|
4
|
+
import OpenAI from "openai";
|
|
5
|
+
import { GoogleGenAI } from "@google/genai";
|
|
6
|
+
async function getImageCredentials(sb, storeId) {
|
|
7
|
+
const creds = {};
|
|
8
|
+
const keys = ["OPENAI_API_KEY", "GOOGLE_AI_API_KEY"];
|
|
9
|
+
const results = await Promise.all(keys.map(async (k) => {
|
|
10
|
+
try {
|
|
11
|
+
const r = await sb.rpc("decrypt_secret", { p_name: k, p_store_id: storeId });
|
|
12
|
+
return r.data;
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
}));
|
|
18
|
+
if (results[0])
|
|
19
|
+
creds.openai = results[0];
|
|
20
|
+
if (results[1])
|
|
21
|
+
creds.google = results[1];
|
|
22
|
+
return creds;
|
|
23
|
+
}
|
|
24
|
+
// ============================================================================
|
|
25
|
+
// PROVIDER IMPLEMENTATIONS
|
|
26
|
+
// ============================================================================
|
|
27
|
+
async function generateWithDalle(apiKey, prompt, size, quality, style) {
|
|
28
|
+
const client = new OpenAI({ apiKey });
|
|
29
|
+
const validSizes = ["1024x1024", "1024x1792", "1792x1024"];
|
|
30
|
+
const selectedSize = validSizes.includes(size) ? size : "1024x1024";
|
|
31
|
+
const resp = await client.images.generate({
|
|
32
|
+
model: "dall-e-3",
|
|
33
|
+
prompt,
|
|
34
|
+
n: 1,
|
|
35
|
+
size: selectedSize,
|
|
36
|
+
quality: quality === "hd" ? "hd" : "standard",
|
|
37
|
+
style: style === "natural" ? "natural" : "vivid",
|
|
38
|
+
response_format: "b64_json",
|
|
39
|
+
});
|
|
40
|
+
const first = resp.data?.[0];
|
|
41
|
+
if (!first?.b64_json)
|
|
42
|
+
throw new Error("DALL-E returned no image data");
|
|
43
|
+
return {
|
|
44
|
+
base64: first.b64_json,
|
|
45
|
+
revisedPrompt: first.revised_prompt || prompt,
|
|
46
|
+
};
|
|
47
|
+
}
|
|
48
|
+
async function generateWithImagen(apiKey, prompt, aspectRatio) {
|
|
49
|
+
const client = new GoogleGenAI({ apiKey });
|
|
50
|
+
const validRatios = ["1:1", "3:4", "4:3", "9:16", "16:9"];
|
|
51
|
+
const selectedRatio = validRatios.includes(aspectRatio) ? aspectRatio : "1:1";
|
|
52
|
+
const response = await client.models.generateImages({
|
|
53
|
+
model: "imagen-4.0-generate-001",
|
|
54
|
+
prompt,
|
|
55
|
+
config: {
|
|
56
|
+
numberOfImages: 1,
|
|
57
|
+
aspectRatio: selectedRatio,
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
const image = response.generatedImages?.[0];
|
|
61
|
+
if (!image?.image?.imageBytes) {
|
|
62
|
+
throw new Error("Imagen returned no image data");
|
|
63
|
+
}
|
|
64
|
+
return { base64: image.image.imageBytes };
|
|
65
|
+
}
|
|
66
|
+
async function generateWithGemini(apiKey, prompt, model = "gemini-2.5-flash-image") {
|
|
67
|
+
const client = new GoogleGenAI({ apiKey });
|
|
68
|
+
const response = await client.models.generateContent({
|
|
69
|
+
model,
|
|
70
|
+
contents: prompt,
|
|
71
|
+
config: {
|
|
72
|
+
responseModalities: ["TEXT", "IMAGE"],
|
|
73
|
+
},
|
|
74
|
+
});
|
|
75
|
+
// Find image part in response
|
|
76
|
+
const parts = response.candidates?.[0]?.content?.parts;
|
|
77
|
+
if (!parts)
|
|
78
|
+
throw new Error("Gemini returned no content parts");
|
|
79
|
+
for (const part of parts) {
|
|
80
|
+
if (part.inlineData?.data) {
|
|
81
|
+
return {
|
|
82
|
+
base64: part.inlineData.data,
|
|
83
|
+
mimeType: part.inlineData.mimeType || "image/png",
|
|
84
|
+
};
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
throw new Error("Gemini response contained no image data");
|
|
88
|
+
}
|
|
89
|
+
// ============================================================================
|
|
90
|
+
// STORAGE + MEDIA HELPERS
|
|
91
|
+
// ============================================================================
|
|
92
|
+
async function uploadAndRecord(sb, storeId, base64Data, prompt, provider, model, mimeType = "image/png") {
|
|
93
|
+
const id = crypto.randomUUID();
|
|
94
|
+
const ext = mimeType.includes("jpeg") || mimeType.includes("jpg") ? "jpg" : "png";
|
|
95
|
+
const fileName = `${id}.${ext}`;
|
|
96
|
+
const storeIdUpper = storeId.toUpperCase();
|
|
97
|
+
const storagePath = `ai-generated/${storeIdUpper}/standalone/${fileName}`;
|
|
98
|
+
// Decode base64 to buffer
|
|
99
|
+
const buffer = Buffer.from(base64Data, "base64");
|
|
100
|
+
// Upload to Supabase storage
|
|
101
|
+
const { error: uploadErr } = await sb.storage
|
|
102
|
+
.from("product-images")
|
|
103
|
+
.upload(storagePath, buffer, {
|
|
104
|
+
contentType: mimeType,
|
|
105
|
+
upsert: true,
|
|
106
|
+
});
|
|
107
|
+
if (uploadErr) {
|
|
108
|
+
throw new Error(`Storage upload failed: ${uploadErr.message}`);
|
|
109
|
+
}
|
|
110
|
+
// Get public URL
|
|
111
|
+
const { data: urlData } = sb.storage.from("product-images").getPublicUrl(storagePath);
|
|
112
|
+
const fileUrl = urlData.publicUrl;
|
|
113
|
+
// Determine AI tags based on provider
|
|
114
|
+
const aiTags = [
|
|
115
|
+
provider === "openai" ? "DALL-E 3" : provider === "imagen" ? "Imagen 3" : "Gemini",
|
|
116
|
+
"AI Generated",
|
|
117
|
+
];
|
|
118
|
+
// Insert into store_media
|
|
119
|
+
const { data: mediaRow, error: mediaErr } = await sb
|
|
120
|
+
.from("store_media")
|
|
121
|
+
.insert({
|
|
122
|
+
store_id: storeId,
|
|
123
|
+
file_name: fileName,
|
|
124
|
+
file_path: storagePath,
|
|
125
|
+
file_url: fileUrl,
|
|
126
|
+
file_size: buffer.length,
|
|
127
|
+
file_type: mimeType,
|
|
128
|
+
category: "ai_generated",
|
|
129
|
+
ai_tags: aiTags,
|
|
130
|
+
ai_description: prompt.substring(0, 500),
|
|
131
|
+
source: `mcp-${provider}`,
|
|
132
|
+
folder: "ai-generated",
|
|
133
|
+
})
|
|
134
|
+
.select("id")
|
|
135
|
+
.single();
|
|
136
|
+
if (mediaErr) {
|
|
137
|
+
console.error("[image-gen] store_media insert error:", mediaErr.message);
|
|
138
|
+
}
|
|
139
|
+
return {
|
|
140
|
+
id,
|
|
141
|
+
provider,
|
|
142
|
+
model,
|
|
143
|
+
prompt,
|
|
144
|
+
file_url: fileUrl,
|
|
145
|
+
file_name: fileName,
|
|
146
|
+
file_size: buffer.length,
|
|
147
|
+
media_id: mediaRow?.id || id,
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
// ============================================================================
|
|
151
|
+
// HANDLER
|
|
152
|
+
// ============================================================================
|
|
153
|
+
export async function handleImageGen(sb, args, storeId) {
|
|
154
|
+
const action = args.action;
|
|
155
|
+
if (!storeId) {
|
|
156
|
+
return { success: false, error: "store_id is required" };
|
|
157
|
+
}
|
|
158
|
+
switch (action) {
|
|
159
|
+
// ================================================================
|
|
160
|
+
// GENERATE — single image generation
|
|
161
|
+
// ================================================================
|
|
162
|
+
case "generate": {
|
|
163
|
+
const prompt = args.prompt;
|
|
164
|
+
if (!prompt)
|
|
165
|
+
return { success: false, error: "prompt is required" };
|
|
166
|
+
const provider = args.provider || "openai";
|
|
167
|
+
const size = args.size || "1024x1024";
|
|
168
|
+
const quality = args.quality || "standard";
|
|
169
|
+
const style = args.style || "vivid";
|
|
170
|
+
const aspectRatio = args.aspect_ratio || "1:1";
|
|
171
|
+
const creds = await getImageCredentials(sb, storeId);
|
|
172
|
+
try {
|
|
173
|
+
let base64;
|
|
174
|
+
let model;
|
|
175
|
+
let mimeType = "image/png";
|
|
176
|
+
switch (provider) {
|
|
177
|
+
case "openai": {
|
|
178
|
+
if (!creds.openai)
|
|
179
|
+
return { success: false, error: "OpenAI API key not configured" };
|
|
180
|
+
const result = await generateWithDalle(creds.openai, prompt, size, quality, style);
|
|
181
|
+
base64 = result.base64;
|
|
182
|
+
model = "dall-e-3";
|
|
183
|
+
break;
|
|
184
|
+
}
|
|
185
|
+
case "imagen": {
|
|
186
|
+
if (!creds.google)
|
|
187
|
+
return { success: false, error: "Google AI API key not configured" };
|
|
188
|
+
const result = await generateWithImagen(creds.google, prompt, aspectRatio);
|
|
189
|
+
base64 = result.base64;
|
|
190
|
+
model = "imagen-4.0-generate-001";
|
|
191
|
+
break;
|
|
192
|
+
}
|
|
193
|
+
case "gemini": {
|
|
194
|
+
if (!creds.google)
|
|
195
|
+
return { success: false, error: "Google AI API key not configured" };
|
|
196
|
+
const result = await generateWithGemini(creds.google, prompt);
|
|
197
|
+
base64 = result.base64;
|
|
198
|
+
model = "gemini-2.5-flash-image";
|
|
199
|
+
mimeType = result.mimeType;
|
|
200
|
+
break;
|
|
201
|
+
}
|
|
202
|
+
case "gemini3": {
|
|
203
|
+
if (!creds.google)
|
|
204
|
+
return { success: false, error: "Google AI API key not configured" };
|
|
205
|
+
const result = await generateWithGemini(creds.google, prompt, "gemini-3-pro-image-preview");
|
|
206
|
+
base64 = result.base64;
|
|
207
|
+
model = "gemini-3-pro-image-preview";
|
|
208
|
+
mimeType = result.mimeType;
|
|
209
|
+
break;
|
|
210
|
+
}
|
|
211
|
+
default:
|
|
212
|
+
return { success: false, error: `Unknown provider: ${provider}. Use openai, imagen, gemini, or gemini3` };
|
|
213
|
+
}
|
|
214
|
+
const image = await uploadAndRecord(sb, storeId, base64, prompt, provider, model, mimeType);
|
|
215
|
+
return { success: true, data: image };
|
|
216
|
+
}
|
|
217
|
+
catch (err) {
|
|
218
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
219
|
+
return { success: false, error: `Image generation failed: ${msg}` };
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
// ================================================================
|
|
223
|
+
// BATCH — parallel batch generation (multiple prompts and/or providers)
|
|
224
|
+
// ================================================================
|
|
225
|
+
case "batch": {
|
|
226
|
+
const items = args.items;
|
|
227
|
+
if (!items || !Array.isArray(items) || items.length === 0) {
|
|
228
|
+
return { success: false, error: "items array is required with at least one {prompt} entry" };
|
|
229
|
+
}
|
|
230
|
+
if (items.length > 10) {
|
|
231
|
+
return { success: false, error: "Maximum 10 images per batch" };
|
|
232
|
+
}
|
|
233
|
+
const creds = await getImageCredentials(sb, storeId);
|
|
234
|
+
// Run all generations in parallel
|
|
235
|
+
const results = await Promise.allSettled(items.map(async (item) => {
|
|
236
|
+
const provider = item.provider || "openai";
|
|
237
|
+
const size = item.size || "1024x1024";
|
|
238
|
+
const quality = item.quality || "standard";
|
|
239
|
+
const style = item.style || "vivid";
|
|
240
|
+
const aspectRatio = item.aspect_ratio || "1:1";
|
|
241
|
+
let base64;
|
|
242
|
+
let model;
|
|
243
|
+
let mimeType = "image/png";
|
|
244
|
+
switch (provider) {
|
|
245
|
+
case "openai": {
|
|
246
|
+
if (!creds.openai)
|
|
247
|
+
throw new Error("OpenAI API key not configured");
|
|
248
|
+
const result = await generateWithDalle(creds.openai, item.prompt, size, quality, style);
|
|
249
|
+
base64 = result.base64;
|
|
250
|
+
model = "dall-e-3";
|
|
251
|
+
break;
|
|
252
|
+
}
|
|
253
|
+
case "imagen": {
|
|
254
|
+
if (!creds.google)
|
|
255
|
+
throw new Error("Google AI API key not configured");
|
|
256
|
+
const result = await generateWithImagen(creds.google, item.prompt, aspectRatio);
|
|
257
|
+
base64 = result.base64;
|
|
258
|
+
model = "imagen-4.0-generate-001";
|
|
259
|
+
break;
|
|
260
|
+
}
|
|
261
|
+
case "gemini": {
|
|
262
|
+
if (!creds.google)
|
|
263
|
+
throw new Error("Google AI API key not configured");
|
|
264
|
+
const result = await generateWithGemini(creds.google, item.prompt);
|
|
265
|
+
base64 = result.base64;
|
|
266
|
+
model = "gemini-2.5-flash-image";
|
|
267
|
+
mimeType = result.mimeType;
|
|
268
|
+
break;
|
|
269
|
+
}
|
|
270
|
+
case "gemini3": {
|
|
271
|
+
if (!creds.google)
|
|
272
|
+
throw new Error("Google AI API key not configured");
|
|
273
|
+
const result = await generateWithGemini(creds.google, item.prompt, "gemini-3-pro-image-preview");
|
|
274
|
+
base64 = result.base64;
|
|
275
|
+
model = "gemini-3-pro-image-preview";
|
|
276
|
+
mimeType = result.mimeType;
|
|
277
|
+
break;
|
|
278
|
+
}
|
|
279
|
+
default:
|
|
280
|
+
throw new Error(`Unknown provider: ${provider}`);
|
|
281
|
+
}
|
|
282
|
+
return uploadAndRecord(sb, storeId, base64, item.prompt, provider, model, mimeType);
|
|
283
|
+
}));
|
|
284
|
+
const images = [];
|
|
285
|
+
const errors = [];
|
|
286
|
+
results.forEach((r, i) => {
|
|
287
|
+
if (r.status === "fulfilled") {
|
|
288
|
+
images.push(r.value);
|
|
289
|
+
}
|
|
290
|
+
else {
|
|
291
|
+
errors.push({
|
|
292
|
+
index: i,
|
|
293
|
+
prompt: items[i].prompt,
|
|
294
|
+
error: r.reason instanceof Error ? r.reason.message : String(r.reason),
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
});
|
|
298
|
+
return {
|
|
299
|
+
success: true,
|
|
300
|
+
data: {
|
|
301
|
+
generated: images.length,
|
|
302
|
+
failed: errors.length,
|
|
303
|
+
total: items.length,
|
|
304
|
+
images,
|
|
305
|
+
...(errors.length > 0 ? { errors } : {}),
|
|
306
|
+
},
|
|
307
|
+
};
|
|
308
|
+
}
|
|
309
|
+
// ================================================================
|
|
310
|
+
// LIST — list generated images from store_media
|
|
311
|
+
// ================================================================
|
|
312
|
+
case "list": {
|
|
313
|
+
const limit = Math.min(args.limit || 25, 100);
|
|
314
|
+
const category = args.category || "ai_generated";
|
|
315
|
+
const folder = args.folder;
|
|
316
|
+
let query = sb
|
|
317
|
+
.from("store_media")
|
|
318
|
+
.select("id, file_name, file_url, file_size, file_type, category, ai_tags, ai_description, source, folder, created_at")
|
|
319
|
+
.eq("store_id", storeId)
|
|
320
|
+
.eq("status", "active")
|
|
321
|
+
.order("created_at", { ascending: false })
|
|
322
|
+
.limit(limit);
|
|
323
|
+
if (category !== "all") {
|
|
324
|
+
query = query.eq("category", category);
|
|
325
|
+
}
|
|
326
|
+
if (folder) {
|
|
327
|
+
query = query.eq("folder", folder);
|
|
328
|
+
}
|
|
329
|
+
const { data, error } = await query;
|
|
330
|
+
if (error)
|
|
331
|
+
return { success: false, error: error.message };
|
|
332
|
+
return { success: true, data: { images: data, count: data?.length || 0 } };
|
|
333
|
+
}
|
|
334
|
+
// ================================================================
|
|
335
|
+
// GET — get a specific image by media_id
|
|
336
|
+
// ================================================================
|
|
337
|
+
case "get": {
|
|
338
|
+
const mediaId = args.media_id;
|
|
339
|
+
if (!mediaId)
|
|
340
|
+
return { success: false, error: "media_id is required" };
|
|
341
|
+
const { data, error } = await sb
|
|
342
|
+
.from("store_media")
|
|
343
|
+
.select("*")
|
|
344
|
+
.eq("id", mediaId)
|
|
345
|
+
.eq("store_id", storeId)
|
|
346
|
+
.single();
|
|
347
|
+
if (error)
|
|
348
|
+
return { success: false, error: error.message };
|
|
349
|
+
return { success: true, data };
|
|
350
|
+
}
|
|
351
|
+
// ================================================================
|
|
352
|
+
// DELETE — soft-delete an image (set status to archived)
|
|
353
|
+
// ================================================================
|
|
354
|
+
case "delete": {
|
|
355
|
+
const mediaId = args.media_id;
|
|
356
|
+
if (!mediaId)
|
|
357
|
+
return { success: false, error: "media_id is required" };
|
|
358
|
+
const { error } = await sb
|
|
359
|
+
.from("store_media")
|
|
360
|
+
.update({ status: "archived", updated_at: new Date().toISOString() })
|
|
361
|
+
.eq("id", mediaId)
|
|
362
|
+
.eq("store_id", storeId);
|
|
363
|
+
if (error)
|
|
364
|
+
return { success: false, error: error.message };
|
|
365
|
+
return { success: true, data: { deleted: mediaId } };
|
|
366
|
+
}
|
|
367
|
+
// ================================================================
|
|
368
|
+
// PROVIDERS — list available image generation providers
|
|
369
|
+
// ================================================================
|
|
370
|
+
case "providers": {
|
|
371
|
+
const creds = await getImageCredentials(sb, storeId);
|
|
372
|
+
return {
|
|
373
|
+
success: true,
|
|
374
|
+
data: {
|
|
375
|
+
providers: [
|
|
376
|
+
{
|
|
377
|
+
provider: "openai",
|
|
378
|
+
model: "dall-e-3",
|
|
379
|
+
configured: !!creds.openai,
|
|
380
|
+
sizes: ["1024x1024", "1024x1792", "1792x1024"],
|
|
381
|
+
quality_options: ["standard", "hd"],
|
|
382
|
+
style_options: ["vivid", "natural"],
|
|
383
|
+
},
|
|
384
|
+
{
|
|
385
|
+
provider: "imagen",
|
|
386
|
+
model: "imagen-4.0-generate-001",
|
|
387
|
+
configured: !!creds.google,
|
|
388
|
+
aspect_ratios: ["1:1", "3:4", "4:3", "9:16", "16:9"],
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
provider: "gemini",
|
|
392
|
+
model: "gemini-2.5-flash-image",
|
|
393
|
+
configured: !!creds.google,
|
|
394
|
+
note: "Gemini 2.5 Flash native image generation (Nano Banana)",
|
|
395
|
+
},
|
|
396
|
+
{
|
|
397
|
+
provider: "gemini3",
|
|
398
|
+
model: "gemini-3-pro-image-preview",
|
|
399
|
+
configured: !!creds.google,
|
|
400
|
+
note: "Gemini 3 Pro image generation — highest quality Google model",
|
|
401
|
+
},
|
|
402
|
+
],
|
|
403
|
+
},
|
|
404
|
+
};
|
|
405
|
+
}
|
|
406
|
+
default:
|
|
407
|
+
return { success: false, error: `Unknown action: ${action}. Valid: generate, batch, list, get, delete, providers` };
|
|
408
|
+
}
|
|
409
|
+
}
|