@productmaker/mcp 11.7.0 → 11.8.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +21 -1
- package/dist/http.js +1438 -973
- package/dist/stdio.js +1438 -973
- package/package.json +1 -1
package/dist/http.js
CHANGED
|
@@ -7240,6 +7240,8 @@ var ApproveVideoAnglesRequest = z35.object({
|
|
|
7240
7240
|
var ApproveVideoAnglesResponse = z35.object({
|
|
7241
7241
|
success: z35.boolean(),
|
|
7242
7242
|
taskId: z35.string().uuid(),
|
|
7243
|
+
/** Persisted keys scheduled by this approval; visible candidate indices are not worker keys. */
|
|
7244
|
+
approvedAngleKeys: z35.array(z35.string().regex(/^angle_\d+$/)).min(1).max(3).optional(),
|
|
7243
7245
|
reason: ApproveAnglesRefusalReason.optional()
|
|
7244
7246
|
});
|
|
7245
7247
|
var SaveVideoDraftRequest = z35.object({
|
|
@@ -10012,20 +10014,287 @@ var TikTokAdvertiserSchema = z53.object({
|
|
|
10012
10014
|
status: z53.string().optional(),
|
|
10013
10015
|
timezone: z53.string().optional()
|
|
10014
10016
|
});
|
|
10017
|
+
var TIKTOK_BUDGET_CURRENCY_POLICY = {
|
|
10018
|
+
USD: [
|
|
10019
|
+
1,
|
|
10020
|
+
0.01
|
|
10021
|
+
],
|
|
10022
|
+
EUR: [
|
|
10023
|
+
1,
|
|
10024
|
+
0.01
|
|
10025
|
+
],
|
|
10026
|
+
JPY: [
|
|
10027
|
+
100,
|
|
10028
|
+
1
|
|
10029
|
+
],
|
|
10030
|
+
HKD: [
|
|
10031
|
+
10,
|
|
10032
|
+
0.01
|
|
10033
|
+
],
|
|
10034
|
+
GBP: [
|
|
10035
|
+
1,
|
|
10036
|
+
0.01
|
|
10037
|
+
],
|
|
10038
|
+
MYR: [
|
|
10039
|
+
1,
|
|
10040
|
+
0.01
|
|
10041
|
+
],
|
|
10042
|
+
RUB: [
|
|
10043
|
+
100,
|
|
10044
|
+
0.01
|
|
10045
|
+
],
|
|
10046
|
+
ZAR: [
|
|
10047
|
+
10,
|
|
10048
|
+
0.01
|
|
10049
|
+
],
|
|
10050
|
+
KRW: [
|
|
10051
|
+
1e3,
|
|
10052
|
+
1
|
|
10053
|
+
],
|
|
10054
|
+
AED: [
|
|
10055
|
+
1,
|
|
10056
|
+
0.01
|
|
10057
|
+
],
|
|
10058
|
+
SAR: [
|
|
10059
|
+
1,
|
|
10060
|
+
0.01
|
|
10061
|
+
],
|
|
10062
|
+
HUF: [
|
|
10063
|
+
1,
|
|
10064
|
+
1
|
|
10065
|
+
],
|
|
10066
|
+
PLN: [
|
|
10067
|
+
4,
|
|
10068
|
+
0.01
|
|
10069
|
+
],
|
|
10070
|
+
DKK: [
|
|
10071
|
+
10,
|
|
10072
|
+
0.01
|
|
10073
|
+
],
|
|
10074
|
+
SEK: [
|
|
10075
|
+
10,
|
|
10076
|
+
0.01
|
|
10077
|
+
],
|
|
10078
|
+
NOK: [
|
|
10079
|
+
10,
|
|
10080
|
+
0.01
|
|
10081
|
+
],
|
|
10082
|
+
TRY: [
|
|
10083
|
+
10,
|
|
10084
|
+
0.01
|
|
10085
|
+
],
|
|
10086
|
+
MXN: [
|
|
10087
|
+
10,
|
|
10088
|
+
0.01
|
|
10089
|
+
],
|
|
10090
|
+
THB: [
|
|
10091
|
+
10,
|
|
10092
|
+
0.01
|
|
10093
|
+
],
|
|
10094
|
+
AUD: [
|
|
10095
|
+
1,
|
|
10096
|
+
0.01
|
|
10097
|
+
],
|
|
10098
|
+
CAD: [
|
|
10099
|
+
1,
|
|
10100
|
+
0.01
|
|
10101
|
+
],
|
|
10102
|
+
NZD: [
|
|
10103
|
+
1,
|
|
10104
|
+
0.01
|
|
10105
|
+
],
|
|
10106
|
+
SGD: [
|
|
10107
|
+
1,
|
|
10108
|
+
0.01
|
|
10109
|
+
],
|
|
10110
|
+
CHF: [
|
|
10111
|
+
1,
|
|
10112
|
+
0.01
|
|
10113
|
+
],
|
|
10114
|
+
CNY: [
|
|
10115
|
+
10,
|
|
10116
|
+
0.01
|
|
10117
|
+
],
|
|
10118
|
+
DZD: [
|
|
10119
|
+
100,
|
|
10120
|
+
0.01
|
|
10121
|
+
],
|
|
10122
|
+
ARS: [
|
|
10123
|
+
1,
|
|
10124
|
+
0.01
|
|
10125
|
+
],
|
|
10126
|
+
BDT: [
|
|
10127
|
+
100,
|
|
10128
|
+
0.01
|
|
10129
|
+
],
|
|
10130
|
+
BOB: [
|
|
10131
|
+
10,
|
|
10132
|
+
0.01
|
|
10133
|
+
],
|
|
10134
|
+
BRL: [
|
|
10135
|
+
1,
|
|
10136
|
+
0.01
|
|
10137
|
+
],
|
|
10138
|
+
CLP: [
|
|
10139
|
+
1e3,
|
|
10140
|
+
1
|
|
10141
|
+
],
|
|
10142
|
+
COP: [
|
|
10143
|
+
1e3,
|
|
10144
|
+
0.01
|
|
10145
|
+
],
|
|
10146
|
+
CRC: [
|
|
10147
|
+
1e3,
|
|
10148
|
+
0.01
|
|
10149
|
+
],
|
|
10150
|
+
CZK: [
|
|
10151
|
+
10,
|
|
10152
|
+
0.01
|
|
10153
|
+
],
|
|
10154
|
+
EGP: [
|
|
10155
|
+
10,
|
|
10156
|
+
0.01
|
|
10157
|
+
],
|
|
10158
|
+
GTQ: [
|
|
10159
|
+
10,
|
|
10160
|
+
0.01
|
|
10161
|
+
],
|
|
10162
|
+
HNL: [
|
|
10163
|
+
10,
|
|
10164
|
+
0.01
|
|
10165
|
+
],
|
|
10166
|
+
ISK: [
|
|
10167
|
+
100,
|
|
10168
|
+
1
|
|
10169
|
+
],
|
|
10170
|
+
INR: [
|
|
10171
|
+
100,
|
|
10172
|
+
0.01
|
|
10173
|
+
],
|
|
10174
|
+
IDR: [
|
|
10175
|
+
1e4,
|
|
10176
|
+
1
|
|
10177
|
+
],
|
|
10178
|
+
ILS: [
|
|
10179
|
+
1,
|
|
10180
|
+
0.01
|
|
10181
|
+
],
|
|
10182
|
+
KES: [
|
|
10183
|
+
100,
|
|
10184
|
+
0.01
|
|
10185
|
+
],
|
|
10186
|
+
MOP: [
|
|
10187
|
+
10,
|
|
10188
|
+
0.01
|
|
10189
|
+
],
|
|
10190
|
+
TWD: [
|
|
10191
|
+
10,
|
|
10192
|
+
1
|
|
10193
|
+
],
|
|
10194
|
+
NIO: [
|
|
10195
|
+
10,
|
|
10196
|
+
0.01
|
|
10197
|
+
],
|
|
10198
|
+
NGN: [
|
|
10199
|
+
100,
|
|
10200
|
+
0.01
|
|
10201
|
+
],
|
|
10202
|
+
PKR: [
|
|
10203
|
+
100,
|
|
10204
|
+
0.01
|
|
10205
|
+
],
|
|
10206
|
+
PYG: [
|
|
10207
|
+
1e4,
|
|
10208
|
+
1
|
|
10209
|
+
],
|
|
10210
|
+
PEN: [
|
|
10211
|
+
1,
|
|
10212
|
+
0.01
|
|
10213
|
+
],
|
|
10214
|
+
PHP: [
|
|
10215
|
+
50,
|
|
10216
|
+
0.01
|
|
10217
|
+
],
|
|
10218
|
+
QAR: [
|
|
10219
|
+
1,
|
|
10220
|
+
0.01
|
|
10221
|
+
],
|
|
10222
|
+
RON: [
|
|
10223
|
+
1,
|
|
10224
|
+
0.01
|
|
10225
|
+
],
|
|
10226
|
+
UAH: [
|
|
10227
|
+
10,
|
|
10228
|
+
0.01
|
|
10229
|
+
],
|
|
10230
|
+
UYU: [
|
|
10231
|
+
10,
|
|
10232
|
+
0.01
|
|
10233
|
+
],
|
|
10234
|
+
VEF: [
|
|
10235
|
+
1e5,
|
|
10236
|
+
0.01
|
|
10237
|
+
],
|
|
10238
|
+
VND: [
|
|
10239
|
+
1e4,
|
|
10240
|
+
1
|
|
10241
|
+
]
|
|
10242
|
+
};
|
|
10243
|
+
var TIKTOK_BUDGET_RULES_BY_CURRENCY = Object.freeze(Object.fromEntries(Object.entries(TIKTOK_BUDGET_CURRENCY_POLICY).map(([currency, policy]) => {
|
|
10244
|
+
if (!policy) throw new Error(`Missing TikTok budget policy for ${currency}`);
|
|
10245
|
+
const [ratio, precision] = policy;
|
|
10246
|
+
return [
|
|
10247
|
+
currency,
|
|
10248
|
+
Object.freeze({
|
|
10249
|
+
minimumDailyBudget: 20 * ratio,
|
|
10250
|
+
maximumDailyBudgetExclusive: 1e7 * ratio,
|
|
10251
|
+
precision
|
|
10252
|
+
})
|
|
10253
|
+
];
|
|
10254
|
+
})));
|
|
10255
|
+
var TIKTOK_DAILY_BUDGET_BY_CURRENCY = Object.freeze(Object.fromEntries(Object.entries(TIKTOK_BUDGET_RULES_BY_CURRENCY).map(([currency, rule]) => [
|
|
10256
|
+
currency,
|
|
10257
|
+
rule?.minimumDailyBudget
|
|
10258
|
+
])));
|
|
10259
|
+
var TikTokBudgetCurrencySchema = z53.string().trim().toUpperCase().regex(/^[A-Z]{3}$/);
|
|
10015
10260
|
var TikTokObjectiveMode = z53.enum([
|
|
10016
10261
|
"auto",
|
|
10017
10262
|
"web_conversions",
|
|
10018
10263
|
"traffic"
|
|
10019
10264
|
]);
|
|
10265
|
+
var TikTokCampaignDestinationSchema = z53.discriminatedUnion("type", [
|
|
10266
|
+
z53.object({
|
|
10267
|
+
type: z53.literal("landing")
|
|
10268
|
+
}),
|
|
10269
|
+
z53.object({
|
|
10270
|
+
type: z53.literal("whatsapp"),
|
|
10271
|
+
phoneNumber: z53.string().trim().regex(/^\+?[1-9][\d\s().-]{6,30}$/).refine((value) => /^\d{7,15}$/.test(value.replace(/\D/g, "")), "Use an international WhatsApp number"),
|
|
10272
|
+
/** Disambiguates shared calling codes such as +1. Independent of ad targeting. */
|
|
10273
|
+
phoneRegionCode: CountryIso2Schema.optional()
|
|
10274
|
+
})
|
|
10275
|
+
]);
|
|
10020
10276
|
var TikTokCampaignConfigSchema = z53.object({
|
|
10021
10277
|
objectiveMode: TikTokObjectiveMode.default("auto"),
|
|
10022
10278
|
/** Optional — service defaults to the currency-aware advertiser minimum
|
|
10023
|
-
|
|
10024
|
-
|
|
10025
|
-
dailyBudget: z53.number().
|
|
10279
|
+
* when omitted (see TikTokService.createCampaignFromCreatives), so
|
|
10280
|
+
* partial overrides ({targetCountry} only) don't 400 at validation. */
|
|
10281
|
+
dailyBudget: z53.number().finite().positive().optional(),
|
|
10282
|
+
/** Required with an explicit dailyBudget; validated against the advertiser. No FX conversion. */
|
|
10283
|
+
budgetCurrency: TikTokBudgetCurrencySchema.optional(),
|
|
10026
10284
|
/** ISO-2 code or resolvable country name — normalized to alpha-2 at validation. */
|
|
10027
10285
|
targetCountry: CountryIso2Schema.optional(),
|
|
10028
|
-
campaignName: z53.string().trim().min(1).max(100).optional()
|
|
10286
|
+
campaignName: z53.string().trim().min(1).max(100).optional(),
|
|
10287
|
+
destination: TikTokCampaignDestinationSchema.optional()
|
|
10288
|
+
}).superRefine((value, ctx) => {
|
|
10289
|
+
if (value.dailyBudget !== void 0 && !value.budgetCurrency) {
|
|
10290
|
+
ctx.addIssue({
|
|
10291
|
+
code: z53.ZodIssueCode.custom,
|
|
10292
|
+
path: [
|
|
10293
|
+
"budgetCurrency"
|
|
10294
|
+
],
|
|
10295
|
+
message: "TIKTOK_BUDGET_CURRENCY_REQUIRED"
|
|
10296
|
+
});
|
|
10297
|
+
}
|
|
10029
10298
|
});
|
|
10030
10299
|
var TikTokCreateCampaignBodySchema = z53.object({
|
|
10031
10300
|
advertiserId: z53.string().min(1, "Debes seleccionar una cuenta publicitaria"),
|
|
@@ -10070,11 +10339,21 @@ var TikTokCreateCampaignFromCreativesBodySchema = z53.object({
|
|
|
10070
10339
|
})).min(1).max(CAMPAIGN_LIMITS.MAX_CREATIVES),
|
|
10071
10340
|
advertiserId: z53.string().min(1),
|
|
10072
10341
|
pixelId: z53.string().optional(),
|
|
10073
|
-
landingUrl: z53.string().url(),
|
|
10342
|
+
landingUrl: z53.string().url().optional(),
|
|
10074
10343
|
/** ISO 3166-1 alpha-2 country code (country names are normalized to alpha-2) */
|
|
10075
10344
|
targetCountry: CountryIso2Schema.default("US"),
|
|
10076
10345
|
campaignName: z53.string().min(1).max(100).optional(),
|
|
10077
10346
|
campaignConfig: TikTokCampaignConfigSchema.optional()
|
|
10347
|
+
}).superRefine((value, ctx) => {
|
|
10348
|
+
if (value.campaignConfig?.destination?.type !== "whatsapp" && !value.landingUrl) {
|
|
10349
|
+
ctx.addIssue({
|
|
10350
|
+
code: z53.ZodIssueCode.custom,
|
|
10351
|
+
path: [
|
|
10352
|
+
"landingUrl"
|
|
10353
|
+
],
|
|
10354
|
+
message: "A landing URL is required for a website destination"
|
|
10355
|
+
});
|
|
10356
|
+
}
|
|
10078
10357
|
});
|
|
10079
10358
|
var TikTokCreateCampaignResponseSchema = z53.object({
|
|
10080
10359
|
campaignId: z53.string(),
|
|
@@ -19457,7 +19736,7 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
|
|
|
19457
19736
|
], [
|
|
19458
19737
|
"campaign_status"
|
|
19459
19738
|
]),
|
|
19460
|
-
defineCapability("get_video_script", "
|
|
19739
|
+
defineCapability("get_video_script", "e987ff48555dfdab439f9910fb1fa25af373c78c8a9a5ef26458c82add90f2a2", "none", "read_only", [
|
|
19461
19740
|
"read"
|
|
19462
19741
|
], [
|
|
19463
19742
|
slot("task", true, [
|
|
@@ -19853,7 +20132,7 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
|
|
|
19853
20132
|
], [
|
|
19854
20133
|
"brand"
|
|
19855
20134
|
], MCP_ONLY_CHANNEL_EXPOSURE),
|
|
19856
|
-
defineCapability("create_service_landing", "
|
|
20135
|
+
defineCapability("create_service_landing", "ce99d75f4b00bea23b6bf4f56ef3331b266176cb0a9dead55611ee78d21c41b3", "credit_consuming", "creative", [
|
|
19857
20136
|
"credit_consuming",
|
|
19858
20137
|
"state_change"
|
|
19859
20138
|
], [
|
|
@@ -19931,37 +20210,47 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
|
|
|
19931
20210
|
], [
|
|
19932
20211
|
"commerce_verification"
|
|
19933
20212
|
], MCP_ONLY_CHANNEL_EXPOSURE),
|
|
19934
|
-
defineCapability(
|
|
20213
|
+
defineCapability(
|
|
20214
|
+
"publish_to_tiktok",
|
|
20215
|
+
// MCP 11.7.0: native WhatsApp destination and major-currency budget inputs.
|
|
20216
|
+
"50b932193b62929498ae342417427ef84b1982eb7620c6baffb62c8fb986e66e",
|
|
19935
20217
|
"external_mutation",
|
|
19936
|
-
"
|
|
19937
|
-
|
|
19938
|
-
|
|
19939
|
-
"
|
|
19940
|
-
]
|
|
19941
|
-
|
|
19942
|
-
"
|
|
19943
|
-
|
|
19944
|
-
|
|
19945
|
-
"
|
|
19946
|
-
|
|
19947
|
-
|
|
19948
|
-
"
|
|
19949
|
-
|
|
19950
|
-
|
|
19951
|
-
"
|
|
19952
|
-
|
|
19953
|
-
|
|
19954
|
-
"
|
|
19955
|
-
|
|
19956
|
-
|
|
19957
|
-
"
|
|
19958
|
-
|
|
19959
|
-
|
|
19960
|
-
|
|
19961
|
-
|
|
19962
|
-
|
|
19963
|
-
|
|
19964
|
-
|
|
20218
|
+
"publishing",
|
|
20219
|
+
[
|
|
20220
|
+
"external_mutation",
|
|
20221
|
+
"state_change"
|
|
20222
|
+
],
|
|
20223
|
+
[
|
|
20224
|
+
slot("task", true, [
|
|
20225
|
+
"taskId"
|
|
20226
|
+
]),
|
|
20227
|
+
slot("advertiser", true, [
|
|
20228
|
+
"advertiserId"
|
|
20229
|
+
]),
|
|
20230
|
+
slot("tracking", false, [
|
|
20231
|
+
"pixelId"
|
|
20232
|
+
]),
|
|
20233
|
+
slot("landing", false, [
|
|
20234
|
+
"landingUrl"
|
|
20235
|
+
]),
|
|
20236
|
+
slot("creative_selection", false, [
|
|
20237
|
+
"angleIndexes"
|
|
20238
|
+
]),
|
|
20239
|
+
slot("campaign_configuration", false, [
|
|
20240
|
+
"campaignConfig"
|
|
20241
|
+
]),
|
|
20242
|
+
slot("ad_copy", false, [
|
|
20243
|
+
"primaryText"
|
|
20244
|
+
])
|
|
20245
|
+
],
|
|
20246
|
+
[
|
|
20247
|
+
"creative",
|
|
20248
|
+
"tiktok_advertiser"
|
|
20249
|
+
],
|
|
20250
|
+
[
|
|
20251
|
+
"tiktok_publication"
|
|
20252
|
+
]
|
|
20253
|
+
),
|
|
19965
20254
|
defineCapability("prepare_winning_product_image", "6915790d22256a648374412ac4d11126fe3fabc9404f4552205057f9da3ce0db", "none", "business", [
|
|
19966
20255
|
"state_change"
|
|
19967
20256
|
], [
|
|
@@ -22268,51 +22557,6 @@ var ServicePageGenerateRequestSchema = z104.object({
|
|
|
22268
22557
|
instruction: ServicePageEditInstructionSchema.optional(),
|
|
22269
22558
|
attachmentRefs: ServicePageAttachmentRefsSchema.optional()
|
|
22270
22559
|
}).strict();
|
|
22271
|
-
var SERVICE_PAGE_SOURCES_MISSING_CODES = /* @__PURE__ */ new Set([
|
|
22272
|
-
"SERVICE_PAGE_SOURCES_REQUIRED",
|
|
22273
|
-
"SERVICE_PAGE_SOURCE_TEXT_REQUIRED"
|
|
22274
|
-
]);
|
|
22275
|
-
function isRetryableServicePageFailureCode(errorCode) {
|
|
22276
|
-
return servicePageFailurePolicy(errorCode).retryable;
|
|
22277
|
-
}
|
|
22278
|
-
__name(isRetryableServicePageFailureCode, "isRetryableServicePageFailureCode");
|
|
22279
|
-
function servicePageFailurePolicy(errorCode) {
|
|
22280
|
-
const code = errorCode ?? "";
|
|
22281
|
-
const retryable = !SERVICE_PAGE_SOURCES_MISSING_CODES.has(code) && !/CREDIT|QUOTE|REVISION|CONFLICT|WINDOW_EXPIRED|NOT_FOUND|POLICY_INVALID|SNAPSHOT_INVALID|OWNER_MISMATCH|PROVIDER_ROUTE_UNSUPPORTED|PROVIDER_REJECTED/.test(code);
|
|
22282
|
-
if (code.includes("QUOTE_EXPIRED")) return {
|
|
22283
|
-
reason: "quote_expired",
|
|
22284
|
-
retryable
|
|
22285
|
-
};
|
|
22286
|
-
if (code.includes("CREDIT")) return {
|
|
22287
|
-
reason: "credits",
|
|
22288
|
-
retryable
|
|
22289
|
-
};
|
|
22290
|
-
if (code.includes("NOT_FOUND")) return {
|
|
22291
|
-
reason: "not_found",
|
|
22292
|
-
retryable
|
|
22293
|
-
};
|
|
22294
|
-
if (/PROVIDER|ACCEPTANCE/.test(code)) return {
|
|
22295
|
-
reason: "provider",
|
|
22296
|
-
retryable
|
|
22297
|
-
};
|
|
22298
|
-
if (/NETWORK|TIMEOUT|QUEUE/.test(code)) return {
|
|
22299
|
-
reason: "network",
|
|
22300
|
-
retryable
|
|
22301
|
-
};
|
|
22302
|
-
if (/REVISION|STALE|CONFLICT/.test(code)) return {
|
|
22303
|
-
reason: "conflict",
|
|
22304
|
-
retryable
|
|
22305
|
-
};
|
|
22306
|
-
if (/INVALID|PRECONDITION|MISSING|REQUIRED|MISMATCH/.test(code)) return {
|
|
22307
|
-
reason: "validation",
|
|
22308
|
-
retryable
|
|
22309
|
-
};
|
|
22310
|
-
return {
|
|
22311
|
-
reason: "unknown",
|
|
22312
|
-
retryable
|
|
22313
|
-
};
|
|
22314
|
-
}
|
|
22315
|
-
__name(servicePageFailurePolicy, "servicePageFailurePolicy");
|
|
22316
22560
|
var SERVICE_PAGE_CREATION_MAX_ATTEMPTS = 3;
|
|
22317
22561
|
var ServicePageCreationMarkerSchema = z104.object({
|
|
22318
22562
|
rootOperationId: z104.string().uuid().optional(),
|
|
@@ -22464,6 +22708,18 @@ var ServicePagePreviewResponseSchema = z104.object({
|
|
|
22464
22708
|
artifact: ServiceLandingArtifactSchema,
|
|
22465
22709
|
assetsById: z104.record(AssetIdSchema, ServicePagePublicAssetSchema)
|
|
22466
22710
|
}).strict();
|
|
22711
|
+
var ServicePageAdminViewSchema = z104.object({
|
|
22712
|
+
id: z104.string().uuid(),
|
|
22713
|
+
businessName: z104.string().trim().min(1).max(120).nullable(),
|
|
22714
|
+
state: z104.enum([
|
|
22715
|
+
"created",
|
|
22716
|
+
"generating",
|
|
22717
|
+
"error"
|
|
22718
|
+
]),
|
|
22719
|
+
publicUrl: z104.string().url().nullable(),
|
|
22720
|
+
artifact: ServiceLandingArtifactSchema.nullable(),
|
|
22721
|
+
assetsById: z104.record(AssetIdSchema, ServicePagePublicAssetSchema)
|
|
22722
|
+
}).strict();
|
|
22467
22723
|
var ServicePagePreviewRequestSchema = z104.object({
|
|
22468
22724
|
expectedRevision: z104.number().int().nonnegative(),
|
|
22469
22725
|
candidateOperationId: z104.string().uuid().optional(),
|
|
@@ -22991,7 +23247,9 @@ var TaskAdDefaultsSchema = z113.object({
|
|
|
22991
23247
|
]).nullable(),
|
|
22992
23248
|
headline: z113.string().min(1).max(AD_HEADLINE_MAX_CHARS).nullable(),
|
|
22993
23249
|
/** ISO 3166-1 alpha-2 when known. */
|
|
22994
|
-
country: z113.string().min(2).nullable()
|
|
23250
|
+
country: z113.string().min(2).nullable(),
|
|
23251
|
+
/** The task Brand's contact; optional for older API responses. */
|
|
23252
|
+
whatsappNumber: WhatsAppE164Schema.nullable().optional()
|
|
22995
23253
|
});
|
|
22996
23254
|
|
|
22997
23255
|
// ../../packages/types/src/service-website-capture.ts
|
|
@@ -25237,7 +25495,7 @@ var ApiClient = class {
|
|
|
25237
25495
|
};
|
|
25238
25496
|
|
|
25239
25497
|
// src/index.ts
|
|
25240
|
-
var MCP_VERSION = "11.
|
|
25498
|
+
var MCP_VERSION = "11.8.1";
|
|
25241
25499
|
|
|
25242
25500
|
// src/meta-upload-app.ts
|
|
25243
25501
|
import { readFileSync } from "fs";
|
|
@@ -25309,7 +25567,7 @@ function registerMediaUploadAppResource(server, resolveEndpoint) {
|
|
|
25309
25567
|
__name(registerMediaUploadAppResource, "registerMediaUploadAppResource");
|
|
25310
25568
|
|
|
25311
25569
|
// src/tools/tasks.ts
|
|
25312
|
-
import { z as
|
|
25570
|
+
import { z as z122 } from "zod";
|
|
25313
25571
|
|
|
25314
25572
|
// src/resolve-image.ts
|
|
25315
25573
|
import { lookup as dnsLookup } from "dns/promises";
|
|
@@ -26332,6 +26590,13 @@ var McpErrorCode = {
|
|
|
26332
26590
|
META_WHATSAPP_INVALID_NUMBER: "META_WHATSAPP_INVALID_NUMBER",
|
|
26333
26591
|
META_INVALID_CTA: "META_INVALID_CTA",
|
|
26334
26592
|
// TikTok Ads
|
|
26593
|
+
TIKTOK_SERVICE_VIDEO_REQUIRED: "TIKTOK_SERVICE_VIDEO_REQUIRED",
|
|
26594
|
+
TIKTOK_BUDGET_CURRENCY_REQUIRED: "TIKTOK_BUDGET_CURRENCY_REQUIRED",
|
|
26595
|
+
TIKTOK_BUDGET_CURRENCY_UNSUPPORTED: "TIKTOK_BUDGET_CURRENCY_UNSUPPORTED",
|
|
26596
|
+
TIKTOK_BUDGET_CURRENCY_MISMATCH: "TIKTOK_BUDGET_CURRENCY_MISMATCH",
|
|
26597
|
+
TIKTOK_BUDGET_TOO_LOW: "TIKTOK_BUDGET_TOO_LOW",
|
|
26598
|
+
TIKTOK_BUDGET_PRECISION_INVALID: "TIKTOK_BUDGET_PRECISION_INVALID",
|
|
26599
|
+
TIKTOK_BUDGET_TOO_HIGH: "TIKTOK_BUDGET_TOO_HIGH",
|
|
26335
26600
|
TIKTOK_NOT_CONNECTED: "TIKTOK_NOT_CONNECTED",
|
|
26336
26601
|
TIKTOK_TOKEN_EXPIRED: "TIKTOK_TOKEN_EXPIRED",
|
|
26337
26602
|
TIKTOK_PERMISSION_DENIED: "TIKTOK_PERMISSION_DENIED",
|
|
@@ -26346,6 +26611,12 @@ var McpErrorCode = {
|
|
|
26346
26611
|
TIKTOK_RATE_LIMITED: "TIKTOK_RATE_LIMITED",
|
|
26347
26612
|
TIKTOK_SERVER_ERROR: "TIKTOK_SERVER_ERROR",
|
|
26348
26613
|
TIKTOK_INVALID_DATA: "TIKTOK_INVALID_DATA",
|
|
26614
|
+
TIKTOK_WHATSAPP_INVALID_NUMBER: "TIKTOK_WHATSAPP_INVALID_NUMBER",
|
|
26615
|
+
TIKTOK_WHATSAPP_PHONE_REGION_REQUIRED: "TIKTOK_WHATSAPP_PHONE_REGION_REQUIRED",
|
|
26616
|
+
TIKTOK_WHATSAPP_INVALID_OBJECTIVE: "TIKTOK_WHATSAPP_INVALID_OBJECTIVE",
|
|
26617
|
+
TIKTOK_WHATSAPP_UNSUPPORTED_COUNTRY: "TIKTOK_WHATSAPP_UNSUPPORTED_COUNTRY",
|
|
26618
|
+
TIKTOK_WHATSAPP_VIDEO_REQUIRED: "TIKTOK_WHATSAPP_VIDEO_REQUIRED",
|
|
26619
|
+
TIKTOK_WHATSAPP_UNAVAILABLE: "TIKTOK_WHATSAPP_UNAVAILABLE",
|
|
26349
26620
|
// Actor voice lifecycle (contextual voice cloning — the API throws these as
|
|
26350
26621
|
// Nest ConflictException("VOICE_*"), so they arrive in body.message)
|
|
26351
26622
|
VOICE_FEATURE_DISABLED: "VOICE_FEATURE_DISABLED",
|
|
@@ -26438,6 +26709,19 @@ var CODE_MESSAGES = {
|
|
|
26438
26709
|
TIKTOK_RATE_LIMITED: "TikTok rate-limited the request. Wait a few minutes before retrying.",
|
|
26439
26710
|
TIKTOK_SERVER_ERROR: "TikTok returned a server error. Retry in a few minutes.",
|
|
26440
26711
|
TIKTOK_INVALID_DATA: "TikTok rejected the request due to invalid data. Verify `advertiserId`, `pixelId`, and `campaignConfig`.",
|
|
26712
|
+
TIKTOK_BUDGET_CURRENCY_REQUIRED: "Verify the selected advertiser currency and pass budgetCurrency with an explicit dailyBudget. If the account currency is unavailable, refresh advertiser access; never assume USD or reinterpret a cents amount.",
|
|
26713
|
+
TIKTOK_BUDGET_CURRENCY_UNSUPPORTED: "The selected advertiser currency has no verified TikTok budget policy. Do not guess a default or convert currencies.",
|
|
26714
|
+
TIKTOK_BUDGET_CURRENCY_MISMATCH: "The budget currency differs from the selected advertiser currency. dailyBudgetUsd supports USD accounts only; use dailyBudget plus the exact account budgetCurrency, without guessed FX.",
|
|
26715
|
+
TIKTOK_BUDGET_TOO_LOW: "The daily budget is below the provider minimum in account-currency major units. Ask for a valid explicit amount; never silently increase it.",
|
|
26716
|
+
TIKTOK_BUDGET_PRECISION_INVALID: "The daily budget exceeds the supported precision for the advertiser currency. Ask for an amount with the required precision.",
|
|
26717
|
+
TIKTOK_BUDGET_TOO_HIGH: "The daily budget meets or exceeds the exclusive provider maximum in account-currency major units. Ask for a lower explicit amount.",
|
|
26718
|
+
TIKTOK_SERVICE_VIDEO_REQUIRED: "Service image ads are supported on Meta. For TikTok, choose a service video; never silently omit an image from a mixed selected set.",
|
|
26719
|
+
TIKTOK_WHATSAPP_INVALID_NUMBER: "Use a complete international WhatsApp number including its calling code.",
|
|
26720
|
+
TIKTOK_WHATSAPP_PHONE_REGION_REQUIRED: "Ask the user for the country of this phone number and pass destination.phoneRegionCode. Do not assume it is the target country.",
|
|
26721
|
+
TIKTOK_WHATSAPP_INVALID_OBJECTIVE: "WhatsApp uses native click optimization. Choose a landing destination for web conversions.",
|
|
26722
|
+
TIKTOK_WHATSAPP_UNSUPPORTED_COUNTRY: "TikTok does not support native WhatsApp ad targeting in this country. Choose a supported country or a landing page.",
|
|
26723
|
+
TIKTOK_WHATSAPP_VIDEO_REQUIRED: "Native TikTok WhatsApp ads require video creatives. Choose a video or a landing destination for this image.",
|
|
26724
|
+
TIKTOK_WHATSAPP_UNAVAILABLE: "Verify the international WhatsApp number and ask TikTok to enable instant messaging ads for this advertiser. Do not retry as website traffic.",
|
|
26441
26725
|
// Campaign (shared)
|
|
26442
26726
|
CAMPAIGN_NOT_FOUND: "Campaign not found or does not belong to this user. Verify the `campaignId`.",
|
|
26443
26727
|
CAMPAIGN_TASK_NOT_FOUND: "Campaign task not found. Verify the `taskId`.",
|
|
@@ -26562,6 +26846,19 @@ var INVALID_PARAM_CODES = /* @__PURE__ */ new Set([
|
|
|
26562
26846
|
// Validation-shape backend errors (data-level rejection)
|
|
26563
26847
|
McpErrorCode.META_INVALID_DATA,
|
|
26564
26848
|
McpErrorCode.TIKTOK_INVALID_DATA,
|
|
26849
|
+
McpErrorCode.TIKTOK_SERVICE_VIDEO_REQUIRED,
|
|
26850
|
+
McpErrorCode.TIKTOK_BUDGET_CURRENCY_REQUIRED,
|
|
26851
|
+
McpErrorCode.TIKTOK_BUDGET_CURRENCY_UNSUPPORTED,
|
|
26852
|
+
McpErrorCode.TIKTOK_BUDGET_CURRENCY_MISMATCH,
|
|
26853
|
+
McpErrorCode.TIKTOK_BUDGET_TOO_LOW,
|
|
26854
|
+
McpErrorCode.TIKTOK_BUDGET_PRECISION_INVALID,
|
|
26855
|
+
McpErrorCode.TIKTOK_BUDGET_TOO_HIGH,
|
|
26856
|
+
McpErrorCode.TIKTOK_WHATSAPP_INVALID_NUMBER,
|
|
26857
|
+
McpErrorCode.TIKTOK_WHATSAPP_PHONE_REGION_REQUIRED,
|
|
26858
|
+
McpErrorCode.TIKTOK_WHATSAPP_INVALID_OBJECTIVE,
|
|
26859
|
+
McpErrorCode.TIKTOK_WHATSAPP_UNSUPPORTED_COUNTRY,
|
|
26860
|
+
McpErrorCode.TIKTOK_WHATSAPP_VIDEO_REQUIRED,
|
|
26861
|
+
McpErrorCode.TIKTOK_WHATSAPP_UNAVAILABLE,
|
|
26565
26862
|
// Out-of-band user-resolvable auth/billing/connection — caller fixes by
|
|
26566
26863
|
// going to Facebook/TikTok/Shopify and reconnecting, finishing
|
|
26567
26864
|
// verification, or adding a payment method. None of these are transient,
|
|
@@ -26692,6 +26989,19 @@ var PASSTHROUGH_CODES = /* @__PURE__ */ new Set([
|
|
|
26692
26989
|
McpErrorCode.TIKTOK_RATE_LIMITED,
|
|
26693
26990
|
McpErrorCode.TIKTOK_SERVER_ERROR,
|
|
26694
26991
|
McpErrorCode.TIKTOK_INVALID_DATA,
|
|
26992
|
+
McpErrorCode.TIKTOK_SERVICE_VIDEO_REQUIRED,
|
|
26993
|
+
McpErrorCode.TIKTOK_BUDGET_CURRENCY_REQUIRED,
|
|
26994
|
+
McpErrorCode.TIKTOK_BUDGET_CURRENCY_UNSUPPORTED,
|
|
26995
|
+
McpErrorCode.TIKTOK_BUDGET_CURRENCY_MISMATCH,
|
|
26996
|
+
McpErrorCode.TIKTOK_BUDGET_TOO_LOW,
|
|
26997
|
+
McpErrorCode.TIKTOK_BUDGET_PRECISION_INVALID,
|
|
26998
|
+
McpErrorCode.TIKTOK_BUDGET_TOO_HIGH,
|
|
26999
|
+
McpErrorCode.TIKTOK_WHATSAPP_INVALID_NUMBER,
|
|
27000
|
+
McpErrorCode.TIKTOK_WHATSAPP_PHONE_REGION_REQUIRED,
|
|
27001
|
+
McpErrorCode.TIKTOK_WHATSAPP_INVALID_OBJECTIVE,
|
|
27002
|
+
McpErrorCode.TIKTOK_WHATSAPP_UNSUPPORTED_COUNTRY,
|
|
27003
|
+
McpErrorCode.TIKTOK_WHATSAPP_VIDEO_REQUIRED,
|
|
27004
|
+
McpErrorCode.TIKTOK_WHATSAPP_UNAVAILABLE,
|
|
26695
27005
|
// Campaign (shared)
|
|
26696
27006
|
McpErrorCode.CAMPAIGN_NOT_FOUND,
|
|
26697
27007
|
McpErrorCode.CAMPAIGN_TASK_NOT_FOUND,
|
|
@@ -26871,8 +27181,67 @@ function approveRefusalMessage(reason) {
|
|
|
26871
27181
|
}
|
|
26872
27182
|
__name(approveRefusalMessage, "approveRefusalMessage");
|
|
26873
27183
|
|
|
27184
|
+
// src/tools/task-outputs.ts
|
|
27185
|
+
import { z as z118 } from "zod";
|
|
27186
|
+
|
|
27187
|
+
// src/tools/conversational-review-format.ts
|
|
27188
|
+
function escapeMarkdownText(value) {
|
|
27189
|
+
return value.replace(/\\/g, "\\\\").replace(/([`*_{}[\]()<>#+.!|>])/g, "\\$1").replace(/[\r\n\u2028\u2029]+/g, " ");
|
|
27190
|
+
}
|
|
27191
|
+
__name(escapeMarkdownText, "escapeMarkdownText");
|
|
27192
|
+
function trustedPreviewUrl(raw) {
|
|
27193
|
+
if (/[\u0000-\u001f\u007f]/.test(raw)) return null;
|
|
27194
|
+
try {
|
|
27195
|
+
const url = new URL(raw);
|
|
27196
|
+
if (url.username || url.password) return null;
|
|
27197
|
+
const hostname = url.hostname.toLowerCase();
|
|
27198
|
+
const productMakerHost = hostname === "productmaker.app" || hostname.endsWith(".productmaker.app");
|
|
27199
|
+
const localHost = hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
|
|
27200
|
+
if (url.protocol === "https:" && productMakerHost && (!url.port || url.port === "443")) {
|
|
27201
|
+
return url.toString().replace(/\(/g, "%28").replace(/\)/g, "%29");
|
|
27202
|
+
}
|
|
27203
|
+
if (url.protocol === "http:" && localHost) {
|
|
27204
|
+
return url.toString().replace(/\(/g, "%28").replace(/\)/g, "%29");
|
|
27205
|
+
}
|
|
27206
|
+
return null;
|
|
27207
|
+
} catch {
|
|
27208
|
+
return null;
|
|
27209
|
+
}
|
|
27210
|
+
}
|
|
27211
|
+
__name(trustedPreviewUrl, "trustedPreviewUrl");
|
|
27212
|
+
function renderPreview(preview2, index) {
|
|
27213
|
+
const label = escapeMarkdownText(preview2.label);
|
|
27214
|
+
const url = trustedPreviewUrl(preview2.previewUrl);
|
|
27215
|
+
return [
|
|
27216
|
+
`### Foto ${index + 1}: ${label}`,
|
|
27217
|
+
...preview2.view ? [
|
|
27218
|
+
`- **Vista:** ${escapeMarkdownText(preview2.view)}`
|
|
27219
|
+
] : [],
|
|
27220
|
+
...url ? [
|
|
27221
|
+
``
|
|
27222
|
+
] : [
|
|
27223
|
+
"- Vista previa externa bloqueada por seguridad. \xC1brela desde ProductMaker Web."
|
|
27224
|
+
]
|
|
27225
|
+
];
|
|
27226
|
+
}
|
|
27227
|
+
__name(renderPreview, "renderPreview");
|
|
27228
|
+
function formatCredits(creditCents) {
|
|
27229
|
+
return new Intl.NumberFormat("es-CO", {
|
|
27230
|
+
minimumFractionDigits: creditCents % 100 === 0 ? 0 : 2,
|
|
27231
|
+
maximumFractionDigits: 2
|
|
27232
|
+
}).format(creditCents / 100);
|
|
27233
|
+
}
|
|
27234
|
+
__name(formatCredits, "formatCredits");
|
|
27235
|
+
|
|
26874
27236
|
// src/tools/task-outputs.ts
|
|
26875
27237
|
var WEBAPP_BASE = "https://productmaker.app";
|
|
27238
|
+
var CreativeVariantIdentity = z118.object({
|
|
27239
|
+
variantTaskId: z118.string().uuid(),
|
|
27240
|
+
sourceTaskId: z118.string().uuid(),
|
|
27241
|
+
kind: TaskCreativeVariantKind,
|
|
27242
|
+
status: TaskStatusSchema,
|
|
27243
|
+
error: z118.string().optional()
|
|
27244
|
+
});
|
|
26876
27245
|
function proxifyOutputs(outputs, proxyBaseUrl) {
|
|
26877
27246
|
if (!proxyBaseUrl || !isProxyEnabled()) return outputs;
|
|
26878
27247
|
const rewrite = /* @__PURE__ */ __name((url, filename) => buildProxyUrl({
|
|
@@ -26916,7 +27285,15 @@ function proxifyOutputs(outputs, proxyBaseUrl) {
|
|
|
26916
27285
|
...variant,
|
|
26917
27286
|
url: rewrite(variant.url, `video-${sanitizeFilename(v.angleKey)}-${sanitizeFilename(variant.kind)}.mp4`)
|
|
26918
27287
|
}))
|
|
26919
|
-
}))
|
|
27288
|
+
})),
|
|
27289
|
+
...outputs.creativeVariants?.length ? {
|
|
27290
|
+
creativeVariants: outputs.creativeVariants.map((child) => ({
|
|
27291
|
+
...child,
|
|
27292
|
+
...child.outputs ? {
|
|
27293
|
+
outputs: proxifyOutputs(child.outputs, proxyBaseUrl)
|
|
27294
|
+
} : {}
|
|
27295
|
+
}))
|
|
27296
|
+
} : {}
|
|
26920
27297
|
};
|
|
26921
27298
|
}
|
|
26922
27299
|
__name(proxifyOutputs, "proxifyOutputs");
|
|
@@ -26926,6 +27303,37 @@ function sanitizeFilename(s) {
|
|
|
26926
27303
|
__name(sanitizeFilename, "sanitizeFilename");
|
|
26927
27304
|
async function fetchTaskOutputs(api, taskId, options) {
|
|
26928
27305
|
const raw = await api.getJson(`/v1/results/${encodeURIComponent(taskId)}?signedUrls=true`, options);
|
|
27306
|
+
const creativeVariants = (raw.creativeVariants ?? []).flatMap((child) => {
|
|
27307
|
+
const identity = CreativeVariantIdentity.safeParse(child);
|
|
27308
|
+
if (!identity.success || identity.data.sourceTaskId !== taskId) return [];
|
|
27309
|
+
const { error, ...details } = identity.data;
|
|
27310
|
+
return [
|
|
27311
|
+
{
|
|
27312
|
+
...details,
|
|
27313
|
+
...error ? {
|
|
27314
|
+
error: error.slice(0, 1e3)
|
|
27315
|
+
} : {},
|
|
27316
|
+
nextAction: {
|
|
27317
|
+
tool: "get_task_status",
|
|
27318
|
+
arguments: {
|
|
27319
|
+
taskId: details.variantTaskId
|
|
27320
|
+
}
|
|
27321
|
+
},
|
|
27322
|
+
...details.status === "done" ? {
|
|
27323
|
+
outputs: projectTaskOutputs(child, details.variantTaskId)
|
|
27324
|
+
} : {}
|
|
27325
|
+
}
|
|
27326
|
+
];
|
|
27327
|
+
});
|
|
27328
|
+
return {
|
|
27329
|
+
...projectTaskOutputs(raw, taskId),
|
|
27330
|
+
...creativeVariants.length ? {
|
|
27331
|
+
creativeVariants
|
|
27332
|
+
} : {}
|
|
27333
|
+
};
|
|
27334
|
+
}
|
|
27335
|
+
__name(fetchTaskOutputs, "fetchTaskOutputs");
|
|
27336
|
+
function projectTaskOutputs(raw, taskId) {
|
|
26929
27337
|
const videos = (raw.videoGenerators ?? []).map((vg) => {
|
|
26930
27338
|
const variants2 = (vg.variants ?? []).filter((v) => Boolean(v.kind) && Boolean(v.url)).map((v) => ({
|
|
26931
27339
|
kind: v.kind,
|
|
@@ -27010,7 +27418,7 @@ async function fetchTaskOutputs(api, taskId, options) {
|
|
|
27010
27418
|
adCopy: typeof raw.adCreative?.adCopy === "string" && raw.adCreative.adCopy.length ? raw.adCreative.adCopy : void 0
|
|
27011
27419
|
};
|
|
27012
27420
|
}
|
|
27013
|
-
__name(
|
|
27421
|
+
__name(projectTaskOutputs, "projectTaskOutputs");
|
|
27014
27422
|
function renderOutputsMarkdown(outputs) {
|
|
27015
27423
|
const parts = [];
|
|
27016
27424
|
parts.push(`\u2705 **Tu tarea est\xE1 lista** \u2014 [Abrir en Product Maker](${outputs.webappUrl})`);
|
|
@@ -27052,6 +27460,18 @@ function renderOutputsMarkdown(outputs) {
|
|
|
27052
27460
|
}
|
|
27053
27461
|
}
|
|
27054
27462
|
}
|
|
27463
|
+
for (const child of outputs.creativeVariants ?? []) {
|
|
27464
|
+
const label = child.kind === "image" ? "imagen" : child.kind;
|
|
27465
|
+
parts.push(`
|
|
27466
|
+
### Variante de ${label}`);
|
|
27467
|
+
if (child.status === "done" && child.outputs) {
|
|
27468
|
+
parts.push(renderOutputsMarkdown(child.outputs));
|
|
27469
|
+
} else if (child.status === "error") {
|
|
27470
|
+
parts.push(escapeMarkdownText(child.error ?? "No se pudo entregar esta variante."));
|
|
27471
|
+
} else {
|
|
27472
|
+
parts.push("La variante sigue gener\xE1ndose. Consulta su estado antes de iniciar otra.");
|
|
27473
|
+
}
|
|
27474
|
+
}
|
|
27055
27475
|
return parts.join("\n");
|
|
27056
27476
|
}
|
|
27057
27477
|
__name(renderOutputsMarkdown, "renderOutputsMarkdown");
|
|
@@ -27095,55 +27515,6 @@ __name(outputGifs, "outputGifs");
|
|
|
27095
27515
|
var PendingPresentationSchema = PendingUserActionSchema;
|
|
27096
27516
|
var VideoScriptSchema = GetVideoScriptForReviewResponse;
|
|
27097
27517
|
|
|
27098
|
-
// src/tools/conversational-review-format.ts
|
|
27099
|
-
function escapeMarkdownText(value) {
|
|
27100
|
-
return value.replace(/\\/g, "\\\\").replace(/([`*_{}[\]()<>#+.!|>])/g, "\\$1").replace(/[\r\n\u2028\u2029]+/g, " ");
|
|
27101
|
-
}
|
|
27102
|
-
__name(escapeMarkdownText, "escapeMarkdownText");
|
|
27103
|
-
function trustedPreviewUrl(raw) {
|
|
27104
|
-
if (/[\u0000-\u001f\u007f]/.test(raw)) return null;
|
|
27105
|
-
try {
|
|
27106
|
-
const url = new URL(raw);
|
|
27107
|
-
if (url.username || url.password) return null;
|
|
27108
|
-
const hostname = url.hostname.toLowerCase();
|
|
27109
|
-
const productMakerHost = hostname === "productmaker.app" || hostname.endsWith(".productmaker.app");
|
|
27110
|
-
const localHost = hostname === "localhost" || hostname === "127.0.0.1" || hostname === "[::1]";
|
|
27111
|
-
if (url.protocol === "https:" && productMakerHost && (!url.port || url.port === "443")) {
|
|
27112
|
-
return url.toString().replace(/\(/g, "%28").replace(/\)/g, "%29");
|
|
27113
|
-
}
|
|
27114
|
-
if (url.protocol === "http:" && localHost) {
|
|
27115
|
-
return url.toString().replace(/\(/g, "%28").replace(/\)/g, "%29");
|
|
27116
|
-
}
|
|
27117
|
-
return null;
|
|
27118
|
-
} catch {
|
|
27119
|
-
return null;
|
|
27120
|
-
}
|
|
27121
|
-
}
|
|
27122
|
-
__name(trustedPreviewUrl, "trustedPreviewUrl");
|
|
27123
|
-
function renderPreview(preview2, index) {
|
|
27124
|
-
const label = escapeMarkdownText(preview2.label);
|
|
27125
|
-
const url = trustedPreviewUrl(preview2.previewUrl);
|
|
27126
|
-
return [
|
|
27127
|
-
`### Foto ${index + 1}: ${label}`,
|
|
27128
|
-
...preview2.view ? [
|
|
27129
|
-
`- **Vista:** ${escapeMarkdownText(preview2.view)}`
|
|
27130
|
-
] : [],
|
|
27131
|
-
...url ? [
|
|
27132
|
-
``
|
|
27133
|
-
] : [
|
|
27134
|
-
"- Vista previa externa bloqueada por seguridad. \xC1brela desde ProductMaker Web."
|
|
27135
|
-
]
|
|
27136
|
-
];
|
|
27137
|
-
}
|
|
27138
|
-
__name(renderPreview, "renderPreview");
|
|
27139
|
-
function formatCredits(creditCents) {
|
|
27140
|
-
return new Intl.NumberFormat("es-CO", {
|
|
27141
|
-
minimumFractionDigits: creditCents % 100 === 0 ? 0 : 2,
|
|
27142
|
-
maximumFractionDigits: 2
|
|
27143
|
-
}).format(creditCents / 100);
|
|
27144
|
-
}
|
|
27145
|
-
__name(formatCredits, "formatCredits");
|
|
27146
|
-
|
|
27147
27518
|
// src/tools/conversational-review.ts
|
|
27148
27519
|
var PRODUCT_REFERENCE_LABELS = {
|
|
27149
27520
|
same_product: "Es el mismo producto",
|
|
@@ -27473,29 +27844,29 @@ ${parsed.data.error ? `${escapeMarkdownText(parsed.data.error)}
|
|
|
27473
27844
|
__name(renderVideoScriptMarkdown, "renderVideoScriptMarkdown");
|
|
27474
27845
|
|
|
27475
27846
|
// src/tools/media-presentation.ts
|
|
27476
|
-
import { z as
|
|
27477
|
-
var HttpsPresentationUrlSchema =
|
|
27847
|
+
import { z as z119 } from "zod";
|
|
27848
|
+
var HttpsPresentationUrlSchema = z119.string().url().max(2048).refine((value) => new URL(value).protocol === "https:");
|
|
27478
27849
|
var ProductMakerPreviewUrlSchema = HttpsPresentationUrlSchema.refine((value) => {
|
|
27479
27850
|
const hostname = new URL(value).hostname.toLowerCase();
|
|
27480
27851
|
return hostname === "productmaker.app" || hostname.endsWith(".productmaker.app");
|
|
27481
27852
|
}, "preview URL must be owned by ProductMaker");
|
|
27482
|
-
var positiveIntAtMost = /* @__PURE__ */ __name((maximum) =>
|
|
27483
|
-
var PresentationImageSchema =
|
|
27484
|
-
kind:
|
|
27853
|
+
var positiveIntAtMost = /* @__PURE__ */ __name((maximum) => z119.number().int().positive().max(maximum), "positiveIntAtMost");
|
|
27854
|
+
var PresentationImageSchema = z119.object({
|
|
27855
|
+
kind: z119.literal("image"),
|
|
27485
27856
|
url: HttpsPresentationUrlSchema,
|
|
27486
|
-
mimeType:
|
|
27857
|
+
mimeType: z119.enum([
|
|
27487
27858
|
"image/jpeg",
|
|
27488
27859
|
"image/png"
|
|
27489
27860
|
]),
|
|
27490
27861
|
byteSize: positiveIntAtMost(5 * 1024 * 1024),
|
|
27491
27862
|
width: positiveIntAtMost(16384),
|
|
27492
27863
|
height: positiveIntAtMost(16384),
|
|
27493
|
-
alt:
|
|
27864
|
+
alt: z119.string().trim().min(1).max(240)
|
|
27494
27865
|
}).strict();
|
|
27495
27866
|
var McpMediaPresentationSchema = PresentationImageSchema;
|
|
27496
|
-
var GalleryImageSchema =
|
|
27867
|
+
var GalleryImageSchema = z119.object({
|
|
27497
27868
|
url: ProductMakerPreviewUrlSchema,
|
|
27498
|
-
alt:
|
|
27869
|
+
alt: z119.string().trim().min(1).max(240)
|
|
27499
27870
|
});
|
|
27500
27871
|
var MCP_GALLERY_IMAGE_MAX_BYTES = 10 * 1024 * 1024;
|
|
27501
27872
|
async function imageBlocks(image, transport) {
|
|
@@ -27552,12 +27923,12 @@ async function buildMcpMediaPresentationContent(rawPresentation, transport = "ht
|
|
|
27552
27923
|
];
|
|
27553
27924
|
}
|
|
27554
27925
|
__name(buildMcpMediaPresentationContent, "buildMcpMediaPresentationContent");
|
|
27555
|
-
var OwnedImagePreviewSchema =
|
|
27926
|
+
var OwnedImagePreviewSchema = z119.object({
|
|
27556
27927
|
url: HttpsPresentationUrlSchema.refine((value) => {
|
|
27557
27928
|
const url = new URL(value);
|
|
27558
27929
|
return !url.username && !url.password && !isPrivateHost(url.hostname);
|
|
27559
27930
|
}, "Preview URL must be public HTTPS without credentials"),
|
|
27560
|
-
alt:
|
|
27931
|
+
alt: z119.string().trim().min(1).max(240)
|
|
27561
27932
|
});
|
|
27562
27933
|
async function buildMcpImagePreviewContent(rawPreview, transport = "http") {
|
|
27563
27934
|
const preview2 = OwnedImagePreviewSchema.safeParse(rawPreview);
|
|
@@ -27640,7 +28011,7 @@ async function buildMcpImageGalleryContent(rawItems, transport = "http") {
|
|
|
27640
28011
|
__name(buildMcpImageGalleryContent, "buildMcpImageGalleryContent");
|
|
27641
28012
|
|
|
27642
28013
|
// src/tools/animated-video.ts
|
|
27643
|
-
import { z as
|
|
28014
|
+
import { z as z120 } from "zod";
|
|
27644
28015
|
|
|
27645
28016
|
// src/tools/paid-confirmation.ts
|
|
27646
28017
|
function describeMarketStudyChoice(enabled) {
|
|
@@ -27889,29 +28260,29 @@ function hookVariantsLabel(count) {
|
|
|
27889
28260
|
return count === 1 ? "1 versi\xF3n del gancho" : `${count} versiones del gancho`;
|
|
27890
28261
|
}
|
|
27891
28262
|
__name(hookVariantsLabel, "hookVariantsLabel");
|
|
27892
|
-
var DurationInput =
|
|
27893
|
-
var CreateAnimatedVideoInput =
|
|
27894
|
-
action:
|
|
28263
|
+
var DurationInput = z120.union(MOTION_GRAPHICS_DURATIONS.map((d) => z120.literal(d)));
|
|
28264
|
+
var CreateAnimatedVideoInput = z120.object({
|
|
28265
|
+
action: z120.enum([
|
|
27895
28266
|
"prepare",
|
|
27896
28267
|
"status",
|
|
27897
28268
|
"cancel",
|
|
27898
28269
|
"generate"
|
|
27899
28270
|
]).default("prepare").describe("prepare inicia una captura gratuita; status consulta websiteCaptureId; cancel la cancela; generate requiere captura ready y confirmaci\xF3n expl\xEDcita del usuario despu\xE9s de mostrar vista previa y precio."),
|
|
27900
|
-
websiteCaptureId:
|
|
27901
|
-
generationRequestId:
|
|
27902
|
-
confirmed:
|
|
28271
|
+
websiteCaptureId: z120.string().uuid().optional().describe("ID de la captura preparada. Obligatorio para status/cancel/generate; no inventarlo."),
|
|
28272
|
+
generationRequestId: z120.string().uuid().optional().describe("Identidad opcional de una generaci\xF3n confirmada. Repite el mismo UUID al recuperar una respuesta perdida; usa otro \xFAnicamente cuando el usuario pida y confirme otro video, nunca por un error de transporte."),
|
|
28273
|
+
confirmed: z120.boolean().optional().describe("Solo true despu\xE9s de que el usuario confirme esta captura, formato, duraci\xF3n, idioma y precio. Obligatorio para generate; preparar no genera ni cobra."),
|
|
27903
28274
|
// Plain text, not `.url()`: users type «cal.com», and the web accepts it.
|
|
27904
28275
|
// normalizeWebAddress (shared with the web) adds https:// and refuses
|
|
27905
28276
|
// anything that is not a public http(s) address.
|
|
27906
|
-
landingUrl:
|
|
28277
|
+
landingUrl: z120.string().trim().min(1).optional().describe("Enlace p\xFAblico de la p\xE1gina del servicio, como lo dio el usuario (\xABcal.com\xBB o \xABhttps://cal.com\xBB). El video sale de lo que muestra esa p\xE1gina: su marca, colores y mensajes."),
|
|
27907
28278
|
format: MotionGraphicsFormatSchema.optional().describe('Formato: "vertical" (9:16, Reels/TikTok), "square" (1:1, feed) u "horizontal" (16:9, YouTube/web). Si el usuario no lo dijo, PREG\xDANTALE.'),
|
|
27908
28279
|
durationSec: DurationInput.optional().describe(`Duraci\xF3n en segundos: ${MOTION_GRAPHICS_DURATIONS.join(", ")}. Fija el precio (ver la descripci\xF3n de la herramienta). Si el usuario no la dijo, PREG\xDANTALE.`),
|
|
27909
28280
|
language: MotionGraphicsLanguageSchema.optional().describe('Idioma de los textos del video: "es", "en" o "pt".'),
|
|
27910
28281
|
videoQuality: MotionGraphicsVideoQualitySchema.default(DEFAULT_MOTION_GRAPHICS_VIDEO_QUALITY).describe('Calidad IA: "economy" (econ\xF3mica) o "pro" (alta, por defecto). Afecta el precio de los clips IA.'),
|
|
27911
28282
|
videoResolution: MotionGraphicsVideoResolutionSchema.default(DEFAULT_MOTION_GRAPHICS_VIDEO_RESOLUTION).describe('Resoluci\xF3n: "480p" (por defecto), "720p" o "1080p". 1080p solo est\xE1 disponible con videoQuality="pro".'),
|
|
27912
|
-
notes:
|
|
28283
|
+
notes: z120.string().trim().max(MOTION_GRAPHICS_NOTES_MAX_CHARS).optional().describe("Opcional. Idea creativa, escenarios, acciones, di\xE1logo, voz o m\xFAsica en lenguaje natural. El director puede hacer solo motion graphics, escenas reales o escenas imposibles seg\xFAn la idea; las frases gu\xEDan el guion sin garantizar reproducci\xF3n exacta."),
|
|
27913
28284
|
hookVariants: MotionGraphicsHookVariantsSchema.optional().describe(`Opcional. Versiones del gancho: el mismo video con distintas aperturas para probar cu\xE1l funciona mejor, de 1 a ${MOTION_GRAPHICS_HOOK_VARIANTS_MAX} (por defecto 1). Cada versi\xF3n extra tiene precio (ver la descripci\xF3n de la herramienta); \xFAsalo solo si el usuario lo pide.`),
|
|
27914
|
-
music:
|
|
28285
|
+
music: z120.boolean().optional().describe("Opcional. M\xFAsica y efectos dirigidos seg\xFAn el negocio y el video (por defecto true), con una copia adicional solo con voces. false entrega solo voces, sin m\xFAsica ni efectos a\xF1adidos ni el cargo de m\xFAsica. \xDAsalo solo si el usuario lo pide.")
|
|
27915
28286
|
}).strict();
|
|
27916
28287
|
function captureNextAction(capture) {
|
|
27917
28288
|
if (capture.status === "ready") return "Muestra la vista previa al usuario y confirma formato, duraci\xF3n, idioma, calidad IA, resoluci\xF3n y precio. Solo despu\xE9s llama create_animated_video con action=generate, este websiteCaptureId y confirmed=true.";
|
|
@@ -27961,49 +28332,49 @@ var FORMAT_LABELS = {
|
|
|
27961
28332
|
square: "cuadrado 1:1",
|
|
27962
28333
|
horizontal: "horizontal 16:9"
|
|
27963
28334
|
};
|
|
27964
|
-
var AnimatedVideoResultSchema =
|
|
27965
|
-
status:
|
|
28335
|
+
var AnimatedVideoResultSchema = z120.object({
|
|
28336
|
+
status: z120.enum([
|
|
27966
28337
|
"pending",
|
|
27967
28338
|
"done",
|
|
27968
28339
|
"error"
|
|
27969
28340
|
]),
|
|
27970
|
-
serviceMode:
|
|
27971
|
-
finalMp4Url:
|
|
27972
|
-
adCopy:
|
|
27973
|
-
adCopies:
|
|
27974
|
-
error:
|
|
27975
|
-
motionGraphics:
|
|
28341
|
+
serviceMode: z120.literal("motion_graphics"),
|
|
28342
|
+
finalMp4Url: z120.string().optional(),
|
|
28343
|
+
adCopy: z120.string().optional(),
|
|
28344
|
+
adCopies: z120.array(z120.string()).optional(),
|
|
28345
|
+
error: z120.string().optional(),
|
|
28346
|
+
motionGraphics: z120.object({
|
|
27976
28347
|
stage: MotionGraphicsStageSchema,
|
|
27977
28348
|
format: MotionGraphicsFormatSchema,
|
|
27978
|
-
durationSec:
|
|
27979
|
-
width:
|
|
27980
|
-
height:
|
|
28349
|
+
durationSec: z120.number(),
|
|
28350
|
+
width: z120.number().optional(),
|
|
28351
|
+
height: z120.number().optional(),
|
|
27981
28352
|
language: MotionGraphicsLanguageSchema.optional(),
|
|
27982
28353
|
videoQuality: MotionGraphicsVideoQualitySchema.optional().catch(void 0),
|
|
27983
28354
|
videoResolution: MotionGraphicsVideoResolutionSchema.optional().catch(void 0),
|
|
27984
|
-
queuedAt:
|
|
27985
|
-
jobsAhead:
|
|
27986
|
-
stageStartedAt:
|
|
27987
|
-
renderProgress:
|
|
28355
|
+
queuedAt: z120.string().optional(),
|
|
28356
|
+
jobsAhead: z120.number().int().nonnegative().optional(),
|
|
28357
|
+
stageStartedAt: z120.string().optional(),
|
|
28358
|
+
renderProgress: z120.number().optional(),
|
|
27988
28359
|
// AI clip fields (absent on a video paid before clips, or from an API
|
|
27989
28360
|
// that predates them). Lenient: an unreadable value is dropped
|
|
27990
28361
|
// instead of hiding the status.
|
|
27991
|
-
clipCount:
|
|
27992
|
-
clipsUsed:
|
|
27993
|
-
clipPriceCents:
|
|
27994
|
-
clipsRefunded:
|
|
28362
|
+
clipCount: z120.number().int().nonnegative().optional().catch(void 0),
|
|
28363
|
+
clipsUsed: z120.number().int().nonnegative().optional().catch(void 0),
|
|
28364
|
+
clipPriceCents: z120.number().finite().nonnegative().optional().catch(void 0),
|
|
28365
|
+
clipsRefunded: z120.number().int().nonnegative().optional().catch(void 0),
|
|
27995
28366
|
// Hook versions (absent from an API or a video before them): the
|
|
27996
28367
|
// count ordered and, once done, the signed URLs of the EXTRA versions
|
|
27997
28368
|
// (hook 2, hook 3); `finalMp4Url` is hook 1.
|
|
27998
|
-
hookVariants:
|
|
27999
|
-
cleanVideoUrl:
|
|
28000
|
-
cleanVariantUrls:
|
|
28001
|
-
variantUrls:
|
|
28369
|
+
hookVariants: z120.number().int().min(1).max(MOTION_GRAPHICS_HOOK_VARIANTS_MAX).optional().catch(void 0),
|
|
28370
|
+
cleanVideoUrl: z120.string().url().optional().catch(void 0),
|
|
28371
|
+
cleanVariantUrls: z120.array(z120.string().url()).max(MOTION_GRAPHICS_HOOK_VARIANTS_MAX - 1).optional().catch(void 0),
|
|
28372
|
+
variantUrls: z120.array(z120.string().min(1)).max(MOTION_GRAPHICS_HOOK_VARIANTS_MAX - 1).optional().catch(void 0),
|
|
28002
28373
|
// Extra hook versions given back, as the task recorded it once the
|
|
28003
28374
|
// refunds landed (absent until then, and from an API before it).
|
|
28004
|
-
variantsRefunded:
|
|
28005
|
-
activity:
|
|
28006
|
-
previewUrl:
|
|
28375
|
+
variantsRefunded: z120.number().int().nonnegative().optional().catch(void 0),
|
|
28376
|
+
activity: z120.array(MotionGraphicsActivitySchema).optional().catch(void 0),
|
|
28377
|
+
previewUrl: z120.string().optional()
|
|
28007
28378
|
}).passthrough()
|
|
28008
28379
|
}).passthrough();
|
|
28009
28380
|
function parseAnimatedVideoResult(value) {
|
|
@@ -28306,10 +28677,10 @@ function registerAnimatedVideoTools(server, api) {
|
|
|
28306
28677
|
__name(registerAnimatedVideoTools, "registerAnimatedVideoTools");
|
|
28307
28678
|
|
|
28308
28679
|
// src/tools/winning-product-image.ts
|
|
28309
|
-
import { z as
|
|
28310
|
-
var WinnerReferenceInput =
|
|
28311
|
-
runId:
|
|
28312
|
-
candidateSourceId:
|
|
28680
|
+
import { z as z121 } from "zod";
|
|
28681
|
+
var WinnerReferenceInput = z121.object({
|
|
28682
|
+
runId: z121.string().uuid(),
|
|
28683
|
+
candidateSourceId: z121.string().trim().min(1).max(160)
|
|
28313
28684
|
}).strict().describe("Referencia opaca de un producto devuelto por find_winning_products/get_product_research_run.");
|
|
28314
28685
|
async function resolveWinnerImages(api, winnerReference, images) {
|
|
28315
28686
|
if (!winnerReference) return images;
|
|
@@ -28346,62 +28717,62 @@ var createProductTaskSingleOutputDescription = renderCreateProductTaskAvoidWhenF
|
|
|
28346
28717
|
var CREATE_SERVICE_VIDEO_ON_MCP = PRODUCTMAKER_MCP_CAPABILITY_NAMES.includes("create_service_video");
|
|
28347
28718
|
var listTasksGuidance = getProductMakerCapabilityModelGuidance("list_tasks");
|
|
28348
28719
|
var editTaskDraftGuidance = getProductMakerCapabilityModelGuidance("edit_task_draft");
|
|
28349
|
-
var CreateProductTaskInput =
|
|
28720
|
+
var CreateProductTaskInput = z122.object({
|
|
28350
28721
|
images: ImagesInput.optional().describe("1\u20135 fotos del mismo producto. Omitir \xFAnicamente cuando projectId apunta a un proyecto propio con imagen guardada."),
|
|
28351
28722
|
winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
|
|
28352
|
-
projectId:
|
|
28353
|
-
productUrl:
|
|
28723
|
+
projectId: z122.string().uuid().optional().describe("Opcional. Proyecto guiado propio. Permite continuar sin volver a subir la imagen guardada; nunca evita cr\xE9ditos, cuotas ni confirmaciones."),
|
|
28724
|
+
productUrl: z122.string().url().optional().describe("Opcional. URL de la p\xE1gina del producto (Shopify, AliExpress, Amazon, etc.) para enriquecer el contexto. Si se omite, la IA infiere todo desde la imagen."),
|
|
28354
28725
|
language: Lang.describe('C\xF3digo de idioma para el contenido generado. Ejemplos: "es", "en", "pt". REQUERIDO \u2014 si el usuario no lo especific\xF3, PREG\xDANTALE antes de invocar. NUNCA infieras desde el contexto del chat ni asumas "es" por default.'),
|
|
28355
28726
|
country: Country.describe('C\xF3digo ISO del pa\xEDs objetivo. Ejemplos: "CO", "MX", "US", "AR". Define moneda, m\xE9todos de pago locales y tono. REQUERIDO \u2014 si el usuario no lo especific\xF3, PREG\xDANTALE antes de invocar. NUNCA infieras desde el contexto del chat.'),
|
|
28356
|
-
price:
|
|
28357
|
-
compareAtPrice:
|
|
28358
|
-
offer:
|
|
28359
|
-
paymentMethods:
|
|
28360
|
-
productContext:
|
|
28361
|
-
productLabel:
|
|
28727
|
+
price: z122.string().min(1).max(120).optional().describe('Precio que se mostrar\xE1 en la landing y video. Formato libre \u2014 ej. "$89.900", "USD 29.99", "MXN 599". Opcional pero MUY IMPACTANTE: si el usuario no lo mencion\xF3, PREG\xDANTALE antes de invocar. Si te dice "t\xFA elige", om\xEDtelo y el backend sugiere uno.'),
|
|
28728
|
+
compareAtPrice: z122.string().min(1).max(120).optional().describe('Opcional. Precio anterior para comunicar un descuento real en landing e im\xE1genes. Ej. "$129.000" cuando price="$89.900".'),
|
|
28729
|
+
offer: z122.string().min(1).max(240).optional().describe('Oferta o promoci\xF3n a destacar. Ej. "2x1", "Env\xEDo gratis hoy", "50% OFF". Opcional pero MUY IMPACTANTE: si el usuario no lo mencion\xF3, PREG\xDANTALE antes de invocar (es v\xE1lido que diga "sin oferta"). Si te dice "t\xFA elige", om\xEDtelo.'),
|
|
28730
|
+
paymentMethods: z122.string().min(1).max(240).optional().describe('Opcional. M\xE9todos de pago que puede mostrar la landing. Ej. "Tarjeta, PSE, Nequi, Contraentrega". Si se omite, la landing no muestra m\xE9todos de pago.'),
|
|
28731
|
+
productContext: z122.string().max(PRODUCT_CONTEXT_MAX_CHARS).optional().describe("Opcional. Informacion adicional del producto que la IA debe usar como contexto prioritario: uso real, comprador, restricciones, diferenciadores o direccion creativa. No reemplaza la investigacion de competencia; si hay competencia, guia el primer angulo y los outputs no deben contradecirlo."),
|
|
28732
|
+
productLabel: z122.string().trim().max(80).optional().describe('Opcional. Qu\xE9 es el producto, en pocas palabras (ej. "quita pelusas para ropa"). Es AUTORITATIVO: si lo env\xEDas, la IA usa esta identidad y no la reemplaza por otra categor\xEDa. Si lo omites, la IA detecta el producto desde la imagen.'),
|
|
28362
28733
|
videoPreset: VideoPresetEnum.default("auto").describe('Opcional. Tipo/narrativa del video \u2014 \xFAnico campo de "estilo" que el usuario controla. Default "auto" (la IA escoge tras analizar el producto). Todos los presets funcionan a 15s (single_call) y 30s (Multiescena); "problem_solution" en single_call abre sin el producto y el producto entra por referencia en su beat de soluci\xF3n. Opciones: "auto", "ugc_dynamic" (review con experiencia y prueba), "ugc_how_to" (tutorial con pasos y resultado visible), "ugc_unboxing_chaos" (apertura y primera prueba), "problem_solution" (problema concreto, producto como soluci\xF3n y CTA), "product_showcase" (producto ejecutando una funci\xF3n real), "wearable_showcase" (prenda o accesorio modelado), "cinematic" (TV spot con receta cinematogr\xE1fica), "wild_card" (idea imposible: un truco visual que en la vida real no podr\xEDa pasar, y al cierre la invitaci\xF3n a comprar), "pixar_problem" (problema animado 3D), "pixar_sassy" (producto que habla). Si el usuario pide algo fuera de esta lista, p\xEDdele una opci\xF3n v\xE1lida.'),
|
|
28363
28734
|
animationStyle: AnimationStyleEnum.optional().describe('Opcional. Estilo visual SOLO para presets animados ("pixar_problem" o "pixar_sassy") \u2014 la API lo rechaza con cualquier otro preset. Opciones: "pixar_3d" (default, look 3D de pel\xEDcula animada), "claymation" (plastilina stop-motion artesanal), "wes_anderson" (tableau sim\xE9trico pastel), "sci_fi" (futurista con HUDs y ne\xF3n), "realista" (fotorrealista, fiel al producto). Si el usuario pide un look animado sin nombrar el estilo, omite el campo.'),
|
|
28364
|
-
durationSeconds:
|
|
28365
|
-
|
|
28366
|
-
|
|
28735
|
+
durationSeconds: z122.union([
|
|
28736
|
+
z122.literal(15),
|
|
28737
|
+
z122.literal(30)
|
|
28367
28738
|
]).default(15).describe("Opcional. Duraci\xF3n objetivo del video: 15s (single_call, default) o 30s (Multiescena, aproximadamente 30s y facturado por escena)."),
|
|
28368
|
-
pauseForAngleReview:
|
|
28369
|
-
aiDecidesAll:
|
|
28739
|
+
pauseForAngleReview: z122.boolean().optional().describe("Compatibilidad heredada. MCP deriva esta pausa de aiDecidesAll: manual siempre pausa y autom\xE1tico siempre la omite. No uses este campo para saltar reviews."),
|
|
28740
|
+
aiDecidesAll: z122.boolean().optional().describe("Mapea el toggle web \u201CDejar que la IA decida todo\u201D. Si true, ProductMaker omite reviews. Act\xEDvalo \xFAnicamente cuando el usuario lo pida expl\xEDcitamente. Omitido/false = reviews conversacionales."),
|
|
28370
28741
|
videoTier: VideoTierEnum.optional().describe('Opcional. Estilo del video. "basic" = "Realista" para 15s; al pedir durationSeconds=30 el sistema selecciona internamente Multiescena. No se expone el tier interno directamente.'),
|
|
28371
28742
|
videoStructure: VideoStructureEnum.default("single_take").describe('Opcional. Formato: "single_take" = Un solo clip (generado completo; puede incluir cambios de plano) o "multi_scene" = Multiescena. Default: single_take.'),
|
|
28372
28743
|
videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El proveedor se elige internamente. Default: economy.'),
|
|
28373
28744
|
videoResolution: VideoResolutionEnum.optional().describe('Opcional. Resoluci\xF3n del render. En la web se pregunta "\xBFResoluci\xF3n del video?". "480p" = excelente calidad y m\xE1s econ\xF3mico (RECOMENDADO, default si se omite); "720p" = m\xE1xima nitidez, entre 3% y 15% m\xE1s caro seg\xFAn formato y tier. Si el usuario no menciona resoluci\xF3n, OMITE este campo (el backend usa 480p).'),
|
|
28374
|
-
videoAngleCount:
|
|
28745
|
+
videoAngleCount: z122.number().int().min(1).max(3).optional().describe("Cantidad de videos a renderizar: 1, 2 o 3. REQUERIDO cuando outputs incluye video (o se omite outputs, cuyo default incluye video); om\xEDtelo s\xF3lo cuando no se generar\xE1 video. Preg\xFAntalo incluso con aiDecidesAll=true porque cambia el costo."),
|
|
28375
28746
|
angleNarratives: PublicNarrativeStyleEnum.array().max(3).optional().describe('Opcional. Narrativa POR \xC1NGULO (posicional). Valores actuales: "review", "ugc_how_to", "ugc_unboxing_chaos", "problem_product_cta" (problema concreto, producto como soluci\xF3n y CTA), "product_showcase", "wearable_showcase", "cinematic", "wild_card", "animated_problem_pixar", "sassy_product_pixar", "market" (narrativa an\xE1lisis de mercado: adapta el video a los patrones ganadores estudiados de la competencia; requiere competitorScanEnabled: true). angleNarratives[i] fuerza la narrativa del \xE1ngulo i; las posiciones restantes las elige la IA. La lista no puede superar videoAngleCount.'),
|
|
28376
|
-
outputs:
|
|
28747
|
+
outputs: z122.array(z122.enum([
|
|
28377
28748
|
"landing",
|
|
28378
28749
|
"video",
|
|
28379
28750
|
"image"
|
|
28380
28751
|
])).min(1).max(3).optional().describe(`Opcional. Qu\xE9 outputs generar. Default: todos ["landing","video","image"]. Para 2 outputs: ["landing","image"] (sin video), ["video","image"] (sin landing), ["landing","video"] (sin imagen). ${createProductTaskSingleOutputDescription}`),
|
|
28381
|
-
includeInitialLandingGif:
|
|
28382
|
-
competitorScanEnabled:
|
|
28752
|
+
includeInitialLandingGif: z122.boolean().optional().describe("Opcional. En nuevas landings cl\xE1sicas habilitadas, omitirlo incluye el primer GIF del producto y su coste en el total. Env\xEDa false si el usuario lo excluye: no se genera ni se reserva su coste. Conserva la elecci\xF3n al confirmar y al reintentar."),
|
|
28753
|
+
competitorScanEnabled: z122.boolean().optional().describe("Opcional. Default false: omitirlo significa SIN estudio de mercado. Antes de crear, llama estimate_market_study_cost con kind=product_task, muestra al usuario el costo con y sin estudio y preg\xFAntale si lo quiere; env\xEDa true solo si lo acepta (o si solicita la narrativa an\xE1lisis de mercado). Si la tarea incluye video, true analiza anuncios de la competencia y desbloquea la narrativa an\xE1lisis de mercado; si el estudio no encuentra datos suficientes, degrada al planner cl\xE1sico."),
|
|
28383
28754
|
generateAiEdit: AiEditRequestSchema.optional().describe('Opcional. Pide la Edici\xF3n con IA: una pasada que a\xF1ade texto, efectos y m\xFAsica sobre cada video entregado (variante with_ai_edit; se cobra al entregar, por video). Nivel: "economy" (Econ\xF3mica, Sonnet 5.5, m\xE1s barata) o "pro" (Opus 5.5, mejor calidad, ~10 min). true equivale a "pro"; false/omitido = sin edici\xF3n.'),
|
|
28384
|
-
replicateWinnerWhenFound:
|
|
28385
|
-
brandId:
|
|
28386
|
-
actorId:
|
|
28755
|
+
replicateWinnerWhenFound: z122.boolean().optional().describe("Conserva la preferencia de copiar un ganador si existe. false estudia el mercado sin reemplazar un \xE1ngulo por el anuncio ganador. No a\xF1ade una pregunta obligatoria."),
|
|
28756
|
+
brandId: z122.string().uuid().optional().describe("Opcional. ID de una marca del usuario; si se env\xEDa, el sistema usa su voz, colores y persona para enriquecer los outputs generados."),
|
|
28757
|
+
actorId: z122.string().trim().min(1).max(120).optional().describe("Opcional. ID de un personaje guardado (usa list_actors para verlos). Si lo env\xEDas, su foto y su voz mandan sobre la descripci\xF3n de texto."),
|
|
28387
28758
|
creativeGender: CreativeGenderEnum.optional().describe('Opcional. QUI\xC9N APARECE EN PANTALLA en todos los creativos de la task: el presentador del video, las personas fotografiadas en la landing y la persona del anuncio. NO es la voz. M\xE1ndalo en cuanto el usuario lo diga en cualquier momento de la conversaci\xF3n y con cualquier redacci\xF3n ("quiero una mujer", "que salga un hombre", "esto es para hombres"): si no lo mandas, el g\xE9nero lo inventa la IA y el usuario recibe lo contrario de lo que pidi\xF3 sin ning\xFAn aviso. "mixed" solo cuando pida expl\xEDcitamente ambos. Si adem\xE1s mandas actorId, el personaje guardado manda sobre este campo.'),
|
|
28388
|
-
creativeDirection:
|
|
28389
|
-
headline:
|
|
28390
|
-
subheadline:
|
|
28759
|
+
creativeDirection: z122.string().max(500).optional().describe('Opcional. Direcci\xF3n creativa en texto libre (colores, mood, estilo) que aplica a los outputs de IMAGEN y LANDING (no al video \u2014 el estilo/ambiente del video se dirige con scriptNotes). M\xC1XIMA PRIORIDAD: anula marca, colores y estilo por defecto. Ej. "amarillo y azul, minimalista". M\xE1x 500 caracteres.'),
|
|
28760
|
+
headline: z122.string().max(120).optional().describe("Opcional. Titular EXACTO a renderizar. Se imprime tal cual: la IA no lo reescribe, no lo acorta y no lo traduce. Se aplica a las IM\xC1GENES y a la portada de la landing de esta task (el video no lo usa; para el video usa scriptNotes). \xDAsalo cuando el copy es de marca y no es negociable. M\xE1x 120 caracteres. Si lo omites, la IA escribe el titular."),
|
|
28761
|
+
subheadline: z122.string().max(160).optional().describe("Opcional. Subt\xEDtulo EXACTO a renderizar, misma regla que headline. Independiente: puedes fijar solo el subt\xEDtulo. M\xE1x 160 caracteres."),
|
|
28391
28762
|
landingStrategy: LandingStrategyEnum.optional().describe('Opcional. Estructura de la landing cl\xE1sica cuando landing est\xE1 entre outputs: "classic" (estructura original probada y recomendada; default del primer rollout), "auto" (la IA decide; experimental), "pain_solution", "social_proof" (Landing Viral: UGC, WhatsApp, Instagram y evidencia social), "benefits_clarity", "offer_value" o "lifestyle_identity". Default "classic".'),
|
|
28392
28763
|
landingImageFormat: LandingImageFormatEnum.default("9:16").describe('Opcional. Formato/relaci\xF3n de aspecto de las im\xE1genes de la landing cl\xE1sica cuando landing est\xE1 entre outputs: "9:16" (vertical, por defecto), "4:5" (vertical compacto para feed) o "1:1" (cuadrado). Default "9:16".')
|
|
28393
28764
|
}).strict();
|
|
28394
|
-
var CreateServiceVideoInput =
|
|
28395
|
-
landingUrl:
|
|
28396
|
-
additionalContext:
|
|
28765
|
+
var CreateServiceVideoInput = z122.object({
|
|
28766
|
+
landingUrl: z122.string().url().describe("URL p\xFAblica de la landing del servicio. Es suficiente para generar el video; los medios son opcionales en la web."),
|
|
28767
|
+
additionalContext: z122.string().max(3e3).optional().describe('Instrucci\xF3n natural prioritaria. Ej.: "adapta el ritmo de estos competidores", "enfatiza reservas de demos" o restricciones de claims.'),
|
|
28397
28768
|
language: Lang.describe("Idioma del video: es, en o pt."),
|
|
28398
|
-
voiceId:
|
|
28399
|
-
brandId:
|
|
28400
|
-
reviewMode:
|
|
28769
|
+
voiceId: z122.string().trim().min(1).pipe(VoiceId).optional().describe('Opcional. Voz para toda la narraci\xF3n. Usa "auto" para que la IA la alinee con el presentador. Las voces del banco compartido fueron retiradas.'),
|
|
28770
|
+
brandId: z122.string().uuid().optional().describe("Marca guardada del usuario. Aplica voz, mensajes, paleta y persona predeterminada."),
|
|
28771
|
+
reviewMode: z122.enum([
|
|
28401
28772
|
"automatic",
|
|
28402
28773
|
"guided"
|
|
28403
28774
|
]).default("automatic").describe("automatic = la IA elige concepto y guion sin pausas; guided = el usuario aprueba concepto y storyboard."),
|
|
28404
|
-
videoPreset:
|
|
28775
|
+
videoPreset: z122.enum([
|
|
28405
28776
|
"auto",
|
|
28406
28777
|
"ugc_dynamic",
|
|
28407
28778
|
"ugc_how_to",
|
|
@@ -28411,128 +28782,128 @@ var CreateServiceVideoInput = z121.object({
|
|
|
28411
28782
|
videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El proveedor se elige internamente. Default: economy.'),
|
|
28412
28783
|
videoResolution: VideoResolutionEnum.default("480p").describe('Opcional. Resoluci\xF3n: "480p" o "720p". 720p cuesta m\xE1s por segundo y solo est\xE1 disponible en "economy" y "pro" (Medio = 768P). Default: 480p.')
|
|
28413
28784
|
}).strict();
|
|
28414
|
-
var GetTaskStatusInput =
|
|
28415
|
-
taskId:
|
|
28416
|
-
waitSeconds:
|
|
28785
|
+
var GetTaskStatusInput = z122.object({
|
|
28786
|
+
taskId: z122.string().min(1),
|
|
28787
|
+
waitSeconds: z122.number().int().min(0).max(120).optional()
|
|
28417
28788
|
});
|
|
28418
|
-
var ListTasksInput =
|
|
28419
|
-
limit:
|
|
28420
|
-
offset:
|
|
28421
|
-
search:
|
|
28789
|
+
var ListTasksInput = z122.object({
|
|
28790
|
+
limit: z122.number().int().min(1).max(50).optional(),
|
|
28791
|
+
offset: z122.number().int().min(0).optional(),
|
|
28792
|
+
search: z122.string().optional()
|
|
28422
28793
|
});
|
|
28423
28794
|
var MCP_REVIEW_LIST_FIELD_MAX = IMAGE_WIZARD_LIST_FIELD_MAX;
|
|
28424
28795
|
var MCP_REVIEW_FEATURE_ITEM_MAX = IMAGE_FEATURE_ITEM_MAX;
|
|
28425
|
-
var EditTaskDraftInput =
|
|
28426
|
-
taskId:
|
|
28427
|
-
angleIndex:
|
|
28428
|
-
angle:
|
|
28429
|
-
angle:
|
|
28430
|
-
buyerPersona:
|
|
28431
|
-
actor:
|
|
28432
|
-
actorId:
|
|
28433
|
-
gender:
|
|
28796
|
+
var EditTaskDraftInput = z122.object({
|
|
28797
|
+
taskId: z122.string().min(1),
|
|
28798
|
+
angleIndex: z122.number().int().min(0),
|
|
28799
|
+
angle: z122.object({
|
|
28800
|
+
angle: z122.string().min(1).max(480),
|
|
28801
|
+
buyerPersona: z122.string().min(1).max(360),
|
|
28802
|
+
actor: z122.string().min(1).max(360).optional(),
|
|
28803
|
+
actorId: z122.string().trim().min(1).optional().describe("Opcional. ID de un personaje guardado (usa list_actors para verlos). Si lo env\xEDas, su foto y su voz mandan sobre la descripci\xF3n de texto."),
|
|
28804
|
+
gender: z122.enum([
|
|
28434
28805
|
"female",
|
|
28435
28806
|
"male"
|
|
28436
28807
|
]).optional(),
|
|
28437
|
-
scriptNotes:
|
|
28808
|
+
scriptNotes: z122.string().max(2e3).optional()
|
|
28438
28809
|
})
|
|
28439
28810
|
});
|
|
28440
|
-
var PendingActionPayload =
|
|
28441
|
-
|
|
28442
|
-
kind:
|
|
28811
|
+
var PendingActionPayload = z122.discriminatedUnion("kind", [
|
|
28812
|
+
z122.object({
|
|
28813
|
+
kind: z122.literal("product_reference_set_approval"),
|
|
28443
28814
|
scope: ProductReferenceScopeEnum.optional(),
|
|
28444
|
-
scopeKey:
|
|
28445
|
-
scopeSnapshotId:
|
|
28446
|
-
expectedScopeHash:
|
|
28815
|
+
scopeKey: z122.string().min(1).max(120).optional(),
|
|
28816
|
+
scopeSnapshotId: z122.string().uuid().optional(),
|
|
28817
|
+
expectedScopeHash: z122.string().min(1).max(128).optional(),
|
|
28447
28818
|
decision: ProductReferenceResolutionDecisionEnum,
|
|
28448
28819
|
reason: ProductReferenceRejectionReasonEnum.optional(),
|
|
28449
|
-
affectedRefKeys:
|
|
28450
|
-
affectedPhotoNumbers:
|
|
28451
|
-
recoveryAction:
|
|
28820
|
+
affectedRefKeys: z122.array(z122.string().min(1).max(200)).min(1).optional(),
|
|
28821
|
+
affectedPhotoNumbers: z122.array(z122.number().int().positive()).min(1).optional(),
|
|
28822
|
+
recoveryAction: z122.enum([
|
|
28452
28823
|
"remove",
|
|
28453
28824
|
"replace",
|
|
28454
28825
|
"upload",
|
|
28455
28826
|
"return_to_selection"
|
|
28456
28827
|
]).optional()
|
|
28457
28828
|
}),
|
|
28458
|
-
|
|
28459
|
-
kind:
|
|
28460
|
-
selectedPhotoNumbers:
|
|
28829
|
+
z122.object({
|
|
28830
|
+
kind: z122.literal("product_reference_confirmation"),
|
|
28831
|
+
selectedPhotoNumbers: z122.array(z122.number().int().positive().max(5)).min(1).max(5).optional().describe("Opcional. N\xFAmeros visibles de las fotos que el usuario quiere conservar; las dem\xE1s se deseleccionan. Debe quedar al menos una."),
|
|
28461
28832
|
userChoice: ProductReferenceUserChoiceEnum.optional(),
|
|
28462
|
-
confirmedProductNames:
|
|
28833
|
+
confirmedProductNames: z122.array(z122.string().min(1).max(120)).min(2).max(8).optional(),
|
|
28463
28834
|
videoStructure: VideoStructureEnum.optional().describe("Opcional. Formato para reanudar el video: single_take (Un solo clip, generado completo; puede incluir cambios de plano) o multi_scene (Multiescena). El backend vuelve a validar que sea compatible con el agrupamiento confirmado."),
|
|
28464
28835
|
videoQuality: VideoQualityEnum.optional().describe("Opcional. Calidad para reanudar el video: economy (Econ\xF3mico), medium (Medio) o pro. El proveedor se elige internamente y el backend vuelve a cotizar la ruta."),
|
|
28465
|
-
useMultiSceneShowcase:
|
|
28836
|
+
useMultiSceneShowcase: z122.boolean().optional().describe("Compatibilidad con confirmaciones antiguas: si es true junto con userChoice=variants, conserva el showcase multiescena.")
|
|
28466
28837
|
}),
|
|
28467
|
-
|
|
28468
|
-
kind:
|
|
28838
|
+
z122.object({
|
|
28839
|
+
kind: z122.literal("angle_review_approval"),
|
|
28469
28840
|
// All edits are optional — empty action body just approves the
|
|
28470
28841
|
// backend-generated draft as-is. Field shapes mirror the angle-review
|
|
28471
28842
|
// request contracts in @packages/types/wizard.ts; the handler routes to
|
|
28472
28843
|
// the dedicated video/image/autopilot endpoint based on StatusResponse.kind.
|
|
28473
|
-
customAngle:
|
|
28844
|
+
customAngle: z122.string().min(1).max(480).optional(),
|
|
28474
28845
|
// Keep the shared MCP action within the strictest downstream contract:
|
|
28475
28846
|
// autopilot/image resume endpoints cap these fields at 1500 characters.
|
|
28476
|
-
painPoints:
|
|
28477
|
-
benefits:
|
|
28847
|
+
painPoints: z122.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
|
|
28848
|
+
benefits: z122.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
|
|
28478
28849
|
// Same policy as the two fields above: the strictest downstream contract
|
|
28479
28850
|
// wins. The image endpoint caps each feature at 240 while landing/video
|
|
28480
28851
|
// accept 300, and this single action routes to whichever the task is — so
|
|
28481
28852
|
// accepting 300 here turns a 250-character feature on an image task into
|
|
28482
28853
|
// an opaque HTTP 400 after the model already believed it had been saved.
|
|
28483
|
-
features:
|
|
28484
|
-
buyerPersona:
|
|
28854
|
+
features: z122.array(z122.string().min(1).max(MCP_REVIEW_FEATURE_ITEM_MAX)).max(10).optional(),
|
|
28855
|
+
buyerPersona: z122.string().min(1).max(360).optional(),
|
|
28485
28856
|
narrativeStyle: PublicNarrativeStyleEnum.optional().describe('Narrativa del video. "problem_product_cta" (Problema y Soluci\xF3n) funciona en ambos formatos \u2014 en Un solo clip abre sin producto y el producto entra por referencia en su beat. La familia storyteller ("animated_storyteller", "animated_inner_journey", "animated_object_soul", "animated_timeline") no est\xE1 disponible por ahora.'),
|
|
28486
|
-
actor:
|
|
28487
|
-
actorId:
|
|
28488
|
-
creativeDirection:
|
|
28489
|
-
selectedAngleNumbers:
|
|
28490
|
-
angleEdits:
|
|
28491
|
-
angleNumber:
|
|
28492
|
-
narrativeSelection:
|
|
28857
|
+
actor: z122.string().min(1).max(360).optional().describe("Nueva descripci\xF3n del presentador. Al enviarla sin actorId, se elimina autom\xE1ticamente cualquier actor guardado previo de esos \xE1ngulos."),
|
|
28858
|
+
actorId: z122.string().max(120).nullable().optional(),
|
|
28859
|
+
creativeDirection: z122.string().max(2e3).optional(),
|
|
28860
|
+
selectedAngleNumbers: z122.array(z122.number().int().positive()).min(1).max(3).optional().describe("N\xFAmeros visibles (1-based) de los \xE1ngulos que el usuario quiere renderizar. Deben ser \xFAnicos, existir en la review y no superar el videoAngleCount autorizado."),
|
|
28861
|
+
angleEdits: z122.array(z122.object({
|
|
28862
|
+
angleNumber: z122.number().int().positive(),
|
|
28863
|
+
narrativeSelection: z122.enum([
|
|
28493
28864
|
"market",
|
|
28494
28865
|
"guided"
|
|
28495
28866
|
]).optional().describe("Elecci\xF3n expl\xEDcita: market usa el estudio disponible; guided usa la narrativa elegida para este \xE1ngulo."),
|
|
28496
|
-
angle:
|
|
28497
|
-
buyerPersona:
|
|
28867
|
+
angle: z122.string().min(1).max(480).optional(),
|
|
28868
|
+
buyerPersona: z122.string().min(1).max(360).optional(),
|
|
28498
28869
|
narrativeStyle: PublicNarrativeStyleEnum.optional().describe('Narrativa del video. "problem_product_cta" (Problema y Soluci\xF3n) funciona en ambos formatos \u2014 en Un solo clip abre sin producto y el producto entra por referencia en su beat. La familia storyteller ("animated_storyteller", "animated_inner_journey", "animated_object_soul", "animated_timeline") no est\xE1 disponible por ahora.'),
|
|
28499
|
-
actor:
|
|
28500
|
-
actorId:
|
|
28501
|
-
creativeDirection:
|
|
28870
|
+
actor: z122.string().min(1).max(360).optional(),
|
|
28871
|
+
actorId: z122.string().max(120).nullable().optional(),
|
|
28872
|
+
creativeDirection: z122.string().max(2e3).optional()
|
|
28502
28873
|
}).strict()).max(3).optional().describe("Ediciones independientes por n\xFAmero visible de \xE1ngulo. S\xF3lo se aceptan para \xE1ngulos incluidos en selectedAngleNumbers (o en la selecci\xF3n por defecto)."),
|
|
28503
|
-
gapDurationSeconds:
|
|
28504
|
-
|
|
28505
|
-
|
|
28874
|
+
gapDurationSeconds: z122.union([
|
|
28875
|
+
z122.literal(15),
|
|
28876
|
+
z122.literal(30)
|
|
28506
28877
|
]).optional().describe("Opcional. Solo para aceptar expl\xEDcitamente la recomendaci\xF3n gapDurationChoice del status. 30 env\xEDa el override double_30s para el \xE1ngulo recomendado; 15 u omitido conserva la duraci\xF3n cotizada.")
|
|
28507
28878
|
}),
|
|
28508
|
-
|
|
28509
|
-
kind:
|
|
28510
|
-
angleId:
|
|
28511
|
-
angleNumber:
|
|
28512
|
-
content:
|
|
28513
|
-
creativeDirection:
|
|
28514
|
-
actor:
|
|
28879
|
+
z122.object({
|
|
28880
|
+
kind: z122.literal("service_angle_approval"),
|
|
28881
|
+
angleId: z122.string().uuid().optional(),
|
|
28882
|
+
angleNumber: z122.number().int().positive().optional(),
|
|
28883
|
+
content: z122.string().min(1).max(480).optional(),
|
|
28884
|
+
creativeDirection: z122.string().min(1).max(1500).optional(),
|
|
28885
|
+
actor: z122.string().min(1).max(360).optional()
|
|
28515
28886
|
}),
|
|
28516
|
-
|
|
28517
|
-
kind:
|
|
28518
|
-
voiceovers:
|
|
28519
|
-
visualDirections:
|
|
28520
|
-
voiceoversByScene:
|
|
28521
|
-
visualDirectionsByScene:
|
|
28887
|
+
z122.object({
|
|
28888
|
+
kind: z122.literal("service_script_approval"),
|
|
28889
|
+
voiceovers: z122.record(z122.string(), z122.string().min(1).max(600)).optional(),
|
|
28890
|
+
visualDirections: z122.record(z122.string(), z122.string().min(1).max(1200)).optional(),
|
|
28891
|
+
voiceoversByScene: z122.record(z122.string(), z122.string().min(1).max(600)).optional(),
|
|
28892
|
+
visualDirectionsByScene: z122.record(z122.string(), z122.string().min(1).max(1200)).optional()
|
|
28522
28893
|
})
|
|
28523
28894
|
]);
|
|
28524
|
-
var ResolvePendingActionInput =
|
|
28525
|
-
taskId:
|
|
28895
|
+
var ResolvePendingActionInput = z122.object({
|
|
28896
|
+
taskId: z122.string().min(1),
|
|
28526
28897
|
action: PendingActionPayload
|
|
28527
28898
|
}).strict();
|
|
28528
28899
|
function resolveVariantConfirmVideoTier(action) {
|
|
28529
28900
|
return action.useMultiSceneShowcase && action.userChoice === "variants" ? "standard" : void 0;
|
|
28530
28901
|
}
|
|
28531
28902
|
__name(resolveVariantConfirmVideoTier, "resolveVariantConfirmVideoTier");
|
|
28532
|
-
var StatusForResolveSchema =
|
|
28903
|
+
var StatusForResolveSchema = z122.object({
|
|
28533
28904
|
// Metadata used to select the backend resume contract. Older API responses
|
|
28534
28905
|
// may omit these fields, so the resolver keeps the generic fallback.
|
|
28535
|
-
kind:
|
|
28906
|
+
kind: z122.enum([
|
|
28536
28907
|
"autopilot",
|
|
28537
28908
|
"video",
|
|
28538
28909
|
"image",
|
|
@@ -28540,18 +28911,18 @@ var StatusForResolveSchema = z121.object({
|
|
|
28540
28911
|
"mix",
|
|
28541
28912
|
"service"
|
|
28542
28913
|
]).optional(),
|
|
28543
|
-
selectedOutputs:
|
|
28914
|
+
selectedOutputs: z122.array(z122.enum([
|
|
28544
28915
|
"landing",
|
|
28545
28916
|
"video",
|
|
28546
28917
|
"image"
|
|
28547
28918
|
])).optional(),
|
|
28548
|
-
videoAngleCount:
|
|
28549
|
-
ugcFormat:
|
|
28919
|
+
videoAngleCount: z122.number().int().min(1).max(3).optional(),
|
|
28920
|
+
ugcFormat: z122.enum([
|
|
28550
28921
|
"single_8s",
|
|
28551
28922
|
"single_15s",
|
|
28552
28923
|
"double_30s"
|
|
28553
28924
|
]).optional(),
|
|
28554
|
-
videoStyle:
|
|
28925
|
+
videoStyle: z122.enum([
|
|
28555
28926
|
"ugc",
|
|
28556
28927
|
"cartoon_3d",
|
|
28557
28928
|
"product_only",
|
|
@@ -28561,13 +28932,13 @@ var StatusForResolveSchema = z121.object({
|
|
|
28561
28932
|
videoQuality: VideoQualityEnum.optional(),
|
|
28562
28933
|
videoRouteId: VideoRouteIdEnum.optional(),
|
|
28563
28934
|
videoModel: TaskVideoModelEnum.optional(),
|
|
28564
|
-
videoTier:
|
|
28935
|
+
videoTier: z122.enum([
|
|
28565
28936
|
"legacy",
|
|
28566
28937
|
"standard",
|
|
28567
28938
|
"pro",
|
|
28568
28939
|
"single_call"
|
|
28569
28940
|
]).optional(),
|
|
28570
|
-
videoResolution:
|
|
28941
|
+
videoResolution: z122.enum([
|
|
28571
28942
|
"480p",
|
|
28572
28943
|
"720p"
|
|
28573
28944
|
]).optional(),
|
|
@@ -28575,60 +28946,60 @@ var StatusForResolveSchema = z121.object({
|
|
|
28575
28946
|
// A task created before a narrative was blocked/hidden must still parse,
|
|
28576
28947
|
// or resolve_pending_action could never approve it.
|
|
28577
28948
|
narrativeStyle: NarrativeStyle.optional(),
|
|
28578
|
-
pauseForVideoScriptReview:
|
|
28579
|
-
pendingUserAction:
|
|
28580
|
-
kind:
|
|
28581
|
-
candidateGrouping:
|
|
28582
|
-
selectedImageUrls:
|
|
28583
|
-
proposedProductNames:
|
|
28949
|
+
pauseForVideoScriptReview: z122.boolean().optional(),
|
|
28950
|
+
pendingUserAction: z122.object({
|
|
28951
|
+
kind: z122.string(),
|
|
28952
|
+
candidateGrouping: z122.string().optional(),
|
|
28953
|
+
selectedImageUrls: z122.array(z122.string()).optional(),
|
|
28954
|
+
proposedProductNames: z122.array(z122.string()).optional(),
|
|
28584
28955
|
// Adaptive reference questions are server-owned. Echo only the evidence
|
|
28585
28956
|
// identity and the choices shown by the current snapshot; never accept a
|
|
28586
28957
|
// client-supplied reference set as authorization.
|
|
28587
|
-
options:
|
|
28588
|
-
mode:
|
|
28958
|
+
options: z122.array(ProductReferenceUserChoiceEnum).max(4).optional(),
|
|
28959
|
+
mode: z122.enum([
|
|
28589
28960
|
"question",
|
|
28590
28961
|
"visual_recovery"
|
|
28591
28962
|
]).optional(),
|
|
28592
28963
|
/** Hand-mirrored from packages/types result.ts — see CLAUDE.md § MCP Server Sync. */
|
|
28593
|
-
canKeepSelection:
|
|
28594
|
-
decisionKey:
|
|
28595
|
-
questionOrdinal:
|
|
28596
|
-
questionCeiling:
|
|
28597
|
-
|
|
28598
|
-
|
|
28964
|
+
canKeepSelection: z122.boolean().optional(),
|
|
28965
|
+
decisionKey: z122.string().optional(),
|
|
28966
|
+
questionOrdinal: z122.number().int().min(1).max(5).optional(),
|
|
28967
|
+
questionCeiling: z122.union([
|
|
28968
|
+
z122.literal(3),
|
|
28969
|
+
z122.literal(5)
|
|
28599
28970
|
]).optional(),
|
|
28600
|
-
referenceEvidenceVersion:
|
|
28601
|
-
expectedEvidenceHash:
|
|
28602
|
-
question:
|
|
28603
|
-
prompt:
|
|
28604
|
-
helpText:
|
|
28605
|
-
options:
|
|
28971
|
+
referenceEvidenceVersion: z122.number().int().positive().optional(),
|
|
28972
|
+
expectedEvidenceHash: z122.string().optional(),
|
|
28973
|
+
question: z122.object({
|
|
28974
|
+
prompt: z122.string().min(1).max(240),
|
|
28975
|
+
helpText: z122.string().min(1).max(300).optional(),
|
|
28976
|
+
options: z122.array(z122.object({
|
|
28606
28977
|
value: ProductReferenceUserChoiceEnum,
|
|
28607
|
-
label:
|
|
28608
|
-
description:
|
|
28978
|
+
label: z122.string().min(1).max(120),
|
|
28979
|
+
description: z122.string().min(1).max(240).optional()
|
|
28609
28980
|
})).min(2).max(4)
|
|
28610
28981
|
}).optional(),
|
|
28611
28982
|
scope: ProductReferenceScopeEnum.optional(),
|
|
28612
|
-
scopeKey:
|
|
28613
|
-
scopeSnapshotId:
|
|
28614
|
-
scopeHash:
|
|
28615
|
-
baseReferenceSetHash:
|
|
28616
|
-
phase:
|
|
28983
|
+
scopeKey: z122.string().optional(),
|
|
28984
|
+
scopeSnapshotId: z122.string().uuid().optional(),
|
|
28985
|
+
scopeHash: z122.string().optional(),
|
|
28986
|
+
baseReferenceSetHash: z122.string().optional(),
|
|
28987
|
+
phase: z122.enum([
|
|
28617
28988
|
"preparation",
|
|
28618
28989
|
"final"
|
|
28619
28990
|
]).optional(),
|
|
28620
|
-
selectedRefKeys:
|
|
28621
|
-
allowedDecisions:
|
|
28622
|
-
previews:
|
|
28623
|
-
refKey:
|
|
28991
|
+
selectedRefKeys: z122.array(z122.string().min(1).max(200)).optional(),
|
|
28992
|
+
allowedDecisions: z122.array(ProductReferenceResolutionDecisionEnum).optional(),
|
|
28993
|
+
previews: z122.array(z122.object({
|
|
28994
|
+
refKey: z122.string().min(1).max(200)
|
|
28624
28995
|
}).passthrough()).optional(),
|
|
28625
|
-
customAngleDraft:
|
|
28626
|
-
painPointsDraft:
|
|
28627
|
-
benefitsDraft:
|
|
28628
|
-
featuresDraft:
|
|
28629
|
-
angleOptions:
|
|
28630
|
-
index:
|
|
28631
|
-
angle:
|
|
28996
|
+
customAngleDraft: z122.string().optional(),
|
|
28997
|
+
painPointsDraft: z122.string().optional(),
|
|
28998
|
+
benefitsDraft: z122.string().optional(),
|
|
28999
|
+
featuresDraft: z122.array(z122.string()).optional(),
|
|
29000
|
+
angleOptions: z122.array(z122.object({
|
|
29001
|
+
index: z122.number().int().nonnegative(),
|
|
29002
|
+
angle: z122.string().min(1)
|
|
28632
29003
|
}).passthrough()).min(1).max(5).optional(),
|
|
28633
29004
|
// Recommendation consumed only when the caller explicitly sends
|
|
28634
29005
|
// gapDurationSeconds: 30 in the angle approval action.
|
|
@@ -28638,17 +29009,17 @@ var StatusForResolveSchema = z121.object({
|
|
|
28638
29009
|
// keys. `actorId` (the saved custom actor the picker stored) was silently
|
|
28639
29010
|
// dropped here, so the approval handler below could not echo it back on the
|
|
28640
29011
|
// PATCH — the selection looked accepted and reached no render.
|
|
28641
|
-
angles:
|
|
28642
|
-
id:
|
|
28643
|
-
content:
|
|
28644
|
-
creativeDirection:
|
|
28645
|
-
actor:
|
|
28646
|
-
actorId:
|
|
29012
|
+
angles: z122.array(z122.object({
|
|
29013
|
+
id: z122.string().uuid(),
|
|
29014
|
+
content: z122.string(),
|
|
29015
|
+
creativeDirection: z122.string(),
|
|
29016
|
+
actor: z122.string(),
|
|
29017
|
+
actorId: z122.string().nullable().optional()
|
|
28647
29018
|
}).passthrough()).optional(),
|
|
28648
|
-
panels:
|
|
28649
|
-
beatId:
|
|
28650
|
-
voiceover:
|
|
28651
|
-
visualDirection:
|
|
29019
|
+
panels: z122.array(z122.object({
|
|
29020
|
+
beatId: z122.string(),
|
|
29021
|
+
voiceover: z122.string(),
|
|
29022
|
+
visualDirection: z122.string()
|
|
28652
29023
|
}).passthrough()).optional()
|
|
28653
29024
|
}).optional()
|
|
28654
29025
|
}).passthrough();
|
|
@@ -29001,8 +29372,8 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
|
|
|
29001
29372
|
server.registerTool("verify_landing_commerce", {
|
|
29002
29373
|
description: getProductMakerCapabilityModelGuidance("verify_landing_commerce").summary + " Verifica una correcci\xF3n manual de precios, tachados o packs de una landing editable existente. Solo relee Shopify y los recibos externos; no cambia precios, inventario, SKU ni compra una edici\xF3n. Pasa taskId y editId de la edici\xF3n ya conocida; nunca inventes IDs ni pidas repetir el cambio. Devuelve el estado can\xF3nico por proveedor: conserva el aviso pendiente hasta confirmar los valores reales. Solo despu\xE9s de confirmar todos los valores, el servidor puede volver a habilitar la compra. Web guardada no demuestra publicaci\xF3n p\xFAblica ni checkout; muestra las correcciones y enlaces pendientes sin c\xF3digos t\xE9cnicos. La disponibilidad del editor conserva sus permisos actuales.",
|
|
29003
29374
|
inputSchema: {
|
|
29004
|
-
taskId:
|
|
29005
|
-
editId:
|
|
29375
|
+
taskId: z122.string().uuid(),
|
|
29376
|
+
editId: z122.string().uuid()
|
|
29006
29377
|
},
|
|
29007
29378
|
annotations: OVERWRITES_EXTERNAL
|
|
29008
29379
|
}, async (input) => {
|
|
@@ -29193,16 +29564,16 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
|
|
|
29193
29564
|
if (input.search) qs.set("search", input.search);
|
|
29194
29565
|
const path3 = `/v1/tasks${qs.toString() ? "?" + qs.toString() : ""}`;
|
|
29195
29566
|
const r = await api.getJson(path3);
|
|
29196
|
-
const page =
|
|
29197
|
-
items:
|
|
29567
|
+
const page = z122.object({
|
|
29568
|
+
items: z122.array(z122.unknown())
|
|
29198
29569
|
}).passthrough().safeParse(r);
|
|
29199
29570
|
if (!page.success) return asText(r);
|
|
29200
29571
|
return asText({
|
|
29201
29572
|
...page.data,
|
|
29202
29573
|
items: page.data.items.map((item) => {
|
|
29203
|
-
const servicePage =
|
|
29204
|
-
taskId:
|
|
29205
|
-
resourceType:
|
|
29574
|
+
const servicePage = z122.object({
|
|
29575
|
+
taskId: z122.string().uuid(),
|
|
29576
|
+
resourceType: z122.literal("service_page")
|
|
29206
29577
|
}).passthrough().safeParse(item);
|
|
29207
29578
|
if (!servicePage.success) return item;
|
|
29208
29579
|
return {
|
|
@@ -29524,13 +29895,34 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
|
|
|
29524
29895
|
if (isVideoTask) {
|
|
29525
29896
|
body.selectedAngleIndices = selectedAngleIndices;
|
|
29526
29897
|
const r2 = await api.postJson(`/v1/tasks/${encodeURIComponent(input.taskId)}/approve-video-angles`, body);
|
|
29898
|
+
const angleKeys = r2.approvedAngleKeys;
|
|
29899
|
+
const hasCanonicalKeys = r2.success === true && Array.isArray(angleKeys) && angleKeys.length === selectedAngleIndices.length && angleKeys.length > 0 && angleKeys.every((key) => typeof key === "string" && /^angle_\d+$/.test(key)) && new Set(angleKeys).size === angleKeys.length;
|
|
29527
29900
|
return asText({
|
|
29528
29901
|
...r2,
|
|
29529
29902
|
...status.pauseForVideoScriptReview === true ? {
|
|
29530
|
-
reviewNextAction: {
|
|
29903
|
+
reviewNextAction: hasCanonicalKeys ? {
|
|
29531
29904
|
kind: "poll_video_script",
|
|
29532
29905
|
tool: "get_video_script",
|
|
29533
|
-
|
|
29906
|
+
arguments: {
|
|
29907
|
+
taskId: input.taskId,
|
|
29908
|
+
angleKey: angleKeys[0]
|
|
29909
|
+
},
|
|
29910
|
+
calls: angleKeys.map((angleKey) => ({
|
|
29911
|
+
tool: "get_video_script",
|
|
29912
|
+
arguments: {
|
|
29913
|
+
taskId: input.taskId,
|
|
29914
|
+
angleKey
|
|
29915
|
+
}
|
|
29916
|
+
})),
|
|
29917
|
+
instruction: "Usa exactamente los arguments de cada llamada; no omitas ni derives angleKey del n\xFAmero visible. Consulta cada guion hasta ready/error/approved/skipped. Si devuelve ready, presenta el guion y espera al usuario. Si devuelve error, consulta get_task_status antes de ofrecer una recuperaci\xF3n. Si devuelve approved o skipped, contin\xFAa con la siguiente clave; al terminar, reanuda get_task_status."
|
|
29918
|
+
} : {
|
|
29919
|
+
kind: "poll_task_status",
|
|
29920
|
+
tool: "get_task_status",
|
|
29921
|
+
arguments: {
|
|
29922
|
+
taskId: input.taskId,
|
|
29923
|
+
waitSeconds: 45
|
|
29924
|
+
},
|
|
29925
|
+
instruction: "La aprobaci\xF3n no confirm\xF3 las claves de los guiones programados. Consulta get_task_status para recuperar el estado y su nextAction; no asumas angle_0 ni inicies otra generaci\xF3n."
|
|
29534
29926
|
}
|
|
29535
29927
|
} : {}
|
|
29536
29928
|
});
|
|
@@ -29671,28 +30063,28 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
|
|
|
29671
30063
|
__name(registerTaskTools, "registerTaskTools");
|
|
29672
30064
|
|
|
29673
30065
|
// src/tools/brands.ts
|
|
29674
|
-
import { z as
|
|
30066
|
+
import { z as z123 } from "zod";
|
|
29675
30067
|
var guidance2 = getProductMakerCapabilityModelGuidance("create_brand");
|
|
29676
30068
|
var BRAND_START_REPLAY_WINDOW_MS = 15 * 60 * 1e3;
|
|
29677
30069
|
var BRAND_NOTES_MAX_CHARS = 2e4;
|
|
29678
30070
|
var BRAND_AMBIGUOUS_REQUEST_RETENTION_MS = 24 * 60 * 60 * 1e3;
|
|
29679
30071
|
var BRAND_CREATION_REQUEST_LIMIT = 500;
|
|
29680
30072
|
var brandCreationRequests = /* @__PURE__ */ new Map();
|
|
29681
|
-
var CreateBrandInput =
|
|
29682
|
-
action:
|
|
30073
|
+
var CreateBrandInput = z123.object({
|
|
30074
|
+
action: z123.enum([
|
|
29683
30075
|
"start",
|
|
29684
30076
|
"status",
|
|
29685
30077
|
"list"
|
|
29686
30078
|
]).default("start").describe("start cotiza (sin confirmed) o inicia (confirmed=true) el an\xE1lisis; status consulta brandId hasta ready o failed; list muestra las marcas que el usuario ya tiene."),
|
|
29687
|
-
sourceUrl:
|
|
29688
|
-
businessNotes:
|
|
29689
|
-
language:
|
|
30079
|
+
sourceUrl: z123.string().trim().min(1).max(BRAND_SOURCE_URL_MAX_LENGTH).optional().describe("Instagram, Facebook, TikTok o web p\xFAblica del negocio, como la dio el usuario (\xAB@sanlucasbarberia\xBB, \xABinstagram.com/sanlucasbarberia\xBB, \xABmibarberia.com\xBB). Obligatorio para start."),
|
|
30080
|
+
businessNotes: z123.string().trim().max(BRAND_NOTES_MAX_CHARS).optional().describe("Opcional. Lo que el usuario cuente de su negocio en el chat (servicios y precios, WhatsApp, ciudad o zona, horarios). Se guarda como documento del negocio y llega tal cual a la marca y a su landing. Copia sus palabras; no inventes datos."),
|
|
30081
|
+
language: z123.enum([
|
|
29690
30082
|
"es",
|
|
29691
30083
|
"en",
|
|
29692
30084
|
"pt"
|
|
29693
30085
|
]).optional().describe("Idioma de la conversaci\xF3n. Solo se usa si la p\xE1gina del negocio no deja claro su idioma."),
|
|
29694
|
-
confirmed:
|
|
29695
|
-
brandId:
|
|
30086
|
+
confirmed: z123.boolean().optional().describe("Solo true despu\xE9s de mostrar el precio y que el usuario acepte. Sin confirmed, start solo cotiza y no cobra."),
|
|
30087
|
+
brandId: z123.string().uuid().optional().describe("ID de la marca. Obligatorio para status; no lo inventes.")
|
|
29696
30088
|
}).strict();
|
|
29697
30089
|
function normalizeBrandSourceUrl(raw) {
|
|
29698
30090
|
const value = raw.trim();
|
|
@@ -29975,27 +30367,26 @@ function registerBrandTools(server, api, options = {}) {
|
|
|
29975
30367
|
__name(registerBrandTools, "registerBrandTools");
|
|
29976
30368
|
|
|
29977
30369
|
// src/tools/service-landing.ts
|
|
29978
|
-
import { createHash as createHash4 } from "crypto";
|
|
29979
|
-
import { z as
|
|
30370
|
+
import { createHash as createHash4, randomUUID } from "crypto";
|
|
30371
|
+
import { z as z124 } from "zod";
|
|
29980
30372
|
var guidance3 = getProductMakerCapabilityModelGuidance("create_service_landing");
|
|
29981
30373
|
var SERVICE_LANDING_KEY_NAMESPACE = "6f1d8c2a-3b4e-5f60-8a7b-9c0d1e2f3a4b";
|
|
29982
30374
|
var SERVICE_LANDING_INFO_MAX_CHARS = 2e4;
|
|
29983
|
-
var CreateServiceLandingInput =
|
|
29984
|
-
action:
|
|
30375
|
+
var CreateServiceLandingInput = z124.object({
|
|
30376
|
+
action: z124.enum([
|
|
29985
30377
|
"prepare",
|
|
29986
30378
|
"build",
|
|
29987
30379
|
"status",
|
|
29988
30380
|
"publish"
|
|
29989
|
-
]).default("prepare").describe("prepare (gratis) crea o retoma la landing de la marca y da el precio; build (pagado, confirmed=true)
|
|
29990
|
-
brandId:
|
|
29991
|
-
servicePageId:
|
|
29992
|
-
businessInfo:
|
|
29993
|
-
confirmed:
|
|
29994
|
-
maxCredits:
|
|
29995
|
-
operationId:
|
|
29996
|
-
slug:
|
|
30381
|
+
]).default("prepare").describe("prepare (gratis) crea o retoma la landing de la marca y da el precio; build (pagado, confirmed=true) genera la p\xE1gina directamente con la marca y los datos guardados; status sigue el avance; publish la publica y devuelve su enlace."),
|
|
30382
|
+
brandId: z124.string().uuid().optional().describe("ID de la marca (de create_brand). Obligatorio para prepare. Nunca un taskId de producto."),
|
|
30383
|
+
servicePageId: z124.string().uuid().optional().describe("ID de la landing que devolvi\xF3 prepare. Obligatorio para build, status y publish."),
|
|
30384
|
+
businessInfo: z124.string().trim().max(SERVICE_LANDING_INFO_MAX_CHARS).optional().describe("Opcional. Lo que el usuario cont\xF3 del negocio y no estaba en su marca: servicios y precios, WhatsApp o tel\xE9fono, ciudad o zona, horarios. Copia sus palabras; no inventes datos."),
|
|
30385
|
+
confirmed: z124.boolean().optional().describe("Solo true despu\xE9s de mostrar el precio total y que el usuario acepte. Obligatorio para build."),
|
|
30386
|
+
maxCredits: z124.number().int().positive().optional().describe("El total en cr\xE9ditos que el usuario acept\xF3 (el que devolvi\xF3 prepare). Obligatorio para build: ninguna etapa se inicia si su precio supera este total."),
|
|
30387
|
+
operationId: z124.string().uuid().optional().describe("Opcional en status: la operaci\xF3n que devolvi\xF3 build."),
|
|
30388
|
+
slug: z124.string().trim().toLowerCase().regex(/^[a-z0-9]+(?:-[a-z0-9]+)*$/).max(64).optional().describe("Opcional en publish: la direcci\xF3n corta de la p\xE1gina (ej. sanlucas-barberia). Si falta se usa la sugerida desde el nombre del negocio.")
|
|
29997
30389
|
}).strict();
|
|
29998
|
-
var SERVICE_LANDING_MAX_BUILD_ATTEMPTS = 10;
|
|
29999
30390
|
function serviceKey(...parts) {
|
|
30000
30391
|
return deriveUuidV5(parts.join(":"), SERVICE_LANDING_KEY_NAMESPACE);
|
|
30001
30392
|
}
|
|
@@ -30045,18 +30436,6 @@ function serviceEditorUrl(api, pageId) {
|
|
|
30045
30436
|
}
|
|
30046
30437
|
}
|
|
30047
30438
|
__name(serviceEditorUrl, "serviceEditorUrl");
|
|
30048
|
-
var MISSING_LABELS = {
|
|
30049
|
-
"business.name": "nombre del negocio",
|
|
30050
|
-
services: "servicios (y su precio, si lo tiene)",
|
|
30051
|
-
"contact.channels": "WhatsApp, tel\xE9fono o enlace para reservar",
|
|
30052
|
-
"contact.primaryCta": "c\xF3mo quiere que lo contacten primero"
|
|
30053
|
-
};
|
|
30054
|
-
function describeMissing(fields) {
|
|
30055
|
-
return [
|
|
30056
|
-
...new Set(fields.map((field) => MISSING_LABELS[field]).filter((label) => Boolean(label)))
|
|
30057
|
-
];
|
|
30058
|
-
}
|
|
30059
|
-
__name(describeMissing, "describeMissing");
|
|
30060
30439
|
function summarizeFacts(facts) {
|
|
30061
30440
|
return {
|
|
30062
30441
|
...facts.business.name ? {
|
|
@@ -30079,14 +30458,13 @@ function summarizeFacts(facts) {
|
|
|
30079
30458
|
}
|
|
30080
30459
|
__name(summarizeFacts, "summarizeFacts");
|
|
30081
30460
|
var OPERATION_ERROR_TEXT = {
|
|
30082
|
-
SERVICE_PAGE_SOURCES_REQUIRED: "No hay informaci\xF3n del negocio para escribir la p\xE1gina. Pide al usuario que cuente sus servicios y
|
|
30083
|
-
SOURCE_TEXT_REQUIRED: "No hay informaci\xF3n del negocio para escribir la p\xE1gina. Pide al usuario que cuente sus servicios y
|
|
30461
|
+
SERVICE_PAGE_SOURCES_REQUIRED: "No hay informaci\xF3n del negocio para escribir la p\xE1gina. Pide al usuario que cuente sus servicios y env\xEDalos como businessInfo al preparar otra landing; muestra su precio y espera autorizaci\xF3n antes de generarla.",
|
|
30462
|
+
SOURCE_TEXT_REQUIRED: "No hay informaci\xF3n del negocio para escribir la p\xE1gina. Pide al usuario que cuente sus servicios y env\xEDalos como businessInfo al preparar otra landing; muestra su precio y espera autorizaci\xF3n antes de generarla."
|
|
30084
30463
|
};
|
|
30085
30464
|
function operationFailureText(code) {
|
|
30086
30465
|
const actionable = code ? OPERATION_ERROR_TEXT[code] : void 0;
|
|
30087
30466
|
if (actionable) return actionable;
|
|
30088
|
-
|
|
30089
|
-
return "La etapa fall\xF3 y no se cobr\xF3. Vuelve a llamar build (mismo maxCredits) sin preguntar: reintenta solo. Si falla 3 veces seguidas, sugiere terminarla en la web de ProductMaker.";
|
|
30467
|
+
return "La etapa termin\xF3 con error y no se cobr\xF3. Explica su causa. Si el usuario quiere otra landing, usa prepare con su marca, muestra el nuevo precio y espera autorizaci\xF3n antes de build; no reintentes la landing fallida autom\xE1ticamente.";
|
|
30090
30468
|
}
|
|
30091
30469
|
__name(operationFailureText, "operationFailureText");
|
|
30092
30470
|
function isPageGenerated(page) {
|
|
@@ -30101,6 +30479,30 @@ function registerServiceLandingTools(server, api) {
|
|
|
30101
30479
|
return pages.find((page) => page.brandId === brandId) ?? null;
|
|
30102
30480
|
}
|
|
30103
30481
|
__name(findPageForBrand, "findPageForBrand");
|
|
30482
|
+
async function createPageForBrand(brandId, includeBrandLogo) {
|
|
30483
|
+
try {
|
|
30484
|
+
const page = await api.postJson("/v1/service-pages", {
|
|
30485
|
+
brandId,
|
|
30486
|
+
includeBrandLogo,
|
|
30487
|
+
// Free workspace identity must not replay a terminal workspace after
|
|
30488
|
+
// its Brand association is released by canonical admission.
|
|
30489
|
+
idempotencyKey: randomUUID()
|
|
30490
|
+
});
|
|
30491
|
+
return {
|
|
30492
|
+
page,
|
|
30493
|
+
resumed: false
|
|
30494
|
+
};
|
|
30495
|
+
} catch (error) {
|
|
30496
|
+
if (error instanceof ApiHttpError && error.status < 500 && serviceApiCode(error) !== "SERVICE_PAGE_CONFLICT_BUSINESS") throw error;
|
|
30497
|
+
const existing = await findPageForBrand(brandId);
|
|
30498
|
+
if (!existing) throw error;
|
|
30499
|
+
return {
|
|
30500
|
+
page: await readPage(existing.id),
|
|
30501
|
+
resumed: true
|
|
30502
|
+
};
|
|
30503
|
+
}
|
|
30504
|
+
}
|
|
30505
|
+
__name(createPageForBrand, "createPageForBrand");
|
|
30104
30506
|
async function addBusinessInfo(page, info) {
|
|
30105
30507
|
try {
|
|
30106
30508
|
await api.postMultipart(`${pagePath(page.id)}/intake`, {}, {
|
|
@@ -30114,24 +30516,39 @@ function registerServiceLandingTools(server, api) {
|
|
|
30114
30516
|
return readPage(page.id);
|
|
30115
30517
|
}
|
|
30116
30518
|
__name(addBusinessInfo, "addBusinessInfo");
|
|
30117
|
-
async function quote(page
|
|
30118
|
-
return api.postJson(`${pagePath(page.id)}/quotes
|
|
30519
|
+
async function quote(page) {
|
|
30520
|
+
return api.postJson(`${pagePath(page.id)}/quotes/generation`, {
|
|
30119
30521
|
expectedRevision: page.draftRevision
|
|
30120
30522
|
});
|
|
30121
30523
|
}
|
|
30122
30524
|
__name(quote, "quote");
|
|
30123
|
-
async function
|
|
30124
|
-
|
|
30125
|
-
|
|
30126
|
-
|
|
30127
|
-
|
|
30128
|
-
|
|
30129
|
-
|
|
30130
|
-
|
|
30131
|
-
|
|
30132
|
-
|
|
30133
|
-
|
|
30134
|
-
|
|
30525
|
+
async function readCreation(pageId) {
|
|
30526
|
+
return ServicePageCreationStatusSchema.parse(await api.getJson(`${pagePath(pageId)}/creation`));
|
|
30527
|
+
}
|
|
30528
|
+
__name(readCreation, "readCreation");
|
|
30529
|
+
function creationResponse(pageId, creation) {
|
|
30530
|
+
const editorUrl = serviceEditorUrl(api, pageId);
|
|
30531
|
+
return asText({
|
|
30532
|
+
servicePageId: pageId,
|
|
30533
|
+
status: creation.status === "running" ? "generating" : "error",
|
|
30534
|
+
...creation.status === "running" && editorUrl ? {
|
|
30535
|
+
editorUrl
|
|
30536
|
+
} : {},
|
|
30537
|
+
...creation.status === "failed" ? {
|
|
30538
|
+
errorCode: creation.errorCode
|
|
30539
|
+
} : {},
|
|
30540
|
+
nextAction: creation.status === "running" ? "La landing se est\xE1 generando. Puedes salir del chat y seguirla en Tareas. Vuelve a llamar action=status con el mismo servicePageId; no inicies otra generaci\xF3n." : "La creaci\xF3n termin\xF3 con error y queda en Tareas. Para crear otra landing, usa action=prepare con la marca elegida y muestra el nuevo precio; solo inicia build cuando el usuario lo autorice. No reutilices esta landing fallida."
|
|
30541
|
+
});
|
|
30542
|
+
}
|
|
30543
|
+
__name(creationResponse, "creationResponse");
|
|
30544
|
+
async function startOperation(page, quoted) {
|
|
30545
|
+
const operation = ServicePageOperationResponseSchema.parse(await api.postJson(`${pagePath(page.id)}/generate`, {
|
|
30546
|
+
quoteId: quoted.quoteId,
|
|
30547
|
+
idempotencyKey: serviceKey(page.id, "generation", page.draftRevision),
|
|
30548
|
+
expectedRevision: page.draftRevision
|
|
30549
|
+
}));
|
|
30550
|
+
if (operation.servicePageId !== page.id || operation.kind !== "generation") {
|
|
30551
|
+
throw mcp(McpErrorCode.INVALID_INPUT, "La operaci\xF3n no pertenece a la generaci\xF3n de esta landing.");
|
|
30135
30552
|
}
|
|
30136
30553
|
return operation;
|
|
30137
30554
|
}
|
|
@@ -30153,7 +30570,7 @@ function registerServiceLandingTools(server, api) {
|
|
|
30153
30570
|
}
|
|
30154
30571
|
__name(generatedResponse, "generatedResponse");
|
|
30155
30572
|
server.registerTool("create_service_landing", {
|
|
30156
|
-
description: guidance3.summary + " Parte del brandId de create_brand y termina con el enlace p\xFAblico de la p\xE1gina. NO es para productos de dropshipping (para eso generate_landing / create_product_task). Flujo: 1) action=prepare con brandId (gratis):
|
|
30573
|
+
description: guidance3.summary + " Parte del brandId de create_brand y termina con el enlace p\xFAblico de la p\xE1gina. NO es para productos de dropshipping (para eso generate_landing / create_product_task). Flujo: 1) action=prepare con brandId (gratis): prepara la landing y devuelve el precio estimado. 2) Pregunta una sola vez los datos que falten; puede omitirlos. 3) Cuando acepte el precio, action=build con servicePageId, confirmed=true, maxCredits y businessInfo: inicia una sola generaci\xF3n con la marca y las fuentes guardadas, sin una lectura pagada previa. 4) action=status hasta generated o error; generando se sigue en Tareas y contin\xFAa aunque cierre el chat. No llames build para continuar una etapa. 5) Muestra el enlace para verla y, si acepta, action=publish. Repetir una llamada no cobra dos veces. Con el enlace publicado sigue create_animated_video si quiere un video y create_service_images con el mismo brandId si quiere im\xE1genes.",
|
|
30157
30574
|
inputSchema: CreateServiceLandingInput.shape,
|
|
30158
30575
|
annotations: CREATES_PAID
|
|
30159
30576
|
}, async (rawInput) => {
|
|
@@ -30172,37 +30589,37 @@ function registerServiceLandingTools(server, api) {
|
|
|
30172
30589
|
});
|
|
30173
30590
|
}
|
|
30174
30591
|
const existing = await findPageForBrand(input.brandId);
|
|
30175
|
-
let
|
|
30176
|
-
|
|
30177
|
-
|
|
30178
|
-
|
|
30179
|
-
|
|
30592
|
+
let workspace = existing ? {
|
|
30593
|
+
page: await readPage(existing.id),
|
|
30594
|
+
resumed: true
|
|
30595
|
+
} : await createPageForBrand(input.brandId, Boolean(brand.logoKey));
|
|
30596
|
+
let page2 = workspace.page;
|
|
30180
30597
|
if (isPageGenerated(page2)) return generatedResponse(page2);
|
|
30598
|
+
let creation2 = await readCreation(page2.id);
|
|
30599
|
+
if (existing && creation2.status === "failed") {
|
|
30600
|
+
workspace = await createPageForBrand(input.brandId, Boolean(brand.logoKey));
|
|
30601
|
+
page2 = workspace.page;
|
|
30602
|
+
if (isPageGenerated(page2)) return generatedResponse(page2);
|
|
30603
|
+
creation2 = await readCreation(page2.id);
|
|
30604
|
+
}
|
|
30605
|
+
if (creation2.status !== "idle") return creationResponse(page2.id, creation2);
|
|
30181
30606
|
if (input.businessInfo) page2 = await addBusinessInfo(page2, input.businessInfo);
|
|
30182
|
-
const
|
|
30183
|
-
const generationQuote = await quote(page2, "generation");
|
|
30184
|
-
const facts = factsQuote ? quoteRange(factsQuote) : {
|
|
30185
|
-
min: 0,
|
|
30186
|
-
max: 0
|
|
30187
|
-
};
|
|
30607
|
+
const generationQuote = await quote(page2);
|
|
30188
30608
|
const build = quoteRange(generationQuote);
|
|
30189
|
-
const totalMin =
|
|
30190
|
-
const totalCredits =
|
|
30191
|
-
const requiredBalanceCredits =
|
|
30609
|
+
const totalMin = build.min;
|
|
30610
|
+
const totalCredits = build.max;
|
|
30611
|
+
const requiredBalanceCredits = generationQuote.credits;
|
|
30192
30612
|
const askFor = page2.facts.contact.channels.some((channel) => channel.kind === "whatsapp") ? "su ciudad o zona y sus servicios con precio (su WhatsApp ya viene de la marca: no lo pidas)" : "su WhatsApp o tel\xE9fono, su ciudad o zona y sus servicios con precio";
|
|
30193
30613
|
const priceText = totalMin === totalCredits ? `${totalCredits} cr\xE9ditos` : `entre ${totalMin} y ${totalCredits} cr\xE9ditos`;
|
|
30194
30614
|
return asText({
|
|
30195
30615
|
servicePageId: page2.id,
|
|
30196
30616
|
charged: false,
|
|
30197
|
-
...
|
|
30617
|
+
...workspace.resumed ? {
|
|
30198
30618
|
resumed: true
|
|
30199
30619
|
} : {},
|
|
30200
30620
|
business: page2.businessName,
|
|
30201
30621
|
known: summarizeFacts(page2.facts),
|
|
30202
30622
|
price: {
|
|
30203
|
-
...factsQuote ? {
|
|
30204
|
-
readBusinessInfoCredits: facts
|
|
30205
|
-
} : {},
|
|
30206
30623
|
buildPageCredits: build,
|
|
30207
30624
|
totalMinCredits: totalMin,
|
|
30208
30625
|
totalCredits,
|
|
@@ -30215,33 +30632,22 @@ function registerServiceLandingTools(server, api) {
|
|
|
30215
30632
|
throw mcp(McpErrorCode.INVALID_INPUT, "servicePageId es obligatorio: usa el que devolvi\xF3 prepare. No se cobr\xF3 nada.");
|
|
30216
30633
|
}
|
|
30217
30634
|
if (input.action === "status") {
|
|
30218
|
-
|
|
30219
|
-
|
|
30220
|
-
|
|
30221
|
-
|
|
30222
|
-
return asText({
|
|
30223
|
-
servicePageId: input.servicePageId,
|
|
30224
|
-
status: creation.status,
|
|
30225
|
-
...editorUrl ? {
|
|
30226
|
-
editorUrl
|
|
30227
|
-
} : {},
|
|
30228
|
-
...creation.status === "failed" ? {
|
|
30229
|
-
errorCode: creation.errorCode,
|
|
30230
|
-
reason: "No pudimos terminar la p\xE1gina. Tus datos siguen guardados."
|
|
30231
|
-
} : {},
|
|
30232
|
-
nextAction: creation.status === "running" ? "Sigue en curso. Vuelve a llamar action=status con el mismo servicePageId en unos segundos; no inicies otra etapa." : "La creaci\xF3n fall\xF3. Muestra el motivo al usuario y el enlace al editor, si est\xE1 disponible; no inicies otra generaci\xF3n sin su autorizaci\xF3n."
|
|
30233
|
-
});
|
|
30234
|
-
}
|
|
30235
|
-
}
|
|
30635
|
+
const creation2 = await readCreation(input.servicePageId);
|
|
30636
|
+
if (creation2.status !== "idle") return creationResponse(input.servicePageId, creation2);
|
|
30637
|
+
let page2 = await readPage(input.servicePageId);
|
|
30638
|
+
if (isPageGenerated(page2)) return generatedResponse(page2);
|
|
30236
30639
|
let operation2 = null;
|
|
30237
30640
|
if (input.operationId) {
|
|
30238
|
-
operation2 = await api.getJson(`/v1/service-pages/operations/${encodeURIComponent(input.operationId)}`);
|
|
30641
|
+
operation2 = ServicePageOperationResponseSchema.parse(await api.getJson(`/v1/service-pages/operations/${encodeURIComponent(input.operationId)}`));
|
|
30642
|
+
if (operation2.servicePageId !== input.servicePageId) {
|
|
30643
|
+
throw mcp(McpErrorCode.INVALID_INPUT, "La operaci\xF3n no pertenece a esta landing.");
|
|
30644
|
+
}
|
|
30239
30645
|
if (operation2.status === "queued" || operation2.status === "running") {
|
|
30240
30646
|
return asText({
|
|
30241
30647
|
servicePageId: input.servicePageId,
|
|
30242
30648
|
operationId: operation2.opId,
|
|
30243
30649
|
step: operation2.kind === "generation" ? "creando la p\xE1gina" : "leyendo los datos del negocio",
|
|
30244
|
-
status:
|
|
30650
|
+
status: "generating",
|
|
30245
30651
|
nextAction: "Sigue en curso. Llama action=status otra vez con el mismo operationId en unos segundos; no inicies otra etapa."
|
|
30246
30652
|
});
|
|
30247
30653
|
}
|
|
@@ -30249,49 +30655,28 @@ function registerServiceLandingTools(server, api) {
|
|
|
30249
30655
|
return asText({
|
|
30250
30656
|
servicePageId: input.servicePageId,
|
|
30251
30657
|
operationId: operation2.opId,
|
|
30252
|
-
status: "
|
|
30658
|
+
status: "generating",
|
|
30253
30659
|
// Unknown on purpose: the charge is exactly what is being
|
|
30254
30660
|
// confirmed. Settlement only charges a completed step.
|
|
30255
|
-
nextAction: "
|
|
30661
|
+
nextAction: "La landing se sigue generando: el servidor est\xE1 confirmando si se complet\xF3 y la resuelve solo. Si no se completa, se devuelve lo cobrado. Dile al usuario que sus datos est\xE1n guardados; vuelve a llamar action=status con el mismo operationId en unos minutos. No inicies otra generaci\xF3n mientras tanto."
|
|
30256
30662
|
});
|
|
30257
30663
|
}
|
|
30258
30664
|
if (operation2.status !== "succeeded") {
|
|
30259
30665
|
return asText({
|
|
30260
30666
|
servicePageId: input.servicePageId,
|
|
30261
30667
|
operationId: operation2.opId,
|
|
30262
|
-
status: "
|
|
30668
|
+
status: "error",
|
|
30669
|
+
errorCode: operation2.errorCode,
|
|
30263
30670
|
charged: false,
|
|
30264
30671
|
reason: operationFailureText(operation2.errorCode)
|
|
30265
30672
|
});
|
|
30266
30673
|
}
|
|
30267
30674
|
}
|
|
30268
|
-
|
|
30675
|
+
if (operation2?.status === "succeeded") page2 = await readPage(input.servicePageId);
|
|
30269
30676
|
if (isPageGenerated(page2)) return generatedResponse(page2);
|
|
30270
|
-
|
|
30271
|
-
|
|
30272
|
-
|
|
30273
|
-
servicePageId: page2.id,
|
|
30274
|
-
status: "not_generated",
|
|
30275
|
-
operationStatus: "unknown",
|
|
30276
|
-
...editorUrl ? {
|
|
30277
|
-
editorUrl
|
|
30278
|
-
} : {},
|
|
30279
|
-
reason: "La p\xE1gina a\xFAn no tiene un resultado generado. Sin operationId no podemos determinar el estado de la operaci\xF3n; consulta sus tareas o abre el editor para revisar su progreso.",
|
|
30280
|
-
nextAction: {
|
|
30281
|
-
tool: "list_tasks",
|
|
30282
|
-
arguments: {}
|
|
30283
|
-
}
|
|
30284
|
-
});
|
|
30285
|
-
}
|
|
30286
|
-
const missing = describeMissing(page2.missingFields);
|
|
30287
|
-
return asText({
|
|
30288
|
-
servicePageId: page2.id,
|
|
30289
|
-
status: page2.factExtractionCompleted ? "business_info_read" : "waiting_for_build",
|
|
30290
|
-
found: summarizeFacts(page2.facts),
|
|
30291
|
-
...missing.length ? {
|
|
30292
|
-
stillMissing: missing
|
|
30293
|
-
} : {},
|
|
30294
|
-
nextAction: page2.factExtractionCompleted ? `Muestra en pocas l\xEDneas lo que encontramos del negocio${missing.length ? " y lo que falta (puede agregarlo en businessInfo o seguir sin eso)" : ""}. Luego llama action=build con el mismo servicePageId, confirmed=true y el mismo maxCredits para crear la p\xE1gina.` : "A\xFAn no se leyeron los datos del negocio. Llama action=build con confirmed=true y el maxCredits que acept\xF3 el usuario."
|
|
30677
|
+
return creationResponse(page2.id, {
|
|
30678
|
+
status: "failed",
|
|
30679
|
+
errorCode: "SERVICE_PAGE_CREATION_STALLED"
|
|
30295
30680
|
});
|
|
30296
30681
|
}
|
|
30297
30682
|
if (input.action === "publish") {
|
|
@@ -30309,7 +30694,7 @@ function registerServiceLandingTools(server, api) {
|
|
|
30309
30694
|
});
|
|
30310
30695
|
return asText({
|
|
30311
30696
|
servicePageId: page2.id,
|
|
30312
|
-
status: "
|
|
30697
|
+
status: "generated",
|
|
30313
30698
|
publicUrl: published.publicUrl,
|
|
30314
30699
|
nextAction: `Comparte el enlace ${published.publicUrl} con el usuario. Si pidi\xF3 un video, sigue con create_animated_video action=prepare y landingUrl=${published.publicUrl}; si pidi\xF3 im\xE1genes, con create_service_images y brandId=${page2.brandId ?? "(el de su marca)"}.`
|
|
30315
30700
|
});
|
|
@@ -30317,7 +30702,8 @@ function registerServiceLandingTools(server, api) {
|
|
|
30317
30702
|
if (serviceApiCode(error)?.includes("SLUG")) {
|
|
30318
30703
|
return asText({
|
|
30319
30704
|
servicePageId: page2.id,
|
|
30320
|
-
status: "
|
|
30705
|
+
status: "generated",
|
|
30706
|
+
publicationErrorCode: "SERVICE_PAGE_SLUG_TAKEN",
|
|
30321
30707
|
slug,
|
|
30322
30708
|
nextAction: `La direcci\xF3n \xAB${slug}\xBB ya est\xE1 en uso. Prop\xF3n otra (por ejemplo \xAB${slug}-${(/* @__PURE__ */ new Date()).getFullYear()}\xBB o con la ciudad) y llama action=publish con slug.`
|
|
30323
30709
|
});
|
|
@@ -30330,12 +30716,10 @@ function registerServiceLandingTools(server, api) {
|
|
|
30330
30716
|
}
|
|
30331
30717
|
let page = await readPage(input.servicePageId);
|
|
30332
30718
|
if (isPageGenerated(page)) return generatedResponse(page);
|
|
30333
|
-
const
|
|
30719
|
+
const creation = await readCreation(page.id);
|
|
30720
|
+
if (creation.status !== "idle") return creationResponse(page.id, creation);
|
|
30334
30721
|
if (input.businessInfo) page = await addBusinessInfo(page, input.businessInfo);
|
|
30335
|
-
const
|
|
30336
|
-
const needsFacts = !page.factExtractionCompleted || addedInfo;
|
|
30337
|
-
const purpose = needsFacts ? "fact-extraction" : "generation";
|
|
30338
|
-
const quoted = await quote(page, purpose);
|
|
30722
|
+
const quoted = await quote(page);
|
|
30339
30723
|
const credits = quoteRange(quoted).max;
|
|
30340
30724
|
if (credits > input.maxCredits) {
|
|
30341
30725
|
return asText({
|
|
@@ -30345,15 +30729,18 @@ function registerServiceLandingTools(server, api) {
|
|
|
30345
30729
|
nextAction: `El precio subi\xF3 a ${credits} cr\xE9ditos, m\xE1s de lo aceptado (${input.maxCredits}). Preg\xFAntale al usuario si sigue y, si acepta, repite build con maxCredits=${credits}.`
|
|
30346
30730
|
});
|
|
30347
30731
|
}
|
|
30348
|
-
await requirePaidCreativeConfirmation(server,
|
|
30349
|
-
const operation = await startOperation(page,
|
|
30732
|
+
await requirePaidCreativeConfirmation(server, `Generar la landing del negocio. Precio estimado: hasta ${credits} cr\xE9ditos (total aceptado: ${input.maxCredits}).`);
|
|
30733
|
+
const operation = await startOperation(page, quoted);
|
|
30350
30734
|
return asText({
|
|
30351
30735
|
servicePageId: page.id,
|
|
30352
30736
|
operationId: operation.opId,
|
|
30353
|
-
step:
|
|
30354
|
-
status: operation.status,
|
|
30737
|
+
step: "creando la p\xE1gina",
|
|
30738
|
+
status: operation.status === "failed" || operation.status === "conflict" ? "error" : "generating",
|
|
30739
|
+
...operation.errorCode ? {
|
|
30740
|
+
errorCode: operation.errorCode
|
|
30741
|
+
} : {},
|
|
30355
30742
|
priceCredits: credits,
|
|
30356
|
-
nextAction: operation.status === "failed" ? operationFailureText(operation.errorCode) :
|
|
30743
|
+
nextAction: operation.status === "failed" || operation.status === "conflict" ? operationFailureText(operation.errorCode) : "La landing se est\xE1 generando y aparece en Tareas. Llama action=status con servicePageId hasta generated o error. La generaci\xF3n contin\xFAa aunque salgas del chat."
|
|
30357
30744
|
});
|
|
30358
30745
|
} catch (error) {
|
|
30359
30746
|
throw translateError(error);
|
|
@@ -30363,7 +30750,7 @@ function registerServiceLandingTools(server, api) {
|
|
|
30363
30750
|
__name(registerServiceLandingTools, "registerServiceLandingTools");
|
|
30364
30751
|
|
|
30365
30752
|
// src/tools/service-images.ts
|
|
30366
|
-
import { z as
|
|
30753
|
+
import { z as z125 } from "zod";
|
|
30367
30754
|
var guidance4 = getProductMakerCapabilityModelGuidance("create_service_images");
|
|
30368
30755
|
var SERVICE_IMAGE_FORMATS = [
|
|
30369
30756
|
"4:5",
|
|
@@ -30376,23 +30763,23 @@ var LANGUAGE_TAGS = {
|
|
|
30376
30763
|
en: "en-US",
|
|
30377
30764
|
pt: "pt-BR"
|
|
30378
30765
|
};
|
|
30379
|
-
var CreateServiceImagesInput =
|
|
30380
|
-
brandId:
|
|
30381
|
-
instruction:
|
|
30382
|
-
delegateToAi:
|
|
30383
|
-
format:
|
|
30384
|
-
count:
|
|
30385
|
-
quality:
|
|
30766
|
+
var CreateServiceImagesInput = z125.object({
|
|
30767
|
+
brandId: z125.string().uuid().optional().describe("ID de la marca (de create_brand). Recomendado: da nombre, colores, tono y servicios. Nunca un taskId de producto."),
|
|
30768
|
+
instruction: z125.string().trim().max(4e3).optional().describe("Qu\xE9 servicio o promoci\xF3n mostrar, con las palabras del usuario (ej. \xABcorte + barba a $35.000 los martes\xBB). Si el usuario deja que la IA decida, om\xEDtelo y usa delegateToAi=true."),
|
|
30769
|
+
delegateToAi: z125.boolean().optional().describe("true si el usuario prefiere que la IA elija qu\xE9 mostrar a partir de su marca."),
|
|
30770
|
+
format: z125.enum(SERVICE_IMAGE_FORMATS).optional().describe('Formato: "4:5" (feed, por defecto), "9:16" (historias/reels) o "1:1" (cuadrado).'),
|
|
30771
|
+
count: z125.number().int().min(1).max(SERVICE_IMAGE_MAX_COUNT).optional().describe("Cu\xE1ntas im\xE1genes, de 1 a 3 (por defecto 1)."),
|
|
30772
|
+
quality: z125.enum([
|
|
30386
30773
|
"standard",
|
|
30387
30774
|
"high"
|
|
30388
30775
|
]).optional().describe('Calidad: "standard" (por defecto) o "high" (m\xE1s cara; no disponible en 4:5).'),
|
|
30389
|
-
language:
|
|
30776
|
+
language: z125.enum([
|
|
30390
30777
|
"es",
|
|
30391
30778
|
"en",
|
|
30392
30779
|
"pt"
|
|
30393
30780
|
]).optional().describe("Idioma de los textos de la imagen (por defecto es)."),
|
|
30394
|
-
adCopy:
|
|
30395
|
-
confirmed:
|
|
30781
|
+
adCopy: z125.boolean().optional().describe("Compatibilidad con clientes anteriores: el copy para publicar siempre est\xE1 incluido en cada imagen de servicios."),
|
|
30782
|
+
confirmed: z125.boolean().optional().describe("Solo true despu\xE9s de mostrar el precio y que el usuario acepte. Sin confirmed, solo cotiza y no cobra.")
|
|
30396
30783
|
}).strict();
|
|
30397
30784
|
function serviceImageModel(quality) {
|
|
30398
30785
|
return quality === "high" ? AD_CREATIVE_MODELS.PREMIUM : AD_CREATIVE_MODELS.STANDARD;
|
|
@@ -30503,7 +30890,7 @@ function registerServiceImageTools(server, api, options = {}) {
|
|
|
30503
30890
|
nextAction: "Dile al usuario que est\xE1s creando sus im\xE1genes. Llama get_task_status con este taskId (waitSeconds=45) hasta done (trae las im\xE1genes) o error."
|
|
30504
30891
|
});
|
|
30505
30892
|
} catch (error) {
|
|
30506
|
-
if (error instanceof
|
|
30893
|
+
if (error instanceof z125.ZodError) throw invalidInputFromZod(error);
|
|
30507
30894
|
throw translateError(error);
|
|
30508
30895
|
}
|
|
30509
30896
|
});
|
|
@@ -30511,7 +30898,7 @@ function registerServiceImageTools(server, api, options = {}) {
|
|
|
30511
30898
|
__name(registerServiceImageTools, "registerServiceImageTools");
|
|
30512
30899
|
|
|
30513
30900
|
// src/tools/creatives.ts
|
|
30514
|
-
import { z as
|
|
30901
|
+
import { z as z126 } from "zod";
|
|
30515
30902
|
var generateFreeVideoGuidance = getProductMakerCapabilityModelGuidance("generate_free_video");
|
|
30516
30903
|
var generateVideoCreativeGuidance = getProductMakerCapabilityModelGuidance("generate_video_creative");
|
|
30517
30904
|
var generateImageCreativesGuidance = getProductMakerCapabilityModelGuidance("generate_image_creatives");
|
|
@@ -30522,72 +30909,72 @@ var CreativeRefs = {
|
|
|
30522
30909
|
images: ImagesInput,
|
|
30523
30910
|
language: Lang.describe('Idioma del contenido. Ej. "es", "en", "pt". REQUERIDO \u2014 si el usuario no lo dijo, PREG\xDANTALE antes de invocar. NUNCA infieras desde el contexto del chat ni asumas un default.'),
|
|
30524
30911
|
country: Country.describe('Pa\xEDs objetivo ISO. Ej. "CO", "MX", "US", "AR". Define moneda, m\xE9todos de pago y tono. REQUERIDO \u2014 si el usuario no lo dijo, PREG\xDANTALE antes de invocar. NUNCA infieras desde el contexto del chat ni asumas un default.'),
|
|
30525
|
-
price:
|
|
30526
|
-
offer:
|
|
30527
|
-
compareAtPrice:
|
|
30528
|
-
productContext:
|
|
30529
|
-
productLabel:
|
|
30530
|
-
buyerPersona:
|
|
30531
|
-
isCombo:
|
|
30532
|
-
competitorScanEnabled:
|
|
30533
|
-
brandId:
|
|
30912
|
+
price: z126.string().min(1).max(120).optional().describe('Precio en formato libre \u2014 ej. "$89.900", "USD 29.99". Opcional pero MUY IMPACTANTE para conversi\xF3n: si el usuario no lo mencion\xF3, PREG\xDANTALE antes de invocar. Si el usuario te dice "t\xFA elige", omite el campo y la IA del backend sugiere uno.'),
|
|
30913
|
+
offer: z126.string().min(1).max(240).optional().describe('Oferta a destacar \u2014 ej. "2x1", "Env\xEDo gratis", "50% OFF". Opcional pero MUY IMPACTANTE: si el usuario no lo mencion\xF3, PREG\xDANTALE antes de invocar (es v\xE1lido que diga "sin oferta"). Si el usuario te dice "t\xFA elige", omite el campo.'),
|
|
30914
|
+
compareAtPrice: z126.string().min(1).max(120).optional().describe('Opcional. Precio anterior o de referencia para mostrar descuento. Ej. "$129.000" cuando price="$89.900".'),
|
|
30915
|
+
productContext: z126.string().max(3e3).optional().describe("Opcional. Informacion adicional del producto que la IA debe usar como contexto prioritario: uso real, comprador, restricciones, diferenciadores o direccion creativa. No reemplaza la investigacion de competencia; si hay competencia, guia el primer angulo y los outputs no deben contradecirlo."),
|
|
30916
|
+
productLabel: z126.string().trim().max(80).optional().describe('Opcional. Nombre o tipo del producto en pocas palabras (ej. "collar de oro", "quita pelusas para ropa"). Es AUTORITATIVO: la IA usa esta identidad y no la reemplaza por otra categor\xEDa. Si lo omites, la IA lo detecta desde la imagen. NO salta la extracci\xF3n.'),
|
|
30917
|
+
buyerPersona: z126.string().optional().describe('Opcional. Descripci\xF3n del comprador objetivo. Ej. "Mujeres 35-50, profesionales urbanas". Si se omite, la IA infiere desde el \xE1ngulo y producto.'),
|
|
30918
|
+
isCombo: z126.boolean().optional().describe("Opcional. Si true, el creativo presenta el producto como combo/pack. Default false."),
|
|
30919
|
+
competitorScanEnabled: z126.boolean().optional().describe("Opcional. Default false: omitirlo significa SIN estudio de mercado. Antes de crear, llama estimate_market_study_cost, muestra al usuario el costo con y sin estudio y preg\xFAntale si lo quiere; env\xEDa true solo si lo acepta (o si solicita la narrativa an\xE1lisis de mercado). En video, true analiza anuncios de la competencia y desbloquea la narrativa an\xE1lisis de mercado; si el estudio no encuentra datos suficientes, degrada al planner cl\xE1sico."),
|
|
30920
|
+
brandId: z126.string().uuid().optional().describe("Opcional. ID de una marca del usuario; si se env\xEDa, el sistema usa su voz, colores y persona para enriquecer el creativo.")
|
|
30534
30921
|
};
|
|
30535
|
-
var VideoPresenter =
|
|
30536
|
-
|
|
30537
|
-
mode:
|
|
30922
|
+
var VideoPresenter = z126.discriminatedUnion("mode", [
|
|
30923
|
+
z126.object({
|
|
30924
|
+
mode: z126.literal("none")
|
|
30538
30925
|
}).strict(),
|
|
30539
|
-
|
|
30540
|
-
mode:
|
|
30541
|
-
actorId:
|
|
30926
|
+
z126.object({
|
|
30927
|
+
mode: z126.literal("saved_actor"),
|
|
30928
|
+
actorId: z126.string().trim().min(1).max(120).describe("ID devuelto por list_actors para un actor guardado del usuario.")
|
|
30542
30929
|
}).strict(),
|
|
30543
|
-
|
|
30544
|
-
mode:
|
|
30545
|
-
description:
|
|
30930
|
+
z126.object({
|
|
30931
|
+
mode: z126.literal("described"),
|
|
30932
|
+
description: z126.string().trim().min(1).max(500).describe("Descripci\xF3n concreta de la persona que presenta el producto.")
|
|
30546
30933
|
}).strict()
|
|
30547
30934
|
]);
|
|
30548
|
-
var VideoCreativeSetup =
|
|
30549
|
-
|
|
30550
|
-
mode:
|
|
30935
|
+
var VideoCreativeSetup = z126.discriminatedUnion("mode", [
|
|
30936
|
+
z126.object({
|
|
30937
|
+
mode: z126.literal("automatic").describe('S\xF3lo cuando el usuario pidi\xF3 expl\xEDcitamente "decide todo".')
|
|
30551
30938
|
}).strict(),
|
|
30552
|
-
|
|
30553
|
-
mode:
|
|
30939
|
+
z126.object({
|
|
30940
|
+
mode: z126.literal("guided"),
|
|
30554
30941
|
videoPreset: VideoPresetEnum.default("auto").describe('Narrativa opcional. Con estudio de mercado no la preguntes: se usa "auto" y el estudio define la estructura. Sin estudio conserva la elecci\xF3n del usuario. Todas las narrativas funcionan en Un solo clip y Multiescena.'),
|
|
30555
|
-
buyerPersona:
|
|
30942
|
+
buyerPersona: z126.string().trim().min(1).max(360),
|
|
30556
30943
|
animationStyle: AnimationStyleEnum.optional().describe('Opcional. Estilo visual SOLO para presets animados ("pixar_problem" o "pixar_sassy") \u2014 la API lo rechaza con cualquier otro preset. Opciones: "pixar_3d" (default, look 3D de pel\xEDcula animada), "claymation" (plastilina stop-motion artesanal), "wes_anderson" (tableau sim\xE9trico pastel), "sci_fi" (futurista con HUDs y ne\xF3n), "realista" (fotorrealista, fiel al producto). Si el usuario pide un look animado sin nombrar el estilo, omite el campo.'),
|
|
30557
30944
|
presenter: VideoPresenter,
|
|
30558
|
-
creativeDirection:
|
|
30945
|
+
creativeDirection: z126.string().trim().min(1).max(500).nullable().describe("Direcci\xF3n visual elegida. null significa que el usuario deleg\xF3 expl\xEDcitamente esta decisi\xF3n.")
|
|
30559
30946
|
}).strict()
|
|
30560
30947
|
]);
|
|
30561
|
-
var VideoInput =
|
|
30948
|
+
var VideoInput = z126.object({
|
|
30562
30949
|
images: CreativeRefs.images.optional(),
|
|
30563
30950
|
winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
|
|
30564
|
-
title:
|
|
30565
|
-
primaryAngle:
|
|
30951
|
+
title: z126.string().min(1).describe('T\xEDtulo corto del producto. Aparece en la primera vista del video. Ej. "Crema Anti-Edad Premium".'),
|
|
30952
|
+
primaryAngle: z126.string().min(1).describe('\xC1ngulo de venta principal (frase del beneficio). Ej. "Reduce arrugas en 14 d\xEDas" o "Para quienes odian las cremas grasosas".'),
|
|
30566
30953
|
language: CreativeRefs.language,
|
|
30567
30954
|
country: CreativeRefs.country,
|
|
30568
|
-
aspectRatio:
|
|
30955
|
+
aspectRatio: z126.enum([
|
|
30569
30956
|
"9:16",
|
|
30570
30957
|
"16:9",
|
|
30571
30958
|
"Auto"
|
|
30572
30959
|
]).describe('Relaci\xF3n de aspecto. "9:16" = vertical (TikTok/Reels \u2014 default recomendado para ads). "16:9" = horizontal (YouTube). "Auto" = decide la IA.'),
|
|
30573
30960
|
generateAiEdit: AiEditRequestSchema.optional().describe('Opcional. Pide la Edici\xF3n con IA: una pasada que a\xF1ade texto, efectos y m\xFAsica sobre cada video entregado (variante with_ai_edit; se cobra al entregar, por video). Nivel: "economy" (Econ\xF3mica, Sonnet 5.5, m\xE1s barata) o "pro" (Opus 5.5, mejor calidad, ~10 min). true equivale a "pro"; false/omitido = sin edici\xF3n.'),
|
|
30574
|
-
durationSeconds:
|
|
30575
|
-
videoAngleCount:
|
|
30961
|
+
durationSeconds: z126.number().int().min(4).max(30).default(15).describe("Opcional. Duraci\xF3n objetivo: Un solo clip Econ\xF3mico o Medio usa 15s; Un solo clip Pro usa 15s o 30s; Multiescena usa 15s o 30s totales. La combinaci\xF3n de formato y calidad determina la ruta y el costo."),
|
|
30962
|
+
videoAngleCount: z126.number().int().min(1).max(3).describe("Cantidad de videos a renderizar: 1, 2 o 3. Es una decisi\xF3n de costo obligatoria: preg\xFAntala incluso cuando creativeSetup.mode=automatic."),
|
|
30576
30963
|
angleNarratives: PublicNarrativeStyleEnum.array().max(3).optional().describe('Opcional. Narrativa POR \xC1NGULO (posicional). Valores actuales: "review", "ugc_how_to", "ugc_unboxing_chaos", "problem_product_cta" (problema concreto, producto como soluci\xF3n y CTA), "product_showcase", "wearable_showcase", "cinematic", "wild_card", "animated_problem_pixar", "sassy_product_pixar", "market" (narrativa an\xE1lisis de mercado: adapta el video a los patrones ganadores estudiados de la competencia; requiere competitorScanEnabled: true). angleNarratives[i] fuerza la narrativa del \xE1ngulo i; las posiciones restantes las elige la IA. La lista no puede superar videoAngleCount.'),
|
|
30577
30964
|
creativeSetup: VideoCreativeSetup.describe("Configuraci\xF3n creativa obligatoria. En guided pregunta narrativa, p\xFAblico, presentador y direcci\xF3n antes de confirmar. Usa automatic s\xF3lo si el usuario deleg\xF3 todo expl\xEDcitamente."),
|
|
30578
30965
|
videoStructure: VideoStructureEnum.default("single_take").describe('Opcional. Formato: "single_take" = Un solo clip (generado completo; puede incluir cambios de plano) o "multi_scene" = Multiescena (varias tomas concatenadas). Default: single_take.'),
|
|
30579
30966
|
videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El sistema elige el proveedor internamente. Default: economy.'),
|
|
30580
30967
|
videoResolution: VideoResolutionEnum.optional().describe('Opcional. Resoluci\xF3n del render: "480p" o "720p". Si se omite, se usa 480p; elige 720p expl\xEDcitamente si necesitas m\xE1s nitidez.'),
|
|
30581
|
-
features:
|
|
30968
|
+
features: z126.array(z126.string()).optional().describe('Opcional. Lista de features/beneficios clave a mencionar. Ej. ["resistente al agua", "bater\xEDa 24h", "carga inal\xE1mbrica"].'),
|
|
30582
30969
|
price: CreativeRefs.price,
|
|
30583
30970
|
offer: CreativeRefs.offer,
|
|
30584
30971
|
productContext: CreativeRefs.productContext,
|
|
30585
30972
|
productLabel: CreativeRefs.productLabel,
|
|
30586
|
-
cta:
|
|
30587
|
-
scriptNotes:
|
|
30973
|
+
cta: z126.string().optional().describe('Opcional. Call-to-action final del video. Ej. "Compra ahora", "Pide el tuyo hoy", "Link en bio". Si se omite, la IA escribe uno.'),
|
|
30974
|
+
scriptNotes: z126.string().optional().describe('Opcional. Notas/restricciones para el guion (la IA las usa al redactar). Ej. "No mencionar la marca X", "Tono divertido, no cl\xEDnico", "Mencionar 2x1". NO es el guion literal: creativeSetup.mode=guided activa siempre la revisi\xF3n palabra-por-palabra con get_video_script / approve_video_script.'),
|
|
30588
30975
|
creativeGender: CreativeGenderEnum.optional().describe('Opcional. QUI\xC9N APARECE EN PANTALLA en el video: mujer ("female"), hombre ("male") o ambos ("mixed"). NO es la voz; cuando se fija, la voz se alinea sola con el personaje. M\xE1ndalo en cuanto el usuario diga qui\xE9n debe SALIR en el video, con cualquier redacci\xF3n ("quiero una mujer", "que salga un hombre", "protagonista femenina"): si no lo mandas, el g\xE9nero lo inventa la IA y el usuario puede recibir lo contrario de lo que pidi\xF3 sin ning\xFAn aviso. NO lo mandes cuando hable del P\xDABLICO COMPRADOR ("esto es para hombres", "mi p\xFAblico son mujeres", "va dirigido a mam\xE1s"): eso es a qui\xE9n se le vende, no qui\xE9n act\xFAa, y fijarlo ah\xED pinea un protagonista que nadie pidi\xF3. "mixed" solo cuando pida expl\xEDcitamente ambos, y ten en cuenta que no garantiza una mezcla: no fija ning\xFAn g\xE9nero y cada creativo elige su protagonista. No lo preguntes como paso obligatorio. Si creativeSetup.presenter.mode="saved_actor", el personaje guardado manda sobre este campo.'),
|
|
30589
30976
|
competitorScanEnabled: CreativeRefs.competitorScanEnabled,
|
|
30590
|
-
replicateWinnerWhenFound:
|
|
30977
|
+
replicateWinnerWhenFound: z126.boolean().optional().describe("Conserva la preferencia de copiar un ganador si existe. false permite estudiar el mercado sin reemplazar un \xE1ngulo por el anuncio ganador. No a\xF1adas una pregunta obligatoria para este campo."),
|
|
30591
30978
|
brandId: CreativeRefs.brandId
|
|
30592
30979
|
}).strict();
|
|
30593
30980
|
var FreeVideoQualityEnum = VideoQualityEnum;
|
|
@@ -30605,7 +30992,7 @@ var FREE_VIDEO_DURATIONS_BY_QUALITY = {
|
|
|
30605
30992
|
length: 29
|
|
30606
30993
|
}, (_, index) => index + 2)
|
|
30607
30994
|
};
|
|
30608
|
-
var FreeVideoModelIdEnum =
|
|
30995
|
+
var FreeVideoModelIdEnum = z126.enum([
|
|
30609
30996
|
"grok-imagine-video-1-5-preview",
|
|
30610
30997
|
"minimax-h3/reference-to-video",
|
|
30611
30998
|
"wan/3-0-video",
|
|
@@ -30616,66 +31003,66 @@ var FREE_SELECTABLE_MODEL_IDS = [
|
|
|
30616
31003
|
"minimax-h3/reference-to-video",
|
|
30617
31004
|
"wan/3-0-video"
|
|
30618
31005
|
];
|
|
30619
|
-
var FreeVideoInput =
|
|
31006
|
+
var FreeVideoInput = z126.object({
|
|
30620
31007
|
images: ImagesInput.optional().describe("Opcional. 1-5 fotos del producto. Om\xEDtelo para generar desde texto puro."),
|
|
30621
|
-
rawPrompt:
|
|
31008
|
+
rawPrompt: z126.string().trim().min(1).max(2e3).describe("Prompt o guion exacto del video. Si activas subt\xEDtulos, este mismo texto se usa como guion de subt\xEDtulos."),
|
|
30622
31009
|
language: CreativeRefs.language,
|
|
30623
31010
|
quality: FreeVideoQualityEnum.describe('Calidad del video: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro (Wan).'),
|
|
30624
31011
|
// Retired in MCP 7.0.0 (Task 11): kept in the schema, accepted, and
|
|
30625
31012
|
// parsed ONLY so the handler can reject it with a message naming its
|
|
30626
31013
|
// replacement — dropping it silently would turn a caller's explicit
|
|
30627
31014
|
// Pro++ pick into a quiet fallback to Wan.
|
|
30628
|
-
freeProModel:
|
|
31015
|
+
freeProModel: z126.enum([
|
|
30629
31016
|
"wan",
|
|
30630
31017
|
"seedance"
|
|
30631
31018
|
]).optional().describe("ELIMINADO en MCP 7.0.0 \u2014 usa `modelId`. Enviar este campo produce un error."),
|
|
30632
31019
|
modelId: FreeVideoModelIdEnum.optional().describe('Opcional. Elige expl\xEDcitamente el modelo del registro en vez del default de la calidad: "grok-imagine-video-1-5-preview" (Grok 1.5), "minimax-h3/reference-to-video" (H3 Max) o "wan/3-0-video" (Wan 3.0). Om\xEDtelo para usar el modelo por defecto de la calidad elegida. El modelo determina la duraci\xF3n permitida (Grok 6/8/10/15s, H3 Max 4-15s, Wan 2-30s) y el precio. "bytedance/seedance-2-5" est\xE1 inactivo y se rechaza con un error claro, nunca un 500.'),
|
|
30633
|
-
durationSeconds:
|
|
31020
|
+
durationSeconds: z126.number().int().min(2).max(30).describe("Duraci\xF3n exacta. Econ\xF3mico: 6, 8, 10 o 15s; Medio: enteros de 4 a 15s; Pro Wan: 2 a 30s; Pro++ Seedance: 4 a 30s."),
|
|
30634
31021
|
videoResolution: VideoResolutionEnum.describe("Resoluci\xF3n del video: 480p o 720p."),
|
|
30635
|
-
generateAiMusic:
|
|
31022
|
+
generateAiMusic: z126.boolean().default(false).describe('Opcional. Agrega m\xFAsica instrumental IA debajo del audio nativo. Default false. Equivale a generateAiEdit (nivel "pro"): la Edici\xF3n con IA trae su propia m\xFAsica.'),
|
|
30636
31023
|
generateAiEdit: AiEditRequestSchema.optional().describe('Opcional. Pide la Edici\xF3n con IA: una pasada que a\xF1ade texto, gr\xE1ficos y m\xFAsica sobre el video ya entregado (variante with_ai_edit; se cobra al entregar). Nivel: "economy" (Econ\xF3mica, Sonnet 5.5, m\xE1s barata) o "pro" (Opus 5.5, mejor calidad, ~10 min). true equivale a "pro". Default sin edici\xF3n.'),
|
|
30637
|
-
addSubtitles:
|
|
30638
|
-
idempotencyKey:
|
|
31024
|
+
addSubtitles: z126.boolean().default(false).describe("Opcional. Quema subt\xEDtulos usando el rawPrompt exacto. Default false."),
|
|
31025
|
+
idempotencyKey: z126.string().uuid().optional().describe("Opcional. Se acepta por compatibilidad pero se ignora: la identidad del reintento se deriva autom\xE1ticamente de los argumentos sem\xE1nticos, as\xED que un retry con los mismos argumentos ya es idempotente sin este campo.")
|
|
30639
31026
|
}).strict();
|
|
30640
31027
|
var imageStyleList = ImageCreativeStyleEnum.options.join(" | ");
|
|
30641
|
-
var ImageCreativeSetup =
|
|
30642
|
-
|
|
30643
|
-
mode:
|
|
31028
|
+
var ImageCreativeSetup = z126.discriminatedUnion("mode", [
|
|
31029
|
+
z126.object({
|
|
31030
|
+
mode: z126.literal("automatic")
|
|
30644
31031
|
}).strict(),
|
|
30645
|
-
|
|
30646
|
-
mode:
|
|
30647
|
-
creativeArchetype:
|
|
31032
|
+
z126.object({
|
|
31033
|
+
mode: z126.literal("guided"),
|
|
31034
|
+
creativeArchetype: z126.union([
|
|
30648
31035
|
ImageCreativeArchetypeEnum,
|
|
30649
|
-
|
|
31036
|
+
z126.literal("ai_decides")
|
|
30650
31037
|
]),
|
|
30651
|
-
visualTreatment:
|
|
31038
|
+
visualTreatment: z126.union([
|
|
30652
31039
|
ImageCreativeVisualTreatmentEnum,
|
|
30653
|
-
|
|
31040
|
+
z126.literal("ai_decides")
|
|
30654
31041
|
]),
|
|
30655
31042
|
aspectRatio: ImageCreativeAspectRatioEnum,
|
|
30656
|
-
nVariants:
|
|
30657
|
-
|
|
30658
|
-
|
|
30659
|
-
|
|
30660
|
-
|
|
30661
|
-
|
|
31043
|
+
nVariants: z126.union([
|
|
31044
|
+
z126.literal(1),
|
|
31045
|
+
z126.literal(2),
|
|
31046
|
+
z126.literal(3),
|
|
31047
|
+
z126.literal(4),
|
|
31048
|
+
z126.literal(6)
|
|
30662
31049
|
]),
|
|
30663
|
-
imageModel:
|
|
30664
|
-
styleMix:
|
|
30665
|
-
generateAdCopy:
|
|
30666
|
-
competitorScanEnabled:
|
|
30667
|
-
productContext:
|
|
30668
|
-
creativeDirection:
|
|
30669
|
-
brandColors:
|
|
30670
|
-
headline:
|
|
30671
|
-
subheadline:
|
|
31050
|
+
imageModel: z126.enum(PUBLIC_IMAGE_QUALITY_INPUTS).describe('Calidad: "image:1k" (Est\xE1ndar) o "image:2k" (Premium). Los tokens gpt-image-2-5:{1k,2k} y gpt-image-2:{1k,2k} se siguen aceptando.'),
|
|
31051
|
+
styleMix: z126.boolean().nullable().describe("Decisi\xF3n s\xF3lo para 2\u20134 variantes. Usa null para 1 o 6, cuando la UI no hace esta pregunta."),
|
|
31052
|
+
generateAdCopy: z126.boolean(),
|
|
31053
|
+
competitorScanEnabled: z126.boolean(),
|
|
31054
|
+
productContext: z126.string().trim().min(1).max(3e3).nullable(),
|
|
31055
|
+
creativeDirection: z126.string().trim().min(1).max(500).nullable(),
|
|
31056
|
+
brandColors: z126.string().trim().min(1).max(240).nullable().describe('Colores en lenguaje natural, igual que en el chat web. Ej. "Azul y Dorado". null significa sin colores espec\xEDficos.'),
|
|
31057
|
+
headline: z126.string().trim().min(1).max(120).nullable(),
|
|
31058
|
+
subheadline: z126.string().trim().min(1).max(160).nullable()
|
|
30672
31059
|
}).strict()
|
|
30673
31060
|
]).superRefine((setup, context) => {
|
|
30674
31061
|
if (setup.mode !== "guided") return;
|
|
30675
31062
|
const needsStyleMix = setup.nVariants >= 2 && setup.nVariants <= 4;
|
|
30676
31063
|
if (needsStyleMix && setup.styleMix === null) {
|
|
30677
31064
|
context.addIssue({
|
|
30678
|
-
code:
|
|
31065
|
+
code: z126.ZodIssueCode.custom,
|
|
30679
31066
|
path: [
|
|
30680
31067
|
"styleMix"
|
|
30681
31068
|
],
|
|
@@ -30684,7 +31071,7 @@ var ImageCreativeSetup = z125.discriminatedUnion("mode", [
|
|
|
30684
31071
|
}
|
|
30685
31072
|
if (!needsStyleMix && setup.styleMix !== null) {
|
|
30686
31073
|
context.addIssue({
|
|
30687
|
-
code:
|
|
31074
|
+
code: z126.ZodIssueCode.custom,
|
|
30688
31075
|
path: [
|
|
30689
31076
|
"styleMix"
|
|
30690
31077
|
],
|
|
@@ -30693,7 +31080,7 @@ var ImageCreativeSetup = z125.discriminatedUnion("mode", [
|
|
|
30693
31080
|
}
|
|
30694
31081
|
if (imageResolutionOf(setup.imageModel) === "2k" && setup.aspectRatio === "4:5") {
|
|
30695
31082
|
context.addIssue({
|
|
30696
|
-
code:
|
|
31083
|
+
code: z126.ZodIssueCode.custom,
|
|
30697
31084
|
path: [
|
|
30698
31085
|
"aspectRatio"
|
|
30699
31086
|
],
|
|
@@ -30701,55 +31088,55 @@ var ImageCreativeSetup = z125.discriminatedUnion("mode", [
|
|
|
30701
31088
|
});
|
|
30702
31089
|
}
|
|
30703
31090
|
});
|
|
30704
|
-
var LandingCreativeSetup =
|
|
30705
|
-
|
|
30706
|
-
mode:
|
|
31091
|
+
var LandingCreativeSetup = z126.discriminatedUnion("mode", [
|
|
31092
|
+
z126.object({
|
|
31093
|
+
mode: z126.literal("automatic")
|
|
30707
31094
|
}).strict(),
|
|
30708
|
-
|
|
30709
|
-
mode:
|
|
31095
|
+
z126.object({
|
|
31096
|
+
mode: z126.literal("guided"),
|
|
30710
31097
|
landingStrategy: LandingStrategyEnum,
|
|
30711
31098
|
landingImageFormat: LandingImageFormatEnum,
|
|
30712
|
-
competitorScanEnabled:
|
|
30713
|
-
paymentMethods:
|
|
30714
|
-
productContext:
|
|
30715
|
-
creativeDirection:
|
|
30716
|
-
headline:
|
|
30717
|
-
subheadline:
|
|
31099
|
+
competitorScanEnabled: z126.boolean(),
|
|
31100
|
+
paymentMethods: z126.string().trim().min(1).max(240).nullable(),
|
|
31101
|
+
productContext: z126.string().trim().min(1).max(3e3).nullable(),
|
|
31102
|
+
creativeDirection: z126.string().trim().min(1).max(500).nullable(),
|
|
31103
|
+
headline: z126.string().trim().min(1).max(120).nullable(),
|
|
31104
|
+
subheadline: z126.string().trim().min(1).max(160).nullable()
|
|
30718
31105
|
}).strict()
|
|
30719
31106
|
]);
|
|
30720
|
-
var ImageInput =
|
|
31107
|
+
var ImageInput = z126.object({
|
|
30721
31108
|
images: CreativeRefs.images.optional(),
|
|
30722
31109
|
winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
|
|
30723
|
-
productTitle:
|
|
30724
|
-
primaryAngle:
|
|
31110
|
+
productTitle: z126.string().min(1).describe('Nombre del producto. Ej. "Crema Anti-Edad Premium".'),
|
|
31111
|
+
primaryAngle: z126.string().min(1).optional().describe('Opcional. \xC1ngulo de venta principal. Si se omite, ProductMaker lo genera y creativeSetup.mode="guided" lo muestra para revisi\xF3n antes de crear las im\xE1genes.'),
|
|
30725
31112
|
buyerPersona: CreativeRefs.buyerPersona,
|
|
30726
31113
|
language: CreativeRefs.language,
|
|
30727
31114
|
country: CreativeRefs.country,
|
|
30728
31115
|
creativeSetup: ImageCreativeSetup.describe("Configuraci\xF3n obligatoria equivalente al wizard web. Usa guided salvo que el usuario delegue expl\xEDcitamente todo; presenta las decisiones guiadas en un \xFAnico checklist compacto."),
|
|
30729
31116
|
imageStyle: ImageCreativeStyleEnum.optional().describe(`Opcional. Estilo del shot del producto. Valores: ${imageStyleList}. Si se omite, la IA escoge seg\xFAn el archetype.`),
|
|
30730
|
-
features:
|
|
31117
|
+
features: z126.array(z126.string()).optional().describe('Opcional. Features/beneficios a destacar visualmente. Ej. ["resistente al agua", "ultra liviano"].'),
|
|
30731
31118
|
price: CreativeRefs.price,
|
|
30732
|
-
omitPrice:
|
|
31119
|
+
omitPrice: z126.boolean().optional().describe("Pon true \xFAnicamente cuando el usuario pida expl\xEDcitamente una imagen sin precio. Evita que el backend reutilice un precio extra\xEDdo del producto. No lo combines con price ni compareAtPrice."),
|
|
30733
31120
|
compareAtPrice: CreativeRefs.compareAtPrice,
|
|
30734
31121
|
offer: CreativeRefs.offer,
|
|
30735
31122
|
productLabel: CreativeRefs.productLabel,
|
|
30736
31123
|
isCombo: CreativeRefs.isCombo,
|
|
30737
31124
|
brandId: CreativeRefs.brandId
|
|
30738
31125
|
});
|
|
30739
|
-
var EditImageCreativeInput =
|
|
30740
|
-
taskId:
|
|
30741
|
-
variantIndex:
|
|
30742
|
-
clientRequestId:
|
|
30743
|
-
instruction:
|
|
31126
|
+
var EditImageCreativeInput = z126.object({
|
|
31127
|
+
taskId: z126.string().uuid().describe("ID de la tarea de imagen ya finalizada."),
|
|
31128
|
+
variantIndex: z126.number().int().min(0).max(10).describe("\xCDndice de la variante a corregir (0 = primera imagen)."),
|
|
31129
|
+
clientRequestId: z126.string().min(1).max(160).optional().describe("Identidad estable de esta correcci\xF3n; reutil\xEDzala al reconciliar una respuesta perdida, no para otra instrucci\xF3n."),
|
|
31130
|
+
instruction: z126.string().min(1).max(1e3).describe('Qu\xE9 cambiar en esa imagen. Ej. "quita el badge de env\xEDo gratis", "cambia el fondo a blanco".')
|
|
30744
31131
|
});
|
|
30745
|
-
var LandingInput =
|
|
30746
|
-
includeInitialLandingGif:
|
|
31132
|
+
var LandingInput = z126.object({
|
|
31133
|
+
includeInitialLandingGif: z126.boolean().optional().describe("Opcional. En nuevas landings cl\xE1sicas habilitadas, omitirlo incluye el primer GIF del producto y su coste en el total. Env\xEDa false si el usuario lo excluye: no se genera ni se reserva su coste. Conserva la elecci\xF3n al confirmar y al reintentar."),
|
|
30747
31134
|
images: CreativeRefs.images.optional(),
|
|
30748
31135
|
winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
|
|
30749
31136
|
language: CreativeRefs.language,
|
|
30750
31137
|
country: CreativeRefs.country,
|
|
30751
31138
|
creativeSetup: LandingCreativeSetup.describe("Configuraci\xF3n obligatoria de landing cl\xE1sica equivalente al wizard web. No expone landing editable/code mientras siga siendo admin-only."),
|
|
30752
|
-
salesAngle:
|
|
31139
|
+
salesAngle: z126.string().optional().describe('Opcional. \xC1ngulo de venta principal. Ej. "Reduce arrugas en 14 d\xEDas". Si se omite, la IA lo deduce de la imagen.'),
|
|
30753
31140
|
buyerPersona: CreativeRefs.buyerPersona,
|
|
30754
31141
|
price: CreativeRefs.price,
|
|
30755
31142
|
compareAtPrice: CreativeRefs.compareAtPrice,
|
|
@@ -31031,8 +31418,8 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
|
|
|
31031
31418
|
server.registerTool("get_image_edit_status", {
|
|
31032
31419
|
description: imageEditStatusGuidance.summary,
|
|
31033
31420
|
inputSchema: {
|
|
31034
|
-
taskId:
|
|
31035
|
-
operationId:
|
|
31421
|
+
taskId: z126.string().uuid(),
|
|
31422
|
+
operationId: z126.string().uuid()
|
|
31036
31423
|
},
|
|
31037
31424
|
annotations: READS_INTERNAL
|
|
31038
31425
|
}, async (input) => {
|
|
@@ -31089,10 +31476,10 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
|
|
|
31089
31476
|
__name(registerCreativeTools, "registerCreativeTools");
|
|
31090
31477
|
|
|
31091
31478
|
// src/tools/creative-variants.ts
|
|
31092
|
-
import { z as
|
|
31479
|
+
import { z as z127 } from "zod";
|
|
31093
31480
|
var estimateCreativeVariantGuidance = getProductMakerCapabilityModelGuidance("estimate_creative_variant");
|
|
31094
31481
|
var createCreativeVariantGuidance = getProductMakerCapabilityModelGuidance("create_creative_variant");
|
|
31095
|
-
var LandingSectionKeyEnum =
|
|
31482
|
+
var LandingSectionKeyEnum = z127.enum([
|
|
31096
31483
|
"problem_hook",
|
|
31097
31484
|
"problem_cost",
|
|
31098
31485
|
"solution_mechanism",
|
|
@@ -31132,24 +31519,24 @@ var LandingSectionKeyEnum = z126.enum([
|
|
|
31132
31519
|
"lifestyle_fit",
|
|
31133
31520
|
"join_lifestyle"
|
|
31134
31521
|
]);
|
|
31135
|
-
var CreativeVariantKindEnum =
|
|
31522
|
+
var CreativeVariantKindEnum = z127.enum([
|
|
31136
31523
|
"video",
|
|
31137
31524
|
"image",
|
|
31138
31525
|
"landing"
|
|
31139
31526
|
]);
|
|
31140
|
-
var EstimateCreativeVariantInputBase =
|
|
31141
|
-
sourceTaskId:
|
|
31527
|
+
var EstimateCreativeVariantInputBase = z127.object({
|
|
31528
|
+
sourceTaskId: z127.string().uuid().describe("ID de la tarea original completada."),
|
|
31142
31529
|
kind: CreativeVariantKindEnum,
|
|
31143
31530
|
videoPreset: TaskCreativeVariantVideoPresetEnum.optional().describe("Opcional para video. Solo cambia el preset p\xFAblico; el servidor conserva el modelo/tier del task origen."),
|
|
31144
31531
|
videoResolution: VideoResolutionEnum.optional().describe("Opcional para video. Resoluci\xF3n del nuevo render."),
|
|
31145
|
-
nVariants:
|
|
31532
|
+
nVariants: z127.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
|
|
31146
31533
|
sectionKey: LandingSectionKeyEnum.optional().describe("Opcional para landing. Si ya conoces la secci\xF3n, evita cotizar la clasificaci\xF3n con IA."),
|
|
31147
|
-
instructions:
|
|
31534
|
+
instructions: z127.string().trim().min(1).max(2e3).optional().describe("Opcional para landing. Si se env\xEDa sin sectionKey, el estimado suma la clasificaci\xF3n pagada con IA.")
|
|
31148
31535
|
}).strict();
|
|
31149
31536
|
var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine((input, ctx) => {
|
|
31150
31537
|
if (input.kind === "video" && input.nVariants !== void 0) {
|
|
31151
31538
|
ctx.addIssue({
|
|
31152
|
-
code:
|
|
31539
|
+
code: z127.ZodIssueCode.custom,
|
|
31153
31540
|
path: [
|
|
31154
31541
|
"nVariants"
|
|
31155
31542
|
],
|
|
@@ -31159,7 +31546,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
|
|
|
31159
31546
|
if (input.kind !== "video") {
|
|
31160
31547
|
if (input.videoPreset !== void 0) {
|
|
31161
31548
|
ctx.addIssue({
|
|
31162
|
-
code:
|
|
31549
|
+
code: z127.ZodIssueCode.custom,
|
|
31163
31550
|
path: [
|
|
31164
31551
|
"videoPreset"
|
|
31165
31552
|
],
|
|
@@ -31168,7 +31555,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
|
|
|
31168
31555
|
}
|
|
31169
31556
|
if (input.videoResolution !== void 0) {
|
|
31170
31557
|
ctx.addIssue({
|
|
31171
|
-
code:
|
|
31558
|
+
code: z127.ZodIssueCode.custom,
|
|
31172
31559
|
path: [
|
|
31173
31560
|
"videoResolution"
|
|
31174
31561
|
],
|
|
@@ -31178,7 +31565,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
|
|
|
31178
31565
|
}
|
|
31179
31566
|
if (input.kind !== "image" && input.nVariants !== void 0) {
|
|
31180
31567
|
ctx.addIssue({
|
|
31181
|
-
code:
|
|
31568
|
+
code: z127.ZodIssueCode.custom,
|
|
31182
31569
|
path: [
|
|
31183
31570
|
"nVariants"
|
|
31184
31571
|
],
|
|
@@ -31188,7 +31575,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
|
|
|
31188
31575
|
if (input.kind !== "landing") {
|
|
31189
31576
|
if (input.sectionKey !== void 0) {
|
|
31190
31577
|
ctx.addIssue({
|
|
31191
|
-
code:
|
|
31578
|
+
code: z127.ZodIssueCode.custom,
|
|
31192
31579
|
path: [
|
|
31193
31580
|
"sectionKey"
|
|
31194
31581
|
],
|
|
@@ -31197,7 +31584,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
|
|
|
31197
31584
|
}
|
|
31198
31585
|
if (input.instructions !== void 0) {
|
|
31199
31586
|
ctx.addIssue({
|
|
31200
|
-
code:
|
|
31587
|
+
code: z127.ZodIssueCode.custom,
|
|
31201
31588
|
path: [
|
|
31202
31589
|
"instructions"
|
|
31203
31590
|
],
|
|
@@ -31206,31 +31593,31 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
|
|
|
31206
31593
|
}
|
|
31207
31594
|
}
|
|
31208
31595
|
});
|
|
31209
|
-
var CreateCreativeVariantInputBase =
|
|
31210
|
-
sourceTaskId:
|
|
31596
|
+
var CreateCreativeVariantInputBase = z127.object({
|
|
31597
|
+
sourceTaskId: z127.string().uuid().describe("ID de la tarea original completada."),
|
|
31211
31598
|
kind: CreativeVariantKindEnum,
|
|
31212
|
-
confirm:
|
|
31213
|
-
clientRequestId:
|
|
31214
|
-
angle:
|
|
31215
|
-
buyerPersona:
|
|
31216
|
-
scriptNotes:
|
|
31217
|
-
creativeDirection:
|
|
31599
|
+
confirm: z127.literal(true).describe("Confirmaci\xF3n expl\xEDcita del usuario despu\xE9s de mostrarle el estimado de cr\xE9ditos."),
|
|
31600
|
+
clientRequestId: z127.string().uuid().describe("UUID estable para esta intenci\xF3n (obligatorio por compatibilidad de contrato; el servidor deriva la identidad real del request desde los argumentos sem\xE1nticos, as\xED que un UUID nuevo en un retry NO crea una variante duplicada). Si la API devuelve status=error, una nueva generaci\xF3n exige otra confirmaci\xF3n."),
|
|
31601
|
+
angle: z127.string().trim().min(1).max(500).optional().describe("\xC1ngulo nuevo para video o imagen."),
|
|
31602
|
+
buyerPersona: z127.string().trim().min(1).max(360).optional().describe("Buyer persona coherente con el \xE1ngulo."),
|
|
31603
|
+
scriptNotes: z127.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n breve del guion para una variante de video."),
|
|
31604
|
+
creativeDirection: z127.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n creativa para una variante de imagen."),
|
|
31218
31605
|
videoPreset: TaskCreativeVariantVideoPresetEnum.optional().describe("Opcional para video. Preset p\xFAblico; el servidor resuelve modelo/tier desde el task origen."),
|
|
31219
31606
|
videoResolution: VideoResolutionEnum.optional().describe("Opcional para video."),
|
|
31220
|
-
generateAiMusic:
|
|
31221
|
-
nVariants:
|
|
31607
|
+
generateAiMusic: z127.boolean().optional().describe("Opcional para video."),
|
|
31608
|
+
nVariants: z127.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
|
|
31222
31609
|
imageStyle: ImageCreativeStyleEnum.optional().describe("Opcional para imagen."),
|
|
31223
31610
|
creativeArchetype: ImageCreativeArchetypeEnum.optional().describe("Opcional para imagen."),
|
|
31224
31611
|
visualTreatment: ImageCreativeVisualTreatmentEnum.optional().describe("Opcional para imagen."),
|
|
31225
31612
|
aspectRatio: ImageCreativeAspectRatioEnum.optional().describe("Opcional para imagen."),
|
|
31226
|
-
styleMix:
|
|
31613
|
+
styleMix: z127.boolean().optional().describe("Opcional para imagen."),
|
|
31227
31614
|
sectionKey: LandingSectionKeyEnum.optional().describe("Opcional para landing. Si se omite, se clasifica con IA a partir de instructions."),
|
|
31228
|
-
instructions:
|
|
31615
|
+
instructions: z127.string().trim().min(1).max(2e3).optional().describe("Solicitud libre para una nueva secci\xF3n de landing. La IA la clasifica si no env\xEDas sectionKey.")
|
|
31229
31616
|
}).strict();
|
|
31230
31617
|
var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((input, ctx) => {
|
|
31231
31618
|
if ((input.kind === "video" || input.kind === "image") && !input.angle) {
|
|
31232
31619
|
ctx.addIssue({
|
|
31233
|
-
code:
|
|
31620
|
+
code: z127.ZodIssueCode.custom,
|
|
31234
31621
|
path: [
|
|
31235
31622
|
"angle"
|
|
31236
31623
|
],
|
|
@@ -31239,7 +31626,7 @@ var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((inp
|
|
|
31239
31626
|
}
|
|
31240
31627
|
if (input.kind === "landing" && !input.sectionKey && !input.instructions) {
|
|
31241
31628
|
ctx.addIssue({
|
|
31242
|
-
code:
|
|
31629
|
+
code: z127.ZodIssueCode.custom,
|
|
31243
31630
|
path: [
|
|
31244
31631
|
"instructions"
|
|
31245
31632
|
],
|
|
@@ -31285,7 +31672,7 @@ var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((inp
|
|
|
31285
31672
|
for (const field of fieldsByKind[input.kind]) {
|
|
31286
31673
|
if (input[field] !== void 0) {
|
|
31287
31674
|
ctx.addIssue({
|
|
31288
|
-
code:
|
|
31675
|
+
code: z127.ZodIssueCode.custom,
|
|
31289
31676
|
path: [
|
|
31290
31677
|
field
|
|
31291
31678
|
],
|
|
@@ -31341,8 +31728,10 @@ function registerCreativeVariantTools(server, api) {
|
|
|
31341
31728
|
inputSchema: CreateCreativeVariantInputBase.shape,
|
|
31342
31729
|
annotations: CREATES_PAID
|
|
31343
31730
|
}, async (input) => {
|
|
31731
|
+
let sourceTaskId;
|
|
31344
31732
|
try {
|
|
31345
31733
|
const validatedInput = parseVariantInput(CreateCreativeVariantInput, input);
|
|
31734
|
+
sourceTaskId = validatedInput.sourceTaskId;
|
|
31346
31735
|
const estimateInput = EstimateCreativeVariantInput.parse({
|
|
31347
31736
|
sourceTaskId: validatedInput.sourceTaskId,
|
|
31348
31737
|
kind: validatedInput.kind,
|
|
@@ -31353,7 +31742,7 @@ function registerCreativeVariantTools(server, api) {
|
|
|
31353
31742
|
instructions: validatedInput.instructions
|
|
31354
31743
|
});
|
|
31355
31744
|
const estimate = await api.postJson(`/v1/tasks/${encodeURIComponent(validatedInput.sourceTaskId)}/creative-variants/estimate`, estimatePayload(estimateInput));
|
|
31356
|
-
if (!estimate.hasSufficientBalance) {
|
|
31745
|
+
if (validatedInput.kind === "landing" && !validatedInput.sectionKey && !estimate.hasSufficientBalance) {
|
|
31357
31746
|
throw mcp(McpErrorCode.INSUFFICIENT_CREDITS, `Saldo insuficiente. La variante requiere hasta ${estimate.estimatedMaxCostCredits} cr\xE9ditos y tu saldo es ${estimate.userBalanceCredits}.`);
|
|
31358
31747
|
}
|
|
31359
31748
|
let sectionKey = validatedInput.sectionKey;
|
|
@@ -31411,20 +31800,43 @@ function registerCreativeVariantTools(server, api) {
|
|
|
31411
31800
|
estimate
|
|
31412
31801
|
});
|
|
31413
31802
|
} catch (error) {
|
|
31414
|
-
|
|
31803
|
+
const translated = translateError(error);
|
|
31804
|
+
if (!sourceTaskId) throw translated;
|
|
31805
|
+
const details = isRecord3(translated.data) ? translated.data : {};
|
|
31806
|
+
return {
|
|
31807
|
+
...asText({
|
|
31808
|
+
error: {
|
|
31809
|
+
code: typeof details.code === "string" ? details.code : McpErrorCode.INTERNAL,
|
|
31810
|
+
message: translated.message,
|
|
31811
|
+
...typeof details.variantTaskId === "string" ? {
|
|
31812
|
+
variantTaskId: details.variantTaskId
|
|
31813
|
+
} : {}
|
|
31814
|
+
},
|
|
31815
|
+
// A classification or transport failure does not prove that no
|
|
31816
|
+
// child was admitted. Inspect owned children before another buy.
|
|
31817
|
+
nextAction: {
|
|
31818
|
+
tool: "get_task_status",
|
|
31819
|
+
arguments: {
|
|
31820
|
+
taskId: sourceTaskId
|
|
31821
|
+
},
|
|
31822
|
+
instruction: "Revisa las variantes de la tarea original antes de iniciar otro intento pagado. No crees otra variante autom\xE1ticamente."
|
|
31823
|
+
}
|
|
31824
|
+
}),
|
|
31825
|
+
isError: true
|
|
31826
|
+
};
|
|
31415
31827
|
}
|
|
31416
31828
|
});
|
|
31417
31829
|
}
|
|
31418
31830
|
__name(registerCreativeVariantTools, "registerCreativeVariantTools");
|
|
31419
31831
|
|
|
31420
31832
|
// src/tools/script-review.ts
|
|
31421
|
-
import { z as
|
|
31833
|
+
import { z as z128 } from "zod";
|
|
31422
31834
|
var getVideoScriptGuidance = getProductMakerCapabilityModelGuidance("get_video_script");
|
|
31423
31835
|
var regenerateVideoScriptGuidance = getProductMakerCapabilityModelGuidance("regenerate_video_script");
|
|
31424
31836
|
var approveVideoScriptGuidance = getProductMakerCapabilityModelGuidance("approve_video_script");
|
|
31425
|
-
var GetVideoScriptInput =
|
|
31426
|
-
taskId:
|
|
31427
|
-
angleKey:
|
|
31837
|
+
var GetVideoScriptInput = z128.object({
|
|
31838
|
+
taskId: z128.string().min(1).describe("ID de la tarea (la misma que devolvi\xF3 create_product_task / generate_video_creative)."),
|
|
31839
|
+
angleKey: z128.string().min(1).optional().describe('Clave persistida del \xE1ngulo cuyo guion se quiere leer (formato "angle_0", "angle_1", ...). Usa exactamente el angleKey recibido en reviewNextAction.calls al aprobar \xE1ngulos, incluso si s\xF3lo elegiste uno. Si se omite, el backend resuelve a "angle_0" literal; elegir el segundo candidato no crea angle_0. No derives esta clave del n\xFAmero visible del candidato.')
|
|
31428
31840
|
}).strict();
|
|
31429
31841
|
var ApproveVideoScriptInput = ApproveVideoScriptCapabilityRequest;
|
|
31430
31842
|
var RegenerateVideoScriptInput = RegenerateVideoScriptCapabilityRequest.extend({
|
|
@@ -31432,7 +31844,7 @@ var RegenerateVideoScriptInput = RegenerateVideoScriptCapabilityRequest.extend({
|
|
|
31432
31844
|
});
|
|
31433
31845
|
function registerScriptReviewTools(server, api) {
|
|
31434
31846
|
server.registerTool("get_video_script", {
|
|
31435
|
-
description: getVideoScriptGuidance.summary + ' S\xF3lo funciona cuando la tarea fue creada con `pauseForVideoScriptReview: true` (via generate_video_creative). Devuelve { status, angleKey, perClipSeconds?, scenes: [{ index, dialogue, maxWords, minWords?, beatId?, persuasiveFunction?, winnerVisual?, expectedVisual? }], error? }. En escenas copiadas de un winner, `persuasiveFunction` explica qu\xE9 logra ese beat, `winnerVisual` conserva la observaci\xF3n fuente y `expectedVisual` describe nuestra adaptaci\xF3n localizada; muestra los tres junto al di\xE1logo para que una edici\xF3n no desaline\xE9 guion y visual. El campo `error` (cuando viene con status="ready") es el motivo legible por el que un intento previo de aprobaci\xF3n fue rechazado; mu\xE9straselo al usuario.\n\nREGLA DURA: status="ready" es un estado terminal de interacci\xF3n. Presenta el guion una sola vez y NO vuelvas a llamar get_video_script ni get_task_status hasta que el usuario responda aprobar, editar o regenerar. La respuesta a\xF1ade interactionState="awaiting_user_review" y nextAction="present_script_and_wait".\n\nCU\xC1NDO LLAMAR: no existe un status top-level "awaiting_script_review" en get_task_status. Si la tarea fue creada con pauseForVideoScriptReview=true, polea get_task_status hasta que `status === "processing"` y llama este tool; su campo `status` es la se\xF1al real:\n- "ready" \u2192 presenta todas las escenas y DETENTE hasta la respuesta del usuario.\n- "not_ready" \u2192 espera 5\u201310s y reintenta este tool.\n- "approved" \u2192 ya fue aprobado; en multi-angle consulta otro angleKey.\n- "skipped" \u2192 el usuario opt\xF3 por no revisar.\n- "error" \u2192
|
|
31847
|
+
description: getVideoScriptGuidance.summary + ' S\xF3lo funciona cuando la tarea fue creada con `pauseForVideoScriptReview: true` (via generate_video_creative). Devuelve { status, angleKey, perClipSeconds?, scenes: [{ index, dialogue, maxWords, minWords?, beatId?, persuasiveFunction?, winnerVisual?, expectedVisual? }], error? }. En escenas copiadas de un winner, `persuasiveFunction` explica qu\xE9 logra ese beat, `winnerVisual` conserva la observaci\xF3n fuente y `expectedVisual` describe nuestra adaptaci\xF3n localizada; muestra los tres junto al di\xE1logo para que una edici\xF3n no desaline\xE9 guion y visual. El campo `error` (cuando viene con status="ready") es el motivo legible por el que un intento previo de aprobaci\xF3n fue rechazado; mu\xE9straselo al usuario.\n\nREGLA DURA: status="ready" es un estado terminal de interacci\xF3n. Presenta el guion una sola vez y NO vuelvas a llamar get_video_script ni get_task_status hasta que el usuario responda aprobar, editar o regenerar. La respuesta a\xF1ade interactionState="awaiting_user_review" y nextAction="present_script_and_wait".\n\nCU\xC1NDO LLAMAR: no existe un status top-level "awaiting_script_review" en get_task_status. Si la tarea fue creada con pauseForVideoScriptReview=true, polea get_task_status hasta que `status === "processing"` y llama este tool; su campo `status` es la se\xF1al real:\n- "ready" \u2192 presenta todas las escenas y DETENTE hasta la respuesta del usuario.\n- "not_ready" \u2192 espera 5\u201310s y reintenta este tool.\n- "approved" \u2192 ya fue aprobado; en multi-angle consulta otro angleKey.\n- "skipped" \u2192 el usuario opt\xF3 por no revisar.\n- "error" \u2192 consulta `get_task_status` antes de ofrecer recuperaci\xF3n. No regeneres autom\xE1ticamente una tarea terminal.\n\nANGLE KEY: usa las claves expl\xEDcitas de reviewNextAction.calls, incluso si s\xF3lo seleccionaste un candidato. Cuando uno est\xE9 ready, detente en ese \xE1ngulo y espera la decisi\xF3n antes de consultar otro.',
|
|
31436
31848
|
inputSchema: GetVideoScriptInput.shape,
|
|
31437
31849
|
annotations: READS_INTERNAL
|
|
31438
31850
|
}, async (input) => {
|
|
@@ -31440,6 +31852,28 @@ function registerScriptReviewTools(server, api) {
|
|
|
31440
31852
|
const qs = input.angleKey ? `?angleKey=${encodeURIComponent(input.angleKey)}` : "";
|
|
31441
31853
|
const r = await api.getJson(`/v1/tasks/${encodeURIComponent(input.taskId)}/video-script${qs}`);
|
|
31442
31854
|
const review = renderVideoScriptMarkdown(r);
|
|
31855
|
+
if (review && typeof r === "object" && r !== null && "status" in r && r.status === "error") {
|
|
31856
|
+
const error = "error" in r && typeof r.error === "string" ? escapeMarkdownText(r.error) : "No se pudo preparar este guion.";
|
|
31857
|
+
return {
|
|
31858
|
+
content: [
|
|
31859
|
+
{
|
|
31860
|
+
type: "text",
|
|
31861
|
+
text: `## No se pudo preparar el guion
|
|
31862
|
+
|
|
31863
|
+
${error}
|
|
31864
|
+
|
|
31865
|
+
Consulta get_task_status con esta tarea antes de reintentar. Si la tarea termin\xF3 en error, sigue su recuperaci\xF3n; si sigue activa y s\xF3lo fall\xF3 el guion, ofrece regenerarlo con confirmaci\xF3n del usuario. No inicies una regeneraci\xF3n pagada autom\xE1ticamente.`
|
|
31866
|
+
}
|
|
31867
|
+
],
|
|
31868
|
+
structuredContent: {
|
|
31869
|
+
...r,
|
|
31870
|
+
nextAction: "get_task_status",
|
|
31871
|
+
nextActionArguments: {
|
|
31872
|
+
taskId: input.taskId
|
|
31873
|
+
}
|
|
31874
|
+
}
|
|
31875
|
+
};
|
|
31876
|
+
}
|
|
31443
31877
|
return review ? {
|
|
31444
31878
|
content: [
|
|
31445
31879
|
{
|
|
@@ -31468,7 +31902,7 @@ function registerScriptReviewTools(server, api) {
|
|
|
31468
31902
|
}
|
|
31469
31903
|
});
|
|
31470
31904
|
server.registerTool("regenerate_video_script", {
|
|
31471
|
-
description: regenerateVideoScriptGuidance.summary + ' \xDAsalo cuando:\n- get_video_script devuelve status="error"
|
|
31905
|
+
description: regenerateVideoScriptGuidance.summary + ' \xDAsalo cuando:\n- get_video_script devuelve status="error", get_task_status confirma que la tarea sigue activa y el usuario confirma reintentar el guion.\n- El usuario rechaza el guion entero y prefiere reintentar (no editar l\xEDnea por l\xEDnea).\n- Quieres probar otra narrativa (pasa `narrativeStyle`).\n\nFlujo: llama este tool \u2192 polea get_video_script hasta que vuelva a status="ready" \u2192 mu\xE9strale el nuevo guion al usuario \u2192 approve_video_script.\n\nIMPORTANTE: regenerar CUESTA cr\xE9ditos de LLM. No lo invoques sin confirmaci\xF3n del usuario, incluso si el guion est\xE1 en error. Para una tarea terminal, sigue primero la recuperaci\xF3n de get_task_status.\n\nMULTI-ANGLE: pasa el mismo `angleKey` que usaste con get_video_script.',
|
|
31472
31906
|
inputSchema: RegenerateVideoScriptInput.shape,
|
|
31473
31907
|
annotations: OVERWRITES_EXTERNAL
|
|
31474
31908
|
}, async (input) => {
|
|
@@ -31507,7 +31941,7 @@ function registerScriptReviewTools(server, api) {
|
|
|
31507
31941
|
__name(registerScriptReviewTools, "registerScriptReviewTools");
|
|
31508
31942
|
|
|
31509
31943
|
// src/tools/connections.ts
|
|
31510
|
-
import { z as
|
|
31944
|
+
import { z as z129 } from "zod";
|
|
31511
31945
|
var listShopifyShopsGuidance = getProductMakerCapabilityModelGuidance("list_shopify_shops");
|
|
31512
31946
|
var listShopifyProductsGuidance = getProductMakerCapabilityModelGuidance("list_shopify_products");
|
|
31513
31947
|
var listMetaAdAccountsGuidance = getProductMakerCapabilityModelGuidance("list_meta_ad_accounts");
|
|
@@ -31516,7 +31950,7 @@ var listTikTokAdvertisersGuidance = getProductMakerCapabilityModelGuidance("list
|
|
|
31516
31950
|
function registerConnectionTools(server, api) {
|
|
31517
31951
|
server.registerTool("list_shopify_shops", {
|
|
31518
31952
|
description: listShopifyShopsGuidance.summary + " Si la lista est\xE1 vac\xEDa, dile al usuario que conecte una tienda en productmaker.app/integrations antes de intentar publicar.",
|
|
31519
|
-
inputSchema:
|
|
31953
|
+
inputSchema: z129.object({}).shape,
|
|
31520
31954
|
annotations: READS_INTERNAL
|
|
31521
31955
|
}, async () => {
|
|
31522
31956
|
try {
|
|
@@ -31528,10 +31962,10 @@ function registerConnectionTools(server, api) {
|
|
|
31528
31962
|
});
|
|
31529
31963
|
server.registerTool("list_shopify_products", {
|
|
31530
31964
|
description: listShopifyProductsGuidance.summary + ' Usa el `id` devuelto junto con `publicationMode="existing"` en `publish_to_shopify`. Si `taskId` se proporciona, la respuesta tambi\xE9n indica el producto publicado actualmente para esa tarea y tienda. No modifica Shopify.',
|
|
31531
|
-
inputSchema:
|
|
31532
|
-
shopDomain:
|
|
31533
|
-
query:
|
|
31534
|
-
taskId:
|
|
31965
|
+
inputSchema: z129.object({
|
|
31966
|
+
shopDomain: z129.string().min(3).max(120),
|
|
31967
|
+
query: z129.string().trim().max(120).optional(),
|
|
31968
|
+
taskId: z129.string().uuid().optional()
|
|
31535
31969
|
}).shape,
|
|
31536
31970
|
annotations: READS_EXTERNAL
|
|
31537
31971
|
}, async ({ shopDomain, query, taskId }) => {
|
|
@@ -31549,7 +31983,7 @@ function registerConnectionTools(server, api) {
|
|
|
31549
31983
|
});
|
|
31550
31984
|
server.registerTool("list_meta_ad_accounts", {
|
|
31551
31985
|
description: listMetaAdAccountsGuidance.summary + " Para publicar, prefiere `list_meta_destinations`, que tambi\xE9n devuelve el portfolio y las p\xE1ginas disponibles. Si est\xE1 vac\xEDa, ind\xEDcale al usuario conectar Meta en productmaker.app/integrations.",
|
|
31552
|
-
inputSchema:
|
|
31986
|
+
inputSchema: z129.object({}).shape,
|
|
31553
31987
|
annotations: READS_EXTERNAL
|
|
31554
31988
|
}, async () => {
|
|
31555
31989
|
try {
|
|
@@ -31561,7 +31995,7 @@ function registerConnectionTools(server, api) {
|
|
|
31561
31995
|
});
|
|
31562
31996
|
server.registerTool("list_meta_destinations", {
|
|
31563
31997
|
description: listMetaDestinationsGuidance.summary + " Es obligatorio llamar esta herramienta antes de publicar, mostrar las opciones y enviar al publicador el `portfolioId`, `adAccountId` y `pageId` elegidos; nunca elijas silenciosamente la primera p\xE1gina o cuenta. No modifica Meta.",
|
|
31564
|
-
inputSchema:
|
|
31998
|
+
inputSchema: z129.object({}).shape,
|
|
31565
31999
|
annotations: READS_EXTERNAL,
|
|
31566
32000
|
_meta: {
|
|
31567
32001
|
"openai/widgetAccessible": true
|
|
@@ -31576,7 +32010,7 @@ function registerConnectionTools(server, api) {
|
|
|
31576
32010
|
});
|
|
31577
32011
|
server.registerTool("list_tiktok_advertisers", {
|
|
31578
32012
|
description: listTikTokAdvertisersGuidance.summary + " Si est\xE1 vac\xEDa, ind\xEDcale al usuario conectar TikTok en productmaker.app/integrations.",
|
|
31579
|
-
inputSchema:
|
|
32013
|
+
inputSchema: z129.object({}).shape,
|
|
31580
32014
|
annotations: READS_EXTERNAL
|
|
31581
32015
|
}, async () => {
|
|
31582
32016
|
try {
|
|
@@ -31590,7 +32024,7 @@ function registerConnectionTools(server, api) {
|
|
|
31590
32024
|
__name(registerConnectionTools, "registerConnectionTools");
|
|
31591
32025
|
|
|
31592
32026
|
// src/tools/actors.ts
|
|
31593
|
-
import { z as
|
|
32027
|
+
import { z as z130 } from "zod";
|
|
31594
32028
|
var listActorsGuidance = getProductMakerCapabilityModelGuidance("list_actors");
|
|
31595
32029
|
var actorVoiceGuidance = {
|
|
31596
32030
|
capabilities: getProductMakerCapabilityModelGuidance("get_actor_voice_capabilities"),
|
|
@@ -31630,7 +32064,7 @@ function sanitizeVoiceResult(value) {
|
|
|
31630
32064
|
__name(sanitizeVoiceResult, "sanitizeVoiceResult");
|
|
31631
32065
|
function registerActorTools(server, api) {
|
|
31632
32066
|
const actor = {
|
|
31633
|
-
actorId:
|
|
32067
|
+
actorId: z130.string().min(1).max(64)
|
|
31634
32068
|
};
|
|
31635
32069
|
const safe = /* @__PURE__ */ __name(async (request) => {
|
|
31636
32070
|
try {
|
|
@@ -31659,8 +32093,8 @@ function registerActorTools(server, api) {
|
|
|
31659
32093
|
inputSchema: {
|
|
31660
32094
|
...actor,
|
|
31661
32095
|
draft: ActorVoiceDraftSchema,
|
|
31662
|
-
requestKey:
|
|
31663
|
-
acceptedQuoteId:
|
|
32096
|
+
requestKey: z130.string().trim().min(1).max(128),
|
|
32097
|
+
acceptedQuoteId: z130.string().trim().min(1).max(128)
|
|
31664
32098
|
},
|
|
31665
32099
|
annotations: CREATES_PAID
|
|
31666
32100
|
}, async ({ actorId, ...body }) => safe(api.postJson(`/v1/actors/${encodeURIComponent(actorId)}/voice/previews`, body)));
|
|
@@ -31668,7 +32102,7 @@ function registerActorTools(server, api) {
|
|
|
31668
32102
|
description: actorVoiceGuidance.get.summary,
|
|
31669
32103
|
inputSchema: {
|
|
31670
32104
|
...actor,
|
|
31671
|
-
candidateId:
|
|
32105
|
+
candidateId: z130.string().min(1).max(64)
|
|
31672
32106
|
},
|
|
31673
32107
|
// Polling can resume the first paid submission of an accepted quote.
|
|
31674
32108
|
// The immutable candidate/operation key keeps recovery idempotent.
|
|
@@ -31681,16 +32115,16 @@ function registerActorTools(server, api) {
|
|
|
31681
32115
|
description: actorVoiceGuidance.approve.summary,
|
|
31682
32116
|
inputSchema: {
|
|
31683
32117
|
...actor,
|
|
31684
|
-
candidateId:
|
|
31685
|
-
expectedRevision:
|
|
31686
|
-
expectedApprovedRevision:
|
|
32118
|
+
candidateId: z130.string().min(1).max(64),
|
|
32119
|
+
expectedRevision: z130.number().int().positive(),
|
|
32120
|
+
expectedApprovedRevision: z130.number().int().positive().nullable().optional()
|
|
31687
32121
|
},
|
|
31688
32122
|
// Replaces the selected voice and withdraws the old catalog grants.
|
|
31689
32123
|
annotations: OVERWRITES_INTERNAL
|
|
31690
32124
|
}, async ({ actorId, ...body }) => safe(api.postJson(`/v1/actors/${encodeURIComponent(actorId)}/voice/approve`, body)));
|
|
31691
32125
|
server.registerTool("list_actors", {
|
|
31692
32126
|
description: listActorsGuidance.summary + " Devuelve id, nombre, descripci\xF3n, g\xE9nero y voz privada del personaje. Cuando el personaje tiene una voz personalizada, `voice.identityId` y `voice.revision` identifican la versi\xF3n aprobada \u2014 conserva la revisi\xF3n al llamar `approve_actor_voice` (expectedApprovedRevision) para reemplazarla. Los IDs de proveedor nunca se exponen por MCP. Usa el `id` como `actorId` al crear o editar una tarea. Solo aparecen los personajes listos para usar; si la lista est\xE1 vac\xEDa, dile al usuario que cree uno en productmaker.app antes de intentar asignarlo. No modifica nada.",
|
|
31693
|
-
inputSchema:
|
|
32127
|
+
inputSchema: z130.object({}).shape,
|
|
31694
32128
|
annotations: READS_INTERNAL
|
|
31695
32129
|
}, async () => {
|
|
31696
32130
|
try {
|
|
@@ -31723,7 +32157,7 @@ function registerActorTools(server, api) {
|
|
|
31723
32157
|
__name(registerActorTools, "registerActorTools");
|
|
31724
32158
|
|
|
31725
32159
|
// src/tools/publish.ts
|
|
31726
|
-
import { z as
|
|
32160
|
+
import { z as z131 } from "zod";
|
|
31727
32161
|
|
|
31728
32162
|
// src/tools/meta-publish-attempt-id.ts
|
|
31729
32163
|
var META_PUBLISH_NAMESPACE = "7b19c9ac-b4eb-4db1-970e-c2f24ce30b98";
|
|
@@ -31762,40 +32196,40 @@ var publishToShopifyGuidance = getProductMakerCapabilityModelGuidance("publish_t
|
|
|
31762
32196
|
var publishToMetaGuidance = getProductMakerCapabilityModelGuidance("publish_to_meta");
|
|
31763
32197
|
var publishCreativesToMetaGuidance = getProductMakerCapabilityModelGuidance("publish_creatives_to_meta");
|
|
31764
32198
|
var publishToTikTokGuidance = getProductMakerCapabilityModelGuidance("publish_to_tiktok");
|
|
31765
|
-
var ShopifyInput =
|
|
31766
|
-
taskId:
|
|
31767
|
-
shopDomain:
|
|
32199
|
+
var ShopifyInput = z131.object({
|
|
32200
|
+
taskId: z131.string().min(1),
|
|
32201
|
+
shopDomain: z131.string().min(1),
|
|
31768
32202
|
/** Override: number of landing images to include. Default = ALL images the
|
|
31769
32203
|
* task generated (the MCP fetches /v1/results first to count). Bounded
|
|
31770
32204
|
* generously here; the backend validates each index against
|
|
31771
32205
|
* landing.images.length and rejects out-of-range. */
|
|
31772
|
-
numLandingImages:
|
|
31773
|
-
variantIndex:
|
|
32206
|
+
numLandingImages: z131.number().int().min(1).max(20).optional(),
|
|
32207
|
+
variantIndex: z131.number().int().min(0).optional(),
|
|
31774
32208
|
/** ASK THE USER before setting: "¿Tu producto tiene variantes (talla, color, etc.)?".
|
|
31775
32209
|
* When true, the landing renders variant-picker pills; when false, it ships
|
|
31776
32210
|
* a single-option product page. Defaults to false. */
|
|
31777
|
-
showVariantPicker:
|
|
32211
|
+
showVariantPicker: z131.boolean().optional(),
|
|
31778
32212
|
/** Default `auto` updates the product previously published for this task and
|
|
31779
32213
|
* shop. Use `existing` with targetProductId to choose another product, or
|
|
31780
32214
|
* `new` only when the user explicitly wants a duplicate/new listing. */
|
|
31781
|
-
publicationMode:
|
|
32215
|
+
publicationMode: z131.enum([
|
|
31782
32216
|
"auto",
|
|
31783
32217
|
"existing",
|
|
31784
32218
|
"new"
|
|
31785
32219
|
]).optional(),
|
|
31786
32220
|
/** Shopify product GID, numeric id, or admin product URL. Required when
|
|
31787
32221
|
* publicationMode is `existing`. */
|
|
31788
|
-
targetProductId:
|
|
32222
|
+
targetProductId: z131.string().trim().min(1).max(300).optional(),
|
|
31789
32223
|
/** Add an announcement bar text above add-to-cart (optional). */
|
|
31790
|
-
announcementBarEnabled:
|
|
31791
|
-
announcementBarText:
|
|
32224
|
+
announcementBarEnabled: z131.boolean().optional(),
|
|
32225
|
+
announcementBarText: z131.string().trim().min(1).max(SHOPIFY_ANNOUNCEMENT_BAR_MAX_LENGTH).optional(),
|
|
31792
32226
|
commerceCorrection: PublishCommerceCorrectionSchema.optional().describe("Complete seller-confirmed commerce values, with the revision and fingerprint returned in recovery. Never invent missing prices or convert currency."),
|
|
31793
|
-
confirmed:
|
|
32227
|
+
confirmed: z131.boolean().optional().describe("Required as true only when submitting commerceCorrection, after showing its values and obtaining explicit seller confirmation.")
|
|
31794
32228
|
});
|
|
31795
32229
|
var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value, ctx) => {
|
|
31796
32230
|
if (value.commerceCorrection && value.confirmed !== true) {
|
|
31797
32231
|
ctx.addIssue({
|
|
31798
|
-
code:
|
|
32232
|
+
code: z131.ZodIssueCode.custom,
|
|
31799
32233
|
path: [
|
|
31800
32234
|
"confirmed"
|
|
31801
32235
|
],
|
|
@@ -31804,7 +32238,7 @@ var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value,
|
|
|
31804
32238
|
}
|
|
31805
32239
|
if (value.announcementBarEnabled && !value.announcementBarText) {
|
|
31806
32240
|
ctx.addIssue({
|
|
31807
|
-
code:
|
|
32241
|
+
code: z131.ZodIssueCode.custom,
|
|
31808
32242
|
path: [
|
|
31809
32243
|
"announcementBarText"
|
|
31810
32244
|
],
|
|
@@ -31813,7 +32247,7 @@ var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value,
|
|
|
31813
32247
|
}
|
|
31814
32248
|
if (!value.announcementBarEnabled && value.announcementBarText) {
|
|
31815
32249
|
ctx.addIssue({
|
|
31816
|
-
code:
|
|
32250
|
+
code: z131.ZodIssueCode.custom,
|
|
31817
32251
|
path: [
|
|
31818
32252
|
"announcementBarText"
|
|
31819
32253
|
],
|
|
@@ -31827,91 +32261,90 @@ function parseShopifyInput(rawInput) {
|
|
|
31827
32261
|
return parsed.data;
|
|
31828
32262
|
}
|
|
31829
32263
|
__name(parseShopifyInput, "parseShopifyInput");
|
|
31830
|
-
var McpCampaignConfig =
|
|
31831
|
-
/**
|
|
31832
|
-
*
|
|
31833
|
-
|
|
31834
|
-
dailyBudgetUsd: z130.number().positive().optional(),
|
|
32264
|
+
var McpCampaignConfig = z131.object({
|
|
32265
|
+
/** Legacy USD amount. Meta retains its existing conversion; the TikTok
|
|
32266
|
+
* schema below restricts this input to USD advertiser accounts. */
|
|
32267
|
+
dailyBudgetUsd: z131.number().positive().optional(),
|
|
31835
32268
|
/** ISO-3166-1 alpha-2 country codes or resolvable names (CountryIso2Schema
|
|
31836
32269
|
* normalizes at validation). Meta accepts max 1 (single-country ad set).
|
|
31837
32270
|
* TikTok takes only the first entry. */
|
|
31838
|
-
targetCountries:
|
|
31839
|
-
campaignName:
|
|
32271
|
+
targetCountries: z131.array(CountryIso2Schema).max(1).optional(),
|
|
32272
|
+
campaignName: z131.string().trim().min(1).max(100).optional()
|
|
31840
32273
|
});
|
|
31841
32274
|
var McpAdAccountId = MetaAdAccountId.describe('Meta ad account id. Accepts "act_1234567890" or the bare numeric id "1234567890".');
|
|
31842
|
-
var MetaInput =
|
|
31843
|
-
taskId:
|
|
32275
|
+
var MetaInput = z131.object({
|
|
32276
|
+
taskId: z131.string().min(1),
|
|
31844
32277
|
/** Exact Meta Business portfolio selected from `list_meta_destinations`. */
|
|
31845
|
-
portfolioId:
|
|
32278
|
+
portfolioId: z131.string().trim().min(1),
|
|
31846
32279
|
/** Exact Facebook Page selected from `list_meta_destinations`. */
|
|
31847
|
-
pageId:
|
|
32280
|
+
pageId: z131.string().trim().min(1),
|
|
31848
32281
|
adAccountId: McpAdAccountId,
|
|
31849
|
-
pixelId:
|
|
31850
|
-
landingUrl:
|
|
32282
|
+
pixelId: z131.string().min(1).optional(),
|
|
32283
|
+
landingUrl: z131.string().url().optional(),
|
|
31851
32284
|
/** Select which angles to publish by 0-based index. Omit to publish all
|
|
31852
32285
|
* successful angles. Example: a task with 3 angles → `[0,2]` publishes #0 + #2. */
|
|
31853
|
-
angleIndexes:
|
|
32286
|
+
angleIndexes: z131.array(z131.number().int().nonnegative()).optional(),
|
|
31854
32287
|
campaignConfig: McpCampaignConfig.optional(),
|
|
31855
32288
|
/** Override the ad's primary text (body copy). If omitted, ProductMaker
|
|
31856
32289
|
* uses the auto-generated copy attached to the task. Capped at 500 chars
|
|
31857
32290
|
* (Meta's primary-text limit). */
|
|
31858
|
-
primaryText:
|
|
32291
|
+
primaryText: z131.string().trim().min(1).max(500).optional(),
|
|
31859
32292
|
/** Optional WhatsApp number. When set, the ad button opens a WhatsApp chat
|
|
31860
32293
|
* (wa.me) instead of a landing page. */
|
|
31861
|
-
phoneNumber:
|
|
32294
|
+
phoneNumber: z131.string().min(8).max(32).optional()
|
|
31862
32295
|
});
|
|
31863
|
-
var GroupedTaskSource =
|
|
31864
|
-
type:
|
|
31865
|
-
taskId:
|
|
31866
|
-
angleIndex:
|
|
31867
|
-
videoVariant:
|
|
32296
|
+
var GroupedTaskSource = z131.object({
|
|
32297
|
+
type: z131.literal("task"),
|
|
32298
|
+
taskId: z131.string().min(1),
|
|
32299
|
+
angleIndex: z131.number().int().min(0).optional(),
|
|
32300
|
+
videoVariant: z131.enum([
|
|
31868
32301
|
"with_subtitles",
|
|
31869
32302
|
"without_subtitles"
|
|
31870
32303
|
]).optional(),
|
|
31871
|
-
imageVariantIndex:
|
|
31872
|
-
});
|
|
31873
|
-
var GroupedMediaSource =
|
|
31874
|
-
type:
|
|
31875
|
-
url:
|
|
31876
|
-
path:
|
|
31877
|
-
thumbnailUrl:
|
|
31878
|
-
thumbnailPath:
|
|
32304
|
+
imageVariantIndex: z131.number().int().min(0).optional()
|
|
32305
|
+
});
|
|
32306
|
+
var GroupedMediaSource = z131.object({
|
|
32307
|
+
type: z131.literal("media"),
|
|
32308
|
+
url: z131.string().url().optional().describe("Public HTTPS media URL. For a file on the user laptop, use request_media_upload on the hosted MCP instead."),
|
|
32309
|
+
path: z131.string().min(1).optional().describe('Local file path only when this MCP runs over stdio. On the hosted MCP, call request_media_upload and then use source.type="asset".'),
|
|
32310
|
+
thumbnailUrl: z131.string().url().optional(),
|
|
32311
|
+
thumbnailPath: z131.string().min(1).optional()
|
|
31879
32312
|
}).refine((value) => Boolean(value.url) !== Boolean(value.path), {
|
|
31880
32313
|
message: "media source needs exactly one of `url` or `path`"
|
|
31881
32314
|
}).refine((value) => !(value.thumbnailUrl && value.thumbnailPath), {
|
|
31882
32315
|
message: "media source needs at most one of `thumbnailUrl` or `thumbnailPath`"
|
|
31883
32316
|
});
|
|
31884
|
-
var GroupedUploadedAssetSource =
|
|
31885
|
-
type:
|
|
32317
|
+
var GroupedUploadedAssetSource = z131.object({
|
|
32318
|
+
type: z131.literal("asset"),
|
|
31886
32319
|
/** Returned by check_media_upload. ProductMaker resolves ownership server-side. */
|
|
31887
|
-
assetId:
|
|
31888
|
-
thumbnailAssetId:
|
|
32320
|
+
assetId: z131.string().uuid(),
|
|
32321
|
+
thumbnailAssetId: z131.string().uuid().optional()
|
|
31889
32322
|
});
|
|
31890
|
-
var GroupedCreative =
|
|
31891
|
-
type:
|
|
32323
|
+
var GroupedCreative = z131.object({
|
|
32324
|
+
type: z131.enum([
|
|
31892
32325
|
"image",
|
|
31893
32326
|
"video"
|
|
31894
32327
|
]),
|
|
31895
|
-
source:
|
|
32328
|
+
source: z131.union([
|
|
31896
32329
|
GroupedTaskSource,
|
|
31897
32330
|
GroupedMediaSource,
|
|
31898
32331
|
GroupedUploadedAssetSource
|
|
31899
32332
|
]),
|
|
31900
|
-
title:
|
|
31901
|
-
description:
|
|
32333
|
+
title: z131.string().max(120).optional(),
|
|
32334
|
+
description: z131.string().max(500).optional(),
|
|
31902
32335
|
cta: MetaCtaType.optional(),
|
|
31903
|
-
creativeId:
|
|
32336
|
+
creativeId: z131.string().min(1).optional()
|
|
31904
32337
|
});
|
|
31905
|
-
var GroupedCampaignConfigBase =
|
|
32338
|
+
var GroupedCampaignConfigBase = z131.object({
|
|
31906
32339
|
campaignType: MetaCampaignType.default("sales"),
|
|
31907
32340
|
optimizationMode: MetaOptimizationMode.default("advantage_plus"),
|
|
31908
32341
|
budgetMode: MetaBudgetMode.optional(),
|
|
31909
|
-
campaignDailyBudget:
|
|
31910
|
-
adSets:
|
|
31911
|
-
tempId:
|
|
31912
|
-
name:
|
|
31913
|
-
dailyBudget:
|
|
31914
|
-
creativeIds:
|
|
32342
|
+
campaignDailyBudget: z131.number().int().positive().optional(),
|
|
32343
|
+
adSets: z131.array(z131.object({
|
|
32344
|
+
tempId: z131.string().min(1).max(80),
|
|
32345
|
+
name: z131.string().min(1).max(100),
|
|
32346
|
+
dailyBudget: z131.number().int().positive().optional(),
|
|
32347
|
+
creativeIds: z131.array(z131.string().min(1)).min(1)
|
|
31915
32348
|
})).min(1).max(CAMPAIGN_LIMITS.MAX_AD_SETS),
|
|
31916
32349
|
/**
|
|
31917
32350
|
* Valid values are 'landing' and 'whatsapp' — there is no 'website'. This
|
|
@@ -31919,17 +32352,17 @@ var GroupedCampaignConfigBase = z130.object({
|
|
|
31919
32352
|
* opaque `invalid_literal` and made the WhatsApp destination — supported by
|
|
31920
32353
|
* the API since #849 — unreachable from this tool.
|
|
31921
32354
|
*/
|
|
31922
|
-
destination:
|
|
31923
|
-
|
|
31924
|
-
type:
|
|
31925
|
-
landingUrl:
|
|
32355
|
+
destination: z131.discriminatedUnion("type", [
|
|
32356
|
+
z131.object({
|
|
32357
|
+
type: z131.literal("landing"),
|
|
32358
|
+
landingUrl: z131.string().url()
|
|
31926
32359
|
}),
|
|
31927
|
-
|
|
31928
|
-
type:
|
|
31929
|
-
phoneNumber:
|
|
32360
|
+
z131.object({
|
|
32361
|
+
type: z131.literal("whatsapp"),
|
|
32362
|
+
phoneNumber: z131.string().min(8).max(32)
|
|
31930
32363
|
})
|
|
31931
32364
|
]),
|
|
31932
|
-
saveAsDefault:
|
|
32365
|
+
saveAsDefault: z131.boolean().default(false),
|
|
31933
32366
|
budgetPolicy: MetaBudgetPolicy.optional()
|
|
31934
32367
|
});
|
|
31935
32368
|
function resolveBudgetMode(value) {
|
|
@@ -31943,7 +32376,7 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
|
|
|
31943
32376
|
const budgetMode = resolveBudgetMode(value);
|
|
31944
32377
|
if (budgetMode === "campaign" && value.campaignDailyBudget === void 0) {
|
|
31945
32378
|
ctx.addIssue({
|
|
31946
|
-
code:
|
|
32379
|
+
code: z131.ZodIssueCode.custom,
|
|
31947
32380
|
path: [
|
|
31948
32381
|
"campaignDailyBudget"
|
|
31949
32382
|
],
|
|
@@ -31954,7 +32387,7 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
|
|
|
31954
32387
|
value.adSets.forEach((adSet, index) => {
|
|
31955
32388
|
if (adSet.dailyBudget === void 0) {
|
|
31956
32389
|
ctx.addIssue({
|
|
31957
|
-
code:
|
|
32390
|
+
code: z131.ZodIssueCode.custom,
|
|
31958
32391
|
path: [
|
|
31959
32392
|
"adSets",
|
|
31960
32393
|
index,
|
|
@@ -31969,25 +32402,25 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
|
|
|
31969
32402
|
...value,
|
|
31970
32403
|
budgetMode: resolveBudgetMode(value)
|
|
31971
32404
|
}));
|
|
31972
|
-
var PublishCreativesToMetaInputBase =
|
|
31973
|
-
creatives:
|
|
32405
|
+
var PublishCreativesToMetaInputBase = z131.object({
|
|
32406
|
+
creatives: z131.array(GroupedCreative).min(1).max(CAMPAIGN_LIMITS.MAX_CREATIVES),
|
|
31974
32407
|
/** Exact Meta Business portfolio selected from `list_meta_destinations`. */
|
|
31975
|
-
portfolioId:
|
|
32408
|
+
portfolioId: z131.string().trim().min(1),
|
|
31976
32409
|
/** Exact Facebook Page selected from `list_meta_destinations`. */
|
|
31977
|
-
pageId:
|
|
32410
|
+
pageId: z131.string().trim().min(1),
|
|
31978
32411
|
adAccountId: McpAdAccountId,
|
|
31979
|
-
pixelId:
|
|
32412
|
+
pixelId: z131.string().min(1).optional(),
|
|
31980
32413
|
/** Required unless `campaignConfig.destination` is whatsapp or a creative
|
|
31981
32414
|
* comes from a task (the API then lands on the published service landing
|
|
31982
32415
|
* of its service tasks) — see the superRefine below. Mirrors the API's
|
|
31983
32416
|
* `FacebookCreateCampaignFromTasksBodySchema`. */
|
|
31984
|
-
landingUrl:
|
|
32417
|
+
landingUrl: z131.string().url().optional(),
|
|
31985
32418
|
/** ISO-2 code or resolvable country name — mirrors the API contract
|
|
31986
32419
|
* (CountryIso2Schema), which normalizes names to alpha-2 at validation.
|
|
31987
32420
|
* Omitted: the brand country of its service tasks (the API answers
|
|
31988
32421
|
* META_NO_TARGET_COUNTRY when it has none); "US" for products. */
|
|
31989
32422
|
targetCountry: CountryIso2Schema.optional(),
|
|
31990
|
-
campaignName:
|
|
32423
|
+
campaignName: z131.string().trim().min(1).max(100),
|
|
31991
32424
|
campaignConfig: GroupedCampaignConfig.optional()
|
|
31992
32425
|
});
|
|
31993
32426
|
var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((value, ctx) => {
|
|
@@ -31995,7 +32428,7 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
|
|
|
31995
32428
|
const hasTaskCreative = value.creatives.some((creative) => creative.source.type === "task");
|
|
31996
32429
|
if (destination?.type !== "whatsapp" && destination?.type !== "landing" && !value.landingUrl && !hasTaskCreative) {
|
|
31997
32430
|
ctx.addIssue({
|
|
31998
|
-
code:
|
|
32431
|
+
code: z131.ZodIssueCode.custom,
|
|
31999
32432
|
path: [
|
|
32000
32433
|
"landingUrl"
|
|
32001
32434
|
],
|
|
@@ -32004,7 +32437,7 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
|
|
|
32004
32437
|
}
|
|
32005
32438
|
if (destination?.type === "landing" && value.landingUrl && destination.landingUrl !== value.landingUrl) {
|
|
32006
32439
|
ctx.addIssue({
|
|
32007
|
-
code:
|
|
32440
|
+
code: z131.ZodIssueCode.custom,
|
|
32008
32441
|
path: [
|
|
32009
32442
|
"campaignConfig",
|
|
32010
32443
|
"destination",
|
|
@@ -32023,16 +32456,16 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
|
|
|
32023
32456
|
}
|
|
32024
32457
|
return value;
|
|
32025
32458
|
});
|
|
32026
|
-
var PresignUploadResponseSchema =
|
|
32027
|
-
uploadUrl:
|
|
32459
|
+
var PresignUploadResponseSchema = z131.object({
|
|
32460
|
+
uploadUrl: z131.string().url().refine((value) => {
|
|
32028
32461
|
const url = new URL(value);
|
|
32029
32462
|
return !url.username && !url.password && url.protocol === "https:";
|
|
32030
32463
|
}, "presigned upload URL must be HTTPS without embedded credentials"),
|
|
32031
|
-
publicUrl:
|
|
32464
|
+
publicUrl: z131.string().url().refine((value) => {
|
|
32032
32465
|
const url = new URL(value);
|
|
32033
32466
|
return !url.username && !url.password;
|
|
32034
32467
|
}, "public media URL must not contain embedded credentials"),
|
|
32035
|
-
stagingAssetId:
|
|
32468
|
+
stagingAssetId: z131.string().uuid()
|
|
32036
32469
|
});
|
|
32037
32470
|
async function uploadResolvedMedia(api, media, assetRole) {
|
|
32038
32471
|
if (!media.buffer) throw new ResolveMediaError("INVALID_INPUT", "resolved media has no bytes");
|
|
@@ -32057,16 +32490,41 @@ async function resolveAndUploadMedia(api, ref, expectedKind, assetRole, transpor
|
|
|
32057
32490
|
return uploadResolvedMedia(api, media, assetRole);
|
|
32058
32491
|
}
|
|
32059
32492
|
__name(resolveAndUploadMedia, "resolveAndUploadMedia");
|
|
32060
|
-
var
|
|
32061
|
-
|
|
32062
|
-
|
|
32063
|
-
|
|
32064
|
-
|
|
32065
|
-
|
|
32066
|
-
|
|
32493
|
+
var TikTokMcpCampaignConfig = McpCampaignConfig.extend({
|
|
32494
|
+
dailyBudgetUsd: z131.number().finite().positive().optional().describe("Legacy USD amount, supported only for USD advertiser accounts. No FX conversion."),
|
|
32495
|
+
dailyBudget: z131.number().finite().positive().optional().describe("Daily budget in the selected advertiser currency major units; pass budgetCurrency together."),
|
|
32496
|
+
budgetCurrency: TikTokBudgetCurrencySchema.optional(),
|
|
32497
|
+
destination: TikTokCampaignDestinationSchema.optional()
|
|
32498
|
+
}).superRefine((value, ctx) => {
|
|
32499
|
+
if (value.dailyBudgetUsd !== void 0 && (value.dailyBudget !== void 0 || value.budgetCurrency !== void 0)) {
|
|
32500
|
+
ctx.addIssue({
|
|
32501
|
+
code: z131.ZodIssueCode.custom,
|
|
32502
|
+
path: [
|
|
32503
|
+
"dailyBudgetUsd"
|
|
32504
|
+
],
|
|
32505
|
+
message: "Choose either dailyBudgetUsd or dailyBudget with budgetCurrency, never both."
|
|
32506
|
+
});
|
|
32507
|
+
}
|
|
32508
|
+
if (value.dailyBudget !== void 0 !== (value.budgetCurrency !== void 0)) {
|
|
32509
|
+
ctx.addIssue({
|
|
32510
|
+
code: z131.ZodIssueCode.custom,
|
|
32511
|
+
path: [
|
|
32512
|
+
"budgetCurrency"
|
|
32513
|
+
],
|
|
32514
|
+
message: "dailyBudget and budgetCurrency must be supplied together."
|
|
32515
|
+
});
|
|
32516
|
+
}
|
|
32517
|
+
});
|
|
32518
|
+
var TikTokInput = z131.object({
|
|
32519
|
+
taskId: z131.string().min(1),
|
|
32520
|
+
advertiserId: z131.string().min(1),
|
|
32521
|
+
pixelId: z131.string().min(1).optional(),
|
|
32522
|
+
landingUrl: z131.string().url().optional(),
|
|
32523
|
+
angleIndexes: z131.array(z131.number().int().nonnegative()).optional(),
|
|
32524
|
+
campaignConfig: TikTokMcpCampaignConfig.optional(),
|
|
32067
32525
|
/** Override the ad's description (TikTok's body copy). If omitted,
|
|
32068
32526
|
* ProductMaker uses the auto-generated copy attached to the task. */
|
|
32069
|
-
primaryText:
|
|
32527
|
+
primaryText: z131.string().trim().min(1).max(500).optional()
|
|
32070
32528
|
});
|
|
32071
32529
|
function registerPublishTools(server, api, opts = {}) {
|
|
32072
32530
|
const transport = opts.transport ?? "http";
|
|
@@ -32288,7 +32746,7 @@ function registerPublishTools(server, api, opts = {}) {
|
|
|
32288
32746
|
}
|
|
32289
32747
|
});
|
|
32290
32748
|
server.registerTool("publish_to_tiktok", {
|
|
32291
|
-
description: publishToTikTokGuidance.summary + " La campa\xF1a se crea SIEMPRE en estado PAUSED \u2014 el usuario la activa manualmente en TikTok Ads Manager. Use `list_tiktok_advertisers` antes para un advertiserId v\xE1lido. `pixelId` opcional pero recomendado para tracking. `angleIndexes` (opcional): selecciona qu\xE9 \xE1ngulos de la tarea original publicar \u2014 ej. [0,2]; omitir = publicar todos, incluidas las variantes creativas generadas despu\xE9s. `campaignConfig` (opcional): `
|
|
32749
|
+
description: publishToTikTokGuidance.summary + " Las tareas de servicios publican \xFAnicamente videos en TikTok; para im\xE1genes de servicios usa Meta Ads. No omitas im\xE1genes seleccionadas de una tarea mixta para forzar su publicaci\xF3n. La campa\xF1a se crea SIEMPRE en estado PAUSED \u2014 el usuario la activa manualmente en TikTok Ads Manager. Use `list_tiktok_advertisers` antes para un advertiserId v\xE1lido. `pixelId` opcional pero recomendado para tracking web. `campaignConfig.destination` acepta landing (default) o {type: 'whatsapp', phoneNumber: '+573001234567', phoneRegionCode?: 'CO'} para anuncios nativos de WhatsApp con videos. WhatsApp usa clics y no requiere landingUrl ni pixelId; phoneRegionCode identifica el pa\xEDs del tel\xE9fono y es obligatorio si el prefijo es compartido, como +1. No asumas que coincide con el pa\xEDs objetivo. TikTok exige habilitaci\xF3n de mensajer\xEDa para algunos advertisers; no sustituyas una denegaci\xF3n por tr\xE1fico web. `angleIndexes` (opcional): selecciona qu\xE9 \xE1ngulos de la tarea original publicar \u2014 ej. [0,2]; omitir = publicar todos, incluidas las variantes creativas generadas despu\xE9s. `campaignConfig` (opcional): `dailyBudget` + `budgetCurrency` (importe diario en unidades principales de la moneda de la cuenta, ej. 25.50 y USD, o 20000 y COP). `dailyBudgetUsd` es legado y solo sirve para cuentas USD; no se convierte FX. No env\xEDes ambos. Sin presupuesto expl\xEDcito se usa el m\xEDnimo documentado para la moneda real de la cuenta. `targetCountries` (c\xF3digos ISO-2, primero se usa), `campaignName` (m\xE1x 100 chars). `primaryText` (opcional, m\xE1x 500 chars): override del copy del anuncio \u2014 solo \xFAsalo si el usuario te pas\xF3 un texto espec\xEDfico; si no, ProductMaker usa el copy auto-generado de la tarea. Despu\xE9s de publicar usa `get_tiktok_campaign_status` para chequear el estado.",
|
|
32292
32750
|
inputSchema: TikTokInput.shape,
|
|
32293
32751
|
annotations: CREATES_EXTERNAL
|
|
32294
32752
|
}, async ({ taskId, campaignConfig, primaryText, ...rest }) => {
|
|
@@ -32409,48 +32867,55 @@ function toMetaCampaignOverrides(cfg) {
|
|
|
32409
32867
|
__name(toMetaCampaignOverrides, "toMetaCampaignOverrides");
|
|
32410
32868
|
function toTikTokCampaignConfig(cfg) {
|
|
32411
32869
|
const out = {};
|
|
32412
|
-
if (cfg.dailyBudgetUsd !== void 0)
|
|
32870
|
+
if (cfg.dailyBudgetUsd !== void 0) {
|
|
32871
|
+
out.dailyBudget = cfg.dailyBudgetUsd;
|
|
32872
|
+
out.budgetCurrency = "USD";
|
|
32873
|
+
} else if (cfg.dailyBudget !== void 0) {
|
|
32874
|
+
out.dailyBudget = cfg.dailyBudget;
|
|
32875
|
+
out.budgetCurrency = cfg.budgetCurrency;
|
|
32876
|
+
}
|
|
32413
32877
|
if (cfg.targetCountries && cfg.targetCountries.length > 0) out.targetCountry = cfg.targetCountries[0];
|
|
32414
32878
|
if (cfg.campaignName !== void 0) out.campaignName = cfg.campaignName;
|
|
32879
|
+
if (cfg.destination !== void 0) out.destination = cfg.destination;
|
|
32415
32880
|
return out;
|
|
32416
32881
|
}
|
|
32417
32882
|
__name(toTikTokCampaignConfig, "toTikTokCampaignConfig");
|
|
32418
32883
|
|
|
32419
32884
|
// src/tools/meta-upload.ts
|
|
32420
32885
|
import { registerAppTool } from "@modelcontextprotocol/ext-apps/server";
|
|
32421
|
-
import { z as
|
|
32886
|
+
import { z as z132 } from "zod";
|
|
32422
32887
|
var requestMediaUploadGuidance = getProductMakerCapabilityModelGuidance("request_media_upload");
|
|
32423
|
-
var UploadSessionInputBase =
|
|
32424
|
-
mediaKind:
|
|
32888
|
+
var UploadSessionInputBase = z132.object({
|
|
32889
|
+
mediaKind: z132.enum([
|
|
32425
32890
|
"image",
|
|
32426
32891
|
"video",
|
|
32427
32892
|
"mixed"
|
|
32428
32893
|
]).default("mixed").describe("The kind of file the user will select. Use image for product references and landing pages, video for a single video, and mixed only when the consumer supports both."),
|
|
32429
|
-
assetRole:
|
|
32894
|
+
assetRole: z132.enum([
|
|
32430
32895
|
"media",
|
|
32431
32896
|
"thumbnail"
|
|
32432
32897
|
]).default("media").describe("Use media for the creative itself; thumbnail only for an image thumbnail."),
|
|
32433
|
-
uploadPurpose:
|
|
32898
|
+
uploadPurpose: z132.enum([
|
|
32434
32899
|
"product_reference",
|
|
32435
32900
|
"creative",
|
|
32436
32901
|
"generic"
|
|
32437
32902
|
]).default("generic").describe("The user's purpose for these files. Use product_reference for a product photo used by tasks or landings, creative for media that will become an ad or creative, and generic only when neither applies."),
|
|
32438
|
-
maxFiles:
|
|
32903
|
+
maxFiles: z132.number().int().min(1).max(10).optional().describe("Optional batch limit: image accepts 1-5, video exactly 1, and mixed 1-10.")
|
|
32439
32904
|
});
|
|
32440
|
-
var OpenAiFileReference =
|
|
32441
|
-
download_url:
|
|
32442
|
-
file_id:
|
|
32443
|
-
mime_type:
|
|
32444
|
-
file_name:
|
|
32905
|
+
var OpenAiFileReference = z132.object({
|
|
32906
|
+
download_url: z132.string().url().describe("Required by ChatGPT's openai/fileParams schema. The App prefers getFileDownloadUrl(file_id) for a fresh URL, and the server never fetches this value."),
|
|
32907
|
+
file_id: z132.string().min(1),
|
|
32908
|
+
mime_type: z132.string().min(1).optional(),
|
|
32909
|
+
file_name: z132.string().min(1).optional()
|
|
32445
32910
|
});
|
|
32446
32911
|
var UploadSessionToolInputShape = {
|
|
32447
32912
|
...UploadSessionInputBase.shape,
|
|
32448
|
-
files:
|
|
32913
|
+
files: z132.array(OpenAiFileReference).max(10).optional().describe("Optional OpenAI-hosted file references provided by ChatGPT. They are only metadata for the UI bridge and are never forwarded to ProductMaker.")
|
|
32449
32914
|
};
|
|
32450
|
-
var UploadSessionToolInput =
|
|
32915
|
+
var UploadSessionToolInput = z132.object(UploadSessionToolInputShape).superRefine((value, ctx) => {
|
|
32451
32916
|
if (value.assetRole === "thumbnail" && value.mediaKind !== "image") {
|
|
32452
32917
|
ctx.addIssue({
|
|
32453
|
-
code:
|
|
32918
|
+
code: z132.ZodIssueCode.custom,
|
|
32454
32919
|
path: [
|
|
32455
32920
|
"mediaKind"
|
|
32456
32921
|
],
|
|
@@ -32459,7 +32924,7 @@ var UploadSessionToolInput = z131.object(UploadSessionToolInputShape).superRefin
|
|
|
32459
32924
|
}
|
|
32460
32925
|
if (value.mediaKind === "video" && value.maxFiles !== void 0 && value.maxFiles !== 1) {
|
|
32461
32926
|
ctx.addIssue({
|
|
32462
|
-
code:
|
|
32927
|
+
code: z132.ZodIssueCode.custom,
|
|
32463
32928
|
path: [
|
|
32464
32929
|
"maxFiles"
|
|
32465
32930
|
],
|
|
@@ -32468,7 +32933,7 @@ var UploadSessionToolInput = z131.object(UploadSessionToolInputShape).superRefin
|
|
|
32468
32933
|
}
|
|
32469
32934
|
if (value.mediaKind === "image" && (value.maxFiles ?? 1) > 5) {
|
|
32470
32935
|
ctx.addIssue({
|
|
32471
|
-
code:
|
|
32936
|
+
code: z132.ZodIssueCode.custom,
|
|
32472
32937
|
path: [
|
|
32473
32938
|
"maxFiles"
|
|
32474
32939
|
],
|
|
@@ -32476,38 +32941,38 @@ var UploadSessionToolInput = z131.object(UploadSessionToolInputShape).superRefin
|
|
|
32476
32941
|
});
|
|
32477
32942
|
}
|
|
32478
32943
|
});
|
|
32479
|
-
var UploadSessionResponse =
|
|
32480
|
-
sessionId:
|
|
32481
|
-
uploadPageUrl:
|
|
32482
|
-
mediaKind:
|
|
32944
|
+
var UploadSessionResponse = z132.object({
|
|
32945
|
+
sessionId: z132.string().uuid(),
|
|
32946
|
+
uploadPageUrl: z132.string().url(),
|
|
32947
|
+
mediaKind: z132.enum([
|
|
32483
32948
|
"image",
|
|
32484
32949
|
"video",
|
|
32485
32950
|
"mixed"
|
|
32486
32951
|
]),
|
|
32487
|
-
assetRole:
|
|
32952
|
+
assetRole: z132.enum([
|
|
32488
32953
|
"media",
|
|
32489
32954
|
"thumbnail"
|
|
32490
32955
|
]),
|
|
32491
|
-
maxFiles:
|
|
32492
|
-
expiresAt:
|
|
32956
|
+
maxFiles: z132.number().int().positive(),
|
|
32957
|
+
expiresAt: z132.string().datetime()
|
|
32493
32958
|
});
|
|
32494
|
-
var UploadStatusInput =
|
|
32495
|
-
sessionId:
|
|
32959
|
+
var UploadStatusInput = z132.object({
|
|
32960
|
+
sessionId: z132.string().uuid().describe("The sessionId returned by request_media_upload.")
|
|
32496
32961
|
});
|
|
32497
|
-
var UniversalUploadStatusResponse =
|
|
32498
|
-
|
|
32499
|
-
status:
|
|
32500
|
-
assets:
|
|
32962
|
+
var UniversalUploadStatusResponse = z132.discriminatedUnion("status", [
|
|
32963
|
+
z132.object({
|
|
32964
|
+
status: z132.literal("pending"),
|
|
32965
|
+
assets: z132.array(z132.never()).length(0)
|
|
32501
32966
|
}),
|
|
32502
|
-
|
|
32503
|
-
status:
|
|
32504
|
-
assets:
|
|
32505
|
-
assetId:
|
|
32506
|
-
mediaKind:
|
|
32967
|
+
z132.object({
|
|
32968
|
+
status: z132.literal("uploaded"),
|
|
32969
|
+
assets: z132.array(z132.object({
|
|
32970
|
+
assetId: z132.string().uuid(),
|
|
32971
|
+
mediaKind: z132.enum([
|
|
32507
32972
|
"image",
|
|
32508
32973
|
"video"
|
|
32509
32974
|
]),
|
|
32510
|
-
assetRole:
|
|
32975
|
+
assetRole: z132.enum([
|
|
32511
32976
|
"media",
|
|
32512
32977
|
"thumbnail"
|
|
32513
32978
|
])
|
|
@@ -32515,13 +32980,13 @@ var UniversalUploadStatusResponse = z131.discriminatedUnion("status", [
|
|
|
32515
32980
|
})
|
|
32516
32981
|
]);
|
|
32517
32982
|
var UniversalUploadStructuredResponse = UploadSessionResponse.extend({
|
|
32518
|
-
uploadPurpose:
|
|
32983
|
+
uploadPurpose: z132.enum([
|
|
32519
32984
|
"product_reference",
|
|
32520
32985
|
"creative",
|
|
32521
32986
|
"generic"
|
|
32522
32987
|
]),
|
|
32523
|
-
checkToolName:
|
|
32524
|
-
resolveEndpoint:
|
|
32988
|
+
checkToolName: z132.literal("check_media_upload"),
|
|
32989
|
+
resolveEndpoint: z132.string().url()
|
|
32525
32990
|
});
|
|
32526
32991
|
function contextualizeUploadPageUrl(uploadPageUrl, uploadPurpose) {
|
|
32527
32992
|
const url = new URL(uploadPageUrl);
|
|
@@ -32612,15 +33077,15 @@ function registerMediaUploadTools(server, api) {
|
|
|
32612
33077
|
__name(registerMediaUploadTools, "registerMediaUploadTools");
|
|
32613
33078
|
|
|
32614
33079
|
// src/tools/campaigns.ts
|
|
32615
|
-
import { z as
|
|
33080
|
+
import { z as z133 } from "zod";
|
|
32616
33081
|
var getMetaCampaignStatusGuidance = getProductMakerCapabilityModelGuidance("get_meta_campaign_status");
|
|
32617
33082
|
var getTikTokCampaignStatusGuidance = getProductMakerCapabilityModelGuidance("get_tiktok_campaign_status");
|
|
32618
|
-
var MetaStatusInput =
|
|
32619
|
-
campaignId:
|
|
33083
|
+
var MetaStatusInput = z133.object({
|
|
33084
|
+
campaignId: z133.string().min(1).describe("Meta campaign ID returned by publish_to_meta.")
|
|
32620
33085
|
});
|
|
32621
|
-
var TikTokStatusInput =
|
|
32622
|
-
campaignId:
|
|
32623
|
-
advertiserId:
|
|
33086
|
+
var TikTokStatusInput = z133.object({
|
|
33087
|
+
campaignId: z133.string().min(1).describe("TikTok campaign ID returned by publish_to_tiktok."),
|
|
33088
|
+
advertiserId: z133.string().min(1).describe("The same advertiserId used to publish the campaign.")
|
|
32624
33089
|
});
|
|
32625
33090
|
function registerCampaignTools(server, api) {
|
|
32626
33091
|
server.registerTool("get_meta_campaign_status", {
|
|
@@ -32725,10 +33190,10 @@ function renderTikTokStatusMarkdown(r) {
|
|
|
32725
33190
|
__name(renderTikTokStatusMarkdown, "renderTikTokStatusMarkdown");
|
|
32726
33191
|
|
|
32727
33192
|
// ../../packages/product-economics/src/product-costing.ts
|
|
32728
|
-
import { z as
|
|
33193
|
+
import { z as z135 } from "zod";
|
|
32729
33194
|
|
|
32730
33195
|
// ../../packages/product-economics/src/product-costing-countries.ts
|
|
32731
|
-
import { z as
|
|
33196
|
+
import { z as z134 } from "zod";
|
|
32732
33197
|
|
|
32733
33198
|
// ../../packages/product-economics/src/product-costing-shipping-references.json
|
|
32734
33199
|
var product_costing_shipping_references_default = {
|
|
@@ -32792,21 +33257,21 @@ var product_costing_shipping_references_default = {
|
|
|
32792
33257
|
};
|
|
32793
33258
|
|
|
32794
33259
|
// ../../packages/product-economics/src/product-costing-countries.ts
|
|
32795
|
-
var ShippingReferenceSchema =
|
|
32796
|
-
reference:
|
|
32797
|
-
min:
|
|
32798
|
-
max:
|
|
32799
|
-
updatedAt:
|
|
32800
|
-
confidence:
|
|
33260
|
+
var ShippingReferenceSchema = z134.object({
|
|
33261
|
+
reference: z134.number().positive(),
|
|
33262
|
+
min: z134.number().nonnegative(),
|
|
33263
|
+
max: z134.number().positive(),
|
|
33264
|
+
updatedAt: z134.string().date(),
|
|
33265
|
+
confidence: z134.enum([
|
|
32801
33266
|
"high",
|
|
32802
33267
|
"medium",
|
|
32803
33268
|
"medium-low"
|
|
32804
33269
|
]),
|
|
32805
|
-
sources:
|
|
33270
|
+
sources: z134.array(z134.string().url().startsWith("https://")).min(1).max(3)
|
|
32806
33271
|
}).superRefine(({ reference, min, max }, context) => {
|
|
32807
33272
|
if (min > reference || reference > max) {
|
|
32808
33273
|
context.addIssue({
|
|
32809
|
-
code:
|
|
33274
|
+
code: z134.ZodIssueCode.custom,
|
|
32810
33275
|
message: "shipping_reference_outside_range",
|
|
32811
33276
|
path: [
|
|
32812
33277
|
"reference"
|
|
@@ -32814,7 +33279,7 @@ var ShippingReferenceSchema = z133.object({
|
|
|
32814
33279
|
});
|
|
32815
33280
|
}
|
|
32816
33281
|
});
|
|
32817
|
-
var SHIPPING_REFERENCES =
|
|
33282
|
+
var SHIPPING_REFERENCES = z134.record(ShippingReferenceSchema).parse(product_costing_shipping_references_default);
|
|
32818
33283
|
var PRODUCT_COSTING_COUNTRY_CODES = Object.freeze(Object.keys(SHIPPING_REFERENCES));
|
|
32819
33284
|
var SPANISH_LOCALE_COUNTRIES = /* @__PURE__ */ new Set([
|
|
32820
33285
|
"MX",
|
|
@@ -32996,18 +33461,18 @@ function getProductCostingCountryName(country) {
|
|
|
32996
33461
|
__name(getProductCostingCountryName, "getProductCostingCountryName");
|
|
32997
33462
|
|
|
32998
33463
|
// ../../packages/product-economics/src/product-costing.ts
|
|
32999
|
-
var ProductCostingInputSchema =
|
|
33000
|
-
country:
|
|
33001
|
-
supplierCost:
|
|
33002
|
-
shippingCost:
|
|
33003
|
-
returnRate:
|
|
33004
|
-
cancellationRate:
|
|
33005
|
-
adsManagerCpa:
|
|
33006
|
-
desiredMargin:
|
|
33464
|
+
var ProductCostingInputSchema = z135.object({
|
|
33465
|
+
country: z135.string().refine(isProductCostingCountryCode, "unsupported_country"),
|
|
33466
|
+
supplierCost: z135.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").positive("supplier_cost_positive"),
|
|
33467
|
+
shippingCost: z135.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("shipping_cost_nonnegative"),
|
|
33468
|
+
returnRate: z135.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
|
|
33469
|
+
cancellationRate: z135.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
|
|
33470
|
+
adsManagerCpa: z135.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("cpa_nonnegative"),
|
|
33471
|
+
desiredMargin: z135.number().finite().min(0, "margin_nonnegative").lt(1, "margin_below_one")
|
|
33007
33472
|
}).superRefine(({ returnRate, cancellationRate }, context) => {
|
|
33008
33473
|
if (returnRate + cancellationRate >= 1) {
|
|
33009
33474
|
context.addIssue({
|
|
33010
|
-
code:
|
|
33475
|
+
code: z135.ZodIssueCode.custom,
|
|
33011
33476
|
message: "delivery_rate_positive",
|
|
33012
33477
|
path: [
|
|
33013
33478
|
"cancellationRate"
|
|
@@ -33104,15 +33569,15 @@ function calculateProductCosting(rawInput) {
|
|
|
33104
33569
|
__name(calculateProductCosting, "calculateProductCosting");
|
|
33105
33570
|
|
|
33106
33571
|
// src/tools/product-costing.ts
|
|
33107
|
-
import { z as
|
|
33572
|
+
import { z as z136 } from "zod";
|
|
33108
33573
|
var costProductGuidance = getProductMakerCapabilityModelGuidance("cost_product");
|
|
33109
|
-
var optionalAmount = /* @__PURE__ */ __name((description) =>
|
|
33110
|
-
var optionalPercent = /* @__PURE__ */ __name((description) =>
|
|
33111
|
-
var ProductCostingToolInput =
|
|
33112
|
-
country:
|
|
33574
|
+
var optionalAmount = /* @__PURE__ */ __name((description) => z136.number().finite().max(Number.MAX_SAFE_INTEGER).nonnegative().optional().describe(description), "optionalAmount");
|
|
33575
|
+
var optionalPercent = /* @__PURE__ */ __name((description) => z136.number().finite().min(0).lt(100).optional().describe(description), "optionalPercent");
|
|
33576
|
+
var ProductCostingToolInput = z136.object({
|
|
33577
|
+
country: z136.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
|
|
33113
33578
|
message: "Pa\xEDs no soportado por ProductMaker."
|
|
33114
33579
|
}).optional().describe("C\xF3digo ISO-2 de cualquiera de los pa\xEDses disponibles en ProductMaker. Omite para Colombia."),
|
|
33115
|
-
supplierCost:
|
|
33580
|
+
supplierCost: z136.number().finite().max(Number.MAX_SAFE_INTEGER).positive().optional().describe("Costo real de una unidad con el proveedor, en la moneda del pa\xEDs. Requerido salvo que uses supplierCostCop para Colombia."),
|
|
33116
33581
|
supplierCostCop: optionalAmount("Alias anterior para costo del proveedor en Colombia. Prefiere supplierCost."),
|
|
33117
33582
|
shippingCost: optionalAmount("Costo de un env\xEDo en la moneda del pa\xEDs. Omite para usar el valor gu\xEDa vigente."),
|
|
33118
33583
|
shippingCostCop: optionalAmount("Alias anterior para flete en Colombia. Prefiere shippingCost."),
|
|
@@ -33275,7 +33740,7 @@ function formatPercent(value) {
|
|
|
33275
33740
|
__name(formatPercent, "formatPercent");
|
|
33276
33741
|
|
|
33277
33742
|
// src/tools/product-research.ts
|
|
33278
|
-
import { z as
|
|
33743
|
+
import { z as z137 } from "zod";
|
|
33279
33744
|
|
|
33280
33745
|
// src/tools/product-research-idempotency.ts
|
|
33281
33746
|
var RESEARCH_IDEMPOTENCY_WINDOW_MS = 2 * 60 * 60 * 1e3;
|
|
@@ -33646,17 +34111,17 @@ var TERMINAL2 = /* @__PURE__ */ new Set([
|
|
|
33646
34111
|
]);
|
|
33647
34112
|
var POLL_INTERVAL_MS = 5e3;
|
|
33648
34113
|
var MAX_WAIT_SECONDS = 120;
|
|
33649
|
-
var FindInput =
|
|
34114
|
+
var FindInput = z137.object({
|
|
33650
34115
|
targetCountry: ResearchTargetCountryEnum.describe("Pa\xEDs objetivo. S\xF3lo CO, MX, PE, EC y CL tienen cobertura de investigaci\xF3n."),
|
|
33651
34116
|
categoryKey: ResearchCategoryEnum.default("auto").describe('Categor\xEDa a investigar. Usa "auto" para que la IA elija seg\xFAn el mercado.'),
|
|
33652
|
-
confirmed:
|
|
33653
|
-
waitSeconds:
|
|
34117
|
+
confirmed: z137.boolean().describe(`Ponlo en true SOLO despu\xE9s de que el usuario haya aceptado el cargo de ${PRICE_CREDITS} cr\xE9ditos. No lo asumas.`),
|
|
34118
|
+
waitSeconds: z137.number().int().min(0).max(MAX_WAIT_SECONDS).optional().describe("Segundos a esperar el reporte antes de devolver el runId. M\xE1ximo 120.")
|
|
33654
34119
|
});
|
|
33655
|
-
var GetInput =
|
|
33656
|
-
runId:
|
|
34120
|
+
var GetInput = z137.object({
|
|
34121
|
+
runId: z137.string().uuid().describe("ID del run devuelto por find_winning_products.")
|
|
33657
34122
|
});
|
|
33658
|
-
var ListInput =
|
|
33659
|
-
limit:
|
|
34123
|
+
var ListInput = z137.object({
|
|
34124
|
+
limit: z137.number().int().min(1).max(20).default(10)
|
|
33660
34125
|
});
|
|
33661
34126
|
function textResult(text2) {
|
|
33662
34127
|
return {
|
|
@@ -33795,17 +34260,17 @@ _Esta llamada no cobr\xF3 cr\xE9ditos: se reutiliz\xF3 una investigaci\xF3n reci
|
|
|
33795
34260
|
__name(registerProductResearchTools, "registerProductResearchTools");
|
|
33796
34261
|
|
|
33797
34262
|
// src/tools/dropshipping-projects.ts
|
|
33798
|
-
import { z as
|
|
34263
|
+
import { z as z138 } from "zod";
|
|
33799
34264
|
var startDropshippingProjectGuidance = getProductMakerCapabilityModelGuidance("start_dropshipping_project");
|
|
33800
34265
|
var costDropshippingProjectGuidance = getProductMakerCapabilityModelGuidance("cost_dropshipping_project");
|
|
33801
34266
|
var guideDropshippingLaunchGuidance = getProductMakerCapabilityModelGuidance("guide_dropshipping_launch");
|
|
33802
|
-
var ProjectId =
|
|
33803
|
-
var DropshippingProjectStatus =
|
|
34267
|
+
var ProjectId = z138.string().uuid();
|
|
34268
|
+
var DropshippingProjectStatus = z138.enum([
|
|
33804
34269
|
"active",
|
|
33805
34270
|
"completed",
|
|
33806
34271
|
"archived"
|
|
33807
34272
|
]);
|
|
33808
|
-
var DropshippingProjectPhase =
|
|
34273
|
+
var DropshippingProjectPhase = z138.enum([
|
|
33809
34274
|
"research",
|
|
33810
34275
|
"costing",
|
|
33811
34276
|
"media",
|
|
@@ -33814,21 +34279,21 @@ var DropshippingProjectPhase = z137.enum([
|
|
|
33814
34279
|
"advertising",
|
|
33815
34280
|
"complete"
|
|
33816
34281
|
]);
|
|
33817
|
-
var DropshippingRewardMilestone =
|
|
34282
|
+
var DropshippingRewardMilestone = z138.enum([
|
|
33818
34283
|
"product_selected",
|
|
33819
34284
|
"costing_saved",
|
|
33820
34285
|
"product_media_ready",
|
|
33821
34286
|
"creatives_completed",
|
|
33822
34287
|
"campaign_created"
|
|
33823
34288
|
]);
|
|
33824
|
-
var TargetCountry =
|
|
34289
|
+
var TargetCountry = z138.enum([
|
|
33825
34290
|
"CO",
|
|
33826
34291
|
"MX",
|
|
33827
34292
|
"PE",
|
|
33828
34293
|
"EC",
|
|
33829
34294
|
"CL"
|
|
33830
34295
|
]);
|
|
33831
|
-
var ResearchCategory =
|
|
34296
|
+
var ResearchCategory = z138.enum([
|
|
33832
34297
|
"auto",
|
|
33833
34298
|
"automotive",
|
|
33834
34299
|
"kitchen",
|
|
@@ -33843,7 +34308,7 @@ var ResearchCategory = z137.enum([
|
|
|
33843
34308
|
"garden",
|
|
33844
34309
|
"cleaning"
|
|
33845
34310
|
]);
|
|
33846
|
-
var HttpUrl3 =
|
|
34311
|
+
var HttpUrl3 = z138.string().url().max(2e3).refine((value) => {
|
|
33847
34312
|
try {
|
|
33848
34313
|
return [
|
|
33849
34314
|
"http:",
|
|
@@ -33853,45 +34318,45 @@ var HttpUrl3 = z137.string().url().max(2e3).refine((value) => {
|
|
|
33853
34318
|
return false;
|
|
33854
34319
|
}
|
|
33855
34320
|
}, "URL must use HTTP(S)");
|
|
33856
|
-
var ResearchCandidateOrigin =
|
|
33857
|
-
type:
|
|
34321
|
+
var ResearchCandidateOrigin = z138.object({
|
|
34322
|
+
type: z138.literal("research_candidate"),
|
|
33858
34323
|
runId: ProjectId,
|
|
33859
|
-
candidateSourceId:
|
|
34324
|
+
candidateSourceId: z138.string().min(1).max(160)
|
|
33860
34325
|
});
|
|
33861
|
-
var TaskOrigin =
|
|
33862
|
-
type:
|
|
34326
|
+
var TaskOrigin = z138.object({
|
|
34327
|
+
type: z138.literal("task"),
|
|
33863
34328
|
taskId: ProjectId
|
|
33864
34329
|
});
|
|
33865
|
-
var ManualOrigin =
|
|
33866
|
-
type:
|
|
34330
|
+
var ManualOrigin = z138.object({
|
|
34331
|
+
type: z138.literal("manual"),
|
|
33867
34332
|
clientRequestId: ProjectId,
|
|
33868
|
-
country:
|
|
34333
|
+
country: z138.string().min(2).max(3).optional()
|
|
33869
34334
|
});
|
|
33870
|
-
var StartProjectInput =
|
|
33871
|
-
origin:
|
|
34335
|
+
var StartProjectInput = z138.object({
|
|
34336
|
+
origin: z138.discriminatedUnion("type", [
|
|
33872
34337
|
ResearchCandidateOrigin,
|
|
33873
34338
|
TaskOrigin,
|
|
33874
34339
|
ManualOrigin
|
|
33875
34340
|
]),
|
|
33876
|
-
productName:
|
|
34341
|
+
productName: z138.string().trim().min(1).max(240).optional(),
|
|
33877
34342
|
productUrl: HttpUrl3.optional(),
|
|
33878
|
-
country:
|
|
33879
|
-
languageCode:
|
|
34343
|
+
country: z138.string().min(2).max(3).optional(),
|
|
34344
|
+
languageCode: z138.string().min(2).max(16).optional()
|
|
33880
34345
|
}).strict();
|
|
33881
|
-
var CostProjectInput =
|
|
34346
|
+
var CostProjectInput = z138.object({
|
|
33882
34347
|
projectId: ProjectId,
|
|
33883
|
-
version:
|
|
33884
|
-
country:
|
|
34348
|
+
version: z138.number().int().positive().describe("Version le\xEDda del proyecto. Copia la \xFAltima que viste; no se la pidas al usuario."),
|
|
34349
|
+
country: z138.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
|
|
33885
34350
|
message: "Pa\xEDs no soportado por ProductMaker."
|
|
33886
34351
|
}).describe("C\xF3digo ISO-2 del pa\xEDs del proyecto. Usa el `targetCountry` que devuelve el proyecto."),
|
|
33887
|
-
supplierCost:
|
|
33888
|
-
shippingCost:
|
|
33889
|
-
returnRate:
|
|
33890
|
-
cancellationRate:
|
|
33891
|
-
adsManagerCpa:
|
|
33892
|
-
desiredMargin:
|
|
33893
|
-
});
|
|
33894
|
-
var GuideInput =
|
|
34352
|
+
supplierCost: z138.number().finite().positive().describe("Costo real de una unidad con el proveedor, en la moneda del pa\xEDs. \xDANICO dato que debes pedirle al usuario: nunca lo inventes."),
|
|
34353
|
+
shippingCost: z138.number().finite().nonnegative().optional().describe("Costo de un env\xEDo. Omite para usar el valor gu\xEDa del pa\xEDs en vez de inventarlo."),
|
|
34354
|
+
returnRate: z138.number().finite().min(0).lt(1).optional().describe("Fracci\xF3n de pedidos devueltos (0.25 = 25%). Omite para usar el valor gu\xEDa del pa\xEDs."),
|
|
34355
|
+
cancellationRate: z138.number().finite().min(0).lt(1).optional().describe("Fracci\xF3n de pedidos cancelados (0.15 = 15%). Omite para usar el valor gu\xEDa del pa\xEDs."),
|
|
34356
|
+
adsManagerCpa: z138.number().finite().nonnegative().optional().describe("Costo por compra de Ads Manager. Omite para usar el valor gu\xEDa del pa\xEDs."),
|
|
34357
|
+
desiredMargin: z138.number().finite().min(0).lt(1).optional().describe("Margen deseado (0.1 = 10%). Omite para usar el valor gu\xEDa del pa\xEDs.")
|
|
34358
|
+
});
|
|
34359
|
+
var GuideInput = z138.object({
|
|
33895
34360
|
projectId: ProjectId.optional()
|
|
33896
34361
|
}).strict();
|
|
33897
34362
|
var NEXT_ACTION_KINDS = [
|
|
@@ -33909,29 +34374,29 @@ var NEXT_ACTION_KINDS = [
|
|
|
33909
34374
|
"repair_meta_campaign",
|
|
33910
34375
|
"review_paused_campaign"
|
|
33911
34376
|
];
|
|
33912
|
-
var DropshippingProjectNextAction =
|
|
33913
|
-
kind:
|
|
33914
|
-
href:
|
|
34377
|
+
var DropshippingProjectNextAction = z138.discriminatedUnion("kind", NEXT_ACTION_KINDS.map((kind) => z138.object({
|
|
34378
|
+
kind: z138.literal(kind),
|
|
34379
|
+
href: z138.string().min(1)
|
|
33915
34380
|
})));
|
|
33916
|
-
var CostingInputSchema =
|
|
33917
|
-
country:
|
|
33918
|
-
supplierCost:
|
|
33919
|
-
shippingCost:
|
|
33920
|
-
returnRate:
|
|
33921
|
-
cancellationRate:
|
|
33922
|
-
adsManagerCpa:
|
|
33923
|
-
desiredMargin:
|
|
34381
|
+
var CostingInputSchema = z138.object({
|
|
34382
|
+
country: z138.string().min(2).max(3),
|
|
34383
|
+
supplierCost: z138.number().finite().positive(),
|
|
34384
|
+
shippingCost: z138.number().finite().nonnegative(),
|
|
34385
|
+
returnRate: z138.number().finite().min(0).lt(1),
|
|
34386
|
+
cancellationRate: z138.number().finite().min(0).lt(1),
|
|
34387
|
+
adsManagerCpa: z138.number().finite().nonnegative(),
|
|
34388
|
+
desiredMargin: z138.number().finite().min(0).lt(1)
|
|
33924
34389
|
}).superRefine(({ returnRate, cancellationRate }, context) => {
|
|
33925
34390
|
if (returnRate + cancellationRate >= 1) context.addIssue({
|
|
33926
|
-
code:
|
|
34391
|
+
code: z138.ZodIssueCode.custom,
|
|
33927
34392
|
path: [
|
|
33928
34393
|
"cancellationRate"
|
|
33929
34394
|
]
|
|
33930
34395
|
});
|
|
33931
34396
|
});
|
|
33932
|
-
var FiniteCostingNumber =
|
|
33933
|
-
var CostingResultSchema =
|
|
33934
|
-
country:
|
|
34397
|
+
var FiniteCostingNumber = z138.number().finite();
|
|
34398
|
+
var CostingResultSchema = z138.object({
|
|
34399
|
+
country: z138.string().min(2).max(3),
|
|
33935
34400
|
deliveryRate: FiniteCostingNumber,
|
|
33936
34401
|
adjustedShippingCost: FiniteCostingNumber,
|
|
33937
34402
|
adjustedCpa: FiniteCostingNumber,
|
|
@@ -33944,45 +34409,45 @@ var CostingResultSchema = z137.object({
|
|
|
33944
34409
|
estimatedProfit: FiniteCostingNumber,
|
|
33945
34410
|
actualMargin: FiniteCostingNumber,
|
|
33946
34411
|
breakEvenAdsManagerCpa: FiniteCostingNumber,
|
|
33947
|
-
wasPriceAutoAdjusted:
|
|
33948
|
-
profitabilityStatus:
|
|
33949
|
-
});
|
|
33950
|
-
var RewardProgressSchema =
|
|
33951
|
-
campaignKey:
|
|
33952
|
-
totalCredits:
|
|
33953
|
-
earnedCredits:
|
|
33954
|
-
milestones:
|
|
34412
|
+
wasPriceAutoAdjusted: z138.boolean(),
|
|
34413
|
+
profitabilityStatus: z138.literal("healthy")
|
|
34414
|
+
});
|
|
34415
|
+
var RewardProgressSchema = z138.object({
|
|
34416
|
+
campaignKey: z138.literal("dropshipping-launch-v1"),
|
|
34417
|
+
totalCredits: z138.number().int().positive(),
|
|
34418
|
+
earnedCredits: z138.number().int().nonnegative(),
|
|
34419
|
+
milestones: z138.array(z138.object({
|
|
33955
34420
|
milestone: DropshippingRewardMilestone,
|
|
33956
|
-
credits:
|
|
33957
|
-
available:
|
|
33958
|
-
earned:
|
|
34421
|
+
credits: z138.number().int().positive(),
|
|
34422
|
+
available: z138.boolean().optional(),
|
|
34423
|
+
earned: z138.boolean(),
|
|
33959
34424
|
grantId: ProjectId.nullable(),
|
|
33960
|
-
grantedAt:
|
|
34425
|
+
grantedAt: z138.string().datetime().nullable()
|
|
33961
34426
|
})).length(DropshippingRewardMilestone.options.length)
|
|
33962
34427
|
});
|
|
33963
|
-
var ProjectResponseSchema =
|
|
34428
|
+
var ProjectResponseSchema = z138.object({
|
|
33964
34429
|
id: ProjectId,
|
|
33965
34430
|
taskId: ProjectId.nullable(),
|
|
33966
34431
|
status: DropshippingProjectStatus,
|
|
33967
|
-
originKey:
|
|
34432
|
+
originKey: z138.string().min(1),
|
|
33968
34433
|
researchRunId: ProjectId.nullable(),
|
|
33969
|
-
candidateSourceId:
|
|
33970
|
-
productName:
|
|
34434
|
+
candidateSourceId: z138.string().nullable(),
|
|
34435
|
+
productName: z138.string().nullable(),
|
|
33971
34436
|
productUrl: HttpUrl3.nullable(),
|
|
33972
34437
|
referenceImageUrl: HttpUrl3.nullable(),
|
|
33973
|
-
targetCountry:
|
|
33974
|
-
languageCode:
|
|
33975
|
-
hasReferenceImage:
|
|
33976
|
-
hasWinnerReferenceImage:
|
|
34438
|
+
targetCountry: z138.string().nullable(),
|
|
34439
|
+
languageCode: z138.string().nullable(),
|
|
34440
|
+
hasReferenceImage: z138.boolean(),
|
|
34441
|
+
hasWinnerReferenceImage: z138.boolean(),
|
|
33977
34442
|
costingInput: CostingInputSchema.nullable(),
|
|
33978
34443
|
costingResult: CostingResultSchema.nullable(),
|
|
33979
|
-
costingVersion:
|
|
33980
|
-
version:
|
|
34444
|
+
costingVersion: z138.number().int().positive().nullable(),
|
|
34445
|
+
version: z138.number().int().positive(),
|
|
33981
34446
|
phase: DropshippingProjectPhase,
|
|
33982
34447
|
nextAction: DropshippingProjectNextAction.nullable(),
|
|
33983
34448
|
rewards: RewardProgressSchema,
|
|
33984
|
-
createdAt:
|
|
33985
|
-
updatedAt:
|
|
34449
|
+
createdAt: z138.string().datetime(),
|
|
34450
|
+
updatedAt: z138.string().datetime()
|
|
33986
34451
|
}).passthrough();
|
|
33987
34452
|
var NEXT_ACTION_GUIDANCE = {
|
|
33988
34453
|
cost_product: "Llama `cost_dropshipping_project` con el costo real del proveedor. Nunca lo inventes: p\xEDdeselo al usuario. Es el \xDANICO dato que debes pedirle: omite env\xEDo, devoluciones, cancelaciones, CPA y margen para que ProductMaker use los valores gu\xEDa del pa\xEDs, y luego dile al usuario cu\xE1les us\xF3 por si quiere corregirlos.",
|
|
@@ -34102,58 +34567,58 @@ function registerDropshippingProjectTools(server, api) {
|
|
|
34102
34567
|
__name(registerDropshippingProjectTools, "registerDropshippingProjectTools");
|
|
34103
34568
|
|
|
34104
34569
|
// src/tools/daily-control.ts
|
|
34105
|
-
import { z as
|
|
34570
|
+
import { z as z139 } from "zod";
|
|
34106
34571
|
var getDailyControlGuidance = getProductMakerCapabilityModelGuidance("get_daily_control");
|
|
34107
34572
|
var linkCampaignToProjectGuidance = getProductMakerCapabilityModelGuidance("link_campaign_to_project");
|
|
34108
34573
|
var reportDailyReturnsGuidance = getProductMakerCapabilityModelGuidance("report_daily_returns");
|
|
34109
|
-
var ProviderCampaignIdentifier =
|
|
34110
|
-
var DateOnly =
|
|
34111
|
-
var DailyControlInput =
|
|
34574
|
+
var ProviderCampaignIdentifier = z139.string().min(1).max(64).regex(/^[A-Za-z0-9_-]+$/);
|
|
34575
|
+
var DateOnly = z139.string().regex(/^\d{4}-\d{2}-\d{2}$/);
|
|
34576
|
+
var DailyControlInput = z139.object({
|
|
34112
34577
|
date: DateOnly.optional().describe("D\xEDa final de la ventana (YYYY-MM-DD). Si se omite, la ventana termina AYER en UTC \u2014 nunca hoy, porque el d\xEDa en curso est\xE1 incompleto \u2014 y el servidor puede correrla un d\xEDa m\xE1s atr\xE1s si en la zona horaria de la tienda ese d\xEDa todav\xEDa no ha cerrado."),
|
|
34113
|
-
days:
|
|
34114
|
-
projectId:
|
|
34578
|
+
days: z139.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
|
|
34579
|
+
projectId: z139.string().uuid().optional().describe("Opcional: limita el reporte a un solo proyecto en vez de todos los productos activos.")
|
|
34115
34580
|
}).strict();
|
|
34116
|
-
var LinkCampaignInput =
|
|
34117
|
-
projectId:
|
|
34118
|
-
provider:
|
|
34581
|
+
var LinkCampaignInput = z139.object({
|
|
34582
|
+
projectId: z139.string().uuid(),
|
|
34583
|
+
provider: z139.enum([
|
|
34119
34584
|
"meta",
|
|
34120
34585
|
"tiktok"
|
|
34121
34586
|
]),
|
|
34122
34587
|
accountId: ProviderCampaignIdentifier.describe("Cuenta publicitaria del proveedor. Para Meta el servidor la IGNORA y deriva la cuenta real de la campa\xF1a \u2014 se sigue pidiendo aqu\xED solo porque TikTok s\xED la necesita para resolver la campa\xF1a."),
|
|
34123
34588
|
campaignId: ProviderCampaignIdentifier
|
|
34124
34589
|
}).strict();
|
|
34125
|
-
var ReportReturnsInput =
|
|
34126
|
-
projectId:
|
|
34590
|
+
var ReportReturnsInput = z139.object({
|
|
34591
|
+
projectId: z139.string().uuid(),
|
|
34127
34592
|
date: DateOnly,
|
|
34128
|
-
returnedOrders:
|
|
34129
|
-
note:
|
|
34593
|
+
returnedOrders: z139.number().int().min(0).max(1e5),
|
|
34594
|
+
note: z139.string().trim().max(280).optional()
|
|
34130
34595
|
}).strict();
|
|
34131
|
-
var DailyControlStatusMirror = DailyControlStatusEnum.or(
|
|
34132
|
-
var DailyControlLightMirror = DailyControlLightEnum.or(
|
|
34133
|
-
var DailyControlSourceMirror = DailyControlSourceEnum.or(
|
|
34134
|
-
var DailyControlVerdictMirror = DailyControlVerdictEnum.or(
|
|
34135
|
-
var DailyControlDayMirror =
|
|
34136
|
-
date:
|
|
34137
|
-
returnedOrders:
|
|
34596
|
+
var DailyControlStatusMirror = DailyControlStatusEnum.or(z139.string());
|
|
34597
|
+
var DailyControlLightMirror = DailyControlLightEnum.or(z139.string());
|
|
34598
|
+
var DailyControlSourceMirror = DailyControlSourceEnum.or(z139.string());
|
|
34599
|
+
var DailyControlVerdictMirror = DailyControlVerdictEnum.or(z139.string());
|
|
34600
|
+
var DailyControlDayMirror = z139.object({
|
|
34601
|
+
date: z139.string(),
|
|
34602
|
+
returnedOrders: z139.number(),
|
|
34138
34603
|
returnedSource: DailyControlSourceMirror,
|
|
34139
34604
|
cancelledSource: DailyControlSourceMirror,
|
|
34140
|
-
hasEstimates:
|
|
34605
|
+
hasEstimates: z139.boolean(),
|
|
34141
34606
|
light: DailyControlLightMirror
|
|
34142
34607
|
}).passthrough();
|
|
34143
|
-
var DailyControlProductMirror =
|
|
34144
|
-
projectId:
|
|
34145
|
-
productName:
|
|
34608
|
+
var DailyControlProductMirror = z139.object({
|
|
34609
|
+
projectId: z139.string().uuid(),
|
|
34610
|
+
productName: z139.string().nullable(),
|
|
34146
34611
|
status: DailyControlStatusMirror,
|
|
34147
|
-
statusMessage:
|
|
34148
|
-
days:
|
|
34612
|
+
statusMessage: z139.string().nullable(),
|
|
34613
|
+
days: z139.array(DailyControlDayMirror),
|
|
34149
34614
|
verdict: DailyControlVerdictMirror.nullable(),
|
|
34150
|
-
rationale:
|
|
34615
|
+
rationale: z139.string().nullable()
|
|
34151
34616
|
}).passthrough();
|
|
34152
|
-
var DailyControlResponseMirror =
|
|
34153
|
-
since:
|
|
34154
|
-
until:
|
|
34155
|
-
products:
|
|
34156
|
-
archivedProjectSpend:
|
|
34617
|
+
var DailyControlResponseMirror = z139.object({
|
|
34618
|
+
since: z139.string(),
|
|
34619
|
+
until: z139.string(),
|
|
34620
|
+
products: z139.array(DailyControlProductMirror),
|
|
34621
|
+
archivedProjectSpend: z139.array(z139.unknown())
|
|
34157
34622
|
}).passthrough();
|
|
34158
34623
|
var MCP_WARNINGS_KEY = "_mcpDailyControlWarnings";
|
|
34159
34624
|
function withWarnings(response) {
|
|
@@ -34228,7 +34693,7 @@ __name(registerDailyControlTools, "registerDailyControlTools");
|
|
|
34228
34693
|
// src/tools/product-control.ts
|
|
34229
34694
|
import { readFile, stat } from "fs/promises";
|
|
34230
34695
|
import { basename as basename2, isAbsolute, resolve as resolve3 } from "path";
|
|
34231
|
-
import { z as
|
|
34696
|
+
import { z as z140 } from "zod";
|
|
34232
34697
|
var getProductControlGuidance = getProductMakerCapabilityModelGuidance("get_product_control");
|
|
34233
34698
|
var listImportableProductsGuidance = getProductMakerCapabilityModelGuidance("list_importable_products");
|
|
34234
34699
|
var importProductControlsGuidance = getProductMakerCapabilityModelGuidance("import_product_controls");
|
|
@@ -34241,36 +34706,36 @@ var createOperationGuidance = getProductMakerCapabilityModelGuidance("create_ope
|
|
|
34241
34706
|
var mergeProductsGuidance = getProductMakerCapabilityModelGuidance("merge_products");
|
|
34242
34707
|
var syncShopifyOrdersGuidance = getProductMakerCapabilityModelGuidance("sync_shopify_orders");
|
|
34243
34708
|
var importOrdersFileGuidance = getProductMakerCapabilityModelGuidance("import_orders_file");
|
|
34244
|
-
var DateOnly2 =
|
|
34709
|
+
var DateOnly2 = z140.string().regex(/^\d{4}-\d{2}-\d{2}$/);
|
|
34245
34710
|
var IMPORT_BATCH_MAX2 = 50;
|
|
34246
|
-
var ProductControlListInput =
|
|
34247
|
-
days:
|
|
34711
|
+
var ProductControlListInput = z140.object({
|
|
34712
|
+
days: z140.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
|
|
34248
34713
|
date: DateOnly2.optional().describe("D\xEDa final de la ventana (YYYY-MM-DD). Si se omite, termina en el \xFAltimo d\xEDa cerrado \u2014 nunca hoy, que est\xE1 incompleto."),
|
|
34249
|
-
shopDomain:
|
|
34714
|
+
shopDomain: z140.string().min(1).optional().describe("Tienda, si tiene m\xE1s de una conectada.")
|
|
34250
34715
|
}).strict();
|
|
34251
|
-
var ImportableProductsInput =
|
|
34252
|
-
q:
|
|
34253
|
-
after:
|
|
34254
|
-
shopDomain:
|
|
34716
|
+
var ImportableProductsInput = z140.object({
|
|
34717
|
+
q: z140.string().trim().max(120).optional().describe("B\xFAsqueda por t\xEDtulo. Sin esto un cat\xE1logo grande es inrecorrible."),
|
|
34718
|
+
after: z140.string().max(512).optional().describe("Cursor de la p\xE1gina anterior, tal como vino en la respuesta."),
|
|
34719
|
+
shopDomain: z140.string().min(1).optional()
|
|
34255
34720
|
}).strict();
|
|
34256
|
-
var ImportProductControlsInput =
|
|
34257
|
-
shopifyProductIds:
|
|
34721
|
+
var ImportProductControlsInput = z140.object({
|
|
34722
|
+
shopifyProductIds: z140.array(z140.string().min(1).max(64)).min(1).max(IMPORT_BATCH_MAX2).describe("Identificadores tal como vinieron de list_importable_products. NO los inventes ni los deduzcas del t\xEDtulo."),
|
|
34258
34723
|
// Obligatorio, como en el endpoint: con dos tiendas conectadas, importar
|
|
34259
34724
|
// sin decir a cuál archivaría el producto bajo la tienda equivocada.
|
|
34260
|
-
shopDomain:
|
|
34725
|
+
shopDomain: z140.string().min(1)
|
|
34261
34726
|
}).strict();
|
|
34262
|
-
var SetProductCostingInput =
|
|
34263
|
-
shopDomain:
|
|
34264
|
-
shopifyProductId:
|
|
34265
|
-
targetCountry:
|
|
34266
|
-
supplierCost:
|
|
34267
|
-
shippingCost:
|
|
34268
|
-
returnRate:
|
|
34269
|
-
cancellationRate:
|
|
34727
|
+
var SetProductCostingInput = z140.object({
|
|
34728
|
+
shopDomain: z140.string().min(1),
|
|
34729
|
+
shopifyProductId: z140.string().min(1).max(64),
|
|
34730
|
+
targetCountry: z140.string().length(2).describe("Pa\xEDs de venta en ISO-2, que fija moneda y referencia de flete."),
|
|
34731
|
+
supplierCost: z140.number().finite().positive().describe("Lo que le cuesta el producto al proveedor. Nunca cero."),
|
|
34732
|
+
shippingCost: z140.number().finite().nonnegative(),
|
|
34733
|
+
returnRate: z140.number().finite().min(0).lt(1).describe("Proporci\xF3n 0\u20131, no porcentaje: 0.15 es quince por ciento."),
|
|
34734
|
+
cancellationRate: z140.number().finite().min(0).lt(1)
|
|
34270
34735
|
}).strict();
|
|
34271
|
-
var Count =
|
|
34272
|
-
var ReportProductCountsInput =
|
|
34273
|
-
productControlId:
|
|
34736
|
+
var Count = z140.number().int().min(0).max(1e5).nullable().optional();
|
|
34737
|
+
var ReportProductCountsInput = z140.object({
|
|
34738
|
+
productControlId: z140.string().uuid().describe("El identificador que devuelve get_product_control."),
|
|
34274
34739
|
date: DateOnly2,
|
|
34275
34740
|
orders: Count.describe("Pedidos que entraron ese d\xEDa."),
|
|
34276
34741
|
cancelledOrders: Count,
|
|
@@ -34280,36 +34745,36 @@ var ReportProductCountsInput = z139.object({
|
|
|
34280
34745
|
}).strict();
|
|
34281
34746
|
var MAX_ORDERS_FILE_BYTES = 8 * 1024 * 1024;
|
|
34282
34747
|
var SyncShopifyOrdersInput = SyncShopifyOrdersSchema;
|
|
34283
|
-
var ImportOrdersFileInput =
|
|
34748
|
+
var ImportOrdersFileInput = z140.object({
|
|
34284
34749
|
/** Ruta ABSOLUTA en la máquina de quien usa el MCP. */
|
|
34285
|
-
path:
|
|
34286
|
-
operationId:
|
|
34750
|
+
path: z140.string().min(1),
|
|
34751
|
+
operationId: z140.string().uuid().optional(),
|
|
34287
34752
|
/** Solo mirar: devuelve el resumen y no escribe nada. */
|
|
34288
|
-
dryRun:
|
|
34753
|
+
dryRun: z140.boolean().optional()
|
|
34289
34754
|
}).strict();
|
|
34290
|
-
var CreateOperationInput =
|
|
34291
|
-
countryCode:
|
|
34292
|
-
label:
|
|
34755
|
+
var CreateOperationInput = z140.object({
|
|
34756
|
+
countryCode: z140.string().length(2),
|
|
34757
|
+
label: z140.string().trim().min(1).max(60).optional()
|
|
34293
34758
|
}).strict();
|
|
34294
|
-
var MergeProductsInput =
|
|
34295
|
-
sourceId:
|
|
34296
|
-
targetId:
|
|
34759
|
+
var MergeProductsInput = z140.object({
|
|
34760
|
+
sourceId: z140.string().uuid(),
|
|
34761
|
+
targetId: z140.string().uuid()
|
|
34297
34762
|
}).strict();
|
|
34298
|
-
var SetMonthlyExpenseInput =
|
|
34299
|
-
month:
|
|
34763
|
+
var SetMonthlyExpenseInput = z140.object({
|
|
34764
|
+
month: z140.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/).optional(),
|
|
34300
34765
|
label: SaveMonthlyExpenseSchema.shape.label,
|
|
34301
|
-
amount:
|
|
34302
|
-
operationId:
|
|
34766
|
+
amount: z140.number().finite().min(0),
|
|
34767
|
+
operationId: z140.string().uuid().optional()
|
|
34303
34768
|
}).strict();
|
|
34304
|
-
var SetAdSpendInput =
|
|
34305
|
-
month:
|
|
34306
|
-
operationId:
|
|
34769
|
+
var SetAdSpendInput = z140.object({
|
|
34770
|
+
month: z140.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/).optional(),
|
|
34771
|
+
operationId: z140.string().uuid().optional(),
|
|
34307
34772
|
/** null RETIRA la corrección; cero afirma que no pautó. */
|
|
34308
|
-
amount:
|
|
34773
|
+
amount: z140.number().finite().min(0).nullable()
|
|
34309
34774
|
}).strict();
|
|
34310
|
-
var GetFinancesInput =
|
|
34311
|
-
month:
|
|
34312
|
-
operationId:
|
|
34775
|
+
var GetFinancesInput = z140.object({
|
|
34776
|
+
month: z140.string().regex(/^\d{4}-(0[1-9]|1[0-2])$/).optional().describe("Mes en YYYY-MM. Si se omite, el mes en curso. Solo mes calendario."),
|
|
34777
|
+
operationId: z140.string().uuid().optional().describe("El negocio, si tiene mas de uno. Con uno solo no hace falta decirlo.")
|
|
34313
34778
|
}).strict();
|
|
34314
34779
|
function registerProductControlTools(server, api, { transport = "http" } = {}) {
|
|
34315
34780
|
server.registerTool("get_product_control", {
|
|
@@ -34501,28 +34966,28 @@ function registerProductControlTools(server, api, { transport = "http" } = {}) {
|
|
|
34501
34966
|
__name(registerProductControlTools, "registerProductControlTools");
|
|
34502
34967
|
|
|
34503
34968
|
// src/tools/market-study-estimate.ts
|
|
34504
|
-
import { z as
|
|
34969
|
+
import { z as z141 } from "zod";
|
|
34505
34970
|
var estimateMarketStudyGuidance = getProductMakerCapabilityModelGuidance("estimate_market_study_cost");
|
|
34506
|
-
var ProductTaskOutputEnum =
|
|
34971
|
+
var ProductTaskOutputEnum = z141.enum([
|
|
34507
34972
|
"landing",
|
|
34508
34973
|
"video",
|
|
34509
34974
|
"image"
|
|
34510
34975
|
]);
|
|
34511
|
-
var EstimateMarketStudyInput =
|
|
34512
|
-
kind:
|
|
34976
|
+
var EstimateMarketStudyInput = z141.object({
|
|
34977
|
+
kind: z141.enum([
|
|
34513
34978
|
"video",
|
|
34514
34979
|
"product_task"
|
|
34515
34980
|
]).describe('"video" para generate_video_creative; "product_task" para create_product_task.'),
|
|
34516
|
-
videoAngleCount:
|
|
34517
|
-
durationSeconds:
|
|
34981
|
+
videoAngleCount: z141.number().int().min(1).max(3).describe("Los mismos 1, 2 o 3 videos que vas a pedir al crear."),
|
|
34982
|
+
durationSeconds: z141.number().int().min(4).max(30).default(15).describe("La misma duraci\xF3n que enviar\xE1s al crear."),
|
|
34518
34983
|
videoStructure: VideoStructureEnum.default("single_take"),
|
|
34519
34984
|
videoQuality: VideoQualityEnum.default("economy"),
|
|
34520
34985
|
videoResolution: VideoResolutionEnum.default("480p"),
|
|
34521
|
-
productImageCount:
|
|
34986
|
+
productImageCount: z141.number().int().min(1).max(5).optional().describe("Cantidad de fotos del producto que adjuntar\xE1s (1-5)."),
|
|
34522
34987
|
outputs: ProductTaskOutputEnum.array().min(1).max(3).optional().describe('Solo para kind="product_task": los mismos outputs de create_product_task. Default: todos.'),
|
|
34523
|
-
generateAiMusic:
|
|
34988
|
+
generateAiMusic: z141.boolean().optional(),
|
|
34524
34989
|
generateAiEdit: AiEditRequestSchema.optional(),
|
|
34525
|
-
replicateWinnerWhenFound:
|
|
34990
|
+
replicateWinnerWhenFound: z141.boolean().optional().describe("La misma preferencia que enviar\xE1s al crear. false excluye la reserva de r\xE9plica del ganador de la cotizaci\xF3n con estudio.")
|
|
34526
34991
|
}).strict();
|
|
34527
34992
|
function buildMarketStudyEstimateRequests(input) {
|
|
34528
34993
|
const quotesVideo = input.kind === "video" || (input.outputs ?? [
|