@reaatech/media-pipeline-mcp-luma 0.3.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Media Pipeline MCP Contributors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,133 @@
1
+ # @reaatech/media-pipeline-mcp-luma
2
+
3
+ [![npm version](https://img.shields.io/npm/v/@reaatech/media-pipeline-mcp-luma.svg)](https://www.npmjs.com/package/@reaatech/media-pipeline-mcp-luma)
4
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](https://github.com/reaatech/media-pipeline-mcp/blob/main/LICENSE)
5
+ [![CI](https://img.shields.io/github/actions/workflow/status/reaatech/media-pipeline-mcp/ci.yml?branch=main&label=CI)](https://github.com/reaatech/media-pipeline-mcp/actions/workflows/ci.yml)
6
+
7
+ > **Status:** Pre-1.0 — APIs may change in minor versions. Pin to a specific version in production.
8
+
9
+ Luma AI provider for the media pipeline framework. Supports 3D model generation via Luma Genie using the Dream Machine API. Text-to-3D with GLB and USDZ output formats.
10
+
11
+ ## Installation
12
+
13
+ ```bash
14
+ npm install @reaatech/media-pipeline-mcp-luma
15
+ # or
16
+ pnpm add @reaatech/media-pipeline-mcp-luma
17
+ ```
18
+
19
+ ## Feature Overview
20
+
21
+ - **Text-to-3D** — generate 3D meshes from text descriptions via Luma Genie
22
+ - **GLB and USDZ output** — native support for both standard mesh formats
23
+ - **Poll-based completion** — automatic polling with configurable interval and timeout
24
+ - **Webhook support** — provider declares webhook capability for async completion
25
+ - **Cost estimation** — fixed per-generation cost reporting
26
+
27
+ ## Quick Start
28
+
29
+ ```typescript
30
+ import { LumaProvider } from "@reaatech/media-pipeline-mcp-luma";
31
+
32
+ const provider = new LumaProvider({
33
+ apiKey: process.env.LUMA_API_KEY!,
34
+ });
35
+
36
+ const result = await provider.execute({
37
+ operation: "mesh.generate",
38
+ params: {
39
+ prompt: "A low-poly cartoon dragon with wings spread",
40
+ format: "glb",
41
+ },
42
+ config: {},
43
+ });
44
+
45
+ console.log(result.metadata.format); // "glb"
46
+ console.log(result.metadata.taskId); // "gen_abc123..."
47
+ console.log(result.costUsd); // 0.30
48
+ ```
49
+
50
+ Requesting USDZ format:
51
+
52
+ ```typescript
53
+ const result = await provider.execute({
54
+ operation: "mesh.generate",
55
+ params: {
56
+ prompt: "A modern chair with wooden legs and fabric cushion",
57
+ format: "usdz",
58
+ },
59
+ config: {},
60
+ });
61
+ ```
62
+
63
+ ## Supported Operations
64
+
65
+ | Operation | API Endpoint | Description |
66
+ |-----------|-------------|-------------|
67
+ | `mesh.generate` | `/dream-machine/v1/generations` | Text-to-3D mesh generation via Luma Genie |
68
+
69
+ ## Configuration
70
+
71
+ ```typescript
72
+ interface LumaConfig {
73
+ apiKey: string; // Required — Luma API key (or set LUMA_API_KEY env var)
74
+ baseUrl?: string; // Default: "https://api.lumalabs.ai"
75
+ pollIntervalMs?: number; // Default: 5000
76
+ maxWaitMs?: number; // Default: 900000 (15 min)
77
+ }
78
+ ```
79
+
80
+ ## API Reference
81
+
82
+ ### `LumaProvider`
83
+
84
+ Main provider class extending `MediaProvider`.
85
+
86
+ | Member | Type | Description |
87
+ |--------|------|-------------|
88
+ | `supportedOperations` | `string[]` | `['mesh.generate']` |
89
+ | `supportsStreaming` | `Set<string>` | `{'mesh.generate'}` |
90
+ | `supportsWebhooks` | `boolean` | `true` — webhook delivery supported by Luma API |
91
+ | `healthCheck()` | `Promise<ProviderHealth>` | Checks `/dream-machine/v1/generations` endpoint |
92
+ | `estimateCost(input)` | `Promise<CostEstimate>` | Returns `{ costUsd: 0.30 }` |
93
+ | `execute(input)` | `Promise<ProviderOutput>` | Submits generation, polls for completion, downloads mesh |
94
+
95
+ ### `LumaConfig`
96
+
97
+ Configuration interface (see Configuration section above).
98
+
99
+ ## Mesh Generation Parameters
100
+
101
+ | Parameter | Type | Default | Description |
102
+ |-----------|------|---------|-------------|
103
+ | `prompt` | `string` | — | Text description of the 3D model to generate |
104
+ | `format` | `string` | `"glb"` | Output format: `"glb"` or `"usdz"` |
105
+ | `sourceArtifactId` | `string` | — | Optional reference image URL for image-to-3D |
106
+
107
+ ## Output Metadata
108
+
109
+ | Field | Type | Description |
110
+ |-------|------|-------------|
111
+ | `provider` | `string` | `"luma"` |
112
+ | `taskId` | `string` | Luma generation ID |
113
+ | `format` | `string` | Actual output format (glb or usdz) |
114
+ | `requestedFormat` | `string` | Format requested by caller |
115
+ | `hasTextures` | `boolean` | `true` — Luma Genie includes textures |
116
+ | `hasAnimation` | `boolean` | `false` — static mesh |
117
+ | `prompt` | `string` | Original generation prompt |
118
+
119
+ ## Cost Estimation
120
+
121
+ | Operation | Model | Estimated Cost |
122
+ |-----------|-------|---------------|
123
+ | `mesh.generate` | Genie | $0.30 / generation |
124
+
125
+ ## Related Packages
126
+
127
+ - [`@reaatech/media-pipeline-mcp-provider-core`](https://www.npmjs.com/package/@reaatech/media-pipeline-mcp-provider-core) — Base provider class
128
+ - [`@reaatech/media-pipeline-mcp-meshy`](https://www.npmjs.com/package/@reaatech/media-pipeline-mcp-meshy) — Meshy 3D provider (PBR textures, image-to-3D)
129
+ - [`@reaatech/media-pipeline-mcp-server`](https://www.npmjs.com/package/@reaatech/media-pipeline-mcp-server) — MCP server
130
+
131
+ ## License
132
+
133
+ [MIT](https://github.com/reaatech/media-pipeline-mcp/blob/main/LICENSE)
package/dist/index.cjs ADDED
@@ -0,0 +1,174 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/index.ts
21
+ var index_exports = {};
22
+ __export(index_exports, {
23
+ LumaProvider: () => LumaProvider
24
+ });
25
+ module.exports = __toCommonJS(index_exports);
26
+
27
+ // src/luma-provider.ts
28
+ var import_media_pipeline_mcp_provider_core = require("@reaatech/media-pipeline-mcp-provider-core");
29
+
30
+ // src/pricing.json
31
+ var pricing_default = {
32
+ "mesh.generate": {
33
+ genie: {
34
+ input: { perUnit: 0.3, unit: "1 generation" },
35
+ expectedDurationMs: 6e4
36
+ }
37
+ }
38
+ };
39
+
40
+ // src/luma-provider.ts
41
+ var PRICING = pricing_default;
42
+ var GENIE_PRICE = PRICING["mesh.generate"].genie.input.perUnit;
43
+ var LumaProvider = class extends import_media_pipeline_mcp_provider_core.MediaProvider {
44
+ name = "luma";
45
+ supportedOperations = ["mesh.generate"];
46
+ /**
47
+ * §0.6 / F21 — Luma supports webhook delivery (via webhook_url config on the
48
+ * generation request) but the in-tree impl currently polls. The capability flag
49
+ * still says yes so the §0.6 capability matrix matches the plan.
50
+ */
51
+ supportsStreaming = /* @__PURE__ */ new Set(["mesh.generate"]);
52
+ supportsWebhooks = true;
53
+ /**
54
+ * F2 cacheConfig per plan §F21: luma bills per generation. Same shape as meshy —
55
+ * deterministic inputs drive output, and webhook_url is the only common
56
+ * runtime-volatile param.
57
+ */
58
+ static cacheConfig = {
59
+ deterministicParams: ["prompt", "sourceArtifactId", "format", "model", "type"],
60
+ nonDeterministicParams: ["webhook_url"],
61
+ normalize: (inputs) => {
62
+ const out = {};
63
+ for (const [k, v] of Object.entries(inputs)) {
64
+ if (k === "webhook_url") continue;
65
+ out[k] = typeof v === "string" ? v.trim().replace(/\s+/g, " ") : v;
66
+ }
67
+ return out;
68
+ }
69
+ };
70
+ apiKey;
71
+ baseUrl;
72
+ pollIntervalMs;
73
+ maxWaitMs;
74
+ constructor(config) {
75
+ super();
76
+ this.apiKey = config?.apiKey ?? process.env.LUMA_API_KEY ?? "";
77
+ this.baseUrl = config?.baseUrl ?? "https://api.lumalabs.ai";
78
+ this.pollIntervalMs = config?.pollIntervalMs ?? 5e3;
79
+ this.maxWaitMs = config?.maxWaitMs ?? 15 * 60 * 1e3;
80
+ }
81
+ async execute(input) {
82
+ if (!this.apiKey) {
83
+ throw new Error("LUMA_API_KEY not configured");
84
+ }
85
+ const prompt = input.params.prompt;
86
+ const sourceArtifactId = input.params.sourceArtifactId;
87
+ const requestedFormat = input.params.format ?? "glb";
88
+ const body = {
89
+ type: "mesh",
90
+ prompt: prompt ?? ""
91
+ };
92
+ if (sourceArtifactId) body.image_url = sourceArtifactId;
93
+ const startedAt = Date.now();
94
+ const createResp = await fetch(`${this.baseUrl}/dream-machine/v1/generations`, {
95
+ method: "POST",
96
+ headers: {
97
+ Authorization: `Bearer ${this.apiKey}`,
98
+ "Content-Type": "application/json",
99
+ Accept: "application/json"
100
+ },
101
+ body: JSON.stringify(body)
102
+ });
103
+ if (!createResp.ok) {
104
+ throw new Error(
105
+ `Luma create failed: ${createResp.status} ${await createResp.text().catch(() => "")}`
106
+ );
107
+ }
108
+ const created = await createResp.json();
109
+ const deadline = startedAt + this.maxWaitMs;
110
+ let status = created;
111
+ while (Date.now() < deadline && status.state !== "completed" && status.state !== "failed") {
112
+ await new Promise((resolve) => setTimeout(resolve, this.pollIntervalMs));
113
+ const pollResp = await fetch(`${this.baseUrl}/dream-machine/v1/generations/${created.id}`, {
114
+ headers: { Authorization: `Bearer ${this.apiKey}` }
115
+ });
116
+ if (!pollResp.ok) {
117
+ throw new Error(`Luma poll failed: ${pollResp.status}`);
118
+ }
119
+ status = await pollResp.json();
120
+ }
121
+ if (status.state !== "completed") {
122
+ throw new Error(`Luma generation did not complete: ${status.failure_reason ?? status.state}`);
123
+ }
124
+ const meshAssets = status.assets?.mesh;
125
+ const downloadUrl = requestedFormat === "usdz" ? meshAssets?.usdz : meshAssets?.glb;
126
+ if (!downloadUrl) {
127
+ throw new Error(`Luma succeeded but no mesh URL for format=${requestedFormat}`);
128
+ }
129
+ const modelResp = await fetch(downloadUrl);
130
+ if (!modelResp.ok) {
131
+ throw new Error(`Failed to download Luma mesh: ${modelResp.status}`);
132
+ }
133
+ const modelBuf = Buffer.from(await modelResp.arrayBuffer());
134
+ const finalFormat = requestedFormat === "usdz" && meshAssets?.usdz ? "usdz" : "glb";
135
+ return {
136
+ data: modelBuf,
137
+ mimeType: finalFormat === "usdz" ? "model/vnd.usdz+zip" : "model/gltf-binary",
138
+ metadata: {
139
+ provider: this.name,
140
+ taskId: created.id,
141
+ format: finalFormat,
142
+ requestedFormat,
143
+ hasTextures: true,
144
+ hasAnimation: false,
145
+ prompt,
146
+ sourceArtifactId
147
+ },
148
+ costUsd: GENIE_PRICE,
149
+ durationMs: Date.now() - startedAt
150
+ };
151
+ }
152
+ async estimateCost(_input) {
153
+ return { costUsd: GENIE_PRICE, currency: "USD" };
154
+ }
155
+ async healthCheck() {
156
+ if (!this.apiKey) {
157
+ return { healthy: false, error: "LUMA_API_KEY not configured" };
158
+ }
159
+ try {
160
+ const resp = await fetch(`${this.baseUrl}/dream-machine/v1/generations?limit=1`, {
161
+ headers: { Authorization: `Bearer ${this.apiKey}` },
162
+ signal: AbortSignal.timeout(5e3)
163
+ });
164
+ return { healthy: resp.ok, latency: 100, error: resp.ok ? void 0 : `HTTP ${resp.status}` };
165
+ } catch (err) {
166
+ return { healthy: false, error: err.message };
167
+ }
168
+ }
169
+ };
170
+ // Annotate the CommonJS export names for ESM import in node:
171
+ 0 && (module.exports = {
172
+ LumaProvider
173
+ });
174
+ //# sourceMappingURL=index.cjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/luma-provider.ts","../src/pricing.json"],"sourcesContent":["export { LumaProvider } from './luma-provider.js';\n","import { MediaProvider } from '@reaatech/media-pipeline-mcp-provider-core';\nimport type {\n CostEstimate,\n ProviderCacheConfig,\n ProviderHealth,\n ProviderInput,\n ProviderOutput,\n} from '@reaatech/media-pipeline-mcp-provider-core';\nimport pricing from './pricing.json' with { type: 'json' };\n\nconst PRICING = pricing as {\n 'mesh.generate': { genie: { input: { perUnit: number } } };\n};\nconst GENIE_PRICE = PRICING['mesh.generate'].genie.input.perUnit;\n\n/**\n * Luma Genie text-to-3D / image-to-3D provider (F21).\n *\n * Uses Luma's Dream Machine API (https://lumalabs.ai/dream-machine/api). The previous\n * implementation returned a hardcoded JSON blob with no API call — replaced here with\n * a poll-based real implementation. Webhook delivery is supported in Luma's API but\n * left to the F7 wiring (callers provide a webhook_url through config when desired).\n */\nexport interface LumaConfig {\n apiKey: string;\n baseUrl?: string;\n pollIntervalMs?: number;\n maxWaitMs?: number;\n}\n\ninterface LumaGenerationResponse {\n id: string;\n state: 'queued' | 'dreaming' | 'completed' | 'failed';\n assets?: { mesh?: { glb?: string; usdz?: string } } | null;\n failure_reason?: string;\n}\n\nexport class LumaProvider extends MediaProvider {\n readonly name = 'luma';\n readonly supportedOperations: string[] = ['mesh.generate'];\n\n /**\n * §0.6 / F21 — Luma supports webhook delivery (via webhook_url config on the\n * generation request) but the in-tree impl currently polls. The capability flag\n * still says yes so the §0.6 capability matrix matches the plan.\n */\n readonly supportsStreaming = new Set<string>(['mesh.generate']);\n readonly supportsWebhooks = true;\n\n /**\n * F2 cacheConfig per plan §F21: luma bills per generation. Same shape as meshy —\n * deterministic inputs drive output, and webhook_url is the only common\n * runtime-volatile param.\n */\n static cacheConfig: ProviderCacheConfig = {\n deterministicParams: ['prompt', 'sourceArtifactId', 'format', 'model', 'type'],\n nonDeterministicParams: ['webhook_url'],\n normalize: (inputs: Record<string, unknown>): Record<string, unknown> => {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(inputs)) {\n if (k === 'webhook_url') continue;\n out[k] = typeof v === 'string' ? v.trim().replace(/\\s+/g, ' ') : v;\n }\n return out;\n },\n };\n\n private apiKey: string;\n private baseUrl: string;\n private pollIntervalMs: number;\n private maxWaitMs: number;\n\n constructor(config?: Record<string, unknown>) {\n super();\n this.apiKey = (config?.apiKey as string) ?? process.env.LUMA_API_KEY ?? '';\n this.baseUrl = (config?.baseUrl as string) ?? 'https://api.lumalabs.ai';\n this.pollIntervalMs = (config?.pollIntervalMs as number) ?? 5_000;\n this.maxWaitMs = (config?.maxWaitMs as number) ?? 15 * 60 * 1000;\n }\n\n async execute(input: ProviderInput): Promise<ProviderOutput> {\n if (!this.apiKey) {\n throw new Error('LUMA_API_KEY not configured');\n }\n\n const prompt = input.params.prompt as string | undefined;\n const sourceArtifactId = input.params.sourceArtifactId as string | undefined;\n const requestedFormat = (input.params.format as string | undefined) ?? 'glb';\n\n const body: Record<string, unknown> = {\n type: 'mesh',\n prompt: prompt ?? '',\n };\n if (sourceArtifactId) body.image_url = sourceArtifactId;\n\n const startedAt = Date.now();\n const createResp = await fetch(`${this.baseUrl}/dream-machine/v1/generations`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n },\n body: JSON.stringify(body),\n });\n if (!createResp.ok) {\n throw new Error(\n `Luma create failed: ${createResp.status} ${await createResp.text().catch(() => '')}`,\n );\n }\n const created = (await createResp.json()) as LumaGenerationResponse;\n\n const deadline = startedAt + this.maxWaitMs;\n let status: LumaGenerationResponse = created;\n while (Date.now() < deadline && status.state !== 'completed' && status.state !== 'failed') {\n await new Promise((resolve) => setTimeout(resolve, this.pollIntervalMs));\n const pollResp = await fetch(`${this.baseUrl}/dream-machine/v1/generations/${created.id}`, {\n headers: { Authorization: `Bearer ${this.apiKey}` },\n });\n if (!pollResp.ok) {\n throw new Error(`Luma poll failed: ${pollResp.status}`);\n }\n status = (await pollResp.json()) as LumaGenerationResponse;\n }\n\n if (status.state !== 'completed') {\n throw new Error(`Luma generation did not complete: ${status.failure_reason ?? status.state}`);\n }\n\n // Luma natively returns glb + usdz. ply/fbx/obj would need external conversion.\n const meshAssets = status.assets?.mesh;\n const downloadUrl = requestedFormat === 'usdz' ? meshAssets?.usdz : meshAssets?.glb;\n if (!downloadUrl) {\n throw new Error(`Luma succeeded but no mesh URL for format=${requestedFormat}`);\n }\n const modelResp = await fetch(downloadUrl);\n if (!modelResp.ok) {\n throw new Error(`Failed to download Luma mesh: ${modelResp.status}`);\n }\n const modelBuf = Buffer.from(await modelResp.arrayBuffer());\n const finalFormat = requestedFormat === 'usdz' && meshAssets?.usdz ? 'usdz' : 'glb';\n\n return {\n data: modelBuf,\n mimeType: finalFormat === 'usdz' ? 'model/vnd.usdz+zip' : 'model/gltf-binary',\n metadata: {\n provider: this.name,\n taskId: created.id,\n format: finalFormat,\n requestedFormat,\n hasTextures: true,\n hasAnimation: false,\n prompt,\n sourceArtifactId,\n },\n costUsd: GENIE_PRICE,\n durationMs: Date.now() - startedAt,\n };\n }\n\n async estimateCost(_input: ProviderInput): Promise<CostEstimate> {\n return { costUsd: GENIE_PRICE, currency: 'USD' };\n }\n\n async healthCheck(): Promise<ProviderHealth> {\n if (!this.apiKey) {\n return { healthy: false, error: 'LUMA_API_KEY not configured' };\n }\n try {\n const resp = await fetch(`${this.baseUrl}/dream-machine/v1/generations?limit=1`, {\n headers: { Authorization: `Bearer ${this.apiKey}` },\n signal: AbortSignal.timeout(5_000),\n });\n return { healthy: resp.ok, latency: 100, error: resp.ok ? undefined : `HTTP ${resp.status}` };\n } catch (err) {\n return { healthy: false, error: (err as Error).message };\n }\n }\n}\n","{\n \"mesh.generate\": {\n \"genie\": {\n \"input\": { \"perUnit\": 0.3, \"unit\": \"1 generation\" },\n \"expectedDurationMs\": 60000\n }\n }\n}\n"],"mappings":"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","names":[]}
@@ -0,0 +1,29 @@
1
+ import { MediaProvider, ProviderCacheConfig, ProviderInput, ProviderOutput, CostEstimate, ProviderHealth } from '@reaatech/media-pipeline-mcp-provider-core';
2
+
3
+ declare class LumaProvider extends MediaProvider {
4
+ readonly name = "luma";
5
+ readonly supportedOperations: string[];
6
+ /**
7
+ * §0.6 / F21 — Luma supports webhook delivery (via webhook_url config on the
8
+ * generation request) but the in-tree impl currently polls. The capability flag
9
+ * still says yes so the §0.6 capability matrix matches the plan.
10
+ */
11
+ readonly supportsStreaming: Set<string>;
12
+ readonly supportsWebhooks = true;
13
+ /**
14
+ * F2 cacheConfig per plan §F21: luma bills per generation. Same shape as meshy —
15
+ * deterministic inputs drive output, and webhook_url is the only common
16
+ * runtime-volatile param.
17
+ */
18
+ static cacheConfig: ProviderCacheConfig;
19
+ private apiKey;
20
+ private baseUrl;
21
+ private pollIntervalMs;
22
+ private maxWaitMs;
23
+ constructor(config?: Record<string, unknown>);
24
+ execute(input: ProviderInput): Promise<ProviderOutput>;
25
+ estimateCost(_input: ProviderInput): Promise<CostEstimate>;
26
+ healthCheck(): Promise<ProviderHealth>;
27
+ }
28
+
29
+ export { LumaProvider };
@@ -0,0 +1,29 @@
1
+ import { MediaProvider, ProviderCacheConfig, ProviderInput, ProviderOutput, CostEstimate, ProviderHealth } from '@reaatech/media-pipeline-mcp-provider-core';
2
+
3
+ declare class LumaProvider extends MediaProvider {
4
+ readonly name = "luma";
5
+ readonly supportedOperations: string[];
6
+ /**
7
+ * §0.6 / F21 — Luma supports webhook delivery (via webhook_url config on the
8
+ * generation request) but the in-tree impl currently polls. The capability flag
9
+ * still says yes so the §0.6 capability matrix matches the plan.
10
+ */
11
+ readonly supportsStreaming: Set<string>;
12
+ readonly supportsWebhooks = true;
13
+ /**
14
+ * F2 cacheConfig per plan §F21: luma bills per generation. Same shape as meshy —
15
+ * deterministic inputs drive output, and webhook_url is the only common
16
+ * runtime-volatile param.
17
+ */
18
+ static cacheConfig: ProviderCacheConfig;
19
+ private apiKey;
20
+ private baseUrl;
21
+ private pollIntervalMs;
22
+ private maxWaitMs;
23
+ constructor(config?: Record<string, unknown>);
24
+ execute(input: ProviderInput): Promise<ProviderOutput>;
25
+ estimateCost(_input: ProviderInput): Promise<CostEstimate>;
26
+ healthCheck(): Promise<ProviderHealth>;
27
+ }
28
+
29
+ export { LumaProvider };
package/dist/index.js ADDED
@@ -0,0 +1,147 @@
1
+ // src/luma-provider.ts
2
+ import { MediaProvider } from "@reaatech/media-pipeline-mcp-provider-core";
3
+
4
+ // src/pricing.json
5
+ var pricing_default = {
6
+ "mesh.generate": {
7
+ genie: {
8
+ input: { perUnit: 0.3, unit: "1 generation" },
9
+ expectedDurationMs: 6e4
10
+ }
11
+ }
12
+ };
13
+
14
+ // src/luma-provider.ts
15
+ var PRICING = pricing_default;
16
+ var GENIE_PRICE = PRICING["mesh.generate"].genie.input.perUnit;
17
+ var LumaProvider = class extends MediaProvider {
18
+ name = "luma";
19
+ supportedOperations = ["mesh.generate"];
20
+ /**
21
+ * §0.6 / F21 — Luma supports webhook delivery (via webhook_url config on the
22
+ * generation request) but the in-tree impl currently polls. The capability flag
23
+ * still says yes so the §0.6 capability matrix matches the plan.
24
+ */
25
+ supportsStreaming = /* @__PURE__ */ new Set(["mesh.generate"]);
26
+ supportsWebhooks = true;
27
+ /**
28
+ * F2 cacheConfig per plan §F21: luma bills per generation. Same shape as meshy —
29
+ * deterministic inputs drive output, and webhook_url is the only common
30
+ * runtime-volatile param.
31
+ */
32
+ static cacheConfig = {
33
+ deterministicParams: ["prompt", "sourceArtifactId", "format", "model", "type"],
34
+ nonDeterministicParams: ["webhook_url"],
35
+ normalize: (inputs) => {
36
+ const out = {};
37
+ for (const [k, v] of Object.entries(inputs)) {
38
+ if (k === "webhook_url") continue;
39
+ out[k] = typeof v === "string" ? v.trim().replace(/\s+/g, " ") : v;
40
+ }
41
+ return out;
42
+ }
43
+ };
44
+ apiKey;
45
+ baseUrl;
46
+ pollIntervalMs;
47
+ maxWaitMs;
48
+ constructor(config) {
49
+ super();
50
+ this.apiKey = config?.apiKey ?? process.env.LUMA_API_KEY ?? "";
51
+ this.baseUrl = config?.baseUrl ?? "https://api.lumalabs.ai";
52
+ this.pollIntervalMs = config?.pollIntervalMs ?? 5e3;
53
+ this.maxWaitMs = config?.maxWaitMs ?? 15 * 60 * 1e3;
54
+ }
55
+ async execute(input) {
56
+ if (!this.apiKey) {
57
+ throw new Error("LUMA_API_KEY not configured");
58
+ }
59
+ const prompt = input.params.prompt;
60
+ const sourceArtifactId = input.params.sourceArtifactId;
61
+ const requestedFormat = input.params.format ?? "glb";
62
+ const body = {
63
+ type: "mesh",
64
+ prompt: prompt ?? ""
65
+ };
66
+ if (sourceArtifactId) body.image_url = sourceArtifactId;
67
+ const startedAt = Date.now();
68
+ const createResp = await fetch(`${this.baseUrl}/dream-machine/v1/generations`, {
69
+ method: "POST",
70
+ headers: {
71
+ Authorization: `Bearer ${this.apiKey}`,
72
+ "Content-Type": "application/json",
73
+ Accept: "application/json"
74
+ },
75
+ body: JSON.stringify(body)
76
+ });
77
+ if (!createResp.ok) {
78
+ throw new Error(
79
+ `Luma create failed: ${createResp.status} ${await createResp.text().catch(() => "")}`
80
+ );
81
+ }
82
+ const created = await createResp.json();
83
+ const deadline = startedAt + this.maxWaitMs;
84
+ let status = created;
85
+ while (Date.now() < deadline && status.state !== "completed" && status.state !== "failed") {
86
+ await new Promise((resolve) => setTimeout(resolve, this.pollIntervalMs));
87
+ const pollResp = await fetch(`${this.baseUrl}/dream-machine/v1/generations/${created.id}`, {
88
+ headers: { Authorization: `Bearer ${this.apiKey}` }
89
+ });
90
+ if (!pollResp.ok) {
91
+ throw new Error(`Luma poll failed: ${pollResp.status}`);
92
+ }
93
+ status = await pollResp.json();
94
+ }
95
+ if (status.state !== "completed") {
96
+ throw new Error(`Luma generation did not complete: ${status.failure_reason ?? status.state}`);
97
+ }
98
+ const meshAssets = status.assets?.mesh;
99
+ const downloadUrl = requestedFormat === "usdz" ? meshAssets?.usdz : meshAssets?.glb;
100
+ if (!downloadUrl) {
101
+ throw new Error(`Luma succeeded but no mesh URL for format=${requestedFormat}`);
102
+ }
103
+ const modelResp = await fetch(downloadUrl);
104
+ if (!modelResp.ok) {
105
+ throw new Error(`Failed to download Luma mesh: ${modelResp.status}`);
106
+ }
107
+ const modelBuf = Buffer.from(await modelResp.arrayBuffer());
108
+ const finalFormat = requestedFormat === "usdz" && meshAssets?.usdz ? "usdz" : "glb";
109
+ return {
110
+ data: modelBuf,
111
+ mimeType: finalFormat === "usdz" ? "model/vnd.usdz+zip" : "model/gltf-binary",
112
+ metadata: {
113
+ provider: this.name,
114
+ taskId: created.id,
115
+ format: finalFormat,
116
+ requestedFormat,
117
+ hasTextures: true,
118
+ hasAnimation: false,
119
+ prompt,
120
+ sourceArtifactId
121
+ },
122
+ costUsd: GENIE_PRICE,
123
+ durationMs: Date.now() - startedAt
124
+ };
125
+ }
126
+ async estimateCost(_input) {
127
+ return { costUsd: GENIE_PRICE, currency: "USD" };
128
+ }
129
+ async healthCheck() {
130
+ if (!this.apiKey) {
131
+ return { healthy: false, error: "LUMA_API_KEY not configured" };
132
+ }
133
+ try {
134
+ const resp = await fetch(`${this.baseUrl}/dream-machine/v1/generations?limit=1`, {
135
+ headers: { Authorization: `Bearer ${this.apiKey}` },
136
+ signal: AbortSignal.timeout(5e3)
137
+ });
138
+ return { healthy: resp.ok, latency: 100, error: resp.ok ? void 0 : `HTTP ${resp.status}` };
139
+ } catch (err) {
140
+ return { healthy: false, error: err.message };
141
+ }
142
+ }
143
+ };
144
+ export {
145
+ LumaProvider
146
+ };
147
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/luma-provider.ts","../src/pricing.json"],"sourcesContent":["import { MediaProvider } from '@reaatech/media-pipeline-mcp-provider-core';\nimport type {\n CostEstimate,\n ProviderCacheConfig,\n ProviderHealth,\n ProviderInput,\n ProviderOutput,\n} from '@reaatech/media-pipeline-mcp-provider-core';\nimport pricing from './pricing.json' with { type: 'json' };\n\nconst PRICING = pricing as {\n 'mesh.generate': { genie: { input: { perUnit: number } } };\n};\nconst GENIE_PRICE = PRICING['mesh.generate'].genie.input.perUnit;\n\n/**\n * Luma Genie text-to-3D / image-to-3D provider (F21).\n *\n * Uses Luma's Dream Machine API (https://lumalabs.ai/dream-machine/api). The previous\n * implementation returned a hardcoded JSON blob with no API call — replaced here with\n * a poll-based real implementation. Webhook delivery is supported in Luma's API but\n * left to the F7 wiring (callers provide a webhook_url through config when desired).\n */\nexport interface LumaConfig {\n apiKey: string;\n baseUrl?: string;\n pollIntervalMs?: number;\n maxWaitMs?: number;\n}\n\ninterface LumaGenerationResponse {\n id: string;\n state: 'queued' | 'dreaming' | 'completed' | 'failed';\n assets?: { mesh?: { glb?: string; usdz?: string } } | null;\n failure_reason?: string;\n}\n\nexport class LumaProvider extends MediaProvider {\n readonly name = 'luma';\n readonly supportedOperations: string[] = ['mesh.generate'];\n\n /**\n * §0.6 / F21 — Luma supports webhook delivery (via webhook_url config on the\n * generation request) but the in-tree impl currently polls. The capability flag\n * still says yes so the §0.6 capability matrix matches the plan.\n */\n readonly supportsStreaming = new Set<string>(['mesh.generate']);\n readonly supportsWebhooks = true;\n\n /**\n * F2 cacheConfig per plan §F21: luma bills per generation. Same shape as meshy —\n * deterministic inputs drive output, and webhook_url is the only common\n * runtime-volatile param.\n */\n static cacheConfig: ProviderCacheConfig = {\n deterministicParams: ['prompt', 'sourceArtifactId', 'format', 'model', 'type'],\n nonDeterministicParams: ['webhook_url'],\n normalize: (inputs: Record<string, unknown>): Record<string, unknown> => {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(inputs)) {\n if (k === 'webhook_url') continue;\n out[k] = typeof v === 'string' ? v.trim().replace(/\\s+/g, ' ') : v;\n }\n return out;\n },\n };\n\n private apiKey: string;\n private baseUrl: string;\n private pollIntervalMs: number;\n private maxWaitMs: number;\n\n constructor(config?: Record<string, unknown>) {\n super();\n this.apiKey = (config?.apiKey as string) ?? process.env.LUMA_API_KEY ?? '';\n this.baseUrl = (config?.baseUrl as string) ?? 'https://api.lumalabs.ai';\n this.pollIntervalMs = (config?.pollIntervalMs as number) ?? 5_000;\n this.maxWaitMs = (config?.maxWaitMs as number) ?? 15 * 60 * 1000;\n }\n\n async execute(input: ProviderInput): Promise<ProviderOutput> {\n if (!this.apiKey) {\n throw new Error('LUMA_API_KEY not configured');\n }\n\n const prompt = input.params.prompt as string | undefined;\n const sourceArtifactId = input.params.sourceArtifactId as string | undefined;\n const requestedFormat = (input.params.format as string | undefined) ?? 'glb';\n\n const body: Record<string, unknown> = {\n type: 'mesh',\n prompt: prompt ?? '',\n };\n if (sourceArtifactId) body.image_url = sourceArtifactId;\n\n const startedAt = Date.now();\n const createResp = await fetch(`${this.baseUrl}/dream-machine/v1/generations`, {\n method: 'POST',\n headers: {\n Authorization: `Bearer ${this.apiKey}`,\n 'Content-Type': 'application/json',\n Accept: 'application/json',\n },\n body: JSON.stringify(body),\n });\n if (!createResp.ok) {\n throw new Error(\n `Luma create failed: ${createResp.status} ${await createResp.text().catch(() => '')}`,\n );\n }\n const created = (await createResp.json()) as LumaGenerationResponse;\n\n const deadline = startedAt + this.maxWaitMs;\n let status: LumaGenerationResponse = created;\n while (Date.now() < deadline && status.state !== 'completed' && status.state !== 'failed') {\n await new Promise((resolve) => setTimeout(resolve, this.pollIntervalMs));\n const pollResp = await fetch(`${this.baseUrl}/dream-machine/v1/generations/${created.id}`, {\n headers: { Authorization: `Bearer ${this.apiKey}` },\n });\n if (!pollResp.ok) {\n throw new Error(`Luma poll failed: ${pollResp.status}`);\n }\n status = (await pollResp.json()) as LumaGenerationResponse;\n }\n\n if (status.state !== 'completed') {\n throw new Error(`Luma generation did not complete: ${status.failure_reason ?? status.state}`);\n }\n\n // Luma natively returns glb + usdz. ply/fbx/obj would need external conversion.\n const meshAssets = status.assets?.mesh;\n const downloadUrl = requestedFormat === 'usdz' ? meshAssets?.usdz : meshAssets?.glb;\n if (!downloadUrl) {\n throw new Error(`Luma succeeded but no mesh URL for format=${requestedFormat}`);\n }\n const modelResp = await fetch(downloadUrl);\n if (!modelResp.ok) {\n throw new Error(`Failed to download Luma mesh: ${modelResp.status}`);\n }\n const modelBuf = Buffer.from(await modelResp.arrayBuffer());\n const finalFormat = requestedFormat === 'usdz' && meshAssets?.usdz ? 'usdz' : 'glb';\n\n return {\n data: modelBuf,\n mimeType: finalFormat === 'usdz' ? 'model/vnd.usdz+zip' : 'model/gltf-binary',\n metadata: {\n provider: this.name,\n taskId: created.id,\n format: finalFormat,\n requestedFormat,\n hasTextures: true,\n hasAnimation: false,\n prompt,\n sourceArtifactId,\n },\n costUsd: GENIE_PRICE,\n durationMs: Date.now() - startedAt,\n };\n }\n\n async estimateCost(_input: ProviderInput): Promise<CostEstimate> {\n return { costUsd: GENIE_PRICE, currency: 'USD' };\n }\n\n async healthCheck(): Promise<ProviderHealth> {\n if (!this.apiKey) {\n return { healthy: false, error: 'LUMA_API_KEY not configured' };\n }\n try {\n const resp = await fetch(`${this.baseUrl}/dream-machine/v1/generations?limit=1`, {\n headers: { Authorization: `Bearer ${this.apiKey}` },\n signal: AbortSignal.timeout(5_000),\n });\n return { healthy: resp.ok, latency: 100, error: resp.ok ? undefined : `HTTP ${resp.status}` };\n } catch (err) {\n return { healthy: false, error: (err as Error).message };\n }\n }\n}\n","{\n \"mesh.generate\": {\n \"genie\": {\n \"input\": { \"perUnit\": 0.3, \"unit\": \"1 generation\" },\n \"expectedDurationMs\": 60000\n }\n }\n}\n"],"mappings":"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","names":[]}
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "@reaatech/media-pipeline-mcp-luma",
3
+ "version": "0.3.0",
4
+ "type": "module",
5
+ "main": "./dist/index.cjs",
6
+ "module": "./dist/index.js",
7
+ "types": "./dist/index.d.ts",
8
+ "exports": {
9
+ ".": {
10
+ "types": "./dist/index.d.ts",
11
+ "import": "./dist/index.js",
12
+ "require": "./dist/index.cjs"
13
+ }
14
+ },
15
+ "files": [
16
+ "dist"
17
+ ],
18
+ "dependencies": {
19
+ "@reaatech/media-pipeline-mcp-provider-core": "0.3.0"
20
+ },
21
+ "devDependencies": {
22
+ "@types/node": "^20.0.0",
23
+ "tsup": "^8.0.0",
24
+ "typescript": "^5.0.0",
25
+ "vitest": "^3.0.0"
26
+ },
27
+ "scripts": {
28
+ "build": "tsup src/index.ts --dts --format esm,cjs --sourcemap",
29
+ "test": "vitest run --passWithNoTests",
30
+ "typecheck": "tsc --noEmit"
31
+ }
32
+ }