@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/http.js
CHANGED
|
@@ -153,10 +153,60 @@ var ApiClient = class {
|
|
|
153
153
|
};
|
|
154
154
|
|
|
155
155
|
// src/index.ts
|
|
156
|
-
var MCP_VERSION = "2.
|
|
156
|
+
var MCP_VERSION = "2.9.1";
|
|
157
|
+
|
|
158
|
+
// src/meta-upload-app.ts
|
|
159
|
+
import { readFileSync } from "fs";
|
|
160
|
+
import { registerAppResource, RESOURCE_MIME_TYPE } from "@modelcontextprotocol/ext-apps/server";
|
|
161
|
+
var META_UPLOAD_APP_RESOURCE_URI = "ui://meta-upload/v1.html";
|
|
162
|
+
var META_UPLOAD_APP_NAME = "Meta upload app";
|
|
163
|
+
var META_UPLOAD_APP_HTML_URL = new URL("./ui/meta-upload-app.html", import.meta.url);
|
|
164
|
+
var META_UPLOAD_APP_CSP = {
|
|
165
|
+
connectDomains: [
|
|
166
|
+
"https://productmaker.app",
|
|
167
|
+
"https://www.productmaker.app",
|
|
168
|
+
"https://*.r2.cloudflarestorage.com",
|
|
169
|
+
"https://*.oaiusercontent.com"
|
|
170
|
+
]
|
|
171
|
+
};
|
|
172
|
+
function readMetaUploadAppHtml(htmlUrl = META_UPLOAD_APP_HTML_URL) {
|
|
173
|
+
try {
|
|
174
|
+
return readFileSync(htmlUrl, "utf8");
|
|
175
|
+
} catch (error) {
|
|
176
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
177
|
+
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}`);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
__name(readMetaUploadAppHtml, "readMetaUploadAppHtml");
|
|
181
|
+
function registerMetaUploadAppResource(server) {
|
|
182
|
+
const html = readMetaUploadAppHtml();
|
|
183
|
+
registerAppResource(server, META_UPLOAD_APP_NAME, META_UPLOAD_APP_RESOURCE_URI, {
|
|
184
|
+
title: "Meta upload app",
|
|
185
|
+
mimeType: RESOURCE_MIME_TYPE,
|
|
186
|
+
_meta: {
|
|
187
|
+
ui: {
|
|
188
|
+
csp: META_UPLOAD_APP_CSP
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
}, async () => ({
|
|
192
|
+
contents: [
|
|
193
|
+
{
|
|
194
|
+
uri: META_UPLOAD_APP_RESOURCE_URI,
|
|
195
|
+
mimeType: RESOURCE_MIME_TYPE,
|
|
196
|
+
text: html,
|
|
197
|
+
_meta: {
|
|
198
|
+
ui: {
|
|
199
|
+
csp: META_UPLOAD_APP_CSP
|
|
200
|
+
}
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
]
|
|
204
|
+
}));
|
|
205
|
+
}
|
|
206
|
+
__name(registerMetaUploadAppResource, "registerMetaUploadAppResource");
|
|
157
207
|
|
|
158
208
|
// src/tools/tasks.ts
|
|
159
|
-
import { z as
|
|
209
|
+
import { z as z46 } from "zod";
|
|
160
210
|
|
|
161
211
|
// src/resolve-image.ts
|
|
162
212
|
import { lookup as dnsLookup } from "dns/promises";
|
|
@@ -2256,6 +2306,25 @@ var ShopifyPublicationStatus = z19.enum([
|
|
|
2256
2306
|
"success",
|
|
2257
2307
|
"error"
|
|
2258
2308
|
]);
|
|
2309
|
+
var ShopifyTrackingSyncStatus = z19.enum([
|
|
2310
|
+
"synced",
|
|
2311
|
+
"migrated",
|
|
2312
|
+
"not_detected"
|
|
2313
|
+
]);
|
|
2314
|
+
var ShopifyTrackingSource = z19.enum([
|
|
2315
|
+
"theme",
|
|
2316
|
+
"legacy_layout",
|
|
2317
|
+
"theme_and_legacy",
|
|
2318
|
+
"none"
|
|
2319
|
+
]);
|
|
2320
|
+
var ShopifyTrackingResult = z19.object({
|
|
2321
|
+
status: ShopifyTrackingSyncStatus,
|
|
2322
|
+
manualCodeDetected: z19.boolean(),
|
|
2323
|
+
/** True when code from a prior ProductMaker layout was preserved automatically. */
|
|
2324
|
+
legacyCodeMigrated: z19.boolean().default(false),
|
|
2325
|
+
source: ShopifyTrackingSource.default("none"),
|
|
2326
|
+
syncedAt: z19.string().datetime()
|
|
2327
|
+
});
|
|
2259
2328
|
var ShopifyPublishResponse = z19.object({
|
|
2260
2329
|
publicationId: z19.string().uuid(),
|
|
2261
2330
|
taskId: z19.string().uuid(),
|
|
@@ -2271,6 +2340,8 @@ var ShopifyPublishResponse = z19.object({
|
|
|
2271
2340
|
needsThemeSetup: z19.boolean().optional(),
|
|
2272
2341
|
/** One-click theme-editor deep link to add the Code Landing block (when needsThemeSetup). */
|
|
2273
2342
|
themeEditorDeepLink: z19.string().url().optional(),
|
|
2343
|
+
/** Tracking copied from the theme or migrated from a previous ProductMaker layout. */
|
|
2344
|
+
tracking: ShopifyTrackingResult.optional(),
|
|
2274
2345
|
createdAt: z19.string().datetime().optional(),
|
|
2275
2346
|
updatedAt: z19.string().datetime().optional()
|
|
2276
2347
|
});
|
|
@@ -3169,7 +3240,9 @@ var ImageCreativeEstimationOptions = z24.object({
|
|
|
3169
3240
|
});
|
|
3170
3241
|
var RegenerateLandingRoleBody = z24.object({
|
|
3171
3242
|
comment: z24.string().max(500).optional(),
|
|
3172
|
-
sourceKey: z24.string().max(200).optional()
|
|
3243
|
+
sourceKey: z24.string().max(200).optional(),
|
|
3244
|
+
/** Client-generated key lets a lost response be retried without another charge. */
|
|
3245
|
+
clientRequestId: z24.string().uuid().optional()
|
|
3173
3246
|
}).strict();
|
|
3174
3247
|
var LandingRegenerateEstimationOptions = z24.object({
|
|
3175
3248
|
/** KIE image endpoint has non-linear pricing by nVariants; for landing we default to 2. */
|
|
@@ -3720,6 +3793,25 @@ var ALLOWED_MEDIA_CONTENT_TYPES = [
|
|
|
3720
3793
|
"audio/wav",
|
|
3721
3794
|
"audio/x-wav"
|
|
3722
3795
|
];
|
|
3796
|
+
var META_STAGING_IMAGE_CONTENT_TYPES = /* @__PURE__ */ new Set([
|
|
3797
|
+
"image/jpeg",
|
|
3798
|
+
"image/png",
|
|
3799
|
+
"image/webp"
|
|
3800
|
+
]);
|
|
3801
|
+
var META_STAGING_MEDIA_CONTENT_TYPES = /* @__PURE__ */ new Set([
|
|
3802
|
+
...META_STAGING_IMAGE_CONTENT_TYPES,
|
|
3803
|
+
"video/mp4",
|
|
3804
|
+
"video/quicktime",
|
|
3805
|
+
"video/webm"
|
|
3806
|
+
]);
|
|
3807
|
+
var META_STAGING_CONTENT_TYPES = [
|
|
3808
|
+
"image/jpeg",
|
|
3809
|
+
"image/png",
|
|
3810
|
+
"image/webp",
|
|
3811
|
+
"video/mp4",
|
|
3812
|
+
"video/quicktime",
|
|
3813
|
+
"video/webm"
|
|
3814
|
+
];
|
|
3723
3815
|
var PresignUploadRequest = z31.object({
|
|
3724
3816
|
/** MIME type of the file to upload */
|
|
3725
3817
|
contentType: z31.enum(ALLOWED_MEDIA_CONTENT_TYPES),
|
|
@@ -3735,8 +3827,51 @@ var PresignUploadRequest = z31.object({
|
|
|
3735
3827
|
purpose: z31.enum([
|
|
3736
3828
|
"ads",
|
|
3737
3829
|
"service",
|
|
3738
|
-
"actor"
|
|
3830
|
+
"actor",
|
|
3831
|
+
"meta_staging"
|
|
3832
|
+
]).optional(),
|
|
3833
|
+
/** Required for purpose=meta_staging so media and thumbnails can be checked independently. */
|
|
3834
|
+
assetRole: z31.enum([
|
|
3835
|
+
"media",
|
|
3836
|
+
"thumbnail"
|
|
3739
3837
|
]).optional()
|
|
3838
|
+
}).superRefine((value, ctx) => {
|
|
3839
|
+
if (value.purpose === "meta_staging") {
|
|
3840
|
+
if (!value.assetRole) {
|
|
3841
|
+
ctx.addIssue({
|
|
3842
|
+
code: z31.ZodIssueCode.custom,
|
|
3843
|
+
path: [
|
|
3844
|
+
"assetRole"
|
|
3845
|
+
],
|
|
3846
|
+
message: "assetRole is required for Meta staging uploads"
|
|
3847
|
+
});
|
|
3848
|
+
} else if (!META_STAGING_MEDIA_CONTENT_TYPES.has(value.contentType)) {
|
|
3849
|
+
ctx.addIssue({
|
|
3850
|
+
code: z31.ZodIssueCode.custom,
|
|
3851
|
+
path: [
|
|
3852
|
+
"contentType"
|
|
3853
|
+
],
|
|
3854
|
+
message: "Meta staging accepts only image or video media"
|
|
3855
|
+
});
|
|
3856
|
+
} else if (value.assetRole === "thumbnail" && !META_STAGING_IMAGE_CONTENT_TYPES.has(value.contentType)) {
|
|
3857
|
+
ctx.addIssue({
|
|
3858
|
+
code: z31.ZodIssueCode.custom,
|
|
3859
|
+
path: [
|
|
3860
|
+
"contentType"
|
|
3861
|
+
],
|
|
3862
|
+
message: "Meta staging thumbnails must be images"
|
|
3863
|
+
});
|
|
3864
|
+
}
|
|
3865
|
+
}
|
|
3866
|
+
if (value.purpose !== "meta_staging" && value.assetRole) {
|
|
3867
|
+
ctx.addIssue({
|
|
3868
|
+
code: z31.ZodIssueCode.custom,
|
|
3869
|
+
path: [
|
|
3870
|
+
"assetRole"
|
|
3871
|
+
],
|
|
3872
|
+
message: "assetRole is only valid for Meta staging uploads"
|
|
3873
|
+
});
|
|
3874
|
+
}
|
|
3740
3875
|
});
|
|
3741
3876
|
var PresignUploadResponse = z31.object({
|
|
3742
3877
|
/** Presigned S3 PUT URL — browser sends file directly here */
|
|
@@ -3746,8 +3881,23 @@ var PresignUploadResponse = z31.object({
|
|
|
3746
3881
|
/** S3 key */
|
|
3747
3882
|
key: z31.string(),
|
|
3748
3883
|
/** Present only for purpose=service. */
|
|
3749
|
-
assetToken: z31.string().min(1).optional()
|
|
3884
|
+
assetToken: z31.string().min(1).optional(),
|
|
3885
|
+
/** Present only for purpose=meta_staging. */
|
|
3886
|
+
stagingAssetId: z31.string().uuid().optional()
|
|
3750
3887
|
});
|
|
3888
|
+
var MetaUploadMediaKind = z31.enum([
|
|
3889
|
+
"image",
|
|
3890
|
+
"video",
|
|
3891
|
+
"mixed"
|
|
3892
|
+
]);
|
|
3893
|
+
var META_UPLOAD_MAX_FILES = CAMPAIGN_LIMITS.MAX_CREATIVES;
|
|
3894
|
+
var MetaUploadAssetSummary = z31.object({
|
|
3895
|
+
stagingAssetId: z31.string().uuid(),
|
|
3896
|
+
mediaKind: z31.enum([
|
|
3897
|
+
"image",
|
|
3898
|
+
"video"
|
|
3899
|
+
])
|
|
3900
|
+
}).strict();
|
|
3751
3901
|
var MetaCampaignType = z31.enum([
|
|
3752
3902
|
"sales",
|
|
3753
3903
|
"traffic",
|
|
@@ -3773,6 +3923,81 @@ var HttpUrl = z31.string().url().refine((value) => {
|
|
|
3773
3923
|
return false;
|
|
3774
3924
|
}
|
|
3775
3925
|
}, "URL must use http or https");
|
|
3926
|
+
var MetaUploadSessionRequest = z31.object({
|
|
3927
|
+
/** The browser page will require a file of this media kind. */
|
|
3928
|
+
mediaKind: MetaUploadMediaKind,
|
|
3929
|
+
/** The staged object role; media is the normal creative input. */
|
|
3930
|
+
assetRole: z31.enum([
|
|
3931
|
+
"media",
|
|
3932
|
+
"thumbnail"
|
|
3933
|
+
]).default("media"),
|
|
3934
|
+
/** Maximum number of files; the API chooses 10 for mixed and 1 otherwise when omitted. */
|
|
3935
|
+
maxFiles: z31.number().int().min(1).max(META_UPLOAD_MAX_FILES).optional()
|
|
3936
|
+
}).strict().superRefine((value, ctx) => {
|
|
3937
|
+
if (value.mediaKind === "mixed" && value.assetRole === "thumbnail") {
|
|
3938
|
+
ctx.addIssue({
|
|
3939
|
+
code: z31.ZodIssueCode.custom,
|
|
3940
|
+
path: [
|
|
3941
|
+
"mediaKind"
|
|
3942
|
+
],
|
|
3943
|
+
message: "Mixed Meta upload sessions cannot be thumbnails"
|
|
3944
|
+
});
|
|
3945
|
+
}
|
|
3946
|
+
if (value.mediaKind !== "mixed" && value.maxFiles !== void 0 && value.maxFiles !== 1) {
|
|
3947
|
+
ctx.addIssue({
|
|
3948
|
+
code: z31.ZodIssueCode.custom,
|
|
3949
|
+
path: [
|
|
3950
|
+
"maxFiles"
|
|
3951
|
+
],
|
|
3952
|
+
message: "Non-mixed Meta upload sessions accept exactly one file"
|
|
3953
|
+
});
|
|
3954
|
+
}
|
|
3955
|
+
if (value.assetRole === "thumbnail" && value.mediaKind !== "image") {
|
|
3956
|
+
ctx.addIssue({
|
|
3957
|
+
code: z31.ZodIssueCode.custom,
|
|
3958
|
+
path: [
|
|
3959
|
+
"mediaKind"
|
|
3960
|
+
],
|
|
3961
|
+
message: "Meta thumbnails must be images"
|
|
3962
|
+
});
|
|
3963
|
+
}
|
|
3964
|
+
});
|
|
3965
|
+
var ResolveMetaUploadSessionRequest = z31.object({
|
|
3966
|
+
/** Opaque signed token embedded in the one-click upload page URL. */
|
|
3967
|
+
token: z31.string().min(1).max(4096),
|
|
3968
|
+
/** Stable browser-generated id so failed PUT retries reuse the same slot. */
|
|
3969
|
+
uploadId: z31.string().uuid().optional(),
|
|
3970
|
+
/** Browser-selected metadata; the API checks it against the session kind/role. */
|
|
3971
|
+
contentType: z31.enum(META_STAGING_CONTENT_TYPES),
|
|
3972
|
+
fileName: z31.string().min(1).max(255),
|
|
3973
|
+
fileSize: z31.number().int().positive().max(CAMPAIGN_LIMITS.MAX_FILE_SIZE_BYTES)
|
|
3974
|
+
}).strict();
|
|
3975
|
+
var MetaUploadSessionResponse = z31.object({
|
|
3976
|
+
sessionId: z31.string().uuid(),
|
|
3977
|
+
uploadPageUrl: HttpUrl,
|
|
3978
|
+
mediaKind: MetaUploadMediaKind,
|
|
3979
|
+
assetRole: z31.enum([
|
|
3980
|
+
"media",
|
|
3981
|
+
"thumbnail"
|
|
3982
|
+
]),
|
|
3983
|
+
maxFiles: z31.number().int().min(1).max(META_UPLOAD_MAX_FILES),
|
|
3984
|
+
expiresAt: z31.string().datetime()
|
|
3985
|
+
}).strict();
|
|
3986
|
+
var ResolveMetaUploadSessionResponse = z31.object({
|
|
3987
|
+
uploadUrl: z31.string().url(),
|
|
3988
|
+
stagingAssetId: z31.string().uuid(),
|
|
3989
|
+
expiresAt: z31.string().datetime()
|
|
3990
|
+
}).strict();
|
|
3991
|
+
var MetaUploadSessionStatusResponse = z31.object({
|
|
3992
|
+
sessionId: z31.string().uuid(),
|
|
3993
|
+
status: z31.enum([
|
|
3994
|
+
"pending",
|
|
3995
|
+
"uploaded"
|
|
3996
|
+
]),
|
|
3997
|
+
assets: z31.array(MetaUploadAssetSummary).max(META_UPLOAD_MAX_FILES),
|
|
3998
|
+
/** Legacy single-file response field retained for older callers. */
|
|
3999
|
+
stagingAssetId: z31.string().uuid().optional()
|
|
4000
|
+
}).strict();
|
|
3776
4001
|
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), {
|
|
3777
4002
|
message: 'adAccountId must look like "act_1234567890" (a bare numeric id is also accepted)'
|
|
3778
4003
|
});
|
|
@@ -3859,18 +4084,26 @@ var UploadToMetaRequest = z31.object({
|
|
|
3859
4084
|
title: z31.string().max(CAMPAIGN_LIMITS.MAX_TITLE_LENGTH),
|
|
3860
4085
|
description: z31.string().max(CAMPAIGN_LIMITS.MAX_DESCRIPTION_LENGTH),
|
|
3861
4086
|
cta: MetaCtaType,
|
|
3862
|
-
/**
|
|
3863
|
-
mediaUrl: HttpUrl,
|
|
4087
|
+
/** Legacy public URL; new Meta flows should use mediaAssetId. */
|
|
4088
|
+
mediaUrl: HttpUrl.optional(),
|
|
4089
|
+
/** Owner-scoped temporary asset created by the Meta staging upload flow. */
|
|
4090
|
+
mediaAssetId: z31.string().uuid().optional(),
|
|
3864
4091
|
/**
|
|
3865
4092
|
* Public URL of an extracted thumbnail. Required for video ads — Meta
|
|
3866
4093
|
* rejects video ad creatives without `image_hash`/`image_url` in
|
|
3867
4094
|
* `video_data` (subcode 1443226). Frontend extracts a frame from the
|
|
3868
4095
|
* video and uploads it before submitting the request.
|
|
3869
4096
|
*/
|
|
3870
|
-
thumbnailUrl: HttpUrl.optional()
|
|
4097
|
+
thumbnailUrl: HttpUrl.optional(),
|
|
4098
|
+
/** Owner-scoped temporary thumbnail created by the Meta staging upload flow. */
|
|
4099
|
+
thumbnailAssetId: z31.string().uuid().optional()
|
|
3871
4100
|
})).min(1).max(CAMPAIGN_LIMITS.MAX_CREATIVES),
|
|
3872
4101
|
/** Meta Ad Account ID */
|
|
3873
4102
|
adAccountId: MetaAdAccountId,
|
|
4103
|
+
/** Meta Business Portfolio selected by the user (optional for legacy callers). */
|
|
4104
|
+
portfolioId: z31.string().min(1).optional(),
|
|
4105
|
+
/** Facebook Page selected by the user (optional for legacy callers). */
|
|
4106
|
+
pageId: z31.string().min(1).optional(),
|
|
3874
4107
|
/** Optional Meta Pixel ID */
|
|
3875
4108
|
pixelId: z31.string().optional(),
|
|
3876
4109
|
/** Landing page URL (required for landing destinations; omitted for whatsapp) */
|
|
@@ -3890,6 +4123,30 @@ var UploadToMetaRequest = z31.object({
|
|
|
3890
4123
|
message: "landingUrl is required for landing destinations"
|
|
3891
4124
|
});
|
|
3892
4125
|
}
|
|
4126
|
+
value.creatives.forEach((creative, index) => {
|
|
4127
|
+
if (Boolean(creative.mediaUrl) === Boolean(creative.mediaAssetId)) {
|
|
4128
|
+
ctx.addIssue({
|
|
4129
|
+
code: z31.ZodIssueCode.custom,
|
|
4130
|
+
path: [
|
|
4131
|
+
"creatives",
|
|
4132
|
+
index,
|
|
4133
|
+
"mediaUrl"
|
|
4134
|
+
],
|
|
4135
|
+
message: "Provide exactly one of mediaUrl or mediaAssetId"
|
|
4136
|
+
});
|
|
4137
|
+
}
|
|
4138
|
+
if (creative.thumbnailUrl && creative.thumbnailAssetId) {
|
|
4139
|
+
ctx.addIssue({
|
|
4140
|
+
code: z31.ZodIssueCode.custom,
|
|
4141
|
+
path: [
|
|
4142
|
+
"creatives",
|
|
4143
|
+
index,
|
|
4144
|
+
"thumbnailUrl"
|
|
4145
|
+
],
|
|
4146
|
+
message: "Provide at most one of thumbnailUrl or thumbnailAssetId"
|
|
4147
|
+
});
|
|
4148
|
+
}
|
|
4149
|
+
});
|
|
3893
4150
|
});
|
|
3894
4151
|
var CampaignLifetimeMetricsSchema = z31.object({
|
|
3895
4152
|
spend: z31.number().nonnegative(),
|
|
@@ -3943,8 +4200,32 @@ var FacebookAdAccountSchema = z32.object({
|
|
|
3943
4200
|
source: z32.enum([
|
|
3944
4201
|
"business",
|
|
3945
4202
|
"personal"
|
|
4203
|
+
]),
|
|
4204
|
+
/** Meta Business Portfolio (or the synthetic `personal` group). */
|
|
4205
|
+
portfolioId: z32.string().min(1),
|
|
4206
|
+
portfolioName: z32.string().min(1),
|
|
4207
|
+
portfolioType: z32.enum([
|
|
4208
|
+
"business",
|
|
4209
|
+
"personal"
|
|
4210
|
+
])
|
|
4211
|
+
});
|
|
4212
|
+
var FacebookMetaPortfolioSchema = z32.object({
|
|
4213
|
+
id: z32.string().min(1),
|
|
4214
|
+
name: z32.string().min(1),
|
|
4215
|
+
type: z32.enum([
|
|
4216
|
+
"business",
|
|
4217
|
+
"personal"
|
|
3946
4218
|
])
|
|
3947
4219
|
});
|
|
4220
|
+
var FacebookMetaPageSchema = z32.object({
|
|
4221
|
+
id: z32.string().min(1),
|
|
4222
|
+
name: z32.string().min(1)
|
|
4223
|
+
});
|
|
4224
|
+
var FacebookMetaDestinationsResponseSchema = z32.object({
|
|
4225
|
+
portfolios: z32.array(FacebookMetaPortfolioSchema),
|
|
4226
|
+
adAccounts: z32.array(FacebookAdAccountSchema),
|
|
4227
|
+
pages: z32.array(FacebookMetaPageSchema)
|
|
4228
|
+
});
|
|
3948
4229
|
var MetaCampaignOverridesSchema = z32.object({
|
|
3949
4230
|
dailyBudgetUsd: z32.number().positive().optional(),
|
|
3950
4231
|
targetCountries: z32.array(z32.string().length(2)).max(1).optional(),
|
|
@@ -3953,6 +4234,8 @@ var MetaCampaignOverridesSchema = z32.object({
|
|
|
3953
4234
|
});
|
|
3954
4235
|
var FacebookCreateCampaignBodySchema = z32.object({
|
|
3955
4236
|
adAccountId: MetaAdAccountId,
|
|
4237
|
+
portfolioId: z32.string().min(1).optional(),
|
|
4238
|
+
pageId: z32.string().min(1).optional(),
|
|
3956
4239
|
pixelId: z32.string().optional(),
|
|
3957
4240
|
landingUrl: HttpUrl2.optional(),
|
|
3958
4241
|
campaignConfig: MetaCampaignConfig.optional(),
|
|
@@ -3983,6 +4266,8 @@ var FacebookCampaignStatusResponseSchema = z32.object({
|
|
|
3983
4266
|
var FacebookCreateCampaignResponseSchema = z32.object({
|
|
3984
4267
|
campaignId: z32.string(),
|
|
3985
4268
|
campaignName: z32.string(),
|
|
4269
|
+
portfolioId: z32.string().optional(),
|
|
4270
|
+
portfolioName: z32.string().optional(),
|
|
3986
4271
|
pageId: z32.string().optional(),
|
|
3987
4272
|
pageName: z32.string().optional(),
|
|
3988
4273
|
// Backward-compatible single ad fields (optional)
|
|
@@ -4025,11 +4310,15 @@ var FacebookCreateCampaignFromCreativesBodySchema = z32.object({
|
|
|
4025
4310
|
title: z32.string().max(120),
|
|
4026
4311
|
description: z32.string().max(500),
|
|
4027
4312
|
cta: MetaCtaType,
|
|
4028
|
-
mediaUrl: HttpUrl2,
|
|
4313
|
+
mediaUrl: HttpUrl2.optional(),
|
|
4314
|
+
mediaAssetId: z32.string().uuid().optional(),
|
|
4029
4315
|
thumbnailUrl: HttpUrl2.optional(),
|
|
4316
|
+
thumbnailAssetId: z32.string().uuid().optional(),
|
|
4030
4317
|
creativeId: z32.string().min(1).optional()
|
|
4031
4318
|
})).min(1).max(CAMPAIGN_LIMITS.MAX_CREATIVES),
|
|
4032
4319
|
adAccountId: MetaAdAccountId,
|
|
4320
|
+
portfolioId: z32.string().min(1).optional(),
|
|
4321
|
+
pageId: z32.string().min(1).optional(),
|
|
4033
4322
|
pixelId: z32.string().optional(),
|
|
4034
4323
|
/** Required unless campaignConfig.destination is 'whatsapp' (see superRefine below). */
|
|
4035
4324
|
landingUrl: HttpUrl2.optional(),
|
|
@@ -4049,6 +4338,30 @@ var FacebookCreateCampaignFromCreativesBodySchema = z32.object({
|
|
|
4049
4338
|
message: "landingUrl is required unless destination is whatsapp"
|
|
4050
4339
|
});
|
|
4051
4340
|
}
|
|
4341
|
+
value.creatives.forEach((creative, index) => {
|
|
4342
|
+
if (Boolean(creative.mediaUrl) === Boolean(creative.mediaAssetId)) {
|
|
4343
|
+
ctx.addIssue({
|
|
4344
|
+
code: z32.ZodIssueCode.custom,
|
|
4345
|
+
path: [
|
|
4346
|
+
"creatives",
|
|
4347
|
+
index,
|
|
4348
|
+
"mediaUrl"
|
|
4349
|
+
],
|
|
4350
|
+
message: "Provide exactly one of mediaUrl or mediaAssetId"
|
|
4351
|
+
});
|
|
4352
|
+
}
|
|
4353
|
+
if (creative.thumbnailUrl && creative.thumbnailAssetId) {
|
|
4354
|
+
ctx.addIssue({
|
|
4355
|
+
code: z32.ZodIssueCode.custom,
|
|
4356
|
+
path: [
|
|
4357
|
+
"creatives",
|
|
4358
|
+
index,
|
|
4359
|
+
"thumbnailUrl"
|
|
4360
|
+
],
|
|
4361
|
+
message: "Provide at most one of thumbnailUrl or thumbnailAssetId"
|
|
4362
|
+
});
|
|
4363
|
+
}
|
|
4364
|
+
});
|
|
4052
4365
|
if (value.campaignConfig?.destination?.type === "landing" && value.landingUrl && value.campaignConfig.destination.landingUrl !== value.landingUrl) {
|
|
4053
4366
|
ctx.addIssue({
|
|
4054
4367
|
code: z32.ZodIssueCode.custom,
|
|
@@ -4126,8 +4439,10 @@ var FacebookTaskCreativeSourceSchema = z32.object({
|
|
|
4126
4439
|
});
|
|
4127
4440
|
var FacebookMediaCreativeSourceSchema = z32.object({
|
|
4128
4441
|
type: z32.literal("media"),
|
|
4129
|
-
mediaUrl: HttpUrl2,
|
|
4130
|
-
|
|
4442
|
+
mediaUrl: HttpUrl2.optional(),
|
|
4443
|
+
mediaAssetId: z32.string().uuid().optional(),
|
|
4444
|
+
thumbnailUrl: HttpUrl2.optional(),
|
|
4445
|
+
thumbnailAssetId: z32.string().uuid().optional()
|
|
4131
4446
|
});
|
|
4132
4447
|
var FacebookCreativeSourceSchema = z32.discriminatedUnion("type", [
|
|
4133
4448
|
FacebookTaskCreativeSourceSchema,
|
|
@@ -4146,6 +4461,9 @@ var FacebookCreateCampaignFromTasksBodySchema = z32.object({
|
|
|
4146
4461
|
creativeId: z32.string().min(1).optional()
|
|
4147
4462
|
})).min(1).max(CAMPAIGN_LIMITS.MAX_CREATIVES),
|
|
4148
4463
|
adAccountId: MetaAdAccountId,
|
|
4464
|
+
/** Explicit destination is required for MCP/remote creative publishing. */
|
|
4465
|
+
portfolioId: z32.string().min(1),
|
|
4466
|
+
pageId: z32.string().min(1),
|
|
4149
4467
|
pixelId: z32.string().optional(),
|
|
4150
4468
|
landingUrl: HttpUrl2.optional(),
|
|
4151
4469
|
targetCountry: z32.string().length(2).default("US"),
|
|
@@ -4162,6 +4480,33 @@ var FacebookCreateCampaignFromTasksBodySchema = z32.object({
|
|
|
4162
4480
|
message: "landingUrl is required unless destination is whatsapp"
|
|
4163
4481
|
});
|
|
4164
4482
|
}
|
|
4483
|
+
value.creatives.forEach((creative, index) => {
|
|
4484
|
+
if (creative.source.type !== "media") return;
|
|
4485
|
+
if (Boolean(creative.source.mediaUrl) === Boolean(creative.source.mediaAssetId)) {
|
|
4486
|
+
ctx.addIssue({
|
|
4487
|
+
code: z32.ZodIssueCode.custom,
|
|
4488
|
+
path: [
|
|
4489
|
+
"creatives",
|
|
4490
|
+
index,
|
|
4491
|
+
"source",
|
|
4492
|
+
"mediaUrl"
|
|
4493
|
+
],
|
|
4494
|
+
message: "Provide exactly one of mediaUrl or mediaAssetId"
|
|
4495
|
+
});
|
|
4496
|
+
}
|
|
4497
|
+
if (creative.source.thumbnailUrl && creative.source.thumbnailAssetId) {
|
|
4498
|
+
ctx.addIssue({
|
|
4499
|
+
code: z32.ZodIssueCode.custom,
|
|
4500
|
+
path: [
|
|
4501
|
+
"creatives",
|
|
4502
|
+
index,
|
|
4503
|
+
"source",
|
|
4504
|
+
"thumbnailUrl"
|
|
4505
|
+
],
|
|
4506
|
+
message: "Provide at most one of thumbnailUrl or thumbnailAssetId"
|
|
4507
|
+
});
|
|
4508
|
+
}
|
|
4509
|
+
});
|
|
4165
4510
|
});
|
|
4166
4511
|
|
|
4167
4512
|
// ../../packages/types/src/tiktok.ts
|
|
@@ -5843,8 +6188,7 @@ var DEFAULT_PRICING = {
|
|
|
5843
6188
|
userPriceCents: 0.04
|
|
5844
6189
|
}
|
|
5845
6190
|
};
|
|
5846
|
-
var
|
|
5847
|
-
var REGEN_SINGLE_CALL_OUR_COST_CENTS = DEFAULT_PRICING["kie:video-generation:grok-15s-480p"].ourCostCents;
|
|
6191
|
+
var REGEN_SINGLE_CALL_OUR_COST_CENTS = DEFAULT_PRICING["kie:video-generation:grok-15s-720p"].ourCostCents;
|
|
5848
6192
|
var SC_FRAME_COMPOSE_OUR_COST_CENTS = DEFAULT_PRICING["kie:image-generation:gpt-image-2:medium"].ourCostCents;
|
|
5849
6193
|
var SC_FRAME_COMPOSE_USER_PRICE_CENTS = DEFAULT_PRICING["kie:image-generation:gpt-image-2:medium"].userPriceCents;
|
|
5850
6194
|
var MS_FRAME_COMPOSE_OUR_COST_CENTS = DEFAULT_PRICING["kie:image-generation:nano-banana-2"].ourCostCents;
|
|
@@ -7121,10 +7465,35 @@ var ListLandingEditsResponse = z37.object({
|
|
|
7121
7465
|
edits: z37.array(LandingEditDto)
|
|
7122
7466
|
});
|
|
7123
7467
|
|
|
7124
|
-
// ../../packages/types/src/
|
|
7468
|
+
// ../../packages/types/src/landing-regeneration.ts
|
|
7125
7469
|
import { z as z38 } from "zod";
|
|
7470
|
+
var LandingRegenerationStatus = z38.enum([
|
|
7471
|
+
"queued",
|
|
7472
|
+
"processing",
|
|
7473
|
+
"published",
|
|
7474
|
+
"failed"
|
|
7475
|
+
]);
|
|
7476
|
+
var RegenerateLandingRoleResponse = z38.object({
|
|
7477
|
+
ok: z38.literal(true),
|
|
7478
|
+
role: LandingRole,
|
|
7479
|
+
promptIndex: z38.number().int().nonnegative(),
|
|
7480
|
+
operationId: z38.string().min(1)
|
|
7481
|
+
});
|
|
7482
|
+
var LandingRegenerationStatusResponse = z38.object({
|
|
7483
|
+
ok: z38.literal(true),
|
|
7484
|
+
operationId: z38.string().min(1),
|
|
7485
|
+
role: LandingRole,
|
|
7486
|
+
status: LandingRegenerationStatus,
|
|
7487
|
+
refunded: z38.boolean(),
|
|
7488
|
+
failureReason: z38.string().nullable(),
|
|
7489
|
+
publishedAssetKey: z38.string().nullable(),
|
|
7490
|
+
updatedAt: z38.string().datetime()
|
|
7491
|
+
});
|
|
7492
|
+
|
|
7493
|
+
// ../../packages/types/src/video-edit.ts
|
|
7494
|
+
import { z as z39 } from "zod";
|
|
7126
7495
|
var MAX_SEGMENT_SECONDS = 3;
|
|
7127
|
-
var VideoEditStatusSchema =
|
|
7496
|
+
var VideoEditStatusSchema = z39.enum([
|
|
7128
7497
|
"pending",
|
|
7129
7498
|
"processing",
|
|
7130
7499
|
"assembling",
|
|
@@ -7133,9 +7502,9 @@ var VideoEditStatusSchema = z38.enum([
|
|
|
7133
7502
|
"discarded",
|
|
7134
7503
|
"failed"
|
|
7135
7504
|
]);
|
|
7136
|
-
var VideoEditTimeSectionSchema =
|
|
7137
|
-
startSec:
|
|
7138
|
-
endSec:
|
|
7505
|
+
var VideoEditTimeSectionSchema = z39.object({
|
|
7506
|
+
startSec: z39.number().min(0),
|
|
7507
|
+
endSec: z39.number().positive()
|
|
7139
7508
|
}).refine((v) => v.endSec > v.startSec, {
|
|
7140
7509
|
message: "endSec must be after startSec",
|
|
7141
7510
|
path: [
|
|
@@ -7147,35 +7516,35 @@ var VideoEditTimeSectionSchema = z38.object({
|
|
|
7147
7516
|
"endSec"
|
|
7148
7517
|
]
|
|
7149
7518
|
});
|
|
7150
|
-
var VideoEditRequestSchema =
|
|
7151
|
-
comment:
|
|
7152
|
-
sections:
|
|
7519
|
+
var VideoEditRequestSchema = z39.object({
|
|
7520
|
+
comment: z39.string().trim().min(1).max(2e3),
|
|
7521
|
+
sections: z39.array(VideoEditTimeSectionSchema).min(1).optional()
|
|
7153
7522
|
});
|
|
7154
|
-
var VideoEditModeSchema =
|
|
7523
|
+
var VideoEditModeSchema = z39.enum([
|
|
7155
7524
|
"wan_edit",
|
|
7156
7525
|
"regenerate"
|
|
7157
7526
|
]);
|
|
7158
|
-
var VideoRegenerationEngineSchema =
|
|
7527
|
+
var VideoRegenerationEngineSchema = z39.enum([
|
|
7159
7528
|
"free_text",
|
|
7160
7529
|
"free_image",
|
|
7161
7530
|
"single_call",
|
|
7162
7531
|
"multi_shot"
|
|
7163
7532
|
]);
|
|
7164
|
-
var VideoRegenerationRouteFingerprintSchema =
|
|
7165
|
-
var RegenerateEditRequestSchema =
|
|
7166
|
-
angleKey:
|
|
7167
|
-
comment:
|
|
7533
|
+
var VideoRegenerationRouteFingerprintSchema = z39.string().trim().min(1).max(128);
|
|
7534
|
+
var RegenerateEditRequestSchema = z39.object({
|
|
7535
|
+
angleKey: z39.string().min(1),
|
|
7536
|
+
comment: z39.string().min(1).max(2e3)
|
|
7168
7537
|
});
|
|
7169
7538
|
|
|
7170
7539
|
// ../../packages/types/src/dropshipping-project.ts
|
|
7171
|
-
import { z as
|
|
7172
|
-
var DropshippingProjectStatusSchema =
|
|
7540
|
+
import { z as z40 } from "zod";
|
|
7541
|
+
var DropshippingProjectStatusSchema = z40.enum([
|
|
7173
7542
|
"active",
|
|
7174
7543
|
"completed",
|
|
7175
7544
|
"archived"
|
|
7176
7545
|
]);
|
|
7177
7546
|
var DROPSHIPPING_LAUNCH_REWARD_CAMPAIGN = "dropshipping-launch-v1";
|
|
7178
|
-
var DropshippingRewardMilestoneSchema =
|
|
7547
|
+
var DropshippingRewardMilestoneSchema = z40.enum([
|
|
7179
7548
|
"product_selected",
|
|
7180
7549
|
"costing_saved",
|
|
7181
7550
|
"product_media_ready",
|
|
@@ -7190,21 +7559,21 @@ var DROPSHIPPING_LAUNCH_REWARD_CREDITS = {
|
|
|
7190
7559
|
campaign_created: 200
|
|
7191
7560
|
};
|
|
7192
7561
|
var DROPSHIPPING_LAUNCH_REWARD_TOTAL_CREDITS = Object.values(DROPSHIPPING_LAUNCH_REWARD_CREDITS).reduce((sum, credits) => sum + credits, 0);
|
|
7193
|
-
var DropshippingProjectRewardMilestoneStateSchema =
|
|
7562
|
+
var DropshippingProjectRewardMilestoneStateSchema = z40.object({
|
|
7194
7563
|
milestone: DropshippingRewardMilestoneSchema,
|
|
7195
|
-
credits:
|
|
7196
|
-
available:
|
|
7197
|
-
earned:
|
|
7198
|
-
grantId:
|
|
7199
|
-
grantedAt:
|
|
7200
|
-
});
|
|
7201
|
-
var DropshippingProjectRewardProgressSchema =
|
|
7202
|
-
campaignKey:
|
|
7203
|
-
totalCredits:
|
|
7204
|
-
earnedCredits:
|
|
7205
|
-
milestones:
|
|
7206
|
-
});
|
|
7207
|
-
var DropshippingProjectPhaseSchema =
|
|
7564
|
+
credits: z40.number().int().positive(),
|
|
7565
|
+
available: z40.boolean().optional(),
|
|
7566
|
+
earned: z40.boolean(),
|
|
7567
|
+
grantId: z40.string().uuid().nullable(),
|
|
7568
|
+
grantedAt: z40.string().datetime().nullable()
|
|
7569
|
+
});
|
|
7570
|
+
var DropshippingProjectRewardProgressSchema = z40.object({
|
|
7571
|
+
campaignKey: z40.literal(DROPSHIPPING_LAUNCH_REWARD_CAMPAIGN),
|
|
7572
|
+
totalCredits: z40.number().int().positive(),
|
|
7573
|
+
earnedCredits: z40.number().int().nonnegative(),
|
|
7574
|
+
milestones: z40.array(DropshippingProjectRewardMilestoneStateSchema).length(DropshippingRewardMilestoneSchema.options.length)
|
|
7575
|
+
});
|
|
7576
|
+
var DropshippingProjectPhaseSchema = z40.enum([
|
|
7208
7577
|
"research",
|
|
7209
7578
|
"costing",
|
|
7210
7579
|
"media",
|
|
@@ -7213,18 +7582,18 @@ var DropshippingProjectPhaseSchema = z39.enum([
|
|
|
7213
7582
|
"advertising",
|
|
7214
7583
|
"complete"
|
|
7215
7584
|
]);
|
|
7216
|
-
var DropshippingProjectCostingInputSchema =
|
|
7217
|
-
country:
|
|
7218
|
-
supplierCost:
|
|
7219
|
-
shippingCost:
|
|
7220
|
-
returnRate:
|
|
7221
|
-
cancellationRate:
|
|
7222
|
-
adsManagerCpa:
|
|
7223
|
-
desiredMargin:
|
|
7585
|
+
var DropshippingProjectCostingInputSchema = z40.object({
|
|
7586
|
+
country: z40.string().min(2).max(3),
|
|
7587
|
+
supplierCost: z40.number().finite().positive(),
|
|
7588
|
+
shippingCost: z40.number().finite().nonnegative(),
|
|
7589
|
+
returnRate: z40.number().finite().min(0).lt(1),
|
|
7590
|
+
cancellationRate: z40.number().finite().min(0).lt(1),
|
|
7591
|
+
adsManagerCpa: z40.number().finite().nonnegative(),
|
|
7592
|
+
desiredMargin: z40.number().finite().min(0).lt(1)
|
|
7224
7593
|
}).superRefine(({ returnRate, cancellationRate }, context) => {
|
|
7225
7594
|
if (returnRate + cancellationRate >= 1) {
|
|
7226
7595
|
context.addIssue({
|
|
7227
|
-
code:
|
|
7596
|
+
code: z40.ZodIssueCode.custom,
|
|
7228
7597
|
path: [
|
|
7229
7598
|
"cancellationRate"
|
|
7230
7599
|
],
|
|
@@ -7232,24 +7601,24 @@ var DropshippingProjectCostingInputSchema = z39.object({
|
|
|
7232
7601
|
});
|
|
7233
7602
|
}
|
|
7234
7603
|
});
|
|
7235
|
-
var DropshippingProjectCostingResultSchema =
|
|
7236
|
-
country:
|
|
7237
|
-
deliveryRate:
|
|
7238
|
-
adjustedShippingCost:
|
|
7239
|
-
adjustedCpa:
|
|
7240
|
-
totalCost:
|
|
7241
|
-
suggestedPrice:
|
|
7242
|
-
baseCommercialPrice:
|
|
7243
|
-
minimumSafePrice:
|
|
7244
|
-
commercialPrice:
|
|
7245
|
-
comparisonPrice:
|
|
7246
|
-
estimatedProfit:
|
|
7247
|
-
actualMargin:
|
|
7248
|
-
breakEvenAdsManagerCpa:
|
|
7249
|
-
wasPriceAutoAdjusted:
|
|
7250
|
-
profitabilityStatus:
|
|
7251
|
-
});
|
|
7252
|
-
var HttpUrlSchema =
|
|
7604
|
+
var DropshippingProjectCostingResultSchema = z40.object({
|
|
7605
|
+
country: z40.string().min(2).max(3),
|
|
7606
|
+
deliveryRate: z40.number().finite(),
|
|
7607
|
+
adjustedShippingCost: z40.number().finite(),
|
|
7608
|
+
adjustedCpa: z40.number().finite(),
|
|
7609
|
+
totalCost: z40.number().finite(),
|
|
7610
|
+
suggestedPrice: z40.number().finite(),
|
|
7611
|
+
baseCommercialPrice: z40.number().finite(),
|
|
7612
|
+
minimumSafePrice: z40.number().finite(),
|
|
7613
|
+
commercialPrice: z40.number().finite(),
|
|
7614
|
+
comparisonPrice: z40.number().finite(),
|
|
7615
|
+
estimatedProfit: z40.number().finite(),
|
|
7616
|
+
actualMargin: z40.number().finite(),
|
|
7617
|
+
breakEvenAdsManagerCpa: z40.number().finite(),
|
|
7618
|
+
wasPriceAutoAdjusted: z40.boolean(),
|
|
7619
|
+
profitabilityStatus: z40.literal("healthy")
|
|
7620
|
+
});
|
|
7621
|
+
var HttpUrlSchema = z40.string().url().max(2e3).refine((value) => {
|
|
7253
7622
|
try {
|
|
7254
7623
|
return [
|
|
7255
7624
|
"http:",
|
|
@@ -7259,124 +7628,124 @@ var HttpUrlSchema = z39.string().url().max(2e3).refine((value) => {
|
|
|
7259
7628
|
return false;
|
|
7260
7629
|
}
|
|
7261
7630
|
}, "Product URL must use HTTP(S)");
|
|
7262
|
-
var ResearchCandidateOriginSchema =
|
|
7263
|
-
type:
|
|
7264
|
-
runId:
|
|
7265
|
-
candidateSourceId:
|
|
7266
|
-
});
|
|
7267
|
-
var TaskOriginSchema =
|
|
7268
|
-
type:
|
|
7269
|
-
taskId:
|
|
7270
|
-
});
|
|
7271
|
-
var ManualOriginSchema =
|
|
7272
|
-
type:
|
|
7273
|
-
clientRequestId:
|
|
7274
|
-
country:
|
|
7275
|
-
});
|
|
7276
|
-
var CreateDropshippingProjectRequestSchema =
|
|
7277
|
-
origin:
|
|
7631
|
+
var ResearchCandidateOriginSchema = z40.object({
|
|
7632
|
+
type: z40.literal("research_candidate"),
|
|
7633
|
+
runId: z40.string().uuid(),
|
|
7634
|
+
candidateSourceId: z40.string().min(1).max(160)
|
|
7635
|
+
});
|
|
7636
|
+
var TaskOriginSchema = z40.object({
|
|
7637
|
+
type: z40.literal("task"),
|
|
7638
|
+
taskId: z40.string().uuid()
|
|
7639
|
+
});
|
|
7640
|
+
var ManualOriginSchema = z40.object({
|
|
7641
|
+
type: z40.literal("manual"),
|
|
7642
|
+
clientRequestId: z40.string().uuid(),
|
|
7643
|
+
country: z40.string().min(2).max(3).optional()
|
|
7644
|
+
});
|
|
7645
|
+
var CreateDropshippingProjectRequestSchema = z40.object({
|
|
7646
|
+
origin: z40.discriminatedUnion("type", [
|
|
7278
7647
|
ResearchCandidateOriginSchema,
|
|
7279
7648
|
TaskOriginSchema,
|
|
7280
7649
|
ManualOriginSchema
|
|
7281
7650
|
]),
|
|
7282
|
-
productName:
|
|
7651
|
+
productName: z40.string().trim().min(1).max(240).optional(),
|
|
7283
7652
|
productUrl: HttpUrlSchema.optional(),
|
|
7284
|
-
country:
|
|
7285
|
-
languageCode:
|
|
7653
|
+
country: z40.string().min(2).max(3).optional(),
|
|
7654
|
+
languageCode: z40.string().min(2).max(16).optional()
|
|
7286
7655
|
}).strict();
|
|
7287
|
-
var SaveDropshippingProjectCostingRequestSchema =
|
|
7656
|
+
var SaveDropshippingProjectCostingRequestSchema = z40.object({
|
|
7288
7657
|
input: DropshippingProjectCostingInputSchema,
|
|
7289
|
-
version:
|
|
7658
|
+
version: z40.number().int().positive()
|
|
7290
7659
|
}).strict();
|
|
7291
|
-
var DropshippingProjectNextActionSchema =
|
|
7292
|
-
|
|
7293
|
-
kind:
|
|
7294
|
-
href:
|
|
7660
|
+
var DropshippingProjectNextActionSchema = z40.discriminatedUnion("kind", [
|
|
7661
|
+
z40.object({
|
|
7662
|
+
kind: z40.literal("cost_product"),
|
|
7663
|
+
href: z40.string().min(1)
|
|
7295
7664
|
}),
|
|
7296
|
-
|
|
7297
|
-
kind:
|
|
7298
|
-
href:
|
|
7665
|
+
z40.object({
|
|
7666
|
+
kind: z40.literal("provide_product_media"),
|
|
7667
|
+
href: z40.string().min(1)
|
|
7299
7668
|
}),
|
|
7300
|
-
|
|
7301
|
-
kind:
|
|
7302
|
-
href:
|
|
7669
|
+
z40.object({
|
|
7670
|
+
kind: z40.literal("generate_creatives"),
|
|
7671
|
+
href: z40.string().min(1)
|
|
7303
7672
|
}),
|
|
7304
|
-
|
|
7305
|
-
kind:
|
|
7306
|
-
href:
|
|
7673
|
+
z40.object({
|
|
7674
|
+
kind: z40.literal("wait_for_creatives"),
|
|
7675
|
+
href: z40.string().min(1)
|
|
7307
7676
|
}),
|
|
7308
|
-
|
|
7309
|
-
kind:
|
|
7310
|
-
href:
|
|
7677
|
+
z40.object({
|
|
7678
|
+
kind: z40.literal("repair_creatives"),
|
|
7679
|
+
href: z40.string().min(1)
|
|
7311
7680
|
}),
|
|
7312
|
-
|
|
7313
|
-
kind:
|
|
7314
|
-
href:
|
|
7681
|
+
z40.object({
|
|
7682
|
+
kind: z40.literal("complete_creative_set"),
|
|
7683
|
+
href: z40.string().min(1)
|
|
7315
7684
|
}),
|
|
7316
|
-
|
|
7317
|
-
kind:
|
|
7318
|
-
href:
|
|
7685
|
+
z40.object({
|
|
7686
|
+
kind: z40.literal("connect_shopify"),
|
|
7687
|
+
href: z40.string().min(1)
|
|
7319
7688
|
}),
|
|
7320
|
-
|
|
7321
|
-
kind:
|
|
7322
|
-
href:
|
|
7689
|
+
z40.object({
|
|
7690
|
+
kind: z40.literal("publish_storefront"),
|
|
7691
|
+
href: z40.string().min(1)
|
|
7323
7692
|
}),
|
|
7324
|
-
|
|
7325
|
-
kind:
|
|
7326
|
-
href:
|
|
7693
|
+
z40.object({
|
|
7694
|
+
kind: z40.literal("wait_for_storefront"),
|
|
7695
|
+
href: z40.string().min(1)
|
|
7327
7696
|
}),
|
|
7328
|
-
|
|
7329
|
-
kind:
|
|
7330
|
-
href:
|
|
7697
|
+
z40.object({
|
|
7698
|
+
kind: z40.literal("connect_meta"),
|
|
7699
|
+
href: z40.string().min(1)
|
|
7331
7700
|
}),
|
|
7332
|
-
|
|
7333
|
-
kind:
|
|
7334
|
-
href:
|
|
7701
|
+
z40.object({
|
|
7702
|
+
kind: z40.literal("create_meta_campaign"),
|
|
7703
|
+
href: z40.string().min(1)
|
|
7335
7704
|
}),
|
|
7336
|
-
|
|
7337
|
-
kind:
|
|
7338
|
-
href:
|
|
7705
|
+
z40.object({
|
|
7706
|
+
kind: z40.literal("repair_meta_campaign"),
|
|
7707
|
+
href: z40.string().min(1)
|
|
7339
7708
|
}),
|
|
7340
|
-
|
|
7341
|
-
kind:
|
|
7342
|
-
href:
|
|
7709
|
+
z40.object({
|
|
7710
|
+
kind: z40.literal("review_paused_campaign"),
|
|
7711
|
+
href: z40.string().min(1)
|
|
7343
7712
|
})
|
|
7344
7713
|
]);
|
|
7345
|
-
var DropshippingProjectResponseSchema =
|
|
7346
|
-
id:
|
|
7347
|
-
taskId:
|
|
7714
|
+
var DropshippingProjectResponseSchema = z40.object({
|
|
7715
|
+
id: z40.string().uuid(),
|
|
7716
|
+
taskId: z40.string().uuid().nullable(),
|
|
7348
7717
|
status: DropshippingProjectStatusSchema,
|
|
7349
|
-
originKey:
|
|
7350
|
-
researchRunId:
|
|
7351
|
-
candidateSourceId:
|
|
7352
|
-
productName:
|
|
7718
|
+
originKey: z40.string().min(1),
|
|
7719
|
+
researchRunId: z40.string().uuid().nullable(),
|
|
7720
|
+
candidateSourceId: z40.string().nullable(),
|
|
7721
|
+
productName: z40.string().nullable(),
|
|
7353
7722
|
productUrl: HttpUrlSchema.nullable(),
|
|
7354
|
-
referenceImageUrl:
|
|
7355
|
-
hasReferenceImage:
|
|
7356
|
-
targetCountry:
|
|
7357
|
-
languageCode:
|
|
7723
|
+
referenceImageUrl: z40.string().url().nullable(),
|
|
7724
|
+
hasReferenceImage: z40.boolean(),
|
|
7725
|
+
targetCountry: z40.string().nullable(),
|
|
7726
|
+
languageCode: z40.string().nullable(),
|
|
7358
7727
|
costingInput: DropshippingProjectCostingInputSchema.nullable(),
|
|
7359
7728
|
costingResult: DropshippingProjectCostingResultSchema.nullable(),
|
|
7360
|
-
costingVersion:
|
|
7361
|
-
version:
|
|
7729
|
+
costingVersion: z40.number().int().positive().nullable(),
|
|
7730
|
+
version: z40.number().int().positive(),
|
|
7362
7731
|
phase: DropshippingProjectPhaseSchema,
|
|
7363
7732
|
nextAction: DropshippingProjectNextActionSchema.nullable(),
|
|
7364
7733
|
rewards: DropshippingProjectRewardProgressSchema,
|
|
7365
|
-
createdAt:
|
|
7366
|
-
updatedAt:
|
|
7734
|
+
createdAt: z40.string().datetime(),
|
|
7735
|
+
updatedAt: z40.string().datetime()
|
|
7367
7736
|
});
|
|
7368
7737
|
|
|
7369
7738
|
// ../../packages/types/src/scene-subject-contract.ts
|
|
7370
|
-
import { z as
|
|
7371
|
-
var SceneSubjectContractSchema =
|
|
7372
|
-
maxPeople:
|
|
7373
|
-
minPeople:
|
|
7374
|
-
minDistinctPeople:
|
|
7375
|
-
maxHands:
|
|
7739
|
+
import { z as z41 } from "zod";
|
|
7740
|
+
var SceneSubjectContractSchema = z41.object({
|
|
7741
|
+
maxPeople: z41.number().int().min(1).max(10),
|
|
7742
|
+
minPeople: z41.number().int().min(0).max(10),
|
|
7743
|
+
minDistinctPeople: z41.number().int().min(0).max(10),
|
|
7744
|
+
maxHands: z41.number().int().min(0).max(20)
|
|
7376
7745
|
}).superRefine((value, ctx) => {
|
|
7377
7746
|
if (value.minPeople > value.maxPeople) {
|
|
7378
7747
|
ctx.addIssue({
|
|
7379
|
-
code:
|
|
7748
|
+
code: z41.ZodIssueCode.custom,
|
|
7380
7749
|
path: [
|
|
7381
7750
|
"minPeople"
|
|
7382
7751
|
],
|
|
@@ -7385,7 +7754,7 @@ var SceneSubjectContractSchema = z40.object({
|
|
|
7385
7754
|
}
|
|
7386
7755
|
if (value.minDistinctPeople > value.maxPeople) {
|
|
7387
7756
|
ctx.addIssue({
|
|
7388
|
-
code:
|
|
7757
|
+
code: z41.ZodIssueCode.custom,
|
|
7389
7758
|
path: [
|
|
7390
7759
|
"minDistinctPeople"
|
|
7391
7760
|
],
|
|
@@ -7394,7 +7763,7 @@ var SceneSubjectContractSchema = z40.object({
|
|
|
7394
7763
|
}
|
|
7395
7764
|
if (value.minDistinctPeople > value.minPeople) {
|
|
7396
7765
|
ctx.addIssue({
|
|
7397
|
-
code:
|
|
7766
|
+
code: z41.ZodIssueCode.custom,
|
|
7398
7767
|
path: [
|
|
7399
7768
|
"minDistinctPeople"
|
|
7400
7769
|
],
|
|
@@ -7404,7 +7773,7 @@ var SceneSubjectContractSchema = z40.object({
|
|
|
7404
7773
|
});
|
|
7405
7774
|
|
|
7406
7775
|
// ../../packages/types/src/service-creative.ts
|
|
7407
|
-
import { z as
|
|
7776
|
+
import { z as z42 } from "zod";
|
|
7408
7777
|
var SERVICE_CREATIVE_PUBLIC_PRESETS = [
|
|
7409
7778
|
"auto",
|
|
7410
7779
|
"ugc_dynamic",
|
|
@@ -7412,19 +7781,19 @@ var SERVICE_CREATIVE_PUBLIC_PRESETS = [
|
|
|
7412
7781
|
"cinematic",
|
|
7413
7782
|
"wild_card"
|
|
7414
7783
|
];
|
|
7415
|
-
var ServiceCreativePresetSchema =
|
|
7784
|
+
var ServiceCreativePresetSchema = z42.enum(SERVICE_CREATIVE_PUBLIC_PRESETS);
|
|
7416
7785
|
var SERVICE_REVIEW_MODES = [
|
|
7417
7786
|
"automatic",
|
|
7418
7787
|
"guided"
|
|
7419
7788
|
];
|
|
7420
|
-
var ServiceReviewModeSchema =
|
|
7789
|
+
var ServiceReviewModeSchema = z42.enum(SERVICE_REVIEW_MODES);
|
|
7421
7790
|
var SERVICE_HIGGSFIELD_MODES = [
|
|
7422
7791
|
"product_review",
|
|
7423
7792
|
"ugc_how_to",
|
|
7424
7793
|
"tv_spot",
|
|
7425
7794
|
"wild_card"
|
|
7426
7795
|
];
|
|
7427
|
-
var ServiceHiggsfieldModeSchema =
|
|
7796
|
+
var ServiceHiggsfieldModeSchema = z42.enum(SERVICE_HIGGSFIELD_MODES);
|
|
7428
7797
|
var SERVICE_MEDIA_ROLES = [
|
|
7429
7798
|
"screen_demo",
|
|
7430
7799
|
"ad_reference",
|
|
@@ -7432,20 +7801,20 @@ var SERVICE_MEDIA_ROLES = [
|
|
|
7432
7801
|
"presenter_reference",
|
|
7433
7802
|
"brand_asset"
|
|
7434
7803
|
];
|
|
7435
|
-
var ServiceMediaRoleSchema =
|
|
7436
|
-
var ServiceMediaAssetSchema =
|
|
7804
|
+
var ServiceMediaRoleSchema = z42.enum(SERVICE_MEDIA_ROLES);
|
|
7805
|
+
var ServiceMediaAssetSchema = z42.object({
|
|
7437
7806
|
role: ServiceMediaRoleSchema,
|
|
7438
|
-
s3Key:
|
|
7807
|
+
s3Key: z42.string().min(1),
|
|
7439
7808
|
/** HMAC ticket returned by the authenticated service-media presign route. */
|
|
7440
|
-
uploadToken:
|
|
7441
|
-
mimeType:
|
|
7442
|
-
durationSec:
|
|
7443
|
-
sourceName:
|
|
7809
|
+
uploadToken: z42.string().min(1).optional(),
|
|
7810
|
+
mimeType: z42.string().min(1),
|
|
7811
|
+
durationSec: z42.number().positive().max(30).optional(),
|
|
7812
|
+
sourceName: z42.string().max(255).optional()
|
|
7444
7813
|
}).superRefine((asset, ctx) => {
|
|
7445
7814
|
const isVideoRole = asset.role === "screen_demo" || asset.role === "ad_reference";
|
|
7446
7815
|
if (isVideoRole && !asset.mimeType.startsWith("video/")) {
|
|
7447
7816
|
ctx.addIssue({
|
|
7448
|
-
code:
|
|
7817
|
+
code: z42.ZodIssueCode.custom,
|
|
7449
7818
|
message: `${asset.role} requires video media`,
|
|
7450
7819
|
path: [
|
|
7451
7820
|
"mimeType"
|
|
@@ -7454,7 +7823,7 @@ var ServiceMediaAssetSchema = z41.object({
|
|
|
7454
7823
|
}
|
|
7455
7824
|
if (isVideoRole && asset.durationSec === void 0) {
|
|
7456
7825
|
ctx.addIssue({
|
|
7457
|
-
code:
|
|
7826
|
+
code: z42.ZodIssueCode.custom,
|
|
7458
7827
|
message: `${asset.role} requires durationSec`,
|
|
7459
7828
|
path: [
|
|
7460
7829
|
"durationSec"
|
|
@@ -7463,7 +7832,7 @@ var ServiceMediaAssetSchema = z41.object({
|
|
|
7463
7832
|
}
|
|
7464
7833
|
if (!isVideoRole && !asset.mimeType.startsWith("image/")) {
|
|
7465
7834
|
ctx.addIssue({
|
|
7466
|
-
code:
|
|
7835
|
+
code: z42.ZodIssueCode.custom,
|
|
7467
7836
|
message: `${asset.role} requires image media`,
|
|
7468
7837
|
path: [
|
|
7469
7838
|
"mimeType"
|
|
@@ -7471,13 +7840,13 @@ var ServiceMediaAssetSchema = z41.object({
|
|
|
7471
7840
|
});
|
|
7472
7841
|
}
|
|
7473
7842
|
});
|
|
7474
|
-
var ServiceMediaBundleSchema =
|
|
7475
|
-
assets:
|
|
7843
|
+
var ServiceMediaBundleSchema = z42.object({
|
|
7844
|
+
assets: z42.array(ServiceMediaAssetSchema).max(15).default([])
|
|
7476
7845
|
}).superRefine((bundle, ctx) => {
|
|
7477
7846
|
const adReferences = bundle.assets.filter((asset) => asset.role === "ad_reference");
|
|
7478
7847
|
if (adReferences.length > 5) {
|
|
7479
7848
|
ctx.addIssue({
|
|
7480
|
-
code:
|
|
7849
|
+
code: z42.ZodIssueCode.custom,
|
|
7481
7850
|
message: "A maximum of five ad_reference videos is allowed",
|
|
7482
7851
|
path: [
|
|
7483
7852
|
"assets"
|
|
@@ -7487,7 +7856,7 @@ var ServiceMediaBundleSchema = z41.object({
|
|
|
7487
7856
|
const screenDemos = bundle.assets.filter((asset) => asset.role === "screen_demo");
|
|
7488
7857
|
if (screenDemos.length > 3) {
|
|
7489
7858
|
ctx.addIssue({
|
|
7490
|
-
code:
|
|
7859
|
+
code: z42.ZodIssueCode.custom,
|
|
7491
7860
|
message: "A maximum of three screen_demo videos is allowed",
|
|
7492
7861
|
path: [
|
|
7493
7862
|
"assets"
|
|
@@ -7504,33 +7873,33 @@ var SERVICE_MEDIA_ANALYSIS_KINDS = [
|
|
|
7504
7873
|
"product",
|
|
7505
7874
|
"other"
|
|
7506
7875
|
];
|
|
7507
|
-
var ServiceMediaAnalysisKindSchema =
|
|
7508
|
-
var ServiceMediaAnalysisItemSchema =
|
|
7509
|
-
assetIndex:
|
|
7510
|
-
mediaType:
|
|
7876
|
+
var ServiceMediaAnalysisKindSchema = z42.enum(SERVICE_MEDIA_ANALYSIS_KINDS);
|
|
7877
|
+
var ServiceMediaAnalysisItemSchema = z42.object({
|
|
7878
|
+
assetIndex: z42.number().int().nonnegative(),
|
|
7879
|
+
mediaType: z42.enum([
|
|
7511
7880
|
"image",
|
|
7512
7881
|
"video"
|
|
7513
7882
|
]),
|
|
7514
7883
|
kind: ServiceMediaAnalysisKindSchema,
|
|
7515
|
-
description:
|
|
7516
|
-
tags:
|
|
7517
|
-
suggestedRoles:
|
|
7518
|
-
visiblePeople:
|
|
7519
|
-
ocrText:
|
|
7520
|
-
speechSummary:
|
|
7521
|
-
});
|
|
7522
|
-
var ServiceMediaAnalysisSchema =
|
|
7523
|
-
version:
|
|
7524
|
-
analyzedAt:
|
|
7525
|
-
pricingAction:
|
|
7526
|
-
assetFingerprint:
|
|
7884
|
+
description: z42.string().min(1).max(1200),
|
|
7885
|
+
tags: z42.array(z42.string().min(1).max(80)).max(12),
|
|
7886
|
+
suggestedRoles: z42.array(ServiceMediaRoleSchema).max(4),
|
|
7887
|
+
visiblePeople: z42.number().int().nonnegative().max(20).optional(),
|
|
7888
|
+
ocrText: z42.string().max(2e3).optional(),
|
|
7889
|
+
speechSummary: z42.string().max(2e3).optional()
|
|
7890
|
+
});
|
|
7891
|
+
var ServiceMediaAnalysisSchema = z42.object({
|
|
7892
|
+
version: z42.literal(1),
|
|
7893
|
+
analyzedAt: z42.string().datetime(),
|
|
7894
|
+
pricingAction: z42.literal("service-media-analysis"),
|
|
7895
|
+
assetFingerprint: z42.string().regex(/^[a-f0-9]{64}$/),
|
|
7527
7896
|
/** Language used for human-readable descriptions and tags. Optional for old checkpoints. */
|
|
7528
|
-
language:
|
|
7897
|
+
language: z42.enum([
|
|
7529
7898
|
"es",
|
|
7530
7899
|
"en",
|
|
7531
7900
|
"pt"
|
|
7532
7901
|
]).optional(),
|
|
7533
|
-
items:
|
|
7902
|
+
items: z42.array(ServiceMediaAnalysisItemSchema).max(15)
|
|
7534
7903
|
});
|
|
7535
7904
|
|
|
7536
7905
|
// ../../packages/types/src/productmaker-chat-capabilities.ts
|
|
@@ -7540,6 +7909,11 @@ var PRODUCTMAKER_MCP_CAPABILITIES = [
|
|
|
7540
7909
|
confirmation: "credit_consuming",
|
|
7541
7910
|
schemaHash: "bab794a9700a8d3f42b97f444a776e7ed4dcd833038c52588f951b50970ff3fa"
|
|
7542
7911
|
},
|
|
7912
|
+
{
|
|
7913
|
+
name: "check_meta_media_upload",
|
|
7914
|
+
confirmation: "none",
|
|
7915
|
+
schemaHash: "62b1af1d796d9466f8926afc5e6d18c4ddeccd5b0269ca7b21c2f6ebcfd2a945"
|
|
7916
|
+
},
|
|
7543
7917
|
{
|
|
7544
7918
|
name: "cost_dropshipping_project",
|
|
7545
7919
|
confirmation: "state_change",
|
|
@@ -7558,7 +7932,7 @@ var PRODUCTMAKER_MCP_CAPABILITIES = [
|
|
|
7558
7932
|
{
|
|
7559
7933
|
name: "create_product_task",
|
|
7560
7934
|
confirmation: "credit_consuming",
|
|
7561
|
-
schemaHash: "
|
|
7935
|
+
schemaHash: "5c5fe82a365c62e44265e79a4100a06820dbbdb2e0ddc296cd066eb2255b1d62"
|
|
7562
7936
|
},
|
|
7563
7937
|
{
|
|
7564
7938
|
name: "create_service_video",
|
|
@@ -7603,7 +7977,7 @@ var PRODUCTMAKER_MCP_CAPABILITIES = [
|
|
|
7603
7977
|
{
|
|
7604
7978
|
name: "generate_video_creative",
|
|
7605
7979
|
confirmation: "credit_consuming",
|
|
7606
|
-
schemaHash: "
|
|
7980
|
+
schemaHash: "04e12ef523e4064b0c204d110baad35d414b605068087c625badf40c46429c8a"
|
|
7607
7981
|
},
|
|
7608
7982
|
{
|
|
7609
7983
|
name: "get_meta_campaign_status",
|
|
@@ -7645,6 +8019,11 @@ var PRODUCTMAKER_MCP_CAPABILITIES = [
|
|
|
7645
8019
|
confirmation: "none",
|
|
7646
8020
|
schemaHash: "7a014b717a77aac971ea0ab5c0ff47bb13e6cae7ef9442d9dedb15ce36381b15"
|
|
7647
8021
|
},
|
|
8022
|
+
{
|
|
8023
|
+
name: "list_meta_destinations",
|
|
8024
|
+
confirmation: "none",
|
|
8025
|
+
schemaHash: "7a014b717a77aac971ea0ab5c0ff47bb13e6cae7ef9442d9dedb15ce36381b15"
|
|
8026
|
+
},
|
|
7648
8027
|
{
|
|
7649
8028
|
name: "list_product_research_runs",
|
|
7650
8029
|
confirmation: "none",
|
|
@@ -7673,12 +8052,12 @@ var PRODUCTMAKER_MCP_CAPABILITIES = [
|
|
|
7673
8052
|
{
|
|
7674
8053
|
name: "publish_creatives_to_meta",
|
|
7675
8054
|
confirmation: "external_mutation",
|
|
7676
|
-
schemaHash: "
|
|
8055
|
+
schemaHash: "59b3d6d5ce25812fee3382b0b1c0cf5e07beb1063048dd0a0d0633686cf29da5"
|
|
7677
8056
|
},
|
|
7678
8057
|
{
|
|
7679
8058
|
name: "publish_to_meta",
|
|
7680
8059
|
confirmation: "external_mutation",
|
|
7681
|
-
schemaHash: "
|
|
8060
|
+
schemaHash: "b507735a1fe13657355cf93163b6ead0db151984e6f2702dcdbf76b4037133ca"
|
|
7682
8061
|
},
|
|
7683
8062
|
{
|
|
7684
8063
|
name: "publish_to_shopify",
|
|
@@ -7695,6 +8074,11 @@ var PRODUCTMAKER_MCP_CAPABILITIES = [
|
|
|
7695
8074
|
confirmation: "credit_consuming",
|
|
7696
8075
|
schemaHash: "745687cb41f904e293105f93bbe6bc0471f63fe097ab8f85d3df8d9833084844"
|
|
7697
8076
|
},
|
|
8077
|
+
{
|
|
8078
|
+
name: "request_meta_media_upload",
|
|
8079
|
+
confirmation: "none",
|
|
8080
|
+
schemaHash: "fad928b17b4658eb5831bb8b62d5e65bd5220ad94b04b90ace09e658e1895c74"
|
|
8081
|
+
},
|
|
7698
8082
|
{
|
|
7699
8083
|
name: "resolve_pending_action",
|
|
7700
8084
|
confirmation: "credit_consuming",
|
|
@@ -7709,8 +8093,8 @@ var PRODUCTMAKER_MCP_CAPABILITIES = [
|
|
|
7709
8093
|
var PRODUCTMAKER_MCP_CAPABILITY_NAMES = PRODUCTMAKER_MCP_CAPABILITIES.map((capability) => capability.name);
|
|
7710
8094
|
|
|
7711
8095
|
// ../../packages/types/src/actor.ts
|
|
7712
|
-
import { z as
|
|
7713
|
-
var ActorStatusSchema =
|
|
8096
|
+
import { z as z43 } from "zod";
|
|
8097
|
+
var ActorStatusSchema = z43.enum([
|
|
7714
8098
|
"draft",
|
|
7715
8099
|
"generating",
|
|
7716
8100
|
"ready",
|
|
@@ -7719,18 +8103,18 @@ var ActorStatusSchema = z42.enum([
|
|
|
7719
8103
|
var ACTOR_NAME_MAX_CHARS = 60;
|
|
7720
8104
|
var ACTOR_DESCRIPTION_MAX_CHARS = 600;
|
|
7721
8105
|
var ACTOR_CANDIDATE_COUNT = 4;
|
|
7722
|
-
var ActorGenderSchema =
|
|
8106
|
+
var ActorGenderSchema = z43.enum([
|
|
7723
8107
|
"female",
|
|
7724
8108
|
"male",
|
|
7725
8109
|
"non_binary"
|
|
7726
8110
|
]);
|
|
7727
|
-
var ActorSchema =
|
|
7728
|
-
id:
|
|
7729
|
-
name:
|
|
7730
|
-
description:
|
|
8111
|
+
var ActorSchema = z43.object({
|
|
8112
|
+
id: z43.string(),
|
|
8113
|
+
name: z43.string().min(1).max(ACTOR_NAME_MAX_CHARS),
|
|
8114
|
+
description: z43.string().max(ACTOR_DESCRIPTION_MAX_CHARS),
|
|
7731
8115
|
gender: ActorGenderSchema,
|
|
7732
|
-
voiceId:
|
|
7733
|
-
brandId:
|
|
8116
|
+
voiceId: z43.string().nullable().optional(),
|
|
8117
|
+
brandId: z43.string().nullable().optional(),
|
|
7734
8118
|
status: ActorStatusSchema,
|
|
7735
8119
|
/**
|
|
7736
8120
|
* A candidate-grid run is in flight RIGHT NOW.
|
|
@@ -7742,32 +8126,114 @@ var ActorSchema = z42.object({
|
|
|
7742
8126
|
* timestamp with a TTL, so an orphaned run reads as `false` instead of
|
|
7743
8127
|
* pinning the personaje forever.
|
|
7744
8128
|
*/
|
|
7745
|
-
generating:
|
|
7746
|
-
photoUrl:
|
|
7747
|
-
avatarUrl:
|
|
7748
|
-
candidateUrls:
|
|
8129
|
+
generating: z43.boolean().optional(),
|
|
8130
|
+
photoUrl: z43.string().url().nullable().optional(),
|
|
8131
|
+
avatarUrl: z43.string().url().nullable().optional(),
|
|
8132
|
+
candidateUrls: z43.array(z43.string().url()).optional(),
|
|
7749
8133
|
/** Indices of candidateUrls that failed the anatomy check (Task 6). */
|
|
7750
|
-
flaggedCandidateIndices:
|
|
8134
|
+
flaggedCandidateIndices: z43.array(z43.number().int()).optional()
|
|
7751
8135
|
});
|
|
7752
|
-
var CreateActorRequest =
|
|
7753
|
-
name:
|
|
7754
|
-
description:
|
|
8136
|
+
var CreateActorRequest = z43.object({
|
|
8137
|
+
name: z43.string().min(1).max(ACTOR_NAME_MAX_CHARS),
|
|
8138
|
+
description: z43.string().max(ACTOR_DESCRIPTION_MAX_CHARS).default(""),
|
|
7755
8139
|
gender: ActorGenderSchema,
|
|
7756
|
-
voiceId:
|
|
7757
|
-
brandId:
|
|
7758
|
-
sourcePhotoKey:
|
|
8140
|
+
voiceId: z43.string().optional(),
|
|
8141
|
+
brandId: z43.string().optional(),
|
|
8142
|
+
sourcePhotoKey: z43.string().optional()
|
|
7759
8143
|
}).refine((v) => v.description.trim().length > 0 || !!v.sourcePhotoKey, {
|
|
7760
8144
|
message: "Se necesita una descripci\xF3n o una foto"
|
|
7761
8145
|
});
|
|
7762
|
-
var UpdateActorRequest =
|
|
7763
|
-
name:
|
|
7764
|
-
description:
|
|
8146
|
+
var UpdateActorRequest = z43.object({
|
|
8147
|
+
name: z43.string().min(1).max(ACTOR_NAME_MAX_CHARS).optional(),
|
|
8148
|
+
description: z43.string().max(ACTOR_DESCRIPTION_MAX_CHARS).optional(),
|
|
7765
8149
|
gender: ActorGenderSchema.optional(),
|
|
7766
|
-
voiceId:
|
|
7767
|
-
brandId:
|
|
8150
|
+
voiceId: z43.string().nullable().optional(),
|
|
8151
|
+
brandId: z43.string().nullable().optional()
|
|
7768
8152
|
});
|
|
7769
|
-
var ApproveActorRequest =
|
|
7770
|
-
candidateIndex:
|
|
8153
|
+
var ApproveActorRequest = z43.object({
|
|
8154
|
+
candidateIndex: z43.number().int().min(0).max(ACTOR_CANDIDATE_COUNT - 1)
|
|
8155
|
+
});
|
|
8156
|
+
|
|
8157
|
+
// ../../packages/types/src/referral-dashboard.ts
|
|
8158
|
+
import { z as z44 } from "zod";
|
|
8159
|
+
var REFERRAL_DASHBOARD_RAW_STATUSES = [
|
|
8160
|
+
"ACTIVE",
|
|
8161
|
+
"PENDING",
|
|
8162
|
+
"GRACE",
|
|
8163
|
+
"CANCELLED",
|
|
8164
|
+
"EXPIRED"
|
|
8165
|
+
];
|
|
8166
|
+
var REFERRAL_DASHBOARD_STATES = [
|
|
8167
|
+
"active",
|
|
8168
|
+
"pending",
|
|
8169
|
+
"inactive",
|
|
8170
|
+
"no_plan"
|
|
8171
|
+
];
|
|
8172
|
+
var REFERRAL_DASHBOARD_PLAN_KINDS = [
|
|
8173
|
+
"current",
|
|
8174
|
+
"last",
|
|
8175
|
+
"none"
|
|
8176
|
+
];
|
|
8177
|
+
var ReferralDashboardRawStatusSchema = z44.enum(REFERRAL_DASHBOARD_RAW_STATUSES);
|
|
8178
|
+
var ReferralDashboardStateSchema = z44.enum(REFERRAL_DASHBOARD_STATES);
|
|
8179
|
+
var ReferralDashboardPlanKindSchema = z44.enum(REFERRAL_DASHBOARD_PLAN_KINDS);
|
|
8180
|
+
var ReferralDashboardStatusSchema = z44.enum([
|
|
8181
|
+
"all",
|
|
8182
|
+
"active",
|
|
8183
|
+
"pending",
|
|
8184
|
+
"inactive"
|
|
8185
|
+
]).default("all");
|
|
8186
|
+
var ReferralDashboardPlanSchema = z44.string().trim().min(1).max(100).optional();
|
|
8187
|
+
var ReferralDashboardFiltersSchema = z44.object({
|
|
8188
|
+
status: ReferralDashboardStatusSchema,
|
|
8189
|
+
plan: ReferralDashboardPlanSchema
|
|
8190
|
+
});
|
|
8191
|
+
var ReferralDashboardSubscriptionSchema = z44.object({
|
|
8192
|
+
planName: z44.string().nullable(),
|
|
8193
|
+
planKind: ReferralDashboardPlanKindSchema,
|
|
8194
|
+
rawStatus: ReferralDashboardRawStatusSchema.nullable(),
|
|
8195
|
+
state: ReferralDashboardStateSchema,
|
|
8196
|
+
currentPeriodEnd: z44.string().datetime({
|
|
8197
|
+
offset: true
|
|
8198
|
+
}).nullable(),
|
|
8199
|
+
cancelAtPeriodEnd: z44.boolean()
|
|
8200
|
+
});
|
|
8201
|
+
var ReferralDashboardReferralSchema = z44.object({
|
|
8202
|
+
id: z44.string().min(1),
|
|
8203
|
+
registeredAt: z44.string().datetime({
|
|
8204
|
+
offset: true
|
|
8205
|
+
}),
|
|
8206
|
+
// Kept in the response for compatibility with existing referral API clients.
|
|
8207
|
+
// The referrer dashboard intentionally does not render these legacy fields.
|
|
8208
|
+
expiresAt: z44.string().datetime({
|
|
8209
|
+
offset: true
|
|
8210
|
+
}).nullable().optional(),
|
|
8211
|
+
status: z44.string().min(1).optional(),
|
|
8212
|
+
referredUser: z44.object({
|
|
8213
|
+
email: z44.string().nullable()
|
|
8214
|
+
}),
|
|
8215
|
+
subscription: ReferralDashboardSubscriptionSchema
|
|
8216
|
+
});
|
|
8217
|
+
var ReferralDashboardReferralsPageSchema = z44.object({
|
|
8218
|
+
referrals: z44.array(ReferralDashboardReferralSchema),
|
|
8219
|
+
total: z44.number().int().nonnegative()
|
|
8220
|
+
});
|
|
8221
|
+
var ReferralDashboardPlanBreakdownSchema = z44.object({
|
|
8222
|
+
planName: z44.string().nullable(),
|
|
8223
|
+
count: z44.number().int().nonnegative()
|
|
8224
|
+
});
|
|
8225
|
+
var ReferralDashboardMonthlyRegistrationSchema = z44.object({
|
|
8226
|
+
month: z44.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/),
|
|
8227
|
+
count: z44.number().int().nonnegative()
|
|
8228
|
+
});
|
|
8229
|
+
var ReferralDashboardOverviewSchema = z44.object({
|
|
8230
|
+
totalReferredUsers: z44.number().int().nonnegative(),
|
|
8231
|
+
activeUsers: z44.number().int().nonnegative(),
|
|
8232
|
+
pendingUsers: z44.number().int().nonnegative(),
|
|
8233
|
+
inactiveUsers: z44.number().int().nonnegative(),
|
|
8234
|
+
noPlanUsers: z44.number().int().nonnegative(),
|
|
8235
|
+
planBreakdown: z44.array(ReferralDashboardPlanBreakdownSchema),
|
|
8236
|
+
monthlyRegistrations: z44.array(ReferralDashboardMonthlyRegistrationSchema).refine((months) => months.length === 6, "Expected six monthly registration buckets")
|
|
7771
8237
|
});
|
|
7772
8238
|
|
|
7773
8239
|
// src/resolve-media.ts
|
|
@@ -8009,10 +8475,10 @@ async function resolveMediaRef(ref, opts) {
|
|
|
8009
8475
|
__name(resolveMediaRef, "resolveMediaRef");
|
|
8010
8476
|
|
|
8011
8477
|
// src/tools/shared.ts
|
|
8012
|
-
import { z as
|
|
8013
|
-
var Lang =
|
|
8014
|
-
var Country =
|
|
8015
|
-
var LandingStrategyEnum =
|
|
8478
|
+
import { z as z45 } from "zod";
|
|
8479
|
+
var Lang = z45.string().min(2).max(10);
|
|
8480
|
+
var Country = z45.string().min(2).max(3);
|
|
8481
|
+
var LandingStrategyEnum = z45.enum([
|
|
8016
8482
|
"auto",
|
|
8017
8483
|
"classic",
|
|
8018
8484
|
"pain_solution",
|
|
@@ -8021,12 +8487,12 @@ var LandingStrategyEnum = z43.enum([
|
|
|
8021
8487
|
"offer_value",
|
|
8022
8488
|
"lifestyle_identity"
|
|
8023
8489
|
]);
|
|
8024
|
-
var LandingImageFormatEnum =
|
|
8490
|
+
var LandingImageFormatEnum = z45.enum([
|
|
8025
8491
|
"9:16",
|
|
8026
8492
|
"4:5",
|
|
8027
8493
|
"1:1"
|
|
8028
8494
|
]);
|
|
8029
|
-
var VideoPresetEnum =
|
|
8495
|
+
var VideoPresetEnum = z45.enum([
|
|
8030
8496
|
"auto",
|
|
8031
8497
|
"ugc_dynamic",
|
|
8032
8498
|
"ugc_how_to",
|
|
@@ -8039,7 +8505,7 @@ var VideoPresetEnum = z43.enum([
|
|
|
8039
8505
|
"pixar_problem",
|
|
8040
8506
|
"pixar_sassy"
|
|
8041
8507
|
]);
|
|
8042
|
-
var TaskCreativeVariantVideoPresetEnum =
|
|
8508
|
+
var TaskCreativeVariantVideoPresetEnum = z45.enum([
|
|
8043
8509
|
"auto",
|
|
8044
8510
|
"ugc_dynamic",
|
|
8045
8511
|
"ugc_how_to",
|
|
@@ -8110,7 +8576,7 @@ function resolveVideoPreset(preset) {
|
|
|
8110
8576
|
return VIDEO_PRESET_RESOLUTION[preset] ?? null;
|
|
8111
8577
|
}
|
|
8112
8578
|
__name(resolveVideoPreset, "resolveVideoPreset");
|
|
8113
|
-
var VideoTierEnum =
|
|
8579
|
+
var VideoTierEnum = z45.enum([
|
|
8114
8580
|
"basic"
|
|
8115
8581
|
]);
|
|
8116
8582
|
function resolveVideoTier(_tier) {
|
|
@@ -8121,27 +8587,21 @@ function resolveWireVideoTier(tier, durationSeconds) {
|
|
|
8121
8587
|
return durationSeconds === 30 ? "standard" : resolveVideoTier(tier);
|
|
8122
8588
|
}
|
|
8123
8589
|
__name(resolveWireVideoTier, "resolveWireVideoTier");
|
|
8124
|
-
function assertVideoPresetDurationCompatibility(videoPreset, durationSeconds) {
|
|
8125
|
-
if (videoPreset === "problem_solution" && durationSeconds !== 30) {
|
|
8126
|
-
throw new Error("Problema y Soluci\xF3n solo est\xE1 disponible en videos Multiescena de 30 segundos.");
|
|
8127
|
-
}
|
|
8128
|
-
}
|
|
8129
|
-
__name(assertVideoPresetDurationCompatibility, "assertVideoPresetDurationCompatibility");
|
|
8130
8590
|
function resolveVideoFormatForDuration(durationSeconds) {
|
|
8131
8591
|
return durationSeconds === 30 ? "double_30s" : "single_15s";
|
|
8132
8592
|
}
|
|
8133
8593
|
__name(resolveVideoFormatForDuration, "resolveVideoFormatForDuration");
|
|
8134
|
-
var VideoResolutionEnum =
|
|
8594
|
+
var VideoResolutionEnum = z45.enum([
|
|
8135
8595
|
"480p",
|
|
8136
8596
|
"720p"
|
|
8137
8597
|
]);
|
|
8138
|
-
var VideoStyleEnum =
|
|
8598
|
+
var VideoStyleEnum = z45.enum([
|
|
8139
8599
|
"ugc",
|
|
8140
8600
|
"cartoon_3d",
|
|
8141
8601
|
"product_only",
|
|
8142
8602
|
"ai_dynamic"
|
|
8143
8603
|
]);
|
|
8144
|
-
var NarrativeStyleEnum =
|
|
8604
|
+
var NarrativeStyleEnum = z45.enum([
|
|
8145
8605
|
"review",
|
|
8146
8606
|
"ugc_how_to",
|
|
8147
8607
|
"problem_product_cta",
|
|
@@ -8158,7 +8618,7 @@ var NarrativeStyleEnum = z43.enum([
|
|
|
8158
8618
|
"ugc_skeptic_confession",
|
|
8159
8619
|
"ugc_demo_review"
|
|
8160
8620
|
]);
|
|
8161
|
-
var PublicNarrativeStyleEnum =
|
|
8621
|
+
var PublicNarrativeStyleEnum = z45.enum([
|
|
8162
8622
|
"review",
|
|
8163
8623
|
"ugc_how_to",
|
|
8164
8624
|
"ugc_unboxing_chaos",
|
|
@@ -8170,7 +8630,7 @@ var PublicNarrativeStyleEnum = z43.enum([
|
|
|
8170
8630
|
"animated_problem_pixar",
|
|
8171
8631
|
"sassy_product_pixar"
|
|
8172
8632
|
]);
|
|
8173
|
-
var VideoModelEnum =
|
|
8633
|
+
var VideoModelEnum = z45.enum([
|
|
8174
8634
|
"veo",
|
|
8175
8635
|
"wan",
|
|
8176
8636
|
"bytedance",
|
|
@@ -8178,25 +8638,25 @@ var VideoModelEnum = z43.enum([
|
|
|
8178
8638
|
"grok",
|
|
8179
8639
|
"kling"
|
|
8180
8640
|
]);
|
|
8181
|
-
var ProductReferenceUserChoiceEnum =
|
|
8641
|
+
var ProductReferenceUserChoiceEnum = z45.enum([
|
|
8182
8642
|
"same_product",
|
|
8183
8643
|
"variants",
|
|
8184
8644
|
"different_products",
|
|
8185
8645
|
"combo_distinct"
|
|
8186
8646
|
]);
|
|
8187
|
-
var ProductReferenceCandidateGroupingEnum =
|
|
8647
|
+
var ProductReferenceCandidateGroupingEnum = z45.enum([
|
|
8188
8648
|
"same_product_same_variant",
|
|
8189
8649
|
"same_product_different_variants",
|
|
8190
8650
|
"different_products",
|
|
8191
8651
|
"unclear"
|
|
8192
8652
|
]);
|
|
8193
|
-
var GapDurationChoiceMirror =
|
|
8194
|
-
angleIndex:
|
|
8195
|
-
recommendedSec:
|
|
8196
|
-
|
|
8197
|
-
|
|
8653
|
+
var GapDurationChoiceMirror = z45.object({
|
|
8654
|
+
angleIndex: z45.number().int().nonnegative(),
|
|
8655
|
+
recommendedSec: z45.union([
|
|
8656
|
+
z45.literal(15),
|
|
8657
|
+
z45.literal(30)
|
|
8198
8658
|
]),
|
|
8199
|
-
estimatedDeltaCredits:
|
|
8659
|
+
estimatedDeltaCredits: z45.number().int().nonnegative().optional()
|
|
8200
8660
|
});
|
|
8201
8661
|
function buildSelectedImageUrlsHash(urls) {
|
|
8202
8662
|
const input = [
|
|
@@ -8210,13 +8670,13 @@ function buildSelectedImageUrlsHash(urls) {
|
|
|
8210
8670
|
return `fnv1a:${hash.toString(16).padStart(8, "0")}:${urls.length}`;
|
|
8211
8671
|
}
|
|
8212
8672
|
__name(buildSelectedImageUrlsHash, "buildSelectedImageUrlsHash");
|
|
8213
|
-
var ImageCreativeStyleEnum =
|
|
8673
|
+
var ImageCreativeStyleEnum = z45.enum([
|
|
8214
8674
|
"studio",
|
|
8215
8675
|
"floating",
|
|
8216
8676
|
"ingredients",
|
|
8217
8677
|
"in_use"
|
|
8218
8678
|
]);
|
|
8219
|
-
var ImageCreativeArchetypeEnum =
|
|
8679
|
+
var ImageCreativeArchetypeEnum = z45.enum([
|
|
8220
8680
|
"direct_response_product_ad",
|
|
8221
8681
|
"hero_outcome",
|
|
8222
8682
|
"offer_value_prop",
|
|
@@ -8225,23 +8685,23 @@ var ImageCreativeArchetypeEnum = z43.enum([
|
|
|
8225
8685
|
"problem_solution",
|
|
8226
8686
|
"lifestyle_identity"
|
|
8227
8687
|
]);
|
|
8228
|
-
var ImageCreativeVisualTreatmentEnum =
|
|
8688
|
+
var ImageCreativeVisualTreatmentEnum = z45.enum([
|
|
8229
8689
|
"performance_product_ad",
|
|
8230
8690
|
"premium_dtc_carousel"
|
|
8231
8691
|
]);
|
|
8232
|
-
var ImageCreativeAspectRatioEnum =
|
|
8692
|
+
var ImageCreativeAspectRatioEnum = z45.enum([
|
|
8233
8693
|
"1:1",
|
|
8234
8694
|
"4:5",
|
|
8235
8695
|
"9:16",
|
|
8236
8696
|
"16:9"
|
|
8237
8697
|
]);
|
|
8238
|
-
var ImageRefSchema =
|
|
8239
|
-
url:
|
|
8240
|
-
path:
|
|
8698
|
+
var ImageRefSchema = z45.object({
|
|
8699
|
+
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.'),
|
|
8700
|
+
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`.')
|
|
8241
8701
|
}).refine((v) => Boolean(v.url) !== Boolean(v.path), {
|
|
8242
8702
|
message: "each image entry must have exactly one of `url` or `path`"
|
|
8243
8703
|
});
|
|
8244
|
-
var ImagesInput =
|
|
8704
|
+
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.');
|
|
8245
8705
|
function asText(value) {
|
|
8246
8706
|
return {
|
|
8247
8707
|
content: [
|
|
@@ -8294,14 +8754,14 @@ async function submitCreative(api, opts) {
|
|
|
8294
8754
|
});
|
|
8295
8755
|
}
|
|
8296
8756
|
__name(submitCreative, "submitCreative");
|
|
8297
|
-
var ResearchTargetCountryEnum =
|
|
8757
|
+
var ResearchTargetCountryEnum = z45.enum([
|
|
8298
8758
|
"CO",
|
|
8299
8759
|
"MX",
|
|
8300
8760
|
"PE",
|
|
8301
8761
|
"EC",
|
|
8302
8762
|
"CL"
|
|
8303
8763
|
]);
|
|
8304
|
-
var ResearchCategoryEnum =
|
|
8764
|
+
var ResearchCategoryEnum = z45.enum([
|
|
8305
8765
|
"auto",
|
|
8306
8766
|
"automotive",
|
|
8307
8767
|
"kitchen",
|
|
@@ -8374,6 +8834,15 @@ var McpErrorCode = {
|
|
|
8374
8834
|
SHOPIFY_PUBLISH_FAILED: "SHOPIFY_PUBLISH_FAILED",
|
|
8375
8835
|
// Meta / Facebook Ads
|
|
8376
8836
|
META_NO_FB_PAGE: "META_NO_FB_PAGE",
|
|
8837
|
+
META_PORTFOLIO_MISMATCH: "META_PORTFOLIO_MISMATCH",
|
|
8838
|
+
META_PAGE_SELECTION_REQUIRED: "META_PAGE_SELECTION_REQUIRED",
|
|
8839
|
+
META_INVALID_PAGE: "META_INVALID_PAGE",
|
|
8840
|
+
META_STAGED_ASSET_NOT_FOUND: "META_STAGED_ASSET_NOT_FOUND",
|
|
8841
|
+
META_STAGED_ASSET_AMBIGUOUS: "META_STAGED_ASSET_AMBIGUOUS",
|
|
8842
|
+
META_STAGED_ASSET_TYPE_MISMATCH: "META_STAGED_ASSET_TYPE_MISMATCH",
|
|
8843
|
+
META_STAGED_ASSET_INVALID: "META_STAGED_ASSET_INVALID",
|
|
8844
|
+
META_PUBLICATION_RECONCILIATION_REQUIRED: "META_PUBLICATION_RECONCILIATION_REQUIRED",
|
|
8845
|
+
META_PUBLICATION_IN_PROGRESS: "META_PUBLICATION_IN_PROGRESS",
|
|
8377
8846
|
META_NO_ADS_CREATED: "META_NO_ADS_CREATED",
|
|
8378
8847
|
META_NO_ASSETS_READY: "META_NO_ASSETS_READY",
|
|
8379
8848
|
META_NO_THUMBNAIL_SOURCE: "META_NO_THUMBNAIL_SOURCE",
|
|
@@ -8426,6 +8895,15 @@ var CODE_MESSAGES = {
|
|
|
8426
8895
|
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.",
|
|
8427
8896
|
// Meta — high-frequency
|
|
8428
8897
|
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).",
|
|
8898
|
+
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.",
|
|
8899
|
+
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`.",
|
|
8900
|
+
META_INVALID_PAGE: "The selected Facebook Page is not available for this Meta connection. Call `list_meta_destinations` again and choose an available `pageId`.",
|
|
8901
|
+
META_STAGED_ASSET_NOT_FOUND: "The temporary media upload was not found or expired. Re-upload the media and retry the Meta publication.",
|
|
8902
|
+
META_STAGED_ASSET_AMBIGUOUS: "The temporary media upload could not be uniquely resolved. Re-upload the media and retry the Meta publication.",
|
|
8903
|
+
META_STAGED_ASSET_TYPE_MISMATCH: "The temporary media type does not match the creative. Re-upload the correct image or video and retry.",
|
|
8904
|
+
META_STAGED_ASSET_INVALID: "The temporary media is empty or exceeds the server size limit. Re-upload the file and retry.",
|
|
8905
|
+
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.",
|
|
8906
|
+
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.",
|
|
8429
8907
|
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.",
|
|
8430
8908
|
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.",
|
|
8431
8909
|
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.",
|
|
@@ -8539,6 +9017,12 @@ var INVALID_PARAM_CODES = /* @__PURE__ */ new Set([
|
|
|
8539
9017
|
McpErrorCode.CAMPAIGN_MISSING_LANDING_URL,
|
|
8540
9018
|
McpErrorCode.CAMPAIGN_RECONCILIATION_REQUIRED,
|
|
8541
9019
|
McpErrorCode.META_NO_LANDING_URL,
|
|
9020
|
+
McpErrorCode.META_PORTFOLIO_MISMATCH,
|
|
9021
|
+
McpErrorCode.META_PAGE_SELECTION_REQUIRED,
|
|
9022
|
+
McpErrorCode.META_INVALID_PAGE,
|
|
9023
|
+
McpErrorCode.META_STAGED_ASSET_NOT_FOUND,
|
|
9024
|
+
McpErrorCode.META_STAGED_ASSET_AMBIGUOUS,
|
|
9025
|
+
McpErrorCode.META_STAGED_ASSET_TYPE_MISMATCH,
|
|
8542
9026
|
McpErrorCode.META_DAILY_BUDGET_TOO_HIGH,
|
|
8543
9027
|
McpErrorCode.META_CAMPAIGN_CONFIG_INVALID,
|
|
8544
9028
|
McpErrorCode.META_WHATSAPP_INVALID_NUMBER,
|
|
@@ -8560,6 +9044,15 @@ var INVALID_PARAM_CODES = /* @__PURE__ */ new Set([
|
|
|
8560
9044
|
McpErrorCode.META_MISSING_PAYMENT,
|
|
8561
9045
|
McpErrorCode.META_ACCOUNT_RESTRICTED,
|
|
8562
9046
|
McpErrorCode.META_NO_FB_PAGE,
|
|
9047
|
+
McpErrorCode.META_PORTFOLIO_MISMATCH,
|
|
9048
|
+
McpErrorCode.META_PAGE_SELECTION_REQUIRED,
|
|
9049
|
+
McpErrorCode.META_INVALID_PAGE,
|
|
9050
|
+
McpErrorCode.META_STAGED_ASSET_NOT_FOUND,
|
|
9051
|
+
McpErrorCode.META_STAGED_ASSET_AMBIGUOUS,
|
|
9052
|
+
McpErrorCode.META_STAGED_ASSET_TYPE_MISMATCH,
|
|
9053
|
+
McpErrorCode.META_STAGED_ASSET_INVALID,
|
|
9054
|
+
McpErrorCode.META_PUBLICATION_RECONCILIATION_REQUIRED,
|
|
9055
|
+
McpErrorCode.META_PUBLICATION_IN_PROGRESS,
|
|
8563
9056
|
McpErrorCode.TIKTOK_TOKEN_EXPIRED,
|
|
8564
9057
|
McpErrorCode.TIKTOK_PERMISSION_DENIED,
|
|
8565
9058
|
McpErrorCode.TIKTOK_MISSING_PAYMENT,
|
|
@@ -8954,53 +9447,53 @@ function renderOutputsMarkdown(outputs) {
|
|
|
8954
9447
|
__name(renderOutputsMarkdown, "renderOutputsMarkdown");
|
|
8955
9448
|
|
|
8956
9449
|
// src/tools/tasks.ts
|
|
8957
|
-
var CreateProductTaskInput =
|
|
9450
|
+
var CreateProductTaskInput = z46.object({
|
|
8958
9451
|
images: ImagesInput.optional().describe("1\u20135 fotos del mismo producto. Omitir \xFAnicamente cuando projectId apunta a un proyecto propio con imagen guardada."),
|
|
8959
|
-
projectId:
|
|
8960
|
-
productUrl:
|
|
9452
|
+
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."),
|
|
9453
|
+
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."),
|
|
8961
9454
|
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.'),
|
|
8962
9455
|
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.'),
|
|
8963
|
-
price:
|
|
8964
|
-
compareAtPrice:
|
|
8965
|
-
offer:
|
|
8966
|
-
paymentMethods:
|
|
8967
|
-
productContext:
|
|
8968
|
-
productLabel:
|
|
8969
|
-
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
|
|
8970
|
-
durationSeconds:
|
|
8971
|
-
|
|
8972
|
-
|
|
9456
|
+
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.'),
|
|
9457
|
+
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".'),
|
|
9458
|
+
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.'),
|
|
9459
|
+
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.'),
|
|
9460
|
+
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."),
|
|
9461
|
+
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.'),
|
|
9462
|
+
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.'),
|
|
9463
|
+
durationSeconds: z46.union([
|
|
9464
|
+
z46.literal(15),
|
|
9465
|
+
z46.literal(30)
|
|
8973
9466
|
]).default(15).describe("Opcional. Duraci\xF3n objetivo del video: 15s (single_call, default) o 30s (Multiescena, aproximadamente 30s y facturado por escena)."),
|
|
8974
|
-
pauseForAngleReview:
|
|
9467
|
+
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."),
|
|
8975
9468
|
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.'),
|
|
8976
9469
|
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).'),
|
|
8977
|
-
multiAngleVideos:
|
|
9470
|
+
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."),
|
|
8978
9471
|
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.'),
|
|
8979
|
-
outputs:
|
|
9472
|
+
outputs: z46.array(z46.enum([
|
|
8980
9473
|
"landing",
|
|
8981
9474
|
"video",
|
|
8982
9475
|
"image"
|
|
8983
9476
|
])).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.'),
|
|
8984
|
-
competitorScanEnabled:
|
|
8985
|
-
brandId:
|
|
8986
|
-
actorId:
|
|
8987
|
-
creativeDirection:
|
|
8988
|
-
headline:
|
|
8989
|
-
subheadline:
|
|
9477
|
+
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."),
|
|
9478
|
+
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."),
|
|
9479
|
+
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."),
|
|
9480
|
+
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.'),
|
|
9481
|
+
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."),
|
|
9482
|
+
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."),
|
|
8990
9483
|
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".'),
|
|
8991
9484
|
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".')
|
|
8992
9485
|
}).strict();
|
|
8993
|
-
var CreateServiceVideoInput =
|
|
8994
|
-
landingUrl:
|
|
8995
|
-
additionalContext:
|
|
9486
|
+
var CreateServiceVideoInput = z46.object({
|
|
9487
|
+
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."),
|
|
9488
|
+
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.'),
|
|
8996
9489
|
language: Lang.describe("Idioma del video: es, en o pt."),
|
|
8997
|
-
voiceId:
|
|
8998
|
-
brandId:
|
|
8999
|
-
reviewMode:
|
|
9490
|
+
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.'),
|
|
9491
|
+
brandId: z46.string().uuid().optional().describe("Marca guardada del usuario. Aplica voz, mensajes, paleta y persona predeterminada."),
|
|
9492
|
+
reviewMode: z46.enum([
|
|
9000
9493
|
"automatic",
|
|
9001
9494
|
"guided"
|
|
9002
9495
|
]).default("automatic").describe("automatic = la IA elige concepto y guion sin pausas; guided = el usuario aprueba concepto y storyboard."),
|
|
9003
|
-
videoPreset:
|
|
9496
|
+
videoPreset: z46.enum([
|
|
9004
9497
|
"auto",
|
|
9005
9498
|
"ugc_dynamic",
|
|
9006
9499
|
"ugc_how_to",
|
|
@@ -9008,35 +9501,35 @@ var CreateServiceVideoInput = z44.object({
|
|
|
9008
9501
|
"wild_card"
|
|
9009
9502
|
]).default("auto")
|
|
9010
9503
|
}).strict();
|
|
9011
|
-
var GetTaskStatusInput =
|
|
9012
|
-
taskId:
|
|
9013
|
-
waitSeconds:
|
|
9014
|
-
});
|
|
9015
|
-
var ListTasksInput =
|
|
9016
|
-
limit:
|
|
9017
|
-
offset:
|
|
9018
|
-
search:
|
|
9019
|
-
});
|
|
9020
|
-
var EditTaskDraftInput =
|
|
9021
|
-
taskId:
|
|
9022
|
-
angleIndex:
|
|
9023
|
-
angle:
|
|
9024
|
-
angle:
|
|
9025
|
-
buyerPersona:
|
|
9026
|
-
actor:
|
|
9027
|
-
actorId:
|
|
9028
|
-
gender:
|
|
9504
|
+
var GetTaskStatusInput = z46.object({
|
|
9505
|
+
taskId: z46.string().min(1),
|
|
9506
|
+
waitSeconds: z46.number().int().min(0).max(120).optional()
|
|
9507
|
+
});
|
|
9508
|
+
var ListTasksInput = z46.object({
|
|
9509
|
+
limit: z46.number().int().min(1).max(50).optional(),
|
|
9510
|
+
offset: z46.number().int().min(0).optional(),
|
|
9511
|
+
search: z46.string().optional()
|
|
9512
|
+
});
|
|
9513
|
+
var EditTaskDraftInput = z46.object({
|
|
9514
|
+
taskId: z46.string().min(1),
|
|
9515
|
+
angleIndex: z46.number().int().min(0),
|
|
9516
|
+
angle: z46.object({
|
|
9517
|
+
angle: z46.string().min(1).max(480),
|
|
9518
|
+
buyerPersona: z46.string().min(1).max(360),
|
|
9519
|
+
actor: z46.string().min(1).max(360).optional(),
|
|
9520
|
+
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."),
|
|
9521
|
+
gender: z46.enum([
|
|
9029
9522
|
"female",
|
|
9030
9523
|
"male"
|
|
9031
9524
|
]).optional(),
|
|
9032
|
-
scriptNotes:
|
|
9525
|
+
scriptNotes: z46.string().max(2e3).optional()
|
|
9033
9526
|
})
|
|
9034
9527
|
});
|
|
9035
|
-
var PendingActionPayload =
|
|
9036
|
-
|
|
9037
|
-
kind:
|
|
9528
|
+
var PendingActionPayload = z46.discriminatedUnion("kind", [
|
|
9529
|
+
z46.object({
|
|
9530
|
+
kind: z46.literal("product_reference_confirmation"),
|
|
9038
9531
|
userChoice: ProductReferenceUserChoiceEnum,
|
|
9039
|
-
confirmedProductNames:
|
|
9532
|
+
confirmedProductNames: z46.array(z46.string().min(1).max(120)).min(2).max(8).optional(),
|
|
9040
9533
|
// SCOPED multi-scene opt-in — the ONLY way STANDARD ("Multiescena") is
|
|
9041
9534
|
// reachable via MCP. Valid ONLY together with userChoice='variants' (same
|
|
9042
9535
|
// product in several colors): renders one shot per color and stitches them,
|
|
@@ -9047,50 +9540,50 @@ var PendingActionPayload = z44.discriminatedUnion("kind", [
|
|
|
9047
9540
|
// safe because multi-scene IS the intended render for a color variant set,
|
|
9048
9541
|
// not a blind quality upsell. Maps to `videoTier: 'standard'` on the
|
|
9049
9542
|
// confirm call; the backend re-gates it (variants + variant_set only).
|
|
9050
|
-
useMultiSceneShowcase:
|
|
9543
|
+
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".')
|
|
9051
9544
|
}),
|
|
9052
|
-
|
|
9053
|
-
kind:
|
|
9545
|
+
z46.object({
|
|
9546
|
+
kind: z46.literal("angle_review_approval"),
|
|
9054
9547
|
// All edits are optional — empty action body just approves the
|
|
9055
9548
|
// backend-generated draft as-is. Field shapes mirror the angle-review
|
|
9056
9549
|
// request contracts in @packages/types/wizard.ts; the handler routes to
|
|
9057
9550
|
// the dedicated video/image/autopilot endpoint based on StatusResponse.kind.
|
|
9058
|
-
customAngle:
|
|
9551
|
+
customAngle: z46.string().min(1).max(480).optional(),
|
|
9059
9552
|
// Keep the shared MCP action within the strictest downstream contract:
|
|
9060
9553
|
// autopilot/image resume endpoints cap these fields at 1500 characters.
|
|
9061
|
-
painPoints:
|
|
9062
|
-
benefits:
|
|
9063
|
-
features:
|
|
9064
|
-
gapDurationSeconds:
|
|
9065
|
-
|
|
9066
|
-
|
|
9554
|
+
painPoints: z46.string().max(1500).optional(),
|
|
9555
|
+
benefits: z46.string().max(1500).optional(),
|
|
9556
|
+
features: z46.array(z46.string().min(1).max(300)).max(10).optional(),
|
|
9557
|
+
gapDurationSeconds: z46.union([
|
|
9558
|
+
z46.literal(15),
|
|
9559
|
+
z46.literal(30)
|
|
9067
9560
|
]).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.")
|
|
9068
9561
|
}),
|
|
9069
|
-
|
|
9070
|
-
kind:
|
|
9071
|
-
angleId:
|
|
9072
|
-
content:
|
|
9073
|
-
creativeDirection:
|
|
9074
|
-
actor:
|
|
9562
|
+
z46.object({
|
|
9563
|
+
kind: z46.literal("service_angle_approval"),
|
|
9564
|
+
angleId: z46.string().uuid(),
|
|
9565
|
+
content: z46.string().min(1).max(480).optional(),
|
|
9566
|
+
creativeDirection: z46.string().min(1).max(1500).optional(),
|
|
9567
|
+
actor: z46.string().min(1).max(360).optional()
|
|
9075
9568
|
}),
|
|
9076
|
-
|
|
9077
|
-
kind:
|
|
9078
|
-
voiceovers:
|
|
9079
|
-
visualDirections:
|
|
9569
|
+
z46.object({
|
|
9570
|
+
kind: z46.literal("service_script_approval"),
|
|
9571
|
+
voiceovers: z46.record(z46.string(), z46.string().min(1).max(600)).optional(),
|
|
9572
|
+
visualDirections: z46.record(z46.string(), z46.string().min(1).max(1200)).optional()
|
|
9080
9573
|
})
|
|
9081
9574
|
]);
|
|
9082
|
-
var ResolvePendingActionInput =
|
|
9083
|
-
taskId:
|
|
9575
|
+
var ResolvePendingActionInput = z46.object({
|
|
9576
|
+
taskId: z46.string().min(1),
|
|
9084
9577
|
action: PendingActionPayload
|
|
9085
9578
|
}).strict();
|
|
9086
9579
|
function resolveVariantConfirmVideoTier(action) {
|
|
9087
9580
|
return action.useMultiSceneShowcase && action.userChoice === "variants" ? "standard" : void 0;
|
|
9088
9581
|
}
|
|
9089
9582
|
__name(resolveVariantConfirmVideoTier, "resolveVariantConfirmVideoTier");
|
|
9090
|
-
var StatusForResolveSchema =
|
|
9583
|
+
var StatusForResolveSchema = z46.object({
|
|
9091
9584
|
// Metadata used to select the backend resume contract. Older API responses
|
|
9092
9585
|
// may omit these fields, so the resolver keeps the generic fallback.
|
|
9093
|
-
kind:
|
|
9586
|
+
kind: z46.enum([
|
|
9094
9587
|
"autopilot",
|
|
9095
9588
|
"video",
|
|
9096
9589
|
"image",
|
|
@@ -9098,24 +9591,24 @@ var StatusForResolveSchema = z44.object({
|
|
|
9098
9591
|
"mix",
|
|
9099
9592
|
"service"
|
|
9100
9593
|
]).optional(),
|
|
9101
|
-
selectedOutputs:
|
|
9594
|
+
selectedOutputs: z46.array(z46.enum([
|
|
9102
9595
|
"landing",
|
|
9103
9596
|
"video",
|
|
9104
9597
|
"image"
|
|
9105
9598
|
])).optional(),
|
|
9106
|
-
videoAngleCount:
|
|
9107
|
-
ugcFormat:
|
|
9599
|
+
videoAngleCount: z46.number().int().min(1).max(3).optional(),
|
|
9600
|
+
ugcFormat: z46.enum([
|
|
9108
9601
|
"single_8s",
|
|
9109
9602
|
"single_15s",
|
|
9110
9603
|
"double_30s"
|
|
9111
9604
|
]).optional(),
|
|
9112
|
-
videoStyle:
|
|
9605
|
+
videoStyle: z46.enum([
|
|
9113
9606
|
"ugc",
|
|
9114
9607
|
"cartoon_3d",
|
|
9115
9608
|
"product_only",
|
|
9116
9609
|
"ai_dynamic"
|
|
9117
9610
|
]).optional(),
|
|
9118
|
-
videoModel:
|
|
9611
|
+
videoModel: z46.enum([
|
|
9119
9612
|
"veo",
|
|
9120
9613
|
"wan",
|
|
9121
9614
|
"bytedance",
|
|
@@ -9123,26 +9616,26 @@ var StatusForResolveSchema = z44.object({
|
|
|
9123
9616
|
"grok",
|
|
9124
9617
|
"kling"
|
|
9125
9618
|
]).optional(),
|
|
9126
|
-
videoTier:
|
|
9619
|
+
videoTier: z46.enum([
|
|
9127
9620
|
"legacy",
|
|
9128
9621
|
"standard",
|
|
9129
9622
|
"pro",
|
|
9130
9623
|
"single_call"
|
|
9131
9624
|
]).optional(),
|
|
9132
|
-
videoResolution:
|
|
9625
|
+
videoResolution: z46.enum([
|
|
9133
9626
|
"480p",
|
|
9134
9627
|
"720p"
|
|
9135
9628
|
]).optional(),
|
|
9136
9629
|
narrativeStyle: NarrativeStyleEnum.optional(),
|
|
9137
|
-
pendingUserAction:
|
|
9138
|
-
kind:
|
|
9139
|
-
candidateGrouping:
|
|
9140
|
-
selectedImageUrls:
|
|
9141
|
-
proposedProductNames:
|
|
9142
|
-
customAngleDraft:
|
|
9143
|
-
painPointsDraft:
|
|
9144
|
-
benefitsDraft:
|
|
9145
|
-
featuresDraft:
|
|
9630
|
+
pendingUserAction: z46.object({
|
|
9631
|
+
kind: z46.string(),
|
|
9632
|
+
candidateGrouping: z46.string().optional(),
|
|
9633
|
+
selectedImageUrls: z46.array(z46.string()).optional(),
|
|
9634
|
+
proposedProductNames: z46.array(z46.string()).optional(),
|
|
9635
|
+
customAngleDraft: z46.string().optional(),
|
|
9636
|
+
painPointsDraft: z46.string().optional(),
|
|
9637
|
+
benefitsDraft: z46.string().optional(),
|
|
9638
|
+
featuresDraft: z46.array(z46.string()).optional(),
|
|
9146
9639
|
// Recommendation consumed only when the caller explicitly sends
|
|
9147
9640
|
// gapDurationSeconds: 30 in the angle approval action.
|
|
9148
9641
|
gapDurationChoice: GapDurationChoiceMirror.optional(),
|
|
@@ -9151,17 +9644,17 @@ var StatusForResolveSchema = z44.object({
|
|
|
9151
9644
|
// keys. `actorId` (the saved custom actor the picker stored) was silently
|
|
9152
9645
|
// dropped here, so the approval handler below could not echo it back on the
|
|
9153
9646
|
// PATCH — the selection looked accepted and reached no render.
|
|
9154
|
-
angles:
|
|
9155
|
-
id:
|
|
9156
|
-
content:
|
|
9157
|
-
creativeDirection:
|
|
9158
|
-
actor:
|
|
9159
|
-
actorId:
|
|
9647
|
+
angles: z46.array(z46.object({
|
|
9648
|
+
id: z46.string().uuid(),
|
|
9649
|
+
content: z46.string(),
|
|
9650
|
+
creativeDirection: z46.string(),
|
|
9651
|
+
actor: z46.string(),
|
|
9652
|
+
actorId: z46.string().nullable().optional()
|
|
9160
9653
|
}).passthrough()).optional(),
|
|
9161
|
-
panels:
|
|
9162
|
-
beatId:
|
|
9163
|
-
voiceover:
|
|
9164
|
-
visualDirection:
|
|
9654
|
+
panels: z46.array(z46.object({
|
|
9655
|
+
beatId: z46.string(),
|
|
9656
|
+
voiceover: z46.string(),
|
|
9657
|
+
visualDirection: z46.string()
|
|
9165
9658
|
}).passthrough()).optional()
|
|
9166
9659
|
}).optional()
|
|
9167
9660
|
}).passthrough();
|
|
@@ -9202,7 +9695,6 @@ __name(resolveStatusTaskKind, "resolveStatusTaskKind");
|
|
|
9202
9695
|
function registerTaskTools(server, api, { proxyBaseUrl = null, transport = "http" } = {}) {
|
|
9203
9696
|
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) => {
|
|
9204
9697
|
try {
|
|
9205
|
-
assertVideoPresetDurationCompatibility(input.videoPreset, input.durationSeconds);
|
|
9206
9698
|
if (!input.images && !input.projectId) {
|
|
9207
9699
|
throw new Error("images es requerido salvo que env\xEDes projectId.");
|
|
9208
9700
|
}
|
|
@@ -9602,58 +10094,58 @@ __name(registerTaskTools, "registerTaskTools");
|
|
|
9602
10094
|
|
|
9603
10095
|
// src/tools/creatives.ts
|
|
9604
10096
|
import { randomUUID } from "crypto";
|
|
9605
|
-
import { z as
|
|
10097
|
+
import { z as z47 } from "zod";
|
|
9606
10098
|
var CreativeRefs = {
|
|
9607
10099
|
images: ImagesInput,
|
|
9608
10100
|
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.'),
|
|
9609
10101
|
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.'),
|
|
9610
|
-
price:
|
|
9611
|
-
offer:
|
|
9612
|
-
compareAtPrice:
|
|
9613
|
-
paymentMethods:
|
|
9614
|
-
productContext:
|
|
9615
|
-
productLabel:
|
|
9616
|
-
buyerPersona:
|
|
9617
|
-
isCombo:
|
|
9618
|
-
competitorScanEnabled:
|
|
9619
|
-
brandId:
|
|
9620
|
-
projectId:
|
|
9621
|
-
creativeDirection:
|
|
9622
|
-
headline:
|
|
9623
|
-
subheadline:
|
|
10102
|
+
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.'),
|
|
10103
|
+
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.'),
|
|
10104
|
+
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".'),
|
|
10105
|
+
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.'),
|
|
10106
|
+
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."),
|
|
10107
|
+
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.'),
|
|
10108
|
+
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.'),
|
|
10109
|
+
isCombo: z47.boolean().optional().describe("Opcional. Si true, el creativo presenta el producto como combo/pack. Default false."),
|
|
10110
|
+
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."),
|
|
10111
|
+
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."),
|
|
10112
|
+
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."),
|
|
10113
|
+
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.'),
|
|
10114
|
+
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."),
|
|
10115
|
+
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.")
|
|
9624
10116
|
};
|
|
9625
|
-
var VideoInput =
|
|
10117
|
+
var VideoInput = z47.object({
|
|
9626
10118
|
images: CreativeRefs.images,
|
|
9627
|
-
title:
|
|
9628
|
-
primaryAngle:
|
|
10119
|
+
title: z47.string().min(1).describe('T\xEDtulo corto del producto. Aparece en la primera vista del video. Ej. "Crema Anti-Edad Premium".'),
|
|
10120
|
+
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".'),
|
|
9629
10121
|
language: CreativeRefs.language,
|
|
9630
10122
|
country: CreativeRefs.country,
|
|
9631
|
-
aspectRatio:
|
|
10123
|
+
aspectRatio: z47.enum([
|
|
9632
10124
|
"9:16",
|
|
9633
10125
|
"16:9",
|
|
9634
10126
|
"Auto"
|
|
9635
10127
|
]).describe('Relaci\xF3n de aspecto. "9:16" = vertical (TikTok/Reels \u2014 default recomendado para ads). "16:9" = horizontal (YouTube). "Auto" = decide la IA.'),
|
|
9636
|
-
durationSeconds:
|
|
9637
|
-
|
|
9638
|
-
|
|
10128
|
+
durationSeconds: z47.union([
|
|
10129
|
+
z47.literal(15),
|
|
10130
|
+
z47.literal(30)
|
|
9639
10131
|
]).default(15).describe("Opcional. Duraci\xF3n objetivo: 15s (single_call, default) o 30s (Multiescena, aproximadamente 30s y facturado por escena)."),
|
|
9640
|
-
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
|
|
10132
|
+
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).'),
|
|
9641
10133
|
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.'),
|
|
9642
10134
|
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).'),
|
|
9643
|
-
features:
|
|
10135
|
+
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"].'),
|
|
9644
10136
|
price: CreativeRefs.price,
|
|
9645
10137
|
offer: CreativeRefs.offer,
|
|
9646
10138
|
productContext: CreativeRefs.productContext,
|
|
9647
10139
|
productLabel: CreativeRefs.productLabel,
|
|
9648
|
-
cta:
|
|
9649
|
-
scriptNotes:
|
|
9650
|
-
pauseForVideoScriptReview:
|
|
9651
|
-
pauseForAngleReview:
|
|
10140
|
+
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.'),
|
|
10141
|
+
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.'),
|
|
10142
|
+
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."),
|
|
10143
|
+
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."),
|
|
9652
10144
|
competitorScanEnabled: CreativeRefs.competitorScanEnabled,
|
|
9653
10145
|
brandId: CreativeRefs.brandId,
|
|
9654
10146
|
projectId: CreativeRefs.projectId
|
|
9655
10147
|
}).strict();
|
|
9656
|
-
var FreeVideoQualityEnum =
|
|
10148
|
+
var FreeVideoQualityEnum = z47.enum([
|
|
9657
10149
|
"economical",
|
|
9658
10150
|
"high_detail"
|
|
9659
10151
|
]);
|
|
@@ -9675,38 +10167,38 @@ var FREE_VIDEO_DURATIONS_BY_QUALITY = {
|
|
|
9675
10167
|
15
|
|
9676
10168
|
]
|
|
9677
10169
|
};
|
|
9678
|
-
var FreeVideoInput =
|
|
10170
|
+
var FreeVideoInput = z47.object({
|
|
9679
10171
|
images: ImagesInput.optional().describe("Opcional. 1-5 fotos del producto. Om\xEDtelo para generar desde texto puro."),
|
|
9680
|
-
rawPrompt:
|
|
10172
|
+
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."),
|
|
9681
10173
|
quality: FreeVideoQualityEnum.describe('Calidad del video: "economical" = Econ\xF3mico o "high_detail" = Alto detalle.'),
|
|
9682
|
-
durationSeconds:
|
|
10174
|
+
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."),
|
|
9683
10175
|
videoResolution: VideoResolutionEnum.describe("Resoluci\xF3n del video: 480p o 720p."),
|
|
9684
|
-
generateAiMusic:
|
|
9685
|
-
addSubtitles:
|
|
9686
|
-
idempotencyKey:
|
|
10176
|
+
generateAiMusic: z47.boolean().default(false).describe("Opcional. Agrega m\xFAsica instrumental IA debajo del audio nativo. Default false."),
|
|
10177
|
+
addSubtitles: z47.boolean().default(false).describe("Opcional. Quema subt\xEDtulos usando el rawPrompt exacto. Default false."),
|
|
10178
|
+
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.")
|
|
9687
10179
|
}).strict();
|
|
9688
10180
|
var imageStyleList = ImageCreativeStyleEnum.options.join(" | ");
|
|
9689
10181
|
var archetypeList = ImageCreativeArchetypeEnum.options.join(" | ");
|
|
9690
10182
|
var visualTreatmentList = ImageCreativeVisualTreatmentEnum.options.join(" | ");
|
|
9691
10183
|
var aspectRatioList = ImageCreativeAspectRatioEnum.options.join(" | ");
|
|
9692
|
-
var ImageInput =
|
|
10184
|
+
var ImageInput = z47.object({
|
|
9693
10185
|
images: CreativeRefs.images,
|
|
9694
|
-
productTitle:
|
|
9695
|
-
primaryAngle:
|
|
10186
|
+
productTitle: z47.string().min(1).describe('Nombre del producto. Ej. "Crema Anti-Edad Premium".'),
|
|
10187
|
+
primaryAngle: z47.string().min(1).describe('\xC1ngulo de venta principal. Ej. "Reduce arrugas en 14 d\xEDas".'),
|
|
9696
10188
|
buyerPersona: CreativeRefs.buyerPersona,
|
|
9697
10189
|
language: CreativeRefs.language,
|
|
9698
10190
|
country: CreativeRefs.country,
|
|
9699
|
-
nVariants:
|
|
9700
|
-
imageModel:
|
|
10191
|
+
nVariants: z47.number().int().min(1).max(6).optional().describe("Opcional. N\xFAmero de variantes a generar (1-6). Default 3."),
|
|
10192
|
+
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.'),
|
|
9701
10193
|
imageStyle: ImageCreativeStyleEnum.optional().describe(`Opcional. Estilo del shot del producto. Valores: ${imageStyleList}. Si se omite, la IA escoge seg\xFAn el archetype.`),
|
|
9702
10194
|
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).`),
|
|
9703
10195
|
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.`),
|
|
9704
|
-
styleMix:
|
|
10196
|
+
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."),
|
|
9705
10197
|
aspectRatio: ImageCreativeAspectRatioEnum.optional().describe(`Opcional. Relaci\xF3n de aspecto. Valores: ${aspectRatioList}. Default "4:5" (vertical Instagram feed).`),
|
|
9706
|
-
generateAdCopy:
|
|
9707
|
-
pauseForAngleReview:
|
|
9708
|
-
features:
|
|
9709
|
-
brandColors:
|
|
10198
|
+
generateAdCopy: z47.boolean().optional().describe("Opcional. Si true, tambi\xE9n genera headline/body/CTA para el ad. Default false."),
|
|
10199
|
+
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."),
|
|
10200
|
+
features: z47.array(z47.string()).optional().describe('Opcional. Features/beneficios a destacar visualmente. Ej. ["resistente al agua", "ultra liviano"].'),
|
|
10201
|
+
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.'),
|
|
9710
10202
|
price: CreativeRefs.price,
|
|
9711
10203
|
compareAtPrice: CreativeRefs.compareAtPrice,
|
|
9712
10204
|
offer: CreativeRefs.offer,
|
|
@@ -9720,16 +10212,16 @@ var ImageInput = z45.object({
|
|
|
9720
10212
|
headline: CreativeRefs.headline,
|
|
9721
10213
|
subheadline: CreativeRefs.subheadline
|
|
9722
10214
|
});
|
|
9723
|
-
var EditImageCreativeInput =
|
|
9724
|
-
taskId:
|
|
9725
|
-
variantIndex:
|
|
9726
|
-
instruction:
|
|
10215
|
+
var EditImageCreativeInput = z47.object({
|
|
10216
|
+
taskId: z47.string().uuid().describe("ID de la tarea de imagen ya finalizada."),
|
|
10217
|
+
variantIndex: z47.number().int().min(0).max(10).describe("\xCDndice de la variante a corregir (0 = primera imagen)."),
|
|
10218
|
+
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".')
|
|
9727
10219
|
});
|
|
9728
|
-
var LandingInput =
|
|
10220
|
+
var LandingInput = z47.object({
|
|
9729
10221
|
images: CreativeRefs.images,
|
|
9730
10222
|
language: CreativeRefs.language,
|
|
9731
10223
|
country: CreativeRefs.country,
|
|
9732
|
-
salesAngle:
|
|
10224
|
+
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.'),
|
|
9733
10225
|
buyerPersona: CreativeRefs.buyerPersona,
|
|
9734
10226
|
price: CreativeRefs.price,
|
|
9735
10227
|
compareAtPrice: CreativeRefs.compareAtPrice,
|
|
@@ -9780,7 +10272,6 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
|
|
|
9780
10272
|
});
|
|
9781
10273
|
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) => {
|
|
9782
10274
|
try {
|
|
9783
|
-
assertVideoPresetDurationCompatibility(input.videoPreset, input.durationSeconds);
|
|
9784
10275
|
const resolved = resolveVideoPreset(input.videoPreset);
|
|
9785
10276
|
const wireTier = resolveWireVideoTier(input.videoTier, input.durationSeconds);
|
|
9786
10277
|
const { videoTier: _publicTier, videoResolution: _vr, projectId, ...rest } = input;
|
|
@@ -9855,8 +10346,8 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
|
|
|
9855
10346
|
__name(registerCreativeTools, "registerCreativeTools");
|
|
9856
10347
|
|
|
9857
10348
|
// src/tools/creative-variants.ts
|
|
9858
|
-
import { z as
|
|
9859
|
-
var LandingSectionKeyEnum =
|
|
10349
|
+
import { z as z48 } from "zod";
|
|
10350
|
+
var LandingSectionKeyEnum = z48.enum([
|
|
9860
10351
|
"problem_hook",
|
|
9861
10352
|
"problem_cost",
|
|
9862
10353
|
"solution_mechanism",
|
|
@@ -9896,24 +10387,24 @@ var LandingSectionKeyEnum = z46.enum([
|
|
|
9896
10387
|
"lifestyle_fit",
|
|
9897
10388
|
"join_lifestyle"
|
|
9898
10389
|
]);
|
|
9899
|
-
var CreativeVariantKindEnum =
|
|
10390
|
+
var CreativeVariantKindEnum = z48.enum([
|
|
9900
10391
|
"video",
|
|
9901
10392
|
"image",
|
|
9902
10393
|
"landing"
|
|
9903
10394
|
]);
|
|
9904
|
-
var EstimateCreativeVariantInputBase =
|
|
9905
|
-
sourceTaskId:
|
|
10395
|
+
var EstimateCreativeVariantInputBase = z48.object({
|
|
10396
|
+
sourceTaskId: z48.string().uuid().describe("ID de la tarea original completada."),
|
|
9906
10397
|
kind: CreativeVariantKindEnum,
|
|
9907
10398
|
videoPreset: TaskCreativeVariantVideoPresetEnum.optional().describe("Opcional para video. Solo cambia el preset p\xFAblico; el servidor conserva el modelo/tier del task origen."),
|
|
9908
10399
|
videoResolution: VideoResolutionEnum.optional().describe("Opcional para video. Resoluci\xF3n del nuevo render."),
|
|
9909
|
-
nVariants:
|
|
10400
|
+
nVariants: z48.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
|
|
9910
10401
|
sectionKey: LandingSectionKeyEnum.optional().describe("Opcional para landing. Si ya conoces la secci\xF3n, evita cotizar la clasificaci\xF3n con IA."),
|
|
9911
|
-
instructions:
|
|
10402
|
+
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.")
|
|
9912
10403
|
}).strict();
|
|
9913
10404
|
var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine((input, ctx) => {
|
|
9914
10405
|
if (input.kind === "video" && input.nVariants !== void 0) {
|
|
9915
10406
|
ctx.addIssue({
|
|
9916
|
-
code:
|
|
10407
|
+
code: z48.ZodIssueCode.custom,
|
|
9917
10408
|
path: [
|
|
9918
10409
|
"nVariants"
|
|
9919
10410
|
],
|
|
@@ -9923,7 +10414,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
|
|
|
9923
10414
|
if (input.kind !== "video") {
|
|
9924
10415
|
if (input.videoPreset !== void 0) {
|
|
9925
10416
|
ctx.addIssue({
|
|
9926
|
-
code:
|
|
10417
|
+
code: z48.ZodIssueCode.custom,
|
|
9927
10418
|
path: [
|
|
9928
10419
|
"videoPreset"
|
|
9929
10420
|
],
|
|
@@ -9932,7 +10423,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
|
|
|
9932
10423
|
}
|
|
9933
10424
|
if (input.videoResolution !== void 0) {
|
|
9934
10425
|
ctx.addIssue({
|
|
9935
|
-
code:
|
|
10426
|
+
code: z48.ZodIssueCode.custom,
|
|
9936
10427
|
path: [
|
|
9937
10428
|
"videoResolution"
|
|
9938
10429
|
],
|
|
@@ -9942,7 +10433,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
|
|
|
9942
10433
|
}
|
|
9943
10434
|
if (input.kind !== "image" && input.nVariants !== void 0) {
|
|
9944
10435
|
ctx.addIssue({
|
|
9945
|
-
code:
|
|
10436
|
+
code: z48.ZodIssueCode.custom,
|
|
9946
10437
|
path: [
|
|
9947
10438
|
"nVariants"
|
|
9948
10439
|
],
|
|
@@ -9952,7 +10443,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
|
|
|
9952
10443
|
if (input.kind !== "landing") {
|
|
9953
10444
|
if (input.sectionKey !== void 0) {
|
|
9954
10445
|
ctx.addIssue({
|
|
9955
|
-
code:
|
|
10446
|
+
code: z48.ZodIssueCode.custom,
|
|
9956
10447
|
path: [
|
|
9957
10448
|
"sectionKey"
|
|
9958
10449
|
],
|
|
@@ -9961,7 +10452,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
|
|
|
9961
10452
|
}
|
|
9962
10453
|
if (input.instructions !== void 0) {
|
|
9963
10454
|
ctx.addIssue({
|
|
9964
|
-
code:
|
|
10455
|
+
code: z48.ZodIssueCode.custom,
|
|
9965
10456
|
path: [
|
|
9966
10457
|
"instructions"
|
|
9967
10458
|
],
|
|
@@ -9970,31 +10461,31 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
|
|
|
9970
10461
|
}
|
|
9971
10462
|
}
|
|
9972
10463
|
});
|
|
9973
|
-
var CreateCreativeVariantInputBase =
|
|
9974
|
-
sourceTaskId:
|
|
10464
|
+
var CreateCreativeVariantInputBase = z48.object({
|
|
10465
|
+
sourceTaskId: z48.string().uuid().describe("ID de la tarea original completada."),
|
|
9975
10466
|
kind: CreativeVariantKindEnum,
|
|
9976
|
-
confirm:
|
|
9977
|
-
clientRequestId:
|
|
9978
|
-
angle:
|
|
9979
|
-
buyerPersona:
|
|
9980
|
-
scriptNotes:
|
|
9981
|
-
creativeDirection:
|
|
10467
|
+
confirm: z48.literal(true).describe("Confirmaci\xF3n expl\xEDcita del usuario despu\xE9s de mostrarle el estimado de cr\xE9ditos."),
|
|
10468
|
+
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."),
|
|
10469
|
+
angle: z48.string().trim().min(1).max(500).optional().describe("\xC1ngulo nuevo para video o imagen."),
|
|
10470
|
+
buyerPersona: z48.string().trim().min(1).max(360).optional().describe("Buyer persona coherente con el \xE1ngulo."),
|
|
10471
|
+
scriptNotes: z48.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n breve del guion para una variante de video."),
|
|
10472
|
+
creativeDirection: z48.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n creativa para una variante de imagen."),
|
|
9982
10473
|
videoPreset: TaskCreativeVariantVideoPresetEnum.optional().describe("Opcional para video. Preset p\xFAblico; el servidor resuelve modelo/tier desde el task origen."),
|
|
9983
10474
|
videoResolution: VideoResolutionEnum.optional().describe("Opcional para video."),
|
|
9984
|
-
generateAiMusic:
|
|
9985
|
-
nVariants:
|
|
10475
|
+
generateAiMusic: z48.boolean().optional().describe("Opcional para video."),
|
|
10476
|
+
nVariants: z48.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
|
|
9986
10477
|
imageStyle: ImageCreativeStyleEnum.optional().describe("Opcional para imagen."),
|
|
9987
10478
|
creativeArchetype: ImageCreativeArchetypeEnum.optional().describe("Opcional para imagen."),
|
|
9988
10479
|
visualTreatment: ImageCreativeVisualTreatmentEnum.optional().describe("Opcional para imagen."),
|
|
9989
10480
|
aspectRatio: ImageCreativeAspectRatioEnum.optional().describe("Opcional para imagen."),
|
|
9990
|
-
styleMix:
|
|
10481
|
+
styleMix: z48.boolean().optional().describe("Opcional para imagen."),
|
|
9991
10482
|
sectionKey: LandingSectionKeyEnum.optional().describe("Opcional para landing. Si se omite, se clasifica con IA a partir de instructions."),
|
|
9992
|
-
instructions:
|
|
10483
|
+
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.")
|
|
9993
10484
|
}).strict();
|
|
9994
10485
|
var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((input, ctx) => {
|
|
9995
10486
|
if ((input.kind === "video" || input.kind === "image") && !input.angle) {
|
|
9996
10487
|
ctx.addIssue({
|
|
9997
|
-
code:
|
|
10488
|
+
code: z48.ZodIssueCode.custom,
|
|
9998
10489
|
path: [
|
|
9999
10490
|
"angle"
|
|
10000
10491
|
],
|
|
@@ -10003,7 +10494,7 @@ var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((inp
|
|
|
10003
10494
|
}
|
|
10004
10495
|
if (input.kind === "landing" && !input.sectionKey && !input.instructions) {
|
|
10005
10496
|
ctx.addIssue({
|
|
10006
|
-
code:
|
|
10497
|
+
code: z48.ZodIssueCode.custom,
|
|
10007
10498
|
path: [
|
|
10008
10499
|
"instructions"
|
|
10009
10500
|
],
|
|
@@ -10049,7 +10540,7 @@ var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((inp
|
|
|
10049
10540
|
for (const field of fieldsByKind[input.kind]) {
|
|
10050
10541
|
if (input[field] !== void 0) {
|
|
10051
10542
|
ctx.addIssue({
|
|
10052
|
-
code:
|
|
10543
|
+
code: z48.ZodIssueCode.custom,
|
|
10053
10544
|
path: [
|
|
10054
10545
|
field
|
|
10055
10546
|
],
|
|
@@ -10166,27 +10657,27 @@ function registerCreativeVariantTools(server, api) {
|
|
|
10166
10657
|
__name(registerCreativeVariantTools, "registerCreativeVariantTools");
|
|
10167
10658
|
|
|
10168
10659
|
// src/tools/script-review.ts
|
|
10169
|
-
import { z as
|
|
10170
|
-
var GetVideoScriptInput =
|
|
10171
|
-
taskId:
|
|
10172
|
-
angleKey:
|
|
10660
|
+
import { z as z49 } from "zod";
|
|
10661
|
+
var GetVideoScriptInput = z49.object({
|
|
10662
|
+
taskId: z49.string().min(1).describe("ID de la tarea (la misma que devolvi\xF3 create_product_task / generate_video_creative)."),
|
|
10663
|
+
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.')
|
|
10173
10664
|
}).strict();
|
|
10174
10665
|
var VIDEO_SCRIPT_APPROVAL_MAX_SCENES2 = 50;
|
|
10175
10666
|
var VIDEO_SCRIPT_APPROVAL_MAX_DIALOGUE_CHARS2 = 2e3;
|
|
10176
|
-
var ApproveSceneEdit =
|
|
10177
|
-
index:
|
|
10178
|
-
dialogue:
|
|
10667
|
+
var ApproveSceneEdit = z49.object({
|
|
10668
|
+
index: z49.number().int().nonnegative().describe("\xCDndice de la escena (0-based, mismo que devuelve get_video_script)."),
|
|
10669
|
+
dialogue: z49.string().min(1).max(VIDEO_SCRIPT_APPROVAL_MAX_DIALOGUE_CHARS2).refine((v) => v.trim().length > 0, {
|
|
10179
10670
|
message: "dialogue no puede ser s\xF3lo espacios"
|
|
10180
10671
|
}).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.")
|
|
10181
10672
|
}).strict();
|
|
10182
|
-
var ApproveVideoScriptInput =
|
|
10183
|
-
taskId:
|
|
10184
|
-
angleKey:
|
|
10185
|
-
scenes:
|
|
10673
|
+
var ApproveVideoScriptInput = z49.object({
|
|
10674
|
+
taskId: z49.string().min(1).describe("ID de la tarea."),
|
|
10675
|
+
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.'),
|
|
10676
|
+
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.")
|
|
10186
10677
|
}).strict();
|
|
10187
|
-
var RegenerateVideoScriptInput =
|
|
10188
|
-
taskId:
|
|
10189
|
-
angleKey:
|
|
10678
|
+
var RegenerateVideoScriptInput = z49.object({
|
|
10679
|
+
taskId: z49.string().min(1).describe("ID de la tarea."),
|
|
10680
|
+
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.'),
|
|
10190
10681
|
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).')
|
|
10191
10682
|
}).strict();
|
|
10192
10683
|
function registerScriptReviewTools(server, api) {
|
|
@@ -10226,9 +10717,9 @@ function registerScriptReviewTools(server, api) {
|
|
|
10226
10717
|
__name(registerScriptReviewTools, "registerScriptReviewTools");
|
|
10227
10718
|
|
|
10228
10719
|
// src/tools/connections.ts
|
|
10229
|
-
import { z as
|
|
10720
|
+
import { z as z50 } from "zod";
|
|
10230
10721
|
function registerConnectionTools(server, api) {
|
|
10231
|
-
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.",
|
|
10722
|
+
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 () => {
|
|
10232
10723
|
try {
|
|
10233
10724
|
const r = await api.getJson("/v1/shopify/shops");
|
|
10234
10725
|
return asText(r);
|
|
@@ -10236,10 +10727,10 @@ function registerConnectionTools(server, api) {
|
|
|
10236
10727
|
throw translateError(e);
|
|
10237
10728
|
}
|
|
10238
10729
|
});
|
|
10239
|
-
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.',
|
|
10240
|
-
shopDomain:
|
|
10241
|
-
query:
|
|
10242
|
-
taskId:
|
|
10730
|
+
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({
|
|
10731
|
+
shopDomain: z50.string().min(3).max(120),
|
|
10732
|
+
query: z50.string().trim().max(120).optional(),
|
|
10733
|
+
taskId: z50.string().uuid().optional()
|
|
10243
10734
|
}).shape, async ({ shopDomain, query, taskId }) => {
|
|
10244
10735
|
try {
|
|
10245
10736
|
const params = new URLSearchParams({
|
|
@@ -10253,7 +10744,7 @@ function registerConnectionTools(server, api) {
|
|
|
10253
10744
|
throw translateError(e);
|
|
10254
10745
|
}
|
|
10255
10746
|
});
|
|
10256
|
-
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.",
|
|
10747
|
+
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 () => {
|
|
10257
10748
|
try {
|
|
10258
10749
|
const r = await api.getJson("/v1/facebook/ad-accounts");
|
|
10259
10750
|
return asText(r);
|
|
@@ -10261,7 +10752,21 @@ function registerConnectionTools(server, api) {
|
|
|
10261
10752
|
throw translateError(e);
|
|
10262
10753
|
}
|
|
10263
10754
|
});
|
|
10264
|
-
server.
|
|
10755
|
+
server.registerTool("list_meta_destinations", {
|
|
10756
|
+
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.",
|
|
10757
|
+
inputSchema: z50.object({}).shape,
|
|
10758
|
+
_meta: {
|
|
10759
|
+
"openai/widgetAccessible": true
|
|
10760
|
+
}
|
|
10761
|
+
}, async () => {
|
|
10762
|
+
try {
|
|
10763
|
+
const r = await api.getJson("/v1/facebook/destinations");
|
|
10764
|
+
return asText(r);
|
|
10765
|
+
} catch (e) {
|
|
10766
|
+
throw translateError(e);
|
|
10767
|
+
}
|
|
10768
|
+
});
|
|
10769
|
+
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 () => {
|
|
10265
10770
|
try {
|
|
10266
10771
|
const r = await api.getJson("/v1/tiktok/advertisers");
|
|
10267
10772
|
return asText(r);
|
|
@@ -10273,9 +10778,9 @@ function registerConnectionTools(server, api) {
|
|
|
10273
10778
|
__name(registerConnectionTools, "registerConnectionTools");
|
|
10274
10779
|
|
|
10275
10780
|
// src/tools/actors.ts
|
|
10276
|
-
import { z as
|
|
10781
|
+
import { z as z51 } from "zod";
|
|
10277
10782
|
function registerActorTools(server, api) {
|
|
10278
|
-
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.",
|
|
10783
|
+
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 () => {
|
|
10279
10784
|
try {
|
|
10280
10785
|
const rows = await api.getJson("/v1/actors");
|
|
10281
10786
|
const actors = (Array.isArray(rows) ? rows : []).filter((actor) => actor.status === "ready").map(({ id, name, description, gender, voiceId }) => ({
|
|
@@ -10296,105 +10801,116 @@ function registerActorTools(server, api) {
|
|
|
10296
10801
|
__name(registerActorTools, "registerActorTools");
|
|
10297
10802
|
|
|
10298
10803
|
// src/tools/publish.ts
|
|
10299
|
-
import { z as
|
|
10300
|
-
var ShopifyInput =
|
|
10301
|
-
taskId:
|
|
10302
|
-
shopDomain:
|
|
10804
|
+
import { z as z52 } from "zod";
|
|
10805
|
+
var ShopifyInput = z52.object({
|
|
10806
|
+
taskId: z52.string().min(1),
|
|
10807
|
+
shopDomain: z52.string().min(1),
|
|
10303
10808
|
/** Override: number of landing images to include. Default = ALL images the
|
|
10304
10809
|
* task generated (the MCP fetches /v1/results first to count). Bounded
|
|
10305
10810
|
* generously here; the backend validates each index against
|
|
10306
10811
|
* landing.images.length and rejects out-of-range. */
|
|
10307
|
-
numLandingImages:
|
|
10308
|
-
variantIndex:
|
|
10812
|
+
numLandingImages: z52.number().int().min(1).max(20).optional(),
|
|
10813
|
+
variantIndex: z52.number().int().min(0).optional(),
|
|
10309
10814
|
/** ASK THE USER before setting: "¿Tu producto tiene variantes (talla, color, etc.)?".
|
|
10310
10815
|
* When true, the landing renders variant-picker pills; when false, it ships
|
|
10311
10816
|
* a single-option product page. Defaults to false. */
|
|
10312
|
-
showVariantPicker:
|
|
10817
|
+
showVariantPicker: z52.boolean().optional(),
|
|
10313
10818
|
/** Default `auto` updates the product previously published for this task and
|
|
10314
10819
|
* shop. Use `existing` with targetProductId to choose another product, or
|
|
10315
10820
|
* `new` only when the user explicitly wants a duplicate/new listing. */
|
|
10316
|
-
publicationMode:
|
|
10821
|
+
publicationMode: z52.enum([
|
|
10317
10822
|
"auto",
|
|
10318
10823
|
"existing",
|
|
10319
10824
|
"new"
|
|
10320
10825
|
]).optional(),
|
|
10321
10826
|
/** Shopify product GID, numeric id, or admin product URL. Required when
|
|
10322
10827
|
* publicationMode is `existing`. */
|
|
10323
|
-
targetProductId:
|
|
10828
|
+
targetProductId: z52.string().trim().min(1).max(300).optional()
|
|
10324
10829
|
});
|
|
10325
|
-
var McpCampaignConfig =
|
|
10830
|
+
var McpCampaignConfig = z52.object({
|
|
10326
10831
|
/** ALWAYS in US dollars, whatever the ad account's currency is. ProductMaker
|
|
10327
10832
|
* converts to the account currency server-side. Do NOT pre-convert: on a COP
|
|
10328
10833
|
* account the user's "60.000 al día" is `dailyBudgetUsd: 15`, not 60000. */
|
|
10329
|
-
dailyBudgetUsd:
|
|
10834
|
+
dailyBudgetUsd: z52.number().positive().optional(),
|
|
10330
10835
|
/** ISO-3166-1 alpha-2 country codes. Meta accepts max 1 (single-country
|
|
10331
10836
|
* ad set). TikTok takes only the first entry. */
|
|
10332
|
-
targetCountries:
|
|
10333
|
-
campaignName:
|
|
10837
|
+
targetCountries: z52.array(z52.string().length(2)).max(1).optional(),
|
|
10838
|
+
campaignName: z52.string().trim().min(1).max(100).optional()
|
|
10334
10839
|
});
|
|
10335
10840
|
var McpAdAccountId = MetaAdAccountId.describe('Meta ad account id. Accepts "act_1234567890" or the bare numeric id "1234567890".');
|
|
10336
|
-
var MetaInput =
|
|
10337
|
-
taskId:
|
|
10841
|
+
var MetaInput = z52.object({
|
|
10842
|
+
taskId: z52.string().min(1),
|
|
10843
|
+
/** Exact Meta Business portfolio selected from `list_meta_destinations`. */
|
|
10844
|
+
portfolioId: z52.string().trim().min(1),
|
|
10845
|
+
/** Exact Facebook Page selected from `list_meta_destinations`. */
|
|
10846
|
+
pageId: z52.string().trim().min(1),
|
|
10338
10847
|
adAccountId: McpAdAccountId,
|
|
10339
|
-
pixelId:
|
|
10340
|
-
landingUrl:
|
|
10848
|
+
pixelId: z52.string().min(1).optional(),
|
|
10849
|
+
landingUrl: z52.string().url().optional(),
|
|
10341
10850
|
/** Select which angles to publish by 0-based index. Omit to publish all
|
|
10342
10851
|
* successful angles. Example: a task with 3 angles → `[0,2]` publishes #0 + #2. */
|
|
10343
|
-
angleIndexes:
|
|
10852
|
+
angleIndexes: z52.array(z52.number().int().nonnegative()).optional(),
|
|
10344
10853
|
campaignConfig: McpCampaignConfig.optional(),
|
|
10345
10854
|
/** Override the ad's primary text (body copy). If omitted, ProductMaker
|
|
10346
10855
|
* uses the auto-generated copy attached to the task. Capped at 500 chars
|
|
10347
10856
|
* (Meta's primary-text limit). */
|
|
10348
|
-
primaryText:
|
|
10857
|
+
primaryText: z52.string().trim().min(1).max(500).optional(),
|
|
10349
10858
|
/** Optional WhatsApp number. When set, the ad button opens a WhatsApp chat
|
|
10350
10859
|
* (wa.me) instead of a landing page. */
|
|
10351
|
-
phoneNumber:
|
|
10860
|
+
phoneNumber: z52.string().min(8).max(32).optional()
|
|
10352
10861
|
});
|
|
10353
|
-
var GroupedTaskSource =
|
|
10354
|
-
type:
|
|
10355
|
-
taskId:
|
|
10356
|
-
angleIndex:
|
|
10357
|
-
videoVariant:
|
|
10862
|
+
var GroupedTaskSource = z52.object({
|
|
10863
|
+
type: z52.literal("task"),
|
|
10864
|
+
taskId: z52.string().min(1),
|
|
10865
|
+
angleIndex: z52.number().int().min(0).optional(),
|
|
10866
|
+
videoVariant: z52.enum([
|
|
10358
10867
|
"with_subtitles",
|
|
10359
10868
|
"without_subtitles"
|
|
10360
10869
|
]).optional(),
|
|
10361
|
-
imageVariantIndex:
|
|
10362
|
-
});
|
|
10363
|
-
var GroupedMediaSource =
|
|
10364
|
-
type:
|
|
10365
|
-
url:
|
|
10366
|
-
path:
|
|
10367
|
-
thumbnailUrl:
|
|
10368
|
-
thumbnailPath:
|
|
10870
|
+
imageVariantIndex: z52.number().int().min(0).optional()
|
|
10871
|
+
});
|
|
10872
|
+
var GroupedMediaSource = z52.object({
|
|
10873
|
+
type: z52.literal("media"),
|
|
10874
|
+
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."),
|
|
10875
|
+
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".'),
|
|
10876
|
+
thumbnailUrl: z52.string().url().optional(),
|
|
10877
|
+
thumbnailPath: z52.string().min(1).optional()
|
|
10369
10878
|
}).refine((value) => Boolean(value.url) !== Boolean(value.path), {
|
|
10370
10879
|
message: "media source needs exactly one of `url` or `path`"
|
|
10371
10880
|
}).refine((value) => !(value.thumbnailUrl && value.thumbnailPath), {
|
|
10372
10881
|
message: "media source needs at most one of `thumbnailUrl` or `thumbnailPath`"
|
|
10373
10882
|
});
|
|
10374
|
-
var
|
|
10375
|
-
type:
|
|
10883
|
+
var GroupedStagedMediaSource = z52.object({
|
|
10884
|
+
type: z52.literal("staged"),
|
|
10885
|
+
/** Returned by check_meta_media_upload after the user selects a local file. */
|
|
10886
|
+
stagingAssetId: z52.string().uuid(),
|
|
10887
|
+
thumbnailAssetId: z52.string().uuid().optional()
|
|
10888
|
+
});
|
|
10889
|
+
var GroupedCreative = z52.object({
|
|
10890
|
+
type: z52.enum([
|
|
10376
10891
|
"image",
|
|
10377
10892
|
"video"
|
|
10378
10893
|
]),
|
|
10379
|
-
source:
|
|
10894
|
+
source: z52.union([
|
|
10380
10895
|
GroupedTaskSource,
|
|
10381
|
-
GroupedMediaSource
|
|
10896
|
+
GroupedMediaSource,
|
|
10897
|
+
GroupedStagedMediaSource
|
|
10382
10898
|
]),
|
|
10383
|
-
title:
|
|
10384
|
-
description:
|
|
10899
|
+
title: z52.string().max(120).optional(),
|
|
10900
|
+
description: z52.string().max(500).optional(),
|
|
10385
10901
|
cta: MetaCtaType.optional(),
|
|
10386
|
-
creativeId:
|
|
10902
|
+
creativeId: z52.string().min(1).optional()
|
|
10387
10903
|
});
|
|
10388
|
-
var GroupedCampaignConfig =
|
|
10904
|
+
var GroupedCampaignConfig = z52.object({
|
|
10389
10905
|
campaignType: MetaCampaignType.default("sales"),
|
|
10390
10906
|
optimizationMode: MetaOptimizationMode.default("advantage_plus"),
|
|
10391
10907
|
budgetMode: MetaBudgetMode.default("campaign"),
|
|
10392
|
-
campaignDailyBudget:
|
|
10393
|
-
adSets:
|
|
10394
|
-
tempId:
|
|
10395
|
-
name:
|
|
10396
|
-
dailyBudget:
|
|
10397
|
-
creativeIds:
|
|
10908
|
+
campaignDailyBudget: z52.number().int().positive().optional(),
|
|
10909
|
+
adSets: z52.array(z52.object({
|
|
10910
|
+
tempId: z52.string().min(1).max(80),
|
|
10911
|
+
name: z52.string().min(1).max(100),
|
|
10912
|
+
dailyBudget: z52.number().int().positive().optional(),
|
|
10913
|
+
creativeIds: z52.array(z52.string().min(1)).min(1)
|
|
10398
10914
|
})).min(1).max(CAMPAIGN_LIMITS.MAX_AD_SETS),
|
|
10399
10915
|
/**
|
|
10400
10916
|
* Valid values are 'landing' and 'whatsapp' — there is no 'website'. This
|
|
@@ -10402,22 +10918,22 @@ var GroupedCampaignConfig = z50.object({
|
|
|
10402
10918
|
* opaque `invalid_literal` and made the WhatsApp destination — supported by
|
|
10403
10919
|
* the API since #849 — unreachable from this tool.
|
|
10404
10920
|
*/
|
|
10405
|
-
destination:
|
|
10406
|
-
|
|
10407
|
-
type:
|
|
10408
|
-
landingUrl:
|
|
10921
|
+
destination: z52.discriminatedUnion("type", [
|
|
10922
|
+
z52.object({
|
|
10923
|
+
type: z52.literal("landing"),
|
|
10924
|
+
landingUrl: z52.string().url()
|
|
10409
10925
|
}),
|
|
10410
|
-
|
|
10411
|
-
type:
|
|
10412
|
-
phoneNumber:
|
|
10926
|
+
z52.object({
|
|
10927
|
+
type: z52.literal("whatsapp"),
|
|
10928
|
+
phoneNumber: z52.string().min(8).max(32)
|
|
10413
10929
|
})
|
|
10414
10930
|
]),
|
|
10415
|
-
saveAsDefault:
|
|
10931
|
+
saveAsDefault: z52.boolean().default(false),
|
|
10416
10932
|
budgetPolicy: MetaBudgetPolicy.optional()
|
|
10417
10933
|
}).superRefine((value, ctx) => {
|
|
10418
10934
|
if (value.budgetMode === "campaign" && value.campaignDailyBudget === void 0) {
|
|
10419
10935
|
ctx.addIssue({
|
|
10420
|
-
code:
|
|
10936
|
+
code: z52.ZodIssueCode.custom,
|
|
10421
10937
|
path: [
|
|
10422
10938
|
"campaignDailyBudget"
|
|
10423
10939
|
],
|
|
@@ -10428,7 +10944,7 @@ var GroupedCampaignConfig = z50.object({
|
|
|
10428
10944
|
value.adSets.forEach((adSet, index) => {
|
|
10429
10945
|
if (adSet.dailyBudget === void 0) {
|
|
10430
10946
|
ctx.addIssue({
|
|
10431
|
-
code:
|
|
10947
|
+
code: z52.ZodIssueCode.custom,
|
|
10432
10948
|
path: [
|
|
10433
10949
|
"adSets",
|
|
10434
10950
|
index,
|
|
@@ -10440,22 +10956,26 @@ var GroupedCampaignConfig = z50.object({
|
|
|
10440
10956
|
});
|
|
10441
10957
|
}
|
|
10442
10958
|
});
|
|
10443
|
-
var PublishCreativesToMetaInputBase =
|
|
10444
|
-
creatives:
|
|
10959
|
+
var PublishCreativesToMetaInputBase = z52.object({
|
|
10960
|
+
creatives: z52.array(GroupedCreative).min(1).max(CAMPAIGN_LIMITS.MAX_CREATIVES),
|
|
10961
|
+
/** Exact Meta Business portfolio selected from `list_meta_destinations`. */
|
|
10962
|
+
portfolioId: z52.string().trim().min(1),
|
|
10963
|
+
/** Exact Facebook Page selected from `list_meta_destinations`. */
|
|
10964
|
+
pageId: z52.string().trim().min(1),
|
|
10445
10965
|
adAccountId: McpAdAccountId,
|
|
10446
|
-
pixelId:
|
|
10966
|
+
pixelId: z52.string().min(1).optional(),
|
|
10447
10967
|
/** Required unless `campaignConfig.destination` is whatsapp — see the
|
|
10448
10968
|
* superRefine below. Mirrors the API's `UploadToMetaRequest`. */
|
|
10449
|
-
landingUrl:
|
|
10450
|
-
targetCountry:
|
|
10451
|
-
campaignName:
|
|
10969
|
+
landingUrl: z52.string().url().optional(),
|
|
10970
|
+
targetCountry: z52.string().length(2),
|
|
10971
|
+
campaignName: z52.string().trim().min(1).max(100),
|
|
10452
10972
|
campaignConfig: GroupedCampaignConfig.optional()
|
|
10453
10973
|
});
|
|
10454
10974
|
var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((value, ctx) => {
|
|
10455
10975
|
const destination = value.campaignConfig?.destination;
|
|
10456
10976
|
if (destination?.type !== "whatsapp" && !value.landingUrl) {
|
|
10457
10977
|
ctx.addIssue({
|
|
10458
|
-
code:
|
|
10978
|
+
code: z52.ZodIssueCode.custom,
|
|
10459
10979
|
path: [
|
|
10460
10980
|
"landingUrl"
|
|
10461
10981
|
],
|
|
@@ -10464,7 +10984,7 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
|
|
|
10464
10984
|
}
|
|
10465
10985
|
if (destination?.type === "landing" && destination.landingUrl !== value.landingUrl) {
|
|
10466
10986
|
ctx.addIssue({
|
|
10467
|
-
code:
|
|
10987
|
+
code: z52.ZodIssueCode.custom,
|
|
10468
10988
|
path: [
|
|
10469
10989
|
"campaignConfig",
|
|
10470
10990
|
"destination",
|
|
@@ -10474,46 +10994,50 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
|
|
|
10474
10994
|
});
|
|
10475
10995
|
}
|
|
10476
10996
|
});
|
|
10477
|
-
var PresignUploadResponseSchema =
|
|
10478
|
-
uploadUrl:
|
|
10997
|
+
var PresignUploadResponseSchema = z52.object({
|
|
10998
|
+
uploadUrl: z52.string().url().refine((value) => {
|
|
10479
10999
|
const url = new URL(value);
|
|
10480
11000
|
return !url.username && !url.password && url.protocol === "https:";
|
|
10481
11001
|
}, "presigned upload URL must be HTTPS without embedded credentials"),
|
|
10482
|
-
publicUrl:
|
|
11002
|
+
publicUrl: z52.string().url().refine((value) => {
|
|
10483
11003
|
const url = new URL(value);
|
|
10484
11004
|
return !url.username && !url.password;
|
|
10485
|
-
}, "public media URL must not contain embedded credentials")
|
|
11005
|
+
}, "public media URL must not contain embedded credentials"),
|
|
11006
|
+
stagingAssetId: z52.string().uuid()
|
|
10486
11007
|
});
|
|
10487
|
-
async function uploadResolvedMedia(api, media) {
|
|
10488
|
-
if (media.url) return media.url;
|
|
11008
|
+
async function uploadResolvedMedia(api, media, assetRole) {
|
|
10489
11009
|
if (!media.buffer) throw new ResolveMediaError("INVALID_INPUT", "resolved media has no bytes");
|
|
10490
11010
|
const presigned = PresignUploadResponseSchema.parse(await api.postJson("/v1/ads/presign-upload", {
|
|
10491
11011
|
contentType: media.mimetype,
|
|
10492
11012
|
fileName: media.filename,
|
|
10493
|
-
fileSize: media.buffer.byteLength
|
|
11013
|
+
fileSize: media.buffer.byteLength,
|
|
11014
|
+
purpose: "meta_staging",
|
|
11015
|
+
assetRole
|
|
10494
11016
|
}));
|
|
10495
11017
|
await api.putBytes(presigned.uploadUrl, media.buffer, media.mimetype);
|
|
10496
|
-
return
|
|
11018
|
+
return {
|
|
11019
|
+
stagingAssetId: presigned.stagingAssetId
|
|
11020
|
+
};
|
|
10497
11021
|
}
|
|
10498
11022
|
__name(uploadResolvedMedia, "uploadResolvedMedia");
|
|
10499
|
-
async function resolveAndUploadMedia(api, ref, expectedKind, transport) {
|
|
11023
|
+
async function resolveAndUploadMedia(api, ref, expectedKind, assetRole, transport) {
|
|
10500
11024
|
const media = await resolveMediaRef(ref, {
|
|
10501
11025
|
transport,
|
|
10502
11026
|
expectedKind
|
|
10503
11027
|
});
|
|
10504
|
-
return uploadResolvedMedia(api, media);
|
|
11028
|
+
return uploadResolvedMedia(api, media, assetRole);
|
|
10505
11029
|
}
|
|
10506
11030
|
__name(resolveAndUploadMedia, "resolveAndUploadMedia");
|
|
10507
|
-
var TikTokInput =
|
|
10508
|
-
taskId:
|
|
10509
|
-
advertiserId:
|
|
10510
|
-
pixelId:
|
|
10511
|
-
landingUrl:
|
|
10512
|
-
angleIndexes:
|
|
11031
|
+
var TikTokInput = z52.object({
|
|
11032
|
+
taskId: z52.string().min(1),
|
|
11033
|
+
advertiserId: z52.string().min(1),
|
|
11034
|
+
pixelId: z52.string().min(1).optional(),
|
|
11035
|
+
landingUrl: z52.string().url().optional(),
|
|
11036
|
+
angleIndexes: z52.array(z52.number().int().nonnegative()).optional(),
|
|
10513
11037
|
campaignConfig: McpCampaignConfig.optional(),
|
|
10514
11038
|
/** Override the ad's description (TikTok's body copy). If omitted,
|
|
10515
11039
|
* ProductMaker uses the auto-generated copy attached to the task. */
|
|
10516
|
-
primaryText:
|
|
11040
|
+
primaryText: z52.string().trim().min(1).max(500).optional()
|
|
10517
11041
|
});
|
|
10518
11042
|
function registerPublishTools(server, api, opts = {}) {
|
|
10519
11043
|
const transport = opts.transport ?? "http";
|
|
@@ -10552,7 +11076,7 @@ function registerPublishTools(server, api, opts = {}) {
|
|
|
10552
11076
|
throw translateError(e);
|
|
10553
11077
|
}
|
|
10554
11078
|
});
|
|
10555
|
-
server.tool("publish_to_meta", "Crea una campa\xF1a de Meta Ads (Facebook/Instagram) desde UNA sola tarea.
|
|
11079
|
+
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 }) => {
|
|
10556
11080
|
try {
|
|
10557
11081
|
const body = {
|
|
10558
11082
|
...rest
|
|
@@ -10580,7 +11104,7 @@ function registerPublishTools(server, api, opts = {}) {
|
|
|
10580
11104
|
throw translateError(e);
|
|
10581
11105
|
}
|
|
10582
11106
|
});
|
|
10583
|
-
server.tool("publish_creatives_to_meta", "Crea UNA campa\xF1a de Meta Ads
|
|
11107
|
+
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) => {
|
|
10584
11108
|
try {
|
|
10585
11109
|
const parsed = PublishCreativesToMetaInput.safeParse(rawInput);
|
|
10586
11110
|
if (!parsed.success) throw invalidInputFromZod(parsed.error);
|
|
@@ -10606,25 +11130,44 @@ function registerPublishTools(server, api, opts = {}) {
|
|
|
10606
11130
|
});
|
|
10607
11131
|
continue;
|
|
10608
11132
|
}
|
|
10609
|
-
|
|
11133
|
+
if (creative.source.type === "staged") {
|
|
11134
|
+
creatives.push({
|
|
11135
|
+
type: creative.type,
|
|
11136
|
+
source: {
|
|
11137
|
+
type: "media",
|
|
11138
|
+
mediaAssetId: creative.source.stagingAssetId,
|
|
11139
|
+
...creative.source.thumbnailAssetId ? {
|
|
11140
|
+
thumbnailAssetId: creative.source.thumbnailAssetId
|
|
11141
|
+
} : {}
|
|
11142
|
+
},
|
|
11143
|
+
title: creative.title,
|
|
11144
|
+
description: creative.description,
|
|
11145
|
+
cta: creative.cta,
|
|
11146
|
+
creativeId
|
|
11147
|
+
});
|
|
11148
|
+
continue;
|
|
11149
|
+
}
|
|
11150
|
+
const stagedMedia = await resolveAndUploadMedia(api, {
|
|
10610
11151
|
url: creative.source.url,
|
|
10611
11152
|
path: creative.source.path
|
|
10612
|
-
}, creative.type, transport);
|
|
10613
|
-
let
|
|
11153
|
+
}, creative.type, "media", transport);
|
|
11154
|
+
let stagedThumbnail;
|
|
10614
11155
|
if (creative.type === "video") {
|
|
10615
11156
|
if (creative.source.thumbnailUrl || creative.source.thumbnailPath) {
|
|
10616
|
-
|
|
11157
|
+
stagedThumbnail = await resolveAndUploadMedia(api, {
|
|
10617
11158
|
url: creative.source.thumbnailUrl,
|
|
10618
11159
|
path: creative.source.thumbnailPath
|
|
10619
|
-
}, "image", transport);
|
|
11160
|
+
}, "image", "thumbnail", transport);
|
|
10620
11161
|
}
|
|
10621
11162
|
}
|
|
10622
11163
|
creatives.push({
|
|
10623
11164
|
type: creative.type,
|
|
10624
11165
|
source: {
|
|
10625
11166
|
type: "media",
|
|
10626
|
-
|
|
10627
|
-
|
|
11167
|
+
mediaAssetId: stagedMedia.stagingAssetId,
|
|
11168
|
+
...stagedThumbnail ? {
|
|
11169
|
+
thumbnailAssetId: stagedThumbnail.stagingAssetId
|
|
11170
|
+
} : {}
|
|
10628
11171
|
},
|
|
10629
11172
|
title: creative.title,
|
|
10630
11173
|
description: creative.description,
|
|
@@ -10634,6 +11177,8 @@ function registerPublishTools(server, api, opts = {}) {
|
|
|
10634
11177
|
}
|
|
10635
11178
|
const r = await api.postJson("/v1/facebook/campaigns/from-tasks", {
|
|
10636
11179
|
creatives,
|
|
11180
|
+
portfolioId: input.portfolioId,
|
|
11181
|
+
pageId: input.pageId,
|
|
10637
11182
|
adAccountId: input.adAccountId,
|
|
10638
11183
|
pixelId: input.pixelId,
|
|
10639
11184
|
landingUrl: input.landingUrl,
|
|
@@ -10680,6 +11225,17 @@ function renderShopifyPublishMarkdown(r) {
|
|
|
10680
11225
|
if (r.productUrl) lines.push(`
|
|
10681
11226
|
### Producto
|
|
10682
11227
|
[Ver producto](${r.productUrl})`);
|
|
11228
|
+
if (r.needsThemeSetup) {
|
|
11229
|
+
lines.push(r.themeEditorDeepLink ? `
|
|
11230
|
+
\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.");
|
|
11231
|
+
}
|
|
11232
|
+
if (r.tracking?.status === "migrated") {
|
|
11233
|
+
lines.push("\nTracking: \u2705 configuraci\xF3n anterior migrada autom\xE1ticamente. No necesitas editar el tema.");
|
|
11234
|
+
} else if (r.tracking?.status === "synced") {
|
|
11235
|
+
lines.push("\nTracking: \u2705 c\xF3digo manual sincronizado desde `theme.liquid` al layout de ProductMaker.");
|
|
11236
|
+
} else if (r.tracking?.status === "not_detected") {
|
|
11237
|
+
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.");
|
|
11238
|
+
}
|
|
10683
11239
|
if (!r.pageUrl && !r.productUrl && r.status !== "success") {
|
|
10684
11240
|
lines.push("\n_La publicaci\xF3n a\xFAn est\xE1 proces\xE1ndose. Usa `get_task_status` para verificar progreso._");
|
|
10685
11241
|
}
|
|
@@ -10723,14 +11279,162 @@ function toTikTokCampaignConfig(cfg) {
|
|
|
10723
11279
|
}
|
|
10724
11280
|
__name(toTikTokCampaignConfig, "toTikTokCampaignConfig");
|
|
10725
11281
|
|
|
11282
|
+
// src/tools/meta-upload.ts
|
|
11283
|
+
import { z as z53 } from "zod";
|
|
11284
|
+
var MetaUploadSessionInputBase = z53.object({
|
|
11285
|
+
mediaKind: z53.enum([
|
|
11286
|
+
"image",
|
|
11287
|
+
"video",
|
|
11288
|
+
"mixed"
|
|
11289
|
+
]).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."),
|
|
11290
|
+
assetRole: z53.enum([
|
|
11291
|
+
"media",
|
|
11292
|
+
"thumbnail"
|
|
11293
|
+
]).default("media").describe("Use media for the creative itself; thumbnail only for an image thumbnail."),
|
|
11294
|
+
maxFiles: z53.number().int().min(1).max(10).optional().describe("Optional batch limit. Use 1 for a single creative; mixed media defaults to 10.")
|
|
11295
|
+
});
|
|
11296
|
+
var OpenAiFileReference = z53.object({
|
|
11297
|
+
download_url: z53.string().url(),
|
|
11298
|
+
file_id: z53.string().min(1),
|
|
11299
|
+
mime_type: z53.string().min(1).optional(),
|
|
11300
|
+
file_name: z53.string().min(1).optional()
|
|
11301
|
+
}).strict();
|
|
11302
|
+
var MetaUploadSessionToolInputShape = {
|
|
11303
|
+
...MetaUploadSessionInputBase.shape,
|
|
11304
|
+
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.")
|
|
11305
|
+
};
|
|
11306
|
+
var MetaUploadSessionToolInput = z53.object(MetaUploadSessionToolInputShape).superRefine((value, ctx) => {
|
|
11307
|
+
if (value.assetRole === "thumbnail" && value.mediaKind !== "image") {
|
|
11308
|
+
ctx.addIssue({
|
|
11309
|
+
code: z53.ZodIssueCode.custom,
|
|
11310
|
+
path: [
|
|
11311
|
+
"mediaKind"
|
|
11312
|
+
],
|
|
11313
|
+
message: "Meta thumbnails must be images"
|
|
11314
|
+
});
|
|
11315
|
+
}
|
|
11316
|
+
if (value.mediaKind !== "mixed" && value.maxFiles !== void 0 && value.maxFiles !== 1) {
|
|
11317
|
+
ctx.addIssue({
|
|
11318
|
+
code: z53.ZodIssueCode.custom,
|
|
11319
|
+
path: [
|
|
11320
|
+
"maxFiles"
|
|
11321
|
+
],
|
|
11322
|
+
message: "Image and video sessions accept exactly one file"
|
|
11323
|
+
});
|
|
11324
|
+
}
|
|
11325
|
+
});
|
|
11326
|
+
var MetaUploadSessionResponse2 = z53.object({
|
|
11327
|
+
sessionId: z53.string().uuid(),
|
|
11328
|
+
uploadPageUrl: z53.string().url(),
|
|
11329
|
+
mediaKind: z53.enum([
|
|
11330
|
+
"image",
|
|
11331
|
+
"video",
|
|
11332
|
+
"mixed"
|
|
11333
|
+
]),
|
|
11334
|
+
assetRole: z53.enum([
|
|
11335
|
+
"media",
|
|
11336
|
+
"thumbnail"
|
|
11337
|
+
]),
|
|
11338
|
+
maxFiles: z53.number().int().positive(),
|
|
11339
|
+
expiresAt: z53.string().datetime()
|
|
11340
|
+
});
|
|
11341
|
+
var MetaUploadStatusInput = z53.object({
|
|
11342
|
+
sessionId: z53.string().uuid().describe("The sessionId returned by request_meta_media_upload.")
|
|
11343
|
+
});
|
|
11344
|
+
var MetaUploadStatusResponse = z53.object({
|
|
11345
|
+
sessionId: z53.string().uuid(),
|
|
11346
|
+
status: z53.enum([
|
|
11347
|
+
"pending",
|
|
11348
|
+
"uploaded"
|
|
11349
|
+
]),
|
|
11350
|
+
assets: z53.array(z53.object({
|
|
11351
|
+
stagingAssetId: z53.string().uuid(),
|
|
11352
|
+
mediaKind: z53.enum([
|
|
11353
|
+
"image",
|
|
11354
|
+
"video"
|
|
11355
|
+
])
|
|
11356
|
+
})).max(10).default([]),
|
|
11357
|
+
stagingAssetId: z53.string().uuid().optional()
|
|
11358
|
+
});
|
|
11359
|
+
function uploadSessionText(result) {
|
|
11360
|
+
const mediaLabel = result.mediaKind === "mixed" ? "archivos" : result.mediaKind === "video" ? "video" : "imagen";
|
|
11361
|
+
return {
|
|
11362
|
+
content: [
|
|
11363
|
+
{
|
|
11364
|
+
type: "text",
|
|
11365
|
+
text: [
|
|
11366
|
+
`### Prepara tu ${mediaLabel} en ProductMaker`,
|
|
11367
|
+
`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})`,
|
|
11368
|
+
`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.`,
|
|
11369
|
+
`sessionId: \`${result.sessionId}\``,
|
|
11370
|
+
`Este enlace expira: ${result.expiresAt}`
|
|
11371
|
+
].join("\n\n")
|
|
11372
|
+
}
|
|
11373
|
+
]
|
|
11374
|
+
};
|
|
11375
|
+
}
|
|
11376
|
+
__name(uploadSessionText, "uploadSessionText");
|
|
11377
|
+
function registerMetaUploadTools(server, api) {
|
|
11378
|
+
server.registerTool("request_meta_media_upload", {
|
|
11379
|
+
title: "Solicitar carga segura de Meta",
|
|
11380
|
+
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.",
|
|
11381
|
+
inputSchema: MetaUploadSessionToolInputShape,
|
|
11382
|
+
outputSchema: MetaUploadSessionResponse2,
|
|
11383
|
+
_meta: {
|
|
11384
|
+
ui: {
|
|
11385
|
+
resourceUri: META_UPLOAD_APP_RESOURCE_URI,
|
|
11386
|
+
visibility: [
|
|
11387
|
+
"model",
|
|
11388
|
+
"app"
|
|
11389
|
+
]
|
|
11390
|
+
},
|
|
11391
|
+
"openai/outputTemplate": META_UPLOAD_APP_RESOURCE_URI,
|
|
11392
|
+
"openai/widgetAccessible": true,
|
|
11393
|
+
"openai/fileParams": [
|
|
11394
|
+
"files"
|
|
11395
|
+
],
|
|
11396
|
+
"openai/toolInvocation/invoking": "Preparando carga segura\u2026",
|
|
11397
|
+
"openai/toolInvocation/invoked": "Carga segura lista"
|
|
11398
|
+
}
|
|
11399
|
+
}, async (rawInput) => {
|
|
11400
|
+
try {
|
|
11401
|
+
const input = MetaUploadSessionToolInput.parse(rawInput);
|
|
11402
|
+
const { files: _files, ...sessionInput } = input;
|
|
11403
|
+
const result = MetaUploadSessionResponse2.parse(await api.postJson("/v1/ads/meta-upload-sessions", sessionInput));
|
|
11404
|
+
return {
|
|
11405
|
+
structuredContent: result,
|
|
11406
|
+
...uploadSessionText(result)
|
|
11407
|
+
};
|
|
11408
|
+
} catch (error) {
|
|
11409
|
+
throw translateError(error);
|
|
11410
|
+
}
|
|
11411
|
+
});
|
|
11412
|
+
server.registerTool("check_meta_media_upload", {
|
|
11413
|
+
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.',
|
|
11414
|
+
inputSchema: MetaUploadStatusInput.shape,
|
|
11415
|
+
_meta: {
|
|
11416
|
+
"openai/widgetAccessible": true
|
|
11417
|
+
}
|
|
11418
|
+
}, async (rawInput) => {
|
|
11419
|
+
try {
|
|
11420
|
+
const input = MetaUploadStatusInput.parse(rawInput);
|
|
11421
|
+
const result = MetaUploadStatusResponse.parse(await api.getJson(`/v1/ads/meta-upload-sessions/${encodeURIComponent(input.sessionId)}`));
|
|
11422
|
+
return asText(result);
|
|
11423
|
+
} catch (error) {
|
|
11424
|
+
throw translateError(error);
|
|
11425
|
+
}
|
|
11426
|
+
});
|
|
11427
|
+
}
|
|
11428
|
+
__name(registerMetaUploadTools, "registerMetaUploadTools");
|
|
11429
|
+
|
|
10726
11430
|
// src/tools/campaigns.ts
|
|
10727
|
-
import { z as
|
|
10728
|
-
var MetaStatusInput =
|
|
10729
|
-
campaignId:
|
|
11431
|
+
import { z as z54 } from "zod";
|
|
11432
|
+
var MetaStatusInput = z54.object({
|
|
11433
|
+
campaignId: z54.string().min(1).describe("Meta campaign ID returned by publish_to_meta.")
|
|
10730
11434
|
});
|
|
10731
|
-
var TikTokStatusInput =
|
|
10732
|
-
campaignId:
|
|
10733
|
-
advertiserId:
|
|
11435
|
+
var TikTokStatusInput = z54.object({
|
|
11436
|
+
campaignId: z54.string().min(1).describe("TikTok campaign ID returned by publish_to_tiktok."),
|
|
11437
|
+
advertiserId: z54.string().min(1).describe("The same advertiserId used to publish the campaign.")
|
|
10734
11438
|
});
|
|
10735
11439
|
function registerCampaignTools(server, api) {
|
|
10736
11440
|
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) => {
|
|
@@ -10827,10 +11531,10 @@ function renderTikTokStatusMarkdown(r) {
|
|
|
10827
11531
|
__name(renderTikTokStatusMarkdown, "renderTikTokStatusMarkdown");
|
|
10828
11532
|
|
|
10829
11533
|
// ../../packages/product-economics/src/product-costing.ts
|
|
10830
|
-
import { z as
|
|
11534
|
+
import { z as z56 } from "zod";
|
|
10831
11535
|
|
|
10832
11536
|
// ../../packages/product-economics/src/product-costing-countries.ts
|
|
10833
|
-
import { z as
|
|
11537
|
+
import { z as z55 } from "zod";
|
|
10834
11538
|
|
|
10835
11539
|
// ../../packages/product-economics/src/product-costing-shipping-references.json
|
|
10836
11540
|
var product_costing_shipping_references_default = {
|
|
@@ -10894,21 +11598,21 @@ var product_costing_shipping_references_default = {
|
|
|
10894
11598
|
};
|
|
10895
11599
|
|
|
10896
11600
|
// ../../packages/product-economics/src/product-costing-countries.ts
|
|
10897
|
-
var ShippingReferenceSchema =
|
|
10898
|
-
reference:
|
|
10899
|
-
min:
|
|
10900
|
-
max:
|
|
10901
|
-
updatedAt:
|
|
10902
|
-
confidence:
|
|
11601
|
+
var ShippingReferenceSchema = z55.object({
|
|
11602
|
+
reference: z55.number().positive(),
|
|
11603
|
+
min: z55.number().nonnegative(),
|
|
11604
|
+
max: z55.number().positive(),
|
|
11605
|
+
updatedAt: z55.string().date(),
|
|
11606
|
+
confidence: z55.enum([
|
|
10903
11607
|
"high",
|
|
10904
11608
|
"medium",
|
|
10905
11609
|
"medium-low"
|
|
10906
11610
|
]),
|
|
10907
|
-
sources:
|
|
11611
|
+
sources: z55.array(z55.string().url().startsWith("https://")).min(1).max(3)
|
|
10908
11612
|
}).superRefine(({ reference, min, max }, context) => {
|
|
10909
11613
|
if (min > reference || reference > max) {
|
|
10910
11614
|
context.addIssue({
|
|
10911
|
-
code:
|
|
11615
|
+
code: z55.ZodIssueCode.custom,
|
|
10912
11616
|
message: "shipping_reference_outside_range",
|
|
10913
11617
|
path: [
|
|
10914
11618
|
"reference"
|
|
@@ -10916,7 +11620,7 @@ var ShippingReferenceSchema = z52.object({
|
|
|
10916
11620
|
});
|
|
10917
11621
|
}
|
|
10918
11622
|
});
|
|
10919
|
-
var SHIPPING_REFERENCES =
|
|
11623
|
+
var SHIPPING_REFERENCES = z55.record(ShippingReferenceSchema).parse(product_costing_shipping_references_default);
|
|
10920
11624
|
var PRODUCT_COSTING_COUNTRY_CODES = Object.freeze(Object.keys(SHIPPING_REFERENCES));
|
|
10921
11625
|
var SPANISH_LOCALE_COUNTRIES = /* @__PURE__ */ new Set([
|
|
10922
11626
|
"MX",
|
|
@@ -11098,18 +11802,18 @@ function getProductCostingCountryName(country) {
|
|
|
11098
11802
|
__name(getProductCostingCountryName, "getProductCostingCountryName");
|
|
11099
11803
|
|
|
11100
11804
|
// ../../packages/product-economics/src/product-costing.ts
|
|
11101
|
-
var ProductCostingInputSchema =
|
|
11102
|
-
country:
|
|
11103
|
-
supplierCost:
|
|
11104
|
-
shippingCost:
|
|
11105
|
-
returnRate:
|
|
11106
|
-
cancellationRate:
|
|
11107
|
-
adsManagerCpa:
|
|
11108
|
-
desiredMargin:
|
|
11805
|
+
var ProductCostingInputSchema = z56.object({
|
|
11806
|
+
country: z56.string().refine(isProductCostingCountryCode, "unsupported_country"),
|
|
11807
|
+
supplierCost: z56.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").positive("supplier_cost_positive"),
|
|
11808
|
+
shippingCost: z56.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("shipping_cost_nonnegative"),
|
|
11809
|
+
returnRate: z56.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
|
|
11810
|
+
cancellationRate: z56.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
|
|
11811
|
+
adsManagerCpa: z56.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("cpa_nonnegative"),
|
|
11812
|
+
desiredMargin: z56.number().finite().min(0, "margin_nonnegative").lt(1, "margin_below_one")
|
|
11109
11813
|
}).superRefine(({ returnRate, cancellationRate }, context) => {
|
|
11110
11814
|
if (returnRate + cancellationRate >= 1) {
|
|
11111
11815
|
context.addIssue({
|
|
11112
|
-
code:
|
|
11816
|
+
code: z56.ZodIssueCode.custom,
|
|
11113
11817
|
message: "delivery_rate_positive",
|
|
11114
11818
|
path: [
|
|
11115
11819
|
"cancellationRate"
|
|
@@ -11176,14 +11880,14 @@ function calculateProductCosting(rawInput) {
|
|
|
11176
11880
|
__name(calculateProductCosting, "calculateProductCosting");
|
|
11177
11881
|
|
|
11178
11882
|
// src/tools/product-costing.ts
|
|
11179
|
-
import { z as
|
|
11180
|
-
var optionalAmount = /* @__PURE__ */ __name((description) =>
|
|
11181
|
-
var optionalPercent = /* @__PURE__ */ __name((description) =>
|
|
11182
|
-
var ProductCostingToolInput =
|
|
11183
|
-
country:
|
|
11883
|
+
import { z as z57 } from "zod";
|
|
11884
|
+
var optionalAmount = /* @__PURE__ */ __name((description) => z57.number().finite().max(Number.MAX_SAFE_INTEGER).nonnegative().optional().describe(description), "optionalAmount");
|
|
11885
|
+
var optionalPercent = /* @__PURE__ */ __name((description) => z57.number().finite().min(0).lt(100).optional().describe(description), "optionalPercent");
|
|
11886
|
+
var ProductCostingToolInput = z57.object({
|
|
11887
|
+
country: z57.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
|
|
11184
11888
|
message: "Pa\xEDs no soportado por ProductMaker."
|
|
11185
11889
|
}).optional().describe("C\xF3digo ISO-2 de cualquiera de los pa\xEDses disponibles en ProductMaker. Omite para Colombia."),
|
|
11186
|
-
supplierCost:
|
|
11890
|
+
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."),
|
|
11187
11891
|
supplierCostCop: optionalAmount("Alias anterior para costo del proveedor en Colombia. Prefiere supplierCost."),
|
|
11188
11892
|
shippingCost: optionalAmount("Costo de un env\xEDo en la moneda del pa\xEDs. Omite para usar el valor gu\xEDa vigente."),
|
|
11189
11893
|
shippingCostCop: optionalAmount("Alias anterior para flete en Colombia. Prefiere shippingCost."),
|
|
@@ -11315,7 +12019,7 @@ function formatPercent(value) {
|
|
|
11315
12019
|
__name(formatPercent, "formatPercent");
|
|
11316
12020
|
|
|
11317
12021
|
// src/tools/product-research.ts
|
|
11318
|
-
import { z as
|
|
12022
|
+
import { z as z58 } from "zod";
|
|
11319
12023
|
|
|
11320
12024
|
// src/tools/product-research-idempotency.ts
|
|
11321
12025
|
import { createHash as createHash2 } from "crypto";
|
|
@@ -11431,17 +12135,17 @@ var TERMINAL2 = /* @__PURE__ */ new Set([
|
|
|
11431
12135
|
]);
|
|
11432
12136
|
var POLL_INTERVAL_MS = 5e3;
|
|
11433
12137
|
var MAX_WAIT_SECONDS = 120;
|
|
11434
|
-
var FindInput =
|
|
12138
|
+
var FindInput = z58.object({
|
|
11435
12139
|
targetCountry: ResearchTargetCountryEnum.describe("Pa\xEDs objetivo. S\xF3lo CO, MX, PE, EC y CL tienen cobertura de investigaci\xF3n."),
|
|
11436
12140
|
categoryKey: ResearchCategoryEnum.default("auto").describe('Categor\xEDa a investigar. Usa "auto" para que la IA elija seg\xFAn el mercado.'),
|
|
11437
|
-
confirmed:
|
|
11438
|
-
waitSeconds:
|
|
12141
|
+
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.`),
|
|
12142
|
+
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.")
|
|
11439
12143
|
});
|
|
11440
|
-
var GetInput =
|
|
11441
|
-
runId:
|
|
12144
|
+
var GetInput = z58.object({
|
|
12145
|
+
runId: z58.string().uuid().describe("ID del run devuelto por find_winning_products.")
|
|
11442
12146
|
});
|
|
11443
|
-
var ListInput =
|
|
11444
|
-
limit:
|
|
12147
|
+
var ListInput = z58.object({
|
|
12148
|
+
limit: z58.number().int().min(1).max(20).default(10)
|
|
11445
12149
|
});
|
|
11446
12150
|
function textResult(text) {
|
|
11447
12151
|
return {
|
|
@@ -11533,14 +12237,14 @@ _Esta llamada no cobr\xF3 cr\xE9ditos: se reutiliz\xF3 una investigaci\xF3n reci
|
|
|
11533
12237
|
__name(registerProductResearchTools, "registerProductResearchTools");
|
|
11534
12238
|
|
|
11535
12239
|
// src/tools/dropshipping-projects.ts
|
|
11536
|
-
import { z as
|
|
11537
|
-
var ProjectId =
|
|
11538
|
-
var DropshippingProjectStatus =
|
|
12240
|
+
import { z as z59 } from "zod";
|
|
12241
|
+
var ProjectId = z59.string().uuid();
|
|
12242
|
+
var DropshippingProjectStatus = z59.enum([
|
|
11539
12243
|
"active",
|
|
11540
12244
|
"completed",
|
|
11541
12245
|
"archived"
|
|
11542
12246
|
]);
|
|
11543
|
-
var DropshippingProjectPhase =
|
|
12247
|
+
var DropshippingProjectPhase = z59.enum([
|
|
11544
12248
|
"research",
|
|
11545
12249
|
"costing",
|
|
11546
12250
|
"media",
|
|
@@ -11549,21 +12253,21 @@ var DropshippingProjectPhase = z56.enum([
|
|
|
11549
12253
|
"advertising",
|
|
11550
12254
|
"complete"
|
|
11551
12255
|
]);
|
|
11552
|
-
var DropshippingRewardMilestone =
|
|
12256
|
+
var DropshippingRewardMilestone = z59.enum([
|
|
11553
12257
|
"product_selected",
|
|
11554
12258
|
"costing_saved",
|
|
11555
12259
|
"product_media_ready",
|
|
11556
12260
|
"creatives_completed",
|
|
11557
12261
|
"campaign_created"
|
|
11558
12262
|
]);
|
|
11559
|
-
var TargetCountry =
|
|
12263
|
+
var TargetCountry = z59.enum([
|
|
11560
12264
|
"CO",
|
|
11561
12265
|
"MX",
|
|
11562
12266
|
"PE",
|
|
11563
12267
|
"EC",
|
|
11564
12268
|
"CL"
|
|
11565
12269
|
]);
|
|
11566
|
-
var ResearchCategory =
|
|
12270
|
+
var ResearchCategory = z59.enum([
|
|
11567
12271
|
"auto",
|
|
11568
12272
|
"automotive",
|
|
11569
12273
|
"kitchen",
|
|
@@ -11578,7 +12282,7 @@ var ResearchCategory = z56.enum([
|
|
|
11578
12282
|
"garden",
|
|
11579
12283
|
"cleaning"
|
|
11580
12284
|
]);
|
|
11581
|
-
var HttpUrl3 =
|
|
12285
|
+
var HttpUrl3 = z59.string().url().max(2e3).refine((value) => {
|
|
11582
12286
|
try {
|
|
11583
12287
|
return [
|
|
11584
12288
|
"http:",
|
|
@@ -11588,46 +12292,46 @@ var HttpUrl3 = z56.string().url().max(2e3).refine((value) => {
|
|
|
11588
12292
|
return false;
|
|
11589
12293
|
}
|
|
11590
12294
|
}, "URL must use HTTP(S)");
|
|
11591
|
-
var ResearchCandidateOrigin =
|
|
11592
|
-
type:
|
|
12295
|
+
var ResearchCandidateOrigin = z59.object({
|
|
12296
|
+
type: z59.literal("research_candidate"),
|
|
11593
12297
|
runId: ProjectId,
|
|
11594
|
-
candidateSourceId:
|
|
12298
|
+
candidateSourceId: z59.string().min(1).max(160)
|
|
11595
12299
|
});
|
|
11596
|
-
var TaskOrigin =
|
|
11597
|
-
type:
|
|
12300
|
+
var TaskOrigin = z59.object({
|
|
12301
|
+
type: z59.literal("task"),
|
|
11598
12302
|
taskId: ProjectId
|
|
11599
12303
|
});
|
|
11600
|
-
var ManualOrigin =
|
|
11601
|
-
type:
|
|
12304
|
+
var ManualOrigin = z59.object({
|
|
12305
|
+
type: z59.literal("manual"),
|
|
11602
12306
|
clientRequestId: ProjectId,
|
|
11603
|
-
country:
|
|
12307
|
+
country: z59.string().min(2).max(3).optional()
|
|
11604
12308
|
});
|
|
11605
|
-
var StartProjectInput =
|
|
11606
|
-
origin:
|
|
12309
|
+
var StartProjectInput = z59.object({
|
|
12310
|
+
origin: z59.discriminatedUnion("type", [
|
|
11607
12311
|
ResearchCandidateOrigin,
|
|
11608
12312
|
TaskOrigin,
|
|
11609
12313
|
ManualOrigin
|
|
11610
12314
|
]),
|
|
11611
|
-
productName:
|
|
12315
|
+
productName: z59.string().trim().min(1).max(240).optional(),
|
|
11612
12316
|
productUrl: HttpUrl3.optional(),
|
|
11613
|
-
country:
|
|
11614
|
-
languageCode:
|
|
12317
|
+
country: z59.string().min(2).max(3).optional(),
|
|
12318
|
+
languageCode: z59.string().min(2).max(16).optional()
|
|
11615
12319
|
}).strict();
|
|
11616
|
-
var CostProjectInput =
|
|
12320
|
+
var CostProjectInput = z59.object({
|
|
11617
12321
|
projectId: ProjectId,
|
|
11618
|
-
version:
|
|
11619
|
-
country:
|
|
11620
|
-
supplierCost:
|
|
11621
|
-
shippingCost:
|
|
11622
|
-
returnRate:
|
|
11623
|
-
cancellationRate:
|
|
11624
|
-
adsManagerCpa:
|
|
11625
|
-
desiredMargin:
|
|
11626
|
-
});
|
|
11627
|
-
var GuideInput =
|
|
12322
|
+
version: z59.number().int().positive(),
|
|
12323
|
+
country: z59.string().trim().min(2).max(3),
|
|
12324
|
+
supplierCost: z59.number().finite().positive(),
|
|
12325
|
+
shippingCost: z59.number().finite().nonnegative(),
|
|
12326
|
+
returnRate: z59.number().finite().min(0).lt(1),
|
|
12327
|
+
cancellationRate: z59.number().finite().min(0).lt(1),
|
|
12328
|
+
adsManagerCpa: z59.number().finite().nonnegative(),
|
|
12329
|
+
desiredMargin: z59.number().finite().min(0).lt(1)
|
|
12330
|
+
});
|
|
12331
|
+
var GuideInput = z59.object({
|
|
11628
12332
|
projectId: ProjectId.optional()
|
|
11629
12333
|
}).strict();
|
|
11630
|
-
var DropshippingProjectNextAction =
|
|
12334
|
+
var DropshippingProjectNextAction = z59.discriminatedUnion("kind", [
|
|
11631
12335
|
"cost_product",
|
|
11632
12336
|
"provide_product_media",
|
|
11633
12337
|
"generate_creatives",
|
|
@@ -11641,78 +12345,78 @@ var DropshippingProjectNextAction = z56.discriminatedUnion("kind", [
|
|
|
11641
12345
|
"create_meta_campaign",
|
|
11642
12346
|
"repair_meta_campaign",
|
|
11643
12347
|
"review_paused_campaign"
|
|
11644
|
-
].map((kind) =>
|
|
11645
|
-
kind:
|
|
11646
|
-
href:
|
|
12348
|
+
].map((kind) => z59.object({
|
|
12349
|
+
kind: z59.literal(kind),
|
|
12350
|
+
href: z59.string().min(1)
|
|
11647
12351
|
})));
|
|
11648
|
-
var CostingInputSchema =
|
|
11649
|
-
country:
|
|
11650
|
-
supplierCost:
|
|
11651
|
-
shippingCost:
|
|
11652
|
-
returnRate:
|
|
11653
|
-
cancellationRate:
|
|
11654
|
-
adsManagerCpa:
|
|
11655
|
-
desiredMargin:
|
|
12352
|
+
var CostingInputSchema = z59.object({
|
|
12353
|
+
country: z59.string().min(2).max(3),
|
|
12354
|
+
supplierCost: z59.number().finite().positive(),
|
|
12355
|
+
shippingCost: z59.number().finite().nonnegative(),
|
|
12356
|
+
returnRate: z59.number().finite().min(0).lt(1),
|
|
12357
|
+
cancellationRate: z59.number().finite().min(0).lt(1),
|
|
12358
|
+
adsManagerCpa: z59.number().finite().nonnegative(),
|
|
12359
|
+
desiredMargin: z59.number().finite().min(0).lt(1)
|
|
11656
12360
|
}).superRefine(({ returnRate, cancellationRate }, context) => {
|
|
11657
12361
|
if (returnRate + cancellationRate >= 1) context.addIssue({
|
|
11658
|
-
code:
|
|
12362
|
+
code: z59.ZodIssueCode.custom,
|
|
11659
12363
|
path: [
|
|
11660
12364
|
"cancellationRate"
|
|
11661
12365
|
]
|
|
11662
12366
|
});
|
|
11663
12367
|
});
|
|
11664
|
-
var CostingResultSchema =
|
|
11665
|
-
country:
|
|
11666
|
-
deliveryRate:
|
|
11667
|
-
adjustedShippingCost:
|
|
11668
|
-
adjustedCpa:
|
|
11669
|
-
totalCost:
|
|
11670
|
-
suggestedPrice:
|
|
11671
|
-
baseCommercialPrice:
|
|
11672
|
-
minimumSafePrice:
|
|
11673
|
-
commercialPrice:
|
|
11674
|
-
comparisonPrice:
|
|
11675
|
-
estimatedProfit:
|
|
11676
|
-
actualMargin:
|
|
11677
|
-
breakEvenAdsManagerCpa:
|
|
11678
|
-
wasPriceAutoAdjusted:
|
|
11679
|
-
profitabilityStatus:
|
|
11680
|
-
});
|
|
11681
|
-
var RewardProgressSchema =
|
|
11682
|
-
campaignKey:
|
|
11683
|
-
totalCredits:
|
|
11684
|
-
earnedCredits:
|
|
11685
|
-
milestones:
|
|
12368
|
+
var CostingResultSchema = z59.object({
|
|
12369
|
+
country: z59.string().min(2).max(3),
|
|
12370
|
+
deliveryRate: z59.number().finite(),
|
|
12371
|
+
adjustedShippingCost: z59.number().finite(),
|
|
12372
|
+
adjustedCpa: z59.number().finite(),
|
|
12373
|
+
totalCost: z59.number().finite(),
|
|
12374
|
+
suggestedPrice: z59.number().finite(),
|
|
12375
|
+
baseCommercialPrice: z59.number().finite(),
|
|
12376
|
+
minimumSafePrice: z59.number().finite(),
|
|
12377
|
+
commercialPrice: z59.number().finite(),
|
|
12378
|
+
comparisonPrice: z59.number().finite(),
|
|
12379
|
+
estimatedProfit: z59.number().finite(),
|
|
12380
|
+
actualMargin: z59.number().finite(),
|
|
12381
|
+
breakEvenAdsManagerCpa: z59.number().finite(),
|
|
12382
|
+
wasPriceAutoAdjusted: z59.boolean(),
|
|
12383
|
+
profitabilityStatus: z59.literal("healthy")
|
|
12384
|
+
});
|
|
12385
|
+
var RewardProgressSchema = z59.object({
|
|
12386
|
+
campaignKey: z59.literal("dropshipping-launch-v1"),
|
|
12387
|
+
totalCredits: z59.number().int().positive(),
|
|
12388
|
+
earnedCredits: z59.number().int().nonnegative(),
|
|
12389
|
+
milestones: z59.array(z59.object({
|
|
11686
12390
|
milestone: DropshippingRewardMilestone,
|
|
11687
|
-
credits:
|
|
11688
|
-
available:
|
|
11689
|
-
earned:
|
|
12391
|
+
credits: z59.number().int().positive(),
|
|
12392
|
+
available: z59.boolean().optional(),
|
|
12393
|
+
earned: z59.boolean(),
|
|
11690
12394
|
grantId: ProjectId.nullable(),
|
|
11691
|
-
grantedAt:
|
|
12395
|
+
grantedAt: z59.string().datetime().nullable()
|
|
11692
12396
|
})).length(DropshippingRewardMilestone.options.length)
|
|
11693
12397
|
});
|
|
11694
|
-
var ProjectResponseSchema =
|
|
12398
|
+
var ProjectResponseSchema = z59.object({
|
|
11695
12399
|
id: ProjectId,
|
|
11696
12400
|
taskId: ProjectId.nullable(),
|
|
11697
12401
|
status: DropshippingProjectStatus,
|
|
11698
|
-
originKey:
|
|
12402
|
+
originKey: z59.string().min(1),
|
|
11699
12403
|
researchRunId: ProjectId.nullable(),
|
|
11700
|
-
candidateSourceId:
|
|
11701
|
-
productName:
|
|
12404
|
+
candidateSourceId: z59.string().nullable(),
|
|
12405
|
+
productName: z59.string().nullable(),
|
|
11702
12406
|
productUrl: HttpUrl3.nullable(),
|
|
11703
12407
|
referenceImageUrl: HttpUrl3.nullable(),
|
|
11704
|
-
targetCountry:
|
|
11705
|
-
languageCode:
|
|
11706
|
-
hasReferenceImage:
|
|
12408
|
+
targetCountry: z59.string().nullable(),
|
|
12409
|
+
languageCode: z59.string().nullable(),
|
|
12410
|
+
hasReferenceImage: z59.boolean(),
|
|
11707
12411
|
costingInput: CostingInputSchema.nullable(),
|
|
11708
12412
|
costingResult: CostingResultSchema.nullable(),
|
|
11709
|
-
costingVersion:
|
|
11710
|
-
version:
|
|
12413
|
+
costingVersion: z59.number().int().positive().nullable(),
|
|
12414
|
+
version: z59.number().int().positive(),
|
|
11711
12415
|
phase: DropshippingProjectPhase,
|
|
11712
12416
|
nextAction: DropshippingProjectNextAction.nullable(),
|
|
11713
12417
|
rewards: RewardProgressSchema,
|
|
11714
|
-
createdAt:
|
|
11715
|
-
updatedAt:
|
|
12418
|
+
createdAt: z59.string().datetime(),
|
|
12419
|
+
updatedAt: z59.string().datetime()
|
|
11716
12420
|
}).passthrough();
|
|
11717
12421
|
function projectText(raw) {
|
|
11718
12422
|
const project = ProjectResponseSchema.parse(raw);
|
|
@@ -11797,6 +12501,7 @@ function createServer(opts) {
|
|
|
11797
12501
|
}
|
|
11798
12502
|
});
|
|
11799
12503
|
const api = new ApiClient(apiBaseUrl, apiKey);
|
|
12504
|
+
registerMetaUploadAppResource(server);
|
|
11800
12505
|
registerProductCostingTools(server);
|
|
11801
12506
|
registerProductResearchTools(server, api);
|
|
11802
12507
|
registerDropshippingProjectTools(server, api);
|
|
@@ -11814,6 +12519,7 @@ function createServer(opts) {
|
|
|
11814
12519
|
registerPublishTools(server, api, {
|
|
11815
12520
|
transport
|
|
11816
12521
|
});
|
|
12522
|
+
registerMetaUploadTools(server, api);
|
|
11817
12523
|
registerCampaignTools(server, api);
|
|
11818
12524
|
return server;
|
|
11819
12525
|
}
|