@productmaker/mcp 11.8.0 → 11.8.1
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 +21 -1
- package/dist/http.js +1016 -935
- package/dist/stdio.js +1016 -935
- package/package.json +1 -1
package/dist/http.js
CHANGED
|
@@ -7240,6 +7240,8 @@ var ApproveVideoAnglesRequest = z35.object({
|
|
|
7240
7240
|
var ApproveVideoAnglesResponse = z35.object({
|
|
7241
7241
|
success: z35.boolean(),
|
|
7242
7242
|
taskId: z35.string().uuid(),
|
|
7243
|
+
/** Persisted keys scheduled by this approval; visible candidate indices are not worker keys. */
|
|
7244
|
+
approvedAngleKeys: z35.array(z35.string().regex(/^angle_\d+$/)).min(1).max(3).optional(),
|
|
7243
7245
|
reason: ApproveAnglesRefusalReason.optional()
|
|
7244
7246
|
});
|
|
7245
7247
|
var SaveVideoDraftRequest = z35.object({
|
|
@@ -19734,7 +19736,7 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
|
|
|
19734
19736
|
], [
|
|
19735
19737
|
"campaign_status"
|
|
19736
19738
|
]),
|
|
19737
|
-
defineCapability("get_video_script", "
|
|
19739
|
+
defineCapability("get_video_script", "e987ff48555dfdab439f9910fb1fa25af373c78c8a9a5ef26458c82add90f2a2", "none", "read_only", [
|
|
19738
19740
|
"read"
|
|
19739
19741
|
], [
|
|
19740
19742
|
slot("task", true, [
|
|
@@ -20130,7 +20132,7 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
|
|
|
20130
20132
|
], [
|
|
20131
20133
|
"brand"
|
|
20132
20134
|
], MCP_ONLY_CHANNEL_EXPOSURE),
|
|
20133
|
-
defineCapability("create_service_landing", "
|
|
20135
|
+
defineCapability("create_service_landing", "ce99d75f4b00bea23b6bf4f56ef3331b266176cb0a9dead55611ee78d21c41b3", "credit_consuming", "creative", [
|
|
20134
20136
|
"credit_consuming",
|
|
20135
20137
|
"state_change"
|
|
20136
20138
|
], [
|
|
@@ -22555,51 +22557,6 @@ var ServicePageGenerateRequestSchema = z104.object({
|
|
|
22555
22557
|
instruction: ServicePageEditInstructionSchema.optional(),
|
|
22556
22558
|
attachmentRefs: ServicePageAttachmentRefsSchema.optional()
|
|
22557
22559
|
}).strict();
|
|
22558
|
-
var SERVICE_PAGE_SOURCES_MISSING_CODES = /* @__PURE__ */ new Set([
|
|
22559
|
-
"SERVICE_PAGE_SOURCES_REQUIRED",
|
|
22560
|
-
"SERVICE_PAGE_SOURCE_TEXT_REQUIRED"
|
|
22561
|
-
]);
|
|
22562
|
-
function isRetryableServicePageFailureCode(errorCode) {
|
|
22563
|
-
return servicePageFailurePolicy(errorCode).retryable;
|
|
22564
|
-
}
|
|
22565
|
-
__name(isRetryableServicePageFailureCode, "isRetryableServicePageFailureCode");
|
|
22566
|
-
function servicePageFailurePolicy(errorCode) {
|
|
22567
|
-
const code = errorCode ?? "";
|
|
22568
|
-
const retryable = !SERVICE_PAGE_SOURCES_MISSING_CODES.has(code) && !/CREDIT|QUOTE|REVISION|CONFLICT|WINDOW_EXPIRED|NOT_FOUND|POLICY_INVALID|SNAPSHOT_INVALID|OWNER_MISMATCH|PROVIDER_ROUTE_UNSUPPORTED|PROVIDER_REJECTED/.test(code);
|
|
22569
|
-
if (code.includes("QUOTE_EXPIRED")) return {
|
|
22570
|
-
reason: "quote_expired",
|
|
22571
|
-
retryable
|
|
22572
|
-
};
|
|
22573
|
-
if (code.includes("CREDIT")) return {
|
|
22574
|
-
reason: "credits",
|
|
22575
|
-
retryable
|
|
22576
|
-
};
|
|
22577
|
-
if (code.includes("NOT_FOUND")) return {
|
|
22578
|
-
reason: "not_found",
|
|
22579
|
-
retryable
|
|
22580
|
-
};
|
|
22581
|
-
if (/PROVIDER|ACCEPTANCE/.test(code)) return {
|
|
22582
|
-
reason: "provider",
|
|
22583
|
-
retryable
|
|
22584
|
-
};
|
|
22585
|
-
if (/NETWORK|TIMEOUT|QUEUE/.test(code)) return {
|
|
22586
|
-
reason: "network",
|
|
22587
|
-
retryable
|
|
22588
|
-
};
|
|
22589
|
-
if (/REVISION|STALE|CONFLICT/.test(code)) return {
|
|
22590
|
-
reason: "conflict",
|
|
22591
|
-
retryable
|
|
22592
|
-
};
|
|
22593
|
-
if (/INVALID|PRECONDITION|MISSING|REQUIRED|MISMATCH/.test(code)) return {
|
|
22594
|
-
reason: "validation",
|
|
22595
|
-
retryable
|
|
22596
|
-
};
|
|
22597
|
-
return {
|
|
22598
|
-
reason: "unknown",
|
|
22599
|
-
retryable
|
|
22600
|
-
};
|
|
22601
|
-
}
|
|
22602
|
-
__name(servicePageFailurePolicy, "servicePageFailurePolicy");
|
|
22603
22560
|
var SERVICE_PAGE_CREATION_MAX_ATTEMPTS = 3;
|
|
22604
22561
|
var ServicePageCreationMarkerSchema = z104.object({
|
|
22605
22562
|
rootOperationId: z104.string().uuid().optional(),
|
|
@@ -25538,7 +25495,7 @@ var ApiClient = class {
|
|
|
25538
25495
|
};
|
|
25539
25496
|
|
|
25540
25497
|
// src/index.ts
|
|
25541
|
-
var MCP_VERSION = "11.8.
|
|
25498
|
+
var MCP_VERSION = "11.8.1";
|
|
25542
25499
|
|
|
25543
25500
|
// src/meta-upload-app.ts
|
|
25544
25501
|
import { readFileSync } from "fs";
|
|
@@ -25610,7 +25567,7 @@ function registerMediaUploadAppResource(server, resolveEndpoint) {
|
|
|
25610
25567
|
__name(registerMediaUploadAppResource, "registerMediaUploadAppResource");
|
|
25611
25568
|
|
|
25612
25569
|
// src/tools/tasks.ts
|
|
25613
|
-
import { z as
|
|
25570
|
+
import { z as z122 } from "zod";
|
|
25614
25571
|
|
|
25615
25572
|
// src/resolve-image.ts
|
|
25616
25573
|
import { lookup as dnsLookup } from "dns/promises";
|
|
@@ -27224,8 +27181,67 @@ function approveRefusalMessage(reason) {
|
|
|
27224
27181
|
}
|
|
27225
27182
|
__name(approveRefusalMessage, "approveRefusalMessage");
|
|
27226
27183
|
|
|
27184
|
+
// src/tools/task-outputs.ts
|
|
27185
|
+
import { z as z118 } from "zod";
|
|
27186
|
+
|
|
27187
|
+
// src/tools/conversational-review-format.ts
|
|
27188
|
+
function escapeMarkdownText(value) {
|
|
27189
|
+
return value.replace(/\\/g, "\\\\").replace(/([`*_{}[\]()<>#+.!|>])/g, "\\$1").replace(/[\r\n\u2028\u2029]+/g, " ");
|
|
27190
|
+
}
|
|
27191
|
+
__name(escapeMarkdownText, "escapeMarkdownText");
|
|
27192
|
+
function trustedPreviewUrl(raw) {
|
|
27193
|
+
if (/[\u0000-\u001f\u007f]/.test(raw)) return null;
|
|
27194
|
+
try {
|
|
27195
|
+
const url = new URL(raw);
|
|
27196
|
+
if (url.username || url.password) return null;
|
|
27197
|
+
const hostname = url.hostname.toLowerCase();
|
|
27198
|
+
const productMakerHost = hostname === "productmaker.app" || hostname.endsWith(".productmaker.app");
|
|
27199
|
+
const localHost = hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
|
|
27200
|
+
if (url.protocol === "https:" && productMakerHost && (!url.port || url.port === "443")) {
|
|
27201
|
+
return url.toString().replace(/\(/g, "%28").replace(/\)/g, "%29");
|
|
27202
|
+
}
|
|
27203
|
+
if (url.protocol === "http:" && localHost) {
|
|
27204
|
+
return url.toString().replace(/\(/g, "%28").replace(/\)/g, "%29");
|
|
27205
|
+
}
|
|
27206
|
+
return null;
|
|
27207
|
+
} catch {
|
|
27208
|
+
return null;
|
|
27209
|
+
}
|
|
27210
|
+
}
|
|
27211
|
+
__name(trustedPreviewUrl, "trustedPreviewUrl");
|
|
27212
|
+
function renderPreview(preview2, index) {
|
|
27213
|
+
const label = escapeMarkdownText(preview2.label);
|
|
27214
|
+
const url = trustedPreviewUrl(preview2.previewUrl);
|
|
27215
|
+
return [
|
|
27216
|
+
`### Foto ${index + 1}: ${label}`,
|
|
27217
|
+
...preview2.view ? [
|
|
27218
|
+
`- **Vista:** ${escapeMarkdownText(preview2.view)}`
|
|
27219
|
+
] : [],
|
|
27220
|
+
...url ? [
|
|
27221
|
+
``
|
|
27222
|
+
] : [
|
|
27223
|
+
"- Vista previa externa bloqueada por seguridad. \xC1brela desde ProductMaker Web."
|
|
27224
|
+
]
|
|
27225
|
+
];
|
|
27226
|
+
}
|
|
27227
|
+
__name(renderPreview, "renderPreview");
|
|
27228
|
+
function formatCredits(creditCents) {
|
|
27229
|
+
return new Intl.NumberFormat("es-CO", {
|
|
27230
|
+
minimumFractionDigits: creditCents % 100 === 0 ? 0 : 2,
|
|
27231
|
+
maximumFractionDigits: 2
|
|
27232
|
+
}).format(creditCents / 100);
|
|
27233
|
+
}
|
|
27234
|
+
__name(formatCredits, "formatCredits");
|
|
27235
|
+
|
|
27227
27236
|
// src/tools/task-outputs.ts
|
|
27228
27237
|
var WEBAPP_BASE = "https://productmaker.app";
|
|
27238
|
+
var CreativeVariantIdentity = z118.object({
|
|
27239
|
+
variantTaskId: z118.string().uuid(),
|
|
27240
|
+
sourceTaskId: z118.string().uuid(),
|
|
27241
|
+
kind: TaskCreativeVariantKind,
|
|
27242
|
+
status: TaskStatusSchema,
|
|
27243
|
+
error: z118.string().optional()
|
|
27244
|
+
});
|
|
27229
27245
|
function proxifyOutputs(outputs, proxyBaseUrl) {
|
|
27230
27246
|
if (!proxyBaseUrl || !isProxyEnabled()) return outputs;
|
|
27231
27247
|
const rewrite = /* @__PURE__ */ __name((url, filename) => buildProxyUrl({
|
|
@@ -27269,7 +27285,15 @@ function proxifyOutputs(outputs, proxyBaseUrl) {
|
|
|
27269
27285
|
...variant,
|
|
27270
27286
|
url: rewrite(variant.url, `video-${sanitizeFilename(v.angleKey)}-${sanitizeFilename(variant.kind)}.mp4`)
|
|
27271
27287
|
}))
|
|
27272
|
-
}))
|
|
27288
|
+
})),
|
|
27289
|
+
...outputs.creativeVariants?.length ? {
|
|
27290
|
+
creativeVariants: outputs.creativeVariants.map((child) => ({
|
|
27291
|
+
...child,
|
|
27292
|
+
...child.outputs ? {
|
|
27293
|
+
outputs: proxifyOutputs(child.outputs, proxyBaseUrl)
|
|
27294
|
+
} : {}
|
|
27295
|
+
}))
|
|
27296
|
+
} : {}
|
|
27273
27297
|
};
|
|
27274
27298
|
}
|
|
27275
27299
|
__name(proxifyOutputs, "proxifyOutputs");
|
|
@@ -27279,6 +27303,37 @@ function sanitizeFilename(s) {
|
|
|
27279
27303
|
__name(sanitizeFilename, "sanitizeFilename");
|
|
27280
27304
|
async function fetchTaskOutputs(api, taskId, options) {
|
|
27281
27305
|
const raw = await api.getJson(`/v1/results/${encodeURIComponent(taskId)}?signedUrls=true`, options);
|
|
27306
|
+
const creativeVariants = (raw.creativeVariants ?? []).flatMap((child) => {
|
|
27307
|
+
const identity = CreativeVariantIdentity.safeParse(child);
|
|
27308
|
+
if (!identity.success || identity.data.sourceTaskId !== taskId) return [];
|
|
27309
|
+
const { error, ...details } = identity.data;
|
|
27310
|
+
return [
|
|
27311
|
+
{
|
|
27312
|
+
...details,
|
|
27313
|
+
...error ? {
|
|
27314
|
+
error: error.slice(0, 1e3)
|
|
27315
|
+
} : {},
|
|
27316
|
+
nextAction: {
|
|
27317
|
+
tool: "get_task_status",
|
|
27318
|
+
arguments: {
|
|
27319
|
+
taskId: details.variantTaskId
|
|
27320
|
+
}
|
|
27321
|
+
},
|
|
27322
|
+
...details.status === "done" ? {
|
|
27323
|
+
outputs: projectTaskOutputs(child, details.variantTaskId)
|
|
27324
|
+
} : {}
|
|
27325
|
+
}
|
|
27326
|
+
];
|
|
27327
|
+
});
|
|
27328
|
+
return {
|
|
27329
|
+
...projectTaskOutputs(raw, taskId),
|
|
27330
|
+
...creativeVariants.length ? {
|
|
27331
|
+
creativeVariants
|
|
27332
|
+
} : {}
|
|
27333
|
+
};
|
|
27334
|
+
}
|
|
27335
|
+
__name(fetchTaskOutputs, "fetchTaskOutputs");
|
|
27336
|
+
function projectTaskOutputs(raw, taskId) {
|
|
27282
27337
|
const videos = (raw.videoGenerators ?? []).map((vg) => {
|
|
27283
27338
|
const variants2 = (vg.variants ?? []).filter((v) => Boolean(v.kind) && Boolean(v.url)).map((v) => ({
|
|
27284
27339
|
kind: v.kind,
|
|
@@ -27363,7 +27418,7 @@ async function fetchTaskOutputs(api, taskId, options) {
|
|
|
27363
27418
|
adCopy: typeof raw.adCreative?.adCopy === "string" && raw.adCreative.adCopy.length ? raw.adCreative.adCopy : void 0
|
|
27364
27419
|
};
|
|
27365
27420
|
}
|
|
27366
|
-
__name(
|
|
27421
|
+
__name(projectTaskOutputs, "projectTaskOutputs");
|
|
27367
27422
|
function renderOutputsMarkdown(outputs) {
|
|
27368
27423
|
const parts = [];
|
|
27369
27424
|
parts.push(`\u2705 **Tu tarea est\xE1 lista** \u2014 [Abrir en Product Maker](${outputs.webappUrl})`);
|
|
@@ -27405,6 +27460,18 @@ function renderOutputsMarkdown(outputs) {
|
|
|
27405
27460
|
}
|
|
27406
27461
|
}
|
|
27407
27462
|
}
|
|
27463
|
+
for (const child of outputs.creativeVariants ?? []) {
|
|
27464
|
+
const label = child.kind === "image" ? "imagen" : child.kind;
|
|
27465
|
+
parts.push(`
|
|
27466
|
+
### Variante de ${label}`);
|
|
27467
|
+
if (child.status === "done" && child.outputs) {
|
|
27468
|
+
parts.push(renderOutputsMarkdown(child.outputs));
|
|
27469
|
+
} else if (child.status === "error") {
|
|
27470
|
+
parts.push(escapeMarkdownText(child.error ?? "No se pudo entregar esta variante."));
|
|
27471
|
+
} else {
|
|
27472
|
+
parts.push("La variante sigue gener\xE1ndose. Consulta su estado antes de iniciar otra.");
|
|
27473
|
+
}
|
|
27474
|
+
}
|
|
27408
27475
|
return parts.join("\n");
|
|
27409
27476
|
}
|
|
27410
27477
|
__name(renderOutputsMarkdown, "renderOutputsMarkdown");
|
|
@@ -27448,55 +27515,6 @@ __name(outputGifs, "outputGifs");
|
|
|
27448
27515
|
var PendingPresentationSchema = PendingUserActionSchema;
|
|
27449
27516
|
var VideoScriptSchema = GetVideoScriptForReviewResponse;
|
|
27450
27517
|
|
|
27451
|
-
// src/tools/conversational-review-format.ts
|
|
27452
|
-
function escapeMarkdownText(value) {
|
|
27453
|
-
return value.replace(/\\/g, "\\\\").replace(/([`*_{}[\]()<>#+.!|>])/g, "\\$1").replace(/[\r\n\u2028\u2029]+/g, " ");
|
|
27454
|
-
}
|
|
27455
|
-
__name(escapeMarkdownText, "escapeMarkdownText");
|
|
27456
|
-
function trustedPreviewUrl(raw) {
|
|
27457
|
-
if (/[\u0000-\u001f\u007f]/.test(raw)) return null;
|
|
27458
|
-
try {
|
|
27459
|
-
const url = new URL(raw);
|
|
27460
|
-
if (url.username || url.password) return null;
|
|
27461
|
-
const hostname = url.hostname.toLowerCase();
|
|
27462
|
-
const productMakerHost = hostname === "productmaker.app" || hostname.endsWith(".productmaker.app");
|
|
27463
|
-
const localHost = hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
|
|
27464
|
-
if (url.protocol === "https:" && productMakerHost && (!url.port || url.port === "443")) {
|
|
27465
|
-
return url.toString().replace(/\(/g, "%28").replace(/\)/g, "%29");
|
|
27466
|
-
}
|
|
27467
|
-
if (url.protocol === "http:" && localHost) {
|
|
27468
|
-
return url.toString().replace(/\(/g, "%28").replace(/\)/g, "%29");
|
|
27469
|
-
}
|
|
27470
|
-
return null;
|
|
27471
|
-
} catch {
|
|
27472
|
-
return null;
|
|
27473
|
-
}
|
|
27474
|
-
}
|
|
27475
|
-
__name(trustedPreviewUrl, "trustedPreviewUrl");
|
|
27476
|
-
function renderPreview(preview2, index) {
|
|
27477
|
-
const label = escapeMarkdownText(preview2.label);
|
|
27478
|
-
const url = trustedPreviewUrl(preview2.previewUrl);
|
|
27479
|
-
return [
|
|
27480
|
-
`### Foto ${index + 1}: ${label}`,
|
|
27481
|
-
...preview2.view ? [
|
|
27482
|
-
`- **Vista:** ${escapeMarkdownText(preview2.view)}`
|
|
27483
|
-
] : [],
|
|
27484
|
-
...url ? [
|
|
27485
|
-
``
|
|
27486
|
-
] : [
|
|
27487
|
-
"- Vista previa externa bloqueada por seguridad. \xC1brela desde ProductMaker Web."
|
|
27488
|
-
]
|
|
27489
|
-
];
|
|
27490
|
-
}
|
|
27491
|
-
__name(renderPreview, "renderPreview");
|
|
27492
|
-
function formatCredits(creditCents) {
|
|
27493
|
-
return new Intl.NumberFormat("es-CO", {
|
|
27494
|
-
minimumFractionDigits: creditCents % 100 === 0 ? 0 : 2,
|
|
27495
|
-
maximumFractionDigits: 2
|
|
27496
|
-
}).format(creditCents / 100);
|
|
27497
|
-
}
|
|
27498
|
-
__name(formatCredits, "formatCredits");
|
|
27499
|
-
|
|
27500
27518
|
// src/tools/conversational-review.ts
|
|
27501
27519
|
var PRODUCT_REFERENCE_LABELS = {
|
|
27502
27520
|
same_product: "Es el mismo producto",
|
|
@@ -27826,29 +27844,29 @@ ${parsed.data.error ? `${escapeMarkdownText(parsed.data.error)}
|
|
|
27826
27844
|
__name(renderVideoScriptMarkdown, "renderVideoScriptMarkdown");
|
|
27827
27845
|
|
|
27828
27846
|
// src/tools/media-presentation.ts
|
|
27829
|
-
import { z as
|
|
27830
|
-
var HttpsPresentationUrlSchema =
|
|
27847
|
+
import { z as z119 } from "zod";
|
|
27848
|
+
var HttpsPresentationUrlSchema = z119.string().url().max(2048).refine((value) => new URL(value).protocol === "https:");
|
|
27831
27849
|
var ProductMakerPreviewUrlSchema = HttpsPresentationUrlSchema.refine((value) => {
|
|
27832
27850
|
const hostname = new URL(value).hostname.toLowerCase();
|
|
27833
27851
|
return hostname === "productmaker.app" || hostname.endsWith(".productmaker.app");
|
|
27834
27852
|
}, "preview URL must be owned by ProductMaker");
|
|
27835
|
-
var positiveIntAtMost = /* @__PURE__ */ __name((maximum) =>
|
|
27836
|
-
var PresentationImageSchema =
|
|
27837
|
-
kind:
|
|
27853
|
+
var positiveIntAtMost = /* @__PURE__ */ __name((maximum) => z119.number().int().positive().max(maximum), "positiveIntAtMost");
|
|
27854
|
+
var PresentationImageSchema = z119.object({
|
|
27855
|
+
kind: z119.literal("image"),
|
|
27838
27856
|
url: HttpsPresentationUrlSchema,
|
|
27839
|
-
mimeType:
|
|
27857
|
+
mimeType: z119.enum([
|
|
27840
27858
|
"image/jpeg",
|
|
27841
27859
|
"image/png"
|
|
27842
27860
|
]),
|
|
27843
27861
|
byteSize: positiveIntAtMost(5 * 1024 * 1024),
|
|
27844
27862
|
width: positiveIntAtMost(16384),
|
|
27845
27863
|
height: positiveIntAtMost(16384),
|
|
27846
|
-
alt:
|
|
27864
|
+
alt: z119.string().trim().min(1).max(240)
|
|
27847
27865
|
}).strict();
|
|
27848
27866
|
var McpMediaPresentationSchema = PresentationImageSchema;
|
|
27849
|
-
var GalleryImageSchema =
|
|
27867
|
+
var GalleryImageSchema = z119.object({
|
|
27850
27868
|
url: ProductMakerPreviewUrlSchema,
|
|
27851
|
-
alt:
|
|
27869
|
+
alt: z119.string().trim().min(1).max(240)
|
|
27852
27870
|
});
|
|
27853
27871
|
var MCP_GALLERY_IMAGE_MAX_BYTES = 10 * 1024 * 1024;
|
|
27854
27872
|
async function imageBlocks(image, transport) {
|
|
@@ -27905,12 +27923,12 @@ async function buildMcpMediaPresentationContent(rawPresentation, transport = "ht
|
|
|
27905
27923
|
];
|
|
27906
27924
|
}
|
|
27907
27925
|
__name(buildMcpMediaPresentationContent, "buildMcpMediaPresentationContent");
|
|
27908
|
-
var OwnedImagePreviewSchema =
|
|
27926
|
+
var OwnedImagePreviewSchema = z119.object({
|
|
27909
27927
|
url: HttpsPresentationUrlSchema.refine((value) => {
|
|
27910
27928
|
const url = new URL(value);
|
|
27911
27929
|
return !url.username && !url.password && !isPrivateHost(url.hostname);
|
|
27912
27930
|
}, "Preview URL must be public HTTPS without credentials"),
|
|
27913
|
-
alt:
|
|
27931
|
+
alt: z119.string().trim().min(1).max(240)
|
|
27914
27932
|
});
|
|
27915
27933
|
async function buildMcpImagePreviewContent(rawPreview, transport = "http") {
|
|
27916
27934
|
const preview2 = OwnedImagePreviewSchema.safeParse(rawPreview);
|
|
@@ -27993,7 +28011,7 @@ async function buildMcpImageGalleryContent(rawItems, transport = "http") {
|
|
|
27993
28011
|
__name(buildMcpImageGalleryContent, "buildMcpImageGalleryContent");
|
|
27994
28012
|
|
|
27995
28013
|
// src/tools/animated-video.ts
|
|
27996
|
-
import { z as
|
|
28014
|
+
import { z as z120 } from "zod";
|
|
27997
28015
|
|
|
27998
28016
|
// src/tools/paid-confirmation.ts
|
|
27999
28017
|
function describeMarketStudyChoice(enabled) {
|
|
@@ -28242,29 +28260,29 @@ function hookVariantsLabel(count) {
|
|
|
28242
28260
|
return count === 1 ? "1 versi\xF3n del gancho" : `${count} versiones del gancho`;
|
|
28243
28261
|
}
|
|
28244
28262
|
__name(hookVariantsLabel, "hookVariantsLabel");
|
|
28245
|
-
var DurationInput =
|
|
28246
|
-
var CreateAnimatedVideoInput =
|
|
28247
|
-
action:
|
|
28263
|
+
var DurationInput = z120.union(MOTION_GRAPHICS_DURATIONS.map((d) => z120.literal(d)));
|
|
28264
|
+
var CreateAnimatedVideoInput = z120.object({
|
|
28265
|
+
action: z120.enum([
|
|
28248
28266
|
"prepare",
|
|
28249
28267
|
"status",
|
|
28250
28268
|
"cancel",
|
|
28251
28269
|
"generate"
|
|
28252
28270
|
]).default("prepare").describe("prepare inicia una captura gratuita; status consulta websiteCaptureId; cancel la cancela; generate requiere captura ready y confirmaci\xF3n expl\xEDcita del usuario despu\xE9s de mostrar vista previa y precio."),
|
|
28253
|
-
websiteCaptureId:
|
|
28254
|
-
generationRequestId:
|
|
28255
|
-
confirmed:
|
|
28271
|
+
websiteCaptureId: z120.string().uuid().optional().describe("ID de la captura preparada. Obligatorio para status/cancel/generate; no inventarlo."),
|
|
28272
|
+
generationRequestId: z120.string().uuid().optional().describe("Identidad opcional de una generaci\xF3n confirmada. Repite el mismo UUID al recuperar una respuesta perdida; usa otro \xFAnicamente cuando el usuario pida y confirme otro video, nunca por un error de transporte."),
|
|
28273
|
+
confirmed: z120.boolean().optional().describe("Solo true despu\xE9s de que el usuario confirme esta captura, formato, duraci\xF3n, idioma y precio. Obligatorio para generate; preparar no genera ni cobra."),
|
|
28256
28274
|
// Plain text, not `.url()`: users type «cal.com», and the web accepts it.
|
|
28257
28275
|
// normalizeWebAddress (shared with the web) adds https:// and refuses
|
|
28258
28276
|
// anything that is not a public http(s) address.
|
|
28259
|
-
landingUrl:
|
|
28277
|
+
landingUrl: z120.string().trim().min(1).optional().describe("Enlace p\xFAblico de la p\xE1gina del servicio, como lo dio el usuario (\xABcal.com\xBB o \xABhttps://cal.com\xBB). El video sale de lo que muestra esa p\xE1gina: su marca, colores y mensajes."),
|
|
28260
28278
|
format: MotionGraphicsFormatSchema.optional().describe('Formato: "vertical" (9:16, Reels/TikTok), "square" (1:1, feed) u "horizontal" (16:9, YouTube/web). Si el usuario no lo dijo, PREG\xDANTALE.'),
|
|
28261
28279
|
durationSec: DurationInput.optional().describe(`Duraci\xF3n en segundos: ${MOTION_GRAPHICS_DURATIONS.join(", ")}. Fija el precio (ver la descripci\xF3n de la herramienta). Si el usuario no la dijo, PREG\xDANTALE.`),
|
|
28262
28280
|
language: MotionGraphicsLanguageSchema.optional().describe('Idioma de los textos del video: "es", "en" o "pt".'),
|
|
28263
28281
|
videoQuality: MotionGraphicsVideoQualitySchema.default(DEFAULT_MOTION_GRAPHICS_VIDEO_QUALITY).describe('Calidad IA: "economy" (econ\xF3mica) o "pro" (alta, por defecto). Afecta el precio de los clips IA.'),
|
|
28264
28282
|
videoResolution: MotionGraphicsVideoResolutionSchema.default(DEFAULT_MOTION_GRAPHICS_VIDEO_RESOLUTION).describe('Resoluci\xF3n: "480p" (por defecto), "720p" o "1080p". 1080p solo est\xE1 disponible con videoQuality="pro".'),
|
|
28265
|
-
notes:
|
|
28283
|
+
notes: z120.string().trim().max(MOTION_GRAPHICS_NOTES_MAX_CHARS).optional().describe("Opcional. Idea creativa, escenarios, acciones, di\xE1logo, voz o m\xFAsica en lenguaje natural. El director puede hacer solo motion graphics, escenas reales o escenas imposibles seg\xFAn la idea; las frases gu\xEDan el guion sin garantizar reproducci\xF3n exacta."),
|
|
28266
28284
|
hookVariants: MotionGraphicsHookVariantsSchema.optional().describe(`Opcional. Versiones del gancho: el mismo video con distintas aperturas para probar cu\xE1l funciona mejor, de 1 a ${MOTION_GRAPHICS_HOOK_VARIANTS_MAX} (por defecto 1). Cada versi\xF3n extra tiene precio (ver la descripci\xF3n de la herramienta); \xFAsalo solo si el usuario lo pide.`),
|
|
28267
|
-
music:
|
|
28285
|
+
music: z120.boolean().optional().describe("Opcional. M\xFAsica y efectos dirigidos seg\xFAn el negocio y el video (por defecto true), con una copia adicional solo con voces. false entrega solo voces, sin m\xFAsica ni efectos a\xF1adidos ni el cargo de m\xFAsica. \xDAsalo solo si el usuario lo pide.")
|
|
28268
28286
|
}).strict();
|
|
28269
28287
|
function captureNextAction(capture) {
|
|
28270
28288
|
if (capture.status === "ready") return "Muestra la vista previa al usuario y confirma formato, duraci\xF3n, idioma, calidad IA, resoluci\xF3n y precio. Solo despu\xE9s llama create_animated_video con action=generate, este websiteCaptureId y confirmed=true.";
|
|
@@ -28314,49 +28332,49 @@ var FORMAT_LABELS = {
|
|
|
28314
28332
|
square: "cuadrado 1:1",
|
|
28315
28333
|
horizontal: "horizontal 16:9"
|
|
28316
28334
|
};
|
|
28317
|
-
var AnimatedVideoResultSchema =
|
|
28318
|
-
status:
|
|
28335
|
+
var AnimatedVideoResultSchema = z120.object({
|
|
28336
|
+
status: z120.enum([
|
|
28319
28337
|
"pending",
|
|
28320
28338
|
"done",
|
|
28321
28339
|
"error"
|
|
28322
28340
|
]),
|
|
28323
|
-
serviceMode:
|
|
28324
|
-
finalMp4Url:
|
|
28325
|
-
adCopy:
|
|
28326
|
-
adCopies:
|
|
28327
|
-
error:
|
|
28328
|
-
motionGraphics:
|
|
28341
|
+
serviceMode: z120.literal("motion_graphics"),
|
|
28342
|
+
finalMp4Url: z120.string().optional(),
|
|
28343
|
+
adCopy: z120.string().optional(),
|
|
28344
|
+
adCopies: z120.array(z120.string()).optional(),
|
|
28345
|
+
error: z120.string().optional(),
|
|
28346
|
+
motionGraphics: z120.object({
|
|
28329
28347
|
stage: MotionGraphicsStageSchema,
|
|
28330
28348
|
format: MotionGraphicsFormatSchema,
|
|
28331
|
-
durationSec:
|
|
28332
|
-
width:
|
|
28333
|
-
height:
|
|
28349
|
+
durationSec: z120.number(),
|
|
28350
|
+
width: z120.number().optional(),
|
|
28351
|
+
height: z120.number().optional(),
|
|
28334
28352
|
language: MotionGraphicsLanguageSchema.optional(),
|
|
28335
28353
|
videoQuality: MotionGraphicsVideoQualitySchema.optional().catch(void 0),
|
|
28336
28354
|
videoResolution: MotionGraphicsVideoResolutionSchema.optional().catch(void 0),
|
|
28337
|
-
queuedAt:
|
|
28338
|
-
jobsAhead:
|
|
28339
|
-
stageStartedAt:
|
|
28340
|
-
renderProgress:
|
|
28355
|
+
queuedAt: z120.string().optional(),
|
|
28356
|
+
jobsAhead: z120.number().int().nonnegative().optional(),
|
|
28357
|
+
stageStartedAt: z120.string().optional(),
|
|
28358
|
+
renderProgress: z120.number().optional(),
|
|
28341
28359
|
// AI clip fields (absent on a video paid before clips, or from an API
|
|
28342
28360
|
// that predates them). Lenient: an unreadable value is dropped
|
|
28343
28361
|
// instead of hiding the status.
|
|
28344
|
-
clipCount:
|
|
28345
|
-
clipsUsed:
|
|
28346
|
-
clipPriceCents:
|
|
28347
|
-
clipsRefunded:
|
|
28362
|
+
clipCount: z120.number().int().nonnegative().optional().catch(void 0),
|
|
28363
|
+
clipsUsed: z120.number().int().nonnegative().optional().catch(void 0),
|
|
28364
|
+
clipPriceCents: z120.number().finite().nonnegative().optional().catch(void 0),
|
|
28365
|
+
clipsRefunded: z120.number().int().nonnegative().optional().catch(void 0),
|
|
28348
28366
|
// Hook versions (absent from an API or a video before them): the
|
|
28349
28367
|
// count ordered and, once done, the signed URLs of the EXTRA versions
|
|
28350
28368
|
// (hook 2, hook 3); `finalMp4Url` is hook 1.
|
|
28351
|
-
hookVariants:
|
|
28352
|
-
cleanVideoUrl:
|
|
28353
|
-
cleanVariantUrls:
|
|
28354
|
-
variantUrls:
|
|
28369
|
+
hookVariants: z120.number().int().min(1).max(MOTION_GRAPHICS_HOOK_VARIANTS_MAX).optional().catch(void 0),
|
|
28370
|
+
cleanVideoUrl: z120.string().url().optional().catch(void 0),
|
|
28371
|
+
cleanVariantUrls: z120.array(z120.string().url()).max(MOTION_GRAPHICS_HOOK_VARIANTS_MAX - 1).optional().catch(void 0),
|
|
28372
|
+
variantUrls: z120.array(z120.string().min(1)).max(MOTION_GRAPHICS_HOOK_VARIANTS_MAX - 1).optional().catch(void 0),
|
|
28355
28373
|
// Extra hook versions given back, as the task recorded it once the
|
|
28356
28374
|
// refunds landed (absent until then, and from an API before it).
|
|
28357
|
-
variantsRefunded:
|
|
28358
|
-
activity:
|
|
28359
|
-
previewUrl:
|
|
28375
|
+
variantsRefunded: z120.number().int().nonnegative().optional().catch(void 0),
|
|
28376
|
+
activity: z120.array(MotionGraphicsActivitySchema).optional().catch(void 0),
|
|
28377
|
+
previewUrl: z120.string().optional()
|
|
28360
28378
|
}).passthrough()
|
|
28361
28379
|
}).passthrough();
|
|
28362
28380
|
function parseAnimatedVideoResult(value) {
|
|
@@ -28659,10 +28677,10 @@ function registerAnimatedVideoTools(server, api) {
|
|
|
28659
28677
|
__name(registerAnimatedVideoTools, "registerAnimatedVideoTools");
|
|
28660
28678
|
|
|
28661
28679
|
// src/tools/winning-product-image.ts
|
|
28662
|
-
import { z as
|
|
28663
|
-
var WinnerReferenceInput =
|
|
28664
|
-
runId:
|
|
28665
|
-
candidateSourceId:
|
|
28680
|
+
import { z as z121 } from "zod";
|
|
28681
|
+
var WinnerReferenceInput = z121.object({
|
|
28682
|
+
runId: z121.string().uuid(),
|
|
28683
|
+
candidateSourceId: z121.string().trim().min(1).max(160)
|
|
28666
28684
|
}).strict().describe("Referencia opaca de un producto devuelto por find_winning_products/get_product_research_run.");
|
|
28667
28685
|
async function resolveWinnerImages(api, winnerReference, images) {
|
|
28668
28686
|
if (!winnerReference) return images;
|
|
@@ -28699,62 +28717,62 @@ var createProductTaskSingleOutputDescription = renderCreateProductTaskAvoidWhenF
|
|
|
28699
28717
|
var CREATE_SERVICE_VIDEO_ON_MCP = PRODUCTMAKER_MCP_CAPABILITY_NAMES.includes("create_service_video");
|
|
28700
28718
|
var listTasksGuidance = getProductMakerCapabilityModelGuidance("list_tasks");
|
|
28701
28719
|
var editTaskDraftGuidance = getProductMakerCapabilityModelGuidance("edit_task_draft");
|
|
28702
|
-
var CreateProductTaskInput =
|
|
28720
|
+
var CreateProductTaskInput = z122.object({
|
|
28703
28721
|
images: ImagesInput.optional().describe("1\u20135 fotos del mismo producto. Omitir \xFAnicamente cuando projectId apunta a un proyecto propio con imagen guardada."),
|
|
28704
28722
|
winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
|
|
28705
|
-
projectId:
|
|
28706
|
-
productUrl:
|
|
28723
|
+
projectId: z122.string().uuid().optional().describe("Opcional. Proyecto guiado propio. Permite continuar sin volver a subir la imagen guardada; nunca evita cr\xE9ditos, cuotas ni confirmaciones."),
|
|
28724
|
+
productUrl: z122.string().url().optional().describe("Opcional. URL de la p\xE1gina del producto (Shopify, AliExpress, Amazon, etc.) para enriquecer el contexto. Si se omite, la IA infiere todo desde la imagen."),
|
|
28707
28725
|
language: Lang.describe('C\xF3digo de idioma para el contenido generado. Ejemplos: "es", "en", "pt". REQUERIDO \u2014 si el usuario no lo especific\xF3, PREG\xDANTALE antes de invocar. NUNCA infieras desde el contexto del chat ni asumas "es" por default.'),
|
|
28708
28726
|
country: Country.describe('C\xF3digo ISO del pa\xEDs objetivo. Ejemplos: "CO", "MX", "US", "AR". Define moneda, m\xE9todos de pago locales y tono. REQUERIDO \u2014 si el usuario no lo especific\xF3, PREG\xDANTALE antes de invocar. NUNCA infieras desde el contexto del chat.'),
|
|
28709
|
-
price:
|
|
28710
|
-
compareAtPrice:
|
|
28711
|
-
offer:
|
|
28712
|
-
paymentMethods:
|
|
28713
|
-
productContext:
|
|
28714
|
-
productLabel:
|
|
28727
|
+
price: z122.string().min(1).max(120).optional().describe('Precio que se mostrar\xE1 en la landing y video. Formato libre \u2014 ej. "$89.900", "USD 29.99", "MXN 599". Opcional pero MUY IMPACTANTE: si el usuario no lo mencion\xF3, PREG\xDANTALE antes de invocar. Si te dice "t\xFA elige", om\xEDtelo y el backend sugiere uno.'),
|
|
28728
|
+
compareAtPrice: z122.string().min(1).max(120).optional().describe('Opcional. Precio anterior para comunicar un descuento real en landing e im\xE1genes. Ej. "$129.000" cuando price="$89.900".'),
|
|
28729
|
+
offer: z122.string().min(1).max(240).optional().describe('Oferta o promoci\xF3n a destacar. Ej. "2x1", "Env\xEDo gratis hoy", "50% OFF". Opcional pero MUY IMPACTANTE: si el usuario no lo mencion\xF3, PREG\xDANTALE antes de invocar (es v\xE1lido que diga "sin oferta"). Si te dice "t\xFA elige", om\xEDtelo.'),
|
|
28730
|
+
paymentMethods: z122.string().min(1).max(240).optional().describe('Opcional. M\xE9todos de pago que puede mostrar la landing. Ej. "Tarjeta, PSE, Nequi, Contraentrega". Si se omite, la landing no muestra m\xE9todos de pago.'),
|
|
28731
|
+
productContext: z122.string().max(PRODUCT_CONTEXT_MAX_CHARS).optional().describe("Opcional. Informacion adicional del producto que la IA debe usar como contexto prioritario: uso real, comprador, restricciones, diferenciadores o direccion creativa. No reemplaza la investigacion de competencia; si hay competencia, guia el primer angulo y los outputs no deben contradecirlo."),
|
|
28732
|
+
productLabel: z122.string().trim().max(80).optional().describe('Opcional. Qu\xE9 es el producto, en pocas palabras (ej. "quita pelusas para ropa"). Es AUTORITATIVO: si lo env\xEDas, la IA usa esta identidad y no la reemplaza por otra categor\xEDa. Si lo omites, la IA detecta el producto desde la imagen.'),
|
|
28715
28733
|
videoPreset: VideoPresetEnum.default("auto").describe('Opcional. Tipo/narrativa del video \u2014 \xFAnico campo de "estilo" que el usuario controla. Default "auto" (la IA escoge tras analizar el producto). Todos los presets funcionan a 15s (single_call) y 30s (Multiescena); "problem_solution" en single_call abre sin el producto y el producto entra por referencia en su beat de soluci\xF3n. Opciones: "auto", "ugc_dynamic" (review con experiencia y prueba), "ugc_how_to" (tutorial con pasos y resultado visible), "ugc_unboxing_chaos" (apertura y primera prueba), "problem_solution" (problema concreto, producto como soluci\xF3n y CTA), "product_showcase" (producto ejecutando una funci\xF3n real), "wearable_showcase" (prenda o accesorio modelado), "cinematic" (TV spot con receta cinematogr\xE1fica), "wild_card" (idea imposible: un truco visual que en la vida real no podr\xEDa pasar, y al cierre la invitaci\xF3n a comprar), "pixar_problem" (problema animado 3D), "pixar_sassy" (producto que habla). Si el usuario pide algo fuera de esta lista, p\xEDdele una opci\xF3n v\xE1lida.'),
|
|
28716
28734
|
animationStyle: AnimationStyleEnum.optional().describe('Opcional. Estilo visual SOLO para presets animados ("pixar_problem" o "pixar_sassy") \u2014 la API lo rechaza con cualquier otro preset. Opciones: "pixar_3d" (default, look 3D de pel\xEDcula animada), "claymation" (plastilina stop-motion artesanal), "wes_anderson" (tableau sim\xE9trico pastel), "sci_fi" (futurista con HUDs y ne\xF3n), "realista" (fotorrealista, fiel al producto). Si el usuario pide un look animado sin nombrar el estilo, omite el campo.'),
|
|
28717
|
-
durationSeconds:
|
|
28718
|
-
|
|
28719
|
-
|
|
28735
|
+
durationSeconds: z122.union([
|
|
28736
|
+
z122.literal(15),
|
|
28737
|
+
z122.literal(30)
|
|
28720
28738
|
]).default(15).describe("Opcional. Duraci\xF3n objetivo del video: 15s (single_call, default) o 30s (Multiescena, aproximadamente 30s y facturado por escena)."),
|
|
28721
|
-
pauseForAngleReview:
|
|
28722
|
-
aiDecidesAll:
|
|
28739
|
+
pauseForAngleReview: z122.boolean().optional().describe("Compatibilidad heredada. MCP deriva esta pausa de aiDecidesAll: manual siempre pausa y autom\xE1tico siempre la omite. No uses este campo para saltar reviews."),
|
|
28740
|
+
aiDecidesAll: z122.boolean().optional().describe("Mapea el toggle web \u201CDejar que la IA decida todo\u201D. Si true, ProductMaker omite reviews. Act\xEDvalo \xFAnicamente cuando el usuario lo pida expl\xEDcitamente. Omitido/false = reviews conversacionales."),
|
|
28723
28741
|
videoTier: VideoTierEnum.optional().describe('Opcional. Estilo del video. "basic" = "Realista" para 15s; al pedir durationSeconds=30 el sistema selecciona internamente Multiescena. No se expone el tier interno directamente.'),
|
|
28724
28742
|
videoStructure: VideoStructureEnum.default("single_take").describe('Opcional. Formato: "single_take" = Un solo clip (generado completo; puede incluir cambios de plano) o "multi_scene" = Multiescena. Default: single_take.'),
|
|
28725
28743
|
videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El proveedor se elige internamente. Default: economy.'),
|
|
28726
28744
|
videoResolution: VideoResolutionEnum.optional().describe('Opcional. Resoluci\xF3n del render. En la web se pregunta "\xBFResoluci\xF3n del video?". "480p" = excelente calidad y m\xE1s econ\xF3mico (RECOMENDADO, default si se omite); "720p" = m\xE1xima nitidez, entre 3% y 15% m\xE1s caro seg\xFAn formato y tier. Si el usuario no menciona resoluci\xF3n, OMITE este campo (el backend usa 480p).'),
|
|
28727
|
-
videoAngleCount:
|
|
28745
|
+
videoAngleCount: z122.number().int().min(1).max(3).optional().describe("Cantidad de videos a renderizar: 1, 2 o 3. REQUERIDO cuando outputs incluye video (o se omite outputs, cuyo default incluye video); om\xEDtelo s\xF3lo cuando no se generar\xE1 video. Preg\xFAntalo incluso con aiDecidesAll=true porque cambia el costo."),
|
|
28728
28746
|
angleNarratives: PublicNarrativeStyleEnum.array().max(3).optional().describe('Opcional. Narrativa POR \xC1NGULO (posicional). Valores actuales: "review", "ugc_how_to", "ugc_unboxing_chaos", "problem_product_cta" (problema concreto, producto como soluci\xF3n y CTA), "product_showcase", "wearable_showcase", "cinematic", "wild_card", "animated_problem_pixar", "sassy_product_pixar", "market" (narrativa an\xE1lisis de mercado: adapta el video a los patrones ganadores estudiados de la competencia; requiere competitorScanEnabled: true). angleNarratives[i] fuerza la narrativa del \xE1ngulo i; las posiciones restantes las elige la IA. La lista no puede superar videoAngleCount.'),
|
|
28729
|
-
outputs:
|
|
28747
|
+
outputs: z122.array(z122.enum([
|
|
28730
28748
|
"landing",
|
|
28731
28749
|
"video",
|
|
28732
28750
|
"image"
|
|
28733
28751
|
])).min(1).max(3).optional().describe(`Opcional. Qu\xE9 outputs generar. Default: todos ["landing","video","image"]. Para 2 outputs: ["landing","image"] (sin video), ["video","image"] (sin landing), ["landing","video"] (sin imagen). ${createProductTaskSingleOutputDescription}`),
|
|
28734
|
-
includeInitialLandingGif:
|
|
28735
|
-
competitorScanEnabled:
|
|
28752
|
+
includeInitialLandingGif: z122.boolean().optional().describe("Opcional. En nuevas landings cl\xE1sicas habilitadas, omitirlo incluye el primer GIF del producto y su coste en el total. Env\xEDa false si el usuario lo excluye: no se genera ni se reserva su coste. Conserva la elecci\xF3n al confirmar y al reintentar."),
|
|
28753
|
+
competitorScanEnabled: z122.boolean().optional().describe("Opcional. Default false: omitirlo significa SIN estudio de mercado. Antes de crear, llama estimate_market_study_cost con kind=product_task, muestra al usuario el costo con y sin estudio y preg\xFAntale si lo quiere; env\xEDa true solo si lo acepta (o si solicita la narrativa an\xE1lisis de mercado). Si la tarea incluye video, true analiza anuncios de la competencia y desbloquea la narrativa an\xE1lisis de mercado; si el estudio no encuentra datos suficientes, degrada al planner cl\xE1sico."),
|
|
28736
28754
|
generateAiEdit: AiEditRequestSchema.optional().describe('Opcional. Pide la Edici\xF3n con IA: una pasada que a\xF1ade texto, efectos y m\xFAsica sobre cada video entregado (variante with_ai_edit; se cobra al entregar, por video). Nivel: "economy" (Econ\xF3mica, Sonnet 5.5, m\xE1s barata) o "pro" (Opus 5.5, mejor calidad, ~10 min). true equivale a "pro"; false/omitido = sin edici\xF3n.'),
|
|
28737
|
-
replicateWinnerWhenFound:
|
|
28738
|
-
brandId:
|
|
28739
|
-
actorId:
|
|
28755
|
+
replicateWinnerWhenFound: z122.boolean().optional().describe("Conserva la preferencia de copiar un ganador si existe. false estudia el mercado sin reemplazar un \xE1ngulo por el anuncio ganador. No a\xF1ade una pregunta obligatoria."),
|
|
28756
|
+
brandId: z122.string().uuid().optional().describe("Opcional. ID de una marca del usuario; si se env\xEDa, el sistema usa su voz, colores y persona para enriquecer los outputs generados."),
|
|
28757
|
+
actorId: z122.string().trim().min(1).max(120).optional().describe("Opcional. ID de un personaje guardado (usa list_actors para verlos). Si lo env\xEDas, su foto y su voz mandan sobre la descripci\xF3n de texto."),
|
|
28740
28758
|
creativeGender: CreativeGenderEnum.optional().describe('Opcional. QUI\xC9N APARECE EN PANTALLA en todos los creativos de la task: el presentador del video, las personas fotografiadas en la landing y la persona del anuncio. NO es la voz. M\xE1ndalo en cuanto el usuario lo diga en cualquier momento de la conversaci\xF3n y con cualquier redacci\xF3n ("quiero una mujer", "que salga un hombre", "esto es para hombres"): si no lo mandas, el g\xE9nero lo inventa la IA y el usuario recibe lo contrario de lo que pidi\xF3 sin ning\xFAn aviso. "mixed" solo cuando pida expl\xEDcitamente ambos. Si adem\xE1s mandas actorId, el personaje guardado manda sobre este campo.'),
|
|
28741
|
-
creativeDirection:
|
|
28742
|
-
headline:
|
|
28743
|
-
subheadline:
|
|
28759
|
+
creativeDirection: z122.string().max(500).optional().describe('Opcional. Direcci\xF3n creativa en texto libre (colores, mood, estilo) que aplica a los outputs de IMAGEN y LANDING (no al video \u2014 el estilo/ambiente del video se dirige con scriptNotes). M\xC1XIMA PRIORIDAD: anula marca, colores y estilo por defecto. Ej. "amarillo y azul, minimalista". M\xE1x 500 caracteres.'),
|
|
28760
|
+
headline: z122.string().max(120).optional().describe("Opcional. Titular EXACTO a renderizar. Se imprime tal cual: la IA no lo reescribe, no lo acorta y no lo traduce. Se aplica a las IM\xC1GENES y a la portada de la landing de esta task (el video no lo usa; para el video usa scriptNotes). \xDAsalo cuando el copy es de marca y no es negociable. M\xE1x 120 caracteres. Si lo omites, la IA escribe el titular."),
|
|
28761
|
+
subheadline: z122.string().max(160).optional().describe("Opcional. Subt\xEDtulo EXACTO a renderizar, misma regla que headline. Independiente: puedes fijar solo el subt\xEDtulo. M\xE1x 160 caracteres."),
|
|
28744
28762
|
landingStrategy: LandingStrategyEnum.optional().describe('Opcional. Estructura de la landing cl\xE1sica cuando landing est\xE1 entre outputs: "classic" (estructura original probada y recomendada; default del primer rollout), "auto" (la IA decide; experimental), "pain_solution", "social_proof" (Landing Viral: UGC, WhatsApp, Instagram y evidencia social), "benefits_clarity", "offer_value" o "lifestyle_identity". Default "classic".'),
|
|
28745
28763
|
landingImageFormat: LandingImageFormatEnum.default("9:16").describe('Opcional. Formato/relaci\xF3n de aspecto de las im\xE1genes de la landing cl\xE1sica cuando landing est\xE1 entre outputs: "9:16" (vertical, por defecto), "4:5" (vertical compacto para feed) o "1:1" (cuadrado). Default "9:16".')
|
|
28746
28764
|
}).strict();
|
|
28747
|
-
var CreateServiceVideoInput =
|
|
28748
|
-
landingUrl:
|
|
28749
|
-
additionalContext:
|
|
28765
|
+
var CreateServiceVideoInput = z122.object({
|
|
28766
|
+
landingUrl: z122.string().url().describe("URL p\xFAblica de la landing del servicio. Es suficiente para generar el video; los medios son opcionales en la web."),
|
|
28767
|
+
additionalContext: z122.string().max(3e3).optional().describe('Instrucci\xF3n natural prioritaria. Ej.: "adapta el ritmo de estos competidores", "enfatiza reservas de demos" o restricciones de claims.'),
|
|
28750
28768
|
language: Lang.describe("Idioma del video: es, en o pt."),
|
|
28751
|
-
voiceId:
|
|
28752
|
-
brandId:
|
|
28753
|
-
reviewMode:
|
|
28769
|
+
voiceId: z122.string().trim().min(1).pipe(VoiceId).optional().describe('Opcional. Voz para toda la narraci\xF3n. Usa "auto" para que la IA la alinee con el presentador. Las voces del banco compartido fueron retiradas.'),
|
|
28770
|
+
brandId: z122.string().uuid().optional().describe("Marca guardada del usuario. Aplica voz, mensajes, paleta y persona predeterminada."),
|
|
28771
|
+
reviewMode: z122.enum([
|
|
28754
28772
|
"automatic",
|
|
28755
28773
|
"guided"
|
|
28756
28774
|
]).default("automatic").describe("automatic = la IA elige concepto y guion sin pausas; guided = el usuario aprueba concepto y storyboard."),
|
|
28757
|
-
videoPreset:
|
|
28775
|
+
videoPreset: z122.enum([
|
|
28758
28776
|
"auto",
|
|
28759
28777
|
"ugc_dynamic",
|
|
28760
28778
|
"ugc_how_to",
|
|
@@ -28764,128 +28782,128 @@ var CreateServiceVideoInput = z121.object({
|
|
|
28764
28782
|
videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El proveedor se elige internamente. Default: economy.'),
|
|
28765
28783
|
videoResolution: VideoResolutionEnum.default("480p").describe('Opcional. Resoluci\xF3n: "480p" o "720p". 720p cuesta m\xE1s por segundo y solo est\xE1 disponible en "economy" y "pro" (Medio = 768P). Default: 480p.')
|
|
28766
28784
|
}).strict();
|
|
28767
|
-
var GetTaskStatusInput =
|
|
28768
|
-
taskId:
|
|
28769
|
-
waitSeconds:
|
|
28785
|
+
var GetTaskStatusInput = z122.object({
|
|
28786
|
+
taskId: z122.string().min(1),
|
|
28787
|
+
waitSeconds: z122.number().int().min(0).max(120).optional()
|
|
28770
28788
|
});
|
|
28771
|
-
var ListTasksInput =
|
|
28772
|
-
limit:
|
|
28773
|
-
offset:
|
|
28774
|
-
search:
|
|
28789
|
+
var ListTasksInput = z122.object({
|
|
28790
|
+
limit: z122.number().int().min(1).max(50).optional(),
|
|
28791
|
+
offset: z122.number().int().min(0).optional(),
|
|
28792
|
+
search: z122.string().optional()
|
|
28775
28793
|
});
|
|
28776
28794
|
var MCP_REVIEW_LIST_FIELD_MAX = IMAGE_WIZARD_LIST_FIELD_MAX;
|
|
28777
28795
|
var MCP_REVIEW_FEATURE_ITEM_MAX = IMAGE_FEATURE_ITEM_MAX;
|
|
28778
|
-
var EditTaskDraftInput =
|
|
28779
|
-
taskId:
|
|
28780
|
-
angleIndex:
|
|
28781
|
-
angle:
|
|
28782
|
-
angle:
|
|
28783
|
-
buyerPersona:
|
|
28784
|
-
actor:
|
|
28785
|
-
actorId:
|
|
28786
|
-
gender:
|
|
28796
|
+
var EditTaskDraftInput = z122.object({
|
|
28797
|
+
taskId: z122.string().min(1),
|
|
28798
|
+
angleIndex: z122.number().int().min(0),
|
|
28799
|
+
angle: z122.object({
|
|
28800
|
+
angle: z122.string().min(1).max(480),
|
|
28801
|
+
buyerPersona: z122.string().min(1).max(360),
|
|
28802
|
+
actor: z122.string().min(1).max(360).optional(),
|
|
28803
|
+
actorId: z122.string().trim().min(1).optional().describe("Opcional. ID de un personaje guardado (usa list_actors para verlos). Si lo env\xEDas, su foto y su voz mandan sobre la descripci\xF3n de texto."),
|
|
28804
|
+
gender: z122.enum([
|
|
28787
28805
|
"female",
|
|
28788
28806
|
"male"
|
|
28789
28807
|
]).optional(),
|
|
28790
|
-
scriptNotes:
|
|
28808
|
+
scriptNotes: z122.string().max(2e3).optional()
|
|
28791
28809
|
})
|
|
28792
28810
|
});
|
|
28793
|
-
var PendingActionPayload =
|
|
28794
|
-
|
|
28795
|
-
kind:
|
|
28811
|
+
var PendingActionPayload = z122.discriminatedUnion("kind", [
|
|
28812
|
+
z122.object({
|
|
28813
|
+
kind: z122.literal("product_reference_set_approval"),
|
|
28796
28814
|
scope: ProductReferenceScopeEnum.optional(),
|
|
28797
|
-
scopeKey:
|
|
28798
|
-
scopeSnapshotId:
|
|
28799
|
-
expectedScopeHash:
|
|
28815
|
+
scopeKey: z122.string().min(1).max(120).optional(),
|
|
28816
|
+
scopeSnapshotId: z122.string().uuid().optional(),
|
|
28817
|
+
expectedScopeHash: z122.string().min(1).max(128).optional(),
|
|
28800
28818
|
decision: ProductReferenceResolutionDecisionEnum,
|
|
28801
28819
|
reason: ProductReferenceRejectionReasonEnum.optional(),
|
|
28802
|
-
affectedRefKeys:
|
|
28803
|
-
affectedPhotoNumbers:
|
|
28804
|
-
recoveryAction:
|
|
28820
|
+
affectedRefKeys: z122.array(z122.string().min(1).max(200)).min(1).optional(),
|
|
28821
|
+
affectedPhotoNumbers: z122.array(z122.number().int().positive()).min(1).optional(),
|
|
28822
|
+
recoveryAction: z122.enum([
|
|
28805
28823
|
"remove",
|
|
28806
28824
|
"replace",
|
|
28807
28825
|
"upload",
|
|
28808
28826
|
"return_to_selection"
|
|
28809
28827
|
]).optional()
|
|
28810
28828
|
}),
|
|
28811
|
-
|
|
28812
|
-
kind:
|
|
28813
|
-
selectedPhotoNumbers:
|
|
28829
|
+
z122.object({
|
|
28830
|
+
kind: z122.literal("product_reference_confirmation"),
|
|
28831
|
+
selectedPhotoNumbers: z122.array(z122.number().int().positive().max(5)).min(1).max(5).optional().describe("Opcional. N\xFAmeros visibles de las fotos que el usuario quiere conservar; las dem\xE1s se deseleccionan. Debe quedar al menos una."),
|
|
28814
28832
|
userChoice: ProductReferenceUserChoiceEnum.optional(),
|
|
28815
|
-
confirmedProductNames:
|
|
28833
|
+
confirmedProductNames: z122.array(z122.string().min(1).max(120)).min(2).max(8).optional(),
|
|
28816
28834
|
videoStructure: VideoStructureEnum.optional().describe("Opcional. Formato para reanudar el video: single_take (Un solo clip, generado completo; puede incluir cambios de plano) o multi_scene (Multiescena). El backend vuelve a validar que sea compatible con el agrupamiento confirmado."),
|
|
28817
28835
|
videoQuality: VideoQualityEnum.optional().describe("Opcional. Calidad para reanudar el video: economy (Econ\xF3mico), medium (Medio) o pro. El proveedor se elige internamente y el backend vuelve a cotizar la ruta."),
|
|
28818
|
-
useMultiSceneShowcase:
|
|
28836
|
+
useMultiSceneShowcase: z122.boolean().optional().describe("Compatibilidad con confirmaciones antiguas: si es true junto con userChoice=variants, conserva el showcase multiescena.")
|
|
28819
28837
|
}),
|
|
28820
|
-
|
|
28821
|
-
kind:
|
|
28838
|
+
z122.object({
|
|
28839
|
+
kind: z122.literal("angle_review_approval"),
|
|
28822
28840
|
// All edits are optional — empty action body just approves the
|
|
28823
28841
|
// backend-generated draft as-is. Field shapes mirror the angle-review
|
|
28824
28842
|
// request contracts in @packages/types/wizard.ts; the handler routes to
|
|
28825
28843
|
// the dedicated video/image/autopilot endpoint based on StatusResponse.kind.
|
|
28826
|
-
customAngle:
|
|
28844
|
+
customAngle: z122.string().min(1).max(480).optional(),
|
|
28827
28845
|
// Keep the shared MCP action within the strictest downstream contract:
|
|
28828
28846
|
// autopilot/image resume endpoints cap these fields at 1500 characters.
|
|
28829
|
-
painPoints:
|
|
28830
|
-
benefits:
|
|
28847
|
+
painPoints: z122.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
|
|
28848
|
+
benefits: z122.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
|
|
28831
28849
|
// Same policy as the two fields above: the strictest downstream contract
|
|
28832
28850
|
// wins. The image endpoint caps each feature at 240 while landing/video
|
|
28833
28851
|
// accept 300, and this single action routes to whichever the task is — so
|
|
28834
28852
|
// accepting 300 here turns a 250-character feature on an image task into
|
|
28835
28853
|
// an opaque HTTP 400 after the model already believed it had been saved.
|
|
28836
|
-
features:
|
|
28837
|
-
buyerPersona:
|
|
28854
|
+
features: z122.array(z122.string().min(1).max(MCP_REVIEW_FEATURE_ITEM_MAX)).max(10).optional(),
|
|
28855
|
+
buyerPersona: z122.string().min(1).max(360).optional(),
|
|
28838
28856
|
narrativeStyle: PublicNarrativeStyleEnum.optional().describe('Narrativa del video. "problem_product_cta" (Problema y Soluci\xF3n) funciona en ambos formatos \u2014 en Un solo clip abre sin producto y el producto entra por referencia en su beat. La familia storyteller ("animated_storyteller", "animated_inner_journey", "animated_object_soul", "animated_timeline") no est\xE1 disponible por ahora.'),
|
|
28839
|
-
actor:
|
|
28840
|
-
actorId:
|
|
28841
|
-
creativeDirection:
|
|
28842
|
-
selectedAngleNumbers:
|
|
28843
|
-
angleEdits:
|
|
28844
|
-
angleNumber:
|
|
28845
|
-
narrativeSelection:
|
|
28857
|
+
actor: z122.string().min(1).max(360).optional().describe("Nueva descripci\xF3n del presentador. Al enviarla sin actorId, se elimina autom\xE1ticamente cualquier actor guardado previo de esos \xE1ngulos."),
|
|
28858
|
+
actorId: z122.string().max(120).nullable().optional(),
|
|
28859
|
+
creativeDirection: z122.string().max(2e3).optional(),
|
|
28860
|
+
selectedAngleNumbers: z122.array(z122.number().int().positive()).min(1).max(3).optional().describe("N\xFAmeros visibles (1-based) de los \xE1ngulos que el usuario quiere renderizar. Deben ser \xFAnicos, existir en la review y no superar el videoAngleCount autorizado."),
|
|
28861
|
+
angleEdits: z122.array(z122.object({
|
|
28862
|
+
angleNumber: z122.number().int().positive(),
|
|
28863
|
+
narrativeSelection: z122.enum([
|
|
28846
28864
|
"market",
|
|
28847
28865
|
"guided"
|
|
28848
28866
|
]).optional().describe("Elecci\xF3n expl\xEDcita: market usa el estudio disponible; guided usa la narrativa elegida para este \xE1ngulo."),
|
|
28849
|
-
angle:
|
|
28850
|
-
buyerPersona:
|
|
28867
|
+
angle: z122.string().min(1).max(480).optional(),
|
|
28868
|
+
buyerPersona: z122.string().min(1).max(360).optional(),
|
|
28851
28869
|
narrativeStyle: PublicNarrativeStyleEnum.optional().describe('Narrativa del video. "problem_product_cta" (Problema y Soluci\xF3n) funciona en ambos formatos \u2014 en Un solo clip abre sin producto y el producto entra por referencia en su beat. La familia storyteller ("animated_storyteller", "animated_inner_journey", "animated_object_soul", "animated_timeline") no est\xE1 disponible por ahora.'),
|
|
28852
|
-
actor:
|
|
28853
|
-
actorId:
|
|
28854
|
-
creativeDirection:
|
|
28870
|
+
actor: z122.string().min(1).max(360).optional(),
|
|
28871
|
+
actorId: z122.string().max(120).nullable().optional(),
|
|
28872
|
+
creativeDirection: z122.string().max(2e3).optional()
|
|
28855
28873
|
}).strict()).max(3).optional().describe("Ediciones independientes por n\xFAmero visible de \xE1ngulo. S\xF3lo se aceptan para \xE1ngulos incluidos en selectedAngleNumbers (o en la selecci\xF3n por defecto)."),
|
|
28856
|
-
gapDurationSeconds:
|
|
28857
|
-
|
|
28858
|
-
|
|
28874
|
+
gapDurationSeconds: z122.union([
|
|
28875
|
+
z122.literal(15),
|
|
28876
|
+
z122.literal(30)
|
|
28859
28877
|
]).optional().describe("Opcional. Solo para aceptar expl\xEDcitamente la recomendaci\xF3n gapDurationChoice del status. 30 env\xEDa el override double_30s para el \xE1ngulo recomendado; 15 u omitido conserva la duraci\xF3n cotizada.")
|
|
28860
28878
|
}),
|
|
28861
|
-
|
|
28862
|
-
kind:
|
|
28863
|
-
angleId:
|
|
28864
|
-
angleNumber:
|
|
28865
|
-
content:
|
|
28866
|
-
creativeDirection:
|
|
28867
|
-
actor:
|
|
28879
|
+
z122.object({
|
|
28880
|
+
kind: z122.literal("service_angle_approval"),
|
|
28881
|
+
angleId: z122.string().uuid().optional(),
|
|
28882
|
+
angleNumber: z122.number().int().positive().optional(),
|
|
28883
|
+
content: z122.string().min(1).max(480).optional(),
|
|
28884
|
+
creativeDirection: z122.string().min(1).max(1500).optional(),
|
|
28885
|
+
actor: z122.string().min(1).max(360).optional()
|
|
28868
28886
|
}),
|
|
28869
|
-
|
|
28870
|
-
kind:
|
|
28871
|
-
voiceovers:
|
|
28872
|
-
visualDirections:
|
|
28873
|
-
voiceoversByScene:
|
|
28874
|
-
visualDirectionsByScene:
|
|
28887
|
+
z122.object({
|
|
28888
|
+
kind: z122.literal("service_script_approval"),
|
|
28889
|
+
voiceovers: z122.record(z122.string(), z122.string().min(1).max(600)).optional(),
|
|
28890
|
+
visualDirections: z122.record(z122.string(), z122.string().min(1).max(1200)).optional(),
|
|
28891
|
+
voiceoversByScene: z122.record(z122.string(), z122.string().min(1).max(600)).optional(),
|
|
28892
|
+
visualDirectionsByScene: z122.record(z122.string(), z122.string().min(1).max(1200)).optional()
|
|
28875
28893
|
})
|
|
28876
28894
|
]);
|
|
28877
|
-
var ResolvePendingActionInput =
|
|
28878
|
-
taskId:
|
|
28895
|
+
var ResolvePendingActionInput = z122.object({
|
|
28896
|
+
taskId: z122.string().min(1),
|
|
28879
28897
|
action: PendingActionPayload
|
|
28880
28898
|
}).strict();
|
|
28881
28899
|
function resolveVariantConfirmVideoTier(action) {
|
|
28882
28900
|
return action.useMultiSceneShowcase && action.userChoice === "variants" ? "standard" : void 0;
|
|
28883
28901
|
}
|
|
28884
28902
|
__name(resolveVariantConfirmVideoTier, "resolveVariantConfirmVideoTier");
|
|
28885
|
-
var StatusForResolveSchema =
|
|
28903
|
+
var StatusForResolveSchema = z122.object({
|
|
28886
28904
|
// Metadata used to select the backend resume contract. Older API responses
|
|
28887
28905
|
// may omit these fields, so the resolver keeps the generic fallback.
|
|
28888
|
-
kind:
|
|
28906
|
+
kind: z122.enum([
|
|
28889
28907
|
"autopilot",
|
|
28890
28908
|
"video",
|
|
28891
28909
|
"image",
|
|
@@ -28893,18 +28911,18 @@ var StatusForResolveSchema = z121.object({
|
|
|
28893
28911
|
"mix",
|
|
28894
28912
|
"service"
|
|
28895
28913
|
]).optional(),
|
|
28896
|
-
selectedOutputs:
|
|
28914
|
+
selectedOutputs: z122.array(z122.enum([
|
|
28897
28915
|
"landing",
|
|
28898
28916
|
"video",
|
|
28899
28917
|
"image"
|
|
28900
28918
|
])).optional(),
|
|
28901
|
-
videoAngleCount:
|
|
28902
|
-
ugcFormat:
|
|
28919
|
+
videoAngleCount: z122.number().int().min(1).max(3).optional(),
|
|
28920
|
+
ugcFormat: z122.enum([
|
|
28903
28921
|
"single_8s",
|
|
28904
28922
|
"single_15s",
|
|
28905
28923
|
"double_30s"
|
|
28906
28924
|
]).optional(),
|
|
28907
|
-
videoStyle:
|
|
28925
|
+
videoStyle: z122.enum([
|
|
28908
28926
|
"ugc",
|
|
28909
28927
|
"cartoon_3d",
|
|
28910
28928
|
"product_only",
|
|
@@ -28914,13 +28932,13 @@ var StatusForResolveSchema = z121.object({
|
|
|
28914
28932
|
videoQuality: VideoQualityEnum.optional(),
|
|
28915
28933
|
videoRouteId: VideoRouteIdEnum.optional(),
|
|
28916
28934
|
videoModel: TaskVideoModelEnum.optional(),
|
|
28917
|
-
videoTier:
|
|
28935
|
+
videoTier: z122.enum([
|
|
28918
28936
|
"legacy",
|
|
28919
28937
|
"standard",
|
|
28920
28938
|
"pro",
|
|
28921
28939
|
"single_call"
|
|
28922
28940
|
]).optional(),
|
|
28923
|
-
videoResolution:
|
|
28941
|
+
videoResolution: z122.enum([
|
|
28924
28942
|
"480p",
|
|
28925
28943
|
"720p"
|
|
28926
28944
|
]).optional(),
|
|
@@ -28928,60 +28946,60 @@ var StatusForResolveSchema = z121.object({
|
|
|
28928
28946
|
// A task created before a narrative was blocked/hidden must still parse,
|
|
28929
28947
|
// or resolve_pending_action could never approve it.
|
|
28930
28948
|
narrativeStyle: NarrativeStyle.optional(),
|
|
28931
|
-
pauseForVideoScriptReview:
|
|
28932
|
-
pendingUserAction:
|
|
28933
|
-
kind:
|
|
28934
|
-
candidateGrouping:
|
|
28935
|
-
selectedImageUrls:
|
|
28936
|
-
proposedProductNames:
|
|
28949
|
+
pauseForVideoScriptReview: z122.boolean().optional(),
|
|
28950
|
+
pendingUserAction: z122.object({
|
|
28951
|
+
kind: z122.string(),
|
|
28952
|
+
candidateGrouping: z122.string().optional(),
|
|
28953
|
+
selectedImageUrls: z122.array(z122.string()).optional(),
|
|
28954
|
+
proposedProductNames: z122.array(z122.string()).optional(),
|
|
28937
28955
|
// Adaptive reference questions are server-owned. Echo only the evidence
|
|
28938
28956
|
// identity and the choices shown by the current snapshot; never accept a
|
|
28939
28957
|
// client-supplied reference set as authorization.
|
|
28940
|
-
options:
|
|
28941
|
-
mode:
|
|
28958
|
+
options: z122.array(ProductReferenceUserChoiceEnum).max(4).optional(),
|
|
28959
|
+
mode: z122.enum([
|
|
28942
28960
|
"question",
|
|
28943
28961
|
"visual_recovery"
|
|
28944
28962
|
]).optional(),
|
|
28945
28963
|
/** Hand-mirrored from packages/types result.ts — see CLAUDE.md § MCP Server Sync. */
|
|
28946
|
-
canKeepSelection:
|
|
28947
|
-
decisionKey:
|
|
28948
|
-
questionOrdinal:
|
|
28949
|
-
questionCeiling:
|
|
28950
|
-
|
|
28951
|
-
|
|
28964
|
+
canKeepSelection: z122.boolean().optional(),
|
|
28965
|
+
decisionKey: z122.string().optional(),
|
|
28966
|
+
questionOrdinal: z122.number().int().min(1).max(5).optional(),
|
|
28967
|
+
questionCeiling: z122.union([
|
|
28968
|
+
z122.literal(3),
|
|
28969
|
+
z122.literal(5)
|
|
28952
28970
|
]).optional(),
|
|
28953
|
-
referenceEvidenceVersion:
|
|
28954
|
-
expectedEvidenceHash:
|
|
28955
|
-
question:
|
|
28956
|
-
prompt:
|
|
28957
|
-
helpText:
|
|
28958
|
-
options:
|
|
28971
|
+
referenceEvidenceVersion: z122.number().int().positive().optional(),
|
|
28972
|
+
expectedEvidenceHash: z122.string().optional(),
|
|
28973
|
+
question: z122.object({
|
|
28974
|
+
prompt: z122.string().min(1).max(240),
|
|
28975
|
+
helpText: z122.string().min(1).max(300).optional(),
|
|
28976
|
+
options: z122.array(z122.object({
|
|
28959
28977
|
value: ProductReferenceUserChoiceEnum,
|
|
28960
|
-
label:
|
|
28961
|
-
description:
|
|
28978
|
+
label: z122.string().min(1).max(120),
|
|
28979
|
+
description: z122.string().min(1).max(240).optional()
|
|
28962
28980
|
})).min(2).max(4)
|
|
28963
28981
|
}).optional(),
|
|
28964
28982
|
scope: ProductReferenceScopeEnum.optional(),
|
|
28965
|
-
scopeKey:
|
|
28966
|
-
scopeSnapshotId:
|
|
28967
|
-
scopeHash:
|
|
28968
|
-
baseReferenceSetHash:
|
|
28969
|
-
phase:
|
|
28983
|
+
scopeKey: z122.string().optional(),
|
|
28984
|
+
scopeSnapshotId: z122.string().uuid().optional(),
|
|
28985
|
+
scopeHash: z122.string().optional(),
|
|
28986
|
+
baseReferenceSetHash: z122.string().optional(),
|
|
28987
|
+
phase: z122.enum([
|
|
28970
28988
|
"preparation",
|
|
28971
28989
|
"final"
|
|
28972
28990
|
]).optional(),
|
|
28973
|
-
selectedRefKeys:
|
|
28974
|
-
allowedDecisions:
|
|
28975
|
-
previews:
|
|
28976
|
-
refKey:
|
|
28991
|
+
selectedRefKeys: z122.array(z122.string().min(1).max(200)).optional(),
|
|
28992
|
+
allowedDecisions: z122.array(ProductReferenceResolutionDecisionEnum).optional(),
|
|
28993
|
+
previews: z122.array(z122.object({
|
|
28994
|
+
refKey: z122.string().min(1).max(200)
|
|
28977
28995
|
}).passthrough()).optional(),
|
|
28978
|
-
customAngleDraft:
|
|
28979
|
-
painPointsDraft:
|
|
28980
|
-
benefitsDraft:
|
|
28981
|
-
featuresDraft:
|
|
28982
|
-
angleOptions:
|
|
28983
|
-
index:
|
|
28984
|
-
angle:
|
|
28996
|
+
customAngleDraft: z122.string().optional(),
|
|
28997
|
+
painPointsDraft: z122.string().optional(),
|
|
28998
|
+
benefitsDraft: z122.string().optional(),
|
|
28999
|
+
featuresDraft: z122.array(z122.string()).optional(),
|
|
29000
|
+
angleOptions: z122.array(z122.object({
|
|
29001
|
+
index: z122.number().int().nonnegative(),
|
|
29002
|
+
angle: z122.string().min(1)
|
|
28985
29003
|
}).passthrough()).min(1).max(5).optional(),
|
|
28986
29004
|
// Recommendation consumed only when the caller explicitly sends
|
|
28987
29005
|
// gapDurationSeconds: 30 in the angle approval action.
|
|
@@ -28991,17 +29009,17 @@ var StatusForResolveSchema = z121.object({
|
|
|
28991
29009
|
// keys. `actorId` (the saved custom actor the picker stored) was silently
|
|
28992
29010
|
// dropped here, so the approval handler below could not echo it back on the
|
|
28993
29011
|
// PATCH — the selection looked accepted and reached no render.
|
|
28994
|
-
angles:
|
|
28995
|
-
id:
|
|
28996
|
-
content:
|
|
28997
|
-
creativeDirection:
|
|
28998
|
-
actor:
|
|
28999
|
-
actorId:
|
|
29012
|
+
angles: z122.array(z122.object({
|
|
29013
|
+
id: z122.string().uuid(),
|
|
29014
|
+
content: z122.string(),
|
|
29015
|
+
creativeDirection: z122.string(),
|
|
29016
|
+
actor: z122.string(),
|
|
29017
|
+
actorId: z122.string().nullable().optional()
|
|
29000
29018
|
}).passthrough()).optional(),
|
|
29001
|
-
panels:
|
|
29002
|
-
beatId:
|
|
29003
|
-
voiceover:
|
|
29004
|
-
visualDirection:
|
|
29019
|
+
panels: z122.array(z122.object({
|
|
29020
|
+
beatId: z122.string(),
|
|
29021
|
+
voiceover: z122.string(),
|
|
29022
|
+
visualDirection: z122.string()
|
|
29005
29023
|
}).passthrough()).optional()
|
|
29006
29024
|
}).optional()
|
|
29007
29025
|
}).passthrough();
|
|
@@ -29354,8 +29372,8 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
|
|
|
29354
29372
|
server.registerTool("verify_landing_commerce", {
|
|
29355
29373
|
description: getProductMakerCapabilityModelGuidance("verify_landing_commerce").summary + " Verifica una correcci\xF3n manual de precios, tachados o packs de una landing editable existente. Solo relee Shopify y los recibos externos; no cambia precios, inventario, SKU ni compra una edici\xF3n. Pasa taskId y editId de la edici\xF3n ya conocida; nunca inventes IDs ni pidas repetir el cambio. Devuelve el estado can\xF3nico por proveedor: conserva el aviso pendiente hasta confirmar los valores reales. Solo despu\xE9s de confirmar todos los valores, el servidor puede volver a habilitar la compra. Web guardada no demuestra publicaci\xF3n p\xFAblica ni checkout; muestra las correcciones y enlaces pendientes sin c\xF3digos t\xE9cnicos. La disponibilidad del editor conserva sus permisos actuales.",
|
|
29356
29374
|
inputSchema: {
|
|
29357
|
-
taskId:
|
|
29358
|
-
editId:
|
|
29375
|
+
taskId: z122.string().uuid(),
|
|
29376
|
+
editId: z122.string().uuid()
|
|
29359
29377
|
},
|
|
29360
29378
|
annotations: OVERWRITES_EXTERNAL
|
|
29361
29379
|
}, async (input) => {
|
|
@@ -29546,16 +29564,16 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
|
|
|
29546
29564
|
if (input.search) qs.set("search", input.search);
|
|
29547
29565
|
const path3 = `/v1/tasks${qs.toString() ? "?" + qs.toString() : ""}`;
|
|
29548
29566
|
const r = await api.getJson(path3);
|
|
29549
|
-
const page =
|
|
29550
|
-
items:
|
|
29567
|
+
const page = z122.object({
|
|
29568
|
+
items: z122.array(z122.unknown())
|
|
29551
29569
|
}).passthrough().safeParse(r);
|
|
29552
29570
|
if (!page.success) return asText(r);
|
|
29553
29571
|
return asText({
|
|
29554
29572
|
...page.data,
|
|
29555
29573
|
items: page.data.items.map((item) => {
|
|
29556
|
-
const servicePage =
|
|
29557
|
-
taskId:
|
|
29558
|
-
resourceType:
|
|
29574
|
+
const servicePage = z122.object({
|
|
29575
|
+
taskId: z122.string().uuid(),
|
|
29576
|
+
resourceType: z122.literal("service_page")
|
|
29559
29577
|
}).passthrough().safeParse(item);
|
|
29560
29578
|
if (!servicePage.success) return item;
|
|
29561
29579
|
return {
|
|
@@ -29877,13 +29895,34 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
|
|
|
29877
29895
|
if (isVideoTask) {
|
|
29878
29896
|
body.selectedAngleIndices = selectedAngleIndices;
|
|
29879
29897
|
const r2 = await api.postJson(`/v1/tasks/${encodeURIComponent(input.taskId)}/approve-video-angles`, body);
|
|
29898
|
+
const angleKeys = r2.approvedAngleKeys;
|
|
29899
|
+
const hasCanonicalKeys = r2.success === true && Array.isArray(angleKeys) && angleKeys.length === selectedAngleIndices.length && angleKeys.length > 0 && angleKeys.every((key) => typeof key === "string" && /^angle_\d+$/.test(key)) && new Set(angleKeys).size === angleKeys.length;
|
|
29880
29900
|
return asText({
|
|
29881
29901
|
...r2,
|
|
29882
29902
|
...status.pauseForVideoScriptReview === true ? {
|
|
29883
|
-
reviewNextAction: {
|
|
29903
|
+
reviewNextAction: hasCanonicalKeys ? {
|
|
29884
29904
|
kind: "poll_video_script",
|
|
29885
29905
|
tool: "get_video_script",
|
|
29886
|
-
|
|
29906
|
+
arguments: {
|
|
29907
|
+
taskId: input.taskId,
|
|
29908
|
+
angleKey: angleKeys[0]
|
|
29909
|
+
},
|
|
29910
|
+
calls: angleKeys.map((angleKey) => ({
|
|
29911
|
+
tool: "get_video_script",
|
|
29912
|
+
arguments: {
|
|
29913
|
+
taskId: input.taskId,
|
|
29914
|
+
angleKey
|
|
29915
|
+
}
|
|
29916
|
+
})),
|
|
29917
|
+
instruction: "Usa exactamente los arguments de cada llamada; no omitas ni derives angleKey del n\xFAmero visible. Consulta cada guion hasta ready/error/approved/skipped. Si devuelve ready, presenta el guion y espera al usuario. Si devuelve error, consulta get_task_status antes de ofrecer una recuperaci\xF3n. Si devuelve approved o skipped, contin\xFAa con la siguiente clave; al terminar, reanuda get_task_status."
|
|
29918
|
+
} : {
|
|
29919
|
+
kind: "poll_task_status",
|
|
29920
|
+
tool: "get_task_status",
|
|
29921
|
+
arguments: {
|
|
29922
|
+
taskId: input.taskId,
|
|
29923
|
+
waitSeconds: 45
|
|
29924
|
+
},
|
|
29925
|
+
instruction: "La aprobaci\xF3n no confirm\xF3 las claves de los guiones programados. Consulta get_task_status para recuperar el estado y su nextAction; no asumas angle_0 ni inicies otra generaci\xF3n."
|
|
29887
29926
|
}
|
|
29888
29927
|
} : {}
|
|
29889
29928
|
});
|
|
@@ -30024,28 +30063,28 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
|
|
|
30024
30063
|
__name(registerTaskTools, "registerTaskTools");
|
|
30025
30064
|
|
|
30026
30065
|
// src/tools/brands.ts
|
|
30027
|
-
import { z as
|
|
30066
|
+
import { z as z123 } from "zod";
|
|
30028
30067
|
var guidance2 = getProductMakerCapabilityModelGuidance("create_brand");
|
|
30029
30068
|
var BRAND_START_REPLAY_WINDOW_MS = 15 * 60 * 1e3;
|
|
30030
30069
|
var BRAND_NOTES_MAX_CHARS = 2e4;
|
|
30031
30070
|
var BRAND_AMBIGUOUS_REQUEST_RETENTION_MS = 24 * 60 * 60 * 1e3;
|
|
30032
30071
|
var BRAND_CREATION_REQUEST_LIMIT = 500;
|
|
30033
30072
|
var brandCreationRequests = /* @__PURE__ */ new Map();
|
|
30034
|
-
var CreateBrandInput =
|
|
30035
|
-
action:
|
|
30073
|
+
var CreateBrandInput = z123.object({
|
|
30074
|
+
action: z123.enum([
|
|
30036
30075
|
"start",
|
|
30037
30076
|
"status",
|
|
30038
30077
|
"list"
|
|
30039
30078
|
]).default("start").describe("start cotiza (sin confirmed) o inicia (confirmed=true) el an\xE1lisis; status consulta brandId hasta ready o failed; list muestra las marcas que el usuario ya tiene."),
|
|
30040
|
-
sourceUrl:
|
|
30041
|
-
businessNotes:
|
|
30042
|
-
language:
|
|
30079
|
+
sourceUrl: z123.string().trim().min(1).max(BRAND_SOURCE_URL_MAX_LENGTH).optional().describe("Instagram, Facebook, TikTok o web p\xFAblica del negocio, como la dio el usuario (\xAB@sanlucasbarberia\xBB, \xABinstagram.com/sanlucasbarberia\xBB, \xABmibarberia.com\xBB). Obligatorio para start."),
|
|
30080
|
+
businessNotes: z123.string().trim().max(BRAND_NOTES_MAX_CHARS).optional().describe("Opcional. Lo que el usuario cuente de su negocio en el chat (servicios y precios, WhatsApp, ciudad o zona, horarios). Se guarda como documento del negocio y llega tal cual a la marca y a su landing. Copia sus palabras; no inventes datos."),
|
|
30081
|
+
language: z123.enum([
|
|
30043
30082
|
"es",
|
|
30044
30083
|
"en",
|
|
30045
30084
|
"pt"
|
|
30046
30085
|
]).optional().describe("Idioma de la conversaci\xF3n. Solo se usa si la p\xE1gina del negocio no deja claro su idioma."),
|
|
30047
|
-
confirmed:
|
|
30048
|
-
brandId:
|
|
30086
|
+
confirmed: z123.boolean().optional().describe("Solo true despu\xE9s de mostrar el precio y que el usuario acepte. Sin confirmed, start solo cotiza y no cobra."),
|
|
30087
|
+
brandId: z123.string().uuid().optional().describe("ID de la marca. Obligatorio para status; no lo inventes.")
|
|
30049
30088
|
}).strict();
|
|
30050
30089
|
function normalizeBrandSourceUrl(raw) {
|
|
30051
30090
|
const value = raw.trim();
|
|
@@ -30328,27 +30367,26 @@ function registerBrandTools(server, api, options = {}) {
|
|
|
30328
30367
|
__name(registerBrandTools, "registerBrandTools");
|
|
30329
30368
|
|
|
30330
30369
|
// src/tools/service-landing.ts
|
|
30331
|
-
import { createHash as createHash4 } from "crypto";
|
|
30332
|
-
import { z as
|
|
30370
|
+
import { createHash as createHash4, randomUUID } from "crypto";
|
|
30371
|
+
import { z as z124 } from "zod";
|
|
30333
30372
|
var guidance3 = getProductMakerCapabilityModelGuidance("create_service_landing");
|
|
30334
30373
|
var SERVICE_LANDING_KEY_NAMESPACE = "6f1d8c2a-3b4e-5f60-8a7b-9c0d1e2f3a4b";
|
|
30335
30374
|
var SERVICE_LANDING_INFO_MAX_CHARS = 2e4;
|
|
30336
|
-
var CreateServiceLandingInput =
|
|
30337
|
-
action:
|
|
30375
|
+
var CreateServiceLandingInput = z124.object({
|
|
30376
|
+
action: z124.enum([
|
|
30338
30377
|
"prepare",
|
|
30339
30378
|
"build",
|
|
30340
30379
|
"status",
|
|
30341
30380
|
"publish"
|
|
30342
|
-
]).default("prepare").describe("prepare (gratis) crea o retoma la landing de la marca y da el precio; build (pagado, confirmed=true)
|
|
30343
|
-
brandId:
|
|
30344
|
-
servicePageId:
|
|
30345
|
-
businessInfo:
|
|
30346
|
-
confirmed:
|
|
30347
|
-
maxCredits:
|
|
30348
|
-
operationId:
|
|
30349
|
-
slug:
|
|
30381
|
+
]).default("prepare").describe("prepare (gratis) crea o retoma la landing de la marca y da el precio; build (pagado, confirmed=true) genera la p\xE1gina directamente con la marca y los datos guardados; status sigue el avance; publish la publica y devuelve su enlace."),
|
|
30382
|
+
brandId: z124.string().uuid().optional().describe("ID de la marca (de create_brand). Obligatorio para prepare. Nunca un taskId de producto."),
|
|
30383
|
+
servicePageId: z124.string().uuid().optional().describe("ID de la landing que devolvi\xF3 prepare. Obligatorio para build, status y publish."),
|
|
30384
|
+
businessInfo: z124.string().trim().max(SERVICE_LANDING_INFO_MAX_CHARS).optional().describe("Opcional. Lo que el usuario cont\xF3 del negocio y no estaba en su marca: servicios y precios, WhatsApp o tel\xE9fono, ciudad o zona, horarios. Copia sus palabras; no inventes datos."),
|
|
30385
|
+
confirmed: z124.boolean().optional().describe("Solo true despu\xE9s de mostrar el precio total y que el usuario acepte. Obligatorio para build."),
|
|
30386
|
+
maxCredits: z124.number().int().positive().optional().describe("El total en cr\xE9ditos que el usuario acept\xF3 (el que devolvi\xF3 prepare). Obligatorio para build: ninguna etapa se inicia si su precio supera este total."),
|
|
30387
|
+
operationId: z124.string().uuid().optional().describe("Opcional en status: la operaci\xF3n que devolvi\xF3 build."),
|
|
30388
|
+
slug: z124.string().trim().toLowerCase().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/).max(64).optional().describe("Opcional en publish: la direcci\xF3n corta de la p\xE1gina (ej. sanlucas-barberia). Si falta se usa la sugerida desde el nombre del negocio.")
|
|
30350
30389
|
}).strict();
|
|
30351
|
-
var SERVICE_LANDING_MAX_BUILD_ATTEMPTS = 10;
|
|
30352
30390
|
function serviceKey(...parts) {
|
|
30353
30391
|
return deriveUuidV5(parts.join(":"), SERVICE_LANDING_KEY_NAMESPACE);
|
|
30354
30392
|
}
|
|
@@ -30398,18 +30436,6 @@ function serviceEditorUrl(api, pageId) {
|
|
|
30398
30436
|
}
|
|
30399
30437
|
}
|
|
30400
30438
|
__name(serviceEditorUrl, "serviceEditorUrl");
|
|
30401
|
-
var MISSING_LABELS = {
|
|
30402
|
-
"business.name": "nombre del negocio",
|
|
30403
|
-
services: "servicios (y su precio, si lo tiene)",
|
|
30404
|
-
"contact.channels": "WhatsApp, tel\xE9fono o enlace para reservar",
|
|
30405
|
-
"contact.primaryCta": "c\xF3mo quiere que lo contacten primero"
|
|
30406
|
-
};
|
|
30407
|
-
function describeMissing(fields) {
|
|
30408
|
-
return [
|
|
30409
|
-
...new Set(fields.map((field) => MISSING_LABELS[field]).filter((label) => Boolean(label)))
|
|
30410
|
-
];
|
|
30411
|
-
}
|
|
30412
|
-
__name(describeMissing, "describeMissing");
|
|
30413
30439
|
function summarizeFacts(facts) {
|
|
30414
30440
|
return {
|
|
30415
30441
|
...facts.business.name ? {
|
|
@@ -30432,14 +30458,13 @@ function summarizeFacts(facts) {
|
|
|
30432
30458
|
}
|
|
30433
30459
|
__name(summarizeFacts, "summarizeFacts");
|
|
30434
30460
|
var OPERATION_ERROR_TEXT = {
|
|
30435
|
-
SERVICE_PAGE_SOURCES_REQUIRED: "No hay informaci\xF3n del negocio para escribir la p\xE1gina. Pide al usuario que cuente sus servicios y
|
|
30436
|
-
SOURCE_TEXT_REQUIRED: "No hay informaci\xF3n del negocio para escribir la p\xE1gina. Pide al usuario que cuente sus servicios y
|
|
30461
|
+
SERVICE_PAGE_SOURCES_REQUIRED: "No hay informaci\xF3n del negocio para escribir la p\xE1gina. Pide al usuario que cuente sus servicios y env\xEDalos como businessInfo al preparar otra landing; muestra su precio y espera autorizaci\xF3n antes de generarla.",
|
|
30462
|
+
SOURCE_TEXT_REQUIRED: "No hay informaci\xF3n del negocio para escribir la p\xE1gina. Pide al usuario que cuente sus servicios y env\xEDalos como businessInfo al preparar otra landing; muestra su precio y espera autorizaci\xF3n antes de generarla."
|
|
30437
30463
|
};
|
|
30438
30464
|
function operationFailureText(code) {
|
|
30439
30465
|
const actionable = code ? OPERATION_ERROR_TEXT[code] : void 0;
|
|
30440
30466
|
if (actionable) return actionable;
|
|
30441
|
-
|
|
30442
|
-
return "La etapa fall\xF3 y no se cobr\xF3. Vuelve a llamar build (mismo maxCredits) sin preguntar: reintenta solo. Si falla 3 veces seguidas, sugiere terminarla en la web de ProductMaker.";
|
|
30467
|
+
return "La etapa termin\xF3 con error y no se cobr\xF3. Explica su causa. Si el usuario quiere otra landing, usa prepare con su marca, muestra el nuevo precio y espera autorizaci\xF3n antes de build; no reintentes la landing fallida autom\xE1ticamente.";
|
|
30443
30468
|
}
|
|
30444
30469
|
__name(operationFailureText, "operationFailureText");
|
|
30445
30470
|
function isPageGenerated(page) {
|
|
@@ -30454,6 +30479,30 @@ function registerServiceLandingTools(server, api) {
|
|
|
30454
30479
|
return pages.find((page) => page.brandId === brandId) ?? null;
|
|
30455
30480
|
}
|
|
30456
30481
|
__name(findPageForBrand, "findPageForBrand");
|
|
30482
|
+
async function createPageForBrand(brandId, includeBrandLogo) {
|
|
30483
|
+
try {
|
|
30484
|
+
const page = await api.postJson("/v1/service-pages", {
|
|
30485
|
+
brandId,
|
|
30486
|
+
includeBrandLogo,
|
|
30487
|
+
// Free workspace identity must not replay a terminal workspace after
|
|
30488
|
+
// its Brand association is released by canonical admission.
|
|
30489
|
+
idempotencyKey: randomUUID()
|
|
30490
|
+
});
|
|
30491
|
+
return {
|
|
30492
|
+
page,
|
|
30493
|
+
resumed: false
|
|
30494
|
+
};
|
|
30495
|
+
} catch (error) {
|
|
30496
|
+
if (error instanceof ApiHttpError && error.status < 500 && serviceApiCode(error) !== "SERVICE_PAGE_CONFLICT_BUSINESS") throw error;
|
|
30497
|
+
const existing = await findPageForBrand(brandId);
|
|
30498
|
+
if (!existing) throw error;
|
|
30499
|
+
return {
|
|
30500
|
+
page: await readPage(existing.id),
|
|
30501
|
+
resumed: true
|
|
30502
|
+
};
|
|
30503
|
+
}
|
|
30504
|
+
}
|
|
30505
|
+
__name(createPageForBrand, "createPageForBrand");
|
|
30457
30506
|
async function addBusinessInfo(page, info) {
|
|
30458
30507
|
try {
|
|
30459
30508
|
await api.postMultipart(`${pagePath(page.id)}/intake`, {}, {
|
|
@@ -30467,24 +30516,39 @@ function registerServiceLandingTools(server, api) {
|
|
|
30467
30516
|
return readPage(page.id);
|
|
30468
30517
|
}
|
|
30469
30518
|
__name(addBusinessInfo, "addBusinessInfo");
|
|
30470
|
-
async function quote(page
|
|
30471
|
-
return api.postJson(`${pagePath(page.id)}/quotes
|
|
30519
|
+
async function quote(page) {
|
|
30520
|
+
return api.postJson(`${pagePath(page.id)}/quotes/generation`, {
|
|
30472
30521
|
expectedRevision: page.draftRevision
|
|
30473
30522
|
});
|
|
30474
30523
|
}
|
|
30475
30524
|
__name(quote, "quote");
|
|
30476
|
-
async function
|
|
30477
|
-
|
|
30478
|
-
|
|
30479
|
-
|
|
30480
|
-
|
|
30481
|
-
|
|
30482
|
-
|
|
30483
|
-
|
|
30484
|
-
|
|
30485
|
-
|
|
30486
|
-
|
|
30487
|
-
|
|
30525
|
+
async function readCreation(pageId) {
|
|
30526
|
+
return ServicePageCreationStatusSchema.parse(await api.getJson(`${pagePath(pageId)}/creation`));
|
|
30527
|
+
}
|
|
30528
|
+
__name(readCreation, "readCreation");
|
|
30529
|
+
function creationResponse(pageId, creation) {
|
|
30530
|
+
const editorUrl = serviceEditorUrl(api, pageId);
|
|
30531
|
+
return asText({
|
|
30532
|
+
servicePageId: pageId,
|
|
30533
|
+
status: creation.status === "running" ? "generating" : "error",
|
|
30534
|
+
...creation.status === "running" && editorUrl ? {
|
|
30535
|
+
editorUrl
|
|
30536
|
+
} : {},
|
|
30537
|
+
...creation.status === "failed" ? {
|
|
30538
|
+
errorCode: creation.errorCode
|
|
30539
|
+
} : {},
|
|
30540
|
+
nextAction: creation.status === "running" ? "La landing se est\xE1 generando. Puedes salir del chat y seguirla en Tareas. Vuelve a llamar action=status con el mismo servicePageId; no inicies otra generaci\xF3n." : "La creaci\xF3n termin\xF3 con error y queda en Tareas. Para crear otra landing, usa action=prepare con la marca elegida y muestra el nuevo precio; solo inicia build cuando el usuario lo autorice. No reutilices esta landing fallida."
|
|
30541
|
+
});
|
|
30542
|
+
}
|
|
30543
|
+
__name(creationResponse, "creationResponse");
|
|
30544
|
+
async function startOperation(page, quoted) {
|
|
30545
|
+
const operation = ServicePageOperationResponseSchema.parse(await api.postJson(`${pagePath(page.id)}/generate`, {
|
|
30546
|
+
quoteId: quoted.quoteId,
|
|
30547
|
+
idempotencyKey: serviceKey(page.id, "generation", page.draftRevision),
|
|
30548
|
+
expectedRevision: page.draftRevision
|
|
30549
|
+
}));
|
|
30550
|
+
if (operation.servicePageId !== page.id || operation.kind !== "generation") {
|
|
30551
|
+
throw mcp(McpErrorCode.INVALID_INPUT, "La operaci\xF3n no pertenece a la generaci\xF3n de esta landing.");
|
|
30488
30552
|
}
|
|
30489
30553
|
return operation;
|
|
30490
30554
|
}
|
|
@@ -30506,7 +30570,7 @@ function registerServiceLandingTools(server, api) {
|
|
|
30506
30570
|
}
|
|
30507
30571
|
__name(generatedResponse, "generatedResponse");
|
|
30508
30572
|
server.registerTool("create_service_landing", {
|
|
30509
|
-
description: guidance3.summary + " Parte del brandId de create_brand y termina con el enlace p\xFAblico de la p\xE1gina. NO es para productos de dropshipping (para eso generate_landing / create_product_task). Flujo: 1) action=prepare con brandId (gratis):
|
|
30573
|
+
description: guidance3.summary + " Parte del brandId de create_brand y termina con el enlace p\xFAblico de la p\xE1gina. NO es para productos de dropshipping (para eso generate_landing / create_product_task). Flujo: 1) action=prepare con brandId (gratis): prepara la landing y devuelve el precio estimado. 2) Pregunta una sola vez los datos que falten; puede omitirlos. 3) Cuando acepte el precio, action=build con servicePageId, confirmed=true, maxCredits y businessInfo: inicia una sola generaci\xF3n con la marca y las fuentes guardadas, sin una lectura pagada previa. 4) action=status hasta generated o error; generando se sigue en Tareas y contin\xFAa aunque cierre el chat. No llames build para continuar una etapa. 5) Muestra el enlace para verla y, si acepta, action=publish. Repetir una llamada no cobra dos veces. Con el enlace publicado sigue create_animated_video si quiere un video y create_service_images con el mismo brandId si quiere im\xE1genes.",
|
|
30510
30574
|
inputSchema: CreateServiceLandingInput.shape,
|
|
30511
30575
|
annotations: CREATES_PAID
|
|
30512
30576
|
}, async (rawInput) => {
|
|
@@ -30525,37 +30589,37 @@ function registerServiceLandingTools(server, api) {
|
|
|
30525
30589
|
});
|
|
30526
30590
|
}
|
|
30527
30591
|
const existing = await findPageForBrand(input.brandId);
|
|
30528
|
-
let
|
|
30529
|
-
|
|
30530
|
-
|
|
30531
|
-
|
|
30532
|
-
|
|
30592
|
+
let workspace = existing ? {
|
|
30593
|
+
page: await readPage(existing.id),
|
|
30594
|
+
resumed: true
|
|
30595
|
+
} : await createPageForBrand(input.brandId, Boolean(brand.logoKey));
|
|
30596
|
+
let page2 = workspace.page;
|
|
30533
30597
|
if (isPageGenerated(page2)) return generatedResponse(page2);
|
|
30598
|
+
let creation2 = await readCreation(page2.id);
|
|
30599
|
+
if (existing && creation2.status === "failed") {
|
|
30600
|
+
workspace = await createPageForBrand(input.brandId, Boolean(brand.logoKey));
|
|
30601
|
+
page2 = workspace.page;
|
|
30602
|
+
if (isPageGenerated(page2)) return generatedResponse(page2);
|
|
30603
|
+
creation2 = await readCreation(page2.id);
|
|
30604
|
+
}
|
|
30605
|
+
if (creation2.status !== "idle") return creationResponse(page2.id, creation2);
|
|
30534
30606
|
if (input.businessInfo) page2 = await addBusinessInfo(page2, input.businessInfo);
|
|
30535
|
-
const
|
|
30536
|
-
const generationQuote = await quote(page2, "generation");
|
|
30537
|
-
const facts = factsQuote ? quoteRange(factsQuote) : {
|
|
30538
|
-
min: 0,
|
|
30539
|
-
max: 0
|
|
30540
|
-
};
|
|
30607
|
+
const generationQuote = await quote(page2);
|
|
30541
30608
|
const build = quoteRange(generationQuote);
|
|
30542
|
-
const totalMin =
|
|
30543
|
-
const totalCredits =
|
|
30544
|
-
const requiredBalanceCredits =
|
|
30609
|
+
const totalMin = build.min;
|
|
30610
|
+
const totalCredits = build.max;
|
|
30611
|
+
const requiredBalanceCredits = generationQuote.credits;
|
|
30545
30612
|
const askFor = page2.facts.contact.channels.some((channel) => channel.kind === "whatsapp") ? "su ciudad o zona y sus servicios con precio (su WhatsApp ya viene de la marca: no lo pidas)" : "su WhatsApp o tel\xE9fono, su ciudad o zona y sus servicios con precio";
|
|
30546
30613
|
const priceText = totalMin === totalCredits ? `${totalCredits} cr\xE9ditos` : `entre ${totalMin} y ${totalCredits} cr\xE9ditos`;
|
|
30547
30614
|
return asText({
|
|
30548
30615
|
servicePageId: page2.id,
|
|
30549
30616
|
charged: false,
|
|
30550
|
-
...
|
|
30617
|
+
...workspace.resumed ? {
|
|
30551
30618
|
resumed: true
|
|
30552
30619
|
} : {},
|
|
30553
30620
|
business: page2.businessName,
|
|
30554
30621
|
known: summarizeFacts(page2.facts),
|
|
30555
30622
|
price: {
|
|
30556
|
-
...factsQuote ? {
|
|
30557
|
-
readBusinessInfoCredits: facts
|
|
30558
|
-
} : {},
|
|
30559
30623
|
buildPageCredits: build,
|
|
30560
30624
|
totalMinCredits: totalMin,
|
|
30561
30625
|
totalCredits,
|
|
@@ -30568,33 +30632,22 @@ function registerServiceLandingTools(server, api) {
|
|
|
30568
30632
|
throw mcp(McpErrorCode.INVALID_INPUT, "servicePageId es obligatorio: usa el que devolvi\xF3 prepare. No se cobr\xF3 nada.");
|
|
30569
30633
|
}
|
|
30570
30634
|
if (input.action === "status") {
|
|
30571
|
-
|
|
30572
|
-
|
|
30573
|
-
|
|
30574
|
-
|
|
30575
|
-
return asText({
|
|
30576
|
-
servicePageId: input.servicePageId,
|
|
30577
|
-
status: creation.status,
|
|
30578
|
-
...editorUrl ? {
|
|
30579
|
-
editorUrl
|
|
30580
|
-
} : {},
|
|
30581
|
-
...creation.status === "failed" ? {
|
|
30582
|
-
errorCode: creation.errorCode,
|
|
30583
|
-
reason: "No pudimos terminar la p\xE1gina. Tus datos siguen guardados."
|
|
30584
|
-
} : {},
|
|
30585
|
-
nextAction: creation.status === "running" ? "Sigue en curso. Vuelve a llamar action=status con el mismo servicePageId en unos segundos; no inicies otra etapa." : "La creaci\xF3n fall\xF3. Muestra el motivo al usuario y el enlace al editor, si est\xE1 disponible; no inicies otra generaci\xF3n sin su autorizaci\xF3n."
|
|
30586
|
-
});
|
|
30587
|
-
}
|
|
30588
|
-
}
|
|
30635
|
+
const creation2 = await readCreation(input.servicePageId);
|
|
30636
|
+
if (creation2.status !== "idle") return creationResponse(input.servicePageId, creation2);
|
|
30637
|
+
let page2 = await readPage(input.servicePageId);
|
|
30638
|
+
if (isPageGenerated(page2)) return generatedResponse(page2);
|
|
30589
30639
|
let operation2 = null;
|
|
30590
30640
|
if (input.operationId) {
|
|
30591
|
-
operation2 = await api.getJson(`/v1/service-pages/operations/${encodeURIComponent(input.operationId)}`);
|
|
30641
|
+
operation2 = ServicePageOperationResponseSchema.parse(await api.getJson(`/v1/service-pages/operations/${encodeURIComponent(input.operationId)}`));
|
|
30642
|
+
if (operation2.servicePageId !== input.servicePageId) {
|
|
30643
|
+
throw mcp(McpErrorCode.INVALID_INPUT, "La operaci\xF3n no pertenece a esta landing.");
|
|
30644
|
+
}
|
|
30592
30645
|
if (operation2.status === "queued" || operation2.status === "running") {
|
|
30593
30646
|
return asText({
|
|
30594
30647
|
servicePageId: input.servicePageId,
|
|
30595
30648
|
operationId: operation2.opId,
|
|
30596
30649
|
step: operation2.kind === "generation" ? "creando la p\xE1gina" : "leyendo los datos del negocio",
|
|
30597
|
-
status:
|
|
30650
|
+
status: "generating",
|
|
30598
30651
|
nextAction: "Sigue en curso. Llama action=status otra vez con el mismo operationId en unos segundos; no inicies otra etapa."
|
|
30599
30652
|
});
|
|
30600
30653
|
}
|
|
@@ -30602,49 +30655,28 @@ function registerServiceLandingTools(server, api) {
|
|
|
30602
30655
|
return asText({
|
|
30603
30656
|
servicePageId: input.servicePageId,
|
|
30604
30657
|
operationId: operation2.opId,
|
|
30605
|
-
status: "
|
|
30658
|
+
status: "generating",
|
|
30606
30659
|
// Unknown on purpose: the charge is exactly what is being
|
|
30607
30660
|
// confirmed. Settlement only charges a completed step.
|
|
30608
|
-
nextAction: "
|
|
30661
|
+
nextAction: "La landing se sigue generando: el servidor est\xE1 confirmando si se complet\xF3 y la resuelve solo. Si no se completa, se devuelve lo cobrado. Dile al usuario que sus datos est\xE1n guardados; vuelve a llamar action=status con el mismo operationId en unos minutos. No inicies otra generaci\xF3n mientras tanto."
|
|
30609
30662
|
});
|
|
30610
30663
|
}
|
|
30611
30664
|
if (operation2.status !== "succeeded") {
|
|
30612
30665
|
return asText({
|
|
30613
30666
|
servicePageId: input.servicePageId,
|
|
30614
30667
|
operationId: operation2.opId,
|
|
30615
|
-
status: "
|
|
30668
|
+
status: "error",
|
|
30669
|
+
errorCode: operation2.errorCode,
|
|
30616
30670
|
charged: false,
|
|
30617
30671
|
reason: operationFailureText(operation2.errorCode)
|
|
30618
30672
|
});
|
|
30619
30673
|
}
|
|
30620
30674
|
}
|
|
30621
|
-
|
|
30675
|
+
if (operation2?.status === "succeeded") page2 = await readPage(input.servicePageId);
|
|
30622
30676
|
if (isPageGenerated(page2)) return generatedResponse(page2);
|
|
30623
|
-
|
|
30624
|
-
|
|
30625
|
-
|
|
30626
|
-
servicePageId: page2.id,
|
|
30627
|
-
status: "not_generated",
|
|
30628
|
-
operationStatus: "unknown",
|
|
30629
|
-
...editorUrl ? {
|
|
30630
|
-
editorUrl
|
|
30631
|
-
} : {},
|
|
30632
|
-
reason: "La p\xE1gina a\xFAn no tiene un resultado generado. Sin operationId no podemos determinar el estado de la operaci\xF3n; consulta sus tareas o abre el editor para revisar su progreso.",
|
|
30633
|
-
nextAction: {
|
|
30634
|
-
tool: "list_tasks",
|
|
30635
|
-
arguments: {}
|
|
30636
|
-
}
|
|
30637
|
-
});
|
|
30638
|
-
}
|
|
30639
|
-
const missing = describeMissing(page2.missingFields);
|
|
30640
|
-
return asText({
|
|
30641
|
-
servicePageId: page2.id,
|
|
30642
|
-
status: page2.factExtractionCompleted ? "business_info_read" : "waiting_for_build",
|
|
30643
|
-
found: summarizeFacts(page2.facts),
|
|
30644
|
-
...missing.length ? {
|
|
30645
|
-
stillMissing: missing
|
|
30646
|
-
} : {},
|
|
30647
|
-
nextAction: page2.factExtractionCompleted ? `Muestra en pocas l\xEDneas lo que encontramos del negocio${missing.length ? " y lo que falta (puede agregarlo en businessInfo o seguir sin eso)" : ""}. Luego llama action=build con el mismo servicePageId, confirmed=true y el mismo maxCredits para crear la p\xE1gina.` : "A\xFAn no se leyeron los datos del negocio. Llama action=build con confirmed=true y el maxCredits que acept\xF3 el usuario."
|
|
30677
|
+
return creationResponse(page2.id, {
|
|
30678
|
+
status: "failed",
|
|
30679
|
+
errorCode: "SERVICE_PAGE_CREATION_STALLED"
|
|
30648
30680
|
});
|
|
30649
30681
|
}
|
|
30650
30682
|
if (input.action === "publish") {
|
|
@@ -30662,7 +30694,7 @@ function registerServiceLandingTools(server, api) {
|
|
|
30662
30694
|
});
|
|
30663
30695
|
return asText({
|
|
30664
30696
|
servicePageId: page2.id,
|
|
30665
|
-
status: "
|
|
30697
|
+
status: "generated",
|
|
30666
30698
|
publicUrl: published.publicUrl,
|
|
30667
30699
|
nextAction: `Comparte el enlace ${published.publicUrl} con el usuario. Si pidi\xF3 un video, sigue con create_animated_video action=prepare y landingUrl=${published.publicUrl}; si pidi\xF3 im\xE1genes, con create_service_images y brandId=${page2.brandId ?? "(el de su marca)"}.`
|
|
30668
30700
|
});
|
|
@@ -30670,7 +30702,8 @@ function registerServiceLandingTools(server, api) {
|
|
|
30670
30702
|
if (serviceApiCode(error)?.includes("SLUG")) {
|
|
30671
30703
|
return asText({
|
|
30672
30704
|
servicePageId: page2.id,
|
|
30673
|
-
status: "
|
|
30705
|
+
status: "generated",
|
|
30706
|
+
publicationErrorCode: "SERVICE_PAGE_SLUG_TAKEN",
|
|
30674
30707
|
slug,
|
|
30675
30708
|
nextAction: `La direcci\xF3n \xAB${slug}\xBB ya est\xE1 en uso. Prop\xF3n otra (por ejemplo \xAB${slug}-${(/* @__PURE__ */ new Date()).getFullYear()}\xBB o con la ciudad) y llama action=publish con slug.`
|
|
30676
30709
|
});
|
|
@@ -30683,12 +30716,10 @@ function registerServiceLandingTools(server, api) {
|
|
|
30683
30716
|
}
|
|
30684
30717
|
let page = await readPage(input.servicePageId);
|
|
30685
30718
|
if (isPageGenerated(page)) return generatedResponse(page);
|
|
30686
|
-
const
|
|
30719
|
+
const creation = await readCreation(page.id);
|
|
30720
|
+
if (creation.status !== "idle") return creationResponse(page.id, creation);
|
|
30687
30721
|
if (input.businessInfo) page = await addBusinessInfo(page, input.businessInfo);
|
|
30688
|
-
const
|
|
30689
|
-
const needsFacts = !page.factExtractionCompleted || addedInfo;
|
|
30690
|
-
const purpose = needsFacts ? "fact-extraction" : "generation";
|
|
30691
|
-
const quoted = await quote(page, purpose);
|
|
30722
|
+
const quoted = await quote(page);
|
|
30692
30723
|
const credits = quoteRange(quoted).max;
|
|
30693
30724
|
if (credits > input.maxCredits) {
|
|
30694
30725
|
return asText({
|
|
@@ -30698,15 +30729,18 @@ function registerServiceLandingTools(server, api) {
|
|
|
30698
30729
|
nextAction: `El precio subi\xF3 a ${credits} cr\xE9ditos, m\xE1s de lo aceptado (${input.maxCredits}). Preg\xFAntale al usuario si sigue y, si acepta, repite build con maxCredits=${credits}.`
|
|
30699
30730
|
});
|
|
30700
30731
|
}
|
|
30701
|
-
await requirePaidCreativeConfirmation(server,
|
|
30702
|
-
const operation = await startOperation(page,
|
|
30732
|
+
await requirePaidCreativeConfirmation(server, `Generar la landing del negocio. Precio estimado: hasta ${credits} cr\xE9ditos (total aceptado: ${input.maxCredits}).`);
|
|
30733
|
+
const operation = await startOperation(page, quoted);
|
|
30703
30734
|
return asText({
|
|
30704
30735
|
servicePageId: page.id,
|
|
30705
30736
|
operationId: operation.opId,
|
|
30706
|
-
step:
|
|
30707
|
-
status: operation.status,
|
|
30737
|
+
step: "creando la p\xE1gina",
|
|
30738
|
+
status: operation.status === "failed" || operation.status === "conflict" ? "error" : "generating",
|
|
30739
|
+
...operation.errorCode ? {
|
|
30740
|
+
errorCode: operation.errorCode
|
|
30741
|
+
} : {},
|
|
30708
30742
|
priceCredits: credits,
|
|
30709
|
-
nextAction: operation.status === "failed" ? operationFailureText(operation.errorCode) :
|
|
30743
|
+
nextAction: operation.status === "failed" || operation.status === "conflict" ? operationFailureText(operation.errorCode) : "La landing se est\xE1 generando y aparece en Tareas. Llama action=status con servicePageId hasta generated o error. La generaci\xF3n contin\xFAa aunque salgas del chat."
|
|
30710
30744
|
});
|
|
30711
30745
|
} catch (error) {
|
|
30712
30746
|
throw translateError(error);
|
|
@@ -30716,7 +30750,7 @@ function registerServiceLandingTools(server, api) {
|
|
|
30716
30750
|
__name(registerServiceLandingTools, "registerServiceLandingTools");
|
|
30717
30751
|
|
|
30718
30752
|
// src/tools/service-images.ts
|
|
30719
|
-
import { z as
|
|
30753
|
+
import { z as z125 } from "zod";
|
|
30720
30754
|
var guidance4 = getProductMakerCapabilityModelGuidance("create_service_images");
|
|
30721
30755
|
var SERVICE_IMAGE_FORMATS = [
|
|
30722
30756
|
"4:5",
|
|
@@ -30729,23 +30763,23 @@ var LANGUAGE_TAGS = {
|
|
|
30729
30763
|
en: "en-US",
|
|
30730
30764
|
pt: "pt-BR"
|
|
30731
30765
|
};
|
|
30732
|
-
var CreateServiceImagesInput =
|
|
30733
|
-
brandId:
|
|
30734
|
-
instruction:
|
|
30735
|
-
delegateToAi:
|
|
30736
|
-
format:
|
|
30737
|
-
count:
|
|
30738
|
-
quality:
|
|
30766
|
+
var CreateServiceImagesInput = z125.object({
|
|
30767
|
+
brandId: z125.string().uuid().optional().describe("ID de la marca (de create_brand). Recomendado: da nombre, colores, tono y servicios. Nunca un taskId de producto."),
|
|
30768
|
+
instruction: z125.string().trim().max(4e3).optional().describe("Qu\xE9 servicio o promoci\xF3n mostrar, con las palabras del usuario (ej. \xABcorte + barba a $35.000 los martes\xBB). Si el usuario deja que la IA decida, om\xEDtelo y usa delegateToAi=true."),
|
|
30769
|
+
delegateToAi: z125.boolean().optional().describe("true si el usuario prefiere que la IA elija qu\xE9 mostrar a partir de su marca."),
|
|
30770
|
+
format: z125.enum(SERVICE_IMAGE_FORMATS).optional().describe('Formato: "4:5" (feed, por defecto), "9:16" (historias/reels) o "1:1" (cuadrado).'),
|
|
30771
|
+
count: z125.number().int().min(1).max(SERVICE_IMAGE_MAX_COUNT).optional().describe("Cu\xE1ntas im\xE1genes, de 1 a 3 (por defecto 1)."),
|
|
30772
|
+
quality: z125.enum([
|
|
30739
30773
|
"standard",
|
|
30740
30774
|
"high"
|
|
30741
30775
|
]).optional().describe('Calidad: "standard" (por defecto) o "high" (m\xE1s cara; no disponible en 4:5).'),
|
|
30742
|
-
language:
|
|
30776
|
+
language: z125.enum([
|
|
30743
30777
|
"es",
|
|
30744
30778
|
"en",
|
|
30745
30779
|
"pt"
|
|
30746
30780
|
]).optional().describe("Idioma de los textos de la imagen (por defecto es)."),
|
|
30747
|
-
adCopy:
|
|
30748
|
-
confirmed:
|
|
30781
|
+
adCopy: z125.boolean().optional().describe("Compatibilidad con clientes anteriores: el copy para publicar siempre est\xE1 incluido en cada imagen de servicios."),
|
|
30782
|
+
confirmed: z125.boolean().optional().describe("Solo true despu\xE9s de mostrar el precio y que el usuario acepte. Sin confirmed, solo cotiza y no cobra.")
|
|
30749
30783
|
}).strict();
|
|
30750
30784
|
function serviceImageModel(quality) {
|
|
30751
30785
|
return quality === "high" ? AD_CREATIVE_MODELS.PREMIUM : AD_CREATIVE_MODELS.STANDARD;
|
|
@@ -30856,7 +30890,7 @@ function registerServiceImageTools(server, api, options = {}) {
|
|
|
30856
30890
|
nextAction: "Dile al usuario que est\xE1s creando sus im\xE1genes. Llama get_task_status con este taskId (waitSeconds=45) hasta done (trae las im\xE1genes) o error."
|
|
30857
30891
|
});
|
|
30858
30892
|
} catch (error) {
|
|
30859
|
-
if (error instanceof
|
|
30893
|
+
if (error instanceof z125.ZodError) throw invalidInputFromZod(error);
|
|
30860
30894
|
throw translateError(error);
|
|
30861
30895
|
}
|
|
30862
30896
|
});
|
|
@@ -30864,7 +30898,7 @@ function registerServiceImageTools(server, api, options = {}) {
|
|
|
30864
30898
|
__name(registerServiceImageTools, "registerServiceImageTools");
|
|
30865
30899
|
|
|
30866
30900
|
// src/tools/creatives.ts
|
|
30867
|
-
import { z as
|
|
30901
|
+
import { z as z126 } from "zod";
|
|
30868
30902
|
var generateFreeVideoGuidance = getProductMakerCapabilityModelGuidance("generate_free_video");
|
|
30869
30903
|
var generateVideoCreativeGuidance = getProductMakerCapabilityModelGuidance("generate_video_creative");
|
|
30870
30904
|
var generateImageCreativesGuidance = getProductMakerCapabilityModelGuidance("generate_image_creatives");
|
|
@@ -30875,72 +30909,72 @@ var CreativeRefs = {
|
|
|
30875
30909
|
images: ImagesInput,
|
|
30876
30910
|
language: Lang.describe('Idioma del contenido. Ej. "es", "en", "pt". REQUERIDO \u2014 si el usuario no lo dijo, PREG\xDANTALE antes de invocar. NUNCA infieras desde el contexto del chat ni asumas un default.'),
|
|
30877
30911
|
country: Country.describe('Pa\xEDs objetivo ISO. Ej. "CO", "MX", "US", "AR". Define moneda, m\xE9todos de pago y tono. REQUERIDO \u2014 si el usuario no lo dijo, PREG\xDANTALE antes de invocar. NUNCA infieras desde el contexto del chat ni asumas un default.'),
|
|
30878
|
-
price:
|
|
30879
|
-
offer:
|
|
30880
|
-
compareAtPrice:
|
|
30881
|
-
productContext:
|
|
30882
|
-
productLabel:
|
|
30883
|
-
buyerPersona:
|
|
30884
|
-
isCombo:
|
|
30885
|
-
competitorScanEnabled:
|
|
30886
|
-
brandId:
|
|
30912
|
+
price: z126.string().min(1).max(120).optional().describe('Precio en formato libre \u2014 ej. "$89.900", "USD 29.99". Opcional pero MUY IMPACTANTE para conversi\xF3n: si el usuario no lo mencion\xF3, PREG\xDANTALE antes de invocar. Si el usuario te dice "t\xFA elige", omite el campo y la IA del backend sugiere uno.'),
|
|
30913
|
+
offer: z126.string().min(1).max(240).optional().describe('Oferta a destacar \u2014 ej. "2x1", "Env\xEDo gratis", "50% OFF". Opcional pero MUY IMPACTANTE: si el usuario no lo mencion\xF3, PREG\xDANTALE antes de invocar (es v\xE1lido que diga "sin oferta"). Si el usuario te dice "t\xFA elige", omite el campo.'),
|
|
30914
|
+
compareAtPrice: z126.string().min(1).max(120).optional().describe('Opcional. Precio anterior o de referencia para mostrar descuento. Ej. "$129.000" cuando price="$89.900".'),
|
|
30915
|
+
productContext: z126.string().max(3e3).optional().describe("Opcional. Informacion adicional del producto que la IA debe usar como contexto prioritario: uso real, comprador, restricciones, diferenciadores o direccion creativa. No reemplaza la investigacion de competencia; si hay competencia, guia el primer angulo y los outputs no deben contradecirlo."),
|
|
30916
|
+
productLabel: z126.string().trim().max(80).optional().describe('Opcional. Nombre o tipo del producto en pocas palabras (ej. "collar de oro", "quita pelusas para ropa"). Es AUTORITATIVO: la IA usa esta identidad y no la reemplaza por otra categor\xEDa. Si lo omites, la IA lo detecta desde la imagen. NO salta la extracci\xF3n.'),
|
|
30917
|
+
buyerPersona: z126.string().optional().describe('Opcional. Descripci\xF3n del comprador objetivo. Ej. "Mujeres 35-50, profesionales urbanas". Si se omite, la IA infiere desde el \xE1ngulo y producto.'),
|
|
30918
|
+
isCombo: z126.boolean().optional().describe("Opcional. Si true, el creativo presenta el producto como combo/pack. Default false."),
|
|
30919
|
+
competitorScanEnabled: z126.boolean().optional().describe("Opcional. Default false: omitirlo significa SIN estudio de mercado. Antes de crear, llama estimate_market_study_cost, muestra al usuario el costo con y sin estudio y preg\xFAntale si lo quiere; env\xEDa true solo si lo acepta (o si solicita la narrativa an\xE1lisis de mercado). En video, true analiza anuncios de la competencia y desbloquea la narrativa an\xE1lisis de mercado; si el estudio no encuentra datos suficientes, degrada al planner cl\xE1sico."),
|
|
30920
|
+
brandId: z126.string().uuid().optional().describe("Opcional. ID de una marca del usuario; si se env\xEDa, el sistema usa su voz, colores y persona para enriquecer el creativo.")
|
|
30887
30921
|
};
|
|
30888
|
-
var VideoPresenter =
|
|
30889
|
-
|
|
30890
|
-
mode:
|
|
30922
|
+
var VideoPresenter = z126.discriminatedUnion("mode", [
|
|
30923
|
+
z126.object({
|
|
30924
|
+
mode: z126.literal("none")
|
|
30891
30925
|
}).strict(),
|
|
30892
|
-
|
|
30893
|
-
mode:
|
|
30894
|
-
actorId:
|
|
30926
|
+
z126.object({
|
|
30927
|
+
mode: z126.literal("saved_actor"),
|
|
30928
|
+
actorId: z126.string().trim().min(1).max(120).describe("ID devuelto por list_actors para un actor guardado del usuario.")
|
|
30895
30929
|
}).strict(),
|
|
30896
|
-
|
|
30897
|
-
mode:
|
|
30898
|
-
description:
|
|
30930
|
+
z126.object({
|
|
30931
|
+
mode: z126.literal("described"),
|
|
30932
|
+
description: z126.string().trim().min(1).max(500).describe("Descripci\xF3n concreta de la persona que presenta el producto.")
|
|
30899
30933
|
}).strict()
|
|
30900
30934
|
]);
|
|
30901
|
-
var VideoCreativeSetup =
|
|
30902
|
-
|
|
30903
|
-
mode:
|
|
30935
|
+
var VideoCreativeSetup = z126.discriminatedUnion("mode", [
|
|
30936
|
+
z126.object({
|
|
30937
|
+
mode: z126.literal("automatic").describe('S\xF3lo cuando el usuario pidi\xF3 expl\xEDcitamente "decide todo".')
|
|
30904
30938
|
}).strict(),
|
|
30905
|
-
|
|
30906
|
-
mode:
|
|
30939
|
+
z126.object({
|
|
30940
|
+
mode: z126.literal("guided"),
|
|
30907
30941
|
videoPreset: VideoPresetEnum.default("auto").describe('Narrativa opcional. Con estudio de mercado no la preguntes: se usa "auto" y el estudio define la estructura. Sin estudio conserva la elecci\xF3n del usuario. Todas las narrativas funcionan en Un solo clip y Multiescena.'),
|
|
30908
|
-
buyerPersona:
|
|
30942
|
+
buyerPersona: z126.string().trim().min(1).max(360),
|
|
30909
30943
|
animationStyle: AnimationStyleEnum.optional().describe('Opcional. Estilo visual SOLO para presets animados ("pixar_problem" o "pixar_sassy") \u2014 la API lo rechaza con cualquier otro preset. Opciones: "pixar_3d" (default, look 3D de pel\xEDcula animada), "claymation" (plastilina stop-motion artesanal), "wes_anderson" (tableau sim\xE9trico pastel), "sci_fi" (futurista con HUDs y ne\xF3n), "realista" (fotorrealista, fiel al producto). Si el usuario pide un look animado sin nombrar el estilo, omite el campo.'),
|
|
30910
30944
|
presenter: VideoPresenter,
|
|
30911
|
-
creativeDirection:
|
|
30945
|
+
creativeDirection: z126.string().trim().min(1).max(500).nullable().describe("Direcci\xF3n visual elegida. null significa que el usuario deleg\xF3 expl\xEDcitamente esta decisi\xF3n.")
|
|
30912
30946
|
}).strict()
|
|
30913
30947
|
]);
|
|
30914
|
-
var VideoInput =
|
|
30948
|
+
var VideoInput = z126.object({
|
|
30915
30949
|
images: CreativeRefs.images.optional(),
|
|
30916
30950
|
winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
|
|
30917
|
-
title:
|
|
30918
|
-
primaryAngle:
|
|
30951
|
+
title: z126.string().min(1).describe('T\xEDtulo corto del producto. Aparece en la primera vista del video. Ej. "Crema Anti-Edad Premium".'),
|
|
30952
|
+
primaryAngle: z126.string().min(1).describe('\xC1ngulo de venta principal (frase del beneficio). Ej. "Reduce arrugas en 14 d\xEDas" o "Para quienes odian las cremas grasosas".'),
|
|
30919
30953
|
language: CreativeRefs.language,
|
|
30920
30954
|
country: CreativeRefs.country,
|
|
30921
|
-
aspectRatio:
|
|
30955
|
+
aspectRatio: z126.enum([
|
|
30922
30956
|
"9:16",
|
|
30923
30957
|
"16:9",
|
|
30924
30958
|
"Auto"
|
|
30925
30959
|
]).describe('Relaci\xF3n de aspecto. "9:16" = vertical (TikTok/Reels \u2014 default recomendado para ads). "16:9" = horizontal (YouTube). "Auto" = decide la IA.'),
|
|
30926
30960
|
generateAiEdit: AiEditRequestSchema.optional().describe('Opcional. Pide la Edici\xF3n con IA: una pasada que a\xF1ade texto, efectos y m\xFAsica sobre cada video entregado (variante with_ai_edit; se cobra al entregar, por video). Nivel: "economy" (Econ\xF3mica, Sonnet 5.5, m\xE1s barata) o "pro" (Opus 5.5, mejor calidad, ~10 min). true equivale a "pro"; false/omitido = sin edici\xF3n.'),
|
|
30927
|
-
durationSeconds:
|
|
30928
|
-
videoAngleCount:
|
|
30961
|
+
durationSeconds: z126.number().int().min(4).max(30).default(15).describe("Opcional. Duraci\xF3n objetivo: Un solo clip Econ\xF3mico o Medio usa 15s; Un solo clip Pro usa 15s o 30s; Multiescena usa 15s o 30s totales. La combinaci\xF3n de formato y calidad determina la ruta y el costo."),
|
|
30962
|
+
videoAngleCount: z126.number().int().min(1).max(3).describe("Cantidad de videos a renderizar: 1, 2 o 3. Es una decisi\xF3n de costo obligatoria: preg\xFAntala incluso cuando creativeSetup.mode=automatic."),
|
|
30929
30963
|
angleNarratives: PublicNarrativeStyleEnum.array().max(3).optional().describe('Opcional. Narrativa POR \xC1NGULO (posicional). Valores actuales: "review", "ugc_how_to", "ugc_unboxing_chaos", "problem_product_cta" (problema concreto, producto como soluci\xF3n y CTA), "product_showcase", "wearable_showcase", "cinematic", "wild_card", "animated_problem_pixar", "sassy_product_pixar", "market" (narrativa an\xE1lisis de mercado: adapta el video a los patrones ganadores estudiados de la competencia; requiere competitorScanEnabled: true). angleNarratives[i] fuerza la narrativa del \xE1ngulo i; las posiciones restantes las elige la IA. La lista no puede superar videoAngleCount.'),
|
|
30930
30964
|
creativeSetup: VideoCreativeSetup.describe("Configuraci\xF3n creativa obligatoria. En guided pregunta narrativa, p\xFAblico, presentador y direcci\xF3n antes de confirmar. Usa automatic s\xF3lo si el usuario deleg\xF3 todo expl\xEDcitamente."),
|
|
30931
30965
|
videoStructure: VideoStructureEnum.default("single_take").describe('Opcional. Formato: "single_take" = Un solo clip (generado completo; puede incluir cambios de plano) o "multi_scene" = Multiescena (varias tomas concatenadas). Default: single_take.'),
|
|
30932
30966
|
videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El sistema elige el proveedor internamente. Default: economy.'),
|
|
30933
30967
|
videoResolution: VideoResolutionEnum.optional().describe('Opcional. Resoluci\xF3n del render: "480p" o "720p". Si se omite, se usa 480p; elige 720p expl\xEDcitamente si necesitas m\xE1s nitidez.'),
|
|
30934
|
-
features:
|
|
30968
|
+
features: z126.array(z126.string()).optional().describe('Opcional. Lista de features/beneficios clave a mencionar. Ej. ["resistente al agua", "bater\xEDa 24h", "carga inal\xE1mbrica"].'),
|
|
30935
30969
|
price: CreativeRefs.price,
|
|
30936
30970
|
offer: CreativeRefs.offer,
|
|
30937
30971
|
productContext: CreativeRefs.productContext,
|
|
30938
30972
|
productLabel: CreativeRefs.productLabel,
|
|
30939
|
-
cta:
|
|
30940
|
-
scriptNotes:
|
|
30973
|
+
cta: z126.string().optional().describe('Opcional. Call-to-action final del video. Ej. "Compra ahora", "Pide el tuyo hoy", "Link en bio". Si se omite, la IA escribe uno.'),
|
|
30974
|
+
scriptNotes: z126.string().optional().describe('Opcional. Notas/restricciones para el guion (la IA las usa al redactar). Ej. "No mencionar la marca X", "Tono divertido, no cl\xEDnico", "Mencionar 2x1". NO es el guion literal: creativeSetup.mode=guided activa siempre la revisi\xF3n palabra-por-palabra con get_video_script / approve_video_script.'),
|
|
30941
30975
|
creativeGender: CreativeGenderEnum.optional().describe('Opcional. QUI\xC9N APARECE EN PANTALLA en el video: mujer ("female"), hombre ("male") o ambos ("mixed"). NO es la voz; cuando se fija, la voz se alinea sola con el personaje. M\xE1ndalo en cuanto el usuario diga qui\xE9n debe SALIR en el video, con cualquier redacci\xF3n ("quiero una mujer", "que salga un hombre", "protagonista femenina"): si no lo mandas, el g\xE9nero lo inventa la IA y el usuario puede recibir lo contrario de lo que pidi\xF3 sin ning\xFAn aviso. NO lo mandes cuando hable del P\xDABLICO COMPRADOR ("esto es para hombres", "mi p\xFAblico son mujeres", "va dirigido a mam\xE1s"): eso es a qui\xE9n se le vende, no qui\xE9n act\xFAa, y fijarlo ah\xED pinea un protagonista que nadie pidi\xF3. "mixed" solo cuando pida expl\xEDcitamente ambos, y ten en cuenta que no garantiza una mezcla: no fija ning\xFAn g\xE9nero y cada creativo elige su protagonista. No lo preguntes como paso obligatorio. Si creativeSetup.presenter.mode="saved_actor", el personaje guardado manda sobre este campo.'),
|
|
30942
30976
|
competitorScanEnabled: CreativeRefs.competitorScanEnabled,
|
|
30943
|
-
replicateWinnerWhenFound:
|
|
30977
|
+
replicateWinnerWhenFound: z126.boolean().optional().describe("Conserva la preferencia de copiar un ganador si existe. false permite estudiar el mercado sin reemplazar un \xE1ngulo por el anuncio ganador. No a\xF1adas una pregunta obligatoria para este campo."),
|
|
30944
30978
|
brandId: CreativeRefs.brandId
|
|
30945
30979
|
}).strict();
|
|
30946
30980
|
var FreeVideoQualityEnum = VideoQualityEnum;
|
|
@@ -30958,7 +30992,7 @@ var FREE_VIDEO_DURATIONS_BY_QUALITY = {
|
|
|
30958
30992
|
length: 29
|
|
30959
30993
|
}, (_, index) => index + 2)
|
|
30960
30994
|
};
|
|
30961
|
-
var FreeVideoModelIdEnum =
|
|
30995
|
+
var FreeVideoModelIdEnum = z126.enum([
|
|
30962
30996
|
"grok-imagine-video-1-5-preview",
|
|
30963
30997
|
"minimax-h3/reference-to-video",
|
|
30964
30998
|
"wan/3-0-video",
|
|
@@ -30969,66 +31003,66 @@ var FREE_SELECTABLE_MODEL_IDS = [
|
|
|
30969
31003
|
"minimax-h3/reference-to-video",
|
|
30970
31004
|
"wan/3-0-video"
|
|
30971
31005
|
];
|
|
30972
|
-
var FreeVideoInput =
|
|
31006
|
+
var FreeVideoInput = z126.object({
|
|
30973
31007
|
images: ImagesInput.optional().describe("Opcional. 1-5 fotos del producto. Om\xEDtelo para generar desde texto puro."),
|
|
30974
|
-
rawPrompt:
|
|
31008
|
+
rawPrompt: z126.string().trim().min(1).max(2e3).describe("Prompt o guion exacto del video. Si activas subt\xEDtulos, este mismo texto se usa como guion de subt\xEDtulos."),
|
|
30975
31009
|
language: CreativeRefs.language,
|
|
30976
31010
|
quality: FreeVideoQualityEnum.describe('Calidad del video: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro (Wan).'),
|
|
30977
31011
|
// Retired in MCP 7.0.0 (Task 11): kept in the schema, accepted, and
|
|
30978
31012
|
// parsed ONLY so the handler can reject it with a message naming its
|
|
30979
31013
|
// replacement — dropping it silently would turn a caller's explicit
|
|
30980
31014
|
// Pro++ pick into a quiet fallback to Wan.
|
|
30981
|
-
freeProModel:
|
|
31015
|
+
freeProModel: z126.enum([
|
|
30982
31016
|
"wan",
|
|
30983
31017
|
"seedance"
|
|
30984
31018
|
]).optional().describe("ELIMINADO en MCP 7.0.0 \u2014 usa `modelId`. Enviar este campo produce un error."),
|
|
30985
31019
|
modelId: FreeVideoModelIdEnum.optional().describe('Opcional. Elige expl\xEDcitamente el modelo del registro en vez del default de la calidad: "grok-imagine-video-1-5-preview" (Grok 1.5), "minimax-h3/reference-to-video" (H3 Max) o "wan/3-0-video" (Wan 3.0). Om\xEDtelo para usar el modelo por defecto de la calidad elegida. El modelo determina la duraci\xF3n permitida (Grok 6/8/10/15s, H3 Max 4-15s, Wan 2-30s) y el precio. "bytedance/seedance-2-5" est\xE1 inactivo y se rechaza con un error claro, nunca un 500.'),
|
|
30986
|
-
durationSeconds:
|
|
31020
|
+
durationSeconds: z126.number().int().min(2).max(30).describe("Duraci\xF3n exacta. Econ\xF3mico: 6, 8, 10 o 15s; Medio: enteros de 4 a 15s; Pro Wan: 2 a 30s; Pro++ Seedance: 4 a 30s."),
|
|
30987
31021
|
videoResolution: VideoResolutionEnum.describe("Resoluci\xF3n del video: 480p o 720p."),
|
|
30988
|
-
generateAiMusic:
|
|
31022
|
+
generateAiMusic: z126.boolean().default(false).describe('Opcional. Agrega m\xFAsica instrumental IA debajo del audio nativo. Default false. Equivale a generateAiEdit (nivel "pro"): la Edici\xF3n con IA trae su propia m\xFAsica.'),
|
|
30989
31023
|
generateAiEdit: AiEditRequestSchema.optional().describe('Opcional. Pide la Edici\xF3n con IA: una pasada que a\xF1ade texto, gr\xE1ficos y m\xFAsica sobre el video ya entregado (variante with_ai_edit; se cobra al entregar). Nivel: "economy" (Econ\xF3mica, Sonnet 5.5, m\xE1s barata) o "pro" (Opus 5.5, mejor calidad, ~10 min). true equivale a "pro". Default sin edici\xF3n.'),
|
|
30990
|
-
addSubtitles:
|
|
30991
|
-
idempotencyKey:
|
|
31024
|
+
addSubtitles: z126.boolean().default(false).describe("Opcional. Quema subt\xEDtulos usando el rawPrompt exacto. Default false."),
|
|
31025
|
+
idempotencyKey: z126.string().uuid().optional().describe("Opcional. Se acepta por compatibilidad pero se ignora: la identidad del reintento se deriva autom\xE1ticamente de los argumentos sem\xE1nticos, as\xED que un retry con los mismos argumentos ya es idempotente sin este campo.")
|
|
30992
31026
|
}).strict();
|
|
30993
31027
|
var imageStyleList = ImageCreativeStyleEnum.options.join(" | ");
|
|
30994
|
-
var ImageCreativeSetup =
|
|
30995
|
-
|
|
30996
|
-
mode:
|
|
31028
|
+
var ImageCreativeSetup = z126.discriminatedUnion("mode", [
|
|
31029
|
+
z126.object({
|
|
31030
|
+
mode: z126.literal("automatic")
|
|
30997
31031
|
}).strict(),
|
|
30998
|
-
|
|
30999
|
-
mode:
|
|
31000
|
-
creativeArchetype:
|
|
31032
|
+
z126.object({
|
|
31033
|
+
mode: z126.literal("guided"),
|
|
31034
|
+
creativeArchetype: z126.union([
|
|
31001
31035
|
ImageCreativeArchetypeEnum,
|
|
31002
|
-
|
|
31036
|
+
z126.literal("ai_decides")
|
|
31003
31037
|
]),
|
|
31004
|
-
visualTreatment:
|
|
31038
|
+
visualTreatment: z126.union([
|
|
31005
31039
|
ImageCreativeVisualTreatmentEnum,
|
|
31006
|
-
|
|
31040
|
+
z126.literal("ai_decides")
|
|
31007
31041
|
]),
|
|
31008
31042
|
aspectRatio: ImageCreativeAspectRatioEnum,
|
|
31009
|
-
nVariants:
|
|
31010
|
-
|
|
31011
|
-
|
|
31012
|
-
|
|
31013
|
-
|
|
31014
|
-
|
|
31043
|
+
nVariants: z126.union([
|
|
31044
|
+
z126.literal(1),
|
|
31045
|
+
z126.literal(2),
|
|
31046
|
+
z126.literal(3),
|
|
31047
|
+
z126.literal(4),
|
|
31048
|
+
z126.literal(6)
|
|
31015
31049
|
]),
|
|
31016
|
-
imageModel:
|
|
31017
|
-
styleMix:
|
|
31018
|
-
generateAdCopy:
|
|
31019
|
-
competitorScanEnabled:
|
|
31020
|
-
productContext:
|
|
31021
|
-
creativeDirection:
|
|
31022
|
-
brandColors:
|
|
31023
|
-
headline:
|
|
31024
|
-
subheadline:
|
|
31050
|
+
imageModel: z126.enum(PUBLIC_IMAGE_QUALITY_INPUTS).describe('Calidad: "image:1k" (Est\xE1ndar) o "image:2k" (Premium). Los tokens gpt-image-2-5:{1k,2k} y gpt-image-2:{1k,2k} se siguen aceptando.'),
|
|
31051
|
+
styleMix: z126.boolean().nullable().describe("Decisi\xF3n s\xF3lo para 2\u20134 variantes. Usa null para 1 o 6, cuando la UI no hace esta pregunta."),
|
|
31052
|
+
generateAdCopy: z126.boolean(),
|
|
31053
|
+
competitorScanEnabled: z126.boolean(),
|
|
31054
|
+
productContext: z126.string().trim().min(1).max(3e3).nullable(),
|
|
31055
|
+
creativeDirection: z126.string().trim().min(1).max(500).nullable(),
|
|
31056
|
+
brandColors: z126.string().trim().min(1).max(240).nullable().describe('Colores en lenguaje natural, igual que en el chat web. Ej. "Azul y Dorado". null significa sin colores espec\xEDficos.'),
|
|
31057
|
+
headline: z126.string().trim().min(1).max(120).nullable(),
|
|
31058
|
+
subheadline: z126.string().trim().min(1).max(160).nullable()
|
|
31025
31059
|
}).strict()
|
|
31026
31060
|
]).superRefine((setup, context) => {
|
|
31027
31061
|
if (setup.mode !== "guided") return;
|
|
31028
31062
|
const needsStyleMix = setup.nVariants >= 2 && setup.nVariants <= 4;
|
|
31029
31063
|
if (needsStyleMix && setup.styleMix === null) {
|
|
31030
31064
|
context.addIssue({
|
|
31031
|
-
code:
|
|
31065
|
+
code: z126.ZodIssueCode.custom,
|
|
31032
31066
|
path: [
|
|
31033
31067
|
"styleMix"
|
|
31034
31068
|
],
|
|
@@ -31037,7 +31071,7 @@ var ImageCreativeSetup = z125.discriminatedUnion("mode", [
|
|
|
31037
31071
|
}
|
|
31038
31072
|
if (!needsStyleMix && setup.styleMix !== null) {
|
|
31039
31073
|
context.addIssue({
|
|
31040
|
-
code:
|
|
31074
|
+
code: z126.ZodIssueCode.custom,
|
|
31041
31075
|
path: [
|
|
31042
31076
|
"styleMix"
|
|
31043
31077
|
],
|
|
@@ -31046,7 +31080,7 @@ var ImageCreativeSetup = z125.discriminatedUnion("mode", [
|
|
|
31046
31080
|
}
|
|
31047
31081
|
if (imageResolutionOf(setup.imageModel) === "2k" && setup.aspectRatio === "4:5") {
|
|
31048
31082
|
context.addIssue({
|
|
31049
|
-
code:
|
|
31083
|
+
code: z126.ZodIssueCode.custom,
|
|
31050
31084
|
path: [
|
|
31051
31085
|
"aspectRatio"
|
|
31052
31086
|
],
|
|
@@ -31054,55 +31088,55 @@ var ImageCreativeSetup = z125.discriminatedUnion("mode", [
|
|
|
31054
31088
|
});
|
|
31055
31089
|
}
|
|
31056
31090
|
});
|
|
31057
|
-
var LandingCreativeSetup =
|
|
31058
|
-
|
|
31059
|
-
mode:
|
|
31091
|
+
var LandingCreativeSetup = z126.discriminatedUnion("mode", [
|
|
31092
|
+
z126.object({
|
|
31093
|
+
mode: z126.literal("automatic")
|
|
31060
31094
|
}).strict(),
|
|
31061
|
-
|
|
31062
|
-
mode:
|
|
31095
|
+
z126.object({
|
|
31096
|
+
mode: z126.literal("guided"),
|
|
31063
31097
|
landingStrategy: LandingStrategyEnum,
|
|
31064
31098
|
landingImageFormat: LandingImageFormatEnum,
|
|
31065
|
-
competitorScanEnabled:
|
|
31066
|
-
paymentMethods:
|
|
31067
|
-
productContext:
|
|
31068
|
-
creativeDirection:
|
|
31069
|
-
headline:
|
|
31070
|
-
subheadline:
|
|
31099
|
+
competitorScanEnabled: z126.boolean(),
|
|
31100
|
+
paymentMethods: z126.string().trim().min(1).max(240).nullable(),
|
|
31101
|
+
productContext: z126.string().trim().min(1).max(3e3).nullable(),
|
|
31102
|
+
creativeDirection: z126.string().trim().min(1).max(500).nullable(),
|
|
31103
|
+
headline: z126.string().trim().min(1).max(120).nullable(),
|
|
31104
|
+
subheadline: z126.string().trim().min(1).max(160).nullable()
|
|
31071
31105
|
}).strict()
|
|
31072
31106
|
]);
|
|
31073
|
-
var ImageInput =
|
|
31107
|
+
var ImageInput = z126.object({
|
|
31074
31108
|
images: CreativeRefs.images.optional(),
|
|
31075
31109
|
winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
|
|
31076
|
-
productTitle:
|
|
31077
|
-
primaryAngle:
|
|
31110
|
+
productTitle: z126.string().min(1).describe('Nombre del producto. Ej. "Crema Anti-Edad Premium".'),
|
|
31111
|
+
primaryAngle: z126.string().min(1).optional().describe('Opcional. \xC1ngulo de venta principal. Si se omite, ProductMaker lo genera y creativeSetup.mode="guided" lo muestra para revisi\xF3n antes de crear las im\xE1genes.'),
|
|
31078
31112
|
buyerPersona: CreativeRefs.buyerPersona,
|
|
31079
31113
|
language: CreativeRefs.language,
|
|
31080
31114
|
country: CreativeRefs.country,
|
|
31081
31115
|
creativeSetup: ImageCreativeSetup.describe("Configuraci\xF3n obligatoria equivalente al wizard web. Usa guided salvo que el usuario delegue expl\xEDcitamente todo; presenta las decisiones guiadas en un \xFAnico checklist compacto."),
|
|
31082
31116
|
imageStyle: ImageCreativeStyleEnum.optional().describe(`Opcional. Estilo del shot del producto. Valores: ${imageStyleList}. Si se omite, la IA escoge seg\xFAn el archetype.`),
|
|
31083
|
-
features:
|
|
31117
|
+
features: z126.array(z126.string()).optional().describe('Opcional. Features/beneficios a destacar visualmente. Ej. ["resistente al agua", "ultra liviano"].'),
|
|
31084
31118
|
price: CreativeRefs.price,
|
|
31085
|
-
omitPrice:
|
|
31119
|
+
omitPrice: z126.boolean().optional().describe("Pon true \xFAnicamente cuando el usuario pida expl\xEDcitamente una imagen sin precio. Evita que el backend reutilice un precio extra\xEDdo del producto. No lo combines con price ni compareAtPrice."),
|
|
31086
31120
|
compareAtPrice: CreativeRefs.compareAtPrice,
|
|
31087
31121
|
offer: CreativeRefs.offer,
|
|
31088
31122
|
productLabel: CreativeRefs.productLabel,
|
|
31089
31123
|
isCombo: CreativeRefs.isCombo,
|
|
31090
31124
|
brandId: CreativeRefs.brandId
|
|
31091
31125
|
});
|
|
31092
|
-
var EditImageCreativeInput =
|
|
31093
|
-
taskId:
|
|
31094
|
-
variantIndex:
|
|
31095
|
-
clientRequestId:
|
|
31096
|
-
instruction:
|
|
31126
|
+
var EditImageCreativeInput = z126.object({
|
|
31127
|
+
taskId: z126.string().uuid().describe("ID de la tarea de imagen ya finalizada."),
|
|
31128
|
+
variantIndex: z126.number().int().min(0).max(10).describe("\xCDndice de la variante a corregir (0 = primera imagen)."),
|
|
31129
|
+
clientRequestId: z126.string().min(1).max(160).optional().describe("Identidad estable de esta correcci\xF3n; reutil\xEDzala al reconciliar una respuesta perdida, no para otra instrucci\xF3n."),
|
|
31130
|
+
instruction: z126.string().min(1).max(1e3).describe('Qu\xE9 cambiar en esa imagen. Ej. "quita el badge de env\xEDo gratis", "cambia el fondo a blanco".')
|
|
31097
31131
|
});
|
|
31098
|
-
var LandingInput =
|
|
31099
|
-
includeInitialLandingGif:
|
|
31132
|
+
var LandingInput = z126.object({
|
|
31133
|
+
includeInitialLandingGif: z126.boolean().optional().describe("Opcional. En nuevas landings cl\xE1sicas habilitadas, omitirlo incluye el primer GIF del producto y su coste en el total. Env\xEDa false si el usuario lo excluye: no se genera ni se reserva su coste. Conserva la elecci\xF3n al confirmar y al reintentar."),
|
|
31100
31134
|
images: CreativeRefs.images.optional(),
|
|
31101
31135
|
winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
|
|
31102
31136
|
language: CreativeRefs.language,
|
|
31103
31137
|
country: CreativeRefs.country,
|
|
31104
31138
|
creativeSetup: LandingCreativeSetup.describe("Configuraci\xF3n obligatoria de landing cl\xE1sica equivalente al wizard web. No expone landing editable/code mientras siga siendo admin-only."),
|
|
31105
|
-
salesAngle:
|
|
31139
|
+
salesAngle: z126.string().optional().describe('Opcional. \xC1ngulo de venta principal. Ej. "Reduce arrugas en 14 d\xEDas". Si se omite, la IA lo deduce de la imagen.'),
|
|
31106
31140
|
buyerPersona: CreativeRefs.buyerPersona,
|
|
31107
31141
|
price: CreativeRefs.price,
|
|
31108
31142
|
compareAtPrice: CreativeRefs.compareAtPrice,
|
|
@@ -31384,8 +31418,8 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
|
|
|
31384
31418
|
server.registerTool("get_image_edit_status", {
|
|
31385
31419
|
description: imageEditStatusGuidance.summary,
|
|
31386
31420
|
inputSchema: {
|
|
31387
|
-
taskId:
|
|
31388
|
-
operationId:
|
|
31421
|
+
taskId: z126.string().uuid(),
|
|
31422
|
+
operationId: z126.string().uuid()
|
|
31389
31423
|
},
|
|
31390
31424
|
annotations: READS_INTERNAL
|
|
31391
31425
|
}, async (input) => {
|
|
@@ -31442,10 +31476,10 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
|
|
|
31442
31476
|
__name(registerCreativeTools, "registerCreativeTools");
|
|
31443
31477
|
|
|
31444
31478
|
// src/tools/creative-variants.ts
|
|
31445
|
-
import { z as
|
|
31479
|
+
import { z as z127 } from "zod";
|
|
31446
31480
|
var estimateCreativeVariantGuidance = getProductMakerCapabilityModelGuidance("estimate_creative_variant");
|
|
31447
31481
|
var createCreativeVariantGuidance = getProductMakerCapabilityModelGuidance("create_creative_variant");
|
|
31448
|
-
var LandingSectionKeyEnum =
|
|
31482
|
+
var LandingSectionKeyEnum = z127.enum([
|
|
31449
31483
|
"problem_hook",
|
|
31450
31484
|
"problem_cost",
|
|
31451
31485
|
"solution_mechanism",
|
|
@@ -31485,24 +31519,24 @@ var LandingSectionKeyEnum = z126.enum([
|
|
|
31485
31519
|
"lifestyle_fit",
|
|
31486
31520
|
"join_lifestyle"
|
|
31487
31521
|
]);
|
|
31488
|
-
var CreativeVariantKindEnum =
|
|
31522
|
+
var CreativeVariantKindEnum = z127.enum([
|
|
31489
31523
|
"video",
|
|
31490
31524
|
"image",
|
|
31491
31525
|
"landing"
|
|
31492
31526
|
]);
|
|
31493
|
-
var EstimateCreativeVariantInputBase =
|
|
31494
|
-
sourceTaskId:
|
|
31527
|
+
var EstimateCreativeVariantInputBase = z127.object({
|
|
31528
|
+
sourceTaskId: z127.string().uuid().describe("ID de la tarea original completada."),
|
|
31495
31529
|
kind: CreativeVariantKindEnum,
|
|
31496
31530
|
videoPreset: TaskCreativeVariantVideoPresetEnum.optional().describe("Opcional para video. Solo cambia el preset p\xFAblico; el servidor conserva el modelo/tier del task origen."),
|
|
31497
31531
|
videoResolution: VideoResolutionEnum.optional().describe("Opcional para video. Resoluci\xF3n del nuevo render."),
|
|
31498
|
-
nVariants:
|
|
31532
|
+
nVariants: z127.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
|
|
31499
31533
|
sectionKey: LandingSectionKeyEnum.optional().describe("Opcional para landing. Si ya conoces la secci\xF3n, evita cotizar la clasificaci\xF3n con IA."),
|
|
31500
|
-
instructions:
|
|
31534
|
+
instructions: z127.string().trim().min(1).max(2e3).optional().describe("Opcional para landing. Si se env\xEDa sin sectionKey, el estimado suma la clasificaci\xF3n pagada con IA.")
|
|
31501
31535
|
}).strict();
|
|
31502
31536
|
var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine((input, ctx) => {
|
|
31503
31537
|
if (input.kind === "video" && input.nVariants !== void 0) {
|
|
31504
31538
|
ctx.addIssue({
|
|
31505
|
-
code:
|
|
31539
|
+
code: z127.ZodIssueCode.custom,
|
|
31506
31540
|
path: [
|
|
31507
31541
|
"nVariants"
|
|
31508
31542
|
],
|
|
@@ -31512,7 +31546,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
|
|
|
31512
31546
|
if (input.kind !== "video") {
|
|
31513
31547
|
if (input.videoPreset !== void 0) {
|
|
31514
31548
|
ctx.addIssue({
|
|
31515
|
-
code:
|
|
31549
|
+
code: z127.ZodIssueCode.custom,
|
|
31516
31550
|
path: [
|
|
31517
31551
|
"videoPreset"
|
|
31518
31552
|
],
|
|
@@ -31521,7 +31555,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
|
|
|
31521
31555
|
}
|
|
31522
31556
|
if (input.videoResolution !== void 0) {
|
|
31523
31557
|
ctx.addIssue({
|
|
31524
|
-
code:
|
|
31558
|
+
code: z127.ZodIssueCode.custom,
|
|
31525
31559
|
path: [
|
|
31526
31560
|
"videoResolution"
|
|
31527
31561
|
],
|
|
@@ -31531,7 +31565,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
|
|
|
31531
31565
|
}
|
|
31532
31566
|
if (input.kind !== "image" && input.nVariants !== void 0) {
|
|
31533
31567
|
ctx.addIssue({
|
|
31534
|
-
code:
|
|
31568
|
+
code: z127.ZodIssueCode.custom,
|
|
31535
31569
|
path: [
|
|
31536
31570
|
"nVariants"
|
|
31537
31571
|
],
|
|
@@ -31541,7 +31575,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
|
|
|
31541
31575
|
if (input.kind !== "landing") {
|
|
31542
31576
|
if (input.sectionKey !== void 0) {
|
|
31543
31577
|
ctx.addIssue({
|
|
31544
|
-
code:
|
|
31578
|
+
code: z127.ZodIssueCode.custom,
|
|
31545
31579
|
path: [
|
|
31546
31580
|
"sectionKey"
|
|
31547
31581
|
],
|
|
@@ -31550,7 +31584,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
|
|
|
31550
31584
|
}
|
|
31551
31585
|
if (input.instructions !== void 0) {
|
|
31552
31586
|
ctx.addIssue({
|
|
31553
|
-
code:
|
|
31587
|
+
code: z127.ZodIssueCode.custom,
|
|
31554
31588
|
path: [
|
|
31555
31589
|
"instructions"
|
|
31556
31590
|
],
|
|
@@ -31559,31 +31593,31 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
|
|
|
31559
31593
|
}
|
|
31560
31594
|
}
|
|
31561
31595
|
});
|
|
31562
|
-
var CreateCreativeVariantInputBase =
|
|
31563
|
-
sourceTaskId:
|
|
31596
|
+
var CreateCreativeVariantInputBase = z127.object({
|
|
31597
|
+
sourceTaskId: z127.string().uuid().describe("ID de la tarea original completada."),
|
|
31564
31598
|
kind: CreativeVariantKindEnum,
|
|
31565
|
-
confirm:
|
|
31566
|
-
clientRequestId:
|
|
31567
|
-
angle:
|
|
31568
|
-
buyerPersona:
|
|
31569
|
-
scriptNotes:
|
|
31570
|
-
creativeDirection:
|
|
31599
|
+
confirm: z127.literal(true).describe("Confirmaci\xF3n expl\xEDcita del usuario despu\xE9s de mostrarle el estimado de cr\xE9ditos."),
|
|
31600
|
+
clientRequestId: z127.string().uuid().describe("UUID estable para esta intenci\xF3n (obligatorio por compatibilidad de contrato; el servidor deriva la identidad real del request desde los argumentos sem\xE1nticos, as\xED que un UUID nuevo en un retry NO crea una variante duplicada). Si la API devuelve status=error, una nueva generaci\xF3n exige otra confirmaci\xF3n."),
|
|
31601
|
+
angle: z127.string().trim().min(1).max(500).optional().describe("\xC1ngulo nuevo para video o imagen."),
|
|
31602
|
+
buyerPersona: z127.string().trim().min(1).max(360).optional().describe("Buyer persona coherente con el \xE1ngulo."),
|
|
31603
|
+
scriptNotes: z127.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n breve del guion para una variante de video."),
|
|
31604
|
+
creativeDirection: z127.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n creativa para una variante de imagen."),
|
|
31571
31605
|
videoPreset: TaskCreativeVariantVideoPresetEnum.optional().describe("Opcional para video. Preset p\xFAblico; el servidor resuelve modelo/tier desde el task origen."),
|
|
31572
31606
|
videoResolution: VideoResolutionEnum.optional().describe("Opcional para video."),
|
|
31573
|
-
generateAiMusic:
|
|
31574
|
-
nVariants:
|
|
31607
|
+
generateAiMusic: z127.boolean().optional().describe("Opcional para video."),
|
|
31608
|
+
nVariants: z127.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
|
|
31575
31609
|
imageStyle: ImageCreativeStyleEnum.optional().describe("Opcional para imagen."),
|
|
31576
31610
|
creativeArchetype: ImageCreativeArchetypeEnum.optional().describe("Opcional para imagen."),
|
|
31577
31611
|
visualTreatment: ImageCreativeVisualTreatmentEnum.optional().describe("Opcional para imagen."),
|
|
31578
31612
|
aspectRatio: ImageCreativeAspectRatioEnum.optional().describe("Opcional para imagen."),
|
|
31579
|
-
styleMix:
|
|
31613
|
+
styleMix: z127.boolean().optional().describe("Opcional para imagen."),
|
|
31580
31614
|
sectionKey: LandingSectionKeyEnum.optional().describe("Opcional para landing. Si se omite, se clasifica con IA a partir de instructions."),
|
|
31581
|
-
instructions:
|
|
31615
|
+
instructions: z127.string().trim().min(1).max(2e3).optional().describe("Solicitud libre para una nueva secci\xF3n de landing. La IA la clasifica si no env\xEDas sectionKey.")
|
|
31582
31616
|
}).strict();
|
|
31583
31617
|
var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((input, ctx) => {
|
|
31584
31618
|
if ((input.kind === "video" || input.kind === "image") && !input.angle) {
|
|
31585
31619
|
ctx.addIssue({
|
|
31586
|
-
code:
|
|
31620
|
+
code: z127.ZodIssueCode.custom,
|
|
31587
31621
|
path: [
|
|
31588
31622
|
"angle"
|
|
31589
31623
|
],
|
|
@@ -31592,7 +31626,7 @@ var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((inp
|
|
|
31592
31626
|
}
|
|
31593
31627
|
if (input.kind === "landing" && !input.sectionKey && !input.instructions) {
|
|
31594
31628
|
ctx.addIssue({
|
|
31595
|
-
code:
|
|
31629
|
+
code: z127.ZodIssueCode.custom,
|
|
31596
31630
|
path: [
|
|
31597
31631
|
"instructions"
|
|
31598
31632
|
],
|
|
@@ -31638,7 +31672,7 @@ var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((inp
|
|
|
31638
31672
|
for (const field of fieldsByKind[input.kind]) {
|
|
31639
31673
|
if (input[field] !== void 0) {
|
|
31640
31674
|
ctx.addIssue({
|
|
31641
|
-
code:
|
|
31675
|
+
code: z127.ZodIssueCode.custom,
|
|
31642
31676
|
path: [
|
|
31643
31677
|
field
|
|
31644
31678
|
],
|
|
@@ -31694,8 +31728,10 @@ function registerCreativeVariantTools(server, api) {
|
|
|
31694
31728
|
inputSchema: CreateCreativeVariantInputBase.shape,
|
|
31695
31729
|
annotations: CREATES_PAID
|
|
31696
31730
|
}, async (input) => {
|
|
31731
|
+
let sourceTaskId;
|
|
31697
31732
|
try {
|
|
31698
31733
|
const validatedInput = parseVariantInput(CreateCreativeVariantInput, input);
|
|
31734
|
+
sourceTaskId = validatedInput.sourceTaskId;
|
|
31699
31735
|
const estimateInput = EstimateCreativeVariantInput.parse({
|
|
31700
31736
|
sourceTaskId: validatedInput.sourceTaskId,
|
|
31701
31737
|
kind: validatedInput.kind,
|
|
@@ -31706,7 +31742,7 @@ function registerCreativeVariantTools(server, api) {
|
|
|
31706
31742
|
instructions: validatedInput.instructions
|
|
31707
31743
|
});
|
|
31708
31744
|
const estimate = await api.postJson(`/v1/tasks/${encodeURIComponent(validatedInput.sourceTaskId)}/creative-variants/estimate`, estimatePayload(estimateInput));
|
|
31709
|
-
if (!estimate.hasSufficientBalance) {
|
|
31745
|
+
if (validatedInput.kind === "landing" && !validatedInput.sectionKey && !estimate.hasSufficientBalance) {
|
|
31710
31746
|
throw mcp(McpErrorCode.INSUFFICIENT_CREDITS, `Saldo insuficiente. La variante requiere hasta ${estimate.estimatedMaxCostCredits} cr\xE9ditos y tu saldo es ${estimate.userBalanceCredits}.`);
|
|
31711
31747
|
}
|
|
31712
31748
|
let sectionKey = validatedInput.sectionKey;
|
|
@@ -31764,20 +31800,43 @@ function registerCreativeVariantTools(server, api) {
|
|
|
31764
31800
|
estimate
|
|
31765
31801
|
});
|
|
31766
31802
|
} catch (error) {
|
|
31767
|
-
|
|
31803
|
+
const translated = translateError(error);
|
|
31804
|
+
if (!sourceTaskId) throw translated;
|
|
31805
|
+
const details = isRecord3(translated.data) ? translated.data : {};
|
|
31806
|
+
return {
|
|
31807
|
+
...asText({
|
|
31808
|
+
error: {
|
|
31809
|
+
code: typeof details.code === "string" ? details.code : McpErrorCode.INTERNAL,
|
|
31810
|
+
message: translated.message,
|
|
31811
|
+
...typeof details.variantTaskId === "string" ? {
|
|
31812
|
+
variantTaskId: details.variantTaskId
|
|
31813
|
+
} : {}
|
|
31814
|
+
},
|
|
31815
|
+
// A classification or transport failure does not prove that no
|
|
31816
|
+
// child was admitted. Inspect owned children before another buy.
|
|
31817
|
+
nextAction: {
|
|
31818
|
+
tool: "get_task_status",
|
|
31819
|
+
arguments: {
|
|
31820
|
+
taskId: sourceTaskId
|
|
31821
|
+
},
|
|
31822
|
+
instruction: "Revisa las variantes de la tarea original antes de iniciar otro intento pagado. No crees otra variante autom\xE1ticamente."
|
|
31823
|
+
}
|
|
31824
|
+
}),
|
|
31825
|
+
isError: true
|
|
31826
|
+
};
|
|
31768
31827
|
}
|
|
31769
31828
|
});
|
|
31770
31829
|
}
|
|
31771
31830
|
__name(registerCreativeVariantTools, "registerCreativeVariantTools");
|
|
31772
31831
|
|
|
31773
31832
|
// src/tools/script-review.ts
|
|
31774
|
-
import { z as
|
|
31833
|
+
import { z as z128 } from "zod";
|
|
31775
31834
|
var getVideoScriptGuidance = getProductMakerCapabilityModelGuidance("get_video_script");
|
|
31776
31835
|
var regenerateVideoScriptGuidance = getProductMakerCapabilityModelGuidance("regenerate_video_script");
|
|
31777
31836
|
var approveVideoScriptGuidance = getProductMakerCapabilityModelGuidance("approve_video_script");
|
|
31778
|
-
var GetVideoScriptInput =
|
|
31779
|
-
taskId:
|
|
31780
|
-
angleKey:
|
|
31837
|
+
var GetVideoScriptInput = z128.object({
|
|
31838
|
+
taskId: z128.string().min(1).describe("ID de la tarea (la misma que devolvi\xF3 create_product_task / generate_video_creative)."),
|
|
31839
|
+
angleKey: z128.string().min(1).optional().describe('Clave persistida del \xE1ngulo cuyo guion se quiere leer (formato "angle_0", "angle_1", ...). Usa exactamente el angleKey recibido en reviewNextAction.calls al aprobar \xE1ngulos, incluso si s\xF3lo elegiste uno. Si se omite, el backend resuelve a "angle_0" literal; elegir el segundo candidato no crea angle_0. No derives esta clave del n\xFAmero visible del candidato.')
|
|
31781
31840
|
}).strict();
|
|
31782
31841
|
var ApproveVideoScriptInput = ApproveVideoScriptCapabilityRequest;
|
|
31783
31842
|
var RegenerateVideoScriptInput = RegenerateVideoScriptCapabilityRequest.extend({
|
|
@@ -31785,7 +31844,7 @@ var RegenerateVideoScriptInput = RegenerateVideoScriptCapabilityRequest.extend({
|
|
|
31785
31844
|
});
|
|
31786
31845
|
function registerScriptReviewTools(server, api) {
|
|
31787
31846
|
server.registerTool("get_video_script", {
|
|
31788
|
-
description: getVideoScriptGuidance.summary + ' S\xF3lo funciona cuando la tarea fue creada con `pauseForVideoScriptReview: true` (via generate_video_creative). Devuelve { status, angleKey, perClipSeconds?, scenes: [{ index, dialogue, maxWords, minWords?, beatId?, persuasiveFunction?, winnerVisual?, expectedVisual? }], error? }. En escenas copiadas de un winner, `persuasiveFunction` explica qu\xE9 logra ese beat, `winnerVisual` conserva la observaci\xF3n fuente y `expectedVisual` describe nuestra adaptaci\xF3n localizada; muestra los tres junto al di\xE1logo para que una edici\xF3n no desaline\xE9 guion y visual. El campo `error` (cuando viene con status="ready") es el motivo legible por el que un intento previo de aprobaci\xF3n fue rechazado; mu\xE9straselo al usuario.\n\nREGLA DURA: status="ready" es un estado terminal de interacci\xF3n. Presenta el guion una sola vez y NO vuelvas a llamar get_video_script ni get_task_status hasta que el usuario responda aprobar, editar o regenerar. La respuesta a\xF1ade interactionState="awaiting_user_review" y nextAction="present_script_and_wait".\n\nCU\xC1NDO LLAMAR: no existe un status top-level "awaiting_script_review" en get_task_status. Si la tarea fue creada con pauseForVideoScriptReview=true, polea get_task_status hasta que `status === "processing"` y llama este tool; su campo `status` es la se\xF1al real:\n- "ready" \u2192 presenta todas las escenas y DETENTE hasta la respuesta del usuario.\n- "not_ready" \u2192 espera 5\u201310s y reintenta este tool.\n- "approved" \u2192 ya fue aprobado; en multi-angle consulta otro angleKey.\n- "skipped" \u2192 el usuario opt\xF3 por no revisar.\n- "error" \u2192
|
|
31847
|
+
description: getVideoScriptGuidance.summary + ' S\xF3lo funciona cuando la tarea fue creada con `pauseForVideoScriptReview: true` (via generate_video_creative). Devuelve { status, angleKey, perClipSeconds?, scenes: [{ index, dialogue, maxWords, minWords?, beatId?, persuasiveFunction?, winnerVisual?, expectedVisual? }], error? }. En escenas copiadas de un winner, `persuasiveFunction` explica qu\xE9 logra ese beat, `winnerVisual` conserva la observaci\xF3n fuente y `expectedVisual` describe nuestra adaptaci\xF3n localizada; muestra los tres junto al di\xE1logo para que una edici\xF3n no desaline\xE9 guion y visual. El campo `error` (cuando viene con status="ready") es el motivo legible por el que un intento previo de aprobaci\xF3n fue rechazado; mu\xE9straselo al usuario.\n\nREGLA DURA: status="ready" es un estado terminal de interacci\xF3n. Presenta el guion una sola vez y NO vuelvas a llamar get_video_script ni get_task_status hasta que el usuario responda aprobar, editar o regenerar. La respuesta a\xF1ade interactionState="awaiting_user_review" y nextAction="present_script_and_wait".\n\nCU\xC1NDO LLAMAR: no existe un status top-level "awaiting_script_review" en get_task_status. Si la tarea fue creada con pauseForVideoScriptReview=true, polea get_task_status hasta que `status === "processing"` y llama este tool; su campo `status` es la se\xF1al real:\n- "ready" \u2192 presenta todas las escenas y DETENTE hasta la respuesta del usuario.\n- "not_ready" \u2192 espera 5\u201310s y reintenta este tool.\n- "approved" \u2192 ya fue aprobado; en multi-angle consulta otro angleKey.\n- "skipped" \u2192 el usuario opt\xF3 por no revisar.\n- "error" \u2192 consulta `get_task_status` antes de ofrecer recuperaci\xF3n. No regeneres autom\xE1ticamente una tarea terminal.\n\nANGLE KEY: usa las claves expl\xEDcitas de reviewNextAction.calls, incluso si s\xF3lo seleccionaste un candidato. Cuando uno est\xE9 ready, detente en ese \xE1ngulo y espera la decisi\xF3n antes de consultar otro.',
|
|
31789
31848
|
inputSchema: GetVideoScriptInput.shape,
|
|
31790
31849
|
annotations: READS_INTERNAL
|
|
31791
31850
|
}, async (input) => {
|
|
@@ -31793,6 +31852,28 @@ function registerScriptReviewTools(server, api) {
|
|
|
31793
31852
|
const qs = input.angleKey ? `?angleKey=${encodeURIComponent(input.angleKey)}` : "";
|
|
31794
31853
|
const r = await api.getJson(`/v1/tasks/${encodeURIComponent(input.taskId)}/video-script${qs}`);
|
|
31795
31854
|
const review = renderVideoScriptMarkdown(r);
|
|
31855
|
+
if (review && typeof r === "object" && r !== null && "status" in r && r.status === "error") {
|
|
31856
|
+
const error = "error" in r && typeof r.error === "string" ? escapeMarkdownText(r.error) : "No se pudo preparar este guion.";
|
|
31857
|
+
return {
|
|
31858
|
+
content: [
|
|
31859
|
+
{
|
|
31860
|
+
type: "text",
|
|
31861
|
+
text: `## No se pudo preparar el guion
|
|
31862
|
+
|
|
31863
|
+
${error}
|
|
31864
|
+
|
|
31865
|
+
Consulta get_task_status con esta tarea antes de reintentar. Si la tarea termin\xF3 en error, sigue su recuperaci\xF3n; si sigue activa y s\xF3lo fall\xF3 el guion, ofrece regenerarlo con confirmaci\xF3n del usuario. No inicies una regeneraci\xF3n pagada autom\xE1ticamente.`
|
|
31866
|
+
}
|
|
31867
|
+
],
|
|
31868
|
+
structuredContent: {
|
|
31869
|
+
...r,
|
|
31870
|
+
nextAction: "get_task_status",
|
|
31871
|
+
nextActionArguments: {
|
|
31872
|
+
taskId: input.taskId
|
|
31873
|
+
}
|
|
31874
|
+
}
|
|
31875
|
+
};
|
|
31876
|
+
}
|
|
31796
31877
|
return review ? {
|
|
31797
31878
|
content: [
|
|
31798
31879
|
{
|
|
@@ -31821,7 +31902,7 @@ function registerScriptReviewTools(server, api) {
|
|
|
31821
31902
|
}
|
|
31822
31903
|
});
|
|
31823
31904
|
server.registerTool("regenerate_video_script", {
|
|
31824
|
-
description: regenerateVideoScriptGuidance.summary + ' \xDAsalo cuando:\n- get_video_script devuelve status="error"
|
|
31905
|
+
description: regenerateVideoScriptGuidance.summary + ' \xDAsalo cuando:\n- get_video_script devuelve status="error", get_task_status confirma que la tarea sigue activa y el usuario confirma reintentar el guion.\n- El usuario rechaza el guion entero y prefiere reintentar (no editar l\xEDnea por l\xEDnea).\n- Quieres probar otra narrativa (pasa `narrativeStyle`).\n\nFlujo: llama este tool \u2192 polea get_video_script hasta que vuelva a status="ready" \u2192 mu\xE9strale el nuevo guion al usuario \u2192 approve_video_script.\n\nIMPORTANTE: regenerar CUESTA cr\xE9ditos de LLM. No lo invoques sin confirmaci\xF3n del usuario, incluso si el guion est\xE1 en error. Para una tarea terminal, sigue primero la recuperaci\xF3n de get_task_status.\n\nMULTI-ANGLE: pasa el mismo `angleKey` que usaste con get_video_script.',
|
|
31825
31906
|
inputSchema: RegenerateVideoScriptInput.shape,
|
|
31826
31907
|
annotations: OVERWRITES_EXTERNAL
|
|
31827
31908
|
}, async (input) => {
|
|
@@ -31860,7 +31941,7 @@ function registerScriptReviewTools(server, api) {
|
|
|
31860
31941
|
__name(registerScriptReviewTools, "registerScriptReviewTools");
|
|
31861
31942
|
|
|
31862
31943
|
// src/tools/connections.ts
|
|
31863
|
-
import { z as
|
|
31944
|
+
import { z as z129 } from "zod";
|
|
31864
31945
|
var listShopifyShopsGuidance = getProductMakerCapabilityModelGuidance("list_shopify_shops");
|
|
31865
31946
|
var listShopifyProductsGuidance = getProductMakerCapabilityModelGuidance("list_shopify_products");
|
|
31866
31947
|
var listMetaAdAccountsGuidance = getProductMakerCapabilityModelGuidance("list_meta_ad_accounts");
|
|
@@ -31869,7 +31950,7 @@ var listTikTokAdvertisersGuidance = getProductMakerCapabilityModelGuidance("list
|
|
|
31869
31950
|
function registerConnectionTools(server, api) {
|
|
31870
31951
|
server.registerTool("list_shopify_shops", {
|
|
31871
31952
|
description: listShopifyShopsGuidance.summary + " Si la lista est\xE1 vac\xEDa, dile al usuario que conecte una tienda en productmaker.app/integrations antes de intentar publicar.",
|
|
31872
|
-
inputSchema:
|
|
31953
|
+
inputSchema: z129.object({}).shape,
|
|
31873
31954
|
annotations: READS_INTERNAL
|
|
31874
31955
|
}, async () => {
|
|
31875
31956
|
try {
|
|
@@ -31881,10 +31962,10 @@ function registerConnectionTools(server, api) {
|
|
|
31881
31962
|
});
|
|
31882
31963
|
server.registerTool("list_shopify_products", {
|
|
31883
31964
|
description: listShopifyProductsGuidance.summary + ' Usa el `id` devuelto junto con `publicationMode="existing"` en `publish_to_shopify`. Si `taskId` se proporciona, la respuesta tambi\xE9n indica el producto publicado actualmente para esa tarea y tienda. No modifica Shopify.',
|
|
31884
|
-
inputSchema:
|
|
31885
|
-
shopDomain:
|
|
31886
|
-
query:
|
|
31887
|
-
taskId:
|
|
31965
|
+
inputSchema: z129.object({
|
|
31966
|
+
shopDomain: z129.string().min(3).max(120),
|
|
31967
|
+
query: z129.string().trim().max(120).optional(),
|
|
31968
|
+
taskId: z129.string().uuid().optional()
|
|
31888
31969
|
}).shape,
|
|
31889
31970
|
annotations: READS_EXTERNAL
|
|
31890
31971
|
}, async ({ shopDomain, query, taskId }) => {
|
|
@@ -31902,7 +31983,7 @@ function registerConnectionTools(server, api) {
|
|
|
31902
31983
|
});
|
|
31903
31984
|
server.registerTool("list_meta_ad_accounts", {
|
|
31904
31985
|
description: listMetaAdAccountsGuidance.summary + " Para publicar, prefiere `list_meta_destinations`, que tambi\xE9n devuelve el portfolio y las p\xE1ginas disponibles. Si est\xE1 vac\xEDa, ind\xEDcale al usuario conectar Meta en productmaker.app/integrations.",
|
|
31905
|
-
inputSchema:
|
|
31986
|
+
inputSchema: z129.object({}).shape,
|
|
31906
31987
|
annotations: READS_EXTERNAL
|
|
31907
31988
|
}, async () => {
|
|
31908
31989
|
try {
|
|
@@ -31914,7 +31995,7 @@ function registerConnectionTools(server, api) {
|
|
|
31914
31995
|
});
|
|
31915
31996
|
server.registerTool("list_meta_destinations", {
|
|
31916
31997
|
description: listMetaDestinationsGuidance.summary + " Es obligatorio llamar esta herramienta antes de publicar, mostrar las opciones y enviar al publicador el `portfolioId`, `adAccountId` y `pageId` elegidos; nunca elijas silenciosamente la primera p\xE1gina o cuenta. No modifica Meta.",
|
|
31917
|
-
inputSchema:
|
|
31998
|
+
inputSchema: z129.object({}).shape,
|
|
31918
31999
|
annotations: READS_EXTERNAL,
|
|
31919
32000
|
_meta: {
|
|
31920
32001
|
"openai/widgetAccessible": true
|
|
@@ -31929,7 +32010,7 @@ function registerConnectionTools(server, api) {
|
|
|
31929
32010
|
});
|
|
31930
32011
|
server.registerTool("list_tiktok_advertisers", {
|
|
31931
32012
|
description: listTikTokAdvertisersGuidance.summary + " Si est\xE1 vac\xEDa, ind\xEDcale al usuario conectar TikTok en productmaker.app/integrations.",
|
|
31932
|
-
inputSchema:
|
|
32013
|
+
inputSchema: z129.object({}).shape,
|
|
31933
32014
|
annotations: READS_EXTERNAL
|
|
31934
32015
|
}, async () => {
|
|
31935
32016
|
try {
|
|
@@ -31943,7 +32024,7 @@ function registerConnectionTools(server, api) {
|
|
|
31943
32024
|
__name(registerConnectionTools, "registerConnectionTools");
|
|
31944
32025
|
|
|
31945
32026
|
// src/tools/actors.ts
|
|
31946
|
-
import { z as
|
|
32027
|
+
import { z as z130 } from "zod";
|
|
31947
32028
|
var listActorsGuidance = getProductMakerCapabilityModelGuidance("list_actors");
|
|
31948
32029
|
var actorVoiceGuidance = {
|
|
31949
32030
|
capabilities: getProductMakerCapabilityModelGuidance("get_actor_voice_capabilities"),
|
|
@@ -31983,7 +32064,7 @@ function sanitizeVoiceResult(value) {
|
|
|
31983
32064
|
__name(sanitizeVoiceResult, "sanitizeVoiceResult");
|
|
31984
32065
|
function registerActorTools(server, api) {
|
|
31985
32066
|
const actor = {
|
|
31986
|
-
actorId:
|
|
32067
|
+
actorId: z130.string().min(1).max(64)
|
|
31987
32068
|
};
|
|
31988
32069
|
const safe = /* @__PURE__ */ __name(async (request) => {
|
|
31989
32070
|
try {
|
|
@@ -32012,8 +32093,8 @@ function registerActorTools(server, api) {
|
|
|
32012
32093
|
inputSchema: {
|
|
32013
32094
|
...actor,
|
|
32014
32095
|
draft: ActorVoiceDraftSchema,
|
|
32015
|
-
requestKey:
|
|
32016
|
-
acceptedQuoteId:
|
|
32096
|
+
requestKey: z130.string().trim().min(1).max(128),
|
|
32097
|
+
acceptedQuoteId: z130.string().trim().min(1).max(128)
|
|
32017
32098
|
},
|
|
32018
32099
|
annotations: CREATES_PAID
|
|
32019
32100
|
}, async ({ actorId, ...body }) => safe(api.postJson(`/v1/actors/${encodeURIComponent(actorId)}/voice/previews`, body)));
|
|
@@ -32021,7 +32102,7 @@ function registerActorTools(server, api) {
|
|
|
32021
32102
|
description: actorVoiceGuidance.get.summary,
|
|
32022
32103
|
inputSchema: {
|
|
32023
32104
|
...actor,
|
|
32024
|
-
candidateId:
|
|
32105
|
+
candidateId: z130.string().min(1).max(64)
|
|
32025
32106
|
},
|
|
32026
32107
|
// Polling can resume the first paid submission of an accepted quote.
|
|
32027
32108
|
// The immutable candidate/operation key keeps recovery idempotent.
|
|
@@ -32034,16 +32115,16 @@ function registerActorTools(server, api) {
|
|
|
32034
32115
|
description: actorVoiceGuidance.approve.summary,
|
|
32035
32116
|
inputSchema: {
|
|
32036
32117
|
...actor,
|
|
32037
|
-
candidateId:
|
|
32038
|
-
expectedRevision:
|
|
32039
|
-
expectedApprovedRevision:
|
|
32118
|
+
candidateId: z130.string().min(1).max(64),
|
|
32119
|
+
expectedRevision: z130.number().int().positive(),
|
|
32120
|
+
expectedApprovedRevision: z130.number().int().positive().nullable().optional()
|
|
32040
32121
|
},
|
|
32041
32122
|
// Replaces the selected voice and withdraws the old catalog grants.
|
|
32042
32123
|
annotations: OVERWRITES_INTERNAL
|
|
32043
32124
|
}, async ({ actorId, ...body }) => safe(api.postJson(`/v1/actors/${encodeURIComponent(actorId)}/voice/approve`, body)));
|
|
32044
32125
|
server.registerTool("list_actors", {
|
|
32045
32126
|
description: listActorsGuidance.summary + " Devuelve id, nombre, descripci\xF3n, g\xE9nero y voz privada del personaje. Cuando el personaje tiene una voz personalizada, `voice.identityId` y `voice.revision` identifican la versi\xF3n aprobada \u2014 conserva la revisi\xF3n al llamar `approve_actor_voice` (expectedApprovedRevision) para reemplazarla. Los IDs de proveedor nunca se exponen por MCP. Usa el `id` como `actorId` al crear o editar una tarea. Solo aparecen los personajes listos para usar; si la lista est\xE1 vac\xEDa, dile al usuario que cree uno en productmaker.app antes de intentar asignarlo. No modifica nada.",
|
|
32046
|
-
inputSchema:
|
|
32127
|
+
inputSchema: z130.object({}).shape,
|
|
32047
32128
|
annotations: READS_INTERNAL
|
|
32048
32129
|
}, async () => {
|
|
32049
32130
|
try {
|
|
@@ -32076,7 +32157,7 @@ function registerActorTools(server, api) {
|
|
|
32076
32157
|
__name(registerActorTools, "registerActorTools");
|
|
32077
32158
|
|
|
32078
32159
|
// src/tools/publish.ts
|
|
32079
|
-
import { z as
|
|
32160
|
+
import { z as z131 } from "zod";
|
|
32080
32161
|
|
|
32081
32162
|
// src/tools/meta-publish-attempt-id.ts
|
|
32082
32163
|
var META_PUBLISH_NAMESPACE = "7b19c9ac-b4eb-4db1-970e-c2f24ce30b98";
|
|
@@ -32115,40 +32196,40 @@ var publishToShopifyGuidance = getProductMakerCapabilityModelGuidance("publish_t
|
|
|
32115
32196
|
var publishToMetaGuidance = getProductMakerCapabilityModelGuidance("publish_to_meta");
|
|
32116
32197
|
var publishCreativesToMetaGuidance = getProductMakerCapabilityModelGuidance("publish_creatives_to_meta");
|
|
32117
32198
|
var publishToTikTokGuidance = getProductMakerCapabilityModelGuidance("publish_to_tiktok");
|
|
32118
|
-
var ShopifyInput =
|
|
32119
|
-
taskId:
|
|
32120
|
-
shopDomain:
|
|
32199
|
+
var ShopifyInput = z131.object({
|
|
32200
|
+
taskId: z131.string().min(1),
|
|
32201
|
+
shopDomain: z131.string().min(1),
|
|
32121
32202
|
/** Override: number of landing images to include. Default = ALL images the
|
|
32122
32203
|
* task generated (the MCP fetches /v1/results first to count). Bounded
|
|
32123
32204
|
* generously here; the backend validates each index against
|
|
32124
32205
|
* landing.images.length and rejects out-of-range. */
|
|
32125
|
-
numLandingImages:
|
|
32126
|
-
variantIndex:
|
|
32206
|
+
numLandingImages: z131.number().int().min(1).max(20).optional(),
|
|
32207
|
+
variantIndex: z131.number().int().min(0).optional(),
|
|
32127
32208
|
/** ASK THE USER before setting: "¿Tu producto tiene variantes (talla, color, etc.)?".
|
|
32128
32209
|
* When true, the landing renders variant-picker pills; when false, it ships
|
|
32129
32210
|
* a single-option product page. Defaults to false. */
|
|
32130
|
-
showVariantPicker:
|
|
32211
|
+
showVariantPicker: z131.boolean().optional(),
|
|
32131
32212
|
/** Default `auto` updates the product previously published for this task and
|
|
32132
32213
|
* shop. Use `existing` with targetProductId to choose another product, or
|
|
32133
32214
|
* `new` only when the user explicitly wants a duplicate/new listing. */
|
|
32134
|
-
publicationMode:
|
|
32215
|
+
publicationMode: z131.enum([
|
|
32135
32216
|
"auto",
|
|
32136
32217
|
"existing",
|
|
32137
32218
|
"new"
|
|
32138
32219
|
]).optional(),
|
|
32139
32220
|
/** Shopify product GID, numeric id, or admin product URL. Required when
|
|
32140
32221
|
* publicationMode is `existing`. */
|
|
32141
|
-
targetProductId:
|
|
32222
|
+
targetProductId: z131.string().trim().min(1).max(300).optional(),
|
|
32142
32223
|
/** Add an announcement bar text above add-to-cart (optional). */
|
|
32143
|
-
announcementBarEnabled:
|
|
32144
|
-
announcementBarText:
|
|
32224
|
+
announcementBarEnabled: z131.boolean().optional(),
|
|
32225
|
+
announcementBarText: z131.string().trim().min(1).max(SHOPIFY_ANNOUNCEMENT_BAR_MAX_LENGTH).optional(),
|
|
32145
32226
|
commerceCorrection: PublishCommerceCorrectionSchema.optional().describe("Complete seller-confirmed commerce values, with the revision and fingerprint returned in recovery. Never invent missing prices or convert currency."),
|
|
32146
|
-
confirmed:
|
|
32227
|
+
confirmed: z131.boolean().optional().describe("Required as true only when submitting commerceCorrection, after showing its values and obtaining explicit seller confirmation.")
|
|
32147
32228
|
});
|
|
32148
32229
|
var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value, ctx) => {
|
|
32149
32230
|
if (value.commerceCorrection && value.confirmed !== true) {
|
|
32150
32231
|
ctx.addIssue({
|
|
32151
|
-
code:
|
|
32232
|
+
code: z131.ZodIssueCode.custom,
|
|
32152
32233
|
path: [
|
|
32153
32234
|
"confirmed"
|
|
32154
32235
|
],
|
|
@@ -32157,7 +32238,7 @@ var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value,
|
|
|
32157
32238
|
}
|
|
32158
32239
|
if (value.announcementBarEnabled && !value.announcementBarText) {
|
|
32159
32240
|
ctx.addIssue({
|
|
32160
|
-
code:
|
|
32241
|
+
code: z131.ZodIssueCode.custom,
|
|
32161
32242
|
path: [
|
|
32162
32243
|
"announcementBarText"
|
|
32163
32244
|
],
|
|
@@ -32166,7 +32247,7 @@ var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value,
|
|
|
32166
32247
|
}
|
|
32167
32248
|
if (!value.announcementBarEnabled && value.announcementBarText) {
|
|
32168
32249
|
ctx.addIssue({
|
|
32169
|
-
code:
|
|
32250
|
+
code: z131.ZodIssueCode.custom,
|
|
32170
32251
|
path: [
|
|
32171
32252
|
"announcementBarText"
|
|
32172
32253
|
],
|
|
@@ -32180,90 +32261,90 @@ function parseShopifyInput(rawInput) {
|
|
|
32180
32261
|
return parsed.data;
|
|
32181
32262
|
}
|
|
32182
32263
|
__name(parseShopifyInput, "parseShopifyInput");
|
|
32183
|
-
var McpCampaignConfig =
|
|
32264
|
+
var McpCampaignConfig = z131.object({
|
|
32184
32265
|
/** Legacy USD amount. Meta retains its existing conversion; the TikTok
|
|
32185
32266
|
* schema below restricts this input to USD advertiser accounts. */
|
|
32186
|
-
dailyBudgetUsd:
|
|
32267
|
+
dailyBudgetUsd: z131.number().positive().optional(),
|
|
32187
32268
|
/** ISO-3166-1 alpha-2 country codes or resolvable names (CountryIso2Schema
|
|
32188
32269
|
* normalizes at validation). Meta accepts max 1 (single-country ad set).
|
|
32189
32270
|
* TikTok takes only the first entry. */
|
|
32190
|
-
targetCountries:
|
|
32191
|
-
campaignName:
|
|
32271
|
+
targetCountries: z131.array(CountryIso2Schema).max(1).optional(),
|
|
32272
|
+
campaignName: z131.string().trim().min(1).max(100).optional()
|
|
32192
32273
|
});
|
|
32193
32274
|
var McpAdAccountId = MetaAdAccountId.describe('Meta ad account id. Accepts "act_1234567890" or the bare numeric id "1234567890".');
|
|
32194
|
-
var MetaInput =
|
|
32195
|
-
taskId:
|
|
32275
|
+
var MetaInput = z131.object({
|
|
32276
|
+
taskId: z131.string().min(1),
|
|
32196
32277
|
/** Exact Meta Business portfolio selected from `list_meta_destinations`. */
|
|
32197
|
-
portfolioId:
|
|
32278
|
+
portfolioId: z131.string().trim().min(1),
|
|
32198
32279
|
/** Exact Facebook Page selected from `list_meta_destinations`. */
|
|
32199
|
-
pageId:
|
|
32280
|
+
pageId: z131.string().trim().min(1),
|
|
32200
32281
|
adAccountId: McpAdAccountId,
|
|
32201
|
-
pixelId:
|
|
32202
|
-
landingUrl:
|
|
32282
|
+
pixelId: z131.string().min(1).optional(),
|
|
32283
|
+
landingUrl: z131.string().url().optional(),
|
|
32203
32284
|
/** Select which angles to publish by 0-based index. Omit to publish all
|
|
32204
32285
|
* successful angles. Example: a task with 3 angles → `[0,2]` publishes #0 + #2. */
|
|
32205
|
-
angleIndexes:
|
|
32286
|
+
angleIndexes: z131.array(z131.number().int().nonnegative()).optional(),
|
|
32206
32287
|
campaignConfig: McpCampaignConfig.optional(),
|
|
32207
32288
|
/** Override the ad's primary text (body copy). If omitted, ProductMaker
|
|
32208
32289
|
* uses the auto-generated copy attached to the task. Capped at 500 chars
|
|
32209
32290
|
* (Meta's primary-text limit). */
|
|
32210
|
-
primaryText:
|
|
32291
|
+
primaryText: z131.string().trim().min(1).max(500).optional(),
|
|
32211
32292
|
/** Optional WhatsApp number. When set, the ad button opens a WhatsApp chat
|
|
32212
32293
|
* (wa.me) instead of a landing page. */
|
|
32213
|
-
phoneNumber:
|
|
32294
|
+
phoneNumber: z131.string().min(8).max(32).optional()
|
|
32214
32295
|
});
|
|
32215
|
-
var GroupedTaskSource =
|
|
32216
|
-
type:
|
|
32217
|
-
taskId:
|
|
32218
|
-
angleIndex:
|
|
32219
|
-
videoVariant:
|
|
32296
|
+
var GroupedTaskSource = z131.object({
|
|
32297
|
+
type: z131.literal("task"),
|
|
32298
|
+
taskId: z131.string().min(1),
|
|
32299
|
+
angleIndex: z131.number().int().min(0).optional(),
|
|
32300
|
+
videoVariant: z131.enum([
|
|
32220
32301
|
"with_subtitles",
|
|
32221
32302
|
"without_subtitles"
|
|
32222
32303
|
]).optional(),
|
|
32223
|
-
imageVariantIndex:
|
|
32224
|
-
});
|
|
32225
|
-
var GroupedMediaSource =
|
|
32226
|
-
type:
|
|
32227
|
-
url:
|
|
32228
|
-
path:
|
|
32229
|
-
thumbnailUrl:
|
|
32230
|
-
thumbnailPath:
|
|
32304
|
+
imageVariantIndex: z131.number().int().min(0).optional()
|
|
32305
|
+
});
|
|
32306
|
+
var GroupedMediaSource = z131.object({
|
|
32307
|
+
type: z131.literal("media"),
|
|
32308
|
+
url: z131.string().url().optional().describe("Public HTTPS media URL. For a file on the user laptop, use request_media_upload on the hosted MCP instead."),
|
|
32309
|
+
path: z131.string().min(1).optional().describe('Local file path only when this MCP runs over stdio. On the hosted MCP, call request_media_upload and then use source.type="asset".'),
|
|
32310
|
+
thumbnailUrl: z131.string().url().optional(),
|
|
32311
|
+
thumbnailPath: z131.string().min(1).optional()
|
|
32231
32312
|
}).refine((value) => Boolean(value.url) !== Boolean(value.path), {
|
|
32232
32313
|
message: "media source needs exactly one of `url` or `path`"
|
|
32233
32314
|
}).refine((value) => !(value.thumbnailUrl && value.thumbnailPath), {
|
|
32234
32315
|
message: "media source needs at most one of `thumbnailUrl` or `thumbnailPath`"
|
|
32235
32316
|
});
|
|
32236
|
-
var GroupedUploadedAssetSource =
|
|
32237
|
-
type:
|
|
32317
|
+
var GroupedUploadedAssetSource = z131.object({
|
|
32318
|
+
type: z131.literal("asset"),
|
|
32238
32319
|
/** Returned by check_media_upload. ProductMaker resolves ownership server-side. */
|
|
32239
|
-
assetId:
|
|
32240
|
-
thumbnailAssetId:
|
|
32320
|
+
assetId: z131.string().uuid(),
|
|
32321
|
+
thumbnailAssetId: z131.string().uuid().optional()
|
|
32241
32322
|
});
|
|
32242
|
-
var GroupedCreative =
|
|
32243
|
-
type:
|
|
32323
|
+
var GroupedCreative = z131.object({
|
|
32324
|
+
type: z131.enum([
|
|
32244
32325
|
"image",
|
|
32245
32326
|
"video"
|
|
32246
32327
|
]),
|
|
32247
|
-
source:
|
|
32328
|
+
source: z131.union([
|
|
32248
32329
|
GroupedTaskSource,
|
|
32249
32330
|
GroupedMediaSource,
|
|
32250
32331
|
GroupedUploadedAssetSource
|
|
32251
32332
|
]),
|
|
32252
|
-
title:
|
|
32253
|
-
description:
|
|
32333
|
+
title: z131.string().max(120).optional(),
|
|
32334
|
+
description: z131.string().max(500).optional(),
|
|
32254
32335
|
cta: MetaCtaType.optional(),
|
|
32255
|
-
creativeId:
|
|
32336
|
+
creativeId: z131.string().min(1).optional()
|
|
32256
32337
|
});
|
|
32257
|
-
var GroupedCampaignConfigBase =
|
|
32338
|
+
var GroupedCampaignConfigBase = z131.object({
|
|
32258
32339
|
campaignType: MetaCampaignType.default("sales"),
|
|
32259
32340
|
optimizationMode: MetaOptimizationMode.default("advantage_plus"),
|
|
32260
32341
|
budgetMode: MetaBudgetMode.optional(),
|
|
32261
|
-
campaignDailyBudget:
|
|
32262
|
-
adSets:
|
|
32263
|
-
tempId:
|
|
32264
|
-
name:
|
|
32265
|
-
dailyBudget:
|
|
32266
|
-
creativeIds:
|
|
32342
|
+
campaignDailyBudget: z131.number().int().positive().optional(),
|
|
32343
|
+
adSets: z131.array(z131.object({
|
|
32344
|
+
tempId: z131.string().min(1).max(80),
|
|
32345
|
+
name: z131.string().min(1).max(100),
|
|
32346
|
+
dailyBudget: z131.number().int().positive().optional(),
|
|
32347
|
+
creativeIds: z131.array(z131.string().min(1)).min(1)
|
|
32267
32348
|
})).min(1).max(CAMPAIGN_LIMITS.MAX_AD_SETS),
|
|
32268
32349
|
/**
|
|
32269
32350
|
* Valid values are 'landing' and 'whatsapp' — there is no 'website'. This
|
|
@@ -32271,17 +32352,17 @@ var GroupedCampaignConfigBase = z130.object({
|
|
|
32271
32352
|
* opaque `invalid_literal` and made the WhatsApp destination — supported by
|
|
32272
32353
|
* the API since #849 — unreachable from this tool.
|
|
32273
32354
|
*/
|
|
32274
|
-
destination:
|
|
32275
|
-
|
|
32276
|
-
type:
|
|
32277
|
-
landingUrl:
|
|
32355
|
+
destination: z131.discriminatedUnion("type", [
|
|
32356
|
+
z131.object({
|
|
32357
|
+
type: z131.literal("landing"),
|
|
32358
|
+
landingUrl: z131.string().url()
|
|
32278
32359
|
}),
|
|
32279
|
-
|
|
32280
|
-
type:
|
|
32281
|
-
phoneNumber:
|
|
32360
|
+
z131.object({
|
|
32361
|
+
type: z131.literal("whatsapp"),
|
|
32362
|
+
phoneNumber: z131.string().min(8).max(32)
|
|
32282
32363
|
})
|
|
32283
32364
|
]),
|
|
32284
|
-
saveAsDefault:
|
|
32365
|
+
saveAsDefault: z131.boolean().default(false),
|
|
32285
32366
|
budgetPolicy: MetaBudgetPolicy.optional()
|
|
32286
32367
|
});
|
|
32287
32368
|
function resolveBudgetMode(value) {
|
|
@@ -32295,7 +32376,7 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
|
|
|
32295
32376
|
const budgetMode = resolveBudgetMode(value);
|
|
32296
32377
|
if (budgetMode === "campaign" && value.campaignDailyBudget === void 0) {
|
|
32297
32378
|
ctx.addIssue({
|
|
32298
|
-
code:
|
|
32379
|
+
code: z131.ZodIssueCode.custom,
|
|
32299
32380
|
path: [
|
|
32300
32381
|
"campaignDailyBudget"
|
|
32301
32382
|
],
|
|
@@ -32306,7 +32387,7 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
|
|
|
32306
32387
|
value.adSets.forEach((adSet, index) => {
|
|
32307
32388
|
if (adSet.dailyBudget === void 0) {
|
|
32308
32389
|
ctx.addIssue({
|
|
32309
|
-
code:
|
|
32390
|
+
code: z131.ZodIssueCode.custom,
|
|
32310
32391
|
path: [
|
|
32311
32392
|
"adSets",
|
|
32312
32393
|
index,
|
|
@@ -32321,25 +32402,25 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
|
|
|
32321
32402
|
...value,
|
|
32322
32403
|
budgetMode: resolveBudgetMode(value)
|
|
32323
32404
|
}));
|
|
32324
|
-
var PublishCreativesToMetaInputBase =
|
|
32325
|
-
creatives:
|
|
32405
|
+
var PublishCreativesToMetaInputBase = z131.object({
|
|
32406
|
+
creatives: z131.array(GroupedCreative).min(1).max(CAMPAIGN_LIMITS.MAX_CREATIVES),
|
|
32326
32407
|
/** Exact Meta Business portfolio selected from `list_meta_destinations`. */
|
|
32327
|
-
portfolioId:
|
|
32408
|
+
portfolioId: z131.string().trim().min(1),
|
|
32328
32409
|
/** Exact Facebook Page selected from `list_meta_destinations`. */
|
|
32329
|
-
pageId:
|
|
32410
|
+
pageId: z131.string().trim().min(1),
|
|
32330
32411
|
adAccountId: McpAdAccountId,
|
|
32331
|
-
pixelId:
|
|
32412
|
+
pixelId: z131.string().min(1).optional(),
|
|
32332
32413
|
/** Required unless `campaignConfig.destination` is whatsapp or a creative
|
|
32333
32414
|
* comes from a task (the API then lands on the published service landing
|
|
32334
32415
|
* of its service tasks) — see the superRefine below. Mirrors the API's
|
|
32335
32416
|
* `FacebookCreateCampaignFromTasksBodySchema`. */
|
|
32336
|
-
landingUrl:
|
|
32417
|
+
landingUrl: z131.string().url().optional(),
|
|
32337
32418
|
/** ISO-2 code or resolvable country name — mirrors the API contract
|
|
32338
32419
|
* (CountryIso2Schema), which normalizes names to alpha-2 at validation.
|
|
32339
32420
|
* Omitted: the brand country of its service tasks (the API answers
|
|
32340
32421
|
* META_NO_TARGET_COUNTRY when it has none); "US" for products. */
|
|
32341
32422
|
targetCountry: CountryIso2Schema.optional(),
|
|
32342
|
-
campaignName:
|
|
32423
|
+
campaignName: z131.string().trim().min(1).max(100),
|
|
32343
32424
|
campaignConfig: GroupedCampaignConfig.optional()
|
|
32344
32425
|
});
|
|
32345
32426
|
var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((value, ctx) => {
|
|
@@ -32347,7 +32428,7 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
|
|
|
32347
32428
|
const hasTaskCreative = value.creatives.some((creative) => creative.source.type === "task");
|
|
32348
32429
|
if (destination?.type !== "whatsapp" && destination?.type !== "landing" && !value.landingUrl && !hasTaskCreative) {
|
|
32349
32430
|
ctx.addIssue({
|
|
32350
|
-
code:
|
|
32431
|
+
code: z131.ZodIssueCode.custom,
|
|
32351
32432
|
path: [
|
|
32352
32433
|
"landingUrl"
|
|
32353
32434
|
],
|
|
@@ -32356,7 +32437,7 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
|
|
|
32356
32437
|
}
|
|
32357
32438
|
if (destination?.type === "landing" && value.landingUrl && destination.landingUrl !== value.landingUrl) {
|
|
32358
32439
|
ctx.addIssue({
|
|
32359
|
-
code:
|
|
32440
|
+
code: z131.ZodIssueCode.custom,
|
|
32360
32441
|
path: [
|
|
32361
32442
|
"campaignConfig",
|
|
32362
32443
|
"destination",
|
|
@@ -32375,16 +32456,16 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
|
|
|
32375
32456
|
}
|
|
32376
32457
|
return value;
|
|
32377
32458
|
});
|
|
32378
|
-
var PresignUploadResponseSchema =
|
|
32379
|
-
uploadUrl:
|
|
32459
|
+
var PresignUploadResponseSchema = z131.object({
|
|
32460
|
+
uploadUrl: z131.string().url().refine((value) => {
|
|
32380
32461
|
const url = new URL(value);
|
|
32381
32462
|
return !url.username && !url.password && url.protocol === "https:";
|
|
32382
32463
|
}, "presigned upload URL must be HTTPS without embedded credentials"),
|
|
32383
|
-
publicUrl:
|
|
32464
|
+
publicUrl: z131.string().url().refine((value) => {
|
|
32384
32465
|
const url = new URL(value);
|
|
32385
32466
|
return !url.username && !url.password;
|
|
32386
32467
|
}, "public media URL must not contain embedded credentials"),
|
|
32387
|
-
stagingAssetId:
|
|
32468
|
+
stagingAssetId: z131.string().uuid()
|
|
32388
32469
|
});
|
|
32389
32470
|
async function uploadResolvedMedia(api, media, assetRole) {
|
|
32390
32471
|
if (!media.buffer) throw new ResolveMediaError("INVALID_INPUT", "resolved media has no bytes");
|
|
@@ -32410,14 +32491,14 @@ async function resolveAndUploadMedia(api, ref, expectedKind, assetRole, transpor
|
|
|
32410
32491
|
}
|
|
32411
32492
|
__name(resolveAndUploadMedia, "resolveAndUploadMedia");
|
|
32412
32493
|
var TikTokMcpCampaignConfig = McpCampaignConfig.extend({
|
|
32413
|
-
dailyBudgetUsd:
|
|
32414
|
-
dailyBudget:
|
|
32494
|
+
dailyBudgetUsd: z131.number().finite().positive().optional().describe("Legacy USD amount, supported only for USD advertiser accounts. No FX conversion."),
|
|
32495
|
+
dailyBudget: z131.number().finite().positive().optional().describe("Daily budget in the selected advertiser currency major units; pass budgetCurrency together."),
|
|
32415
32496
|
budgetCurrency: TikTokBudgetCurrencySchema.optional(),
|
|
32416
32497
|
destination: TikTokCampaignDestinationSchema.optional()
|
|
32417
32498
|
}).superRefine((value, ctx) => {
|
|
32418
32499
|
if (value.dailyBudgetUsd !== void 0 && (value.dailyBudget !== void 0 || value.budgetCurrency !== void 0)) {
|
|
32419
32500
|
ctx.addIssue({
|
|
32420
|
-
code:
|
|
32501
|
+
code: z131.ZodIssueCode.custom,
|
|
32421
32502
|
path: [
|
|
32422
32503
|
"dailyBudgetUsd"
|
|
32423
32504
|
],
|
|
@@ -32426,7 +32507,7 @@ var TikTokMcpCampaignConfig = McpCampaignConfig.extend({
|
|
|
32426
32507
|
}
|
|
32427
32508
|
if (value.dailyBudget !== void 0 !== (value.budgetCurrency !== void 0)) {
|
|
32428
32509
|
ctx.addIssue({
|
|
32429
|
-
code:
|
|
32510
|
+
code: z131.ZodIssueCode.custom,
|
|
32430
32511
|
path: [
|
|
32431
32512
|
"budgetCurrency"
|
|
32432
32513
|
],
|
|
@@ -32434,16 +32515,16 @@ var TikTokMcpCampaignConfig = McpCampaignConfig.extend({
|
|
|
32434
32515
|
});
|
|
32435
32516
|
}
|
|
32436
32517
|
});
|
|
32437
|
-
var TikTokInput =
|
|
32438
|
-
taskId:
|
|
32439
|
-
advertiserId:
|
|
32440
|
-
pixelId:
|
|
32441
|
-
landingUrl:
|
|
32442
|
-
angleIndexes:
|
|
32518
|
+
var TikTokInput = z131.object({
|
|
32519
|
+
taskId: z131.string().min(1),
|
|
32520
|
+
advertiserId: z131.string().min(1),
|
|
32521
|
+
pixelId: z131.string().min(1).optional(),
|
|
32522
|
+
landingUrl: z131.string().url().optional(),
|
|
32523
|
+
angleIndexes: z131.array(z131.number().int().nonnegative()).optional(),
|
|
32443
32524
|
campaignConfig: TikTokMcpCampaignConfig.optional(),
|
|
32444
32525
|
/** Override the ad's description (TikTok's body copy). If omitted,
|
|
32445
32526
|
* ProductMaker uses the auto-generated copy attached to the task. */
|
|
32446
|
-
primaryText:
|
|
32527
|
+
primaryText: z131.string().trim().min(1).max(500).optional()
|
|
32447
32528
|
});
|
|
32448
32529
|
function registerPublishTools(server, api, opts = {}) {
|
|
32449
32530
|
const transport = opts.transport ?? "http";
|
|
@@ -32802,39 +32883,39 @@ __name(toTikTokCampaignConfig, "toTikTokCampaignConfig");
|
|
|
32802
32883
|
|
|
32803
32884
|
// src/tools/meta-upload.ts
|
|
32804
32885
|
import { registerAppTool } from "@modelcontextprotocol/ext-apps/server";
|
|
32805
|
-
import { z as
|
|
32886
|
+
import { z as z132 } from "zod";
|
|
32806
32887
|
var requestMediaUploadGuidance = getProductMakerCapabilityModelGuidance("request_media_upload");
|
|
32807
|
-
var UploadSessionInputBase =
|
|
32808
|
-
mediaKind:
|
|
32888
|
+
var UploadSessionInputBase = z132.object({
|
|
32889
|
+
mediaKind: z132.enum([
|
|
32809
32890
|
"image",
|
|
32810
32891
|
"video",
|
|
32811
32892
|
"mixed"
|
|
32812
32893
|
]).default("mixed").describe("The kind of file the user will select. Use image for product references and landing pages, video for a single video, and mixed only when the consumer supports both."),
|
|
32813
|
-
assetRole:
|
|
32894
|
+
assetRole: z132.enum([
|
|
32814
32895
|
"media",
|
|
32815
32896
|
"thumbnail"
|
|
32816
32897
|
]).default("media").describe("Use media for the creative itself; thumbnail only for an image thumbnail."),
|
|
32817
|
-
uploadPurpose:
|
|
32898
|
+
uploadPurpose: z132.enum([
|
|
32818
32899
|
"product_reference",
|
|
32819
32900
|
"creative",
|
|
32820
32901
|
"generic"
|
|
32821
32902
|
]).default("generic").describe("The user's purpose for these files. Use product_reference for a product photo used by tasks or landings, creative for media that will become an ad or creative, and generic only when neither applies."),
|
|
32822
|
-
maxFiles:
|
|
32903
|
+
maxFiles: z132.number().int().min(1).max(10).optional().describe("Optional batch limit: image accepts 1-5, video exactly 1, and mixed 1-10.")
|
|
32823
32904
|
});
|
|
32824
|
-
var OpenAiFileReference =
|
|
32825
|
-
download_url:
|
|
32826
|
-
file_id:
|
|
32827
|
-
mime_type:
|
|
32828
|
-
file_name:
|
|
32905
|
+
var OpenAiFileReference = z132.object({
|
|
32906
|
+
download_url: z132.string().url().describe("Required by ChatGPT's openai/fileParams schema. The App prefers getFileDownloadUrl(file_id) for a fresh URL, and the server never fetches this value."),
|
|
32907
|
+
file_id: z132.string().min(1),
|
|
32908
|
+
mime_type: z132.string().min(1).optional(),
|
|
32909
|
+
file_name: z132.string().min(1).optional()
|
|
32829
32910
|
});
|
|
32830
32911
|
var UploadSessionToolInputShape = {
|
|
32831
32912
|
...UploadSessionInputBase.shape,
|
|
32832
|
-
files:
|
|
32913
|
+
files: z132.array(OpenAiFileReference).max(10).optional().describe("Optional OpenAI-hosted file references provided by ChatGPT. They are only metadata for the UI bridge and are never forwarded to ProductMaker.")
|
|
32833
32914
|
};
|
|
32834
|
-
var UploadSessionToolInput =
|
|
32915
|
+
var UploadSessionToolInput = z132.object(UploadSessionToolInputShape).superRefine((value, ctx) => {
|
|
32835
32916
|
if (value.assetRole === "thumbnail" && value.mediaKind !== "image") {
|
|
32836
32917
|
ctx.addIssue({
|
|
32837
|
-
code:
|
|
32918
|
+
code: z132.ZodIssueCode.custom,
|
|
32838
32919
|
path: [
|
|
32839
32920
|
"mediaKind"
|
|
32840
32921
|
],
|
|
@@ -32843,7 +32924,7 @@ var UploadSessionToolInput = z131.object(UploadSessionToolInputShape).superRefin
|
|
|
32843
32924
|
}
|
|
32844
32925
|
if (value.mediaKind === "video" && value.maxFiles !== void 0 && value.maxFiles !== 1) {
|
|
32845
32926
|
ctx.addIssue({
|
|
32846
|
-
code:
|
|
32927
|
+
code: z132.ZodIssueCode.custom,
|
|
32847
32928
|
path: [
|
|
32848
32929
|
"maxFiles"
|
|
32849
32930
|
],
|
|
@@ -32852,7 +32933,7 @@ var UploadSessionToolInput = z131.object(UploadSessionToolInputShape).superRefin
|
|
|
32852
32933
|
}
|
|
32853
32934
|
if (value.mediaKind === "image" && (value.maxFiles ?? 1) > 5) {
|
|
32854
32935
|
ctx.addIssue({
|
|
32855
|
-
code:
|
|
32936
|
+
code: z132.ZodIssueCode.custom,
|
|
32856
32937
|
path: [
|
|
32857
32938
|
"maxFiles"
|
|
32858
32939
|
],
|
|
@@ -32860,38 +32941,38 @@ var UploadSessionToolInput = z131.object(UploadSessionToolInputShape).superRefin
|
|
|
32860
32941
|
});
|
|
32861
32942
|
}
|
|
32862
32943
|
});
|
|
32863
|
-
var UploadSessionResponse =
|
|
32864
|
-
sessionId:
|
|
32865
|
-
uploadPageUrl:
|
|
32866
|
-
mediaKind:
|
|
32944
|
+
var UploadSessionResponse = z132.object({
|
|
32945
|
+
sessionId: z132.string().uuid(),
|
|
32946
|
+
uploadPageUrl: z132.string().url(),
|
|
32947
|
+
mediaKind: z132.enum([
|
|
32867
32948
|
"image",
|
|
32868
32949
|
"video",
|
|
32869
32950
|
"mixed"
|
|
32870
32951
|
]),
|
|
32871
|
-
assetRole:
|
|
32952
|
+
assetRole: z132.enum([
|
|
32872
32953
|
"media",
|
|
32873
32954
|
"thumbnail"
|
|
32874
32955
|
]),
|
|
32875
|
-
maxFiles:
|
|
32876
|
-
expiresAt:
|
|
32956
|
+
maxFiles: z132.number().int().positive(),
|
|
32957
|
+
expiresAt: z132.string().datetime()
|
|
32877
32958
|
});
|
|
32878
|
-
var UploadStatusInput =
|
|
32879
|
-
sessionId:
|
|
32959
|
+
var UploadStatusInput = z132.object({
|
|
32960
|
+
sessionId: z132.string().uuid().describe("The sessionId returned by request_media_upload.")
|
|
32880
32961
|
});
|
|
32881
|
-
var UniversalUploadStatusResponse =
|
|
32882
|
-
|
|
32883
|
-
status:
|
|
32884
|
-
assets:
|
|
32962
|
+
var UniversalUploadStatusResponse = z132.discriminatedUnion("status", [
|
|
32963
|
+
z132.object({
|
|
32964
|
+
status: z132.literal("pending"),
|
|
32965
|
+
assets: z132.array(z132.never()).length(0)
|
|
32885
32966
|
}),
|
|
32886
|
-
|
|
32887
|
-
status:
|
|
32888
|
-
assets:
|
|
32889
|
-
assetId:
|
|
32890
|
-
mediaKind:
|
|
32967
|
+
z132.object({
|
|
32968
|
+
status: z132.literal("uploaded"),
|
|
32969
|
+
assets: z132.array(z132.object({
|
|
32970
|
+
assetId: z132.string().uuid(),
|
|
32971
|
+
mediaKind: z132.enum([
|
|
32891
32972
|
"image",
|
|
32892
32973
|
"video"
|
|
32893
32974
|
]),
|
|
32894
|
-
assetRole:
|
|
32975
|
+
assetRole: z132.enum([
|
|
32895
32976
|
"media",
|
|
32896
32977
|
"thumbnail"
|
|
32897
32978
|
])
|
|
@@ -32899,13 +32980,13 @@ var UniversalUploadStatusResponse = z131.discriminatedUnion("status", [
|
|
|
32899
32980
|
})
|
|
32900
32981
|
]);
|
|
32901
32982
|
var UniversalUploadStructuredResponse = UploadSessionResponse.extend({
|
|
32902
|
-
uploadPurpose:
|
|
32983
|
+
uploadPurpose: z132.enum([
|
|
32903
32984
|
"product_reference",
|
|
32904
32985
|
"creative",
|
|
32905
32986
|
"generic"
|
|
32906
32987
|
]),
|
|
32907
|
-
checkToolName:
|
|
32908
|
-
resolveEndpoint:
|
|
32988
|
+
checkToolName: z132.literal("check_media_upload"),
|
|
32989
|
+
resolveEndpoint: z132.string().url()
|
|
32909
32990
|
});
|
|
32910
32991
|
function contextualizeUploadPageUrl(uploadPageUrl, uploadPurpose) {
|
|
32911
32992
|
const url = new URL(uploadPageUrl);
|
|
@@ -32996,15 +33077,15 @@ function registerMediaUploadTools(server, api) {
|
|
|
32996
33077
|
__name(registerMediaUploadTools, "registerMediaUploadTools");
|
|
32997
33078
|
|
|
32998
33079
|
// src/tools/campaigns.ts
|
|
32999
|
-
import { z as
|
|
33080
|
+
import { z as z133 } from "zod";
|
|
33000
33081
|
var getMetaCampaignStatusGuidance = getProductMakerCapabilityModelGuidance("get_meta_campaign_status");
|
|
33001
33082
|
var getTikTokCampaignStatusGuidance = getProductMakerCapabilityModelGuidance("get_tiktok_campaign_status");
|
|
33002
|
-
var MetaStatusInput =
|
|
33003
|
-
campaignId:
|
|
33083
|
+
var MetaStatusInput = z133.object({
|
|
33084
|
+
campaignId: z133.string().min(1).describe("Meta campaign ID returned by publish_to_meta.")
|
|
33004
33085
|
});
|
|
33005
|
-
var TikTokStatusInput =
|
|
33006
|
-
campaignId:
|
|
33007
|
-
advertiserId:
|
|
33086
|
+
var TikTokStatusInput = z133.object({
|
|
33087
|
+
campaignId: z133.string().min(1).describe("TikTok campaign ID returned by publish_to_tiktok."),
|
|
33088
|
+
advertiserId: z133.string().min(1).describe("The same advertiserId used to publish the campaign.")
|
|
33008
33089
|
});
|
|
33009
33090
|
function registerCampaignTools(server, api) {
|
|
33010
33091
|
server.registerTool("get_meta_campaign_status", {
|
|
@@ -33109,10 +33190,10 @@ function renderTikTokStatusMarkdown(r) {
|
|
|
33109
33190
|
__name(renderTikTokStatusMarkdown, "renderTikTokStatusMarkdown");
|
|
33110
33191
|
|
|
33111
33192
|
// ../../packages/product-economics/src/product-costing.ts
|
|
33112
|
-
import { z as
|
|
33193
|
+
import { z as z135 } from "zod";
|
|
33113
33194
|
|
|
33114
33195
|
// ../../packages/product-economics/src/product-costing-countries.ts
|
|
33115
|
-
import { z as
|
|
33196
|
+
import { z as z134 } from "zod";
|
|
33116
33197
|
|
|
33117
33198
|
// ../../packages/product-economics/src/product-costing-shipping-references.json
|
|
33118
33199
|
var product_costing_shipping_references_default = {
|
|
@@ -33176,21 +33257,21 @@ var product_costing_shipping_references_default = {
|
|
|
33176
33257
|
};
|
|
33177
33258
|
|
|
33178
33259
|
// ../../packages/product-economics/src/product-costing-countries.ts
|
|
33179
|
-
var ShippingReferenceSchema =
|
|
33180
|
-
reference:
|
|
33181
|
-
min:
|
|
33182
|
-
max:
|
|
33183
|
-
updatedAt:
|
|
33184
|
-
confidence:
|
|
33260
|
+
var ShippingReferenceSchema = z134.object({
|
|
33261
|
+
reference: z134.number().positive(),
|
|
33262
|
+
min: z134.number().nonnegative(),
|
|
33263
|
+
max: z134.number().positive(),
|
|
33264
|
+
updatedAt: z134.string().date(),
|
|
33265
|
+
confidence: z134.enum([
|
|
33185
33266
|
"high",
|
|
33186
33267
|
"medium",
|
|
33187
33268
|
"medium-low"
|
|
33188
33269
|
]),
|
|
33189
|
-
sources:
|
|
33270
|
+
sources: z134.array(z134.string().url().startsWith("https://")).min(1).max(3)
|
|
33190
33271
|
}).superRefine(({ reference, min, max }, context) => {
|
|
33191
33272
|
if (min > reference || reference > max) {
|
|
33192
33273
|
context.addIssue({
|
|
33193
|
-
code:
|
|
33274
|
+
code: z134.ZodIssueCode.custom,
|
|
33194
33275
|
message: "shipping_reference_outside_range",
|
|
33195
33276
|
path: [
|
|
33196
33277
|
"reference"
|
|
@@ -33198,7 +33279,7 @@ var ShippingReferenceSchema = z133.object({
|
|
|
33198
33279
|
});
|
|
33199
33280
|
}
|
|
33200
33281
|
});
|
|
33201
|
-
var SHIPPING_REFERENCES =
|
|
33282
|
+
var SHIPPING_REFERENCES = z134.record(ShippingReferenceSchema).parse(product_costing_shipping_references_default);
|
|
33202
33283
|
var PRODUCT_COSTING_COUNTRY_CODES = Object.freeze(Object.keys(SHIPPING_REFERENCES));
|
|
33203
33284
|
var SPANISH_LOCALE_COUNTRIES = /* @__PURE__ */ new Set([
|
|
33204
33285
|
"MX",
|
|
@@ -33380,18 +33461,18 @@ function getProductCostingCountryName(country) {
|
|
|
33380
33461
|
__name(getProductCostingCountryName, "getProductCostingCountryName");
|
|
33381
33462
|
|
|
33382
33463
|
// ../../packages/product-economics/src/product-costing.ts
|
|
33383
|
-
var ProductCostingInputSchema =
|
|
33384
|
-
country:
|
|
33385
|
-
supplierCost:
|
|
33386
|
-
shippingCost:
|
|
33387
|
-
returnRate:
|
|
33388
|
-
cancellationRate:
|
|
33389
|
-
adsManagerCpa:
|
|
33390
|
-
desiredMargin:
|
|
33464
|
+
var ProductCostingInputSchema = z135.object({
|
|
33465
|
+
country: z135.string().refine(isProductCostingCountryCode, "unsupported_country"),
|
|
33466
|
+
supplierCost: z135.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").positive("supplier_cost_positive"),
|
|
33467
|
+
shippingCost: z135.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("shipping_cost_nonnegative"),
|
|
33468
|
+
returnRate: z135.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
|
|
33469
|
+
cancellationRate: z135.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
|
|
33470
|
+
adsManagerCpa: z135.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("cpa_nonnegative"),
|
|
33471
|
+
desiredMargin: z135.number().finite().min(0, "margin_nonnegative").lt(1, "margin_below_one")
|
|
33391
33472
|
}).superRefine(({ returnRate, cancellationRate }, context) => {
|
|
33392
33473
|
if (returnRate + cancellationRate >= 1) {
|
|
33393
33474
|
context.addIssue({
|
|
33394
|
-
code:
|
|
33475
|
+
code: z135.ZodIssueCode.custom,
|
|
33395
33476
|
message: "delivery_rate_positive",
|
|
33396
33477
|
path: [
|
|
33397
33478
|
"cancellationRate"
|
|
@@ -33488,15 +33569,15 @@ function calculateProductCosting(rawInput) {
|
|
|
33488
33569
|
__name(calculateProductCosting, "calculateProductCosting");
|
|
33489
33570
|
|
|
33490
33571
|
// src/tools/product-costing.ts
|
|
33491
|
-
import { z as
|
|
33572
|
+
import { z as z136 } from "zod";
|
|
33492
33573
|
var costProductGuidance = getProductMakerCapabilityModelGuidance("cost_product");
|
|
33493
|
-
var optionalAmount = /* @__PURE__ */ __name((description) =>
|
|
33494
|
-
var optionalPercent = /* @__PURE__ */ __name((description) =>
|
|
33495
|
-
var ProductCostingToolInput =
|
|
33496
|
-
country:
|
|
33574
|
+
var optionalAmount = /* @__PURE__ */ __name((description) => z136.number().finite().max(Number.MAX_SAFE_INTEGER).nonnegative().optional().describe(description), "optionalAmount");
|
|
33575
|
+
var optionalPercent = /* @__PURE__ */ __name((description) => z136.number().finite().min(0).lt(100).optional().describe(description), "optionalPercent");
|
|
33576
|
+
var ProductCostingToolInput = z136.object({
|
|
33577
|
+
country: z136.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
|
|
33497
33578
|
message: "Pa\xEDs no soportado por ProductMaker."
|
|
33498
33579
|
}).optional().describe("C\xF3digo ISO-2 de cualquiera de los pa\xEDses disponibles en ProductMaker. Omite para Colombia."),
|
|
33499
|
-
supplierCost:
|
|
33580
|
+
supplierCost: z136.number().finite().max(Number.MAX_SAFE_INTEGER).positive().optional().describe("Costo real de una unidad con el proveedor, en la moneda del pa\xEDs. Requerido salvo que uses supplierCostCop para Colombia."),
|
|
33500
33581
|
supplierCostCop: optionalAmount("Alias anterior para costo del proveedor en Colombia. Prefiere supplierCost."),
|
|
33501
33582
|
shippingCost: optionalAmount("Costo de un env\xEDo en la moneda del pa\xEDs. Omite para usar el valor gu\xEDa vigente."),
|
|
33502
33583
|
shippingCostCop: optionalAmount("Alias anterior para flete en Colombia. Prefiere shippingCost."),
|
|
@@ -33659,7 +33740,7 @@ function formatPercent(value) {
|
|
|
33659
33740
|
__name(formatPercent, "formatPercent");
|
|
33660
33741
|
|
|
33661
33742
|
// src/tools/product-research.ts
|
|
33662
|
-
import { z as
|
|
33743
|
+
import { z as z137 } from "zod";
|
|
33663
33744
|
|
|
33664
33745
|
// src/tools/product-research-idempotency.ts
|
|
33665
33746
|
var RESEARCH_IDEMPOTENCY_WINDOW_MS = 2 * 60 * 60 * 1e3;
|
|
@@ -34030,17 +34111,17 @@ var TERMINAL2 = /* @__PURE__ */ new Set([
|
|
|
34030
34111
|
]);
|
|
34031
34112
|
var POLL_INTERVAL_MS = 5e3;
|
|
34032
34113
|
var MAX_WAIT_SECONDS = 120;
|
|
34033
|
-
var FindInput =
|
|
34114
|
+
var FindInput = z137.object({
|
|
34034
34115
|
targetCountry: ResearchTargetCountryEnum.describe("Pa\xEDs objetivo. S\xF3lo CO, MX, PE, EC y CL tienen cobertura de investigaci\xF3n."),
|
|
34035
34116
|
categoryKey: ResearchCategoryEnum.default("auto").describe('Categor\xEDa a investigar. Usa "auto" para que la IA elija seg\xFAn el mercado.'),
|
|
34036
|
-
confirmed:
|
|
34037
|
-
waitSeconds:
|
|
34117
|
+
confirmed: z137.boolean().describe(`Ponlo en true SOLO despu\xE9s de que el usuario haya aceptado el cargo de ${PRICE_CREDITS} cr\xE9ditos. No lo asumas.`),
|
|
34118
|
+
waitSeconds: z137.number().int().min(0).max(MAX_WAIT_SECONDS).optional().describe("Segundos a esperar el reporte antes de devolver el runId. M\xE1ximo 120.")
|
|
34038
34119
|
});
|
|
34039
|
-
var GetInput =
|
|
34040
|
-
runId:
|
|
34120
|
+
var GetInput = z137.object({
|
|
34121
|
+
runId: z137.string().uuid().describe("ID del run devuelto por find_winning_products.")
|
|
34041
34122
|
});
|
|
34042
|
-
var ListInput =
|
|
34043
|
-
limit:
|
|
34123
|
+
var ListInput = z137.object({
|
|
34124
|
+
limit: z137.number().int().min(1).max(20).default(10)
|
|
34044
34125
|
});
|
|
34045
34126
|
function textResult(text2) {
|
|
34046
34127
|
return {
|
|
@@ -34179,17 +34260,17 @@ _Esta llamada no cobr\xF3 cr\xE9ditos: se reutiliz\xF3 una investigaci\xF3n reci
|
|
|
34179
34260
|
__name(registerProductResearchTools, "registerProductResearchTools");
|
|
34180
34261
|
|
|
34181
34262
|
// src/tools/dropshipping-projects.ts
|
|
34182
|
-
import { z as
|
|
34263
|
+
import { z as z138 } from "zod";
|
|
34183
34264
|
var startDropshippingProjectGuidance = getProductMakerCapabilityModelGuidance("start_dropshipping_project");
|
|
34184
34265
|
var costDropshippingProjectGuidance = getProductMakerCapabilityModelGuidance("cost_dropshipping_project");
|
|
34185
34266
|
var guideDropshippingLaunchGuidance = getProductMakerCapabilityModelGuidance("guide_dropshipping_launch");
|
|
34186
|
-
var ProjectId =
|
|
34187
|
-
var DropshippingProjectStatus =
|
|
34267
|
+
var ProjectId = z138.string().uuid();
|
|
34268
|
+
var DropshippingProjectStatus = z138.enum([
|
|
34188
34269
|
"active",
|
|
34189
34270
|
"completed",
|
|
34190
34271
|
"archived"
|
|
34191
34272
|
]);
|
|
34192
|
-
var DropshippingProjectPhase =
|
|
34273
|
+
var DropshippingProjectPhase = z138.enum([
|
|
34193
34274
|
"research",
|
|
34194
34275
|
"costing",
|
|
34195
34276
|
"media",
|
|
@@ -34198,21 +34279,21 @@ var DropshippingProjectPhase = z137.enum([
|
|
|
34198
34279
|
"advertising",
|
|
34199
34280
|
"complete"
|
|
34200
34281
|
]);
|
|
34201
|
-
var DropshippingRewardMilestone =
|
|
34282
|
+
var DropshippingRewardMilestone = z138.enum([
|
|
34202
34283
|
"product_selected",
|
|
34203
34284
|
"costing_saved",
|
|
34204
34285
|
"product_media_ready",
|
|
34205
34286
|
"creatives_completed",
|
|
34206
34287
|
"campaign_created"
|
|
34207
34288
|
]);
|
|
34208
|
-
var TargetCountry =
|
|
34289
|
+
var TargetCountry = z138.enum([
|
|
34209
34290
|
"CO",
|
|
34210
34291
|
"MX",
|
|
34211
34292
|
"PE",
|
|
34212
34293
|
"EC",
|
|
34213
34294
|
"CL"
|
|
34214
34295
|
]);
|
|
34215
|
-
var ResearchCategory =
|
|
34296
|
+
var ResearchCategory = z138.enum([
|
|
34216
34297
|
"auto",
|
|
34217
34298
|
"automotive",
|
|
34218
34299
|
"kitchen",
|
|
@@ -34227,7 +34308,7 @@ var ResearchCategory = z137.enum([
|
|
|
34227
34308
|
"garden",
|
|
34228
34309
|
"cleaning"
|
|
34229
34310
|
]);
|
|
34230
|
-
var HttpUrl3 =
|
|
34311
|
+
var HttpUrl3 = z138.string().url().max(2e3).refine((value) => {
|
|
34231
34312
|
try {
|
|
34232
34313
|
return [
|
|
34233
34314
|
"http:",
|
|
@@ -34237,45 +34318,45 @@ var HttpUrl3 = z137.string().url().max(2e3).refine((value) => {
|
|
|
34237
34318
|
return false;
|
|
34238
34319
|
}
|
|
34239
34320
|
}, "URL must use HTTP(S)");
|
|
34240
|
-
var ResearchCandidateOrigin =
|
|
34241
|
-
type:
|
|
34321
|
+
var ResearchCandidateOrigin = z138.object({
|
|
34322
|
+
type: z138.literal("research_candidate"),
|
|
34242
34323
|
runId: ProjectId,
|
|
34243
|
-
candidateSourceId:
|
|
34324
|
+
candidateSourceId: z138.string().min(1).max(160)
|
|
34244
34325
|
});
|
|
34245
|
-
var TaskOrigin =
|
|
34246
|
-
type:
|
|
34326
|
+
var TaskOrigin = z138.object({
|
|
34327
|
+
type: z138.literal("task"),
|
|
34247
34328
|
taskId: ProjectId
|
|
34248
34329
|
});
|
|
34249
|
-
var ManualOrigin =
|
|
34250
|
-
type:
|
|
34330
|
+
var ManualOrigin = z138.object({
|
|
34331
|
+
type: z138.literal("manual"),
|
|
34251
34332
|
clientRequestId: ProjectId,
|
|
34252
|
-
country:
|
|
34333
|
+
country: z138.string().min(2).max(3).optional()
|
|
34253
34334
|
});
|
|
34254
|
-
var StartProjectInput =
|
|
34255
|
-
origin:
|
|
34335
|
+
var StartProjectInput = z138.object({
|
|
34336
|
+
origin: z138.discriminatedUnion("type", [
|
|
34256
34337
|
ResearchCandidateOrigin,
|
|
34257
34338
|
TaskOrigin,
|
|
34258
34339
|
ManualOrigin
|
|
34259
34340
|
]),
|
|
34260
|
-
productName:
|
|
34341
|
+
productName: z138.string().trim().min(1).max(240).optional(),
|
|
34261
34342
|
productUrl: HttpUrl3.optional(),
|
|
34262
|
-
country:
|
|
34263
|
-
languageCode:
|
|
34343
|
+
country: z138.string().min(2).max(3).optional(),
|
|
34344
|
+
languageCode: z138.string().min(2).max(16).optional()
|
|
34264
34345
|
}).strict();
|
|
34265
|
-
var CostProjectInput =
|
|
34346
|
+
var CostProjectInput = z138.object({
|
|
34266
34347
|
projectId: ProjectId,
|
|
34267
|
-
version:
|
|
34268
|
-
country:
|
|
34348
|
+
version: z138.number().int().positive().describe("Version le\xEDda del proyecto. Copia la \xFAltima que viste; no se la pidas al usuario."),
|
|
34349
|
+
country: z138.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
|
|
34269
34350
|
message: "Pa\xEDs no soportado por ProductMaker."
|
|
34270
34351
|
}).describe("C\xF3digo ISO-2 del pa\xEDs del proyecto. Usa el `targetCountry` que devuelve el proyecto."),
|
|
34271
|
-
supplierCost:
|
|
34272
|
-
shippingCost:
|
|
34273
|
-
returnRate:
|
|
34274
|
-
cancellationRate:
|
|
34275
|
-
adsManagerCpa:
|
|
34276
|
-
desiredMargin:
|
|
34277
|
-
});
|
|
34278
|
-
var GuideInput =
|
|
34352
|
+
supplierCost: z138.number().finite().positive().describe("Costo real de una unidad con el proveedor, en la moneda del pa\xEDs. \xDANICO dato que debes pedirle al usuario: nunca lo inventes."),
|
|
34353
|
+
shippingCost: z138.number().finite().nonnegative().optional().describe("Costo de un env\xEDo. Omite para usar el valor gu\xEDa del pa\xEDs en vez de inventarlo."),
|
|
34354
|
+
returnRate: z138.number().finite().min(0).lt(1).optional().describe("Fracci\xF3n de pedidos devueltos (0.25 = 25%). Omite para usar el valor gu\xEDa del pa\xEDs."),
|
|
34355
|
+
cancellationRate: z138.number().finite().min(0).lt(1).optional().describe("Fracci\xF3n de pedidos cancelados (0.15 = 15%). Omite para usar el valor gu\xEDa del pa\xEDs."),
|
|
34356
|
+
adsManagerCpa: z138.number().finite().nonnegative().optional().describe("Costo por compra de Ads Manager. Omite para usar el valor gu\xEDa del pa\xEDs."),
|
|
34357
|
+
desiredMargin: z138.number().finite().min(0).lt(1).optional().describe("Margen deseado (0.1 = 10%). Omite para usar el valor gu\xEDa del pa\xEDs.")
|
|
34358
|
+
});
|
|
34359
|
+
var GuideInput = z138.object({
|
|
34279
34360
|
projectId: ProjectId.optional()
|
|
34280
34361
|
}).strict();
|
|
34281
34362
|
var NEXT_ACTION_KINDS = [
|
|
@@ -34293,29 +34374,29 @@ var NEXT_ACTION_KINDS = [
|
|
|
34293
34374
|
"repair_meta_campaign",
|
|
34294
34375
|
"review_paused_campaign"
|
|
34295
34376
|
];
|
|
34296
|
-
var DropshippingProjectNextAction =
|
|
34297
|
-
kind:
|
|
34298
|
-
href:
|
|
34377
|
+
var DropshippingProjectNextAction = z138.discriminatedUnion("kind", NEXT_ACTION_KINDS.map((kind) => z138.object({
|
|
34378
|
+
kind: z138.literal(kind),
|
|
34379
|
+
href: z138.string().min(1)
|
|
34299
34380
|
})));
|
|
34300
|
-
var CostingInputSchema =
|
|
34301
|
-
country:
|
|
34302
|
-
supplierCost:
|
|
34303
|
-
shippingCost:
|
|
34304
|
-
returnRate:
|
|
34305
|
-
cancellationRate:
|
|
34306
|
-
adsManagerCpa:
|
|
34307
|
-
desiredMargin:
|
|
34381
|
+
var CostingInputSchema = z138.object({
|
|
34382
|
+
country: z138.string().min(2).max(3),
|
|
34383
|
+
supplierCost: z138.number().finite().positive(),
|
|
34384
|
+
shippingCost: z138.number().finite().nonnegative(),
|
|
34385
|
+
returnRate: z138.number().finite().min(0).lt(1),
|
|
34386
|
+
cancellationRate: z138.number().finite().min(0).lt(1),
|
|
34387
|
+
adsManagerCpa: z138.number().finite().nonnegative(),
|
|
34388
|
+
desiredMargin: z138.number().finite().min(0).lt(1)
|
|
34308
34389
|
}).superRefine(({ returnRate, cancellationRate }, context) => {
|
|
34309
34390
|
if (returnRate + cancellationRate >= 1) context.addIssue({
|
|
34310
|
-
code:
|
|
34391
|
+
code: z138.ZodIssueCode.custom,
|
|
34311
34392
|
path: [
|
|
34312
34393
|
"cancellationRate"
|
|
34313
34394
|
]
|
|
34314
34395
|
});
|
|
34315
34396
|
});
|
|
34316
|
-
var FiniteCostingNumber =
|
|
34317
|
-
var CostingResultSchema =
|
|
34318
|
-
country:
|
|
34397
|
+
var FiniteCostingNumber = z138.number().finite();
|
|
34398
|
+
var CostingResultSchema = z138.object({
|
|
34399
|
+
country: z138.string().min(2).max(3),
|
|
34319
34400
|
deliveryRate: FiniteCostingNumber,
|
|
34320
34401
|
adjustedShippingCost: FiniteCostingNumber,
|
|
34321
34402
|
adjustedCpa: FiniteCostingNumber,
|
|
@@ -34328,45 +34409,45 @@ var CostingResultSchema = z137.object({
|
|
|
34328
34409
|
estimatedProfit: FiniteCostingNumber,
|
|
34329
34410
|
actualMargin: FiniteCostingNumber,
|
|
34330
34411
|
breakEvenAdsManagerCpa: FiniteCostingNumber,
|
|
34331
|
-
wasPriceAutoAdjusted:
|
|
34332
|
-
profitabilityStatus:
|
|
34333
|
-
});
|
|
34334
|
-
var RewardProgressSchema =
|
|
34335
|
-
campaignKey:
|
|
34336
|
-
totalCredits:
|
|
34337
|
-
earnedCredits:
|
|
34338
|
-
milestones:
|
|
34412
|
+
wasPriceAutoAdjusted: z138.boolean(),
|
|
34413
|
+
profitabilityStatus: z138.literal("healthy")
|
|
34414
|
+
});
|
|
34415
|
+
var RewardProgressSchema = z138.object({
|
|
34416
|
+
campaignKey: z138.literal("dropshipping-launch-v1"),
|
|
34417
|
+
totalCredits: z138.number().int().positive(),
|
|
34418
|
+
earnedCredits: z138.number().int().nonnegative(),
|
|
34419
|
+
milestones: z138.array(z138.object({
|
|
34339
34420
|
milestone: DropshippingRewardMilestone,
|
|
34340
|
-
credits:
|
|
34341
|
-
available:
|
|
34342
|
-
earned:
|
|
34421
|
+
credits: z138.number().int().positive(),
|
|
34422
|
+
available: z138.boolean().optional(),
|
|
34423
|
+
earned: z138.boolean(),
|
|
34343
34424
|
grantId: ProjectId.nullable(),
|
|
34344
|
-
grantedAt:
|
|
34425
|
+
grantedAt: z138.string().datetime().nullable()
|
|
34345
34426
|
})).length(DropshippingRewardMilestone.options.length)
|
|
34346
34427
|
});
|
|
34347
|
-
var ProjectResponseSchema =
|
|
34428
|
+
var ProjectResponseSchema = z138.object({
|
|
34348
34429
|
id: ProjectId,
|
|
34349
34430
|
taskId: ProjectId.nullable(),
|
|
34350
34431
|
status: DropshippingProjectStatus,
|
|
34351
|
-
originKey:
|
|
34432
|
+
originKey: z138.string().min(1),
|
|
34352
34433
|
researchRunId: ProjectId.nullable(),
|
|
34353
|
-
candidateSourceId:
|
|
34354
|
-
productName:
|
|
34434
|
+
candidateSourceId: z138.string().nullable(),
|
|
34435
|
+
productName: z138.string().nullable(),
|
|
34355
34436
|
productUrl: HttpUrl3.nullable(),
|
|
34356
34437
|
referenceImageUrl: HttpUrl3.nullable(),
|
|
34357
|
-
targetCountry:
|
|
34358
|
-
languageCode:
|
|
34359
|
-
hasReferenceImage:
|
|
34360
|
-
hasWinnerReferenceImage:
|
|
34438
|
+
targetCountry: z138.string().nullable(),
|
|
34439
|
+
languageCode: z138.string().nullable(),
|
|
34440
|
+
hasReferenceImage: z138.boolean(),
|
|
34441
|
+
hasWinnerReferenceImage: z138.boolean(),
|
|
34361
34442
|
costingInput: CostingInputSchema.nullable(),
|
|
34362
34443
|
costingResult: CostingResultSchema.nullable(),
|
|
34363
|
-
costingVersion:
|
|
34364
|
-
version:
|
|
34444
|
+
costingVersion: z138.number().int().positive().nullable(),
|
|
34445
|
+
version: z138.number().int().positive(),
|
|
34365
34446
|
phase: DropshippingProjectPhase,
|
|
34366
34447
|
nextAction: DropshippingProjectNextAction.nullable(),
|
|
34367
34448
|
rewards: RewardProgressSchema,
|
|
34368
|
-
createdAt:
|
|
34369
|
-
updatedAt:
|
|
34449
|
+
createdAt: z138.string().datetime(),
|
|
34450
|
+
updatedAt: z138.string().datetime()
|
|
34370
34451
|
}).passthrough();
|
|
34371
34452
|
var NEXT_ACTION_GUIDANCE = {
|
|
34372
34453
|
cost_product: "Llama `cost_dropshipping_project` con el costo real del proveedor. Nunca lo inventes: p\xEDdeselo al usuario. Es el \xDANICO dato que debes pedirle: omite env\xEDo, devoluciones, cancelaciones, CPA y margen para que ProductMaker use los valores gu\xEDa del pa\xEDs, y luego dile al usuario cu\xE1les us\xF3 por si quiere corregirlos.",
|
|
@@ -34486,58 +34567,58 @@ function registerDropshippingProjectTools(server, api) {
|
|
|
34486
34567
|
__name(registerDropshippingProjectTools, "registerDropshippingProjectTools");
|
|
34487
34568
|
|
|
34488
34569
|
// src/tools/daily-control.ts
|
|
34489
|
-
import { z as
|
|
34570
|
+
import { z as z139 } from "zod";
|
|
34490
34571
|
var getDailyControlGuidance = getProductMakerCapabilityModelGuidance("get_daily_control");
|
|
34491
34572
|
var linkCampaignToProjectGuidance = getProductMakerCapabilityModelGuidance("link_campaign_to_project");
|
|
34492
34573
|
var reportDailyReturnsGuidance = getProductMakerCapabilityModelGuidance("report_daily_returns");
|
|
34493
|
-
var ProviderCampaignIdentifier =
|
|
34494
|
-
var DateOnly =
|
|
34495
|
-
var DailyControlInput =
|
|
34574
|
+
var ProviderCampaignIdentifier = z139.string().min(1).max(64).regex(/^[A-Za-z0-9_-]+$/);
|
|
34575
|
+
var DateOnly = z139.string().regex(/^\d{4}-\d{2}-\d{2}$/);
|
|
34576
|
+
var DailyControlInput = z139.object({
|
|
34496
34577
|
date: DateOnly.optional().describe("D\xEDa final de la ventana (YYYY-MM-DD). Si se omite, la ventana termina AYER en UTC \u2014 nunca hoy, porque el d\xEDa en curso est\xE1 incompleto \u2014 y el servidor puede correrla un d\xEDa m\xE1s atr\xE1s si en la zona horaria de la tienda ese d\xEDa todav\xEDa no ha cerrado."),
|
|
34497
|
-
days:
|
|
34498
|
-
projectId:
|
|
34578
|
+
days: z139.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
|
|
34579
|
+
projectId: z139.string().uuid().optional().describe("Opcional: limita el reporte a un solo proyecto en vez de todos los productos activos.")
|
|
34499
34580
|
}).strict();
|
|
34500
|
-
var LinkCampaignInput =
|
|
34501
|
-
projectId:
|
|
34502
|
-
provider:
|
|
34581
|
+
var LinkCampaignInput = z139.object({
|
|
34582
|
+
projectId: z139.string().uuid(),
|
|
34583
|
+
provider: z139.enum([
|
|
34503
34584
|
"meta",
|
|
34504
34585
|
"tiktok"
|
|
34505
34586
|
]),
|
|
34506
34587
|
accountId: ProviderCampaignIdentifier.describe("Cuenta publicitaria del proveedor. Para Meta el servidor la IGNORA y deriva la cuenta real de la campa\xF1a \u2014 se sigue pidiendo aqu\xED solo porque TikTok s\xED la necesita para resolver la campa\xF1a."),
|
|
34507
34588
|
campaignId: ProviderCampaignIdentifier
|
|
34508
34589
|
}).strict();
|
|
34509
|
-
var ReportReturnsInput =
|
|
34510
|
-
projectId:
|
|
34590
|
+
var ReportReturnsInput = z139.object({
|
|
34591
|
+
projectId: z139.string().uuid(),
|
|
34511
34592
|
date: DateOnly,
|
|
34512
|
-
returnedOrders:
|
|
34513
|
-
note:
|
|
34593
|
+
returnedOrders: z139.number().int().min(0).max(1e5),
|
|
34594
|
+
note: z139.string().trim().max(280).optional()
|
|
34514
34595
|
}).strict();
|
|
34515
|
-
var DailyControlStatusMirror = DailyControlStatusEnum.or(
|
|
34516
|
-
var DailyControlLightMirror = DailyControlLightEnum.or(
|
|
34517
|
-
var DailyControlSourceMirror = DailyControlSourceEnum.or(
|
|
34518
|
-
var DailyControlVerdictMirror = DailyControlVerdictEnum.or(
|
|
34519
|
-
var DailyControlDayMirror =
|
|
34520
|
-
date:
|
|
34521
|
-
returnedOrders:
|
|
34596
|
+
var DailyControlStatusMirror = DailyControlStatusEnum.or(z139.string());
|
|
34597
|
+
var DailyControlLightMirror = DailyControlLightEnum.or(z139.string());
|
|
34598
|
+
var DailyControlSourceMirror = DailyControlSourceEnum.or(z139.string());
|
|
34599
|
+
var DailyControlVerdictMirror = DailyControlVerdictEnum.or(z139.string());
|
|
34600
|
+
var DailyControlDayMirror = z139.object({
|
|
34601
|
+
date: z139.string(),
|
|
34602
|
+
returnedOrders: z139.number(),
|
|
34522
34603
|
returnedSource: DailyControlSourceMirror,
|
|
34523
34604
|
cancelledSource: DailyControlSourceMirror,
|
|
34524
|
-
hasEstimates:
|
|
34605
|
+
hasEstimates: z139.boolean(),
|
|
34525
34606
|
light: DailyControlLightMirror
|
|
34526
34607
|
}).passthrough();
|
|
34527
|
-
var DailyControlProductMirror =
|
|
34528
|
-
projectId:
|
|
34529
|
-
productName:
|
|
34608
|
+
var DailyControlProductMirror = z139.object({
|
|
34609
|
+
projectId: z139.string().uuid(),
|
|
34610
|
+
productName: z139.string().nullable(),
|
|
34530
34611
|
status: DailyControlStatusMirror,
|
|
34531
|
-
statusMessage:
|
|
34532
|
-
days:
|
|
34612
|
+
statusMessage: z139.string().nullable(),
|
|
34613
|
+
days: z139.array(DailyControlDayMirror),
|
|
34533
34614
|
verdict: DailyControlVerdictMirror.nullable(),
|
|
34534
|
-
rationale:
|
|
34615
|
+
rationale: z139.string().nullable()
|
|
34535
34616
|
}).passthrough();
|
|
34536
|
-
var DailyControlResponseMirror =
|
|
34537
|
-
since:
|
|
34538
|
-
until:
|
|
34539
|
-
products:
|
|
34540
|
-
archivedProjectSpend:
|
|
34617
|
+
var DailyControlResponseMirror = z139.object({
|
|
34618
|
+
since: z139.string(),
|
|
34619
|
+
until: z139.string(),
|
|
34620
|
+
products: z139.array(DailyControlProductMirror),
|
|
34621
|
+
archivedProjectSpend: z139.array(z139.unknown())
|
|
34541
34622
|
}).passthrough();
|
|
34542
34623
|
var MCP_WARNINGS_KEY = "_mcpDailyControlWarnings";
|
|
34543
34624
|
function withWarnings(response) {
|
|
@@ -34612,7 +34693,7 @@ __name(registerDailyControlTools, "registerDailyControlTools");
|
|
|
34612
34693
|
// src/tools/product-control.ts
|
|
34613
34694
|
import { readFile, stat } from "fs/promises";
|
|
34614
34695
|
import { basename as basename2, isAbsolute, resolve as resolve3 } from "path";
|
|
34615
|
-
import { z as
|
|
34696
|
+
import { z as z140 } from "zod";
|
|
34616
34697
|
var getProductControlGuidance = getProductMakerCapabilityModelGuidance("get_product_control");
|
|
34617
34698
|
var listImportableProductsGuidance = getProductMakerCapabilityModelGuidance("list_importable_products");
|
|
34618
34699
|
var importProductControlsGuidance = getProductMakerCapabilityModelGuidance("import_product_controls");
|
|
@@ -34625,36 +34706,36 @@ var createOperationGuidance = getProductMakerCapabilityModelGuidance("create_ope
|
|
|
34625
34706
|
var mergeProductsGuidance = getProductMakerCapabilityModelGuidance("merge_products");
|
|
34626
34707
|
var syncShopifyOrdersGuidance = getProductMakerCapabilityModelGuidance("sync_shopify_orders");
|
|
34627
34708
|
var importOrdersFileGuidance = getProductMakerCapabilityModelGuidance("import_orders_file");
|
|
34628
|
-
var DateOnly2 =
|
|
34709
|
+
var DateOnly2 = z140.string().regex(/^\d{4}-\d{2}-\d{2}$/);
|
|
34629
34710
|
var IMPORT_BATCH_MAX2 = 50;
|
|
34630
|
-
var ProductControlListInput =
|
|
34631
|
-
days:
|
|
34711
|
+
var ProductControlListInput = z140.object({
|
|
34712
|
+
days: z140.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
|
|
34632
34713
|
date: DateOnly2.optional().describe("D\xEDa final de la ventana (YYYY-MM-DD). Si se omite, termina en el \xFAltimo d\xEDa cerrado \u2014 nunca hoy, que est\xE1 incompleto."),
|
|
34633
|
-
shopDomain:
|
|
34714
|
+
shopDomain: z140.string().min(1).optional().describe("Tienda, si tiene m\xE1s de una conectada.")
|
|
34634
34715
|
}).strict();
|
|
34635
|
-
var ImportableProductsInput =
|
|
34636
|
-
q:
|
|
34637
|
-
after:
|
|
34638
|
-
shopDomain:
|
|
34716
|
+
var ImportableProductsInput = z140.object({
|
|
34717
|
+
q: z140.string().trim().max(120).optional().describe("B\xFAsqueda por t\xEDtulo. Sin esto un cat\xE1logo grande es inrecorrible."),
|
|
34718
|
+
after: z140.string().max(512).optional().describe("Cursor de la p\xE1gina anterior, tal como vino en la respuesta."),
|
|
34719
|
+
shopDomain: z140.string().min(1).optional()
|
|
34639
34720
|
}).strict();
|
|
34640
|
-
var ImportProductControlsInput =
|
|
34641
|
-
shopifyProductIds:
|
|
34721
|
+
var ImportProductControlsInput = z140.object({
|
|
34722
|
+
shopifyProductIds: z140.array(z140.string().min(1).max(64)).min(1).max(IMPORT_BATCH_MAX2).describe("Identificadores tal como vinieron de list_importable_products. NO los inventes ni los deduzcas del t\xEDtulo."),
|
|
34642
34723
|
// Obligatorio, como en el endpoint: con dos tiendas conectadas, importar
|
|
34643
34724
|
// sin decir a cuál archivaría el producto bajo la tienda equivocada.
|
|
34644
|
-
shopDomain:
|
|
34725
|
+
shopDomain: z140.string().min(1)
|
|
34645
34726
|
}).strict();
|
|
34646
|
-
var SetProductCostingInput =
|
|
34647
|
-
shopDomain:
|
|
34648
|
-
shopifyProductId:
|
|
34649
|
-
targetCountry:
|
|
34650
|
-
supplierCost:
|
|
34651
|
-
shippingCost:
|
|
34652
|
-
returnRate:
|
|
34653
|
-
cancellationRate:
|
|
34727
|
+
var SetProductCostingInput = z140.object({
|
|
34728
|
+
shopDomain: z140.string().min(1),
|
|
34729
|
+
shopifyProductId: z140.string().min(1).max(64),
|
|
34730
|
+
targetCountry: z140.string().length(2).describe("Pa\xEDs de venta en ISO-2, que fija moneda y referencia de flete."),
|
|
34731
|
+
supplierCost: z140.number().finite().positive().describe("Lo que le cuesta el producto al proveedor. Nunca cero."),
|
|
34732
|
+
shippingCost: z140.number().finite().nonnegative(),
|
|
34733
|
+
returnRate: z140.number().finite().min(0).lt(1).describe("Proporci\xF3n 0\u20131, no porcentaje: 0.15 es quince por ciento."),
|
|
34734
|
+
cancellationRate: z140.number().finite().min(0).lt(1)
|
|
34654
34735
|
}).strict();
|
|
34655
|
-
var Count =
|
|
34656
|
-
var ReportProductCountsInput =
|
|
34657
|
-
productControlId:
|
|
34736
|
+
var Count = z140.number().int().min(0).max(1e5).nullable().optional();
|
|
34737
|
+
var ReportProductCountsInput = z140.object({
|
|
34738
|
+
productControlId: z140.string().uuid().describe("El identificador que devuelve get_product_control."),
|
|
34658
34739
|
date: DateOnly2,
|
|
34659
34740
|
orders: Count.describe("Pedidos que entraron ese d\xEDa."),
|
|
34660
34741
|
cancelledOrders: Count,
|
|
@@ -34664,36 +34745,36 @@ var ReportProductCountsInput = z139.object({
|
|
|
34664
34745
|
}).strict();
|
|
34665
34746
|
var MAX_ORDERS_FILE_BYTES = 8 * 1024 * 1024;
|
|
34666
34747
|
var SyncShopifyOrdersInput = SyncShopifyOrdersSchema;
|
|
34667
|
-
var ImportOrdersFileInput =
|
|
34748
|
+
var ImportOrdersFileInput = z140.object({
|
|
34668
34749
|
/** Ruta ABSOLUTA en la máquina de quien usa el MCP. */
|
|
34669
|
-
path:
|
|
34670
|
-
operationId:
|
|
34750
|
+
path: z140.string().min(1),
|
|
34751
|
+
operationId: z140.string().uuid().optional(),
|
|
34671
34752
|
/** Solo mirar: devuelve el resumen y no escribe nada. */
|
|
34672
|
-
dryRun:
|
|
34753
|
+
dryRun: z140.boolean().optional()
|
|
34673
34754
|
}).strict();
|
|
34674
|
-
var CreateOperationInput =
|
|
34675
|
-
countryCode:
|
|
34676
|
-
label:
|
|
34755
|
+
var CreateOperationInput = z140.object({
|
|
34756
|
+
countryCode: z140.string().length(2),
|
|
34757
|
+
label: z140.string().trim().min(1).max(60).optional()
|
|
34677
34758
|
}).strict();
|
|
34678
|
-
var MergeProductsInput =
|
|
34679
|
-
sourceId:
|
|
34680
|
-
targetId:
|
|
34759
|
+
var MergeProductsInput = z140.object({
|
|
34760
|
+
sourceId: z140.string().uuid(),
|
|
34761
|
+
targetId: z140.string().uuid()
|
|
34681
34762
|
}).strict();
|
|
34682
|
-
var SetMonthlyExpenseInput =
|
|
34683
|
-
month:
|
|
34763
|
+
var SetMonthlyExpenseInput = z140.object({
|
|
34764
|
+
month: z140.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/).optional(),
|
|
34684
34765
|
label: SaveMonthlyExpenseSchema.shape.label,
|
|
34685
|
-
amount:
|
|
34686
|
-
operationId:
|
|
34766
|
+
amount: z140.number().finite().min(0),
|
|
34767
|
+
operationId: z140.string().uuid().optional()
|
|
34687
34768
|
}).strict();
|
|
34688
|
-
var SetAdSpendInput =
|
|
34689
|
-
month:
|
|
34690
|
-
operationId:
|
|
34769
|
+
var SetAdSpendInput = z140.object({
|
|
34770
|
+
month: z140.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/).optional(),
|
|
34771
|
+
operationId: z140.string().uuid().optional(),
|
|
34691
34772
|
/** null RETIRA la corrección; cero afirma que no pautó. */
|
|
34692
|
-
amount:
|
|
34773
|
+
amount: z140.number().finite().min(0).nullable()
|
|
34693
34774
|
}).strict();
|
|
34694
|
-
var GetFinancesInput =
|
|
34695
|
-
month:
|
|
34696
|
-
operationId:
|
|
34775
|
+
var GetFinancesInput = z140.object({
|
|
34776
|
+
month: z140.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/).optional().describe("Mes en YYYY-MM. Si se omite, el mes en curso. Solo mes calendario."),
|
|
34777
|
+
operationId: z140.string().uuid().optional().describe("El negocio, si tiene mas de uno. Con uno solo no hace falta decirlo.")
|
|
34697
34778
|
}).strict();
|
|
34698
34779
|
function registerProductControlTools(server, api, { transport = "http" } = {}) {
|
|
34699
34780
|
server.registerTool("get_product_control", {
|
|
@@ -34885,28 +34966,28 @@ function registerProductControlTools(server, api, { transport = "http" } = {}) {
|
|
|
34885
34966
|
__name(registerProductControlTools, "registerProductControlTools");
|
|
34886
34967
|
|
|
34887
34968
|
// src/tools/market-study-estimate.ts
|
|
34888
|
-
import { z as
|
|
34969
|
+
import { z as z141 } from "zod";
|
|
34889
34970
|
var estimateMarketStudyGuidance = getProductMakerCapabilityModelGuidance("estimate_market_study_cost");
|
|
34890
|
-
var ProductTaskOutputEnum =
|
|
34971
|
+
var ProductTaskOutputEnum = z141.enum([
|
|
34891
34972
|
"landing",
|
|
34892
34973
|
"video",
|
|
34893
34974
|
"image"
|
|
34894
34975
|
]);
|
|
34895
|
-
var EstimateMarketStudyInput =
|
|
34896
|
-
kind:
|
|
34976
|
+
var EstimateMarketStudyInput = z141.object({
|
|
34977
|
+
kind: z141.enum([
|
|
34897
34978
|
"video",
|
|
34898
34979
|
"product_task"
|
|
34899
34980
|
]).describe('"video" para generate_video_creative; "product_task" para create_product_task.'),
|
|
34900
|
-
videoAngleCount:
|
|
34901
|
-
durationSeconds:
|
|
34981
|
+
videoAngleCount: z141.number().int().min(1).max(3).describe("Los mismos 1, 2 o 3 videos que vas a pedir al crear."),
|
|
34982
|
+
durationSeconds: z141.number().int().min(4).max(30).default(15).describe("La misma duraci\xF3n que enviar\xE1s al crear."),
|
|
34902
34983
|
videoStructure: VideoStructureEnum.default("single_take"),
|
|
34903
34984
|
videoQuality: VideoQualityEnum.default("economy"),
|
|
34904
34985
|
videoResolution: VideoResolutionEnum.default("480p"),
|
|
34905
|
-
productImageCount:
|
|
34986
|
+
productImageCount: z141.number().int().min(1).max(5).optional().describe("Cantidad de fotos del producto que adjuntar\xE1s (1-5)."),
|
|
34906
34987
|
outputs: ProductTaskOutputEnum.array().min(1).max(3).optional().describe('Solo para kind="product_task": los mismos outputs de create_product_task. Default: todos.'),
|
|
34907
|
-
generateAiMusic:
|
|
34988
|
+
generateAiMusic: z141.boolean().optional(),
|
|
34908
34989
|
generateAiEdit: AiEditRequestSchema.optional(),
|
|
34909
|
-
replicateWinnerWhenFound:
|
|
34990
|
+
replicateWinnerWhenFound: z141.boolean().optional().describe("La misma preferencia que enviar\xE1s al crear. false excluye la reserva de r\xE9plica del ganador de la cotizaci\xF3n con estudio.")
|
|
34910
34991
|
}).strict();
|
|
34911
34992
|
function buildMarketStudyEstimateRequests(input) {
|
|
34912
34993
|
const quotesVideo = input.kind === "video" || (input.outputs ?? [
|