@productmaker/mcp 2.4.0 → 2.9.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 +35 -2
- package/dist/http.js +1386 -680
- package/dist/stdio.js +1386 -680
- package/dist/ui/meta-upload-app.html +2805 -0
- package/package.json +5 -4
package/dist/stdio.js
CHANGED
|
@@ -150,10 +150,60 @@ var ApiClient = class {
|
|
|
150
150
|
};
|
|
151
151
|
|
|
152
152
|
// src/index.ts
|
|
153
|
-
var MCP_VERSION = "2.
|
|
153
|
+
var MCP_VERSION = "2.9.1";
|
|
154
|
+
|
|
155
|
+
// src/meta-upload-app.ts
|
|
156
|
+
import { readFileSync } from "fs";
|
|
157
|
+
import { registerAppResource, RESOURCE_MIME_TYPE } from "@modelcontextprotocol/ext-apps/server";
|
|
158
|
+
var META_UPLOAD_APP_RESOURCE_URI = "ui://meta-upload/v1.html";
|
|
159
|
+
var META_UPLOAD_APP_NAME = "Meta upload app";
|
|
160
|
+
var META_UPLOAD_APP_HTML_URL = new URL("./ui/meta-upload-app.html", import.meta.url);
|
|
161
|
+
var META_UPLOAD_APP_CSP = {
|
|
162
|
+
connectDomains: [
|
|
163
|
+
"https://productmaker.app",
|
|
164
|
+
"https://www.productmaker.app",
|
|
165
|
+
"https://*.r2.cloudflarestorage.com",
|
|
166
|
+
"https://*.oaiusercontent.com"
|
|
167
|
+
]
|
|
168
|
+
};
|
|
169
|
+
function readMetaUploadAppHtml(htmlUrl = META_UPLOAD_APP_HTML_URL) {
|
|
170
|
+
try {
|
|
171
|
+
return readFileSync(htmlUrl, "utf8");
|
|
172
|
+
} catch (error) {
|
|
173
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
174
|
+
throw new Error(`Missing packaged Meta upload app HTML at ${htmlUrl.pathname}. Rebuild @productmaker/mcp so ${META_UPLOAD_APP_RESOURCE_URI} is bundled. Original error: ${message}`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
__name(readMetaUploadAppHtml, "readMetaUploadAppHtml");
|
|
178
|
+
function registerMetaUploadAppResource(server) {
|
|
179
|
+
const html = readMetaUploadAppHtml();
|
|
180
|
+
registerAppResource(server, META_UPLOAD_APP_NAME, META_UPLOAD_APP_RESOURCE_URI, {
|
|
181
|
+
title: "Meta upload app",
|
|
182
|
+
mimeType: RESOURCE_MIME_TYPE,
|
|
183
|
+
_meta: {
|
|
184
|
+
ui: {
|
|
185
|
+
csp: META_UPLOAD_APP_CSP
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}, async () => ({
|
|
189
|
+
contents: [
|
|
190
|
+
{
|
|
191
|
+
uri: META_UPLOAD_APP_RESOURCE_URI,
|
|
192
|
+
mimeType: RESOURCE_MIME_TYPE,
|
|
193
|
+
text: html,
|
|
194
|
+
_meta: {
|
|
195
|
+
ui: {
|
|
196
|
+
csp: META_UPLOAD_APP_CSP
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
]
|
|
201
|
+
}));
|
|
202
|
+
}
|
|
203
|
+
__name(registerMetaUploadAppResource, "registerMetaUploadAppResource");
|
|
154
204
|
|
|
155
205
|
// src/tools/tasks.ts
|
|
156
|
-
import { z as
|
|
206
|
+
import { z as z46 } from "zod";
|
|
157
207
|
|
|
158
208
|
// src/resolve-image.ts
|
|
159
209
|
import { lookup as dnsLookup } from "dns/promises";
|
|
@@ -2253,6 +2303,25 @@ var ShopifyPublicationStatus = z19.enum([
|
|
|
2253
2303
|
"success",
|
|
2254
2304
|
"error"
|
|
2255
2305
|
]);
|
|
2306
|
+
var ShopifyTrackingSyncStatus = z19.enum([
|
|
2307
|
+
"synced",
|
|
2308
|
+
"migrated",
|
|
2309
|
+
"not_detected"
|
|
2310
|
+
]);
|
|
2311
|
+
var ShopifyTrackingSource = z19.enum([
|
|
2312
|
+
"theme",
|
|
2313
|
+
"legacy_layout",
|
|
2314
|
+
"theme_and_legacy",
|
|
2315
|
+
"none"
|
|
2316
|
+
]);
|
|
2317
|
+
var ShopifyTrackingResult = z19.object({
|
|
2318
|
+
status: ShopifyTrackingSyncStatus,
|
|
2319
|
+
manualCodeDetected: z19.boolean(),
|
|
2320
|
+
/** True when code from a prior ProductMaker layout was preserved automatically. */
|
|
2321
|
+
legacyCodeMigrated: z19.boolean().default(false),
|
|
2322
|
+
source: ShopifyTrackingSource.default("none"),
|
|
2323
|
+
syncedAt: z19.string().datetime()
|
|
2324
|
+
});
|
|
2256
2325
|
var ShopifyPublishResponse = z19.object({
|
|
2257
2326
|
publicationId: z19.string().uuid(),
|
|
2258
2327
|
taskId: z19.string().uuid(),
|
|
@@ -2268,6 +2337,8 @@ var ShopifyPublishResponse = z19.object({
|
|
|
2268
2337
|
needsThemeSetup: z19.boolean().optional(),
|
|
2269
2338
|
/** One-click theme-editor deep link to add the Code Landing block (when needsThemeSetup). */
|
|
2270
2339
|
themeEditorDeepLink: z19.string().url().optional(),
|
|
2340
|
+
/** Tracking copied from the theme or migrated from a previous ProductMaker layout. */
|
|
2341
|
+
tracking: ShopifyTrackingResult.optional(),
|
|
2271
2342
|
createdAt: z19.string().datetime().optional(),
|
|
2272
2343
|
updatedAt: z19.string().datetime().optional()
|
|
2273
2344
|
});
|
|
@@ -3166,7 +3237,9 @@ var ImageCreativeEstimationOptions = z24.object({
|
|
|
3166
3237
|
});
|
|
3167
3238
|
var RegenerateLandingRoleBody = z24.object({
|
|
3168
3239
|
comment: z24.string().max(500).optional(),
|
|
3169
|
-
sourceKey: z24.string().max(200).optional()
|
|
3240
|
+
sourceKey: z24.string().max(200).optional(),
|
|
3241
|
+
/** Client-generated key lets a lost response be retried without another charge. */
|
|
3242
|
+
clientRequestId: z24.string().uuid().optional()
|
|
3170
3243
|
}).strict();
|
|
3171
3244
|
var LandingRegenerateEstimationOptions = z24.object({
|
|
3172
3245
|
/** KIE image endpoint has non-linear pricing by nVariants; for landing we default to 2. */
|
|
@@ -3717,6 +3790,25 @@ var ALLOWED_MEDIA_CONTENT_TYPES = [
|
|
|
3717
3790
|
"audio/wav",
|
|
3718
3791
|
"audio/x-wav"
|
|
3719
3792
|
];
|
|
3793
|
+
var META_STAGING_IMAGE_CONTENT_TYPES = /* @__PURE__ */ new Set([
|
|
3794
|
+
"image/jpeg",
|
|
3795
|
+
"image/png",
|
|
3796
|
+
"image/webp"
|
|
3797
|
+
]);
|
|
3798
|
+
var META_STAGING_MEDIA_CONTENT_TYPES = /* @__PURE__ */ new Set([
|
|
3799
|
+
...META_STAGING_IMAGE_CONTENT_TYPES,
|
|
3800
|
+
"video/mp4",
|
|
3801
|
+
"video/quicktime",
|
|
3802
|
+
"video/webm"
|
|
3803
|
+
]);
|
|
3804
|
+
var META_STAGING_CONTENT_TYPES = [
|
|
3805
|
+
"image/jpeg",
|
|
3806
|
+
"image/png",
|
|
3807
|
+
"image/webp",
|
|
3808
|
+
"video/mp4",
|
|
3809
|
+
"video/quicktime",
|
|
3810
|
+
"video/webm"
|
|
3811
|
+
];
|
|
3720
3812
|
var PresignUploadRequest = z31.object({
|
|
3721
3813
|
/** MIME type of the file to upload */
|
|
3722
3814
|
contentType: z31.enum(ALLOWED_MEDIA_CONTENT_TYPES),
|
|
@@ -3732,8 +3824,51 @@ var PresignUploadRequest = z31.object({
|
|
|
3732
3824
|
purpose: z31.enum([
|
|
3733
3825
|
"ads",
|
|
3734
3826
|
"service",
|
|
3735
|
-
"actor"
|
|
3827
|
+
"actor",
|
|
3828
|
+
"meta_staging"
|
|
3829
|
+
]).optional(),
|
|
3830
|
+
/** Required for purpose=meta_staging so media and thumbnails can be checked independently. */
|
|
3831
|
+
assetRole: z31.enum([
|
|
3832
|
+
"media",
|
|
3833
|
+
"thumbnail"
|
|
3736
3834
|
]).optional()
|
|
3835
|
+
}).superRefine((value, ctx) => {
|
|
3836
|
+
if (value.purpose === "meta_staging") {
|
|
3837
|
+
if (!value.assetRole) {
|
|
3838
|
+
ctx.addIssue({
|
|
3839
|
+
code: z31.ZodIssueCode.custom,
|
|
3840
|
+
path: [
|
|
3841
|
+
"assetRole"
|
|
3842
|
+
],
|
|
3843
|
+
message: "assetRole is required for Meta staging uploads"
|
|
3844
|
+
});
|
|
3845
|
+
} else if (!META_STAGING_MEDIA_CONTENT_TYPES.has(value.contentType)) {
|
|
3846
|
+
ctx.addIssue({
|
|
3847
|
+
code: z31.ZodIssueCode.custom,
|
|
3848
|
+
path: [
|
|
3849
|
+
"contentType"
|
|
3850
|
+
],
|
|
3851
|
+
message: "Meta staging accepts only image or video media"
|
|
3852
|
+
});
|
|
3853
|
+
} else if (value.assetRole === "thumbnail" && !META_STAGING_IMAGE_CONTENT_TYPES.has(value.contentType)) {
|
|
3854
|
+
ctx.addIssue({
|
|
3855
|
+
code: z31.ZodIssueCode.custom,
|
|
3856
|
+
path: [
|
|
3857
|
+
"contentType"
|
|
3858
|
+
],
|
|
3859
|
+
message: "Meta staging thumbnails must be images"
|
|
3860
|
+
});
|
|
3861
|
+
}
|
|
3862
|
+
}
|
|
3863
|
+
if (value.purpose !== "meta_staging" && value.assetRole) {
|
|
3864
|
+
ctx.addIssue({
|
|
3865
|
+
code: z31.ZodIssueCode.custom,
|
|
3866
|
+
path: [
|
|
3867
|
+
"assetRole"
|
|
3868
|
+
],
|
|
3869
|
+
message: "assetRole is only valid for Meta staging uploads"
|
|
3870
|
+
});
|
|
3871
|
+
}
|
|
3737
3872
|
});
|
|
3738
3873
|
var PresignUploadResponse = z31.object({
|
|
3739
3874
|
/** Presigned S3 PUT URL — browser sends file directly here */
|
|
@@ -3743,8 +3878,23 @@ var PresignUploadResponse = z31.object({
|
|
|
3743
3878
|
/** S3 key */
|
|
3744
3879
|
key: z31.string(),
|
|
3745
3880
|
/** Present only for purpose=service. */
|
|
3746
|
-
assetToken: z31.string().min(1).optional()
|
|
3881
|
+
assetToken: z31.string().min(1).optional(),
|
|
3882
|
+
/** Present only for purpose=meta_staging. */
|
|
3883
|
+
stagingAssetId: z31.string().uuid().optional()
|
|
3747
3884
|
});
|
|
3885
|
+
var MetaUploadMediaKind = z31.enum([
|
|
3886
|
+
"image",
|
|
3887
|
+
"video",
|
|
3888
|
+
"mixed"
|
|
3889
|
+
]);
|
|
3890
|
+
var META_UPLOAD_MAX_FILES = CAMPAIGN_LIMITS.MAX_CREATIVES;
|
|
3891
|
+
var MetaUploadAssetSummary = z31.object({
|
|
3892
|
+
stagingAssetId: z31.string().uuid(),
|
|
3893
|
+
mediaKind: z31.enum([
|
|
3894
|
+
"image",
|
|
3895
|
+
"video"
|
|
3896
|
+
])
|
|
3897
|
+
}).strict();
|
|
3748
3898
|
var MetaCampaignType = z31.enum([
|
|
3749
3899
|
"sales",
|
|
3750
3900
|
"traffic",
|
|
@@ -3770,6 +3920,81 @@ var HttpUrl = z31.string().url().refine((value) => {
|
|
|
3770
3920
|
return false;
|
|
3771
3921
|
}
|
|
3772
3922
|
}, "URL must use http or https");
|
|
3923
|
+
var MetaUploadSessionRequest = z31.object({
|
|
3924
|
+
/** The browser page will require a file of this media kind. */
|
|
3925
|
+
mediaKind: MetaUploadMediaKind,
|
|
3926
|
+
/** The staged object role; media is the normal creative input. */
|
|
3927
|
+
assetRole: z31.enum([
|
|
3928
|
+
"media",
|
|
3929
|
+
"thumbnail"
|
|
3930
|
+
]).default("media"),
|
|
3931
|
+
/** Maximum number of files; the API chooses 10 for mixed and 1 otherwise when omitted. */
|
|
3932
|
+
maxFiles: z31.number().int().min(1).max(META_UPLOAD_MAX_FILES).optional()
|
|
3933
|
+
}).strict().superRefine((value, ctx) => {
|
|
3934
|
+
if (value.mediaKind === "mixed" && value.assetRole === "thumbnail") {
|
|
3935
|
+
ctx.addIssue({
|
|
3936
|
+
code: z31.ZodIssueCode.custom,
|
|
3937
|
+
path: [
|
|
3938
|
+
"mediaKind"
|
|
3939
|
+
],
|
|
3940
|
+
message: "Mixed Meta upload sessions cannot be thumbnails"
|
|
3941
|
+
});
|
|
3942
|
+
}
|
|
3943
|
+
if (value.mediaKind !== "mixed" && value.maxFiles !== void 0 && value.maxFiles !== 1) {
|
|
3944
|
+
ctx.addIssue({
|
|
3945
|
+
code: z31.ZodIssueCode.custom,
|
|
3946
|
+
path: [
|
|
3947
|
+
"maxFiles"
|
|
3948
|
+
],
|
|
3949
|
+
message: "Non-mixed Meta upload sessions accept exactly one file"
|
|
3950
|
+
});
|
|
3951
|
+
}
|
|
3952
|
+
if (value.assetRole === "thumbnail" && value.mediaKind !== "image") {
|
|
3953
|
+
ctx.addIssue({
|
|
3954
|
+
code: z31.ZodIssueCode.custom,
|
|
3955
|
+
path: [
|
|
3956
|
+
"mediaKind"
|
|
3957
|
+
],
|
|
3958
|
+
message: "Meta thumbnails must be images"
|
|
3959
|
+
});
|
|
3960
|
+
}
|
|
3961
|
+
});
|
|
3962
|
+
var ResolveMetaUploadSessionRequest = z31.object({
|
|
3963
|
+
/** Opaque signed token embedded in the one-click upload page URL. */
|
|
3964
|
+
token: z31.string().min(1).max(4096),
|
|
3965
|
+
/** Stable browser-generated id so failed PUT retries reuse the same slot. */
|
|
3966
|
+
uploadId: z31.string().uuid().optional(),
|
|
3967
|
+
/** Browser-selected metadata; the API checks it against the session kind/role. */
|
|
3968
|
+
contentType: z31.enum(META_STAGING_CONTENT_TYPES),
|
|
3969
|
+
fileName: z31.string().min(1).max(255),
|
|
3970
|
+
fileSize: z31.number().int().positive().max(CAMPAIGN_LIMITS.MAX_FILE_SIZE_BYTES)
|
|
3971
|
+
}).strict();
|
|
3972
|
+
var MetaUploadSessionResponse = z31.object({
|
|
3973
|
+
sessionId: z31.string().uuid(),
|
|
3974
|
+
uploadPageUrl: HttpUrl,
|
|
3975
|
+
mediaKind: MetaUploadMediaKind,
|
|
3976
|
+
assetRole: z31.enum([
|
|
3977
|
+
"media",
|
|
3978
|
+
"thumbnail"
|
|
3979
|
+
]),
|
|
3980
|
+
maxFiles: z31.number().int().min(1).max(META_UPLOAD_MAX_FILES),
|
|
3981
|
+
expiresAt: z31.string().datetime()
|
|
3982
|
+
}).strict();
|
|
3983
|
+
var ResolveMetaUploadSessionResponse = z31.object({
|
|
3984
|
+
uploadUrl: z31.string().url(),
|
|
3985
|
+
stagingAssetId: z31.string().uuid(),
|
|
3986
|
+
expiresAt: z31.string().datetime()
|
|
3987
|
+
}).strict();
|
|
3988
|
+
var MetaUploadSessionStatusResponse = z31.object({
|
|
3989
|
+
sessionId: z31.string().uuid(),
|
|
3990
|
+
status: z31.enum([
|
|
3991
|
+
"pending",
|
|
3992
|
+
"uploaded"
|
|
3993
|
+
]),
|
|
3994
|
+
assets: z31.array(MetaUploadAssetSummary).max(META_UPLOAD_MAX_FILES),
|
|
3995
|
+
/** Legacy single-file response field retained for older callers. */
|
|
3996
|
+
stagingAssetId: z31.string().uuid().optional()
|
|
3997
|
+
}).strict();
|
|
3773
3998
|
var MetaAdAccountId = z31.string().trim().min(1, "Debes seleccionar una cuenta publicitaria").transform((value) => /^\d+$/.test(value) ? `act_${value}` : value).refine((value) => /^act_\d+$/.test(value), {
|
|
3774
3999
|
message: 'adAccountId must look like "act_1234567890" (a bare numeric id is also accepted)'
|
|
3775
4000
|
});
|
|
@@ -3856,18 +4081,26 @@ var UploadToMetaRequest = z31.object({
|
|
|
3856
4081
|
title: z31.string().max(CAMPAIGN_LIMITS.MAX_TITLE_LENGTH),
|
|
3857
4082
|
description: z31.string().max(CAMPAIGN_LIMITS.MAX_DESCRIPTION_LENGTH),
|
|
3858
4083
|
cta: MetaCtaType,
|
|
3859
|
-
/**
|
|
3860
|
-
mediaUrl: HttpUrl,
|
|
4084
|
+
/** Legacy public URL; new Meta flows should use mediaAssetId. */
|
|
4085
|
+
mediaUrl: HttpUrl.optional(),
|
|
4086
|
+
/** Owner-scoped temporary asset created by the Meta staging upload flow. */
|
|
4087
|
+
mediaAssetId: z31.string().uuid().optional(),
|
|
3861
4088
|
/**
|
|
3862
4089
|
* Public URL of an extracted thumbnail. Required for video ads — Meta
|
|
3863
4090
|
* rejects video ad creatives without `image_hash`/`image_url` in
|
|
3864
4091
|
* `video_data` (subcode 1443226). Frontend extracts a frame from the
|
|
3865
4092
|
* video and uploads it before submitting the request.
|
|
3866
4093
|
*/
|
|
3867
|
-
thumbnailUrl: HttpUrl.optional()
|
|
4094
|
+
thumbnailUrl: HttpUrl.optional(),
|
|
4095
|
+
/** Owner-scoped temporary thumbnail created by the Meta staging upload flow. */
|
|
4096
|
+
thumbnailAssetId: z31.string().uuid().optional()
|
|
3868
4097
|
})).min(1).max(CAMPAIGN_LIMITS.MAX_CREATIVES),
|
|
3869
4098
|
/** Meta Ad Account ID */
|
|
3870
4099
|
adAccountId: MetaAdAccountId,
|
|
4100
|
+
/** Meta Business Portfolio selected by the user (optional for legacy callers). */
|
|
4101
|
+
portfolioId: z31.string().min(1).optional(),
|
|
4102
|
+
/** Facebook Page selected by the user (optional for legacy callers). */
|
|
4103
|
+
pageId: z31.string().min(1).optional(),
|
|
3871
4104
|
/** Optional Meta Pixel ID */
|
|
3872
4105
|
pixelId: z31.string().optional(),
|
|
3873
4106
|
/** Landing page URL (required for landing destinations; omitted for whatsapp) */
|
|
@@ -3887,6 +4120,30 @@ var UploadToMetaRequest = z31.object({
|
|
|
3887
4120
|
message: "landingUrl is required for landing destinations"
|
|
3888
4121
|
});
|
|
3889
4122
|
}
|
|
4123
|
+
value.creatives.forEach((creative, index) => {
|
|
4124
|
+
if (Boolean(creative.mediaUrl) === Boolean(creative.mediaAssetId)) {
|
|
4125
|
+
ctx.addIssue({
|
|
4126
|
+
code: z31.ZodIssueCode.custom,
|
|
4127
|
+
path: [
|
|
4128
|
+
"creatives",
|
|
4129
|
+
index,
|
|
4130
|
+
"mediaUrl"
|
|
4131
|
+
],
|
|
4132
|
+
message: "Provide exactly one of mediaUrl or mediaAssetId"
|
|
4133
|
+
});
|
|
4134
|
+
}
|
|
4135
|
+
if (creative.thumbnailUrl && creative.thumbnailAssetId) {
|
|
4136
|
+
ctx.addIssue({
|
|
4137
|
+
code: z31.ZodIssueCode.custom,
|
|
4138
|
+
path: [
|
|
4139
|
+
"creatives",
|
|
4140
|
+
index,
|
|
4141
|
+
"thumbnailUrl"
|
|
4142
|
+
],
|
|
4143
|
+
message: "Provide at most one of thumbnailUrl or thumbnailAssetId"
|
|
4144
|
+
});
|
|
4145
|
+
}
|
|
4146
|
+
});
|
|
3890
4147
|
});
|
|
3891
4148
|
var CampaignLifetimeMetricsSchema = z31.object({
|
|
3892
4149
|
spend: z31.number().nonnegative(),
|
|
@@ -3940,8 +4197,32 @@ var FacebookAdAccountSchema = z32.object({
|
|
|
3940
4197
|
source: z32.enum([
|
|
3941
4198
|
"business",
|
|
3942
4199
|
"personal"
|
|
4200
|
+
]),
|
|
4201
|
+
/** Meta Business Portfolio (or the synthetic `personal` group). */
|
|
4202
|
+
portfolioId: z32.string().min(1),
|
|
4203
|
+
portfolioName: z32.string().min(1),
|
|
4204
|
+
portfolioType: z32.enum([
|
|
4205
|
+
"business",
|
|
4206
|
+
"personal"
|
|
3943
4207
|
])
|
|
3944
4208
|
});
|
|
4209
|
+
var FacebookMetaPortfolioSchema = z32.object({
|
|
4210
|
+
id: z32.string().min(1),
|
|
4211
|
+
name: z32.string().min(1),
|
|
4212
|
+
type: z32.enum([
|
|
4213
|
+
"business",
|
|
4214
|
+
"personal"
|
|
4215
|
+
])
|
|
4216
|
+
});
|
|
4217
|
+
var FacebookMetaPageSchema = z32.object({
|
|
4218
|
+
id: z32.string().min(1),
|
|
4219
|
+
name: z32.string().min(1)
|
|
4220
|
+
});
|
|
4221
|
+
var FacebookMetaDestinationsResponseSchema = z32.object({
|
|
4222
|
+
portfolios: z32.array(FacebookMetaPortfolioSchema),
|
|
4223
|
+
adAccounts: z32.array(FacebookAdAccountSchema),
|
|
4224
|
+
pages: z32.array(FacebookMetaPageSchema)
|
|
4225
|
+
});
|
|
3945
4226
|
var MetaCampaignOverridesSchema = z32.object({
|
|
3946
4227
|
dailyBudgetUsd: z32.number().positive().optional(),
|
|
3947
4228
|
targetCountries: z32.array(z32.string().length(2)).max(1).optional(),
|
|
@@ -3950,6 +4231,8 @@ var MetaCampaignOverridesSchema = z32.object({
|
|
|
3950
4231
|
});
|
|
3951
4232
|
var FacebookCreateCampaignBodySchema = z32.object({
|
|
3952
4233
|
adAccountId: MetaAdAccountId,
|
|
4234
|
+
portfolioId: z32.string().min(1).optional(),
|
|
4235
|
+
pageId: z32.string().min(1).optional(),
|
|
3953
4236
|
pixelId: z32.string().optional(),
|
|
3954
4237
|
landingUrl: HttpUrl2.optional(),
|
|
3955
4238
|
campaignConfig: MetaCampaignConfig.optional(),
|
|
@@ -3980,6 +4263,8 @@ var FacebookCampaignStatusResponseSchema = z32.object({
|
|
|
3980
4263
|
var FacebookCreateCampaignResponseSchema = z32.object({
|
|
3981
4264
|
campaignId: z32.string(),
|
|
3982
4265
|
campaignName: z32.string(),
|
|
4266
|
+
portfolioId: z32.string().optional(),
|
|
4267
|
+
portfolioName: z32.string().optional(),
|
|
3983
4268
|
pageId: z32.string().optional(),
|
|
3984
4269
|
pageName: z32.string().optional(),
|
|
3985
4270
|
// Backward-compatible single ad fields (optional)
|
|
@@ -4022,11 +4307,15 @@ var FacebookCreateCampaignFromCreativesBodySchema = z32.object({
|
|
|
4022
4307
|
title: z32.string().max(120),
|
|
4023
4308
|
description: z32.string().max(500),
|
|
4024
4309
|
cta: MetaCtaType,
|
|
4025
|
-
mediaUrl: HttpUrl2,
|
|
4310
|
+
mediaUrl: HttpUrl2.optional(),
|
|
4311
|
+
mediaAssetId: z32.string().uuid().optional(),
|
|
4026
4312
|
thumbnailUrl: HttpUrl2.optional(),
|
|
4313
|
+
thumbnailAssetId: z32.string().uuid().optional(),
|
|
4027
4314
|
creativeId: z32.string().min(1).optional()
|
|
4028
4315
|
})).min(1).max(CAMPAIGN_LIMITS.MAX_CREATIVES),
|
|
4029
4316
|
adAccountId: MetaAdAccountId,
|
|
4317
|
+
portfolioId: z32.string().min(1).optional(),
|
|
4318
|
+
pageId: z32.string().min(1).optional(),
|
|
4030
4319
|
pixelId: z32.string().optional(),
|
|
4031
4320
|
/** Required unless campaignConfig.destination is 'whatsapp' (see superRefine below). */
|
|
4032
4321
|
landingUrl: HttpUrl2.optional(),
|
|
@@ -4046,6 +4335,30 @@ var FacebookCreateCampaignFromCreativesBodySchema = z32.object({
|
|
|
4046
4335
|
message: "landingUrl is required unless destination is whatsapp"
|
|
4047
4336
|
});
|
|
4048
4337
|
}
|
|
4338
|
+
value.creatives.forEach((creative, index) => {
|
|
4339
|
+
if (Boolean(creative.mediaUrl) === Boolean(creative.mediaAssetId)) {
|
|
4340
|
+
ctx.addIssue({
|
|
4341
|
+
code: z32.ZodIssueCode.custom,
|
|
4342
|
+
path: [
|
|
4343
|
+
"creatives",
|
|
4344
|
+
index,
|
|
4345
|
+
"mediaUrl"
|
|
4346
|
+
],
|
|
4347
|
+
message: "Provide exactly one of mediaUrl or mediaAssetId"
|
|
4348
|
+
});
|
|
4349
|
+
}
|
|
4350
|
+
if (creative.thumbnailUrl && creative.thumbnailAssetId) {
|
|
4351
|
+
ctx.addIssue({
|
|
4352
|
+
code: z32.ZodIssueCode.custom,
|
|
4353
|
+
path: [
|
|
4354
|
+
"creatives",
|
|
4355
|
+
index,
|
|
4356
|
+
"thumbnailUrl"
|
|
4357
|
+
],
|
|
4358
|
+
message: "Provide at most one of thumbnailUrl or thumbnailAssetId"
|
|
4359
|
+
});
|
|
4360
|
+
}
|
|
4361
|
+
});
|
|
4049
4362
|
if (value.campaignConfig?.destination?.type === "landing" && value.landingUrl && value.campaignConfig.destination.landingUrl !== value.landingUrl) {
|
|
4050
4363
|
ctx.addIssue({
|
|
4051
4364
|
code: z32.ZodIssueCode.custom,
|
|
@@ -4123,8 +4436,10 @@ var FacebookTaskCreativeSourceSchema = z32.object({
|
|
|
4123
4436
|
});
|
|
4124
4437
|
var FacebookMediaCreativeSourceSchema = z32.object({
|
|
4125
4438
|
type: z32.literal("media"),
|
|
4126
|
-
mediaUrl: HttpUrl2,
|
|
4127
|
-
|
|
4439
|
+
mediaUrl: HttpUrl2.optional(),
|
|
4440
|
+
mediaAssetId: z32.string().uuid().optional(),
|
|
4441
|
+
thumbnailUrl: HttpUrl2.optional(),
|
|
4442
|
+
thumbnailAssetId: z32.string().uuid().optional()
|
|
4128
4443
|
});
|
|
4129
4444
|
var FacebookCreativeSourceSchema = z32.discriminatedUnion("type", [
|
|
4130
4445
|
FacebookTaskCreativeSourceSchema,
|
|
@@ -4143,6 +4458,9 @@ var FacebookCreateCampaignFromTasksBodySchema = z32.object({
|
|
|
4143
4458
|
creativeId: z32.string().min(1).optional()
|
|
4144
4459
|
})).min(1).max(CAMPAIGN_LIMITS.MAX_CREATIVES),
|
|
4145
4460
|
adAccountId: MetaAdAccountId,
|
|
4461
|
+
/** Explicit destination is required for MCP/remote creative publishing. */
|
|
4462
|
+
portfolioId: z32.string().min(1),
|
|
4463
|
+
pageId: z32.string().min(1),
|
|
4146
4464
|
pixelId: z32.string().optional(),
|
|
4147
4465
|
landingUrl: HttpUrl2.optional(),
|
|
4148
4466
|
targetCountry: z32.string().length(2).default("US"),
|
|
@@ -4159,6 +4477,33 @@ var FacebookCreateCampaignFromTasksBodySchema = z32.object({
|
|
|
4159
4477
|
message: "landingUrl is required unless destination is whatsapp"
|
|
4160
4478
|
});
|
|
4161
4479
|
}
|
|
4480
|
+
value.creatives.forEach((creative, index) => {
|
|
4481
|
+
if (creative.source.type !== "media") return;
|
|
4482
|
+
if (Boolean(creative.source.mediaUrl) === Boolean(creative.source.mediaAssetId)) {
|
|
4483
|
+
ctx.addIssue({
|
|
4484
|
+
code: z32.ZodIssueCode.custom,
|
|
4485
|
+
path: [
|
|
4486
|
+
"creatives",
|
|
4487
|
+
index,
|
|
4488
|
+
"source",
|
|
4489
|
+
"mediaUrl"
|
|
4490
|
+
],
|
|
4491
|
+
message: "Provide exactly one of mediaUrl or mediaAssetId"
|
|
4492
|
+
});
|
|
4493
|
+
}
|
|
4494
|
+
if (creative.source.thumbnailUrl && creative.source.thumbnailAssetId) {
|
|
4495
|
+
ctx.addIssue({
|
|
4496
|
+
code: z32.ZodIssueCode.custom,
|
|
4497
|
+
path: [
|
|
4498
|
+
"creatives",
|
|
4499
|
+
index,
|
|
4500
|
+
"source",
|
|
4501
|
+
"thumbnailUrl"
|
|
4502
|
+
],
|
|
4503
|
+
message: "Provide at most one of thumbnailUrl or thumbnailAssetId"
|
|
4504
|
+
});
|
|
4505
|
+
}
|
|
4506
|
+
});
|
|
4162
4507
|
});
|
|
4163
4508
|
|
|
4164
4509
|
// ../../packages/types/src/tiktok.ts
|
|
@@ -5840,8 +6185,7 @@ var DEFAULT_PRICING = {
|
|
|
5840
6185
|
userPriceCents: 0.04
|
|
5841
6186
|
}
|
|
5842
6187
|
};
|
|
5843
|
-
var
|
|
5844
|
-
var REGEN_SINGLE_CALL_OUR_COST_CENTS = DEFAULT_PRICING["kie:video-generation:grok-15s-480p"].ourCostCents;
|
|
6188
|
+
var REGEN_SINGLE_CALL_OUR_COST_CENTS = DEFAULT_PRICING["kie:video-generation:grok-15s-720p"].ourCostCents;
|
|
5845
6189
|
var SC_FRAME_COMPOSE_OUR_COST_CENTS = DEFAULT_PRICING["kie:image-generation:gpt-image-2:medium"].ourCostCents;
|
|
5846
6190
|
var SC_FRAME_COMPOSE_USER_PRICE_CENTS = DEFAULT_PRICING["kie:image-generation:gpt-image-2:medium"].userPriceCents;
|
|
5847
6191
|
var MS_FRAME_COMPOSE_OUR_COST_CENTS = DEFAULT_PRICING["kie:image-generation:nano-banana-2"].ourCostCents;
|
|
@@ -7118,10 +7462,35 @@ var ListLandingEditsResponse = z37.object({
|
|
|
7118
7462
|
edits: z37.array(LandingEditDto)
|
|
7119
7463
|
});
|
|
7120
7464
|
|
|
7121
|
-
// ../../packages/types/src/
|
|
7465
|
+
// ../../packages/types/src/landing-regeneration.ts
|
|
7122
7466
|
import { z as z38 } from "zod";
|
|
7467
|
+
var LandingRegenerationStatus = z38.enum([
|
|
7468
|
+
"queued",
|
|
7469
|
+
"processing",
|
|
7470
|
+
"published",
|
|
7471
|
+
"failed"
|
|
7472
|
+
]);
|
|
7473
|
+
var RegenerateLandingRoleResponse = z38.object({
|
|
7474
|
+
ok: z38.literal(true),
|
|
7475
|
+
role: LandingRole,
|
|
7476
|
+
promptIndex: z38.number().int().nonnegative(),
|
|
7477
|
+
operationId: z38.string().min(1)
|
|
7478
|
+
});
|
|
7479
|
+
var LandingRegenerationStatusResponse = z38.object({
|
|
7480
|
+
ok: z38.literal(true),
|
|
7481
|
+
operationId: z38.string().min(1),
|
|
7482
|
+
role: LandingRole,
|
|
7483
|
+
status: LandingRegenerationStatus,
|
|
7484
|
+
refunded: z38.boolean(),
|
|
7485
|
+
failureReason: z38.string().nullable(),
|
|
7486
|
+
publishedAssetKey: z38.string().nullable(),
|
|
7487
|
+
updatedAt: z38.string().datetime()
|
|
7488
|
+
});
|
|
7489
|
+
|
|
7490
|
+
// ../../packages/types/src/video-edit.ts
|
|
7491
|
+
import { z as z39 } from "zod";
|
|
7123
7492
|
var MAX_SEGMENT_SECONDS = 3;
|
|
7124
|
-
var VideoEditStatusSchema =
|
|
7493
|
+
var VideoEditStatusSchema = z39.enum([
|
|
7125
7494
|
"pending",
|
|
7126
7495
|
"processing",
|
|
7127
7496
|
"assembling",
|
|
@@ -7130,9 +7499,9 @@ var VideoEditStatusSchema = z38.enum([
|
|
|
7130
7499
|
"discarded",
|
|
7131
7500
|
"failed"
|
|
7132
7501
|
]);
|
|
7133
|
-
var VideoEditTimeSectionSchema =
|
|
7134
|
-
startSec:
|
|
7135
|
-
endSec:
|
|
7502
|
+
var VideoEditTimeSectionSchema = z39.object({
|
|
7503
|
+
startSec: z39.number().min(0),
|
|
7504
|
+
endSec: z39.number().positive()
|
|
7136
7505
|
}).refine((v) => v.endSec > v.startSec, {
|
|
7137
7506
|
message: "endSec must be after startSec",
|
|
7138
7507
|
path: [
|
|
@@ -7144,35 +7513,35 @@ var VideoEditTimeSectionSchema = z38.object({
|
|
|
7144
7513
|
"endSec"
|
|
7145
7514
|
]
|
|
7146
7515
|
});
|
|
7147
|
-
var VideoEditRequestSchema =
|
|
7148
|
-
comment:
|
|
7149
|
-
sections:
|
|
7516
|
+
var VideoEditRequestSchema = z39.object({
|
|
7517
|
+
comment: z39.string().trim().min(1).max(2e3),
|
|
7518
|
+
sections: z39.array(VideoEditTimeSectionSchema).min(1).optional()
|
|
7150
7519
|
});
|
|
7151
|
-
var VideoEditModeSchema =
|
|
7520
|
+
var VideoEditModeSchema = z39.enum([
|
|
7152
7521
|
"wan_edit",
|
|
7153
7522
|
"regenerate"
|
|
7154
7523
|
]);
|
|
7155
|
-
var VideoRegenerationEngineSchema =
|
|
7524
|
+
var VideoRegenerationEngineSchema = z39.enum([
|
|
7156
7525
|
"free_text",
|
|
7157
7526
|
"free_image",
|
|
7158
7527
|
"single_call",
|
|
7159
7528
|
"multi_shot"
|
|
7160
7529
|
]);
|
|
7161
|
-
var VideoRegenerationRouteFingerprintSchema =
|
|
7162
|
-
var RegenerateEditRequestSchema =
|
|
7163
|
-
angleKey:
|
|
7164
|
-
comment:
|
|
7530
|
+
var VideoRegenerationRouteFingerprintSchema = z39.string().trim().min(1).max(128);
|
|
7531
|
+
var RegenerateEditRequestSchema = z39.object({
|
|
7532
|
+
angleKey: z39.string().min(1),
|
|
7533
|
+
comment: z39.string().min(1).max(2e3)
|
|
7165
7534
|
});
|
|
7166
7535
|
|
|
7167
7536
|
// ../../packages/types/src/dropshipping-project.ts
|
|
7168
|
-
import { z as
|
|
7169
|
-
var DropshippingProjectStatusSchema =
|
|
7537
|
+
import { z as z40 } from "zod";
|
|
7538
|
+
var DropshippingProjectStatusSchema = z40.enum([
|
|
7170
7539
|
"active",
|
|
7171
7540
|
"completed",
|
|
7172
7541
|
"archived"
|
|
7173
7542
|
]);
|
|
7174
7543
|
var DROPSHIPPING_LAUNCH_REWARD_CAMPAIGN = "dropshipping-launch-v1";
|
|
7175
|
-
var DropshippingRewardMilestoneSchema =
|
|
7544
|
+
var DropshippingRewardMilestoneSchema = z40.enum([
|
|
7176
7545
|
"product_selected",
|
|
7177
7546
|
"costing_saved",
|
|
7178
7547
|
"product_media_ready",
|
|
@@ -7187,21 +7556,21 @@ var DROPSHIPPING_LAUNCH_REWARD_CREDITS = {
|
|
|
7187
7556
|
campaign_created: 200
|
|
7188
7557
|
};
|
|
7189
7558
|
var DROPSHIPPING_LAUNCH_REWARD_TOTAL_CREDITS = Object.values(DROPSHIPPING_LAUNCH_REWARD_CREDITS).reduce((sum, credits) => sum + credits, 0);
|
|
7190
|
-
var DropshippingProjectRewardMilestoneStateSchema =
|
|
7559
|
+
var DropshippingProjectRewardMilestoneStateSchema = z40.object({
|
|
7191
7560
|
milestone: DropshippingRewardMilestoneSchema,
|
|
7192
|
-
credits:
|
|
7193
|
-
available:
|
|
7194
|
-
earned:
|
|
7195
|
-
grantId:
|
|
7196
|
-
grantedAt:
|
|
7197
|
-
});
|
|
7198
|
-
var DropshippingProjectRewardProgressSchema =
|
|
7199
|
-
campaignKey:
|
|
7200
|
-
totalCredits:
|
|
7201
|
-
earnedCredits:
|
|
7202
|
-
milestones:
|
|
7203
|
-
});
|
|
7204
|
-
var DropshippingProjectPhaseSchema =
|
|
7561
|
+
credits: z40.number().int().positive(),
|
|
7562
|
+
available: z40.boolean().optional(),
|
|
7563
|
+
earned: z40.boolean(),
|
|
7564
|
+
grantId: z40.string().uuid().nullable(),
|
|
7565
|
+
grantedAt: z40.string().datetime().nullable()
|
|
7566
|
+
});
|
|
7567
|
+
var DropshippingProjectRewardProgressSchema = z40.object({
|
|
7568
|
+
campaignKey: z40.literal(DROPSHIPPING_LAUNCH_REWARD_CAMPAIGN),
|
|
7569
|
+
totalCredits: z40.number().int().positive(),
|
|
7570
|
+
earnedCredits: z40.number().int().nonnegative(),
|
|
7571
|
+
milestones: z40.array(DropshippingProjectRewardMilestoneStateSchema).length(DropshippingRewardMilestoneSchema.options.length)
|
|
7572
|
+
});
|
|
7573
|
+
var DropshippingProjectPhaseSchema = z40.enum([
|
|
7205
7574
|
"research",
|
|
7206
7575
|
"costing",
|
|
7207
7576
|
"media",
|
|
@@ -7210,18 +7579,18 @@ var DropshippingProjectPhaseSchema = z39.enum([
|
|
|
7210
7579
|
"advertising",
|
|
7211
7580
|
"complete"
|
|
7212
7581
|
]);
|
|
7213
|
-
var DropshippingProjectCostingInputSchema =
|
|
7214
|
-
country:
|
|
7215
|
-
supplierCost:
|
|
7216
|
-
shippingCost:
|
|
7217
|
-
returnRate:
|
|
7218
|
-
cancellationRate:
|
|
7219
|
-
adsManagerCpa:
|
|
7220
|
-
desiredMargin:
|
|
7582
|
+
var DropshippingProjectCostingInputSchema = z40.object({
|
|
7583
|
+
country: z40.string().min(2).max(3),
|
|
7584
|
+
supplierCost: z40.number().finite().positive(),
|
|
7585
|
+
shippingCost: z40.number().finite().nonnegative(),
|
|
7586
|
+
returnRate: z40.number().finite().min(0).lt(1),
|
|
7587
|
+
cancellationRate: z40.number().finite().min(0).lt(1),
|
|
7588
|
+
adsManagerCpa: z40.number().finite().nonnegative(),
|
|
7589
|
+
desiredMargin: z40.number().finite().min(0).lt(1)
|
|
7221
7590
|
}).superRefine(({ returnRate, cancellationRate }, context) => {
|
|
7222
7591
|
if (returnRate + cancellationRate >= 1) {
|
|
7223
7592
|
context.addIssue({
|
|
7224
|
-
code:
|
|
7593
|
+
code: z40.ZodIssueCode.custom,
|
|
7225
7594
|
path: [
|
|
7226
7595
|
"cancellationRate"
|
|
7227
7596
|
],
|
|
@@ -7229,24 +7598,24 @@ var DropshippingProjectCostingInputSchema = z39.object({
|
|
|
7229
7598
|
});
|
|
7230
7599
|
}
|
|
7231
7600
|
});
|
|
7232
|
-
var DropshippingProjectCostingResultSchema =
|
|
7233
|
-
country:
|
|
7234
|
-
deliveryRate:
|
|
7235
|
-
adjustedShippingCost:
|
|
7236
|
-
adjustedCpa:
|
|
7237
|
-
totalCost:
|
|
7238
|
-
suggestedPrice:
|
|
7239
|
-
baseCommercialPrice:
|
|
7240
|
-
minimumSafePrice:
|
|
7241
|
-
commercialPrice:
|
|
7242
|
-
comparisonPrice:
|
|
7243
|
-
estimatedProfit:
|
|
7244
|
-
actualMargin:
|
|
7245
|
-
breakEvenAdsManagerCpa:
|
|
7246
|
-
wasPriceAutoAdjusted:
|
|
7247
|
-
profitabilityStatus:
|
|
7248
|
-
});
|
|
7249
|
-
var HttpUrlSchema =
|
|
7601
|
+
var DropshippingProjectCostingResultSchema = z40.object({
|
|
7602
|
+
country: z40.string().min(2).max(3),
|
|
7603
|
+
deliveryRate: z40.number().finite(),
|
|
7604
|
+
adjustedShippingCost: z40.number().finite(),
|
|
7605
|
+
adjustedCpa: z40.number().finite(),
|
|
7606
|
+
totalCost: z40.number().finite(),
|
|
7607
|
+
suggestedPrice: z40.number().finite(),
|
|
7608
|
+
baseCommercialPrice: z40.number().finite(),
|
|
7609
|
+
minimumSafePrice: z40.number().finite(),
|
|
7610
|
+
commercialPrice: z40.number().finite(),
|
|
7611
|
+
comparisonPrice: z40.number().finite(),
|
|
7612
|
+
estimatedProfit: z40.number().finite(),
|
|
7613
|
+
actualMargin: z40.number().finite(),
|
|
7614
|
+
breakEvenAdsManagerCpa: z40.number().finite(),
|
|
7615
|
+
wasPriceAutoAdjusted: z40.boolean(),
|
|
7616
|
+
profitabilityStatus: z40.literal("healthy")
|
|
7617
|
+
});
|
|
7618
|
+
var HttpUrlSchema = z40.string().url().max(2e3).refine((value) => {
|
|
7250
7619
|
try {
|
|
7251
7620
|
return [
|
|
7252
7621
|
"http:",
|
|
@@ -7256,124 +7625,124 @@ var HttpUrlSchema = z39.string().url().max(2e3).refine((value) => {
|
|
|
7256
7625
|
return false;
|
|
7257
7626
|
}
|
|
7258
7627
|
}, "Product URL must use HTTP(S)");
|
|
7259
|
-
var ResearchCandidateOriginSchema =
|
|
7260
|
-
type:
|
|
7261
|
-
runId:
|
|
7262
|
-
candidateSourceId:
|
|
7263
|
-
});
|
|
7264
|
-
var TaskOriginSchema =
|
|
7265
|
-
type:
|
|
7266
|
-
taskId:
|
|
7267
|
-
});
|
|
7268
|
-
var ManualOriginSchema =
|
|
7269
|
-
type:
|
|
7270
|
-
clientRequestId:
|
|
7271
|
-
country:
|
|
7272
|
-
});
|
|
7273
|
-
var CreateDropshippingProjectRequestSchema =
|
|
7274
|
-
origin:
|
|
7628
|
+
var ResearchCandidateOriginSchema = z40.object({
|
|
7629
|
+
type: z40.literal("research_candidate"),
|
|
7630
|
+
runId: z40.string().uuid(),
|
|
7631
|
+
candidateSourceId: z40.string().min(1).max(160)
|
|
7632
|
+
});
|
|
7633
|
+
var TaskOriginSchema = z40.object({
|
|
7634
|
+
type: z40.literal("task"),
|
|
7635
|
+
taskId: z40.string().uuid()
|
|
7636
|
+
});
|
|
7637
|
+
var ManualOriginSchema = z40.object({
|
|
7638
|
+
type: z40.literal("manual"),
|
|
7639
|
+
clientRequestId: z40.string().uuid(),
|
|
7640
|
+
country: z40.string().min(2).max(3).optional()
|
|
7641
|
+
});
|
|
7642
|
+
var CreateDropshippingProjectRequestSchema = z40.object({
|
|
7643
|
+
origin: z40.discriminatedUnion("type", [
|
|
7275
7644
|
ResearchCandidateOriginSchema,
|
|
7276
7645
|
TaskOriginSchema,
|
|
7277
7646
|
ManualOriginSchema
|
|
7278
7647
|
]),
|
|
7279
|
-
productName:
|
|
7648
|
+
productName: z40.string().trim().min(1).max(240).optional(),
|
|
7280
7649
|
productUrl: HttpUrlSchema.optional(),
|
|
7281
|
-
country:
|
|
7282
|
-
languageCode:
|
|
7650
|
+
country: z40.string().min(2).max(3).optional(),
|
|
7651
|
+
languageCode: z40.string().min(2).max(16).optional()
|
|
7283
7652
|
}).strict();
|
|
7284
|
-
var SaveDropshippingProjectCostingRequestSchema =
|
|
7653
|
+
var SaveDropshippingProjectCostingRequestSchema = z40.object({
|
|
7285
7654
|
input: DropshippingProjectCostingInputSchema,
|
|
7286
|
-
version:
|
|
7655
|
+
version: z40.number().int().positive()
|
|
7287
7656
|
}).strict();
|
|
7288
|
-
var DropshippingProjectNextActionSchema =
|
|
7289
|
-
|
|
7290
|
-
kind:
|
|
7291
|
-
href:
|
|
7657
|
+
var DropshippingProjectNextActionSchema = z40.discriminatedUnion("kind", [
|
|
7658
|
+
z40.object({
|
|
7659
|
+
kind: z40.literal("cost_product"),
|
|
7660
|
+
href: z40.string().min(1)
|
|
7292
7661
|
}),
|
|
7293
|
-
|
|
7294
|
-
kind:
|
|
7295
|
-
href:
|
|
7662
|
+
z40.object({
|
|
7663
|
+
kind: z40.literal("provide_product_media"),
|
|
7664
|
+
href: z40.string().min(1)
|
|
7296
7665
|
}),
|
|
7297
|
-
|
|
7298
|
-
kind:
|
|
7299
|
-
href:
|
|
7666
|
+
z40.object({
|
|
7667
|
+
kind: z40.literal("generate_creatives"),
|
|
7668
|
+
href: z40.string().min(1)
|
|
7300
7669
|
}),
|
|
7301
|
-
|
|
7302
|
-
kind:
|
|
7303
|
-
href:
|
|
7670
|
+
z40.object({
|
|
7671
|
+
kind: z40.literal("wait_for_creatives"),
|
|
7672
|
+
href: z40.string().min(1)
|
|
7304
7673
|
}),
|
|
7305
|
-
|
|
7306
|
-
kind:
|
|
7307
|
-
href:
|
|
7674
|
+
z40.object({
|
|
7675
|
+
kind: z40.literal("repair_creatives"),
|
|
7676
|
+
href: z40.string().min(1)
|
|
7308
7677
|
}),
|
|
7309
|
-
|
|
7310
|
-
kind:
|
|
7311
|
-
href:
|
|
7678
|
+
z40.object({
|
|
7679
|
+
kind: z40.literal("complete_creative_set"),
|
|
7680
|
+
href: z40.string().min(1)
|
|
7312
7681
|
}),
|
|
7313
|
-
|
|
7314
|
-
kind:
|
|
7315
|
-
href:
|
|
7682
|
+
z40.object({
|
|
7683
|
+
kind: z40.literal("connect_shopify"),
|
|
7684
|
+
href: z40.string().min(1)
|
|
7316
7685
|
}),
|
|
7317
|
-
|
|
7318
|
-
kind:
|
|
7319
|
-
href:
|
|
7686
|
+
z40.object({
|
|
7687
|
+
kind: z40.literal("publish_storefront"),
|
|
7688
|
+
href: z40.string().min(1)
|
|
7320
7689
|
}),
|
|
7321
|
-
|
|
7322
|
-
kind:
|
|
7323
|
-
href:
|
|
7690
|
+
z40.object({
|
|
7691
|
+
kind: z40.literal("wait_for_storefront"),
|
|
7692
|
+
href: z40.string().min(1)
|
|
7324
7693
|
}),
|
|
7325
|
-
|
|
7326
|
-
kind:
|
|
7327
|
-
href:
|
|
7694
|
+
z40.object({
|
|
7695
|
+
kind: z40.literal("connect_meta"),
|
|
7696
|
+
href: z40.string().min(1)
|
|
7328
7697
|
}),
|
|
7329
|
-
|
|
7330
|
-
kind:
|
|
7331
|
-
href:
|
|
7698
|
+
z40.object({
|
|
7699
|
+
kind: z40.literal("create_meta_campaign"),
|
|
7700
|
+
href: z40.string().min(1)
|
|
7332
7701
|
}),
|
|
7333
|
-
|
|
7334
|
-
kind:
|
|
7335
|
-
href:
|
|
7702
|
+
z40.object({
|
|
7703
|
+
kind: z40.literal("repair_meta_campaign"),
|
|
7704
|
+
href: z40.string().min(1)
|
|
7336
7705
|
}),
|
|
7337
|
-
|
|
7338
|
-
kind:
|
|
7339
|
-
href:
|
|
7706
|
+
z40.object({
|
|
7707
|
+
kind: z40.literal("review_paused_campaign"),
|
|
7708
|
+
href: z40.string().min(1)
|
|
7340
7709
|
})
|
|
7341
7710
|
]);
|
|
7342
|
-
var DropshippingProjectResponseSchema =
|
|
7343
|
-
id:
|
|
7344
|
-
taskId:
|
|
7711
|
+
var DropshippingProjectResponseSchema = z40.object({
|
|
7712
|
+
id: z40.string().uuid(),
|
|
7713
|
+
taskId: z40.string().uuid().nullable(),
|
|
7345
7714
|
status: DropshippingProjectStatusSchema,
|
|
7346
|
-
originKey:
|
|
7347
|
-
researchRunId:
|
|
7348
|
-
candidateSourceId:
|
|
7349
|
-
productName:
|
|
7715
|
+
originKey: z40.string().min(1),
|
|
7716
|
+
researchRunId: z40.string().uuid().nullable(),
|
|
7717
|
+
candidateSourceId: z40.string().nullable(),
|
|
7718
|
+
productName: z40.string().nullable(),
|
|
7350
7719
|
productUrl: HttpUrlSchema.nullable(),
|
|
7351
|
-
referenceImageUrl:
|
|
7352
|
-
hasReferenceImage:
|
|
7353
|
-
targetCountry:
|
|
7354
|
-
languageCode:
|
|
7720
|
+
referenceImageUrl: z40.string().url().nullable(),
|
|
7721
|
+
hasReferenceImage: z40.boolean(),
|
|
7722
|
+
targetCountry: z40.string().nullable(),
|
|
7723
|
+
languageCode: z40.string().nullable(),
|
|
7355
7724
|
costingInput: DropshippingProjectCostingInputSchema.nullable(),
|
|
7356
7725
|
costingResult: DropshippingProjectCostingResultSchema.nullable(),
|
|
7357
|
-
costingVersion:
|
|
7358
|
-
version:
|
|
7726
|
+
costingVersion: z40.number().int().positive().nullable(),
|
|
7727
|
+
version: z40.number().int().positive(),
|
|
7359
7728
|
phase: DropshippingProjectPhaseSchema,
|
|
7360
7729
|
nextAction: DropshippingProjectNextActionSchema.nullable(),
|
|
7361
7730
|
rewards: DropshippingProjectRewardProgressSchema,
|
|
7362
|
-
createdAt:
|
|
7363
|
-
updatedAt:
|
|
7731
|
+
createdAt: z40.string().datetime(),
|
|
7732
|
+
updatedAt: z40.string().datetime()
|
|
7364
7733
|
});
|
|
7365
7734
|
|
|
7366
7735
|
// ../../packages/types/src/scene-subject-contract.ts
|
|
7367
|
-
import { z as
|
|
7368
|
-
var SceneSubjectContractSchema =
|
|
7369
|
-
maxPeople:
|
|
7370
|
-
minPeople:
|
|
7371
|
-
minDistinctPeople:
|
|
7372
|
-
maxHands:
|
|
7736
|
+
import { z as z41 } from "zod";
|
|
7737
|
+
var SceneSubjectContractSchema = z41.object({
|
|
7738
|
+
maxPeople: z41.number().int().min(1).max(10),
|
|
7739
|
+
minPeople: z41.number().int().min(0).max(10),
|
|
7740
|
+
minDistinctPeople: z41.number().int().min(0).max(10),
|
|
7741
|
+
maxHands: z41.number().int().min(0).max(20)
|
|
7373
7742
|
}).superRefine((value, ctx) => {
|
|
7374
7743
|
if (value.minPeople > value.maxPeople) {
|
|
7375
7744
|
ctx.addIssue({
|
|
7376
|
-
code:
|
|
7745
|
+
code: z41.ZodIssueCode.custom,
|
|
7377
7746
|
path: [
|
|
7378
7747
|
"minPeople"
|
|
7379
7748
|
],
|
|
@@ -7382,7 +7751,7 @@ var SceneSubjectContractSchema = z40.object({
|
|
|
7382
7751
|
}
|
|
7383
7752
|
if (value.minDistinctPeople > value.maxPeople) {
|
|
7384
7753
|
ctx.addIssue({
|
|
7385
|
-
code:
|
|
7754
|
+
code: z41.ZodIssueCode.custom,
|
|
7386
7755
|
path: [
|
|
7387
7756
|
"minDistinctPeople"
|
|
7388
7757
|
],
|
|
@@ -7391,7 +7760,7 @@ var SceneSubjectContractSchema = z40.object({
|
|
|
7391
7760
|
}
|
|
7392
7761
|
if (value.minDistinctPeople > value.minPeople) {
|
|
7393
7762
|
ctx.addIssue({
|
|
7394
|
-
code:
|
|
7763
|
+
code: z41.ZodIssueCode.custom,
|
|
7395
7764
|
path: [
|
|
7396
7765
|
"minDistinctPeople"
|
|
7397
7766
|
],
|
|
@@ -7401,7 +7770,7 @@ var SceneSubjectContractSchema = z40.object({
|
|
|
7401
7770
|
});
|
|
7402
7771
|
|
|
7403
7772
|
// ../../packages/types/src/service-creative.ts
|
|
7404
|
-
import { z as
|
|
7773
|
+
import { z as z42 } from "zod";
|
|
7405
7774
|
var SERVICE_CREATIVE_PUBLIC_PRESETS = [
|
|
7406
7775
|
"auto",
|
|
7407
7776
|
"ugc_dynamic",
|
|
@@ -7409,19 +7778,19 @@ var SERVICE_CREATIVE_PUBLIC_PRESETS = [
|
|
|
7409
7778
|
"cinematic",
|
|
7410
7779
|
"wild_card"
|
|
7411
7780
|
];
|
|
7412
|
-
var ServiceCreativePresetSchema =
|
|
7781
|
+
var ServiceCreativePresetSchema = z42.enum(SERVICE_CREATIVE_PUBLIC_PRESETS);
|
|
7413
7782
|
var SERVICE_REVIEW_MODES = [
|
|
7414
7783
|
"automatic",
|
|
7415
7784
|
"guided"
|
|
7416
7785
|
];
|
|
7417
|
-
var ServiceReviewModeSchema =
|
|
7786
|
+
var ServiceReviewModeSchema = z42.enum(SERVICE_REVIEW_MODES);
|
|
7418
7787
|
var SERVICE_HIGGSFIELD_MODES = [
|
|
7419
7788
|
"product_review",
|
|
7420
7789
|
"ugc_how_to",
|
|
7421
7790
|
"tv_spot",
|
|
7422
7791
|
"wild_card"
|
|
7423
7792
|
];
|
|
7424
|
-
var ServiceHiggsfieldModeSchema =
|
|
7793
|
+
var ServiceHiggsfieldModeSchema = z42.enum(SERVICE_HIGGSFIELD_MODES);
|
|
7425
7794
|
var SERVICE_MEDIA_ROLES = [
|
|
7426
7795
|
"screen_demo",
|
|
7427
7796
|
"ad_reference",
|
|
@@ -7429,20 +7798,20 @@ var SERVICE_MEDIA_ROLES = [
|
|
|
7429
7798
|
"presenter_reference",
|
|
7430
7799
|
"brand_asset"
|
|
7431
7800
|
];
|
|
7432
|
-
var ServiceMediaRoleSchema =
|
|
7433
|
-
var ServiceMediaAssetSchema =
|
|
7801
|
+
var ServiceMediaRoleSchema = z42.enum(SERVICE_MEDIA_ROLES);
|
|
7802
|
+
var ServiceMediaAssetSchema = z42.object({
|
|
7434
7803
|
role: ServiceMediaRoleSchema,
|
|
7435
|
-
s3Key:
|
|
7804
|
+
s3Key: z42.string().min(1),
|
|
7436
7805
|
/** HMAC ticket returned by the authenticated service-media presign route. */
|
|
7437
|
-
uploadToken:
|
|
7438
|
-
mimeType:
|
|
7439
|
-
durationSec:
|
|
7440
|
-
sourceName:
|
|
7806
|
+
uploadToken: z42.string().min(1).optional(),
|
|
7807
|
+
mimeType: z42.string().min(1),
|
|
7808
|
+
durationSec: z42.number().positive().max(30).optional(),
|
|
7809
|
+
sourceName: z42.string().max(255).optional()
|
|
7441
7810
|
}).superRefine((asset, ctx) => {
|
|
7442
7811
|
const isVideoRole = asset.role === "screen_demo" || asset.role === "ad_reference";
|
|
7443
7812
|
if (isVideoRole && !asset.mimeType.startsWith("video/")) {
|
|
7444
7813
|
ctx.addIssue({
|
|
7445
|
-
code:
|
|
7814
|
+
code: z42.ZodIssueCode.custom,
|
|
7446
7815
|
message: `${asset.role} requires video media`,
|
|
7447
7816
|
path: [
|
|
7448
7817
|
"mimeType"
|
|
@@ -7451,7 +7820,7 @@ var ServiceMediaAssetSchema = z41.object({
|
|
|
7451
7820
|
}
|
|
7452
7821
|
if (isVideoRole && asset.durationSec === void 0) {
|
|
7453
7822
|
ctx.addIssue({
|
|
7454
|
-
code:
|
|
7823
|
+
code: z42.ZodIssueCode.custom,
|
|
7455
7824
|
message: `${asset.role} requires durationSec`,
|
|
7456
7825
|
path: [
|
|
7457
7826
|
"durationSec"
|
|
@@ -7460,7 +7829,7 @@ var ServiceMediaAssetSchema = z41.object({
|
|
|
7460
7829
|
}
|
|
7461
7830
|
if (!isVideoRole && !asset.mimeType.startsWith("image/")) {
|
|
7462
7831
|
ctx.addIssue({
|
|
7463
|
-
code:
|
|
7832
|
+
code: z42.ZodIssueCode.custom,
|
|
7464
7833
|
message: `${asset.role} requires image media`,
|
|
7465
7834
|
path: [
|
|
7466
7835
|
"mimeType"
|
|
@@ -7468,13 +7837,13 @@ var ServiceMediaAssetSchema = z41.object({
|
|
|
7468
7837
|
});
|
|
7469
7838
|
}
|
|
7470
7839
|
});
|
|
7471
|
-
var ServiceMediaBundleSchema =
|
|
7472
|
-
assets:
|
|
7840
|
+
var ServiceMediaBundleSchema = z42.object({
|
|
7841
|
+
assets: z42.array(ServiceMediaAssetSchema).max(15).default([])
|
|
7473
7842
|
}).superRefine((bundle, ctx) => {
|
|
7474
7843
|
const adReferences = bundle.assets.filter((asset) => asset.role === "ad_reference");
|
|
7475
7844
|
if (adReferences.length > 5) {
|
|
7476
7845
|
ctx.addIssue({
|
|
7477
|
-
code:
|
|
7846
|
+
code: z42.ZodIssueCode.custom,
|
|
7478
7847
|
message: "A maximum of five ad_reference videos is allowed",
|
|
7479
7848
|
path: [
|
|
7480
7849
|
"assets"
|
|
@@ -7484,7 +7853,7 @@ var ServiceMediaBundleSchema = z41.object({
|
|
|
7484
7853
|
const screenDemos = bundle.assets.filter((asset) => asset.role === "screen_demo");
|
|
7485
7854
|
if (screenDemos.length > 3) {
|
|
7486
7855
|
ctx.addIssue({
|
|
7487
|
-
code:
|
|
7856
|
+
code: z42.ZodIssueCode.custom,
|
|
7488
7857
|
message: "A maximum of three screen_demo videos is allowed",
|
|
7489
7858
|
path: [
|
|
7490
7859
|
"assets"
|
|
@@ -7501,33 +7870,33 @@ var SERVICE_MEDIA_ANALYSIS_KINDS = [
|
|
|
7501
7870
|
"product",
|
|
7502
7871
|
"other"
|
|
7503
7872
|
];
|
|
7504
|
-
var ServiceMediaAnalysisKindSchema =
|
|
7505
|
-
var ServiceMediaAnalysisItemSchema =
|
|
7506
|
-
assetIndex:
|
|
7507
|
-
mediaType:
|
|
7873
|
+
var ServiceMediaAnalysisKindSchema = z42.enum(SERVICE_MEDIA_ANALYSIS_KINDS);
|
|
7874
|
+
var ServiceMediaAnalysisItemSchema = z42.object({
|
|
7875
|
+
assetIndex: z42.number().int().nonnegative(),
|
|
7876
|
+
mediaType: z42.enum([
|
|
7508
7877
|
"image",
|
|
7509
7878
|
"video"
|
|
7510
7879
|
]),
|
|
7511
7880
|
kind: ServiceMediaAnalysisKindSchema,
|
|
7512
|
-
description:
|
|
7513
|
-
tags:
|
|
7514
|
-
suggestedRoles:
|
|
7515
|
-
visiblePeople:
|
|
7516
|
-
ocrText:
|
|
7517
|
-
speechSummary:
|
|
7518
|
-
});
|
|
7519
|
-
var ServiceMediaAnalysisSchema =
|
|
7520
|
-
version:
|
|
7521
|
-
analyzedAt:
|
|
7522
|
-
pricingAction:
|
|
7523
|
-
assetFingerprint:
|
|
7881
|
+
description: z42.string().min(1).max(1200),
|
|
7882
|
+
tags: z42.array(z42.string().min(1).max(80)).max(12),
|
|
7883
|
+
suggestedRoles: z42.array(ServiceMediaRoleSchema).max(4),
|
|
7884
|
+
visiblePeople: z42.number().int().nonnegative().max(20).optional(),
|
|
7885
|
+
ocrText: z42.string().max(2e3).optional(),
|
|
7886
|
+
speechSummary: z42.string().max(2e3).optional()
|
|
7887
|
+
});
|
|
7888
|
+
var ServiceMediaAnalysisSchema = z42.object({
|
|
7889
|
+
version: z42.literal(1),
|
|
7890
|
+
analyzedAt: z42.string().datetime(),
|
|
7891
|
+
pricingAction: z42.literal("service-media-analysis"),
|
|
7892
|
+
assetFingerprint: z42.string().regex(/^[a-f0-9]{64}$/),
|
|
7524
7893
|
/** Language used for human-readable descriptions and tags. Optional for old checkpoints. */
|
|
7525
|
-
language:
|
|
7894
|
+
language: z42.enum([
|
|
7526
7895
|
"es",
|
|
7527
7896
|
"en",
|
|
7528
7897
|
"pt"
|
|
7529
7898
|
]).optional(),
|
|
7530
|
-
items:
|
|
7899
|
+
items: z42.array(ServiceMediaAnalysisItemSchema).max(15)
|
|
7531
7900
|
});
|
|
7532
7901
|
|
|
7533
7902
|
// ../../packages/types/src/productmaker-chat-capabilities.ts
|
|
@@ -7537,6 +7906,11 @@ var PRODUCTMAKER_MCP_CAPABILITIES = [
|
|
|
7537
7906
|
confirmation: "credit_consuming",
|
|
7538
7907
|
schemaHash: "bab794a9700a8d3f42b97f444a776e7ed4dcd833038c52588f951b50970ff3fa"
|
|
7539
7908
|
},
|
|
7909
|
+
{
|
|
7910
|
+
name: "check_meta_media_upload",
|
|
7911
|
+
confirmation: "none",
|
|
7912
|
+
schemaHash: "62b1af1d796d9466f8926afc5e6d18c4ddeccd5b0269ca7b21c2f6ebcfd2a945"
|
|
7913
|
+
},
|
|
7540
7914
|
{
|
|
7541
7915
|
name: "cost_dropshipping_project",
|
|
7542
7916
|
confirmation: "state_change",
|
|
@@ -7555,7 +7929,7 @@ var PRODUCTMAKER_MCP_CAPABILITIES = [
|
|
|
7555
7929
|
{
|
|
7556
7930
|
name: "create_product_task",
|
|
7557
7931
|
confirmation: "credit_consuming",
|
|
7558
|
-
schemaHash: "
|
|
7932
|
+
schemaHash: "5c5fe82a365c62e44265e79a4100a06820dbbdb2e0ddc296cd066eb2255b1d62"
|
|
7559
7933
|
},
|
|
7560
7934
|
{
|
|
7561
7935
|
name: "create_service_video",
|
|
@@ -7600,7 +7974,7 @@ var PRODUCTMAKER_MCP_CAPABILITIES = [
|
|
|
7600
7974
|
{
|
|
7601
7975
|
name: "generate_video_creative",
|
|
7602
7976
|
confirmation: "credit_consuming",
|
|
7603
|
-
schemaHash: "
|
|
7977
|
+
schemaHash: "04e12ef523e4064b0c204d110baad35d414b605068087c625badf40c46429c8a"
|
|
7604
7978
|
},
|
|
7605
7979
|
{
|
|
7606
7980
|
name: "get_meta_campaign_status",
|
|
@@ -7642,6 +8016,11 @@ var PRODUCTMAKER_MCP_CAPABILITIES = [
|
|
|
7642
8016
|
confirmation: "none",
|
|
7643
8017
|
schemaHash: "7a014b717a77aac971ea0ab5c0ff47bb13e6cae7ef9442d9dedb15ce36381b15"
|
|
7644
8018
|
},
|
|
8019
|
+
{
|
|
8020
|
+
name: "list_meta_destinations",
|
|
8021
|
+
confirmation: "none",
|
|
8022
|
+
schemaHash: "7a014b717a77aac971ea0ab5c0ff47bb13e6cae7ef9442d9dedb15ce36381b15"
|
|
8023
|
+
},
|
|
7645
8024
|
{
|
|
7646
8025
|
name: "list_product_research_runs",
|
|
7647
8026
|
confirmation: "none",
|
|
@@ -7670,12 +8049,12 @@ var PRODUCTMAKER_MCP_CAPABILITIES = [
|
|
|
7670
8049
|
{
|
|
7671
8050
|
name: "publish_creatives_to_meta",
|
|
7672
8051
|
confirmation: "external_mutation",
|
|
7673
|
-
schemaHash: "
|
|
8052
|
+
schemaHash: "59b3d6d5ce25812fee3382b0b1c0cf5e07beb1063048dd0a0d0633686cf29da5"
|
|
7674
8053
|
},
|
|
7675
8054
|
{
|
|
7676
8055
|
name: "publish_to_meta",
|
|
7677
8056
|
confirmation: "external_mutation",
|
|
7678
|
-
schemaHash: "
|
|
8057
|
+
schemaHash: "b507735a1fe13657355cf93163b6ead0db151984e6f2702dcdbf76b4037133ca"
|
|
7679
8058
|
},
|
|
7680
8059
|
{
|
|
7681
8060
|
name: "publish_to_shopify",
|
|
@@ -7692,6 +8071,11 @@ var PRODUCTMAKER_MCP_CAPABILITIES = [
|
|
|
7692
8071
|
confirmation: "credit_consuming",
|
|
7693
8072
|
schemaHash: "745687cb41f904e293105f93bbe6bc0471f63fe097ab8f85d3df8d9833084844"
|
|
7694
8073
|
},
|
|
8074
|
+
{
|
|
8075
|
+
name: "request_meta_media_upload",
|
|
8076
|
+
confirmation: "none",
|
|
8077
|
+
schemaHash: "fad928b17b4658eb5831bb8b62d5e65bd5220ad94b04b90ace09e658e1895c74"
|
|
8078
|
+
},
|
|
7695
8079
|
{
|
|
7696
8080
|
name: "resolve_pending_action",
|
|
7697
8081
|
confirmation: "credit_consuming",
|
|
@@ -7706,8 +8090,8 @@ var PRODUCTMAKER_MCP_CAPABILITIES = [
|
|
|
7706
8090
|
var PRODUCTMAKER_MCP_CAPABILITY_NAMES = PRODUCTMAKER_MCP_CAPABILITIES.map((capability) => capability.name);
|
|
7707
8091
|
|
|
7708
8092
|
// ../../packages/types/src/actor.ts
|
|
7709
|
-
import { z as
|
|
7710
|
-
var ActorStatusSchema =
|
|
8093
|
+
import { z as z43 } from "zod";
|
|
8094
|
+
var ActorStatusSchema = z43.enum([
|
|
7711
8095
|
"draft",
|
|
7712
8096
|
"generating",
|
|
7713
8097
|
"ready",
|
|
@@ -7716,18 +8100,18 @@ var ActorStatusSchema = z42.enum([
|
|
|
7716
8100
|
var ACTOR_NAME_MAX_CHARS = 60;
|
|
7717
8101
|
var ACTOR_DESCRIPTION_MAX_CHARS = 600;
|
|
7718
8102
|
var ACTOR_CANDIDATE_COUNT = 4;
|
|
7719
|
-
var ActorGenderSchema =
|
|
8103
|
+
var ActorGenderSchema = z43.enum([
|
|
7720
8104
|
"female",
|
|
7721
8105
|
"male",
|
|
7722
8106
|
"non_binary"
|
|
7723
8107
|
]);
|
|
7724
|
-
var ActorSchema =
|
|
7725
|
-
id:
|
|
7726
|
-
name:
|
|
7727
|
-
description:
|
|
8108
|
+
var ActorSchema = z43.object({
|
|
8109
|
+
id: z43.string(),
|
|
8110
|
+
name: z43.string().min(1).max(ACTOR_NAME_MAX_CHARS),
|
|
8111
|
+
description: z43.string().max(ACTOR_DESCRIPTION_MAX_CHARS),
|
|
7728
8112
|
gender: ActorGenderSchema,
|
|
7729
|
-
voiceId:
|
|
7730
|
-
brandId:
|
|
8113
|
+
voiceId: z43.string().nullable().optional(),
|
|
8114
|
+
brandId: z43.string().nullable().optional(),
|
|
7731
8115
|
status: ActorStatusSchema,
|
|
7732
8116
|
/**
|
|
7733
8117
|
* A candidate-grid run is in flight RIGHT NOW.
|
|
@@ -7739,32 +8123,114 @@ var ActorSchema = z42.object({
|
|
|
7739
8123
|
* timestamp with a TTL, so an orphaned run reads as `false` instead of
|
|
7740
8124
|
* pinning the personaje forever.
|
|
7741
8125
|
*/
|
|
7742
|
-
generating:
|
|
7743
|
-
photoUrl:
|
|
7744
|
-
avatarUrl:
|
|
7745
|
-
candidateUrls:
|
|
8126
|
+
generating: z43.boolean().optional(),
|
|
8127
|
+
photoUrl: z43.string().url().nullable().optional(),
|
|
8128
|
+
avatarUrl: z43.string().url().nullable().optional(),
|
|
8129
|
+
candidateUrls: z43.array(z43.string().url()).optional(),
|
|
7746
8130
|
/** Indices of candidateUrls that failed the anatomy check (Task 6). */
|
|
7747
|
-
flaggedCandidateIndices:
|
|
8131
|
+
flaggedCandidateIndices: z43.array(z43.number().int()).optional()
|
|
7748
8132
|
});
|
|
7749
|
-
var CreateActorRequest =
|
|
7750
|
-
name:
|
|
7751
|
-
description:
|
|
8133
|
+
var CreateActorRequest = z43.object({
|
|
8134
|
+
name: z43.string().min(1).max(ACTOR_NAME_MAX_CHARS),
|
|
8135
|
+
description: z43.string().max(ACTOR_DESCRIPTION_MAX_CHARS).default(""),
|
|
7752
8136
|
gender: ActorGenderSchema,
|
|
7753
|
-
voiceId:
|
|
7754
|
-
brandId:
|
|
7755
|
-
sourcePhotoKey:
|
|
8137
|
+
voiceId: z43.string().optional(),
|
|
8138
|
+
brandId: z43.string().optional(),
|
|
8139
|
+
sourcePhotoKey: z43.string().optional()
|
|
7756
8140
|
}).refine((v) => v.description.trim().length > 0 || !!v.sourcePhotoKey, {
|
|
7757
8141
|
message: "Se necesita una descripci\xF3n o una foto"
|
|
7758
8142
|
});
|
|
7759
|
-
var UpdateActorRequest =
|
|
7760
|
-
name:
|
|
7761
|
-
description:
|
|
8143
|
+
var UpdateActorRequest = z43.object({
|
|
8144
|
+
name: z43.string().min(1).max(ACTOR_NAME_MAX_CHARS).optional(),
|
|
8145
|
+
description: z43.string().max(ACTOR_DESCRIPTION_MAX_CHARS).optional(),
|
|
7762
8146
|
gender: ActorGenderSchema.optional(),
|
|
7763
|
-
voiceId:
|
|
7764
|
-
brandId:
|
|
8147
|
+
voiceId: z43.string().nullable().optional(),
|
|
8148
|
+
brandId: z43.string().nullable().optional()
|
|
8149
|
+
});
|
|
8150
|
+
var ApproveActorRequest = z43.object({
|
|
8151
|
+
candidateIndex: z43.number().int().min(0).max(ACTOR_CANDIDATE_COUNT - 1)
|
|
8152
|
+
});
|
|
8153
|
+
|
|
8154
|
+
// ../../packages/types/src/referral-dashboard.ts
|
|
8155
|
+
import { z as z44 } from "zod";
|
|
8156
|
+
var REFERRAL_DASHBOARD_RAW_STATUSES = [
|
|
8157
|
+
"ACTIVE",
|
|
8158
|
+
"PENDING",
|
|
8159
|
+
"GRACE",
|
|
8160
|
+
"CANCELLED",
|
|
8161
|
+
"EXPIRED"
|
|
8162
|
+
];
|
|
8163
|
+
var REFERRAL_DASHBOARD_STATES = [
|
|
8164
|
+
"active",
|
|
8165
|
+
"pending",
|
|
8166
|
+
"inactive",
|
|
8167
|
+
"no_plan"
|
|
8168
|
+
];
|
|
8169
|
+
var REFERRAL_DASHBOARD_PLAN_KINDS = [
|
|
8170
|
+
"current",
|
|
8171
|
+
"last",
|
|
8172
|
+
"none"
|
|
8173
|
+
];
|
|
8174
|
+
var ReferralDashboardRawStatusSchema = z44.enum(REFERRAL_DASHBOARD_RAW_STATUSES);
|
|
8175
|
+
var ReferralDashboardStateSchema = z44.enum(REFERRAL_DASHBOARD_STATES);
|
|
8176
|
+
var ReferralDashboardPlanKindSchema = z44.enum(REFERRAL_DASHBOARD_PLAN_KINDS);
|
|
8177
|
+
var ReferralDashboardStatusSchema = z44.enum([
|
|
8178
|
+
"all",
|
|
8179
|
+
"active",
|
|
8180
|
+
"pending",
|
|
8181
|
+
"inactive"
|
|
8182
|
+
]).default("all");
|
|
8183
|
+
var ReferralDashboardPlanSchema = z44.string().trim().min(1).max(100).optional();
|
|
8184
|
+
var ReferralDashboardFiltersSchema = z44.object({
|
|
8185
|
+
status: ReferralDashboardStatusSchema,
|
|
8186
|
+
plan: ReferralDashboardPlanSchema
|
|
8187
|
+
});
|
|
8188
|
+
var ReferralDashboardSubscriptionSchema = z44.object({
|
|
8189
|
+
planName: z44.string().nullable(),
|
|
8190
|
+
planKind: ReferralDashboardPlanKindSchema,
|
|
8191
|
+
rawStatus: ReferralDashboardRawStatusSchema.nullable(),
|
|
8192
|
+
state: ReferralDashboardStateSchema,
|
|
8193
|
+
currentPeriodEnd: z44.string().datetime({
|
|
8194
|
+
offset: true
|
|
8195
|
+
}).nullable(),
|
|
8196
|
+
cancelAtPeriodEnd: z44.boolean()
|
|
8197
|
+
});
|
|
8198
|
+
var ReferralDashboardReferralSchema = z44.object({
|
|
8199
|
+
id: z44.string().min(1),
|
|
8200
|
+
registeredAt: z44.string().datetime({
|
|
8201
|
+
offset: true
|
|
8202
|
+
}),
|
|
8203
|
+
// Kept in the response for compatibility with existing referral API clients.
|
|
8204
|
+
// The referrer dashboard intentionally does not render these legacy fields.
|
|
8205
|
+
expiresAt: z44.string().datetime({
|
|
8206
|
+
offset: true
|
|
8207
|
+
}).nullable().optional(),
|
|
8208
|
+
status: z44.string().min(1).optional(),
|
|
8209
|
+
referredUser: z44.object({
|
|
8210
|
+
email: z44.string().nullable()
|
|
8211
|
+
}),
|
|
8212
|
+
subscription: ReferralDashboardSubscriptionSchema
|
|
8213
|
+
});
|
|
8214
|
+
var ReferralDashboardReferralsPageSchema = z44.object({
|
|
8215
|
+
referrals: z44.array(ReferralDashboardReferralSchema),
|
|
8216
|
+
total: z44.number().int().nonnegative()
|
|
8217
|
+
});
|
|
8218
|
+
var ReferralDashboardPlanBreakdownSchema = z44.object({
|
|
8219
|
+
planName: z44.string().nullable(),
|
|
8220
|
+
count: z44.number().int().nonnegative()
|
|
8221
|
+
});
|
|
8222
|
+
var ReferralDashboardMonthlyRegistrationSchema = z44.object({
|
|
8223
|
+
month: z44.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/),
|
|
8224
|
+
count: z44.number().int().nonnegative()
|
|
7765
8225
|
});
|
|
7766
|
-
var
|
|
7767
|
-
|
|
8226
|
+
var ReferralDashboardOverviewSchema = z44.object({
|
|
8227
|
+
totalReferredUsers: z44.number().int().nonnegative(),
|
|
8228
|
+
activeUsers: z44.number().int().nonnegative(),
|
|
8229
|
+
pendingUsers: z44.number().int().nonnegative(),
|
|
8230
|
+
inactiveUsers: z44.number().int().nonnegative(),
|
|
8231
|
+
noPlanUsers: z44.number().int().nonnegative(),
|
|
8232
|
+
planBreakdown: z44.array(ReferralDashboardPlanBreakdownSchema),
|
|
8233
|
+
monthlyRegistrations: z44.array(ReferralDashboardMonthlyRegistrationSchema).refine((months) => months.length === 6, "Expected six monthly registration buckets")
|
|
7768
8234
|
});
|
|
7769
8235
|
|
|
7770
8236
|
// src/resolve-media.ts
|
|
@@ -8006,10 +8472,10 @@ async function resolveMediaRef(ref, opts) {
|
|
|
8006
8472
|
__name(resolveMediaRef, "resolveMediaRef");
|
|
8007
8473
|
|
|
8008
8474
|
// src/tools/shared.ts
|
|
8009
|
-
import { z as
|
|
8010
|
-
var Lang =
|
|
8011
|
-
var Country =
|
|
8012
|
-
var LandingStrategyEnum =
|
|
8475
|
+
import { z as z45 } from "zod";
|
|
8476
|
+
var Lang = z45.string().min(2).max(10);
|
|
8477
|
+
var Country = z45.string().min(2).max(3);
|
|
8478
|
+
var LandingStrategyEnum = z45.enum([
|
|
8013
8479
|
"auto",
|
|
8014
8480
|
"classic",
|
|
8015
8481
|
"pain_solution",
|
|
@@ -8018,12 +8484,12 @@ var LandingStrategyEnum = z43.enum([
|
|
|
8018
8484
|
"offer_value",
|
|
8019
8485
|
"lifestyle_identity"
|
|
8020
8486
|
]);
|
|
8021
|
-
var LandingImageFormatEnum =
|
|
8487
|
+
var LandingImageFormatEnum = z45.enum([
|
|
8022
8488
|
"9:16",
|
|
8023
8489
|
"4:5",
|
|
8024
8490
|
"1:1"
|
|
8025
8491
|
]);
|
|
8026
|
-
var VideoPresetEnum =
|
|
8492
|
+
var VideoPresetEnum = z45.enum([
|
|
8027
8493
|
"auto",
|
|
8028
8494
|
"ugc_dynamic",
|
|
8029
8495
|
"ugc_how_to",
|
|
@@ -8036,7 +8502,7 @@ var VideoPresetEnum = z43.enum([
|
|
|
8036
8502
|
"pixar_problem",
|
|
8037
8503
|
"pixar_sassy"
|
|
8038
8504
|
]);
|
|
8039
|
-
var TaskCreativeVariantVideoPresetEnum =
|
|
8505
|
+
var TaskCreativeVariantVideoPresetEnum = z45.enum([
|
|
8040
8506
|
"auto",
|
|
8041
8507
|
"ugc_dynamic",
|
|
8042
8508
|
"ugc_how_to",
|
|
@@ -8107,7 +8573,7 @@ function resolveVideoPreset(preset) {
|
|
|
8107
8573
|
return VIDEO_PRESET_RESOLUTION[preset] ?? null;
|
|
8108
8574
|
}
|
|
8109
8575
|
__name(resolveVideoPreset, "resolveVideoPreset");
|
|
8110
|
-
var VideoTierEnum =
|
|
8576
|
+
var VideoTierEnum = z45.enum([
|
|
8111
8577
|
"basic"
|
|
8112
8578
|
]);
|
|
8113
8579
|
function resolveVideoTier(_tier) {
|
|
@@ -8118,27 +8584,21 @@ function resolveWireVideoTier(tier, durationSeconds) {
|
|
|
8118
8584
|
return durationSeconds === 30 ? "standard" : resolveVideoTier(tier);
|
|
8119
8585
|
}
|
|
8120
8586
|
__name(resolveWireVideoTier, "resolveWireVideoTier");
|
|
8121
|
-
function assertVideoPresetDurationCompatibility(videoPreset, durationSeconds) {
|
|
8122
|
-
if (videoPreset === "problem_solution" && durationSeconds !== 30) {
|
|
8123
|
-
throw new Error("Problema y Soluci\xF3n solo est\xE1 disponible en videos Multiescena de 30 segundos.");
|
|
8124
|
-
}
|
|
8125
|
-
}
|
|
8126
|
-
__name(assertVideoPresetDurationCompatibility, "assertVideoPresetDurationCompatibility");
|
|
8127
8587
|
function resolveVideoFormatForDuration(durationSeconds) {
|
|
8128
8588
|
return durationSeconds === 30 ? "double_30s" : "single_15s";
|
|
8129
8589
|
}
|
|
8130
8590
|
__name(resolveVideoFormatForDuration, "resolveVideoFormatForDuration");
|
|
8131
|
-
var VideoResolutionEnum =
|
|
8591
|
+
var VideoResolutionEnum = z45.enum([
|
|
8132
8592
|
"480p",
|
|
8133
8593
|
"720p"
|
|
8134
8594
|
]);
|
|
8135
|
-
var VideoStyleEnum =
|
|
8595
|
+
var VideoStyleEnum = z45.enum([
|
|
8136
8596
|
"ugc",
|
|
8137
8597
|
"cartoon_3d",
|
|
8138
8598
|
"product_only",
|
|
8139
8599
|
"ai_dynamic"
|
|
8140
8600
|
]);
|
|
8141
|
-
var NarrativeStyleEnum =
|
|
8601
|
+
var NarrativeStyleEnum = z45.enum([
|
|
8142
8602
|
"review",
|
|
8143
8603
|
"ugc_how_to",
|
|
8144
8604
|
"problem_product_cta",
|
|
@@ -8155,7 +8615,7 @@ var NarrativeStyleEnum = z43.enum([
|
|
|
8155
8615
|
"ugc_skeptic_confession",
|
|
8156
8616
|
"ugc_demo_review"
|
|
8157
8617
|
]);
|
|
8158
|
-
var PublicNarrativeStyleEnum =
|
|
8618
|
+
var PublicNarrativeStyleEnum = z45.enum([
|
|
8159
8619
|
"review",
|
|
8160
8620
|
"ugc_how_to",
|
|
8161
8621
|
"ugc_unboxing_chaos",
|
|
@@ -8167,7 +8627,7 @@ var PublicNarrativeStyleEnum = z43.enum([
|
|
|
8167
8627
|
"animated_problem_pixar",
|
|
8168
8628
|
"sassy_product_pixar"
|
|
8169
8629
|
]);
|
|
8170
|
-
var VideoModelEnum =
|
|
8630
|
+
var VideoModelEnum = z45.enum([
|
|
8171
8631
|
"veo",
|
|
8172
8632
|
"wan",
|
|
8173
8633
|
"bytedance",
|
|
@@ -8175,25 +8635,25 @@ var VideoModelEnum = z43.enum([
|
|
|
8175
8635
|
"grok",
|
|
8176
8636
|
"kling"
|
|
8177
8637
|
]);
|
|
8178
|
-
var ProductReferenceUserChoiceEnum =
|
|
8638
|
+
var ProductReferenceUserChoiceEnum = z45.enum([
|
|
8179
8639
|
"same_product",
|
|
8180
8640
|
"variants",
|
|
8181
8641
|
"different_products",
|
|
8182
8642
|
"combo_distinct"
|
|
8183
8643
|
]);
|
|
8184
|
-
var ProductReferenceCandidateGroupingEnum =
|
|
8644
|
+
var ProductReferenceCandidateGroupingEnum = z45.enum([
|
|
8185
8645
|
"same_product_same_variant",
|
|
8186
8646
|
"same_product_different_variants",
|
|
8187
8647
|
"different_products",
|
|
8188
8648
|
"unclear"
|
|
8189
8649
|
]);
|
|
8190
|
-
var GapDurationChoiceMirror =
|
|
8191
|
-
angleIndex:
|
|
8192
|
-
recommendedSec:
|
|
8193
|
-
|
|
8194
|
-
|
|
8650
|
+
var GapDurationChoiceMirror = z45.object({
|
|
8651
|
+
angleIndex: z45.number().int().nonnegative(),
|
|
8652
|
+
recommendedSec: z45.union([
|
|
8653
|
+
z45.literal(15),
|
|
8654
|
+
z45.literal(30)
|
|
8195
8655
|
]),
|
|
8196
|
-
estimatedDeltaCredits:
|
|
8656
|
+
estimatedDeltaCredits: z45.number().int().nonnegative().optional()
|
|
8197
8657
|
});
|
|
8198
8658
|
function buildSelectedImageUrlsHash(urls) {
|
|
8199
8659
|
const input = [
|
|
@@ -8207,13 +8667,13 @@ function buildSelectedImageUrlsHash(urls) {
|
|
|
8207
8667
|
return `fnv1a:${hash.toString(16).padStart(8, "0")}:${urls.length}`;
|
|
8208
8668
|
}
|
|
8209
8669
|
__name(buildSelectedImageUrlsHash, "buildSelectedImageUrlsHash");
|
|
8210
|
-
var ImageCreativeStyleEnum =
|
|
8670
|
+
var ImageCreativeStyleEnum = z45.enum([
|
|
8211
8671
|
"studio",
|
|
8212
8672
|
"floating",
|
|
8213
8673
|
"ingredients",
|
|
8214
8674
|
"in_use"
|
|
8215
8675
|
]);
|
|
8216
|
-
var ImageCreativeArchetypeEnum =
|
|
8676
|
+
var ImageCreativeArchetypeEnum = z45.enum([
|
|
8217
8677
|
"direct_response_product_ad",
|
|
8218
8678
|
"hero_outcome",
|
|
8219
8679
|
"offer_value_prop",
|
|
@@ -8222,23 +8682,23 @@ var ImageCreativeArchetypeEnum = z43.enum([
|
|
|
8222
8682
|
"problem_solution",
|
|
8223
8683
|
"lifestyle_identity"
|
|
8224
8684
|
]);
|
|
8225
|
-
var ImageCreativeVisualTreatmentEnum =
|
|
8685
|
+
var ImageCreativeVisualTreatmentEnum = z45.enum([
|
|
8226
8686
|
"performance_product_ad",
|
|
8227
8687
|
"premium_dtc_carousel"
|
|
8228
8688
|
]);
|
|
8229
|
-
var ImageCreativeAspectRatioEnum =
|
|
8689
|
+
var ImageCreativeAspectRatioEnum = z45.enum([
|
|
8230
8690
|
"1:1",
|
|
8231
8691
|
"4:5",
|
|
8232
8692
|
"9:16",
|
|
8233
8693
|
"16:9"
|
|
8234
8694
|
]);
|
|
8235
|
-
var ImageRefSchema =
|
|
8236
|
-
url:
|
|
8237
|
-
path:
|
|
8695
|
+
var ImageRefSchema = z45.object({
|
|
8696
|
+
url: z45.string().url().optional().describe('URL p\xFAblica HTTPS de la foto. Ej: una URL de Shopify CDN, Cloudinary, Imgur. \xDAsala cuando el usuario te diga "est\xE1 en X.com/foto.jpg" o cuando la foto ya est\xE9 hospedada.'),
|
|
8697
|
+
path: z45.string().min(1).optional().describe('Ruta del archivo en el computador del usuario. Ej: "/Users/maria/Desktop/foto.jpg", "~/Pictures/camiseta.png", "C:\\Users\\Maria\\Desktop\\foto.jpg". El MCP local la lee del disco y la sube. SOLO funciona cuando el MCP corre local (stdio). NO funciona en mcp.productmaker.app (HTTP) \u2014 ah\xED usa `url`.')
|
|
8238
8698
|
}).refine((v) => Boolean(v.url) !== Boolean(v.path), {
|
|
8239
8699
|
message: "each image entry must have exactly one of `url` or `path`"
|
|
8240
8700
|
});
|
|
8241
|
-
var ImagesInput =
|
|
8701
|
+
var ImagesInput = z45.array(ImageRefSchema).min(1).max(5).describe('1 a 5 fotos del MISMO producto. La PRIMERA es la principal (hero); las dem\xE1s son \xE1ngulos adicionales. NO mezcles productos distintos en una sola llamada.\n\nCada entrada tiene EXACTAMENTE uno de:\n\u2022 `url` \u2014 URL p\xFAblica HTTPS (Shopify CDN, Cloudinary). Prefi\xE9rela si la foto ya est\xE1 hospedada.\n\u2022 `path` \u2014 Ruta del archivo en el computador del usuario (ej. "/Users/maria/Desktop/foto.jpg", "~/Downloads/camiseta.png"). \xDAsala cuando el usuario te dijo d\xF3nde guard\xF3 la foto. Solo MCP local \u2014 el cliente web rechaza paths.\n\nSi el usuario te peg\xF3 la foto en el chat pero no te dio ni URL ni ruta: PREG\xDANTALE d\xF3nde la tiene guardada (Escritorio, Descargas, etc.). Si el `path` falla con IMAGE_PATH_NOT_FOUND, prueba 1-2 ubicaciones obvias alternativas (~/Desktop, ~/Downloads) antes de molestar al usuario. Tras 3 intentos fallidos, p\xEDdele la ruta completa.');
|
|
8242
8702
|
function asText(value) {
|
|
8243
8703
|
return {
|
|
8244
8704
|
content: [
|
|
@@ -8291,14 +8751,14 @@ async function submitCreative(api, opts) {
|
|
|
8291
8751
|
});
|
|
8292
8752
|
}
|
|
8293
8753
|
__name(submitCreative, "submitCreative");
|
|
8294
|
-
var ResearchTargetCountryEnum =
|
|
8754
|
+
var ResearchTargetCountryEnum = z45.enum([
|
|
8295
8755
|
"CO",
|
|
8296
8756
|
"MX",
|
|
8297
8757
|
"PE",
|
|
8298
8758
|
"EC",
|
|
8299
8759
|
"CL"
|
|
8300
8760
|
]);
|
|
8301
|
-
var ResearchCategoryEnum =
|
|
8761
|
+
var ResearchCategoryEnum = z45.enum([
|
|
8302
8762
|
"auto",
|
|
8303
8763
|
"automotive",
|
|
8304
8764
|
"kitchen",
|
|
@@ -8371,6 +8831,15 @@ var McpErrorCode = {
|
|
|
8371
8831
|
SHOPIFY_PUBLISH_FAILED: "SHOPIFY_PUBLISH_FAILED",
|
|
8372
8832
|
// Meta / Facebook Ads
|
|
8373
8833
|
META_NO_FB_PAGE: "META_NO_FB_PAGE",
|
|
8834
|
+
META_PORTFOLIO_MISMATCH: "META_PORTFOLIO_MISMATCH",
|
|
8835
|
+
META_PAGE_SELECTION_REQUIRED: "META_PAGE_SELECTION_REQUIRED",
|
|
8836
|
+
META_INVALID_PAGE: "META_INVALID_PAGE",
|
|
8837
|
+
META_STAGED_ASSET_NOT_FOUND: "META_STAGED_ASSET_NOT_FOUND",
|
|
8838
|
+
META_STAGED_ASSET_AMBIGUOUS: "META_STAGED_ASSET_AMBIGUOUS",
|
|
8839
|
+
META_STAGED_ASSET_TYPE_MISMATCH: "META_STAGED_ASSET_TYPE_MISMATCH",
|
|
8840
|
+
META_STAGED_ASSET_INVALID: "META_STAGED_ASSET_INVALID",
|
|
8841
|
+
META_PUBLICATION_RECONCILIATION_REQUIRED: "META_PUBLICATION_RECONCILIATION_REQUIRED",
|
|
8842
|
+
META_PUBLICATION_IN_PROGRESS: "META_PUBLICATION_IN_PROGRESS",
|
|
8374
8843
|
META_NO_ADS_CREATED: "META_NO_ADS_CREATED",
|
|
8375
8844
|
META_NO_ASSETS_READY: "META_NO_ASSETS_READY",
|
|
8376
8845
|
META_NO_THUMBNAIL_SOURCE: "META_NO_THUMBNAIL_SOURCE",
|
|
@@ -8423,6 +8892,15 @@ var CODE_MESSAGES = {
|
|
|
8423
8892
|
SHOPIFY_PUBLISH_FAILED: "Shopify rejected the publish. Check that the product/landing does not already exist on the store and that your Shopify plan allows additional products.",
|
|
8424
8893
|
// Meta — high-frequency
|
|
8425
8894
|
META_NO_FB_PAGE: "No Facebook Page is associated with this account. Create one at https://www.facebook.com/pages/create before publishing (Meta requires a Page to run ads).",
|
|
8895
|
+
META_PORTFOLIO_MISMATCH: "The selected Meta portfolio does not contain the selected ad account. Call `list_meta_destinations` again and choose an account from that portfolio.",
|
|
8896
|
+
META_PAGE_SELECTION_REQUIRED: "Meta has multiple Facebook Pages available. Ask the user to choose one with `list_meta_destinations` and retry with its exact `pageId`.",
|
|
8897
|
+
META_INVALID_PAGE: "The selected Facebook Page is not available for this Meta connection. Call `list_meta_destinations` again and choose an available `pageId`.",
|
|
8898
|
+
META_STAGED_ASSET_NOT_FOUND: "The temporary media upload was not found or expired. Re-upload the media and retry the Meta publication.",
|
|
8899
|
+
META_STAGED_ASSET_AMBIGUOUS: "The temporary media upload could not be uniquely resolved. Re-upload the media and retry the Meta publication.",
|
|
8900
|
+
META_STAGED_ASSET_TYPE_MISMATCH: "The temporary media type does not match the creative. Re-upload the correct image or video and retry.",
|
|
8901
|
+
META_STAGED_ASSET_INVALID: "The temporary media is empty or exceeds the server size limit. Re-upload the file and retry.",
|
|
8902
|
+
META_PUBLICATION_RECONCILIATION_REQUIRED: "A previous Meta publication with these exact inputs may already exist. Check Meta before retrying so you do not create a duplicate campaign.",
|
|
8903
|
+
META_PUBLICATION_IN_PROGRESS: "A Meta publication with these exact inputs is already in progress. Wait for it to finish, then check the campaign status.",
|
|
8426
8904
|
META_NO_ADS_CREATED: "No ads could be created. Most likely: the Meta Ads account has no payment method, no Facebook Page is linked, or the Facebook app lost permissions. Verify all three at https://business.facebook.com.",
|
|
8427
8905
|
META_NO_ASSETS_READY: "The task has no videos or ad creative ready to publish yet. Wait for generation to finish or regenerate the assets.",
|
|
8428
8906
|
META_NO_THUMBNAIL_SOURCE: "No image is available to use as the video thumbnail. Upload a product image or generate the ad creative before publishing.",
|
|
@@ -8536,6 +9014,12 @@ var INVALID_PARAM_CODES = /* @__PURE__ */ new Set([
|
|
|
8536
9014
|
McpErrorCode.CAMPAIGN_MISSING_LANDING_URL,
|
|
8537
9015
|
McpErrorCode.CAMPAIGN_RECONCILIATION_REQUIRED,
|
|
8538
9016
|
McpErrorCode.META_NO_LANDING_URL,
|
|
9017
|
+
McpErrorCode.META_PORTFOLIO_MISMATCH,
|
|
9018
|
+
McpErrorCode.META_PAGE_SELECTION_REQUIRED,
|
|
9019
|
+
McpErrorCode.META_INVALID_PAGE,
|
|
9020
|
+
McpErrorCode.META_STAGED_ASSET_NOT_FOUND,
|
|
9021
|
+
McpErrorCode.META_STAGED_ASSET_AMBIGUOUS,
|
|
9022
|
+
McpErrorCode.META_STAGED_ASSET_TYPE_MISMATCH,
|
|
8539
9023
|
McpErrorCode.META_DAILY_BUDGET_TOO_HIGH,
|
|
8540
9024
|
McpErrorCode.META_CAMPAIGN_CONFIG_INVALID,
|
|
8541
9025
|
McpErrorCode.META_WHATSAPP_INVALID_NUMBER,
|
|
@@ -8557,6 +9041,15 @@ var INVALID_PARAM_CODES = /* @__PURE__ */ new Set([
|
|
|
8557
9041
|
McpErrorCode.META_MISSING_PAYMENT,
|
|
8558
9042
|
McpErrorCode.META_ACCOUNT_RESTRICTED,
|
|
8559
9043
|
McpErrorCode.META_NO_FB_PAGE,
|
|
9044
|
+
McpErrorCode.META_PORTFOLIO_MISMATCH,
|
|
9045
|
+
McpErrorCode.META_PAGE_SELECTION_REQUIRED,
|
|
9046
|
+
McpErrorCode.META_INVALID_PAGE,
|
|
9047
|
+
McpErrorCode.META_STAGED_ASSET_NOT_FOUND,
|
|
9048
|
+
McpErrorCode.META_STAGED_ASSET_AMBIGUOUS,
|
|
9049
|
+
McpErrorCode.META_STAGED_ASSET_TYPE_MISMATCH,
|
|
9050
|
+
McpErrorCode.META_STAGED_ASSET_INVALID,
|
|
9051
|
+
McpErrorCode.META_PUBLICATION_RECONCILIATION_REQUIRED,
|
|
9052
|
+
McpErrorCode.META_PUBLICATION_IN_PROGRESS,
|
|
8560
9053
|
McpErrorCode.TIKTOK_TOKEN_EXPIRED,
|
|
8561
9054
|
McpErrorCode.TIKTOK_PERMISSION_DENIED,
|
|
8562
9055
|
McpErrorCode.TIKTOK_MISSING_PAYMENT,
|
|
@@ -8910,53 +9403,53 @@ function renderOutputsMarkdown(outputs) {
|
|
|
8910
9403
|
__name(renderOutputsMarkdown, "renderOutputsMarkdown");
|
|
8911
9404
|
|
|
8912
9405
|
// src/tools/tasks.ts
|
|
8913
|
-
var CreateProductTaskInput =
|
|
9406
|
+
var CreateProductTaskInput = z46.object({
|
|
8914
9407
|
images: ImagesInput.optional().describe("1\u20135 fotos del mismo producto. Omitir \xFAnicamente cuando projectId apunta a un proyecto propio con imagen guardada."),
|
|
8915
|
-
projectId:
|
|
8916
|
-
productUrl:
|
|
9408
|
+
projectId: z46.string().uuid().optional().describe("Opcional. Proyecto guiado propio. Permite continuar sin volver a subir la imagen guardada; nunca evita cr\xE9ditos, cuotas ni confirmaciones."),
|
|
9409
|
+
productUrl: z46.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."),
|
|
8917
9410
|
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.'),
|
|
8918
9411
|
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.'),
|
|
8919
|
-
price:
|
|
8920
|
-
compareAtPrice:
|
|
8921
|
-
offer:
|
|
8922
|
-
paymentMethods:
|
|
8923
|
-
productContext:
|
|
8924
|
-
productLabel:
|
|
8925
|
-
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 y 30s
|
|
8926
|
-
durationSeconds:
|
|
8927
|
-
|
|
8928
|
-
|
|
9412
|
+
price: z46.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.'),
|
|
9413
|
+
compareAtPrice: z46.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".'),
|
|
9414
|
+
offer: z46.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.'),
|
|
9415
|
+
paymentMethods: z46.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.'),
|
|
9416
|
+
productContext: z46.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."),
|
|
9417
|
+
productLabel: z46.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.'),
|
|
9418
|
+
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). 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" (una regla visual experimental original), "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.'),
|
|
9419
|
+
durationSeconds: z46.union([
|
|
9420
|
+
z46.literal(15),
|
|
9421
|
+
z46.literal(30)
|
|
8929
9422
|
]).default(15).describe("Opcional. Duraci\xF3n objetivo del video: 15s (single_call, default) o 30s (Multiescena, aproximadamente 30s y facturado por escena)."),
|
|
8930
|
-
pauseForAngleReview:
|
|
9423
|
+
pauseForAngleReview: z46.boolean().optional().describe("Opcional. Si true, pausa despu\xE9s de generar el \xE1ngulo para que el usuario lo confirme o edite antes del render. \xDAsalo si quiere decidir 15/30s cuando aparezca un winner. Default false."),
|
|
8931
9424
|
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.'),
|
|
8932
9425
|
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).'),
|
|
8933
|
-
multiAngleVideos:
|
|
9426
|
+
multiAngleVideos: z46.boolean().optional().describe("Opcional. Si true, genera m\xFAltiples \xE1ngulos de venta en paralelo (3-5 videos). Si false/omitido, genera 1 video del \xE1ngulo principal. Default false."),
|
|
8934
9427
|
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". angleNarratives[i] fuerza la narrativa del \xE1ngulo i; las posiciones restantes las elige la IA. Requiere multiAngleVideos:true para varios \xE1ngulos.'),
|
|
8935
|
-
outputs:
|
|
9428
|
+
outputs: z46.array(z46.enum([
|
|
8936
9429
|
"landing",
|
|
8937
9430
|
"video",
|
|
8938
9431
|
"image"
|
|
8939
9432
|
])).min(2).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). Para 1 solo output, usa generate_landing / generate_video_creative / generate_image_creatives.'),
|
|
8940
|
-
competitorScanEnabled:
|
|
8941
|
-
brandId:
|
|
8942
|
-
actorId:
|
|
8943
|
-
creativeDirection:
|
|
8944
|
-
headline:
|
|
8945
|
-
subheadline:
|
|
9433
|
+
competitorScanEnabled: z46.boolean().optional().describe("Opcional. Si true (default), el sistema analiza ads de competencia en Meta Ad Library y enriquece los \xE1ngulos generados con hooks y painPoints validados por el mercado (\u2248$0.20-0.48 extra por task \u2014 var\xEDa con cu\xE1ntas transcripciones de video se capturen). Si false, el pipeline genera \xE1ngulos sin esa se\xF1al \u2014 usa esto SOLO si el usuario ya tiene su propia investigaci\xF3n de mercado o quiere ahorrar costos en productos muy nicho sin presencia en Meta. Default true."),
|
|
9434
|
+
brandId: z46.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."),
|
|
9435
|
+
actorId: z46.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."),
|
|
9436
|
+
creativeDirection: z46.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.'),
|
|
9437
|
+
headline: z46.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."),
|
|
9438
|
+
subheadline: z46.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."),
|
|
8946
9439
|
landingStrategy: LandingStrategyEnum.default("classic").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".'),
|
|
8947
9440
|
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".')
|
|
8948
9441
|
}).strict();
|
|
8949
|
-
var CreateServiceVideoInput =
|
|
8950
|
-
landingUrl:
|
|
8951
|
-
additionalContext:
|
|
9442
|
+
var CreateServiceVideoInput = z46.object({
|
|
9443
|
+
landingUrl: z46.string().url().describe("URL p\xFAblica de la landing del servicio. Es suficiente para generar el video; los medios son opcionales en la web."),
|
|
9444
|
+
additionalContext: z46.string().max(3e3).optional().describe('Instrucci\xF3n natural prioritaria. Ej.: "adapta el ritmo de estos competidores", "enfatiza reservas de demos" o restricciones de claims.'),
|
|
8952
9445
|
language: Lang.describe("Idioma del video: es, en o pt."),
|
|
8953
|
-
voiceId:
|
|
8954
|
-
brandId:
|
|
8955
|
-
reviewMode:
|
|
9446
|
+
voiceId: z46.string().trim().min(1).optional().describe('Opcional. Voz de ElevenLabs para toda la narraci\xF3n. Usa "auto" para que la IA la alinee con el presentador o env\xEDa un ID concreto de la lista de voces de la web.'),
|
|
9447
|
+
brandId: z46.string().uuid().optional().describe("Marca guardada del usuario. Aplica voz, mensajes, paleta y persona predeterminada."),
|
|
9448
|
+
reviewMode: z46.enum([
|
|
8956
9449
|
"automatic",
|
|
8957
9450
|
"guided"
|
|
8958
9451
|
]).default("automatic").describe("automatic = la IA elige concepto y guion sin pausas; guided = el usuario aprueba concepto y storyboard."),
|
|
8959
|
-
videoPreset:
|
|
9452
|
+
videoPreset: z46.enum([
|
|
8960
9453
|
"auto",
|
|
8961
9454
|
"ugc_dynamic",
|
|
8962
9455
|
"ugc_how_to",
|
|
@@ -8964,35 +9457,35 @@ var CreateServiceVideoInput = z44.object({
|
|
|
8964
9457
|
"wild_card"
|
|
8965
9458
|
]).default("auto")
|
|
8966
9459
|
}).strict();
|
|
8967
|
-
var GetTaskStatusInput =
|
|
8968
|
-
taskId:
|
|
8969
|
-
waitSeconds:
|
|
8970
|
-
});
|
|
8971
|
-
var ListTasksInput =
|
|
8972
|
-
limit:
|
|
8973
|
-
offset:
|
|
8974
|
-
search:
|
|
8975
|
-
});
|
|
8976
|
-
var EditTaskDraftInput =
|
|
8977
|
-
taskId:
|
|
8978
|
-
angleIndex:
|
|
8979
|
-
angle:
|
|
8980
|
-
angle:
|
|
8981
|
-
buyerPersona:
|
|
8982
|
-
actor:
|
|
8983
|
-
actorId:
|
|
8984
|
-
gender:
|
|
9460
|
+
var GetTaskStatusInput = z46.object({
|
|
9461
|
+
taskId: z46.string().min(1),
|
|
9462
|
+
waitSeconds: z46.number().int().min(0).max(120).optional()
|
|
9463
|
+
});
|
|
9464
|
+
var ListTasksInput = z46.object({
|
|
9465
|
+
limit: z46.number().int().min(1).max(50).optional(),
|
|
9466
|
+
offset: z46.number().int().min(0).optional(),
|
|
9467
|
+
search: z46.string().optional()
|
|
9468
|
+
});
|
|
9469
|
+
var EditTaskDraftInput = z46.object({
|
|
9470
|
+
taskId: z46.string().min(1),
|
|
9471
|
+
angleIndex: z46.number().int().min(0),
|
|
9472
|
+
angle: z46.object({
|
|
9473
|
+
angle: z46.string().min(1).max(480),
|
|
9474
|
+
buyerPersona: z46.string().min(1).max(360),
|
|
9475
|
+
actor: z46.string().min(1).max(360).optional(),
|
|
9476
|
+
actorId: z46.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."),
|
|
9477
|
+
gender: z46.enum([
|
|
8985
9478
|
"female",
|
|
8986
9479
|
"male"
|
|
8987
9480
|
]).optional(),
|
|
8988
|
-
scriptNotes:
|
|
9481
|
+
scriptNotes: z46.string().max(2e3).optional()
|
|
8989
9482
|
})
|
|
8990
9483
|
});
|
|
8991
|
-
var PendingActionPayload =
|
|
8992
|
-
|
|
8993
|
-
kind:
|
|
9484
|
+
var PendingActionPayload = z46.discriminatedUnion("kind", [
|
|
9485
|
+
z46.object({
|
|
9486
|
+
kind: z46.literal("product_reference_confirmation"),
|
|
8994
9487
|
userChoice: ProductReferenceUserChoiceEnum,
|
|
8995
|
-
confirmedProductNames:
|
|
9488
|
+
confirmedProductNames: z46.array(z46.string().min(1).max(120)).min(2).max(8).optional(),
|
|
8996
9489
|
// SCOPED multi-scene opt-in — the ONLY way STANDARD ("Multiescena") is
|
|
8997
9490
|
// reachable via MCP. Valid ONLY together with userChoice='variants' (same
|
|
8998
9491
|
// product in several colors): renders one shot per color and stitches them,
|
|
@@ -9003,50 +9496,50 @@ var PendingActionPayload = z44.discriminatedUnion("kind", [
|
|
|
9003
9496
|
// safe because multi-scene IS the intended render for a color variant set,
|
|
9004
9497
|
// not a blind quality upsell. Maps to `videoTier: 'standard'` on the
|
|
9005
9498
|
// confirm call; the backend re-gates it (variants + variant_set only).
|
|
9006
|
-
useMultiSceneShowcase:
|
|
9499
|
+
useMultiSceneShowcase: z46.boolean().optional().describe('Opcional (SOLO con userChoice="variants"). true = render Multiescena: una toma por color, mostrando todas las variantes, hasta 30s. Se factura POR ESCENA (m\xE1s caro que el render normal de una sola toma) \u2014 AV\xCDSALE del mayor costo al usuario antes de activarlo. Omitir = render est\xE1ndar de una sola toma. Se ignora si userChoice no es "variants".')
|
|
9007
9500
|
}),
|
|
9008
|
-
|
|
9009
|
-
kind:
|
|
9501
|
+
z46.object({
|
|
9502
|
+
kind: z46.literal("angle_review_approval"),
|
|
9010
9503
|
// All edits are optional — empty action body just approves the
|
|
9011
9504
|
// backend-generated draft as-is. Field shapes mirror the angle-review
|
|
9012
9505
|
// request contracts in @packages/types/wizard.ts; the handler routes to
|
|
9013
9506
|
// the dedicated video/image/autopilot endpoint based on StatusResponse.kind.
|
|
9014
|
-
customAngle:
|
|
9507
|
+
customAngle: z46.string().min(1).max(480).optional(),
|
|
9015
9508
|
// Keep the shared MCP action within the strictest downstream contract:
|
|
9016
9509
|
// autopilot/image resume endpoints cap these fields at 1500 characters.
|
|
9017
|
-
painPoints:
|
|
9018
|
-
benefits:
|
|
9019
|
-
features:
|
|
9020
|
-
gapDurationSeconds:
|
|
9021
|
-
|
|
9022
|
-
|
|
9510
|
+
painPoints: z46.string().max(1500).optional(),
|
|
9511
|
+
benefits: z46.string().max(1500).optional(),
|
|
9512
|
+
features: z46.array(z46.string().min(1).max(300)).max(10).optional(),
|
|
9513
|
+
gapDurationSeconds: z46.union([
|
|
9514
|
+
z46.literal(15),
|
|
9515
|
+
z46.literal(30)
|
|
9023
9516
|
]).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.")
|
|
9024
9517
|
}),
|
|
9025
|
-
|
|
9026
|
-
kind:
|
|
9027
|
-
angleId:
|
|
9028
|
-
content:
|
|
9029
|
-
creativeDirection:
|
|
9030
|
-
actor:
|
|
9518
|
+
z46.object({
|
|
9519
|
+
kind: z46.literal("service_angle_approval"),
|
|
9520
|
+
angleId: z46.string().uuid(),
|
|
9521
|
+
content: z46.string().min(1).max(480).optional(),
|
|
9522
|
+
creativeDirection: z46.string().min(1).max(1500).optional(),
|
|
9523
|
+
actor: z46.string().min(1).max(360).optional()
|
|
9031
9524
|
}),
|
|
9032
|
-
|
|
9033
|
-
kind:
|
|
9034
|
-
voiceovers:
|
|
9035
|
-
visualDirections:
|
|
9525
|
+
z46.object({
|
|
9526
|
+
kind: z46.literal("service_script_approval"),
|
|
9527
|
+
voiceovers: z46.record(z46.string(), z46.string().min(1).max(600)).optional(),
|
|
9528
|
+
visualDirections: z46.record(z46.string(), z46.string().min(1).max(1200)).optional()
|
|
9036
9529
|
})
|
|
9037
9530
|
]);
|
|
9038
|
-
var ResolvePendingActionInput =
|
|
9039
|
-
taskId:
|
|
9531
|
+
var ResolvePendingActionInput = z46.object({
|
|
9532
|
+
taskId: z46.string().min(1),
|
|
9040
9533
|
action: PendingActionPayload
|
|
9041
9534
|
}).strict();
|
|
9042
9535
|
function resolveVariantConfirmVideoTier(action) {
|
|
9043
9536
|
return action.useMultiSceneShowcase && action.userChoice === "variants" ? "standard" : void 0;
|
|
9044
9537
|
}
|
|
9045
9538
|
__name(resolveVariantConfirmVideoTier, "resolveVariantConfirmVideoTier");
|
|
9046
|
-
var StatusForResolveSchema =
|
|
9539
|
+
var StatusForResolveSchema = z46.object({
|
|
9047
9540
|
// Metadata used to select the backend resume contract. Older API responses
|
|
9048
9541
|
// may omit these fields, so the resolver keeps the generic fallback.
|
|
9049
|
-
kind:
|
|
9542
|
+
kind: z46.enum([
|
|
9050
9543
|
"autopilot",
|
|
9051
9544
|
"video",
|
|
9052
9545
|
"image",
|
|
@@ -9054,24 +9547,24 @@ var StatusForResolveSchema = z44.object({
|
|
|
9054
9547
|
"mix",
|
|
9055
9548
|
"service"
|
|
9056
9549
|
]).optional(),
|
|
9057
|
-
selectedOutputs:
|
|
9550
|
+
selectedOutputs: z46.array(z46.enum([
|
|
9058
9551
|
"landing",
|
|
9059
9552
|
"video",
|
|
9060
9553
|
"image"
|
|
9061
9554
|
])).optional(),
|
|
9062
|
-
videoAngleCount:
|
|
9063
|
-
ugcFormat:
|
|
9555
|
+
videoAngleCount: z46.number().int().min(1).max(3).optional(),
|
|
9556
|
+
ugcFormat: z46.enum([
|
|
9064
9557
|
"single_8s",
|
|
9065
9558
|
"single_15s",
|
|
9066
9559
|
"double_30s"
|
|
9067
9560
|
]).optional(),
|
|
9068
|
-
videoStyle:
|
|
9561
|
+
videoStyle: z46.enum([
|
|
9069
9562
|
"ugc",
|
|
9070
9563
|
"cartoon_3d",
|
|
9071
9564
|
"product_only",
|
|
9072
9565
|
"ai_dynamic"
|
|
9073
9566
|
]).optional(),
|
|
9074
|
-
videoModel:
|
|
9567
|
+
videoModel: z46.enum([
|
|
9075
9568
|
"veo",
|
|
9076
9569
|
"wan",
|
|
9077
9570
|
"bytedance",
|
|
@@ -9079,26 +9572,26 @@ var StatusForResolveSchema = z44.object({
|
|
|
9079
9572
|
"grok",
|
|
9080
9573
|
"kling"
|
|
9081
9574
|
]).optional(),
|
|
9082
|
-
videoTier:
|
|
9575
|
+
videoTier: z46.enum([
|
|
9083
9576
|
"legacy",
|
|
9084
9577
|
"standard",
|
|
9085
9578
|
"pro",
|
|
9086
9579
|
"single_call"
|
|
9087
9580
|
]).optional(),
|
|
9088
|
-
videoResolution:
|
|
9581
|
+
videoResolution: z46.enum([
|
|
9089
9582
|
"480p",
|
|
9090
9583
|
"720p"
|
|
9091
9584
|
]).optional(),
|
|
9092
9585
|
narrativeStyle: NarrativeStyleEnum.optional(),
|
|
9093
|
-
pendingUserAction:
|
|
9094
|
-
kind:
|
|
9095
|
-
candidateGrouping:
|
|
9096
|
-
selectedImageUrls:
|
|
9097
|
-
proposedProductNames:
|
|
9098
|
-
customAngleDraft:
|
|
9099
|
-
painPointsDraft:
|
|
9100
|
-
benefitsDraft:
|
|
9101
|
-
featuresDraft:
|
|
9586
|
+
pendingUserAction: z46.object({
|
|
9587
|
+
kind: z46.string(),
|
|
9588
|
+
candidateGrouping: z46.string().optional(),
|
|
9589
|
+
selectedImageUrls: z46.array(z46.string()).optional(),
|
|
9590
|
+
proposedProductNames: z46.array(z46.string()).optional(),
|
|
9591
|
+
customAngleDraft: z46.string().optional(),
|
|
9592
|
+
painPointsDraft: z46.string().optional(),
|
|
9593
|
+
benefitsDraft: z46.string().optional(),
|
|
9594
|
+
featuresDraft: z46.array(z46.string()).optional(),
|
|
9102
9595
|
// Recommendation consumed only when the caller explicitly sends
|
|
9103
9596
|
// gapDurationSeconds: 30 in the angle approval action.
|
|
9104
9597
|
gapDurationChoice: GapDurationChoiceMirror.optional(),
|
|
@@ -9107,17 +9600,17 @@ var StatusForResolveSchema = z44.object({
|
|
|
9107
9600
|
// keys. `actorId` (the saved custom actor the picker stored) was silently
|
|
9108
9601
|
// dropped here, so the approval handler below could not echo it back on the
|
|
9109
9602
|
// PATCH — the selection looked accepted and reached no render.
|
|
9110
|
-
angles:
|
|
9111
|
-
id:
|
|
9112
|
-
content:
|
|
9113
|
-
creativeDirection:
|
|
9114
|
-
actor:
|
|
9115
|
-
actorId:
|
|
9603
|
+
angles: z46.array(z46.object({
|
|
9604
|
+
id: z46.string().uuid(),
|
|
9605
|
+
content: z46.string(),
|
|
9606
|
+
creativeDirection: z46.string(),
|
|
9607
|
+
actor: z46.string(),
|
|
9608
|
+
actorId: z46.string().nullable().optional()
|
|
9116
9609
|
}).passthrough()).optional(),
|
|
9117
|
-
panels:
|
|
9118
|
-
beatId:
|
|
9119
|
-
voiceover:
|
|
9120
|
-
visualDirection:
|
|
9610
|
+
panels: z46.array(z46.object({
|
|
9611
|
+
beatId: z46.string(),
|
|
9612
|
+
voiceover: z46.string(),
|
|
9613
|
+
visualDirection: z46.string()
|
|
9121
9614
|
}).passthrough()).optional()
|
|
9122
9615
|
}).optional()
|
|
9123
9616
|
}).passthrough();
|
|
@@ -9158,7 +9651,6 @@ __name(resolveStatusTaskKind, "resolveStatusTaskKind");
|
|
|
9158
9651
|
function registerTaskTools(server, api, { proxyBaseUrl = null, transport = "http" } = {}) {
|
|
9159
9652
|
server.tool("create_product_task", "Crea una tarea de producto desde fotos o desde un proyecto guiado propio. Por defecto genera los 3 outputs (landing + video + image creatives) EN UN MISMO TASK. Devuelve un taskId.\n\nINPUTS REQUERIDOS: images (1-5 fotos del MISMO producto; la primera es la hero) O projectId si el proyecto ya tiene una imagen guardada; adem\xE1s language y country.\n\nANTES de invocar, PREG\xDANTALE al usuario por price, offer y paymentMethods si no los mencion\xF3 \u2014 son inputs de alto impacto en la landing y nunca debes asumirlos. Si hay descuento, pregunta tambi\xE9n compareAtPrice. NO defaultes country/language desde el contexto del chat: preg\xFAntale expl\xEDcitamente, incluso si est\xE1 en LATAM.\n\nSi env\xEDas projectId, debe ser el proyecto propio que el usuario acaba de costear; el backend resolver\xE1 la imagen privada y conservar\xE1 todos los controles de cr\xE9ditos/confirmaci\xF3n. Si el usuario adjunta images junto con projectId, esas fotos reemplazan la referencia solo para este task.\n\nANTES de invocar, DILE CLARAMENTE qu\xE9 outputs vas a generar y que `create_product_task` los genera juntos en un mismo task.\n\nUsa SOLO valores declarados en los enums.", CreateProductTaskInput.shape, async (input) => {
|
|
9160
9653
|
try {
|
|
9161
|
-
assertVideoPresetDurationCompatibility(input.videoPreset, input.durationSeconds);
|
|
9162
9654
|
if (!input.images && !input.projectId) {
|
|
9163
9655
|
throw new Error("images es requerido salvo que env\xEDes projectId.");
|
|
9164
9656
|
}
|
|
@@ -9558,58 +10050,58 @@ __name(registerTaskTools, "registerTaskTools");
|
|
|
9558
10050
|
|
|
9559
10051
|
// src/tools/creatives.ts
|
|
9560
10052
|
import { randomUUID } from "crypto";
|
|
9561
|
-
import { z as
|
|
10053
|
+
import { z as z47 } from "zod";
|
|
9562
10054
|
var CreativeRefs = {
|
|
9563
10055
|
images: ImagesInput,
|
|
9564
10056
|
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.'),
|
|
9565
10057
|
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.'),
|
|
9566
|
-
price:
|
|
9567
|
-
offer:
|
|
9568
|
-
compareAtPrice:
|
|
9569
|
-
paymentMethods:
|
|
9570
|
-
productContext:
|
|
9571
|
-
productLabel:
|
|
9572
|
-
buyerPersona:
|
|
9573
|
-
isCombo:
|
|
9574
|
-
competitorScanEnabled:
|
|
9575
|
-
brandId:
|
|
9576
|
-
projectId:
|
|
9577
|
-
creativeDirection:
|
|
9578
|
-
headline:
|
|
9579
|
-
subheadline:
|
|
10058
|
+
price: z47.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.'),
|
|
10059
|
+
offer: z47.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.'),
|
|
10060
|
+
compareAtPrice: z47.string().min(1).max(120).optional().describe('Opcional. Precio anterior o de referencia para mostrar descuento. Ej. "$129.000" cuando price="$89.900".'),
|
|
10061
|
+
paymentMethods: z47.string().min(1).max(240).optional().describe('Opcional. M\xE9todos de pago a mostrar. Ej. "Tarjeta, PSE, Nequi, Contraentrega". Si se omite, la landing no muestra m\xE9todos de pago.'),
|
|
10062
|
+
productContext: z47.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."),
|
|
10063
|
+
productLabel: z47.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.'),
|
|
10064
|
+
buyerPersona: z47.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.'),
|
|
10065
|
+
isCombo: z47.boolean().optional().describe("Opcional. Si true, el creativo presenta el producto como combo/pack. Default false."),
|
|
10066
|
+
competitorScanEnabled: z47.boolean().optional().describe("Opcional. Si true (default), el sistema analiza ads de competencia en Meta Ad Library y enriquece los \xE1ngulos generados con hooks y painPoints validados por el mercado (\u2248$0.20-0.48 extra por task \u2014 var\xEDa con cu\xE1ntas transcripciones de video se capturen). Si false, el pipeline genera \xE1ngulos sin esa se\xF1al \u2014 usa esto SOLO si el usuario ya tiene su propia investigaci\xF3n de mercado o quiere ahorrar costos en productos muy nicho sin presencia en Meta. Default true."),
|
|
10067
|
+
brandId: z47.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."),
|
|
10068
|
+
projectId: z47.string().uuid().optional().describe("Opcional. ID de un proyecto guiado de dropshipping activo del usuario. Enlaza esta generaci\xF3n con su progreso y recompensas."),
|
|
10069
|
+
creativeDirection: z47.string().max(500).optional().describe('Opcional. Direcci\xF3n creativa en texto libre (colores, mood, estilo). M\xC1XIMA PRIORIDAD: anula marca, colores y estilo por defecto. Aplica SOLO a im\xE1genes y landing. Ej. im\xE1genes: "amarillo, azul y rojo, minimalista"; landing: "elegante, paleta fr\xEDa". Para video usa scriptNotes (ambiente/escenario). M\xE1x 500 caracteres.'),
|
|
10070
|
+
headline: z47.string().max(120).optional().describe("Opcional. Titular EXACTO a renderizar en la imagen (o en la portada de la landing). Se imprime tal cual: la IA no lo reescribe, no lo acorta y no lo traduce. \xDAsalo cuando el copy es de marca y no es negociable. M\xE1x 120 caracteres. Si lo omites, la IA escribe el titular."),
|
|
10071
|
+
subheadline: z47.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.")
|
|
9580
10072
|
};
|
|
9581
|
-
var VideoInput =
|
|
10073
|
+
var VideoInput = z47.object({
|
|
9582
10074
|
images: CreativeRefs.images,
|
|
9583
|
-
title:
|
|
9584
|
-
primaryAngle:
|
|
10075
|
+
title: z47.string().min(1).describe('T\xEDtulo corto del producto. Aparece en la primera vista del video. Ej. "Crema Anti-Edad Premium".'),
|
|
10076
|
+
primaryAngle: z47.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".'),
|
|
9585
10077
|
language: CreativeRefs.language,
|
|
9586
10078
|
country: CreativeRefs.country,
|
|
9587
|
-
aspectRatio:
|
|
10079
|
+
aspectRatio: z47.enum([
|
|
9588
10080
|
"9:16",
|
|
9589
10081
|
"16:9",
|
|
9590
10082
|
"Auto"
|
|
9591
10083
|
]).describe('Relaci\xF3n de aspecto. "9:16" = vertical (TikTok/Reels \u2014 default recomendado para ads). "16:9" = horizontal (YouTube). "Auto" = decide la IA.'),
|
|
9592
|
-
durationSeconds:
|
|
9593
|
-
|
|
9594
|
-
|
|
10084
|
+
durationSeconds: z47.union([
|
|
10085
|
+
z47.literal(15),
|
|
10086
|
+
z47.literal(30)
|
|
9595
10087
|
]).default(15).describe("Opcional. Duraci\xF3n objetivo: 15s (single_call, default) o 30s (Multiescena, aproximadamente 30s y facturado por escena)."),
|
|
9596
|
-
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 y 30s
|
|
10088
|
+
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). 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" (una regla visual experimental original), "pixar_problem" (problema animado 3D), "pixar_sassy" (producto que habla).'),
|
|
9597
10089
|
videoTier: VideoTierEnum.optional().describe('Opcional. Estilo del video. "basic" = "Realista"; para durationSeconds=30 el sistema selecciona internamente Multiescena. No se expone el tier interno directamente.'),
|
|
9598
10090
|
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).'),
|
|
9599
|
-
features:
|
|
10091
|
+
features: z47.array(z47.string()).optional().describe('Opcional. Lista de features/beneficios clave a mencionar. Ej. ["resistente al agua", "bater\xEDa 24h", "carga inal\xE1mbrica"].'),
|
|
9600
10092
|
price: CreativeRefs.price,
|
|
9601
10093
|
offer: CreativeRefs.offer,
|
|
9602
10094
|
productContext: CreativeRefs.productContext,
|
|
9603
10095
|
productLabel: CreativeRefs.productLabel,
|
|
9604
|
-
cta:
|
|
9605
|
-
scriptNotes:
|
|
9606
|
-
pauseForVideoScriptReview:
|
|
9607
|
-
pauseForAngleReview:
|
|
10096
|
+
cta: z47.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.'),
|
|
10097
|
+
scriptNotes: z47.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 \u2014 para editar el guion palabra-por-palabra, pasa `pauseForVideoScriptReview: true` y usa get_video_script / approve_video_script tras la pausa.'),
|
|
10098
|
+
pauseForVideoScriptReview: z47.boolean().optional().describe("Opcional. Si true, la tarea pausa despu\xE9s de generar el guion y antes de renderizar. \xDAsalo cuando el usuario quiera editar el guion antes de gastar cr\xE9ditos en el video. Tras la pausa: get_video_script para leerlo, approve_video_script para aprobar (con o sin ediciones). Default false."),
|
|
10099
|
+
pauseForAngleReview: z47.boolean().optional().describe("Opcional. Si true, pausa despu\xE9s de generar el \xE1ngulo para que el usuario lo confirme o edite antes del render. Default false."),
|
|
9608
10100
|
competitorScanEnabled: CreativeRefs.competitorScanEnabled,
|
|
9609
10101
|
brandId: CreativeRefs.brandId,
|
|
9610
10102
|
projectId: CreativeRefs.projectId
|
|
9611
10103
|
}).strict();
|
|
9612
|
-
var FreeVideoQualityEnum =
|
|
10104
|
+
var FreeVideoQualityEnum = z47.enum([
|
|
9613
10105
|
"economical",
|
|
9614
10106
|
"high_detail"
|
|
9615
10107
|
]);
|
|
@@ -9631,38 +10123,38 @@ var FREE_VIDEO_DURATIONS_BY_QUALITY = {
|
|
|
9631
10123
|
15
|
|
9632
10124
|
]
|
|
9633
10125
|
};
|
|
9634
|
-
var FreeVideoInput =
|
|
10126
|
+
var FreeVideoInput = z47.object({
|
|
9635
10127
|
images: ImagesInput.optional().describe("Opcional. 1-5 fotos del producto. Om\xEDtelo para generar desde texto puro."),
|
|
9636
|
-
rawPrompt:
|
|
10128
|
+
rawPrompt: z47.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."),
|
|
9637
10129
|
quality: FreeVideoQualityEnum.describe('Calidad del video: "economical" = Econ\xF3mico o "high_detail" = Alto detalle.'),
|
|
9638
|
-
durationSeconds:
|
|
10130
|
+
durationSeconds: z47.number().int().min(1).max(15).describe("Duraci\xF3n exacta. Econ\xF3mico permite 6, 8, 10 o 15s; Alto detalle permite 4, 8, 12 o 15s."),
|
|
9639
10131
|
videoResolution: VideoResolutionEnum.describe("Resoluci\xF3n del video: 480p o 720p."),
|
|
9640
|
-
generateAiMusic:
|
|
9641
|
-
addSubtitles:
|
|
9642
|
-
idempotencyKey:
|
|
10132
|
+
generateAiMusic: z47.boolean().default(false).describe("Opcional. Agrega m\xFAsica instrumental IA debajo del audio nativo. Default false."),
|
|
10133
|
+
addSubtitles: z47.boolean().default(false).describe("Opcional. Quema subt\xEDtulos usando el rawPrompt exacto. Default false."),
|
|
10134
|
+
idempotencyKey: z47.string().uuid().optional().describe("Opcional. UUID para reintentar exactamente esta misma solicitud sin crear ni cobrar otro video. Reutiliza el mismo valor si el cliente no recibi\xF3 la respuesta.")
|
|
9643
10135
|
}).strict();
|
|
9644
10136
|
var imageStyleList = ImageCreativeStyleEnum.options.join(" | ");
|
|
9645
10137
|
var archetypeList = ImageCreativeArchetypeEnum.options.join(" | ");
|
|
9646
10138
|
var visualTreatmentList = ImageCreativeVisualTreatmentEnum.options.join(" | ");
|
|
9647
10139
|
var aspectRatioList = ImageCreativeAspectRatioEnum.options.join(" | ");
|
|
9648
|
-
var ImageInput =
|
|
10140
|
+
var ImageInput = z47.object({
|
|
9649
10141
|
images: CreativeRefs.images,
|
|
9650
|
-
productTitle:
|
|
9651
|
-
primaryAngle:
|
|
10142
|
+
productTitle: z47.string().min(1).describe('Nombre del producto. Ej. "Crema Anti-Edad Premium".'),
|
|
10143
|
+
primaryAngle: z47.string().min(1).describe('\xC1ngulo de venta principal. Ej. "Reduce arrugas en 14 d\xEDas".'),
|
|
9652
10144
|
buyerPersona: CreativeRefs.buyerPersona,
|
|
9653
10145
|
language: CreativeRefs.language,
|
|
9654
10146
|
country: CreativeRefs.country,
|
|
9655
|
-
nVariants:
|
|
9656
|
-
imageModel:
|
|
10147
|
+
nVariants: z47.number().int().min(1).max(6).optional().describe("Opcional. N\xFAmero de variantes a generar (1-6). Default 3."),
|
|
10148
|
+
imageModel: z47.string().optional().describe('Opcional. Modelo de imagen. Ej. "gpt-image-2", "nano-banana-2". Om\xEDtelo para usar el default optimizado por costo/calidad.'),
|
|
9657
10149
|
imageStyle: ImageCreativeStyleEnum.optional().describe(`Opcional. Estilo del shot del producto. Valores: ${imageStyleList}. Si se omite, la IA escoge seg\xFAn el archetype.`),
|
|
9658
10150
|
creativeArchetype: ImageCreativeArchetypeEnum.optional().describe(`Opcional. Arquetipo CRO de la composici\xF3n. Valores: ${archetypeList}. Si se omite, la IA escoge seg\xFAn \xE1ngulo+oferta (ej. "offer_value_prop" cuando hay descuento, "social_proof_trust" cuando el \xE1ngulo es testimonial).`),
|
|
9659
10151
|
visualTreatment: ImageCreativeVisualTreatmentEnum.optional().describe(`Opcional. Tratamiento gr\xE1fico. Valores: ${visualTreatmentList} ("performance_product_ad" = dealer-style alto CTR para Meta/TikTok ads; "premium_dtc_carousel" = fotograf\xEDa limpia estilo Allbirds/Glossier). Si se omite, la IA escoge.`),
|
|
9660
|
-
styleMix:
|
|
10152
|
+
styleMix: z47.boolean().optional().describe("Opcional. Si true, las N variantes mezclan distintos imageStyle para A/B test. Si false/omitido, todas comparten estilo. Default false."),
|
|
9661
10153
|
aspectRatio: ImageCreativeAspectRatioEnum.optional().describe(`Opcional. Relaci\xF3n de aspecto. Valores: ${aspectRatioList}. Default "4:5" (vertical Instagram feed).`),
|
|
9662
|
-
generateAdCopy:
|
|
9663
|
-
pauseForAngleReview:
|
|
9664
|
-
features:
|
|
9665
|
-
brandColors:
|
|
10154
|
+
generateAdCopy: z47.boolean().optional().describe("Opcional. Si true, tambi\xE9n genera headline/body/CTA para el ad. Default false."),
|
|
10155
|
+
pauseForAngleReview: z47.boolean().optional().describe("Opcional. Si true, pausa despu\xE9s de generar el \xE1ngulo y antes de las im\xE1genes para que el usuario edite v\xEDa edit_task_draft. Default false."),
|
|
10156
|
+
features: z47.array(z47.string()).optional().describe('Opcional. Features/beneficios a destacar visualmente. Ej. ["resistente al agua", "ultra liviano"].'),
|
|
10157
|
+
brandColors: z47.array(z47.string()).optional().describe('Opcional. Paleta de marca en hex. Ej. ["#FF6B35", "#004E89"]. Si se omite, la IA elige seg\xFAn el producto.'),
|
|
9666
10158
|
price: CreativeRefs.price,
|
|
9667
10159
|
compareAtPrice: CreativeRefs.compareAtPrice,
|
|
9668
10160
|
offer: CreativeRefs.offer,
|
|
@@ -9676,16 +10168,16 @@ var ImageInput = z45.object({
|
|
|
9676
10168
|
headline: CreativeRefs.headline,
|
|
9677
10169
|
subheadline: CreativeRefs.subheadline
|
|
9678
10170
|
});
|
|
9679
|
-
var EditImageCreativeInput =
|
|
9680
|
-
taskId:
|
|
9681
|
-
variantIndex:
|
|
9682
|
-
instruction:
|
|
10171
|
+
var EditImageCreativeInput = z47.object({
|
|
10172
|
+
taskId: z47.string().uuid().describe("ID de la tarea de imagen ya finalizada."),
|
|
10173
|
+
variantIndex: z47.number().int().min(0).max(10).describe("\xCDndice de la variante a corregir (0 = primera imagen)."),
|
|
10174
|
+
instruction: z47.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".')
|
|
9683
10175
|
});
|
|
9684
|
-
var LandingInput =
|
|
10176
|
+
var LandingInput = z47.object({
|
|
9685
10177
|
images: CreativeRefs.images,
|
|
9686
10178
|
language: CreativeRefs.language,
|
|
9687
10179
|
country: CreativeRefs.country,
|
|
9688
|
-
salesAngle:
|
|
10180
|
+
salesAngle: z47.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.'),
|
|
9689
10181
|
buyerPersona: CreativeRefs.buyerPersona,
|
|
9690
10182
|
price: CreativeRefs.price,
|
|
9691
10183
|
compareAtPrice: CreativeRefs.compareAtPrice,
|
|
@@ -9736,7 +10228,6 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
|
|
|
9736
10228
|
});
|
|
9737
10229
|
server.tool("generate_video_creative", 'Genera UN video creativo independiente. Devuelve un taskId.\n\nREQUERIDOS: images (array de 1-5 fotos), title, primaryAngle, language, country, aspectRatio.\n\nANTES de invocar, PREG\xDANTALE al usuario por price y offer si no los mencion\xF3 \u2014 son los inputs de mayor impacto en conversi\xF3n y nunca debes asumirlos. NO defaultes country/language desde el contexto: preg\xFAntale expl\xEDcitamente. Si el usuario te dice "t\xFA elige" para price/offer, om\xEDtelos.\n\nOTROS OPCIONALES (puedes invocar sin ellos y dejar que la IA elija defaults sensatos): durationSeconds (15 o 30), videoPreset (tipo/narrativa del video), features, cta, scriptNotes (dirige el guion Y el ambiente/escenario/est\xE9tica del video, ej. "en una playa, opulento").\n\nCOMPETENCIA Y GAP REPLICATION: con videoPreset="auto" (default) y competitorScanEnabled=true (default), el sistema analiza anuncios de competencia. Si encuentra un winner de video coherente, ancla el primaryAngle y genera autom\xE1ticamente la narrativa `gap_replication` para copiar su estructura audiovisual. No la selecciones manualmente: es un resultado del an\xE1lisis. Si competitorScanEnabled=false, esta b\xFAsqueda se omite.\n\nESTILO: 15s usa "Realista" (single_call); 30s usa "Multiescena" (multi-toma, aproximadamente 30s). Multiescena se factura por escena, as\xED que avisa el costo antes de activarlo.\n\nGUION: el usuario NO escribe el guion desde cero \u2014 la IA lo redacta. Si quiere REVISARLO/EDITARLO antes de renderizar (igual que en la web), pasa `pauseForVideoScriptReview: true`; cuando la tarea quede pausada, usa get_video_script para leer las escenas, ofr\xE9celas al usuario, y llama approve_video_script con las ediciones. Para dirigir el guion ANTES de generar (sin pausar), usa scriptNotes. Para revisar el \xE1ngulo y decidir duraci\xF3n tras el an\xE1lisis de competencia, pasa `pauseForAngleReview: true` y luego resuelve `angle_review_approval` con `gapDurationSeconds`.', VideoInput.shape, async (input) => {
|
|
9738
10230
|
try {
|
|
9739
|
-
assertVideoPresetDurationCompatibility(input.videoPreset, input.durationSeconds);
|
|
9740
10231
|
const resolved = resolveVideoPreset(input.videoPreset);
|
|
9741
10232
|
const wireTier = resolveWireVideoTier(input.videoTier, input.durationSeconds);
|
|
9742
10233
|
const { videoTier: _publicTier, videoResolution: _vr, projectId, ...rest } = input;
|
|
@@ -9811,8 +10302,8 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
|
|
|
9811
10302
|
__name(registerCreativeTools, "registerCreativeTools");
|
|
9812
10303
|
|
|
9813
10304
|
// src/tools/creative-variants.ts
|
|
9814
|
-
import { z as
|
|
9815
|
-
var LandingSectionKeyEnum =
|
|
10305
|
+
import { z as z48 } from "zod";
|
|
10306
|
+
var LandingSectionKeyEnum = z48.enum([
|
|
9816
10307
|
"problem_hook",
|
|
9817
10308
|
"problem_cost",
|
|
9818
10309
|
"solution_mechanism",
|
|
@@ -9852,24 +10343,24 @@ var LandingSectionKeyEnum = z46.enum([
|
|
|
9852
10343
|
"lifestyle_fit",
|
|
9853
10344
|
"join_lifestyle"
|
|
9854
10345
|
]);
|
|
9855
|
-
var CreativeVariantKindEnum =
|
|
10346
|
+
var CreativeVariantKindEnum = z48.enum([
|
|
9856
10347
|
"video",
|
|
9857
10348
|
"image",
|
|
9858
10349
|
"landing"
|
|
9859
10350
|
]);
|
|
9860
|
-
var EstimateCreativeVariantInputBase =
|
|
9861
|
-
sourceTaskId:
|
|
10351
|
+
var EstimateCreativeVariantInputBase = z48.object({
|
|
10352
|
+
sourceTaskId: z48.string().uuid().describe("ID de la tarea original completada."),
|
|
9862
10353
|
kind: CreativeVariantKindEnum,
|
|
9863
10354
|
videoPreset: TaskCreativeVariantVideoPresetEnum.optional().describe("Opcional para video. Solo cambia el preset p\xFAblico; el servidor conserva el modelo/tier del task origen."),
|
|
9864
10355
|
videoResolution: VideoResolutionEnum.optional().describe("Opcional para video. Resoluci\xF3n del nuevo render."),
|
|
9865
|
-
nVariants:
|
|
10356
|
+
nVariants: z48.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
|
|
9866
10357
|
sectionKey: LandingSectionKeyEnum.optional().describe("Opcional para landing. Si ya conoces la secci\xF3n, evita cotizar la clasificaci\xF3n con IA."),
|
|
9867
|
-
instructions:
|
|
10358
|
+
instructions: z48.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.")
|
|
9868
10359
|
}).strict();
|
|
9869
10360
|
var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine((input, ctx) => {
|
|
9870
10361
|
if (input.kind === "video" && input.nVariants !== void 0) {
|
|
9871
10362
|
ctx.addIssue({
|
|
9872
|
-
code:
|
|
10363
|
+
code: z48.ZodIssueCode.custom,
|
|
9873
10364
|
path: [
|
|
9874
10365
|
"nVariants"
|
|
9875
10366
|
],
|
|
@@ -9879,7 +10370,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
|
|
|
9879
10370
|
if (input.kind !== "video") {
|
|
9880
10371
|
if (input.videoPreset !== void 0) {
|
|
9881
10372
|
ctx.addIssue({
|
|
9882
|
-
code:
|
|
10373
|
+
code: z48.ZodIssueCode.custom,
|
|
9883
10374
|
path: [
|
|
9884
10375
|
"videoPreset"
|
|
9885
10376
|
],
|
|
@@ -9888,7 +10379,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
|
|
|
9888
10379
|
}
|
|
9889
10380
|
if (input.videoResolution !== void 0) {
|
|
9890
10381
|
ctx.addIssue({
|
|
9891
|
-
code:
|
|
10382
|
+
code: z48.ZodIssueCode.custom,
|
|
9892
10383
|
path: [
|
|
9893
10384
|
"videoResolution"
|
|
9894
10385
|
],
|
|
@@ -9898,7 +10389,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
|
|
|
9898
10389
|
}
|
|
9899
10390
|
if (input.kind !== "image" && input.nVariants !== void 0) {
|
|
9900
10391
|
ctx.addIssue({
|
|
9901
|
-
code:
|
|
10392
|
+
code: z48.ZodIssueCode.custom,
|
|
9902
10393
|
path: [
|
|
9903
10394
|
"nVariants"
|
|
9904
10395
|
],
|
|
@@ -9908,7 +10399,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
|
|
|
9908
10399
|
if (input.kind !== "landing") {
|
|
9909
10400
|
if (input.sectionKey !== void 0) {
|
|
9910
10401
|
ctx.addIssue({
|
|
9911
|
-
code:
|
|
10402
|
+
code: z48.ZodIssueCode.custom,
|
|
9912
10403
|
path: [
|
|
9913
10404
|
"sectionKey"
|
|
9914
10405
|
],
|
|
@@ -9917,7 +10408,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
|
|
|
9917
10408
|
}
|
|
9918
10409
|
if (input.instructions !== void 0) {
|
|
9919
10410
|
ctx.addIssue({
|
|
9920
|
-
code:
|
|
10411
|
+
code: z48.ZodIssueCode.custom,
|
|
9921
10412
|
path: [
|
|
9922
10413
|
"instructions"
|
|
9923
10414
|
],
|
|
@@ -9926,31 +10417,31 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
|
|
|
9926
10417
|
}
|
|
9927
10418
|
}
|
|
9928
10419
|
});
|
|
9929
|
-
var CreateCreativeVariantInputBase =
|
|
9930
|
-
sourceTaskId:
|
|
10420
|
+
var CreateCreativeVariantInputBase = z48.object({
|
|
10421
|
+
sourceTaskId: z48.string().uuid().describe("ID de la tarea original completada."),
|
|
9931
10422
|
kind: CreativeVariantKindEnum,
|
|
9932
|
-
confirm:
|
|
9933
|
-
clientRequestId:
|
|
9934
|
-
angle:
|
|
9935
|
-
buyerPersona:
|
|
9936
|
-
scriptNotes:
|
|
9937
|
-
creativeDirection:
|
|
10423
|
+
confirm: z48.literal(true).describe("Confirmaci\xF3n expl\xEDcita del usuario despu\xE9s de mostrarle el estimado de cr\xE9ditos."),
|
|
10424
|
+
clientRequestId: z48.string().uuid().describe("UUID estable y obligatorio para esta intenci\xF3n. Reutil\xEDzalo ante timeouts o transporte ambiguo. Si la API devuelve status=error, una nueva generaci\xF3n exige otra confirmaci\xF3n y un UUID nuevo."),
|
|
10425
|
+
angle: z48.string().trim().min(1).max(500).optional().describe("\xC1ngulo nuevo para video o imagen."),
|
|
10426
|
+
buyerPersona: z48.string().trim().min(1).max(360).optional().describe("Buyer persona coherente con el \xE1ngulo."),
|
|
10427
|
+
scriptNotes: z48.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n breve del guion para una variante de video."),
|
|
10428
|
+
creativeDirection: z48.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n creativa para una variante de imagen."),
|
|
9938
10429
|
videoPreset: TaskCreativeVariantVideoPresetEnum.optional().describe("Opcional para video. Preset p\xFAblico; el servidor resuelve modelo/tier desde el task origen."),
|
|
9939
10430
|
videoResolution: VideoResolutionEnum.optional().describe("Opcional para video."),
|
|
9940
|
-
generateAiMusic:
|
|
9941
|
-
nVariants:
|
|
10431
|
+
generateAiMusic: z48.boolean().optional().describe("Opcional para video."),
|
|
10432
|
+
nVariants: z48.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
|
|
9942
10433
|
imageStyle: ImageCreativeStyleEnum.optional().describe("Opcional para imagen."),
|
|
9943
10434
|
creativeArchetype: ImageCreativeArchetypeEnum.optional().describe("Opcional para imagen."),
|
|
9944
10435
|
visualTreatment: ImageCreativeVisualTreatmentEnum.optional().describe("Opcional para imagen."),
|
|
9945
10436
|
aspectRatio: ImageCreativeAspectRatioEnum.optional().describe("Opcional para imagen."),
|
|
9946
|
-
styleMix:
|
|
10437
|
+
styleMix: z48.boolean().optional().describe("Opcional para imagen."),
|
|
9947
10438
|
sectionKey: LandingSectionKeyEnum.optional().describe("Opcional para landing. Si se omite, se clasifica con IA a partir de instructions."),
|
|
9948
|
-
instructions:
|
|
10439
|
+
instructions: z48.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.")
|
|
9949
10440
|
}).strict();
|
|
9950
10441
|
var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((input, ctx) => {
|
|
9951
10442
|
if ((input.kind === "video" || input.kind === "image") && !input.angle) {
|
|
9952
10443
|
ctx.addIssue({
|
|
9953
|
-
code:
|
|
10444
|
+
code: z48.ZodIssueCode.custom,
|
|
9954
10445
|
path: [
|
|
9955
10446
|
"angle"
|
|
9956
10447
|
],
|
|
@@ -9959,7 +10450,7 @@ var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((inp
|
|
|
9959
10450
|
}
|
|
9960
10451
|
if (input.kind === "landing" && !input.sectionKey && !input.instructions) {
|
|
9961
10452
|
ctx.addIssue({
|
|
9962
|
-
code:
|
|
10453
|
+
code: z48.ZodIssueCode.custom,
|
|
9963
10454
|
path: [
|
|
9964
10455
|
"instructions"
|
|
9965
10456
|
],
|
|
@@ -10005,7 +10496,7 @@ var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((inp
|
|
|
10005
10496
|
for (const field of fieldsByKind[input.kind]) {
|
|
10006
10497
|
if (input[field] !== void 0) {
|
|
10007
10498
|
ctx.addIssue({
|
|
10008
|
-
code:
|
|
10499
|
+
code: z48.ZodIssueCode.custom,
|
|
10009
10500
|
path: [
|
|
10010
10501
|
field
|
|
10011
10502
|
],
|
|
@@ -10122,27 +10613,27 @@ function registerCreativeVariantTools(server, api) {
|
|
|
10122
10613
|
__name(registerCreativeVariantTools, "registerCreativeVariantTools");
|
|
10123
10614
|
|
|
10124
10615
|
// src/tools/script-review.ts
|
|
10125
|
-
import { z as
|
|
10126
|
-
var GetVideoScriptInput =
|
|
10127
|
-
taskId:
|
|
10128
|
-
angleKey:
|
|
10616
|
+
import { z as z49 } from "zod";
|
|
10617
|
+
var GetVideoScriptInput = z49.object({
|
|
10618
|
+
taskId: z49.string().min(1).describe("ID de la tarea (la misma que devolvi\xF3 create_product_task / generate_video_creative)."),
|
|
10619
|
+
angleKey: z49.string().min(1).optional().describe('Clave del \xE1ngulo cuyo guion se quiere leer (formato "angle_0", "angle_1", ...). REQUERIDO para tareas multi-angle: si se omite, el backend resuelve a "angle_0" LITERAL (no "el primer pendiente"), as\xED que en multi-angle donde angle_0 ya est\xE9 aprobado/saltado obtendr\xEDas status="approved" y nunca alcanzar\xEDas el \xE1ngulo realmente pendiente. Para single-angle puede omitirse.')
|
|
10129
10620
|
}).strict();
|
|
10130
10621
|
var VIDEO_SCRIPT_APPROVAL_MAX_SCENES2 = 50;
|
|
10131
10622
|
var VIDEO_SCRIPT_APPROVAL_MAX_DIALOGUE_CHARS2 = 2e3;
|
|
10132
|
-
var ApproveSceneEdit =
|
|
10133
|
-
index:
|
|
10134
|
-
dialogue:
|
|
10623
|
+
var ApproveSceneEdit = z49.object({
|
|
10624
|
+
index: z49.number().int().nonnegative().describe("\xCDndice de la escena (0-based, mismo que devuelve get_video_script)."),
|
|
10625
|
+
dialogue: z49.string().min(1).max(VIDEO_SCRIPT_APPROVAL_MAX_DIALOGUE_CHARS2).refine((v) => v.trim().length > 0, {
|
|
10135
10626
|
message: "dialogue no puede ser s\xF3lo espacios"
|
|
10136
10627
|
}).describe("Di\xE1logo final de la escena. NO puede estar vac\xEDo ni ser s\xF3lo espacios. Puede ser el original sin cambios o la edici\xF3n del usuario.")
|
|
10137
10628
|
}).strict();
|
|
10138
|
-
var ApproveVideoScriptInput =
|
|
10139
|
-
taskId:
|
|
10140
|
-
angleKey:
|
|
10141
|
-
scenes:
|
|
10629
|
+
var ApproveVideoScriptInput = z49.object({
|
|
10630
|
+
taskId: z49.string().min(1).describe("ID de la tarea."),
|
|
10631
|
+
angleKey: z49.string().trim().min(1).max(120).optional().describe('Mismo angleKey usado en get_video_script. REQUERIDO en multi-angle (si se omite el backend resuelve a "angle_0" literal). En single-angle puede omitirse.'),
|
|
10632
|
+
scenes: z49.array(ApproveSceneEdit).min(1).max(VIDEO_SCRIPT_APPROVAL_MAX_SCENES2).describe("Escenas con los di\xE1logos finales. El backend mergea por `index` \u2014 las escenas NO incluidas conservan el di\xE1logo original. Debe haber entre 1 y 50 entradas. Para cada entrada que mandes con un dialogue distinto del original, el backend valida minWords \u2264 words \u2264 maxWords y rechaza con 400 si te sales del rango.")
|
|
10142
10633
|
}).strict();
|
|
10143
|
-
var RegenerateVideoScriptInput =
|
|
10144
|
-
taskId:
|
|
10145
|
-
angleKey:
|
|
10634
|
+
var RegenerateVideoScriptInput = z49.object({
|
|
10635
|
+
taskId: z49.string().min(1).describe("ID de la tarea."),
|
|
10636
|
+
angleKey: z49.string().min(1).describe('Clave del \xE1ngulo a regenerar. Single-angle: pasa "angle_0". Multi-angle: el mismo que devuelve get_video_script. NO se puede omitir \u2014 el backend lo exige siempre.'),
|
|
10146
10637
|
narrativeStyle: NarrativeStyleEnum.describe('Narrativa para el nuevo guion. Incluye valores hist\xF3ricos porque esta herramienta tambi\xE9n regenera tareas antiguas. REQUERIDO \u2014 el backend NO acepta "mantener la actual"; siempre tienes que elegir una. Si el usuario quiere re-rolear con la misma narrativa, pasa la que ya tiene el \xE1ngulo (la ves en get_video_script o en get_task_status).')
|
|
10147
10638
|
}).strict();
|
|
10148
10639
|
function registerScriptReviewTools(server, api) {
|
|
@@ -10182,9 +10673,9 @@ function registerScriptReviewTools(server, api) {
|
|
|
10182
10673
|
__name(registerScriptReviewTools, "registerScriptReviewTools");
|
|
10183
10674
|
|
|
10184
10675
|
// src/tools/connections.ts
|
|
10185
|
-
import { z as
|
|
10676
|
+
import { z as z50 } from "zod";
|
|
10186
10677
|
function registerConnectionTools(server, api) {
|
|
10187
|
-
server.tool("list_shopify_shops", "Lista las tiendas Shopify conectadas por este usuario. Si la lista est\xE1 vac\xEDa, dile al usuario que conecte una tienda en productmaker.app/integrations antes de intentar publicar.",
|
|
10678
|
+
server.tool("list_shopify_shops", "Lista las tiendas Shopify conectadas por este usuario. Si la lista est\xE1 vac\xEDa, dile al usuario que conecte una tienda en productmaker.app/integrations antes de intentar publicar.", z50.object({}).shape, async () => {
|
|
10188
10679
|
try {
|
|
10189
10680
|
const r = await api.getJson("/v1/shopify/shops");
|
|
10190
10681
|
return asText(r);
|
|
@@ -10192,10 +10683,10 @@ function registerConnectionTools(server, api) {
|
|
|
10192
10683
|
throw translateError(e);
|
|
10193
10684
|
}
|
|
10194
10685
|
});
|
|
10195
|
-
server.tool("list_shopify_products", 'Busca productos en una tienda Shopify conectada para elegir el target de una republicaci\xF3n. 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.',
|
|
10196
|
-
shopDomain:
|
|
10197
|
-
query:
|
|
10198
|
-
taskId:
|
|
10686
|
+
server.tool("list_shopify_products", 'Busca productos en una tienda Shopify conectada para elegir el target de una republicaci\xF3n. 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.', z50.object({
|
|
10687
|
+
shopDomain: z50.string().min(3).max(120),
|
|
10688
|
+
query: z50.string().trim().max(120).optional(),
|
|
10689
|
+
taskId: z50.string().uuid().optional()
|
|
10199
10690
|
}).shape, async ({ shopDomain, query, taskId }) => {
|
|
10200
10691
|
try {
|
|
10201
10692
|
const params = new URLSearchParams({
|
|
@@ -10209,7 +10700,7 @@ function registerConnectionTools(server, api) {
|
|
|
10209
10700
|
throw translateError(e);
|
|
10210
10701
|
}
|
|
10211
10702
|
});
|
|
10212
|
-
server.tool("list_meta_ad_accounts", "Lista las cuentas publicitarias de Meta conectadas. Si est\xE1 vac\xEDa, ind\xEDcale al usuario conectar Meta en productmaker.app/integrations.",
|
|
10703
|
+
server.tool("list_meta_ad_accounts", "Lista las cuentas publicitarias de Meta conectadas. 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.", z50.object({}).shape, async () => {
|
|
10213
10704
|
try {
|
|
10214
10705
|
const r = await api.getJson("/v1/facebook/ad-accounts");
|
|
10215
10706
|
return asText(r);
|
|
@@ -10217,7 +10708,21 @@ function registerConnectionTools(server, api) {
|
|
|
10217
10708
|
throw translateError(e);
|
|
10218
10709
|
}
|
|
10219
10710
|
});
|
|
10220
|
-
server.
|
|
10711
|
+
server.registerTool("list_meta_destinations", {
|
|
10712
|
+
description: "Lista los destinos de publicaci\xF3n de Meta del usuario: Business portfolios, cuentas publicitarias dentro de cada portfolio y Facebook Pages disponibles. 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.",
|
|
10713
|
+
inputSchema: z50.object({}).shape,
|
|
10714
|
+
_meta: {
|
|
10715
|
+
"openai/widgetAccessible": true
|
|
10716
|
+
}
|
|
10717
|
+
}, async () => {
|
|
10718
|
+
try {
|
|
10719
|
+
const r = await api.getJson("/v1/facebook/destinations");
|
|
10720
|
+
return asText(r);
|
|
10721
|
+
} catch (e) {
|
|
10722
|
+
throw translateError(e);
|
|
10723
|
+
}
|
|
10724
|
+
});
|
|
10725
|
+
server.tool("list_tiktok_advertisers", "Lista las cuentas de TikTok Ads conectadas. Si est\xE1 vac\xEDa, ind\xEDcale al usuario conectar TikTok en productmaker.app/integrations.", z50.object({}).shape, async () => {
|
|
10221
10726
|
try {
|
|
10222
10727
|
const r = await api.getJson("/v1/tiktok/advertisers");
|
|
10223
10728
|
return asText(r);
|
|
@@ -10229,9 +10734,9 @@ function registerConnectionTools(server, api) {
|
|
|
10229
10734
|
__name(registerConnectionTools, "registerConnectionTools");
|
|
10230
10735
|
|
|
10231
10736
|
// src/tools/actors.ts
|
|
10232
|
-
import { z as
|
|
10737
|
+
import { z as z51 } from "zod";
|
|
10233
10738
|
function registerActorTools(server, api) {
|
|
10234
|
-
server.tool("list_actors", "Lista los personajes guardados del usuario (personas creadas con IA que pueden protagonizar los videos e im\xE1genes). Devuelve id, nombre, descripci\xF3n, g\xE9nero y voz. 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.",
|
|
10739
|
+
server.tool("list_actors", "Lista los personajes guardados del usuario (personas creadas con IA que pueden protagonizar los videos e im\xE1genes). Devuelve id, nombre, descripci\xF3n, g\xE9nero y voz. 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.", z51.object({}).shape, async () => {
|
|
10235
10740
|
try {
|
|
10236
10741
|
const rows = await api.getJson("/v1/actors");
|
|
10237
10742
|
const actors = (Array.isArray(rows) ? rows : []).filter((actor) => actor.status === "ready").map(({ id, name, description, gender, voiceId }) => ({
|
|
@@ -10252,105 +10757,116 @@ function registerActorTools(server, api) {
|
|
|
10252
10757
|
__name(registerActorTools, "registerActorTools");
|
|
10253
10758
|
|
|
10254
10759
|
// src/tools/publish.ts
|
|
10255
|
-
import { z as
|
|
10256
|
-
var ShopifyInput =
|
|
10257
|
-
taskId:
|
|
10258
|
-
shopDomain:
|
|
10760
|
+
import { z as z52 } from "zod";
|
|
10761
|
+
var ShopifyInput = z52.object({
|
|
10762
|
+
taskId: z52.string().min(1),
|
|
10763
|
+
shopDomain: z52.string().min(1),
|
|
10259
10764
|
/** Override: number of landing images to include. Default = ALL images the
|
|
10260
10765
|
* task generated (the MCP fetches /v1/results first to count). Bounded
|
|
10261
10766
|
* generously here; the backend validates each index against
|
|
10262
10767
|
* landing.images.length and rejects out-of-range. */
|
|
10263
|
-
numLandingImages:
|
|
10264
|
-
variantIndex:
|
|
10768
|
+
numLandingImages: z52.number().int().min(1).max(20).optional(),
|
|
10769
|
+
variantIndex: z52.number().int().min(0).optional(),
|
|
10265
10770
|
/** ASK THE USER before setting: "¿Tu producto tiene variantes (talla, color, etc.)?".
|
|
10266
10771
|
* When true, the landing renders variant-picker pills; when false, it ships
|
|
10267
10772
|
* a single-option product page. Defaults to false. */
|
|
10268
|
-
showVariantPicker:
|
|
10773
|
+
showVariantPicker: z52.boolean().optional(),
|
|
10269
10774
|
/** Default `auto` updates the product previously published for this task and
|
|
10270
10775
|
* shop. Use `existing` with targetProductId to choose another product, or
|
|
10271
10776
|
* `new` only when the user explicitly wants a duplicate/new listing. */
|
|
10272
|
-
publicationMode:
|
|
10777
|
+
publicationMode: z52.enum([
|
|
10273
10778
|
"auto",
|
|
10274
10779
|
"existing",
|
|
10275
10780
|
"new"
|
|
10276
10781
|
]).optional(),
|
|
10277
10782
|
/** Shopify product GID, numeric id, or admin product URL. Required when
|
|
10278
10783
|
* publicationMode is `existing`. */
|
|
10279
|
-
targetProductId:
|
|
10784
|
+
targetProductId: z52.string().trim().min(1).max(300).optional()
|
|
10280
10785
|
});
|
|
10281
|
-
var McpCampaignConfig =
|
|
10786
|
+
var McpCampaignConfig = z52.object({
|
|
10282
10787
|
/** ALWAYS in US dollars, whatever the ad account's currency is. ProductMaker
|
|
10283
10788
|
* converts to the account currency server-side. Do NOT pre-convert: on a COP
|
|
10284
10789
|
* account the user's "60.000 al día" is `dailyBudgetUsd: 15`, not 60000. */
|
|
10285
|
-
dailyBudgetUsd:
|
|
10790
|
+
dailyBudgetUsd: z52.number().positive().optional(),
|
|
10286
10791
|
/** ISO-3166-1 alpha-2 country codes. Meta accepts max 1 (single-country
|
|
10287
10792
|
* ad set). TikTok takes only the first entry. */
|
|
10288
|
-
targetCountries:
|
|
10289
|
-
campaignName:
|
|
10793
|
+
targetCountries: z52.array(z52.string().length(2)).max(1).optional(),
|
|
10794
|
+
campaignName: z52.string().trim().min(1).max(100).optional()
|
|
10290
10795
|
});
|
|
10291
10796
|
var McpAdAccountId = MetaAdAccountId.describe('Meta ad account id. Accepts "act_1234567890" or the bare numeric id "1234567890".');
|
|
10292
|
-
var MetaInput =
|
|
10293
|
-
taskId:
|
|
10797
|
+
var MetaInput = z52.object({
|
|
10798
|
+
taskId: z52.string().min(1),
|
|
10799
|
+
/** Exact Meta Business portfolio selected from `list_meta_destinations`. */
|
|
10800
|
+
portfolioId: z52.string().trim().min(1),
|
|
10801
|
+
/** Exact Facebook Page selected from `list_meta_destinations`. */
|
|
10802
|
+
pageId: z52.string().trim().min(1),
|
|
10294
10803
|
adAccountId: McpAdAccountId,
|
|
10295
|
-
pixelId:
|
|
10296
|
-
landingUrl:
|
|
10804
|
+
pixelId: z52.string().min(1).optional(),
|
|
10805
|
+
landingUrl: z52.string().url().optional(),
|
|
10297
10806
|
/** Select which angles to publish by 0-based index. Omit to publish all
|
|
10298
10807
|
* successful angles. Example: a task with 3 angles → `[0,2]` publishes #0 + #2. */
|
|
10299
|
-
angleIndexes:
|
|
10808
|
+
angleIndexes: z52.array(z52.number().int().nonnegative()).optional(),
|
|
10300
10809
|
campaignConfig: McpCampaignConfig.optional(),
|
|
10301
10810
|
/** Override the ad's primary text (body copy). If omitted, ProductMaker
|
|
10302
10811
|
* uses the auto-generated copy attached to the task. Capped at 500 chars
|
|
10303
10812
|
* (Meta's primary-text limit). */
|
|
10304
|
-
primaryText:
|
|
10813
|
+
primaryText: z52.string().trim().min(1).max(500).optional(),
|
|
10305
10814
|
/** Optional WhatsApp number. When set, the ad button opens a WhatsApp chat
|
|
10306
10815
|
* (wa.me) instead of a landing page. */
|
|
10307
|
-
phoneNumber:
|
|
10816
|
+
phoneNumber: z52.string().min(8).max(32).optional()
|
|
10308
10817
|
});
|
|
10309
|
-
var GroupedTaskSource =
|
|
10310
|
-
type:
|
|
10311
|
-
taskId:
|
|
10312
|
-
angleIndex:
|
|
10313
|
-
videoVariant:
|
|
10818
|
+
var GroupedTaskSource = z52.object({
|
|
10819
|
+
type: z52.literal("task"),
|
|
10820
|
+
taskId: z52.string().min(1),
|
|
10821
|
+
angleIndex: z52.number().int().min(0).optional(),
|
|
10822
|
+
videoVariant: z52.enum([
|
|
10314
10823
|
"with_subtitles",
|
|
10315
10824
|
"without_subtitles"
|
|
10316
10825
|
]).optional(),
|
|
10317
|
-
imageVariantIndex:
|
|
10318
|
-
});
|
|
10319
|
-
var GroupedMediaSource =
|
|
10320
|
-
type:
|
|
10321
|
-
url:
|
|
10322
|
-
path:
|
|
10323
|
-
thumbnailUrl:
|
|
10324
|
-
thumbnailPath:
|
|
10826
|
+
imageVariantIndex: z52.number().int().min(0).optional()
|
|
10827
|
+
});
|
|
10828
|
+
var GroupedMediaSource = z52.object({
|
|
10829
|
+
type: z52.literal("media"),
|
|
10830
|
+
url: z52.string().url().optional().describe("Public HTTPS media URL. For a file on the user laptop, use request_meta_media_upload on the hosted MCP instead."),
|
|
10831
|
+
path: z52.string().min(1).optional().describe('Local file path only when this MCP runs over stdio. On the hosted MCP, call request_meta_media_upload and then use source.type="staged".'),
|
|
10832
|
+
thumbnailUrl: z52.string().url().optional(),
|
|
10833
|
+
thumbnailPath: z52.string().min(1).optional()
|
|
10325
10834
|
}).refine((value) => Boolean(value.url) !== Boolean(value.path), {
|
|
10326
10835
|
message: "media source needs exactly one of `url` or `path`"
|
|
10327
10836
|
}).refine((value) => !(value.thumbnailUrl && value.thumbnailPath), {
|
|
10328
10837
|
message: "media source needs at most one of `thumbnailUrl` or `thumbnailPath`"
|
|
10329
10838
|
});
|
|
10330
|
-
var
|
|
10331
|
-
type:
|
|
10839
|
+
var GroupedStagedMediaSource = z52.object({
|
|
10840
|
+
type: z52.literal("staged"),
|
|
10841
|
+
/** Returned by check_meta_media_upload after the user selects a local file. */
|
|
10842
|
+
stagingAssetId: z52.string().uuid(),
|
|
10843
|
+
thumbnailAssetId: z52.string().uuid().optional()
|
|
10844
|
+
});
|
|
10845
|
+
var GroupedCreative = z52.object({
|
|
10846
|
+
type: z52.enum([
|
|
10332
10847
|
"image",
|
|
10333
10848
|
"video"
|
|
10334
10849
|
]),
|
|
10335
|
-
source:
|
|
10850
|
+
source: z52.union([
|
|
10336
10851
|
GroupedTaskSource,
|
|
10337
|
-
GroupedMediaSource
|
|
10852
|
+
GroupedMediaSource,
|
|
10853
|
+
GroupedStagedMediaSource
|
|
10338
10854
|
]),
|
|
10339
|
-
title:
|
|
10340
|
-
description:
|
|
10855
|
+
title: z52.string().max(120).optional(),
|
|
10856
|
+
description: z52.string().max(500).optional(),
|
|
10341
10857
|
cta: MetaCtaType.optional(),
|
|
10342
|
-
creativeId:
|
|
10858
|
+
creativeId: z52.string().min(1).optional()
|
|
10343
10859
|
});
|
|
10344
|
-
var GroupedCampaignConfig =
|
|
10860
|
+
var GroupedCampaignConfig = z52.object({
|
|
10345
10861
|
campaignType: MetaCampaignType.default("sales"),
|
|
10346
10862
|
optimizationMode: MetaOptimizationMode.default("advantage_plus"),
|
|
10347
10863
|
budgetMode: MetaBudgetMode.default("campaign"),
|
|
10348
|
-
campaignDailyBudget:
|
|
10349
|
-
adSets:
|
|
10350
|
-
tempId:
|
|
10351
|
-
name:
|
|
10352
|
-
dailyBudget:
|
|
10353
|
-
creativeIds:
|
|
10864
|
+
campaignDailyBudget: z52.number().int().positive().optional(),
|
|
10865
|
+
adSets: z52.array(z52.object({
|
|
10866
|
+
tempId: z52.string().min(1).max(80),
|
|
10867
|
+
name: z52.string().min(1).max(100),
|
|
10868
|
+
dailyBudget: z52.number().int().positive().optional(),
|
|
10869
|
+
creativeIds: z52.array(z52.string().min(1)).min(1)
|
|
10354
10870
|
})).min(1).max(CAMPAIGN_LIMITS.MAX_AD_SETS),
|
|
10355
10871
|
/**
|
|
10356
10872
|
* Valid values are 'landing' and 'whatsapp' — there is no 'website'. This
|
|
@@ -10358,22 +10874,22 @@ var GroupedCampaignConfig = z50.object({
|
|
|
10358
10874
|
* opaque `invalid_literal` and made the WhatsApp destination — supported by
|
|
10359
10875
|
* the API since #849 — unreachable from this tool.
|
|
10360
10876
|
*/
|
|
10361
|
-
destination:
|
|
10362
|
-
|
|
10363
|
-
type:
|
|
10364
|
-
landingUrl:
|
|
10877
|
+
destination: z52.discriminatedUnion("type", [
|
|
10878
|
+
z52.object({
|
|
10879
|
+
type: z52.literal("landing"),
|
|
10880
|
+
landingUrl: z52.string().url()
|
|
10365
10881
|
}),
|
|
10366
|
-
|
|
10367
|
-
type:
|
|
10368
|
-
phoneNumber:
|
|
10882
|
+
z52.object({
|
|
10883
|
+
type: z52.literal("whatsapp"),
|
|
10884
|
+
phoneNumber: z52.string().min(8).max(32)
|
|
10369
10885
|
})
|
|
10370
10886
|
]),
|
|
10371
|
-
saveAsDefault:
|
|
10887
|
+
saveAsDefault: z52.boolean().default(false),
|
|
10372
10888
|
budgetPolicy: MetaBudgetPolicy.optional()
|
|
10373
10889
|
}).superRefine((value, ctx) => {
|
|
10374
10890
|
if (value.budgetMode === "campaign" && value.campaignDailyBudget === void 0) {
|
|
10375
10891
|
ctx.addIssue({
|
|
10376
|
-
code:
|
|
10892
|
+
code: z52.ZodIssueCode.custom,
|
|
10377
10893
|
path: [
|
|
10378
10894
|
"campaignDailyBudget"
|
|
10379
10895
|
],
|
|
@@ -10384,7 +10900,7 @@ var GroupedCampaignConfig = z50.object({
|
|
|
10384
10900
|
value.adSets.forEach((adSet, index) => {
|
|
10385
10901
|
if (adSet.dailyBudget === void 0) {
|
|
10386
10902
|
ctx.addIssue({
|
|
10387
|
-
code:
|
|
10903
|
+
code: z52.ZodIssueCode.custom,
|
|
10388
10904
|
path: [
|
|
10389
10905
|
"adSets",
|
|
10390
10906
|
index,
|
|
@@ -10396,22 +10912,26 @@ var GroupedCampaignConfig = z50.object({
|
|
|
10396
10912
|
});
|
|
10397
10913
|
}
|
|
10398
10914
|
});
|
|
10399
|
-
var PublishCreativesToMetaInputBase =
|
|
10400
|
-
creatives:
|
|
10915
|
+
var PublishCreativesToMetaInputBase = z52.object({
|
|
10916
|
+
creatives: z52.array(GroupedCreative).min(1).max(CAMPAIGN_LIMITS.MAX_CREATIVES),
|
|
10917
|
+
/** Exact Meta Business portfolio selected from `list_meta_destinations`. */
|
|
10918
|
+
portfolioId: z52.string().trim().min(1),
|
|
10919
|
+
/** Exact Facebook Page selected from `list_meta_destinations`. */
|
|
10920
|
+
pageId: z52.string().trim().min(1),
|
|
10401
10921
|
adAccountId: McpAdAccountId,
|
|
10402
|
-
pixelId:
|
|
10922
|
+
pixelId: z52.string().min(1).optional(),
|
|
10403
10923
|
/** Required unless `campaignConfig.destination` is whatsapp — see the
|
|
10404
10924
|
* superRefine below. Mirrors the API's `UploadToMetaRequest`. */
|
|
10405
|
-
landingUrl:
|
|
10406
|
-
targetCountry:
|
|
10407
|
-
campaignName:
|
|
10925
|
+
landingUrl: z52.string().url().optional(),
|
|
10926
|
+
targetCountry: z52.string().length(2),
|
|
10927
|
+
campaignName: z52.string().trim().min(1).max(100),
|
|
10408
10928
|
campaignConfig: GroupedCampaignConfig.optional()
|
|
10409
10929
|
});
|
|
10410
10930
|
var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((value, ctx) => {
|
|
10411
10931
|
const destination = value.campaignConfig?.destination;
|
|
10412
10932
|
if (destination?.type !== "whatsapp" && !value.landingUrl) {
|
|
10413
10933
|
ctx.addIssue({
|
|
10414
|
-
code:
|
|
10934
|
+
code: z52.ZodIssueCode.custom,
|
|
10415
10935
|
path: [
|
|
10416
10936
|
"landingUrl"
|
|
10417
10937
|
],
|
|
@@ -10420,7 +10940,7 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
|
|
|
10420
10940
|
}
|
|
10421
10941
|
if (destination?.type === "landing" && destination.landingUrl !== value.landingUrl) {
|
|
10422
10942
|
ctx.addIssue({
|
|
10423
|
-
code:
|
|
10943
|
+
code: z52.ZodIssueCode.custom,
|
|
10424
10944
|
path: [
|
|
10425
10945
|
"campaignConfig",
|
|
10426
10946
|
"destination",
|
|
@@ -10430,46 +10950,50 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
|
|
|
10430
10950
|
});
|
|
10431
10951
|
}
|
|
10432
10952
|
});
|
|
10433
|
-
var PresignUploadResponseSchema =
|
|
10434
|
-
uploadUrl:
|
|
10953
|
+
var PresignUploadResponseSchema = z52.object({
|
|
10954
|
+
uploadUrl: z52.string().url().refine((value) => {
|
|
10435
10955
|
const url = new URL(value);
|
|
10436
10956
|
return !url.username && !url.password && url.protocol === "https:";
|
|
10437
10957
|
}, "presigned upload URL must be HTTPS without embedded credentials"),
|
|
10438
|
-
publicUrl:
|
|
10958
|
+
publicUrl: z52.string().url().refine((value) => {
|
|
10439
10959
|
const url = new URL(value);
|
|
10440
10960
|
return !url.username && !url.password;
|
|
10441
|
-
}, "public media URL must not contain embedded credentials")
|
|
10961
|
+
}, "public media URL must not contain embedded credentials"),
|
|
10962
|
+
stagingAssetId: z52.string().uuid()
|
|
10442
10963
|
});
|
|
10443
|
-
async function uploadResolvedMedia(api, media) {
|
|
10444
|
-
if (media.url) return media.url;
|
|
10964
|
+
async function uploadResolvedMedia(api, media, assetRole) {
|
|
10445
10965
|
if (!media.buffer) throw new ResolveMediaError("INVALID_INPUT", "resolved media has no bytes");
|
|
10446
10966
|
const presigned = PresignUploadResponseSchema.parse(await api.postJson("/v1/ads/presign-upload", {
|
|
10447
10967
|
contentType: media.mimetype,
|
|
10448
10968
|
fileName: media.filename,
|
|
10449
|
-
fileSize: media.buffer.byteLength
|
|
10969
|
+
fileSize: media.buffer.byteLength,
|
|
10970
|
+
purpose: "meta_staging",
|
|
10971
|
+
assetRole
|
|
10450
10972
|
}));
|
|
10451
10973
|
await api.putBytes(presigned.uploadUrl, media.buffer, media.mimetype);
|
|
10452
|
-
return
|
|
10974
|
+
return {
|
|
10975
|
+
stagingAssetId: presigned.stagingAssetId
|
|
10976
|
+
};
|
|
10453
10977
|
}
|
|
10454
10978
|
__name(uploadResolvedMedia, "uploadResolvedMedia");
|
|
10455
|
-
async function resolveAndUploadMedia(api, ref, expectedKind, transport) {
|
|
10979
|
+
async function resolveAndUploadMedia(api, ref, expectedKind, assetRole, transport) {
|
|
10456
10980
|
const media = await resolveMediaRef(ref, {
|
|
10457
10981
|
transport,
|
|
10458
10982
|
expectedKind
|
|
10459
10983
|
});
|
|
10460
|
-
return uploadResolvedMedia(api, media);
|
|
10984
|
+
return uploadResolvedMedia(api, media, assetRole);
|
|
10461
10985
|
}
|
|
10462
10986
|
__name(resolveAndUploadMedia, "resolveAndUploadMedia");
|
|
10463
|
-
var TikTokInput =
|
|
10464
|
-
taskId:
|
|
10465
|
-
advertiserId:
|
|
10466
|
-
pixelId:
|
|
10467
|
-
landingUrl:
|
|
10468
|
-
angleIndexes:
|
|
10987
|
+
var TikTokInput = z52.object({
|
|
10988
|
+
taskId: z52.string().min(1),
|
|
10989
|
+
advertiserId: z52.string().min(1),
|
|
10990
|
+
pixelId: z52.string().min(1).optional(),
|
|
10991
|
+
landingUrl: z52.string().url().optional(),
|
|
10992
|
+
angleIndexes: z52.array(z52.number().int().nonnegative()).optional(),
|
|
10469
10993
|
campaignConfig: McpCampaignConfig.optional(),
|
|
10470
10994
|
/** Override the ad's description (TikTok's body copy). If omitted,
|
|
10471
10995
|
* ProductMaker uses the auto-generated copy attached to the task. */
|
|
10472
|
-
primaryText:
|
|
10996
|
+
primaryText: z52.string().trim().min(1).max(500).optional()
|
|
10473
10997
|
});
|
|
10474
10998
|
function registerPublishTools(server, api, opts = {}) {
|
|
10475
10999
|
const transport = opts.transport ?? "http";
|
|
@@ -10508,7 +11032,7 @@ function registerPublishTools(server, api, opts = {}) {
|
|
|
10508
11032
|
throw translateError(e);
|
|
10509
11033
|
}
|
|
10510
11034
|
});
|
|
10511
|
-
server.tool("publish_to_meta", "Crea una campa\xF1a de Meta Ads (Facebook/Instagram) desde UNA sola tarea.
|
|
11035
|
+
server.tool("publish_to_meta", "Crea una campa\xF1a de Meta Ads (Facebook/Instagram) desde UNA sola tarea. Antes llama `list_meta_destinations`, deja que el usuario elija el `portfolioId` (Business portfolio), el `adAccountId` y el `pageId` exactos, y env\xEDa esos tres valores; no adivines ni uses la primera p\xE1gina. Si quieres juntar creativos de VARIAS tareas usa `publish_creatives_to_meta`. La campa\xF1a se crea SIEMPRE PAUSED y el usuario la activa manualmente. `pixelId` es opcional. `angleIndexes` permite seleccionar \xE1ngulos. `campaignConfig` admite presupuesto en USD, pa\xEDses ISO-2 y nombre. `primaryText` permite reemplazar el copy y `phoneNumber` configura WhatsApp. Despu\xE9s usa `get_meta_campaign_status`.", MetaInput.shape, async ({ taskId, campaignConfig, primaryText, phoneNumber, ...rest }) => {
|
|
10512
11036
|
try {
|
|
10513
11037
|
const body = {
|
|
10514
11038
|
...rest
|
|
@@ -10536,7 +11060,7 @@ function registerPublishTools(server, api, opts = {}) {
|
|
|
10536
11060
|
throw translateError(e);
|
|
10537
11061
|
}
|
|
10538
11062
|
});
|
|
10539
|
-
server.tool("publish_creatives_to_meta", "Crea UNA campa\xF1a de Meta Ads
|
|
11063
|
+
server.tool("publish_creatives_to_meta", "Crea UNA campa\xF1a de Meta Ads PAUSED agrupando hasta " + CAMPAIGN_LIMITS.MAX_CREATIVES + ' creativos. Antes llama `list_meta_destinations` y pide al usuario elegir el `portfolioId`, `adAccountId` y `pageId` exactos. Para archivos en la laptop con MCP remoto: llama `request_meta_media_upload`, espera al usuario y consulta `check_meta_media_upload`; por CADA entrada de `assets[]` crea un creativo `source.type="staged"`, con `type` igual a su `mediaKind`. Si la carga fue parcial, publica s\xF3lo los assets que ese estado confirm\xF3; nunca inventes assets ni superes diez creativos. Las rutas locales s\xF3lo funcionan con MCP stdio. Los medios propios se suben temporalmente al CDN de ProductMaker y se eliminan despu\xE9s de publicar correctamente; si falla, quedan s\xF3lo para reintento y el TTL los limpia. Para videos la miniatura es opcional y ProductMaker puede generarla con FFmpeg. `campaignConfig.destination` acepta landing o WhatsApp. No actives la campa\xF1a autom\xE1ticamente.', PublishCreativesToMetaInputBase.shape, async (rawInput) => {
|
|
10540
11064
|
try {
|
|
10541
11065
|
const parsed = PublishCreativesToMetaInput.safeParse(rawInput);
|
|
10542
11066
|
if (!parsed.success) throw invalidInputFromZod(parsed.error);
|
|
@@ -10562,25 +11086,44 @@ function registerPublishTools(server, api, opts = {}) {
|
|
|
10562
11086
|
});
|
|
10563
11087
|
continue;
|
|
10564
11088
|
}
|
|
10565
|
-
|
|
11089
|
+
if (creative.source.type === "staged") {
|
|
11090
|
+
creatives.push({
|
|
11091
|
+
type: creative.type,
|
|
11092
|
+
source: {
|
|
11093
|
+
type: "media",
|
|
11094
|
+
mediaAssetId: creative.source.stagingAssetId,
|
|
11095
|
+
...creative.source.thumbnailAssetId ? {
|
|
11096
|
+
thumbnailAssetId: creative.source.thumbnailAssetId
|
|
11097
|
+
} : {}
|
|
11098
|
+
},
|
|
11099
|
+
title: creative.title,
|
|
11100
|
+
description: creative.description,
|
|
11101
|
+
cta: creative.cta,
|
|
11102
|
+
creativeId
|
|
11103
|
+
});
|
|
11104
|
+
continue;
|
|
11105
|
+
}
|
|
11106
|
+
const stagedMedia = await resolveAndUploadMedia(api, {
|
|
10566
11107
|
url: creative.source.url,
|
|
10567
11108
|
path: creative.source.path
|
|
10568
|
-
}, creative.type, transport);
|
|
10569
|
-
let
|
|
11109
|
+
}, creative.type, "media", transport);
|
|
11110
|
+
let stagedThumbnail;
|
|
10570
11111
|
if (creative.type === "video") {
|
|
10571
11112
|
if (creative.source.thumbnailUrl || creative.source.thumbnailPath) {
|
|
10572
|
-
|
|
11113
|
+
stagedThumbnail = await resolveAndUploadMedia(api, {
|
|
10573
11114
|
url: creative.source.thumbnailUrl,
|
|
10574
11115
|
path: creative.source.thumbnailPath
|
|
10575
|
-
}, "image", transport);
|
|
11116
|
+
}, "image", "thumbnail", transport);
|
|
10576
11117
|
}
|
|
10577
11118
|
}
|
|
10578
11119
|
creatives.push({
|
|
10579
11120
|
type: creative.type,
|
|
10580
11121
|
source: {
|
|
10581
11122
|
type: "media",
|
|
10582
|
-
|
|
10583
|
-
|
|
11123
|
+
mediaAssetId: stagedMedia.stagingAssetId,
|
|
11124
|
+
...stagedThumbnail ? {
|
|
11125
|
+
thumbnailAssetId: stagedThumbnail.stagingAssetId
|
|
11126
|
+
} : {}
|
|
10584
11127
|
},
|
|
10585
11128
|
title: creative.title,
|
|
10586
11129
|
description: creative.description,
|
|
@@ -10590,6 +11133,8 @@ function registerPublishTools(server, api, opts = {}) {
|
|
|
10590
11133
|
}
|
|
10591
11134
|
const r = await api.postJson("/v1/facebook/campaigns/from-tasks", {
|
|
10592
11135
|
creatives,
|
|
11136
|
+
portfolioId: input.portfolioId,
|
|
11137
|
+
pageId: input.pageId,
|
|
10593
11138
|
adAccountId: input.adAccountId,
|
|
10594
11139
|
pixelId: input.pixelId,
|
|
10595
11140
|
landingUrl: input.landingUrl,
|
|
@@ -10636,6 +11181,17 @@ function renderShopifyPublishMarkdown(r) {
|
|
|
10636
11181
|
if (r.productUrl) lines.push(`
|
|
10637
11182
|
### Producto
|
|
10638
11183
|
[Ver producto](${r.productUrl})`);
|
|
11184
|
+
if (r.needsThemeSetup) {
|
|
11185
|
+
lines.push(r.themeEditorDeepLink ? `
|
|
11186
|
+
\u26A0\uFE0F La landing est\xE1 publicada, pero falta activar el bloque Code Landing en el tema. [Abrir editor de Shopify](${r.themeEditorDeepLink}) y guardar una vez.` : "\n\u26A0\uFE0F La landing est\xE1 publicada, pero falta activar el bloque Code Landing en el tema. Abre el editor de Shopify, agrega el bloque y guarda una vez.");
|
|
11187
|
+
}
|
|
11188
|
+
if (r.tracking?.status === "migrated") {
|
|
11189
|
+
lines.push("\nTracking: \u2705 configuraci\xF3n anterior migrada autom\xE1ticamente. No necesitas editar el tema.");
|
|
11190
|
+
} else if (r.tracking?.status === "synced") {
|
|
11191
|
+
lines.push("\nTracking: \u2705 c\xF3digo manual sincronizado desde `theme.liquid` al layout de ProductMaker.");
|
|
11192
|
+
} else if (r.tracking?.status === "not_detected") {
|
|
11193
|
+
lines.push("\nTracking: \u2705 ProductMaker dej\xF3 la landing compatible con el tracking nativo de Shopify; no se encontr\xF3 c\xF3digo manual para migrar.");
|
|
11194
|
+
}
|
|
10639
11195
|
if (!r.pageUrl && !r.productUrl && r.status !== "success") {
|
|
10640
11196
|
lines.push("\n_La publicaci\xF3n a\xFAn est\xE1 proces\xE1ndose. Usa `get_task_status` para verificar progreso._");
|
|
10641
11197
|
}
|
|
@@ -10679,14 +11235,162 @@ function toTikTokCampaignConfig(cfg) {
|
|
|
10679
11235
|
}
|
|
10680
11236
|
__name(toTikTokCampaignConfig, "toTikTokCampaignConfig");
|
|
10681
11237
|
|
|
11238
|
+
// src/tools/meta-upload.ts
|
|
11239
|
+
import { z as z53 } from "zod";
|
|
11240
|
+
var MetaUploadSessionInputBase = z53.object({
|
|
11241
|
+
mediaKind: z53.enum([
|
|
11242
|
+
"image",
|
|
11243
|
+
"video",
|
|
11244
|
+
"mixed"
|
|
11245
|
+
]).default("mixed").describe("The kind of file the user will select in the upload page. Use mixed for a normal batch of image and video creatives."),
|
|
11246
|
+
assetRole: z53.enum([
|
|
11247
|
+
"media",
|
|
11248
|
+
"thumbnail"
|
|
11249
|
+
]).default("media").describe("Use media for the creative itself; thumbnail only for an image thumbnail."),
|
|
11250
|
+
maxFiles: z53.number().int().min(1).max(10).optional().describe("Optional batch limit. Use 1 for a single creative; mixed media defaults to 10.")
|
|
11251
|
+
});
|
|
11252
|
+
var OpenAiFileReference = z53.object({
|
|
11253
|
+
download_url: z53.string().url(),
|
|
11254
|
+
file_id: z53.string().min(1),
|
|
11255
|
+
mime_type: z53.string().min(1).optional(),
|
|
11256
|
+
file_name: z53.string().min(1).optional()
|
|
11257
|
+
}).strict();
|
|
11258
|
+
var MetaUploadSessionToolInputShape = {
|
|
11259
|
+
...MetaUploadSessionInputBase.shape,
|
|
11260
|
+
files: z53.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.")
|
|
11261
|
+
};
|
|
11262
|
+
var MetaUploadSessionToolInput = z53.object(MetaUploadSessionToolInputShape).superRefine((value, ctx) => {
|
|
11263
|
+
if (value.assetRole === "thumbnail" && value.mediaKind !== "image") {
|
|
11264
|
+
ctx.addIssue({
|
|
11265
|
+
code: z53.ZodIssueCode.custom,
|
|
11266
|
+
path: [
|
|
11267
|
+
"mediaKind"
|
|
11268
|
+
],
|
|
11269
|
+
message: "Meta thumbnails must be images"
|
|
11270
|
+
});
|
|
11271
|
+
}
|
|
11272
|
+
if (value.mediaKind !== "mixed" && value.maxFiles !== void 0 && value.maxFiles !== 1) {
|
|
11273
|
+
ctx.addIssue({
|
|
11274
|
+
code: z53.ZodIssueCode.custom,
|
|
11275
|
+
path: [
|
|
11276
|
+
"maxFiles"
|
|
11277
|
+
],
|
|
11278
|
+
message: "Image and video sessions accept exactly one file"
|
|
11279
|
+
});
|
|
11280
|
+
}
|
|
11281
|
+
});
|
|
11282
|
+
var MetaUploadSessionResponse2 = z53.object({
|
|
11283
|
+
sessionId: z53.string().uuid(),
|
|
11284
|
+
uploadPageUrl: z53.string().url(),
|
|
11285
|
+
mediaKind: z53.enum([
|
|
11286
|
+
"image",
|
|
11287
|
+
"video",
|
|
11288
|
+
"mixed"
|
|
11289
|
+
]),
|
|
11290
|
+
assetRole: z53.enum([
|
|
11291
|
+
"media",
|
|
11292
|
+
"thumbnail"
|
|
11293
|
+
]),
|
|
11294
|
+
maxFiles: z53.number().int().positive(),
|
|
11295
|
+
expiresAt: z53.string().datetime()
|
|
11296
|
+
});
|
|
11297
|
+
var MetaUploadStatusInput = z53.object({
|
|
11298
|
+
sessionId: z53.string().uuid().describe("The sessionId returned by request_meta_media_upload.")
|
|
11299
|
+
});
|
|
11300
|
+
var MetaUploadStatusResponse = z53.object({
|
|
11301
|
+
sessionId: z53.string().uuid(),
|
|
11302
|
+
status: z53.enum([
|
|
11303
|
+
"pending",
|
|
11304
|
+
"uploaded"
|
|
11305
|
+
]),
|
|
11306
|
+
assets: z53.array(z53.object({
|
|
11307
|
+
stagingAssetId: z53.string().uuid(),
|
|
11308
|
+
mediaKind: z53.enum([
|
|
11309
|
+
"image",
|
|
11310
|
+
"video"
|
|
11311
|
+
])
|
|
11312
|
+
})).max(10).default([]),
|
|
11313
|
+
stagingAssetId: z53.string().uuid().optional()
|
|
11314
|
+
});
|
|
11315
|
+
function uploadSessionText(result) {
|
|
11316
|
+
const mediaLabel = result.mediaKind === "mixed" ? "archivos" : result.mediaKind === "video" ? "video" : "imagen";
|
|
11317
|
+
return {
|
|
11318
|
+
content: [
|
|
11319
|
+
{
|
|
11320
|
+
type: "text",
|
|
11321
|
+
text: [
|
|
11322
|
+
`### Prepara tu ${mediaLabel} en ProductMaker`,
|
|
11323
|
+
`Usa primero el App inline de este chat. Si tu host no soporta el bridge de archivos, usa este fallback: [Abrir carga segura](${result.uploadPageUrl})`,
|
|
11324
|
+
`Puedes seleccionar hasta ${result.maxFiles} ${result.mediaKind === "mixed" ? "archivos" : "archivo"}. Cuando termine, escribe **\u201Clisto\u201D** en este chat para que ProductMaker contin\xFAe con Meta.`,
|
|
11325
|
+
`sessionId: \`${result.sessionId}\``,
|
|
11326
|
+
`Este enlace expira: ${result.expiresAt}`
|
|
11327
|
+
].join("\n\n")
|
|
11328
|
+
}
|
|
11329
|
+
]
|
|
11330
|
+
};
|
|
11331
|
+
}
|
|
11332
|
+
__name(uploadSessionText, "uploadSessionText");
|
|
11333
|
+
function registerMetaUploadTools(server, api) {
|
|
11334
|
+
server.registerTool("request_meta_media_upload", {
|
|
11335
|
+
title: "Solicitar carga segura de Meta",
|
|
11336
|
+
description: "Inicia una carga segura desde la laptop del usuario para creativos propios de Meta. Por defecto crea una sesi\xF3n `mixed` de hasta diez archivos; tambi\xE9n admite una sola imagen o video. Si el usuario adjunta una foto o video en el mismo mensaje de ChatGPT, pasa esas referencias opcionales en `files` para que el MCP App inline las consuma dentro del chat. ProductMaker conserva `files` solo como metadata del UI bridge: NO los descarga y NO los reenv\xEDa. No pidas URL CDN, ruta local, bytes ni base64. El flujo principal es el MCP App inline; el enlace externo de ProductMaker queda como fallback para hosts sin bridge de archivos. Despu\xE9s conserva el `sessionId` y llama `check_meta_media_upload`. Esta herramienta no publica ni consume cr\xE9ditos.",
|
|
11337
|
+
inputSchema: MetaUploadSessionToolInputShape,
|
|
11338
|
+
outputSchema: MetaUploadSessionResponse2,
|
|
11339
|
+
_meta: {
|
|
11340
|
+
ui: {
|
|
11341
|
+
resourceUri: META_UPLOAD_APP_RESOURCE_URI,
|
|
11342
|
+
visibility: [
|
|
11343
|
+
"model",
|
|
11344
|
+
"app"
|
|
11345
|
+
]
|
|
11346
|
+
},
|
|
11347
|
+
"openai/outputTemplate": META_UPLOAD_APP_RESOURCE_URI,
|
|
11348
|
+
"openai/widgetAccessible": true,
|
|
11349
|
+
"openai/fileParams": [
|
|
11350
|
+
"files"
|
|
11351
|
+
],
|
|
11352
|
+
"openai/toolInvocation/invoking": "Preparando carga segura\u2026",
|
|
11353
|
+
"openai/toolInvocation/invoked": "Carga segura lista"
|
|
11354
|
+
}
|
|
11355
|
+
}, async (rawInput) => {
|
|
11356
|
+
try {
|
|
11357
|
+
const input = MetaUploadSessionToolInput.parse(rawInput);
|
|
11358
|
+
const { files: _files, ...sessionInput } = input;
|
|
11359
|
+
const result = MetaUploadSessionResponse2.parse(await api.postJson("/v1/ads/meta-upload-sessions", sessionInput));
|
|
11360
|
+
return {
|
|
11361
|
+
structuredContent: result,
|
|
11362
|
+
...uploadSessionText(result)
|
|
11363
|
+
};
|
|
11364
|
+
} catch (error) {
|
|
11365
|
+
throw translateError(error);
|
|
11366
|
+
}
|
|
11367
|
+
});
|
|
11368
|
+
server.registerTool("check_meta_media_upload", {
|
|
11369
|
+
description: 'Comprueba si el usuario ya termin\xF3 de subir desde el enlace de ProductMaker. Si status=uploaded, devuelve `assets[]`; crea un creativo `source.type="staged"` por cada asset, usando su `mediaKind` como el tipo del creativo, hasta diez en el batch. Si la carga fue parcial, publica \xFAnicamente los assets que `assets[]` reporta como subidos. Conserva el `stagingAssetId` legado si aparece. Si status=pending, pide al usuario que termine; no publiques todav\xEDa.',
|
|
11370
|
+
inputSchema: MetaUploadStatusInput.shape,
|
|
11371
|
+
_meta: {
|
|
11372
|
+
"openai/widgetAccessible": true
|
|
11373
|
+
}
|
|
11374
|
+
}, async (rawInput) => {
|
|
11375
|
+
try {
|
|
11376
|
+
const input = MetaUploadStatusInput.parse(rawInput);
|
|
11377
|
+
const result = MetaUploadStatusResponse.parse(await api.getJson(`/v1/ads/meta-upload-sessions/${encodeURIComponent(input.sessionId)}`));
|
|
11378
|
+
return asText(result);
|
|
11379
|
+
} catch (error) {
|
|
11380
|
+
throw translateError(error);
|
|
11381
|
+
}
|
|
11382
|
+
});
|
|
11383
|
+
}
|
|
11384
|
+
__name(registerMetaUploadTools, "registerMetaUploadTools");
|
|
11385
|
+
|
|
10682
11386
|
// src/tools/campaigns.ts
|
|
10683
|
-
import { z as
|
|
10684
|
-
var MetaStatusInput =
|
|
10685
|
-
campaignId:
|
|
11387
|
+
import { z as z54 } from "zod";
|
|
11388
|
+
var MetaStatusInput = z54.object({
|
|
11389
|
+
campaignId: z54.string().min(1).describe("Meta campaign ID returned by publish_to_meta.")
|
|
10686
11390
|
});
|
|
10687
|
-
var TikTokStatusInput =
|
|
10688
|
-
campaignId:
|
|
10689
|
-
advertiserId:
|
|
11391
|
+
var TikTokStatusInput = z54.object({
|
|
11392
|
+
campaignId: z54.string().min(1).describe("TikTok campaign ID returned by publish_to_tiktok."),
|
|
11393
|
+
advertiserId: z54.string().min(1).describe("The same advertiserId used to publish the campaign.")
|
|
10690
11394
|
});
|
|
10691
11395
|
function registerCampaignTools(server, api) {
|
|
10692
11396
|
server.tool("get_meta_campaign_status", "Consulta el estado actual + m\xE9tricas lifetime (spend, impressions, clicks, reach) de una campa\xF1a Meta publicada. Llama esto DESPU\xC9S de `publish_to_meta` para confirmar que la campa\xF1a se cre\xF3 correctamente y para reportar performance al usuario. Es read-only \u2014 no modifica nada en Meta Ads Manager.", MetaStatusInput.shape, async (input) => {
|
|
@@ -10783,10 +11487,10 @@ function renderTikTokStatusMarkdown(r) {
|
|
|
10783
11487
|
__name(renderTikTokStatusMarkdown, "renderTikTokStatusMarkdown");
|
|
10784
11488
|
|
|
10785
11489
|
// ../../packages/product-economics/src/product-costing.ts
|
|
10786
|
-
import { z as
|
|
11490
|
+
import { z as z56 } from "zod";
|
|
10787
11491
|
|
|
10788
11492
|
// ../../packages/product-economics/src/product-costing-countries.ts
|
|
10789
|
-
import { z as
|
|
11493
|
+
import { z as z55 } from "zod";
|
|
10790
11494
|
|
|
10791
11495
|
// ../../packages/product-economics/src/product-costing-shipping-references.json
|
|
10792
11496
|
var product_costing_shipping_references_default = {
|
|
@@ -10850,21 +11554,21 @@ var product_costing_shipping_references_default = {
|
|
|
10850
11554
|
};
|
|
10851
11555
|
|
|
10852
11556
|
// ../../packages/product-economics/src/product-costing-countries.ts
|
|
10853
|
-
var ShippingReferenceSchema =
|
|
10854
|
-
reference:
|
|
10855
|
-
min:
|
|
10856
|
-
max:
|
|
10857
|
-
updatedAt:
|
|
10858
|
-
confidence:
|
|
11557
|
+
var ShippingReferenceSchema = z55.object({
|
|
11558
|
+
reference: z55.number().positive(),
|
|
11559
|
+
min: z55.number().nonnegative(),
|
|
11560
|
+
max: z55.number().positive(),
|
|
11561
|
+
updatedAt: z55.string().date(),
|
|
11562
|
+
confidence: z55.enum([
|
|
10859
11563
|
"high",
|
|
10860
11564
|
"medium",
|
|
10861
11565
|
"medium-low"
|
|
10862
11566
|
]),
|
|
10863
|
-
sources:
|
|
11567
|
+
sources: z55.array(z55.string().url().startsWith("https://")).min(1).max(3)
|
|
10864
11568
|
}).superRefine(({ reference, min, max }, context) => {
|
|
10865
11569
|
if (min > reference || reference > max) {
|
|
10866
11570
|
context.addIssue({
|
|
10867
|
-
code:
|
|
11571
|
+
code: z55.ZodIssueCode.custom,
|
|
10868
11572
|
message: "shipping_reference_outside_range",
|
|
10869
11573
|
path: [
|
|
10870
11574
|
"reference"
|
|
@@ -10872,7 +11576,7 @@ var ShippingReferenceSchema = z52.object({
|
|
|
10872
11576
|
});
|
|
10873
11577
|
}
|
|
10874
11578
|
});
|
|
10875
|
-
var SHIPPING_REFERENCES =
|
|
11579
|
+
var SHIPPING_REFERENCES = z55.record(ShippingReferenceSchema).parse(product_costing_shipping_references_default);
|
|
10876
11580
|
var PRODUCT_COSTING_COUNTRY_CODES = Object.freeze(Object.keys(SHIPPING_REFERENCES));
|
|
10877
11581
|
var SPANISH_LOCALE_COUNTRIES = /* @__PURE__ */ new Set([
|
|
10878
11582
|
"MX",
|
|
@@ -11054,18 +11758,18 @@ function getProductCostingCountryName(country) {
|
|
|
11054
11758
|
__name(getProductCostingCountryName, "getProductCostingCountryName");
|
|
11055
11759
|
|
|
11056
11760
|
// ../../packages/product-economics/src/product-costing.ts
|
|
11057
|
-
var ProductCostingInputSchema =
|
|
11058
|
-
country:
|
|
11059
|
-
supplierCost:
|
|
11060
|
-
shippingCost:
|
|
11061
|
-
returnRate:
|
|
11062
|
-
cancellationRate:
|
|
11063
|
-
adsManagerCpa:
|
|
11064
|
-
desiredMargin:
|
|
11761
|
+
var ProductCostingInputSchema = z56.object({
|
|
11762
|
+
country: z56.string().refine(isProductCostingCountryCode, "unsupported_country"),
|
|
11763
|
+
supplierCost: z56.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").positive("supplier_cost_positive"),
|
|
11764
|
+
shippingCost: z56.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("shipping_cost_nonnegative"),
|
|
11765
|
+
returnRate: z56.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
|
|
11766
|
+
cancellationRate: z56.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
|
|
11767
|
+
adsManagerCpa: z56.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("cpa_nonnegative"),
|
|
11768
|
+
desiredMargin: z56.number().finite().min(0, "margin_nonnegative").lt(1, "margin_below_one")
|
|
11065
11769
|
}).superRefine(({ returnRate, cancellationRate }, context) => {
|
|
11066
11770
|
if (returnRate + cancellationRate >= 1) {
|
|
11067
11771
|
context.addIssue({
|
|
11068
|
-
code:
|
|
11772
|
+
code: z56.ZodIssueCode.custom,
|
|
11069
11773
|
message: "delivery_rate_positive",
|
|
11070
11774
|
path: [
|
|
11071
11775
|
"cancellationRate"
|
|
@@ -11132,14 +11836,14 @@ function calculateProductCosting(rawInput) {
|
|
|
11132
11836
|
__name(calculateProductCosting, "calculateProductCosting");
|
|
11133
11837
|
|
|
11134
11838
|
// src/tools/product-costing.ts
|
|
11135
|
-
import { z as
|
|
11136
|
-
var optionalAmount = /* @__PURE__ */ __name((description) =>
|
|
11137
|
-
var optionalPercent = /* @__PURE__ */ __name((description) =>
|
|
11138
|
-
var ProductCostingToolInput =
|
|
11139
|
-
country:
|
|
11839
|
+
import { z as z57 } from "zod";
|
|
11840
|
+
var optionalAmount = /* @__PURE__ */ __name((description) => z57.number().finite().max(Number.MAX_SAFE_INTEGER).nonnegative().optional().describe(description), "optionalAmount");
|
|
11841
|
+
var optionalPercent = /* @__PURE__ */ __name((description) => z57.number().finite().min(0).lt(100).optional().describe(description), "optionalPercent");
|
|
11842
|
+
var ProductCostingToolInput = z57.object({
|
|
11843
|
+
country: z57.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
|
|
11140
11844
|
message: "Pa\xEDs no soportado por ProductMaker."
|
|
11141
11845
|
}).optional().describe("C\xF3digo ISO-2 de cualquiera de los pa\xEDses disponibles en ProductMaker. Omite para Colombia."),
|
|
11142
|
-
supplierCost:
|
|
11846
|
+
supplierCost: z57.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."),
|
|
11143
11847
|
supplierCostCop: optionalAmount("Alias anterior para costo del proveedor en Colombia. Prefiere supplierCost."),
|
|
11144
11848
|
shippingCost: optionalAmount("Costo de un env\xEDo en la moneda del pa\xEDs. Omite para usar el valor gu\xEDa vigente."),
|
|
11145
11849
|
shippingCostCop: optionalAmount("Alias anterior para flete en Colombia. Prefiere shippingCost."),
|
|
@@ -11271,7 +11975,7 @@ function formatPercent(value) {
|
|
|
11271
11975
|
__name(formatPercent, "formatPercent");
|
|
11272
11976
|
|
|
11273
11977
|
// src/tools/product-research.ts
|
|
11274
|
-
import { z as
|
|
11978
|
+
import { z as z58 } from "zod";
|
|
11275
11979
|
|
|
11276
11980
|
// src/tools/product-research-idempotency.ts
|
|
11277
11981
|
import { createHash as createHash2 } from "crypto";
|
|
@@ -11387,17 +12091,17 @@ var TERMINAL2 = /* @__PURE__ */ new Set([
|
|
|
11387
12091
|
]);
|
|
11388
12092
|
var POLL_INTERVAL_MS = 5e3;
|
|
11389
12093
|
var MAX_WAIT_SECONDS = 120;
|
|
11390
|
-
var FindInput =
|
|
12094
|
+
var FindInput = z58.object({
|
|
11391
12095
|
targetCountry: ResearchTargetCountryEnum.describe("Pa\xEDs objetivo. S\xF3lo CO, MX, PE, EC y CL tienen cobertura de investigaci\xF3n."),
|
|
11392
12096
|
categoryKey: ResearchCategoryEnum.default("auto").describe('Categor\xEDa a investigar. Usa "auto" para que la IA elija seg\xFAn el mercado.'),
|
|
11393
|
-
confirmed:
|
|
11394
|
-
waitSeconds:
|
|
12097
|
+
confirmed: z58.boolean().describe(`Ponlo en true SOLO despu\xE9s de que el usuario haya aceptado el cargo de ${PRICE_CREDITS} cr\xE9ditos. No lo asumas.`),
|
|
12098
|
+
waitSeconds: z58.number().int().min(0).max(MAX_WAIT_SECONDS).optional().describe("Segundos a esperar el reporte antes de devolver el runId. M\xE1ximo 120.")
|
|
11395
12099
|
});
|
|
11396
|
-
var GetInput =
|
|
11397
|
-
runId:
|
|
12100
|
+
var GetInput = z58.object({
|
|
12101
|
+
runId: z58.string().uuid().describe("ID del run devuelto por find_winning_products.")
|
|
11398
12102
|
});
|
|
11399
|
-
var ListInput =
|
|
11400
|
-
limit:
|
|
12103
|
+
var ListInput = z58.object({
|
|
12104
|
+
limit: z58.number().int().min(1).max(20).default(10)
|
|
11401
12105
|
});
|
|
11402
12106
|
function textResult(text) {
|
|
11403
12107
|
return {
|
|
@@ -11489,14 +12193,14 @@ _Esta llamada no cobr\xF3 cr\xE9ditos: se reutiliz\xF3 una investigaci\xF3n reci
|
|
|
11489
12193
|
__name(registerProductResearchTools, "registerProductResearchTools");
|
|
11490
12194
|
|
|
11491
12195
|
// src/tools/dropshipping-projects.ts
|
|
11492
|
-
import { z as
|
|
11493
|
-
var ProjectId =
|
|
11494
|
-
var DropshippingProjectStatus =
|
|
12196
|
+
import { z as z59 } from "zod";
|
|
12197
|
+
var ProjectId = z59.string().uuid();
|
|
12198
|
+
var DropshippingProjectStatus = z59.enum([
|
|
11495
12199
|
"active",
|
|
11496
12200
|
"completed",
|
|
11497
12201
|
"archived"
|
|
11498
12202
|
]);
|
|
11499
|
-
var DropshippingProjectPhase =
|
|
12203
|
+
var DropshippingProjectPhase = z59.enum([
|
|
11500
12204
|
"research",
|
|
11501
12205
|
"costing",
|
|
11502
12206
|
"media",
|
|
@@ -11505,21 +12209,21 @@ var DropshippingProjectPhase = z56.enum([
|
|
|
11505
12209
|
"advertising",
|
|
11506
12210
|
"complete"
|
|
11507
12211
|
]);
|
|
11508
|
-
var DropshippingRewardMilestone =
|
|
12212
|
+
var DropshippingRewardMilestone = z59.enum([
|
|
11509
12213
|
"product_selected",
|
|
11510
12214
|
"costing_saved",
|
|
11511
12215
|
"product_media_ready",
|
|
11512
12216
|
"creatives_completed",
|
|
11513
12217
|
"campaign_created"
|
|
11514
12218
|
]);
|
|
11515
|
-
var TargetCountry =
|
|
12219
|
+
var TargetCountry = z59.enum([
|
|
11516
12220
|
"CO",
|
|
11517
12221
|
"MX",
|
|
11518
12222
|
"PE",
|
|
11519
12223
|
"EC",
|
|
11520
12224
|
"CL"
|
|
11521
12225
|
]);
|
|
11522
|
-
var ResearchCategory =
|
|
12226
|
+
var ResearchCategory = z59.enum([
|
|
11523
12227
|
"auto",
|
|
11524
12228
|
"automotive",
|
|
11525
12229
|
"kitchen",
|
|
@@ -11534,7 +12238,7 @@ var ResearchCategory = z56.enum([
|
|
|
11534
12238
|
"garden",
|
|
11535
12239
|
"cleaning"
|
|
11536
12240
|
]);
|
|
11537
|
-
var HttpUrl3 =
|
|
12241
|
+
var HttpUrl3 = z59.string().url().max(2e3).refine((value) => {
|
|
11538
12242
|
try {
|
|
11539
12243
|
return [
|
|
11540
12244
|
"http:",
|
|
@@ -11544,46 +12248,46 @@ var HttpUrl3 = z56.string().url().max(2e3).refine((value) => {
|
|
|
11544
12248
|
return false;
|
|
11545
12249
|
}
|
|
11546
12250
|
}, "URL must use HTTP(S)");
|
|
11547
|
-
var ResearchCandidateOrigin =
|
|
11548
|
-
type:
|
|
12251
|
+
var ResearchCandidateOrigin = z59.object({
|
|
12252
|
+
type: z59.literal("research_candidate"),
|
|
11549
12253
|
runId: ProjectId,
|
|
11550
|
-
candidateSourceId:
|
|
12254
|
+
candidateSourceId: z59.string().min(1).max(160)
|
|
11551
12255
|
});
|
|
11552
|
-
var TaskOrigin =
|
|
11553
|
-
type:
|
|
12256
|
+
var TaskOrigin = z59.object({
|
|
12257
|
+
type: z59.literal("task"),
|
|
11554
12258
|
taskId: ProjectId
|
|
11555
12259
|
});
|
|
11556
|
-
var ManualOrigin =
|
|
11557
|
-
type:
|
|
12260
|
+
var ManualOrigin = z59.object({
|
|
12261
|
+
type: z59.literal("manual"),
|
|
11558
12262
|
clientRequestId: ProjectId,
|
|
11559
|
-
country:
|
|
12263
|
+
country: z59.string().min(2).max(3).optional()
|
|
11560
12264
|
});
|
|
11561
|
-
var StartProjectInput =
|
|
11562
|
-
origin:
|
|
12265
|
+
var StartProjectInput = z59.object({
|
|
12266
|
+
origin: z59.discriminatedUnion("type", [
|
|
11563
12267
|
ResearchCandidateOrigin,
|
|
11564
12268
|
TaskOrigin,
|
|
11565
12269
|
ManualOrigin
|
|
11566
12270
|
]),
|
|
11567
|
-
productName:
|
|
12271
|
+
productName: z59.string().trim().min(1).max(240).optional(),
|
|
11568
12272
|
productUrl: HttpUrl3.optional(),
|
|
11569
|
-
country:
|
|
11570
|
-
languageCode:
|
|
12273
|
+
country: z59.string().min(2).max(3).optional(),
|
|
12274
|
+
languageCode: z59.string().min(2).max(16).optional()
|
|
11571
12275
|
}).strict();
|
|
11572
|
-
var CostProjectInput =
|
|
12276
|
+
var CostProjectInput = z59.object({
|
|
11573
12277
|
projectId: ProjectId,
|
|
11574
|
-
version:
|
|
11575
|
-
country:
|
|
11576
|
-
supplierCost:
|
|
11577
|
-
shippingCost:
|
|
11578
|
-
returnRate:
|
|
11579
|
-
cancellationRate:
|
|
11580
|
-
adsManagerCpa:
|
|
11581
|
-
desiredMargin:
|
|
11582
|
-
});
|
|
11583
|
-
var GuideInput =
|
|
12278
|
+
version: z59.number().int().positive(),
|
|
12279
|
+
country: z59.string().trim().min(2).max(3),
|
|
12280
|
+
supplierCost: z59.number().finite().positive(),
|
|
12281
|
+
shippingCost: z59.number().finite().nonnegative(),
|
|
12282
|
+
returnRate: z59.number().finite().min(0).lt(1),
|
|
12283
|
+
cancellationRate: z59.number().finite().min(0).lt(1),
|
|
12284
|
+
adsManagerCpa: z59.number().finite().nonnegative(),
|
|
12285
|
+
desiredMargin: z59.number().finite().min(0).lt(1)
|
|
12286
|
+
});
|
|
12287
|
+
var GuideInput = z59.object({
|
|
11584
12288
|
projectId: ProjectId.optional()
|
|
11585
12289
|
}).strict();
|
|
11586
|
-
var DropshippingProjectNextAction =
|
|
12290
|
+
var DropshippingProjectNextAction = z59.discriminatedUnion("kind", [
|
|
11587
12291
|
"cost_product",
|
|
11588
12292
|
"provide_product_media",
|
|
11589
12293
|
"generate_creatives",
|
|
@@ -11597,78 +12301,78 @@ var DropshippingProjectNextAction = z56.discriminatedUnion("kind", [
|
|
|
11597
12301
|
"create_meta_campaign",
|
|
11598
12302
|
"repair_meta_campaign",
|
|
11599
12303
|
"review_paused_campaign"
|
|
11600
|
-
].map((kind) =>
|
|
11601
|
-
kind:
|
|
11602
|
-
href:
|
|
12304
|
+
].map((kind) => z59.object({
|
|
12305
|
+
kind: z59.literal(kind),
|
|
12306
|
+
href: z59.string().min(1)
|
|
11603
12307
|
})));
|
|
11604
|
-
var CostingInputSchema =
|
|
11605
|
-
country:
|
|
11606
|
-
supplierCost:
|
|
11607
|
-
shippingCost:
|
|
11608
|
-
returnRate:
|
|
11609
|
-
cancellationRate:
|
|
11610
|
-
adsManagerCpa:
|
|
11611
|
-
desiredMargin:
|
|
12308
|
+
var CostingInputSchema = z59.object({
|
|
12309
|
+
country: z59.string().min(2).max(3),
|
|
12310
|
+
supplierCost: z59.number().finite().positive(),
|
|
12311
|
+
shippingCost: z59.number().finite().nonnegative(),
|
|
12312
|
+
returnRate: z59.number().finite().min(0).lt(1),
|
|
12313
|
+
cancellationRate: z59.number().finite().min(0).lt(1),
|
|
12314
|
+
adsManagerCpa: z59.number().finite().nonnegative(),
|
|
12315
|
+
desiredMargin: z59.number().finite().min(0).lt(1)
|
|
11612
12316
|
}).superRefine(({ returnRate, cancellationRate }, context) => {
|
|
11613
12317
|
if (returnRate + cancellationRate >= 1) context.addIssue({
|
|
11614
|
-
code:
|
|
12318
|
+
code: z59.ZodIssueCode.custom,
|
|
11615
12319
|
path: [
|
|
11616
12320
|
"cancellationRate"
|
|
11617
12321
|
]
|
|
11618
12322
|
});
|
|
11619
12323
|
});
|
|
11620
|
-
var CostingResultSchema =
|
|
11621
|
-
country:
|
|
11622
|
-
deliveryRate:
|
|
11623
|
-
adjustedShippingCost:
|
|
11624
|
-
adjustedCpa:
|
|
11625
|
-
totalCost:
|
|
11626
|
-
suggestedPrice:
|
|
11627
|
-
baseCommercialPrice:
|
|
11628
|
-
minimumSafePrice:
|
|
11629
|
-
commercialPrice:
|
|
11630
|
-
comparisonPrice:
|
|
11631
|
-
estimatedProfit:
|
|
11632
|
-
actualMargin:
|
|
11633
|
-
breakEvenAdsManagerCpa:
|
|
11634
|
-
wasPriceAutoAdjusted:
|
|
11635
|
-
profitabilityStatus:
|
|
11636
|
-
});
|
|
11637
|
-
var RewardProgressSchema =
|
|
11638
|
-
campaignKey:
|
|
11639
|
-
totalCredits:
|
|
11640
|
-
earnedCredits:
|
|
11641
|
-
milestones:
|
|
12324
|
+
var CostingResultSchema = z59.object({
|
|
12325
|
+
country: z59.string().min(2).max(3),
|
|
12326
|
+
deliveryRate: z59.number().finite(),
|
|
12327
|
+
adjustedShippingCost: z59.number().finite(),
|
|
12328
|
+
adjustedCpa: z59.number().finite(),
|
|
12329
|
+
totalCost: z59.number().finite(),
|
|
12330
|
+
suggestedPrice: z59.number().finite(),
|
|
12331
|
+
baseCommercialPrice: z59.number().finite(),
|
|
12332
|
+
minimumSafePrice: z59.number().finite(),
|
|
12333
|
+
commercialPrice: z59.number().finite(),
|
|
12334
|
+
comparisonPrice: z59.number().finite(),
|
|
12335
|
+
estimatedProfit: z59.number().finite(),
|
|
12336
|
+
actualMargin: z59.number().finite(),
|
|
12337
|
+
breakEvenAdsManagerCpa: z59.number().finite(),
|
|
12338
|
+
wasPriceAutoAdjusted: z59.boolean(),
|
|
12339
|
+
profitabilityStatus: z59.literal("healthy")
|
|
12340
|
+
});
|
|
12341
|
+
var RewardProgressSchema = z59.object({
|
|
12342
|
+
campaignKey: z59.literal("dropshipping-launch-v1"),
|
|
12343
|
+
totalCredits: z59.number().int().positive(),
|
|
12344
|
+
earnedCredits: z59.number().int().nonnegative(),
|
|
12345
|
+
milestones: z59.array(z59.object({
|
|
11642
12346
|
milestone: DropshippingRewardMilestone,
|
|
11643
|
-
credits:
|
|
11644
|
-
available:
|
|
11645
|
-
earned:
|
|
12347
|
+
credits: z59.number().int().positive(),
|
|
12348
|
+
available: z59.boolean().optional(),
|
|
12349
|
+
earned: z59.boolean(),
|
|
11646
12350
|
grantId: ProjectId.nullable(),
|
|
11647
|
-
grantedAt:
|
|
12351
|
+
grantedAt: z59.string().datetime().nullable()
|
|
11648
12352
|
})).length(DropshippingRewardMilestone.options.length)
|
|
11649
12353
|
});
|
|
11650
|
-
var ProjectResponseSchema =
|
|
12354
|
+
var ProjectResponseSchema = z59.object({
|
|
11651
12355
|
id: ProjectId,
|
|
11652
12356
|
taskId: ProjectId.nullable(),
|
|
11653
12357
|
status: DropshippingProjectStatus,
|
|
11654
|
-
originKey:
|
|
12358
|
+
originKey: z59.string().min(1),
|
|
11655
12359
|
researchRunId: ProjectId.nullable(),
|
|
11656
|
-
candidateSourceId:
|
|
11657
|
-
productName:
|
|
12360
|
+
candidateSourceId: z59.string().nullable(),
|
|
12361
|
+
productName: z59.string().nullable(),
|
|
11658
12362
|
productUrl: HttpUrl3.nullable(),
|
|
11659
12363
|
referenceImageUrl: HttpUrl3.nullable(),
|
|
11660
|
-
targetCountry:
|
|
11661
|
-
languageCode:
|
|
11662
|
-
hasReferenceImage:
|
|
12364
|
+
targetCountry: z59.string().nullable(),
|
|
12365
|
+
languageCode: z59.string().nullable(),
|
|
12366
|
+
hasReferenceImage: z59.boolean(),
|
|
11663
12367
|
costingInput: CostingInputSchema.nullable(),
|
|
11664
12368
|
costingResult: CostingResultSchema.nullable(),
|
|
11665
|
-
costingVersion:
|
|
11666
|
-
version:
|
|
12369
|
+
costingVersion: z59.number().int().positive().nullable(),
|
|
12370
|
+
version: z59.number().int().positive(),
|
|
11667
12371
|
phase: DropshippingProjectPhase,
|
|
11668
12372
|
nextAction: DropshippingProjectNextAction.nullable(),
|
|
11669
12373
|
rewards: RewardProgressSchema,
|
|
11670
|
-
createdAt:
|
|
11671
|
-
updatedAt:
|
|
12374
|
+
createdAt: z59.string().datetime(),
|
|
12375
|
+
updatedAt: z59.string().datetime()
|
|
11672
12376
|
}).passthrough();
|
|
11673
12377
|
function projectText(raw) {
|
|
11674
12378
|
const project = ProjectResponseSchema.parse(raw);
|
|
@@ -11753,6 +12457,7 @@ function createServer(opts) {
|
|
|
11753
12457
|
}
|
|
11754
12458
|
});
|
|
11755
12459
|
const api = new ApiClient(apiBaseUrl, apiKey);
|
|
12460
|
+
registerMetaUploadAppResource(server);
|
|
11756
12461
|
registerProductCostingTools(server);
|
|
11757
12462
|
registerProductResearchTools(server, api);
|
|
11758
12463
|
registerDropshippingProjectTools(server, api);
|
|
@@ -11770,6 +12475,7 @@ function createServer(opts) {
|
|
|
11770
12475
|
registerPublishTools(server, api, {
|
|
11771
12476
|
transport
|
|
11772
12477
|
});
|
|
12478
|
+
registerMetaUploadTools(server, api);
|
|
11773
12479
|
registerCampaignTools(server, api);
|
|
11774
12480
|
return server;
|
|
11775
12481
|
}
|