@productmaker/mcp 8.1.0 → 8.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +14 -1
- package/dist/http.js +1940 -861
- package/dist/stdio.js +1885 -836
- package/package.json +1 -1
package/dist/stdio.js
CHANGED
|
@@ -90,6 +90,23 @@ var VideoPreset = z.enum([
|
|
|
90
90
|
]);
|
|
91
91
|
var VoiceId = z.string();
|
|
92
92
|
var _VIDEO_MODEL_SET = new Set(VideoModel.options);
|
|
93
|
+
var BROLL_VIDEO_MODES = new Set(VideoModel.options);
|
|
94
|
+
var PersistedVideoMode = z.enum([
|
|
95
|
+
...VideoModel.options,
|
|
96
|
+
"avatar_talking",
|
|
97
|
+
"hybrid",
|
|
98
|
+
"sora"
|
|
99
|
+
]);
|
|
100
|
+
var PersistedVideoModel = z.enum([
|
|
101
|
+
...VideoModel.options,
|
|
102
|
+
"sora",
|
|
103
|
+
"infinitalk"
|
|
104
|
+
]);
|
|
105
|
+
var PLAN_VIDEO_MODES = [
|
|
106
|
+
...VideoModel.options,
|
|
107
|
+
"avatar_talking",
|
|
108
|
+
"hybrid"
|
|
109
|
+
];
|
|
93
110
|
|
|
94
111
|
// ../../packages/types/src/video-creation.ts
|
|
95
112
|
import { z as z3 } from "zod";
|
|
@@ -1060,40 +1077,206 @@ var VideoTier = z8.preprocess((v) => v === "grok" ? "single_call" : v, z8.enum([
|
|
|
1060
1077
|
"single_call"
|
|
1061
1078
|
]));
|
|
1062
1079
|
var DEFAULT_VIDEO_TIER = "single_call";
|
|
1080
|
+
var WritableVideoTier = VideoTier.refine((tier) => tier !== "legacy", {
|
|
1081
|
+
message: "VIDEO_TIER_RETIRED"
|
|
1082
|
+
});
|
|
1063
1083
|
|
|
1064
|
-
// ../../packages/types/src/image-
|
|
1065
|
-
var
|
|
1066
|
-
"
|
|
1067
|
-
"
|
|
1084
|
+
// ../../packages/types/src/image-models.ts
|
|
1085
|
+
var IMAGE_RESOLUTIONS = [
|
|
1086
|
+
"1k",
|
|
1087
|
+
"2k",
|
|
1088
|
+
"4k"
|
|
1068
1089
|
];
|
|
1069
|
-
var
|
|
1070
|
-
"
|
|
1071
|
-
"5:
|
|
1072
|
-
"
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
"
|
|
1090
|
+
var GPT_IMAGE_2_5_TOKENS = {
|
|
1091
|
+
"1k": "gpt-image-2-5:1k",
|
|
1092
|
+
"2k": "gpt-image-2-5:2k",
|
|
1093
|
+
"4k": "gpt-image-2-5:4k"
|
|
1094
|
+
};
|
|
1095
|
+
var GPT_IMAGE_2_TOKENS = {
|
|
1096
|
+
"1k": "gpt-image-2:1k",
|
|
1097
|
+
"2k": "gpt-image-2:2k",
|
|
1098
|
+
"4k": "gpt-image-2:4k"
|
|
1099
|
+
};
|
|
1100
|
+
var GPT_IMAGE_2_5 = {
|
|
1101
|
+
id: "gpt-image-2.5",
|
|
1102
|
+
status: "active",
|
|
1103
|
+
renderedBy: "gpt-image-2.5",
|
|
1104
|
+
tokens: GPT_IMAGE_2_5_TOKENS,
|
|
1105
|
+
kie: {
|
|
1106
|
+
imageToImage: [
|
|
1107
|
+
"gpt-image-2-5-sunburst-image-to-image",
|
|
1108
|
+
"gpt-image-2-5-flare-image-to-image"
|
|
1109
|
+
],
|
|
1110
|
+
textToImage: [
|
|
1111
|
+
"gpt-image-2-5-sunburst-text-to-image",
|
|
1112
|
+
"gpt-image-2-5-flare-text-to-image"
|
|
1113
|
+
],
|
|
1114
|
+
shorthands: [
|
|
1115
|
+
"gpt-image-2-5"
|
|
1116
|
+
]
|
|
1117
|
+
},
|
|
1118
|
+
fal: {
|
|
1119
|
+
edit: "openai/gpt-image-2.5/sunburst/edit",
|
|
1120
|
+
textToImage: "openai/gpt-image-2.5/sunburst/text-to-image",
|
|
1121
|
+
quality: {
|
|
1122
|
+
"1k": "low",
|
|
1123
|
+
"2k": "medium",
|
|
1124
|
+
"4k": "high"
|
|
1125
|
+
},
|
|
1126
|
+
ourCostCents: {
|
|
1127
|
+
"1k": 1.5,
|
|
1128
|
+
"2k": 6.1,
|
|
1129
|
+
"4k": 17.8
|
|
1130
|
+
}
|
|
1131
|
+
},
|
|
1132
|
+
// Docs KIE de gpt-image-2-5 (sunburst/flare): 27:16, 16:27, 9:8, 8:9 solo 1K;
|
|
1133
|
+
// 4:5 y 5:4 también bloqueados por encima de 1K.
|
|
1134
|
+
ratiosBlockedAbove1k: [
|
|
1135
|
+
"4:5",
|
|
1136
|
+
"5:4",
|
|
1137
|
+
"27:16",
|
|
1138
|
+
"16:27",
|
|
1139
|
+
"9:8",
|
|
1140
|
+
"8:9"
|
|
1141
|
+
],
|
|
1142
|
+
ledgerSuffix: {
|
|
1143
|
+
"1k": "gpt-image-2",
|
|
1144
|
+
"2k": "gpt-image-2:medium",
|
|
1145
|
+
"4k": "gpt-image-2:high"
|
|
1146
|
+
},
|
|
1147
|
+
falLedgerSuffix: {
|
|
1148
|
+
"1k": "gpt-image-2:1k",
|
|
1149
|
+
"2k": "gpt-image-2:2k",
|
|
1150
|
+
"4k": "gpt-image-2:4k"
|
|
1151
|
+
}
|
|
1152
|
+
};
|
|
1153
|
+
var GPT_IMAGE_2 = {
|
|
1154
|
+
...GPT_IMAGE_2_5,
|
|
1155
|
+
id: "gpt-image-2",
|
|
1156
|
+
status: "retired",
|
|
1157
|
+
renderedBy: GPT_IMAGE_2_5.id,
|
|
1158
|
+
tokens: GPT_IMAGE_2_TOKENS,
|
|
1159
|
+
kie: {
|
|
1160
|
+
imageToImage: [
|
|
1161
|
+
"gpt-image-2-image-to-image"
|
|
1162
|
+
],
|
|
1163
|
+
textToImage: [
|
|
1164
|
+
"gpt-image-2-text-to-image"
|
|
1165
|
+
],
|
|
1166
|
+
shorthands: [
|
|
1167
|
+
"gpt-image-2"
|
|
1168
|
+
]
|
|
1169
|
+
},
|
|
1170
|
+
ratiosBlockedAbove1k: [
|
|
1171
|
+
"4:5",
|
|
1172
|
+
"5:4"
|
|
1173
|
+
]
|
|
1174
|
+
};
|
|
1175
|
+
var IMAGE_MODELS = [
|
|
1176
|
+
GPT_IMAGE_2_5,
|
|
1177
|
+
GPT_IMAGE_2
|
|
1076
1178
|
];
|
|
1077
|
-
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1179
|
+
var ACTIVE_IMAGE_MODEL = GPT_IMAGE_2_5;
|
|
1180
|
+
var IMAGE_WRITE_TOKENS = GPT_IMAGE_2_5_TOKENS;
|
|
1181
|
+
var LEGACY_IMAGE_TOKENS = GPT_IMAGE_2_TOKENS;
|
|
1182
|
+
var PUBLIC_IMAGE_QUALITY_INPUTS = [
|
|
1183
|
+
IMAGE_WRITE_TOKENS["1k"],
|
|
1184
|
+
IMAGE_WRITE_TOKENS["2k"],
|
|
1185
|
+
LEGACY_IMAGE_TOKENS["1k"],
|
|
1186
|
+
LEGACY_IMAGE_TOKENS["2k"],
|
|
1187
|
+
"image:1k",
|
|
1188
|
+
"image:2k"
|
|
1189
|
+
];
|
|
1190
|
+
function entryById(id) {
|
|
1191
|
+
const found = IMAGE_MODELS.find((entry) => entry.id === id);
|
|
1192
|
+
if (!found) throw new Error(`IMAGE_MODEL_UNKNOWN:${id}`);
|
|
1193
|
+
return found;
|
|
1194
|
+
}
|
|
1195
|
+
__name(entryById, "entryById");
|
|
1196
|
+
function resolveImageToken(raw) {
|
|
1197
|
+
if (typeof raw !== "string") return null;
|
|
1198
|
+
let normalized = raw.trim().toLowerCase();
|
|
1199
|
+
let viaFal = false;
|
|
1200
|
+
if (normalized.startsWith("fal:")) {
|
|
1201
|
+
viaFal = true;
|
|
1202
|
+
normalized = normalized.slice("fal:".length);
|
|
1203
|
+
}
|
|
1204
|
+
for (const resolution of IMAGE_RESOLUTIONS) {
|
|
1205
|
+
if (normalized === `image:${resolution}`) {
|
|
1206
|
+
return {
|
|
1207
|
+
resolution,
|
|
1208
|
+
model: ACTIVE_IMAGE_MODEL,
|
|
1209
|
+
declared: ACTIVE_IMAGE_MODEL,
|
|
1210
|
+
spelling: "intent",
|
|
1211
|
+
viaFal
|
|
1212
|
+
};
|
|
1213
|
+
}
|
|
1214
|
+
}
|
|
1215
|
+
for (const entry of IMAGE_MODELS) {
|
|
1216
|
+
for (const resolution of IMAGE_RESOLUTIONS) {
|
|
1217
|
+
if (entry.tokens[resolution] === normalized) {
|
|
1218
|
+
return {
|
|
1219
|
+
resolution,
|
|
1220
|
+
model: entryById(entry.renderedBy),
|
|
1221
|
+
declared: entry,
|
|
1222
|
+
spelling: entry.status === "active" ? "current" : "retired",
|
|
1223
|
+
viaFal
|
|
1224
|
+
};
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1081
1227
|
}
|
|
1082
|
-
return
|
|
1228
|
+
return null;
|
|
1229
|
+
}
|
|
1230
|
+
__name(resolveImageToken, "resolveImageToken");
|
|
1231
|
+
function imageResolutionOf(raw) {
|
|
1232
|
+
const token = resolveImageToken(raw);
|
|
1233
|
+
return token && !token.viaFal ? token.resolution : null;
|
|
1234
|
+
}
|
|
1235
|
+
__name(imageResolutionOf, "imageResolutionOf");
|
|
1236
|
+
function requireKieImageId(ids, index, label) {
|
|
1237
|
+
const id = ids[index];
|
|
1238
|
+
if (!id) throw new Error(`IMAGE_MODEL_NO_KIE_ID:${label}`);
|
|
1239
|
+
return id;
|
|
1240
|
+
}
|
|
1241
|
+
__name(requireKieImageId, "requireKieImageId");
|
|
1242
|
+
var KIE_FLARE_IMAGE_TO_IMAGE_MODEL = requireKieImageId(GPT_IMAGE_2_5.kie.imageToImage, 1, "flare-imageToImage");
|
|
1243
|
+
function canonicalImageModelInput(raw) {
|
|
1244
|
+
if (raw === void 0) return void 0;
|
|
1245
|
+
const token = resolveImageToken(raw);
|
|
1246
|
+
if (!token || token.viaFal || token.spelling !== "intent") return raw;
|
|
1247
|
+
return IMAGE_WRITE_TOKENS[token.resolution];
|
|
1248
|
+
}
|
|
1249
|
+
__name(canonicalImageModelInput, "canonicalImageModelInput");
|
|
1250
|
+
function imageTokenSupportsRatio(aspectRatio, rawToken) {
|
|
1251
|
+
const token = resolveImageToken(rawToken);
|
|
1252
|
+
if (!token) return true;
|
|
1253
|
+
if (token.resolution === "1k") return true;
|
|
1254
|
+
return !token.declared.ratiosBlockedAbove1k.includes(aspectRatio);
|
|
1255
|
+
}
|
|
1256
|
+
__name(imageTokenSupportsRatio, "imageTokenSupportsRatio");
|
|
1257
|
+
|
|
1258
|
+
// ../../packages/types/src/image-provider.ts
|
|
1259
|
+
var GPT_IMAGE_2_RATIOS_BLOCKED_ABOVE_1K = GPT_IMAGE_2.ratiosBlockedAbove1k;
|
|
1260
|
+
var GPT_IMAGE_2_5_RATIOS_BLOCKED_ABOVE_1K = GPT_IMAGE_2_5.ratiosBlockedAbove1k;
|
|
1261
|
+
function gptImage2SupportsTier(aspectRatio, tier) {
|
|
1262
|
+
return imageTokenSupportsRatio(aspectRatio, tier);
|
|
1083
1263
|
}
|
|
1084
1264
|
__name(gptImage2SupportsTier, "gptImage2SupportsTier");
|
|
1085
1265
|
var IMAGE_TIER_UNSUPPORTED_FOR_RATIO_RULE = "image_tier_unsupported_for_ratio";
|
|
1086
1266
|
var IMAGE_TIER_LIST = [
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
"gpt-image-2-5:4k",
|
|
1090
|
-
"gpt-image-2:1k",
|
|
1091
|
-
"gpt-image-2:2k",
|
|
1092
|
-
"gpt-image-2:4k"
|
|
1267
|
+
...Object.values(IMAGE_WRITE_TOKENS),
|
|
1268
|
+
...Object.values(LEGACY_IMAGE_TOKENS)
|
|
1093
1269
|
];
|
|
1270
|
+
function isImageTier(value) {
|
|
1271
|
+
return IMAGE_TIER_LIST.includes(value);
|
|
1272
|
+
}
|
|
1273
|
+
__name(isImageTier, "isImageTier");
|
|
1094
1274
|
function parseImageTier(imageModel) {
|
|
1095
|
-
const
|
|
1096
|
-
|
|
1275
|
+
const token = resolveImageToken(imageModel);
|
|
1276
|
+
if (!token || token.viaFal) return null;
|
|
1277
|
+
if (token.spelling === "intent") return IMAGE_WRITE_TOKENS[token.resolution];
|
|
1278
|
+
const declared = token.declared.tokens[token.resolution];
|
|
1279
|
+
return isImageTier(declared) ? declared : null;
|
|
1097
1280
|
}
|
|
1098
1281
|
__name(parseImageTier, "parseImageTier");
|
|
1099
1282
|
function validateImageTierForRatio(aspectRatio, imageModel) {
|
|
@@ -1669,6 +1852,9 @@ var VideoCreativeJobStatus = z14.object({
|
|
|
1669
1852
|
var VideoCreativeJobPayload = z14.object({
|
|
1670
1853
|
jobId: z14.string().optional(),
|
|
1671
1854
|
status: VideoCreativeJobStatusEnum.optional(),
|
|
1855
|
+
/** True when the submission replayed an existing task instead of billing
|
|
1856
|
+
* new work — callers surface the twin verbatim. Omitted on fresh creates. */
|
|
1857
|
+
replayed: z14.boolean().optional(),
|
|
1672
1858
|
videoStructure: VideoStructure.optional(),
|
|
1673
1859
|
videoQuality: VideoQuality.optional(),
|
|
1674
1860
|
videoRouteId: VideoRouteId.optional(),
|
|
@@ -1762,7 +1948,8 @@ var ImageCreativeJobStatus = z14.object({
|
|
|
1762
1948
|
});
|
|
1763
1949
|
var ImageCreativeJobPayload = z14.object({
|
|
1764
1950
|
jobId: z14.string().uuid(),
|
|
1765
|
-
status: ImageCreativeJobStatusEnum
|
|
1951
|
+
status: ImageCreativeJobStatusEnum,
|
|
1952
|
+
replayed: z14.boolean().optional()
|
|
1766
1953
|
});
|
|
1767
1954
|
var ImageCreativeHistoryEntry = z14.object({
|
|
1768
1955
|
id: z14.string().uuid(),
|
|
@@ -1789,7 +1976,8 @@ var LandingCreativeJobStatus = z14.object({
|
|
|
1789
1976
|
});
|
|
1790
1977
|
var LandingCreativeJobPayload = z14.object({
|
|
1791
1978
|
jobId: z14.string().uuid(),
|
|
1792
|
-
status: LandingCreativeJobStatusEnum
|
|
1979
|
+
status: LandingCreativeJobStatusEnum,
|
|
1980
|
+
replayed: z14.boolean().optional()
|
|
1793
1981
|
});
|
|
1794
1982
|
var LandingCreativeHistoryEntry = z14.object({
|
|
1795
1983
|
id: z14.string().uuid(),
|
|
@@ -3830,7 +4018,7 @@ var IngestOptions = z22.object({
|
|
|
3830
4018
|
durationSeconds: FreeVideoOptionsSchema.shape.durationSeconds.optional(),
|
|
3831
4019
|
addSubtitles: FreeVideoOptionsSchema.shape.addSubtitles.optional(),
|
|
3832
4020
|
subtitleText: z22.string().transform((value) => value.trim()).pipe(z22.string().max(FREE_VIDEO_SUBTITLE_MAX_CHARS)).optional(),
|
|
3833
|
-
videoTier:
|
|
4021
|
+
videoTier: WritableVideoTier.default(DEFAULT_VIDEO_TIER),
|
|
3834
4022
|
narrativeStyle: NarrativeStyle.default("review"),
|
|
3835
4023
|
videoPreset: VideoPreset.optional(),
|
|
3836
4024
|
multiAngleVideos: z22.boolean().default(false),
|
|
@@ -3904,7 +4092,9 @@ var IngestOptions = z22.object({
|
|
|
3904
4092
|
aspectRatio: z22.string().optional(),
|
|
3905
4093
|
brandColors: z22.string().optional(),
|
|
3906
4094
|
nVariants: z22.number().int().min(1).max(6).optional(),
|
|
3907
|
-
|
|
4095
|
+
// O7: `image:Nk` is accepted and stored as the spelling written today
|
|
4096
|
+
// (IMAGE_WRITE_TOKENS); see packages/types/src/image-models.ts.
|
|
4097
|
+
imageModel: z22.string().optional().transform((value) => canonicalImageModelInput(value)),
|
|
3908
4098
|
styleMix: z22.string().optional(),
|
|
3909
4099
|
aiDecidesAll: z22.boolean().optional(),
|
|
3910
4100
|
/** Opt out of the competitor-spy analysis. When false the worker skips
|
|
@@ -4023,7 +4213,7 @@ var VideoOptionsOverride = z22.object({
|
|
|
4023
4213
|
videoStructure: VideoStructure.optional(),
|
|
4024
4214
|
videoQuality: VideoQuality.optional(),
|
|
4025
4215
|
videoModel: VideoModel.optional(),
|
|
4026
|
-
videoTier:
|
|
4216
|
+
videoTier: WritableVideoTier.optional(),
|
|
4027
4217
|
ugcFormat: VideoFormat.optional(),
|
|
4028
4218
|
videoStyle: VideoStyle.optional(),
|
|
4029
4219
|
narrativeStyle: NarrativeStyle.optional(),
|
|
@@ -4106,6 +4296,11 @@ var IngestResumePayload = z22.object({
|
|
|
4106
4296
|
// "keep what the task has". See angle-management.service.ts resumeAfterAngles.
|
|
4107
4297
|
videoStyle: VideoStyle.optional(),
|
|
4108
4298
|
videoModel: VideoModel.default("veo"),
|
|
4299
|
+
// READ schema on purpose, unlike IngestOptions/VideoOptionsOverride: resume
|
|
4300
|
+
// does not write the tier — `resumeAfterAngles` projects the route from the
|
|
4301
|
+
// task's OWN persisted tier and ignores this field. MCP and WhatsApp echo
|
|
4302
|
+
// `status.videoTier`, which is still `legacy` for historical rows; refusing
|
|
4303
|
+
// it made those tasks impossible to resume from both channels.
|
|
4109
4304
|
videoTier: VideoTier.optional(),
|
|
4110
4305
|
videoStructure: VideoStructure.optional(),
|
|
4111
4306
|
videoQuality: VideoQuality.optional(),
|
|
@@ -4916,17 +5111,7 @@ var VideoGenerator = z26.object({
|
|
|
4916
5111
|
format: VideoFormat.optional(),
|
|
4917
5112
|
videoStyle: VideoStyle.optional(),
|
|
4918
5113
|
narrativeStyle: NarrativeStyle.optional(),
|
|
4919
|
-
videoMode:
|
|
4920
|
-
"veo",
|
|
4921
|
-
"wan",
|
|
4922
|
-
"bytedance",
|
|
4923
|
-
"seedance",
|
|
4924
|
-
"grok",
|
|
4925
|
-
"kling",
|
|
4926
|
-
"avatar_talking",
|
|
4927
|
-
"hybrid",
|
|
4928
|
-
"sora"
|
|
4929
|
-
]).optional(),
|
|
5114
|
+
videoMode: PersistedVideoMode.optional(),
|
|
4930
5115
|
videoResolution: VideoResolution.optional(),
|
|
4931
5116
|
videoStructure: VideoStructure.optional(),
|
|
4932
5117
|
videoQuality: VideoQuality.optional(),
|
|
@@ -5463,6 +5648,10 @@ var CreateShopifySubscriptionRequest = z28.object({
|
|
|
5463
5648
|
var CreateShopifyBillingChargeRequest = z28.object({
|
|
5464
5649
|
packId: z28.string().min(1)
|
|
5465
5650
|
});
|
|
5651
|
+
var ShopifyBillingCallbackQuery = z28.object({
|
|
5652
|
+
charge_id: z28.string().regex(/^\d+$/),
|
|
5653
|
+
transactionId: z28.string().uuid()
|
|
5654
|
+
});
|
|
5466
5655
|
var CancelShopifySubscriptionRequest = z28.object({
|
|
5467
5656
|
subscriptionId: z28.string().min(1)
|
|
5468
5657
|
});
|
|
@@ -7291,7 +7480,8 @@ var IMAGE_QA_GATES = [
|
|
|
7291
7480
|
"limb",
|
|
7292
7481
|
"device_panel",
|
|
7293
7482
|
"critical_feature",
|
|
7294
|
-
"cross_section"
|
|
7483
|
+
"cross_section",
|
|
7484
|
+
"usage_fidelity"
|
|
7295
7485
|
];
|
|
7296
7486
|
var ImageQaGate = z36.enum(IMAGE_QA_GATES);
|
|
7297
7487
|
var ImageQaGateOutcome = z36.enum([
|
|
@@ -8337,6 +8527,10 @@ var GEMINI_OMNI_FLAT_USER_PRICE_CENTS = 168;
|
|
|
8337
8527
|
// ../../packages/types/src/pricing.ts
|
|
8338
8528
|
var CREDITS_PER_USD_CENT = 10;
|
|
8339
8529
|
var CREDITS_PER_DOLLAR = 100 * CREDITS_PER_USD_CENT;
|
|
8530
|
+
var AD_CREATIVE_MODELS = {
|
|
8531
|
+
STANDARD: IMAGE_WRITE_TOKENS["1k"],
|
|
8532
|
+
PREMIUM: IMAGE_WRITE_TOKENS["2k"]
|
|
8533
|
+
};
|
|
8340
8534
|
var KALODATA_USD_CENTS_PER_PROVIDER_CREDIT = 9;
|
|
8341
8535
|
var KALODATA_PROVIDER_CREDITS_PER_SOURCE_CEILING = 7.5;
|
|
8342
8536
|
var DEFAULT_PRICING = {
|
|
@@ -9295,6 +9489,27 @@ var DEFAULT_PRICING = {
|
|
|
9295
9489
|
ourCostCents: 1.88,
|
|
9296
9490
|
userPriceCents: 3.76
|
|
9297
9491
|
},
|
|
9492
|
+
// Usage decider (role `usage-decider`: Gemini 3.8 Flash effort:'high' since
|
|
9493
|
+
// 05f543eae, ≤6 images + seller text, temperature 0 json_object, once per
|
|
9494
|
+
// classic landing, always on). Was 3¢ measured on Claude
|
|
9495
|
+
// Sonnet 5 (spike 2026-09-24, 17 prod tasks). NOT re-measured on Flash — no
|
|
9496
|
+
// local BillingEntry row carries the Flash decider yet — so it is priced as
|
|
9497
|
+
// the product truth (`openrouter:product-truth`, 2.2¢ measured from
|
|
9498
|
+
// OpenRouter usage.cost): same model, same effort, same ≤6-photo input and a
|
|
9499
|
+
// JSON answer of similar size. Refine from usage.cost after the e2e. Fallback
|
|
9500
|
+
// only (OpenRouter's usage.cost is billed when present).
|
|
9501
|
+
"openrouter:usage-decision": {
|
|
9502
|
+
ourCostCents: 2.2,
|
|
9503
|
+
userPriceCents: 4.4
|
|
9504
|
+
},
|
|
9505
|
+
// Usage-fidelity QA judge (records misuse; regen gated separately behind
|
|
9506
|
+
// always on, bounded by USAGE_FIDELITY_MAX_REGENS). Sized off landing-image-qa beside it: same
|
|
9507
|
+
// shape of call (1-2 images, a verdict), so quoted at the same rate until
|
|
9508
|
+
// it has its own BillingEntry volume to re-derive from.
|
|
9509
|
+
"openrouter:usage-fidelity": {
|
|
9510
|
+
ourCostCents: 1.88,
|
|
9511
|
+
userPriceCents: 3.76
|
|
9512
|
+
},
|
|
9298
9513
|
// Landing commercial-facts extraction (gemini-3.8-flash, ONE text-only call over
|
|
9299
9514
|
// the seller's offer/context/features). Sized off the image-QA key beside it,
|
|
9300
9515
|
// which measured 1.88¢ at ~11.1K prompt tokens: this prompt is capped at ~3K in
|
|
@@ -10033,6 +10248,24 @@ var DEFAULT_PRICING = {
|
|
|
10033
10248
|
ourCostCents: 0.2,
|
|
10034
10249
|
userPriceCents: 0.4
|
|
10035
10250
|
},
|
|
10251
|
+
// Product truth (Gemini 3.8 Flash effort:'high', ≤6 photos + all seller text, once per
|
|
10252
|
+
// extract, always on). Plan C spike 2026-09-24: 6 calls, US$0.132 total ⇒
|
|
10253
|
+
// 2.2¢/call measured from OpenRouter usage.cost. Replaces usage spec + functional demo +
|
|
10254
|
+
// product-use sheet (+ landing visual-context-fusion) on the same task. Fallback only.
|
|
10255
|
+
"openrouter:product-truth": {
|
|
10256
|
+
ourCostCents: 2.2,
|
|
10257
|
+
userPriceCents: 4.4
|
|
10258
|
+
},
|
|
10259
|
+
// Landing creative director, «categorías» arm (Gemini 3.8 Flash effort:'high', ≤6 photos +
|
|
10260
|
+
// all seller text + the section plan, once per classic landing behind
|
|
10261
|
+
// LANDING_DIRECTOR_ENABLED). ESTIMATE, not measured: same call shape as the product truth
|
|
10262
|
+
// (2.2¢) with a ~2-3x longer JSON answer (one content spec per section) ⇒ ~4¢. Replaces
|
|
10263
|
+
// the visual brief (4¢) + visual-context fusion (0.4¢) + usage decision (2.2¢) on that
|
|
10264
|
+
// landing. Refine from OpenRouter usage.cost after the e2e. Fallback only.
|
|
10265
|
+
"openrouter:landing-director": {
|
|
10266
|
+
ourCostCents: 4,
|
|
10267
|
+
userPriceCents: 8
|
|
10268
|
+
},
|
|
10036
10269
|
// Unit = one reference-grouping pass over the user's product images (0.1241¢).
|
|
10037
10270
|
"openrouter:product-reference-grouping": {
|
|
10038
10271
|
ourCostCents: 0.15,
|
|
@@ -10646,6 +10879,7 @@ var MixSceneResult = z48.object({
|
|
|
10646
10879
|
index: z48.number().int().positive(),
|
|
10647
10880
|
status: z48.enum([
|
|
10648
10881
|
"queued",
|
|
10882
|
+
"submitting",
|
|
10649
10883
|
"submitted",
|
|
10650
10884
|
"done",
|
|
10651
10885
|
"failed"
|
|
@@ -13244,7 +13478,7 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
|
|
|
13244
13478
|
], [
|
|
13245
13479
|
"product_costing"
|
|
13246
13480
|
]),
|
|
13247
|
-
defineCapability("create_creative_variant", "
|
|
13481
|
+
defineCapability("create_creative_variant", "3e02399a7785df328f1c4d63cfbb6d7481abaac9f91d4a5cf51d410e657d63aa", "credit_consuming", "creative", [
|
|
13248
13482
|
"credit_consuming",
|
|
13249
13483
|
"state_change"
|
|
13250
13484
|
], [
|
|
@@ -13494,7 +13728,9 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
|
|
|
13494
13728
|
// MCP 7.0.0 (Task 11, .agent/plans/2026-09-15-model-agnostic-video-routes.md):
|
|
13495
13729
|
// `freeProModel` retired in favor of `modelId` (registry ids). Recomputed
|
|
13496
13730
|
// from `pnpm --filter @productmaker/mcp test` printing the real digest.
|
|
13497
|
-
|
|
13731
|
+
// Re-baselined 2026-09-26: `idempotencyKey` field description corrected —
|
|
13732
|
+
// paid tools ignore caller-provided keys and derive their own semantic key.
|
|
13733
|
+
"35616a32a42a0bc062218fdfbb4cc7f4ecfa814571fb86b4f11ef9e4184855e1",
|
|
13498
13734
|
"credit_consuming",
|
|
13499
13735
|
"creative",
|
|
13500
13736
|
[
|
|
@@ -13550,7 +13786,7 @@ var PRODUCTMAKER_CAPABILITY_REGISTRY = deepFreeze([
|
|
|
13550
13786
|
"video"
|
|
13551
13787
|
]
|
|
13552
13788
|
),
|
|
13553
|
-
defineCapability("generate_image_creatives", "
|
|
13789
|
+
defineCapability("generate_image_creatives", "2f1698b623d98645b7c618a17988f3aac30f403a9c3f3dc26eb5bdbd9c6ef23e", "credit_consuming", "creative", [
|
|
13554
13790
|
"credit_consuming",
|
|
13555
13791
|
"state_change"
|
|
13556
13792
|
], [
|
|
@@ -14947,79 +15183,696 @@ var WhatsAppPresentationManifestSchema = z67.object({
|
|
|
14947
15183
|
}
|
|
14948
15184
|
});
|
|
14949
15185
|
|
|
14950
|
-
// ../../packages/types/src/
|
|
15186
|
+
// ../../packages/types/src/usage-decision.ts
|
|
14951
15187
|
import { z as z68 } from "zod";
|
|
14952
|
-
|
|
15188
|
+
|
|
15189
|
+
// ../../packages/types/src/text-clamp.ts
|
|
15190
|
+
function clampAtWordBoundary(value, max) {
|
|
15191
|
+
if (typeof value !== "string") return value;
|
|
15192
|
+
if (value.length <= max) return value;
|
|
15193
|
+
const cut = value.slice(0, max);
|
|
15194
|
+
const lastSpace = cut.lastIndexOf(" ");
|
|
15195
|
+
const atWordBoundary = lastSpace > 0 ? cut.slice(0, lastSpace) : cut;
|
|
15196
|
+
return atWordBoundary.replace(/[,;:\s]+$/, "");
|
|
15197
|
+
}
|
|
15198
|
+
__name(clampAtWordBoundary, "clampAtWordBoundary");
|
|
15199
|
+
function clampStringArray(max) {
|
|
15200
|
+
return (value) => {
|
|
15201
|
+
if (!Array.isArray(value)) return value;
|
|
15202
|
+
const nonEmpty = value.filter((item) => typeof item === "string" && item.trim().length > 0);
|
|
15203
|
+
return nonEmpty.slice(0, max);
|
|
15204
|
+
};
|
|
15205
|
+
}
|
|
15206
|
+
__name(clampStringArray, "clampStringArray");
|
|
15207
|
+
|
|
15208
|
+
// ../../packages/types/src/usage-decision.ts
|
|
15209
|
+
var USAGE_SCENE_RULE_MAX_CHARS = 240;
|
|
15210
|
+
var USAGE_DECISION_MAX_REQUIRED_PARTS = 6;
|
|
15211
|
+
var USAGE_DECISION_MAX_ALTERNATE_USES = 4;
|
|
15212
|
+
var USAGE_DECISION_MAX_MISUSE = 5;
|
|
15213
|
+
function clampRule(value) {
|
|
15214
|
+
return clampAtWordBoundary(value, USAGE_SCENE_RULE_MAX_CHARS);
|
|
15215
|
+
}
|
|
15216
|
+
__name(clampRule, "clampRule");
|
|
15217
|
+
var UsageDecisionSchema = z68.object({
|
|
15218
|
+
productIdentity: z68.string().min(1),
|
|
15219
|
+
endUser: z68.object({
|
|
15220
|
+
who: z68.string(),
|
|
15221
|
+
appliedTo: z68.string()
|
|
15222
|
+
}),
|
|
15223
|
+
promise: z68.string().min(1),
|
|
15224
|
+
primaryUse: z68.object({
|
|
15225
|
+
scene: z68.string().min(1),
|
|
15226
|
+
postureAndGrip: z68.string(),
|
|
15227
|
+
contactPoint: z68.string(),
|
|
15228
|
+
requiredParts: z68.preprocess(clampStringArray(USAGE_DECISION_MAX_REQUIRED_PARTS), z68.array(z68.string()).max(USAGE_DECISION_MAX_REQUIRED_PARTS))
|
|
15229
|
+
}),
|
|
15230
|
+
validAlternateUses: z68.preprocess(clampStringArray(USAGE_DECISION_MAX_ALTERNATE_USES), z68.array(z68.string()).max(USAGE_DECISION_MAX_ALTERNATE_USES)),
|
|
15231
|
+
misuse: z68.preprocess(clampStringArray(USAGE_DECISION_MAX_MISUSE), z68.array(z68.string().min(1)).max(USAGE_DECISION_MAX_MISUSE)),
|
|
15232
|
+
useSceneRule: z68.preprocess(clampRule, z68.string().min(1).max(USAGE_SCENE_RULE_MAX_CHARS)),
|
|
15233
|
+
/**
|
|
15234
|
+
* True when the promise can ONLY be shown with the primary use (the pain is bending over and
|
|
15235
|
+
* the product has an extension pole: without the pole there is no promise); false when the
|
|
15236
|
+
* valid alternates sell it equally. Drives whether an alternate use in a use scene is a
|
|
15237
|
+
* failure (`requirePrimary` in the usage judge) and whether the prompts' primary use is
|
|
15238
|
+
* mandatory. Optional and fail-safe: missing (decisions stored before the field) or not a
|
|
15239
|
+
* boolean ⇒ `undefined`, read as false by every caller — never a rejected decision.
|
|
15240
|
+
*/
|
|
15241
|
+
primaryRequired: z68.boolean().optional().catch(void 0),
|
|
15242
|
+
confidence: z68.number().min(0).max(1),
|
|
15243
|
+
modelId: z68.string(),
|
|
15244
|
+
decidedAt: z68.string()
|
|
15245
|
+
});
|
|
15246
|
+
|
|
15247
|
+
// ../../packages/types/src/product-truth.ts
|
|
15248
|
+
import { z as z70 } from "zod";
|
|
15249
|
+
|
|
15250
|
+
// ../../packages/types/src/lenient-zod.ts
|
|
15251
|
+
import { z as z69 } from "zod";
|
|
15252
|
+
function trimAndClamp(value, max) {
|
|
15253
|
+
if (typeof value !== "string") return value;
|
|
15254
|
+
return clampAtWordBoundary(value.replace(/\s+/g, " ").trim(), max);
|
|
15255
|
+
}
|
|
15256
|
+
__name(trimAndClamp, "trimAndClamp");
|
|
15257
|
+
function lenientText(max) {
|
|
15258
|
+
return z69.preprocess((v) => trimAndClamp(v, max), z69.string().min(1).max(max));
|
|
15259
|
+
}
|
|
15260
|
+
__name(lenientText, "lenientText");
|
|
15261
|
+
function lenientOptionalText(max) {
|
|
15262
|
+
return z69.preprocess((v) => {
|
|
15263
|
+
if (typeof v !== "string") return void 0;
|
|
15264
|
+
const clamped = trimAndClamp(v, max);
|
|
15265
|
+
return typeof clamped === "string" && clamped.length > 0 ? clamped : void 0;
|
|
15266
|
+
}, z69.string().max(max).optional());
|
|
15267
|
+
}
|
|
15268
|
+
__name(lenientOptionalText, "lenientOptionalText");
|
|
15269
|
+
function lenientTextList(maxItems, maxChars) {
|
|
15270
|
+
return z69.preprocess((v) => {
|
|
15271
|
+
if (!Array.isArray(v)) return [];
|
|
15272
|
+
return v.map((item) => trimAndClamp(item, maxChars)).filter((item) => typeof item === "string" && item.length > 0).slice(0, maxItems);
|
|
15273
|
+
}, z69.array(z69.string().min(1).max(maxChars)).max(maxItems));
|
|
15274
|
+
}
|
|
15275
|
+
__name(lenientTextList, "lenientTextList");
|
|
15276
|
+
function lenientList(item, maxItems) {
|
|
15277
|
+
return z69.preprocess((v) => {
|
|
15278
|
+
if (!Array.isArray(v)) return [];
|
|
15279
|
+
return v.filter((entry) => item.safeParse(entry).success).slice(0, maxItems);
|
|
15280
|
+
}, z69.array(item).max(maxItems));
|
|
15281
|
+
}
|
|
15282
|
+
__name(lenientList, "lenientList");
|
|
15283
|
+
|
|
15284
|
+
// ../../packages/types/src/product-truth.ts
|
|
15285
|
+
var PRODUCT_TRUTH_SCHEMA_VERSION = 1;
|
|
15286
|
+
var PRODUCT_TRUTH_CAPS = {
|
|
15287
|
+
whatItIs: 160,
|
|
15288
|
+
deliveryForm: 120,
|
|
15289
|
+
distinctiveMarks: 6,
|
|
15290
|
+
distinctiveMarkChars: 160,
|
|
15291
|
+
parts: 12,
|
|
15292
|
+
partNameChars: 80,
|
|
15293
|
+
criticalFeatures: 6,
|
|
15294
|
+
connections: 6,
|
|
15295
|
+
connectionChars: 80,
|
|
15296
|
+
states: 4,
|
|
15297
|
+
stateKeyChars: 60,
|
|
15298
|
+
stateLabelChars: 80,
|
|
15299
|
+
partsPresent: 10,
|
|
15300
|
+
orientationInUseChars: 200,
|
|
15301
|
+
appliedToChars: 120,
|
|
15302
|
+
environmentChars: 120,
|
|
15303
|
+
summaryChars: 200,
|
|
15304
|
+
sceneChars: 300,
|
|
15305
|
+
postureAndGripChars: 160,
|
|
15306
|
+
contactPointChars: 120,
|
|
15307
|
+
steps: 8,
|
|
15308
|
+
stepNameChars: 120,
|
|
15309
|
+
stepInstructionChars: 300,
|
|
15310
|
+
visibleEffectChars: 200,
|
|
15311
|
+
beforeStateChars: 200,
|
|
15312
|
+
requiredProps: 8,
|
|
15313
|
+
requiredPropChars: 120,
|
|
15314
|
+
alternates: 3,
|
|
15315
|
+
misuse: 5,
|
|
15316
|
+
misuseChars: 200,
|
|
15317
|
+
mustShowFeatures: 5,
|
|
15318
|
+
mustShowFeatureChars: 100,
|
|
15319
|
+
safety: 5,
|
|
15320
|
+
safetyChars: 200,
|
|
15321
|
+
forbiddenClaims: 8,
|
|
15322
|
+
unsupportedClaims: 5,
|
|
15323
|
+
claimChars: 200,
|
|
15324
|
+
visualSummaryEnChars: 400
|
|
15325
|
+
};
|
|
15326
|
+
var PRODUCT_TRUTH_END_USER_AGE_BANDS = [
|
|
15327
|
+
"baby",
|
|
15328
|
+
"child",
|
|
15329
|
+
"teen",
|
|
15330
|
+
"adult",
|
|
15331
|
+
"any"
|
|
15332
|
+
];
|
|
15333
|
+
var PRODUCT_TRUTH_END_USER_GENDERS = [
|
|
15334
|
+
"female",
|
|
15335
|
+
"male",
|
|
15336
|
+
"any"
|
|
15337
|
+
];
|
|
15338
|
+
var PRODUCT_TRUTH_UNKNOWN_REASONS = [
|
|
15339
|
+
"model_unsure",
|
|
15340
|
+
"no_signal",
|
|
15341
|
+
"invalid_response",
|
|
15342
|
+
"provider_error"
|
|
15343
|
+
];
|
|
15344
|
+
var text = lenientText;
|
|
15345
|
+
var optionalText = lenientOptionalText;
|
|
15346
|
+
var textList = lenientTextList;
|
|
15347
|
+
function toProductTruthStateKey(value) {
|
|
15348
|
+
if (typeof value !== "string") return void 0;
|
|
15349
|
+
const slug = value.toLowerCase().normalize("NFD").replace(/[\u0300-\u036f]/g, "").replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, PRODUCT_TRUTH_CAPS.stateKeyChars);
|
|
15350
|
+
return slug.length > 0 ? slug : void 0;
|
|
15351
|
+
}
|
|
15352
|
+
__name(toProductTruthStateKey, "toProductTruthStateKey");
|
|
15353
|
+
var stateKey = z70.preprocess(toProductTruthStateKey, z70.string().min(1).max(PRODUCT_TRUTH_CAPS.stateKeyChars));
|
|
15354
|
+
var optionalStateKey = z70.preprocess(toProductTruthStateKey, z70.string().min(1).max(PRODUCT_TRUTH_CAPS.stateKeyChars).optional());
|
|
15355
|
+
var AGE_BAND_ALIASES = {
|
|
15356
|
+
baby: "baby",
|
|
15357
|
+
babies: "baby",
|
|
15358
|
+
infant: "baby",
|
|
15359
|
+
infants: "baby",
|
|
15360
|
+
toddler: "child",
|
|
15361
|
+
child: "child",
|
|
15362
|
+
children: "child",
|
|
15363
|
+
kid: "child",
|
|
15364
|
+
kids: "child",
|
|
15365
|
+
teen: "teen",
|
|
15366
|
+
teens: "teen",
|
|
15367
|
+
teenager: "teen",
|
|
15368
|
+
teenagers: "teen",
|
|
15369
|
+
adult: "adult",
|
|
15370
|
+
adults: "adult",
|
|
15371
|
+
any: "any",
|
|
15372
|
+
all: "any",
|
|
15373
|
+
"all ages": "any"
|
|
15374
|
+
};
|
|
15375
|
+
var GENDER_ALIASES = {
|
|
15376
|
+
female: "female",
|
|
15377
|
+
woman: "female",
|
|
15378
|
+
women: "female",
|
|
15379
|
+
girl: "female",
|
|
15380
|
+
male: "male",
|
|
15381
|
+
man: "male",
|
|
15382
|
+
men: "male",
|
|
15383
|
+
boy: "male",
|
|
15384
|
+
any: "any",
|
|
15385
|
+
unisex: "any",
|
|
15386
|
+
both: "any",
|
|
15387
|
+
all: "any"
|
|
15388
|
+
};
|
|
15389
|
+
function matchAlias(raw, aliases) {
|
|
15390
|
+
if (typeof raw !== "string") return void 0;
|
|
15391
|
+
const text2 = raw.trim().toLowerCase();
|
|
15392
|
+
const exact = aliases[text2];
|
|
15393
|
+
if (exact) return exact;
|
|
15394
|
+
const words = new Set(text2.split(/[^a-z]+/).filter(Boolean));
|
|
15395
|
+
for (const [alias, value] of Object.entries(aliases)) {
|
|
15396
|
+
if (words.has(alias)) return value;
|
|
15397
|
+
}
|
|
15398
|
+
return void 0;
|
|
15399
|
+
}
|
|
15400
|
+
__name(matchAlias, "matchAlias");
|
|
15401
|
+
function normalizeEndUser(value) {
|
|
15402
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) return void 0;
|
|
15403
|
+
const v = value;
|
|
15404
|
+
const age = matchAlias(v.ageBand, AGE_BAND_ALIASES);
|
|
15405
|
+
const gender = matchAlias(v.gender, GENDER_ALIASES);
|
|
15406
|
+
if (!age || !gender || typeof v.usedByBuyer !== "boolean") return void 0;
|
|
15407
|
+
return {
|
|
15408
|
+
ageBand: age,
|
|
15409
|
+
gender,
|
|
15410
|
+
usedByBuyer: v.usedByBuyer
|
|
15411
|
+
};
|
|
15412
|
+
}
|
|
15413
|
+
__name(normalizeEndUser, "normalizeEndUser");
|
|
15414
|
+
var ProductTruthEndUserSchema = z70.object({
|
|
15415
|
+
ageBand: z70.enum(PRODUCT_TRUTH_END_USER_AGE_BANDS),
|
|
15416
|
+
gender: z70.enum(PRODUCT_TRUTH_END_USER_GENDERS),
|
|
15417
|
+
usedByBuyer: z70.boolean()
|
|
15418
|
+
});
|
|
15419
|
+
var MATERIAL_HINTS = ProductMorphology.shape.materialHints.unwrap().element.options;
|
|
15420
|
+
var DEMO_TYPES = FunctionalDemonstration.shape.demoType;
|
|
15421
|
+
var PartSchema = z70.object({
|
|
15422
|
+
name: text(PRODUCT_TRUTH_CAPS.partNameChars),
|
|
15423
|
+
kind: z70.enum([
|
|
15424
|
+
"rigid",
|
|
15425
|
+
"flexible",
|
|
15426
|
+
"joint"
|
|
15427
|
+
]).catch("rigid"),
|
|
15428
|
+
count: z70.number().int().min(1).max(20).catch(1)
|
|
15429
|
+
});
|
|
15430
|
+
var CriticalFeatureSchema = z70.object({
|
|
15431
|
+
name: text(60),
|
|
15432
|
+
importance: text(120),
|
|
15433
|
+
antiPattern: optionalText(80),
|
|
15434
|
+
expectedCount: z70.number().int().min(1).max(20).optional().catch(void 0)
|
|
15435
|
+
});
|
|
15436
|
+
var ConnectionSchema = z70.object({
|
|
15437
|
+
part: text(PRODUCT_TRUTH_CAPS.connectionChars),
|
|
15438
|
+
attachesTo: text(PRODUCT_TRUTH_CAPS.connectionChars),
|
|
15439
|
+
where: optionalText(PRODUCT_TRUTH_CAPS.connectionChars)
|
|
15440
|
+
});
|
|
15441
|
+
var StateSchema = z70.object({
|
|
15442
|
+
key: stateKey,
|
|
15443
|
+
label: optionalText(PRODUCT_TRUTH_CAPS.stateLabelChars),
|
|
15444
|
+
partsPresent: textList(PRODUCT_TRUTH_CAPS.partsPresent, PRODUCT_TRUTH_CAPS.partNameChars),
|
|
15445
|
+
orientationInUse: text(PRODUCT_TRUTH_CAPS.orientationInUseChars),
|
|
15446
|
+
naturalOrientation: ProductNaturalOrientation.optional().catch(void 0)
|
|
15447
|
+
});
|
|
15448
|
+
var StepSchema = z70.object({
|
|
15449
|
+
name: text(PRODUCT_TRUTH_CAPS.stepNameChars),
|
|
15450
|
+
instruction: text(PRODUCT_TRUTH_CAPS.stepInstructionChars),
|
|
15451
|
+
kind: z70.enum([
|
|
15452
|
+
"setup",
|
|
15453
|
+
"use",
|
|
15454
|
+
"finish"
|
|
15455
|
+
]).catch("use")
|
|
15456
|
+
});
|
|
15457
|
+
var AlternateSchema = z70.object({
|
|
15458
|
+
summary: text(PRODUCT_TRUTH_CAPS.summaryChars),
|
|
15459
|
+
stateKey: optionalStateKey,
|
|
15460
|
+
advertisedBySeller: z70.boolean().catch(false)
|
|
15461
|
+
});
|
|
15462
|
+
var DemoSchema = z70.object({
|
|
15463
|
+
demoType: DEMO_TYPES.nullable().catch(null),
|
|
15464
|
+
mustShowFeatures: textList(PRODUCT_TRUTH_CAPS.mustShowFeatures, PRODUCT_TRUTH_CAPS.mustShowFeatureChars),
|
|
15465
|
+
importance: z70.enum([
|
|
15466
|
+
"critical",
|
|
15467
|
+
"important",
|
|
15468
|
+
"nice_to_have"
|
|
15469
|
+
]).catch("important")
|
|
15470
|
+
});
|
|
15471
|
+
var objectOrEmpty = /* @__PURE__ */ __name((v) => v && typeof v === "object" && !Array.isArray(v) ? v : {}, "objectOrEmpty");
|
|
15472
|
+
var ProductTruthBody = z70.object({
|
|
15473
|
+
identity: z70.object({
|
|
15474
|
+
whatItIs: text(PRODUCT_TRUTH_CAPS.whatItIs),
|
|
15475
|
+
deliveryForm: optionalText(PRODUCT_TRUTH_CAPS.deliveryForm),
|
|
15476
|
+
distinctiveMarks: textList(PRODUCT_TRUTH_CAPS.distinctiveMarks, PRODUCT_TRUTH_CAPS.distinctiveMarkChars)
|
|
15477
|
+
}),
|
|
15478
|
+
morphology: z70.preprocess(objectOrEmpty, z70.object({
|
|
15479
|
+
shape: ProductGeometryShape.optional().catch(void 0),
|
|
15480
|
+
crossSection: ProductCrossSection.optional().catch(void 0),
|
|
15481
|
+
cornerProfile: ProductCornerProfile.optional().catch(void 0),
|
|
15482
|
+
silhouetteWidthToHeightRatio: z70.number().min(0.05).max(20).optional().catch(void 0),
|
|
15483
|
+
parts: lenientList(PartSchema, PRODUCT_TRUTH_CAPS.parts),
|
|
15484
|
+
criticalFeatures: lenientList(CriticalFeatureSchema, PRODUCT_TRUTH_CAPS.criticalFeatures),
|
|
15485
|
+
shapeLockLevel: z70.enum([
|
|
15486
|
+
"strict",
|
|
15487
|
+
"moderate",
|
|
15488
|
+
"relaxed"
|
|
15489
|
+
]).optional().catch(void 0),
|
|
15490
|
+
materialHints: z70.preprocess((v) => Array.isArray(v) ? [
|
|
15491
|
+
...new Set(v.filter((m) => MATERIAL_HINTS.includes(m)))
|
|
15492
|
+
].slice(0, 3) : [], z70.array(z70.enum(MATERIAL_HINTS)).max(3))
|
|
15493
|
+
})),
|
|
15494
|
+
assembly: z70.object({
|
|
15495
|
+
connections: lenientList(ConnectionSchema, PRODUCT_TRUTH_CAPS.connections),
|
|
15496
|
+
states: z70.preprocess((v) => {
|
|
15497
|
+
if (!Array.isArray(v)) return v;
|
|
15498
|
+
const seen = /* @__PURE__ */ new Set();
|
|
15499
|
+
return v.filter((entry) => {
|
|
15500
|
+
const parsed = StateSchema.safeParse(entry);
|
|
15501
|
+
if (!parsed.success || seen.has(parsed.data.key)) return false;
|
|
15502
|
+
seen.add(parsed.data.key);
|
|
15503
|
+
return true;
|
|
15504
|
+
}).slice(0, PRODUCT_TRUTH_CAPS.states);
|
|
15505
|
+
}, z70.array(StateSchema).min(1).max(PRODUCT_TRUTH_CAPS.states)),
|
|
15506
|
+
defaultStateKey: optionalStateKey
|
|
15507
|
+
}),
|
|
15508
|
+
use: z70.object({
|
|
15509
|
+
endUser: z70.preprocess(normalizeEndUser, ProductTruthEndUserSchema.optional()).catch(void 0),
|
|
15510
|
+
appliedTo: optionalText(PRODUCT_TRUTH_CAPS.appliedToChars),
|
|
15511
|
+
environment: optionalText(PRODUCT_TRUTH_CAPS.environmentChars),
|
|
15512
|
+
primary: z70.object({
|
|
15513
|
+
summary: text(PRODUCT_TRUTH_CAPS.summaryChars),
|
|
15514
|
+
scene: text(PRODUCT_TRUTH_CAPS.sceneChars),
|
|
15515
|
+
postureAndGrip: optionalText(PRODUCT_TRUTH_CAPS.postureAndGripChars),
|
|
15516
|
+
contactPoint: optionalText(PRODUCT_TRUTH_CAPS.contactPointChars),
|
|
15517
|
+
stateKey: optionalStateKey,
|
|
15518
|
+
steps: z70.preprocess((v) => Array.isArray(v) ? v.filter((s) => StepSchema.safeParse(s).success).slice(0, PRODUCT_TRUTH_CAPS.steps) : v, z70.array(StepSchema).min(1).max(PRODUCT_TRUTH_CAPS.steps)),
|
|
15519
|
+
visibleEffect: optionalText(PRODUCT_TRUTH_CAPS.visibleEffectChars),
|
|
15520
|
+
beforeState: optionalText(PRODUCT_TRUTH_CAPS.beforeStateChars),
|
|
15521
|
+
requiredProps: textList(PRODUCT_TRUTH_CAPS.requiredProps, PRODUCT_TRUTH_CAPS.requiredPropChars)
|
|
15522
|
+
}),
|
|
15523
|
+
alternates: lenientList(AlternateSchema, PRODUCT_TRUTH_CAPS.alternates),
|
|
15524
|
+
misuse: textList(PRODUCT_TRUTH_CAPS.misuse, PRODUCT_TRUTH_CAPS.misuseChars),
|
|
15525
|
+
demo: z70.preprocess(objectOrEmpty, DemoSchema),
|
|
15526
|
+
safety: textList(PRODUCT_TRUTH_CAPS.safety, PRODUCT_TRUTH_CAPS.safetyChars)
|
|
15527
|
+
}),
|
|
15528
|
+
claims: z70.preprocess(objectOrEmpty, z70.object({
|
|
15529
|
+
forbidden: textList(PRODUCT_TRUTH_CAPS.forbiddenClaims, PRODUCT_TRUTH_CAPS.claimChars),
|
|
15530
|
+
unsupported: textList(PRODUCT_TRUTH_CAPS.unsupportedClaims, PRODUCT_TRUTH_CAPS.claimChars)
|
|
15531
|
+
})),
|
|
15532
|
+
visualSummaryEn: optionalText(PRODUCT_TRUTH_CAPS.visualSummaryEnChars),
|
|
15533
|
+
evidence: z70.preprocess(objectOrEmpty, z70.object({
|
|
15534
|
+
photoIndexForState: z70.preprocess((v) => {
|
|
15535
|
+
const out = {};
|
|
15536
|
+
if (!v || typeof v !== "object" || Array.isArray(v)) return out;
|
|
15537
|
+
for (const [rawKey, rawIndexes] of Object.entries(v)) {
|
|
15538
|
+
const key = toProductTruthStateKey(rawKey);
|
|
15539
|
+
if (!key || !Array.isArray(rawIndexes)) continue;
|
|
15540
|
+
out[key] = rawIndexes.filter((i) => typeof i === "number" && Number.isInteger(i) && i >= 0 && i < 20);
|
|
15541
|
+
}
|
|
15542
|
+
return out;
|
|
15543
|
+
}, z70.record(z70.array(z70.number().int().min(0).max(19))))
|
|
15544
|
+
})),
|
|
15545
|
+
confidence: z70.preprocess((v) => typeof v === "number" && Number.isFinite(v) ? Math.min(1, Math.max(0, v)) : 0, z70.number().min(0).max(1))
|
|
15546
|
+
});
|
|
15547
|
+
function resolveStateRefs(body) {
|
|
15548
|
+
const keys = new Set(body.assembly.states.map((s) => s.key));
|
|
15549
|
+
const firstKey = body.assembly.states[0]?.key ?? "";
|
|
15550
|
+
const defaultStateKey = body.assembly.defaultStateKey && keys.has(body.assembly.defaultStateKey) ? body.assembly.defaultStateKey : firstKey;
|
|
15551
|
+
const primaryKey = body.use.primary.stateKey && keys.has(body.use.primary.stateKey) ? body.use.primary.stateKey : defaultStateKey;
|
|
15552
|
+
const photoIndexForState = Object.fromEntries(Object.entries(body.evidence.photoIndexForState).filter(([key]) => keys.has(key)));
|
|
15553
|
+
return {
|
|
15554
|
+
...body,
|
|
15555
|
+
assembly: {
|
|
15556
|
+
...body.assembly,
|
|
15557
|
+
defaultStateKey
|
|
15558
|
+
},
|
|
15559
|
+
use: {
|
|
15560
|
+
...body.use,
|
|
15561
|
+
primary: {
|
|
15562
|
+
...body.use.primary,
|
|
15563
|
+
stateKey: primaryKey
|
|
15564
|
+
},
|
|
15565
|
+
alternates: body.use.alternates.map((alt) => ({
|
|
15566
|
+
...alt,
|
|
15567
|
+
stateKey: alt.stateKey && keys.has(alt.stateKey) ? alt.stateKey : defaultStateKey
|
|
15568
|
+
}))
|
|
15569
|
+
},
|
|
15570
|
+
evidence: {
|
|
15571
|
+
...body.evidence,
|
|
15572
|
+
photoIndexForState
|
|
15573
|
+
}
|
|
15574
|
+
};
|
|
15575
|
+
}
|
|
15576
|
+
__name(resolveStateRefs, "resolveStateRefs");
|
|
15577
|
+
var ProductTruthModelResponseSchema = ProductTruthBody.transform(resolveStateRefs);
|
|
15578
|
+
var provenance = {
|
|
15579
|
+
schemaVersion: z70.literal(PRODUCT_TRUTH_SCHEMA_VERSION),
|
|
15580
|
+
modelId: z70.string().min(1),
|
|
15581
|
+
derivedAt: z70.string().min(1),
|
|
15582
|
+
/** Hash of (image keys + seller text + features): a reader that sees a different current
|
|
15583
|
+
* fingerprint treats the truth as absent. See `computeProductTruthFingerprint` in packages/ai. */
|
|
15584
|
+
sourceFingerprint: z70.string().min(1),
|
|
15585
|
+
/** The seller upload KEYS (deduped, sorted) the fingerprint was computed over. Stored so a
|
|
15586
|
+
* reader can recompute the CURRENT fingerprint from today's seller text + features without
|
|
15587
|
+
* knowing the extract job's inputs (plan Global Constraint "Invalidez"). */
|
|
15588
|
+
sourceImageKeys: z70.array(z70.string().min(1)).max(20).optional()
|
|
15589
|
+
};
|
|
15590
|
+
var ProductTruthKnownSchema = ProductTruthBody.extend({
|
|
15591
|
+
...provenance,
|
|
15592
|
+
known: z70.literal(true)
|
|
15593
|
+
}).transform(resolveStateRefs);
|
|
15594
|
+
var ProductTruthUnknownSchema = z70.object({
|
|
15595
|
+
schemaVersion: z70.literal(PRODUCT_TRUTH_SCHEMA_VERSION),
|
|
15596
|
+
known: z70.literal(false),
|
|
15597
|
+
unknownReason: z70.enum(PRODUCT_TRUTH_UNKNOWN_REASONS),
|
|
15598
|
+
modelId: z70.string().optional(),
|
|
15599
|
+
derivedAt: z70.string().min(1),
|
|
15600
|
+
sourceFingerprint: z70.string().min(1),
|
|
15601
|
+
sourceImageKeys: z70.array(z70.string().min(1)).max(20).optional()
|
|
15602
|
+
});
|
|
15603
|
+
var ProductTruthSchema = z70.union([
|
|
15604
|
+
ProductTruthKnownSchema,
|
|
15605
|
+
ProductTruthUnknownSchema
|
|
15606
|
+
]);
|
|
15607
|
+
|
|
15608
|
+
// ../../packages/types/src/landing-director.ts
|
|
15609
|
+
import { z as z71 } from "zod";
|
|
15610
|
+
var LANDING_DIRECTOR_SCHEMA_VERSION = 1;
|
|
15611
|
+
var LANDING_DIRECTOR_ARM = "categories";
|
|
15612
|
+
var LANDING_DIRECTOR_CAPS = {
|
|
15613
|
+
productIdentity: 200,
|
|
15614
|
+
parts: 8,
|
|
15615
|
+
partName: 40,
|
|
15616
|
+
promise: 200,
|
|
15617
|
+
endUserWho: 80,
|
|
15618
|
+
endUserAppliedTo: 80,
|
|
15619
|
+
forbiddenClaims: 10,
|
|
15620
|
+
claimChars: 80,
|
|
15621
|
+
misuse: 5,
|
|
15622
|
+
misuseChars: 120,
|
|
15623
|
+
assembledStates: 3,
|
|
15624
|
+
statePartsMax: 6,
|
|
15625
|
+
orientation: 160,
|
|
15626
|
+
handling: 140,
|
|
15627
|
+
primaryScene: 200,
|
|
15628
|
+
postureAndGrip: 140,
|
|
15629
|
+
contactPoint: 100,
|
|
15630
|
+
alternates: 3,
|
|
15631
|
+
alternateChars: 120,
|
|
15632
|
+
ambiguities: 4,
|
|
15633
|
+
ambiguityChars: 160,
|
|
15634
|
+
sectionKeyChars: 40,
|
|
15635
|
+
personWho: 80,
|
|
15636
|
+
personPosture: 120,
|
|
15637
|
+
personGrip: 120,
|
|
15638
|
+
scene: 450,
|
|
15639
|
+
panels: 4,
|
|
15640
|
+
panelScene: 200,
|
|
15641
|
+
panelCaption: 60,
|
|
15642
|
+
/** Rendered text: an item over its cap is DROPPED, never cut. The headline cap is 80, not
|
|
15643
|
+
* the design's 70: a dropped headline costs the whole director headline, and 7-10 Spanish
|
|
15644
|
+
* words routinely run 70-80 chars. */
|
|
15645
|
+
headline: 80,
|
|
15646
|
+
subheadline: 90,
|
|
15647
|
+
labels: 3,
|
|
15648
|
+
labelChars: 40,
|
|
15649
|
+
captions: 3,
|
|
15650
|
+
captionChars: 60,
|
|
15651
|
+
props: 4,
|
|
15652
|
+
propChars: 40,
|
|
15653
|
+
mustNotShow: 5,
|
|
15654
|
+
mustNotShowChars: 80
|
|
15655
|
+
};
|
|
15656
|
+
var STATE_KEY_PATTERN = /^[a-z][a-z_]{1,23}$/;
|
|
15657
|
+
function toLandingDirectorStateKey(value) {
|
|
15658
|
+
if (typeof value !== "string") return void 0;
|
|
15659
|
+
const slug = value.toLowerCase().normalize("NFD").replace(/[̀-ͯ]/g, "").replace(/[^a-z]+/g, "_").replace(/^_+|_+$/g, "").slice(0, 24).replace(/_+$/g, "");
|
|
15660
|
+
return STATE_KEY_PATTERN.test(slug) ? slug : void 0;
|
|
15661
|
+
}
|
|
15662
|
+
__name(toLandingDirectorStateKey, "toLandingDirectorStateKey");
|
|
15663
|
+
var stateKey2 = z71.preprocess(toLandingDirectorStateKey, z71.string().regex(STATE_KEY_PATTERN));
|
|
15664
|
+
function renderedOptionalText(max) {
|
|
15665
|
+
return z71.preprocess((v) => {
|
|
15666
|
+
if (typeof v !== "string") return void 0;
|
|
15667
|
+
const trimmed = v.replace(/\s+/g, " ").trim();
|
|
15668
|
+
return trimmed.length > 0 && trimmed.length <= max ? trimmed : void 0;
|
|
15669
|
+
}, z71.string().min(1).max(max).optional());
|
|
15670
|
+
}
|
|
15671
|
+
__name(renderedOptionalText, "renderedOptionalText");
|
|
15672
|
+
function renderedTextList(maxItems, maxChars) {
|
|
15673
|
+
return z71.preprocess((v) => {
|
|
15674
|
+
if (!Array.isArray(v)) return [];
|
|
15675
|
+
return v.map((item) => typeof item === "string" ? item.replace(/\s+/g, " ").trim() : "").filter((item) => item.length > 0 && item.length <= maxChars).slice(0, maxItems);
|
|
15676
|
+
}, z71.array(z71.string().min(1).max(maxChars)).max(maxItems));
|
|
15677
|
+
}
|
|
15678
|
+
__name(renderedTextList, "renderedTextList");
|
|
15679
|
+
var C = LANDING_DIRECTOR_CAPS;
|
|
15680
|
+
var PartSchema2 = z71.object({
|
|
15681
|
+
name: lenientText(C.partName),
|
|
15682
|
+
critical: z71.boolean().catch(false)
|
|
15683
|
+
});
|
|
15684
|
+
var AssembledStateSchema = z71.object({
|
|
15685
|
+
key: stateKey2,
|
|
15686
|
+
parts: lenientTextList(C.statePartsMax, C.partName),
|
|
15687
|
+
orientation: lenientText(C.orientation),
|
|
15688
|
+
handling: lenientOptionalText(C.handling)
|
|
15689
|
+
});
|
|
15690
|
+
var END_USER_GENDERS = [
|
|
15691
|
+
"female",
|
|
15692
|
+
"male",
|
|
15693
|
+
"any"
|
|
15694
|
+
];
|
|
15695
|
+
var END_USER_AGE_BANDS = [
|
|
15696
|
+
"child",
|
|
15697
|
+
"teen",
|
|
15698
|
+
"adult",
|
|
15699
|
+
"senior",
|
|
15700
|
+
"any"
|
|
15701
|
+
];
|
|
15702
|
+
var EndUserSchema = z71.object({
|
|
15703
|
+
who: lenientText(C.endUserWho),
|
|
15704
|
+
appliedTo: lenientOptionalText(C.endUserAppliedTo),
|
|
15705
|
+
gender: z71.enum(END_USER_GENDERS).catch("any"),
|
|
15706
|
+
ageBand: z71.enum(END_USER_AGE_BANDS).catch("any")
|
|
15707
|
+
});
|
|
15708
|
+
var LandingDirectorGlobalSchema = z71.object({
|
|
15709
|
+
productIdentity: lenientText(C.productIdentity),
|
|
15710
|
+
parts: lenientList(PartSchema2, C.parts),
|
|
15711
|
+
promise: lenientText(C.promise),
|
|
15712
|
+
endUser: EndUserSchema,
|
|
15713
|
+
forbiddenClaims: lenientTextList(C.forbiddenClaims, C.claimChars),
|
|
15714
|
+
misuse: lenientTextList(C.misuse, C.misuseChars),
|
|
15715
|
+
assembledStates: z71.preprocess((v) => {
|
|
15716
|
+
if (!Array.isArray(v)) return v;
|
|
15717
|
+
const seen = /* @__PURE__ */ new Set();
|
|
15718
|
+
return v.filter((entry) => {
|
|
15719
|
+
const parsed = AssembledStateSchema.safeParse(entry);
|
|
15720
|
+
if (!parsed.success || seen.has(parsed.data.key)) return false;
|
|
15721
|
+
seen.add(parsed.data.key);
|
|
15722
|
+
return true;
|
|
15723
|
+
}).slice(0, C.assembledStates);
|
|
15724
|
+
}, z71.array(AssembledStateSchema).min(1).max(C.assembledStates)),
|
|
15725
|
+
primaryUse: z71.object({
|
|
15726
|
+
assembledState: stateKey2,
|
|
15727
|
+
scene: lenientText(C.primaryScene),
|
|
15728
|
+
postureAndGrip: lenientText(C.postureAndGrip),
|
|
15729
|
+
contactPoint: lenientOptionalText(C.contactPoint)
|
|
15730
|
+
}),
|
|
15731
|
+
primaryRequired: z71.boolean().catch(false),
|
|
15732
|
+
validAlternateUses: lenientTextList(C.alternates, C.alternateChars),
|
|
15733
|
+
ambiguities: lenientTextList(C.ambiguities, C.ambiguityChars)
|
|
15734
|
+
});
|
|
15735
|
+
var LANDING_DIRECTOR_BODY_PARTS = [
|
|
15736
|
+
"hands",
|
|
15737
|
+
"face",
|
|
15738
|
+
"torso",
|
|
15739
|
+
"legs",
|
|
15740
|
+
"feet",
|
|
15741
|
+
"full_body"
|
|
15742
|
+
];
|
|
15743
|
+
var PersonSchema = z71.object({
|
|
15744
|
+
who: lenientText(C.personWho),
|
|
15745
|
+
posture: lenientText(C.personPosture),
|
|
15746
|
+
grip: lenientOptionalText(C.personGrip),
|
|
15747
|
+
bodyPartsVisible: z71.preprocess((v) => Array.isArray(v) ? [
|
|
15748
|
+
...new Set(v.filter((part) => LANDING_DIRECTOR_BODY_PARTS.includes(part)))
|
|
15749
|
+
] : [], z71.array(z71.enum(LANDING_DIRECTOR_BODY_PARTS)))
|
|
15750
|
+
});
|
|
15751
|
+
var LandingDirectorTextSchema = z71.object({
|
|
15752
|
+
headline: renderedOptionalText(C.headline),
|
|
15753
|
+
subheadline: renderedOptionalText(C.subheadline),
|
|
15754
|
+
labels: renderedTextList(C.labels, C.labelChars),
|
|
15755
|
+
captions: renderedTextList(C.captions, C.captionChars)
|
|
15756
|
+
});
|
|
15757
|
+
var PanelSchema = z71.object({
|
|
15758
|
+
scene: lenientText(C.panelScene),
|
|
15759
|
+
caption: renderedOptionalText(C.panelCaption)
|
|
15760
|
+
});
|
|
15761
|
+
var PRODUCT_IN_FRAME_VALUES = [
|
|
15762
|
+
"none",
|
|
15763
|
+
"packshot",
|
|
15764
|
+
"in_use"
|
|
15765
|
+
];
|
|
15766
|
+
var LandingDirectorSectionSchema = z71.object({
|
|
15767
|
+
sectionKey: z71.string().trim().min(1).max(C.sectionKeyChars),
|
|
15768
|
+
/** Present only in the «director» arm. Kept as a flag so the «categorías» validation can
|
|
15769
|
+
* invalidate the section (design §2.3) instead of silently dropping the model's choice. */
|
|
15770
|
+
hasComposition: z71.boolean().default(false),
|
|
15771
|
+
productInFrame: z71.enum(PRODUCT_IN_FRAME_VALUES),
|
|
15772
|
+
assembledState: z71.preprocess((v) => v === null || v === void 0 ? null : toLandingDirectorStateKey(v), z71.string().regex(STATE_KEY_PATTERN).nullable()),
|
|
15773
|
+
usesPrimary: z71.boolean().catch(false),
|
|
15774
|
+
person: z71.preprocess((v) => v === void 0 ? null : v, PersonSchema.nullable()),
|
|
15775
|
+
scene: lenientText(C.scene),
|
|
15776
|
+
panels: lenientList(PanelSchema, C.panels),
|
|
15777
|
+
textToRender: z71.preprocess((v) => v && typeof v === "object" && !Array.isArray(v) ? v : {}, LandingDirectorTextSchema),
|
|
15778
|
+
props: lenientTextList(C.props, C.propChars),
|
|
15779
|
+
mustNotShow: lenientTextList(C.mustNotShow, C.mustNotShowChars)
|
|
15780
|
+
});
|
|
15781
|
+
var LandingDirectorOutputSchema = z71.object({
|
|
15782
|
+
version: z71.literal(LANDING_DIRECTOR_SCHEMA_VERSION),
|
|
15783
|
+
confidence: z71.number().min(0).max(1),
|
|
15784
|
+
global: LandingDirectorGlobalSchema,
|
|
15785
|
+
sections: z71.array(LandingDirectorSectionSchema)
|
|
15786
|
+
});
|
|
15787
|
+
var StoredLandingDirectorSchema = z71.object({
|
|
15788
|
+
version: z71.literal(LANDING_DIRECTOR_SCHEMA_VERSION),
|
|
15789
|
+
arm: z71.literal(LANDING_DIRECTOR_ARM),
|
|
15790
|
+
modelId: z71.string().min(1),
|
|
15791
|
+
generatedAt: z71.string().min(1),
|
|
15792
|
+
confidence: z71.number().min(0).max(1),
|
|
15793
|
+
/** The plan the answer was validated against (sectionKey, or the role on classic). */
|
|
15794
|
+
planSectionKeys: z71.array(z71.string().min(1)),
|
|
15795
|
+
output: LandingDirectorOutputSchema,
|
|
15796
|
+
/** Sections that fell back to the category composition, and why. */
|
|
15797
|
+
fallbackSections: z71.array(z71.object({
|
|
15798
|
+
sectionKey: z71.string().min(1),
|
|
15799
|
+
reason: z71.string().min(1)
|
|
15800
|
+
}))
|
|
15801
|
+
});
|
|
15802
|
+
|
|
15803
|
+
// ../../packages/types/src/flight-recorder.ts
|
|
15804
|
+
import { z as z72 } from "zod";
|
|
15805
|
+
var FlightRecorderGenerationTypeSchema = z72.enum([
|
|
14953
15806
|
"initial",
|
|
14954
15807
|
"regeneration",
|
|
14955
15808
|
"edit",
|
|
14956
15809
|
"retry"
|
|
14957
15810
|
]);
|
|
14958
|
-
var FlightRecorderProviderSchema =
|
|
15811
|
+
var FlightRecorderProviderSchema = z72.enum([
|
|
14959
15812
|
"kie",
|
|
14960
15813
|
"fal"
|
|
14961
15814
|
]);
|
|
14962
|
-
var FlightRecorderElementSchema =
|
|
14963
|
-
name:
|
|
14964
|
-
description:
|
|
14965
|
-
frontalImageUrl:
|
|
14966
|
-
referenceImageUrls:
|
|
14967
|
-
videoUrl:
|
|
14968
|
-
});
|
|
14969
|
-
var FlightRecorderDistillationSchema =
|
|
14970
|
-
actorGender:
|
|
15815
|
+
var FlightRecorderElementSchema = z72.object({
|
|
15816
|
+
name: z72.string().optional(),
|
|
15817
|
+
description: z72.string().optional(),
|
|
15818
|
+
frontalImageUrl: z72.string().optional(),
|
|
15819
|
+
referenceImageUrls: z72.array(z72.string()).optional(),
|
|
15820
|
+
videoUrl: z72.string().optional()
|
|
15821
|
+
});
|
|
15822
|
+
var FlightRecorderDistillationSchema = z72.object({
|
|
15823
|
+
actorGender: z72.enum([
|
|
14971
15824
|
"female",
|
|
14972
15825
|
"male",
|
|
14973
15826
|
"mixed"
|
|
14974
|
-
]).or(
|
|
14975
|
-
voiceId:
|
|
14976
|
-
cameraMotion:
|
|
14977
|
-
}).catchall(
|
|
14978
|
-
var FlightRecorderEntrySchema =
|
|
14979
|
-
schemaVersion:
|
|
14980
|
-
id:
|
|
14981
|
-
taskId:
|
|
14982
|
-
runId:
|
|
14983
|
-
sequence:
|
|
14984
|
-
timestamp:
|
|
14985
|
-
provider: FlightRecorderProviderSchema.or(
|
|
14986
|
-
model:
|
|
14987
|
-
prompt:
|
|
14988
|
-
durationSeconds:
|
|
14989
|
-
aspectRatio:
|
|
14990
|
-
resolution:
|
|
14991
|
-
startImageUrl:
|
|
14992
|
-
endImageUrl:
|
|
14993
|
-
generateAudio:
|
|
15827
|
+
]).or(z72.string()).optional(),
|
|
15828
|
+
voiceId: z72.string().optional(),
|
|
15829
|
+
cameraMotion: z72.string().optional()
|
|
15830
|
+
}).catchall(z72.unknown());
|
|
15831
|
+
var FlightRecorderEntrySchema = z72.object({
|
|
15832
|
+
schemaVersion: z72.literal(1).optional(),
|
|
15833
|
+
id: z72.string().min(1),
|
|
15834
|
+
taskId: z72.string().min(1),
|
|
15835
|
+
runId: z72.string().min(1),
|
|
15836
|
+
sequence: z72.number().int().nonnegative(),
|
|
15837
|
+
timestamp: z72.string().min(1),
|
|
15838
|
+
provider: FlightRecorderProviderSchema.or(z72.string()),
|
|
15839
|
+
model: z72.string().min(1),
|
|
15840
|
+
prompt: z72.string(),
|
|
15841
|
+
durationSeconds: z72.number().nonnegative(),
|
|
15842
|
+
aspectRatio: z72.string().optional(),
|
|
15843
|
+
resolution: z72.string().optional(),
|
|
15844
|
+
startImageUrl: z72.string().optional(),
|
|
15845
|
+
endImageUrl: z72.string().optional(),
|
|
15846
|
+
generateAudio: z72.boolean().optional(),
|
|
14994
15847
|
// Correlation & pipeline metadata
|
|
14995
|
-
angleKey:
|
|
14996
|
-
sceneIndex:
|
|
15848
|
+
angleKey: z72.string().optional(),
|
|
15849
|
+
sceneIndex: z72.number().int().nonnegative().optional(),
|
|
14997
15850
|
generationType: FlightRecorderGenerationTypeSchema,
|
|
14998
|
-
operationId:
|
|
14999
|
-
revisionId:
|
|
15000
|
-
attemptNumber:
|
|
15851
|
+
operationId: z72.string().min(1).optional(),
|
|
15852
|
+
revisionId: z72.string().min(1).optional(),
|
|
15853
|
+
attemptNumber: z72.number().int().nonnegative().default(1),
|
|
15001
15854
|
// Elements & Distillation
|
|
15002
|
-
elements:
|
|
15855
|
+
elements: z72.array(FlightRecorderElementSchema).optional(),
|
|
15003
15856
|
distillation: FlightRecorderDistillationSchema.optional(),
|
|
15004
15857
|
// Raw payload (sanitized of secrets)
|
|
15005
|
-
rawPayload:
|
|
15858
|
+
rawPayload: z72.record(z72.unknown())
|
|
15006
15859
|
});
|
|
15007
|
-
var FlightRecorderQuerySchema =
|
|
15008
|
-
taskId:
|
|
15009
|
-
runId:
|
|
15010
|
-
sceneIndex:
|
|
15011
|
-
angleKey:
|
|
15860
|
+
var FlightRecorderQuerySchema = z72.object({
|
|
15861
|
+
taskId: z72.string().min(1),
|
|
15862
|
+
runId: z72.string().optional(),
|
|
15863
|
+
sceneIndex: z72.number().int().nonnegative().optional(),
|
|
15864
|
+
angleKey: z72.string().optional(),
|
|
15012
15865
|
generationType: FlightRecorderGenerationTypeSchema.optional(),
|
|
15013
|
-
cursor:
|
|
15014
|
-
limit:
|
|
15866
|
+
cursor: z72.number().int().nonnegative().optional(),
|
|
15867
|
+
limit: z72.number().int().positive().optional()
|
|
15015
15868
|
});
|
|
15016
|
-
var FlightRecorderResponseSchema =
|
|
15017
|
-
taskId:
|
|
15018
|
-
runId:
|
|
15019
|
-
entries:
|
|
15869
|
+
var FlightRecorderResponseSchema = z72.object({
|
|
15870
|
+
taskId: z72.string().min(1),
|
|
15871
|
+
runId: z72.string().min(1),
|
|
15872
|
+
entries: z72.array(FlightRecorderEntrySchema),
|
|
15020
15873
|
lastCall: FlightRecorderEntrySchema.nullable(),
|
|
15021
|
-
count:
|
|
15022
|
-
nextCursor:
|
|
15874
|
+
count: z72.number().int().nonnegative(),
|
|
15875
|
+
nextCursor: z72.number().int().nonnegative().nullable()
|
|
15023
15876
|
});
|
|
15024
15877
|
|
|
15025
15878
|
// src/response-body.ts
|
|
@@ -15139,7 +15992,10 @@ var ApiClient = class {
|
|
|
15139
15992
|
method: "POST",
|
|
15140
15993
|
headers: {
|
|
15141
15994
|
...authHeaders,
|
|
15142
|
-
"Content-Type": "application/json"
|
|
15995
|
+
"Content-Type": "application/json",
|
|
15996
|
+
...options?.idempotencyKey ? {
|
|
15997
|
+
"Idempotency-Key": options.idempotencyKey
|
|
15998
|
+
} : {}
|
|
15143
15999
|
},
|
|
15144
16000
|
body: JSON.stringify(body)
|
|
15145
16001
|
}, options);
|
|
@@ -15261,7 +16117,7 @@ var ApiClient = class {
|
|
|
15261
16117
|
};
|
|
15262
16118
|
|
|
15263
16119
|
// src/index.ts
|
|
15264
|
-
var MCP_VERSION = "8.
|
|
16120
|
+
var MCP_VERSION = "8.3.0";
|
|
15265
16121
|
|
|
15266
16122
|
// src/meta-upload-app.ts
|
|
15267
16123
|
import { readFileSync } from "fs";
|
|
@@ -15333,7 +16189,7 @@ function registerMediaUploadAppResource(server, resolveEndpoint) {
|
|
|
15333
16189
|
__name(registerMediaUploadAppResource, "registerMediaUploadAppResource");
|
|
15334
16190
|
|
|
15335
16191
|
// src/tools/tasks.ts
|
|
15336
|
-
import { z as
|
|
16192
|
+
import { z as z76 } from "zod";
|
|
15337
16193
|
|
|
15338
16194
|
// src/resolve-image.ts
|
|
15339
16195
|
import { lookup as dnsLookup } from "dns/promises";
|
|
@@ -15894,10 +16750,10 @@ async function resolveMediaRef(ref, opts) {
|
|
|
15894
16750
|
__name(resolveMediaRef, "resolveMediaRef");
|
|
15895
16751
|
|
|
15896
16752
|
// src/tools/shared.ts
|
|
15897
|
-
import { z as
|
|
15898
|
-
var Lang =
|
|
15899
|
-
var Country =
|
|
15900
|
-
var LandingStrategyEnum =
|
|
16753
|
+
import { z as z73 } from "zod";
|
|
16754
|
+
var Lang = z73.string().regex(/^[a-z]{2}(?:[-_][a-zA-Z]{2})?$/, "Usa un c\xF3digo de idioma BCP-47, por ejemplo es, en-US o pt-BR").max(10);
|
|
16755
|
+
var Country = z73.string().min(2).max(3);
|
|
16756
|
+
var LandingStrategyEnum = z73.enum([
|
|
15901
16757
|
"auto",
|
|
15902
16758
|
"classic",
|
|
15903
16759
|
"pain_solution",
|
|
@@ -15906,12 +16762,12 @@ var LandingStrategyEnum = z69.enum([
|
|
|
15906
16762
|
"offer_value",
|
|
15907
16763
|
"lifestyle_identity"
|
|
15908
16764
|
]);
|
|
15909
|
-
var LandingImageFormatEnum =
|
|
16765
|
+
var LandingImageFormatEnum = z73.enum([
|
|
15910
16766
|
"9:16",
|
|
15911
16767
|
"4:5",
|
|
15912
16768
|
"1:1"
|
|
15913
16769
|
]);
|
|
15914
|
-
var VideoPresetEnum =
|
|
16770
|
+
var VideoPresetEnum = z73.enum([
|
|
15915
16771
|
"auto",
|
|
15916
16772
|
"ugc_dynamic",
|
|
15917
16773
|
"ugc_how_to",
|
|
@@ -15924,21 +16780,21 @@ var VideoPresetEnum = z69.enum([
|
|
|
15924
16780
|
"pixar_problem",
|
|
15925
16781
|
"pixar_sassy"
|
|
15926
16782
|
]);
|
|
15927
|
-
var VideoStructureEnum =
|
|
16783
|
+
var VideoStructureEnum = z73.enum([
|
|
15928
16784
|
"single_take",
|
|
15929
16785
|
"multi_scene"
|
|
15930
16786
|
]);
|
|
15931
|
-
var VideoQualityEnum =
|
|
16787
|
+
var VideoQualityEnum = z73.enum([
|
|
15932
16788
|
"economy",
|
|
15933
16789
|
"medium",
|
|
15934
16790
|
"pro"
|
|
15935
16791
|
]);
|
|
15936
|
-
var VideoRouteIdEnum =
|
|
16792
|
+
var VideoRouteIdEnum = z73.enum([
|
|
15937
16793
|
"single_take",
|
|
15938
16794
|
"multi_scene",
|
|
15939
16795
|
"free"
|
|
15940
16796
|
]);
|
|
15941
|
-
var TaskCreativeVariantVideoPresetEnum =
|
|
16797
|
+
var TaskCreativeVariantVideoPresetEnum = z73.enum([
|
|
15942
16798
|
"auto",
|
|
15943
16799
|
"ugc_dynamic",
|
|
15944
16800
|
"ugc_how_to",
|
|
@@ -15955,53 +16811,43 @@ var VIDEO_PRESET_RESOLUTION = {
|
|
|
15955
16811
|
auto: null,
|
|
15956
16812
|
ugc_dynamic: {
|
|
15957
16813
|
videoStyle: "ai_dynamic",
|
|
15958
|
-
narrativeStyle: "review"
|
|
15959
|
-
videoModel: "veo"
|
|
16814
|
+
narrativeStyle: "review"
|
|
15960
16815
|
},
|
|
15961
16816
|
ugc_how_to: {
|
|
15962
16817
|
videoStyle: "ai_dynamic",
|
|
15963
|
-
narrativeStyle: "ugc_how_to"
|
|
15964
|
-
videoModel: "veo"
|
|
16818
|
+
narrativeStyle: "ugc_how_to"
|
|
15965
16819
|
},
|
|
15966
16820
|
ugc_unboxing_chaos: {
|
|
15967
16821
|
videoStyle: "ai_dynamic",
|
|
15968
|
-
narrativeStyle: "ugc_unboxing_chaos"
|
|
15969
|
-
videoModel: "veo"
|
|
16822
|
+
narrativeStyle: "ugc_unboxing_chaos"
|
|
15970
16823
|
},
|
|
15971
16824
|
problem_solution: {
|
|
15972
16825
|
videoStyle: "ai_dynamic",
|
|
15973
|
-
narrativeStyle: "problem_product_cta"
|
|
15974
|
-
videoModel: "kling"
|
|
16826
|
+
narrativeStyle: "problem_product_cta"
|
|
15975
16827
|
},
|
|
15976
16828
|
pixar_problem: {
|
|
15977
16829
|
videoStyle: "ai_dynamic",
|
|
15978
|
-
narrativeStyle: "animated_problem_pixar"
|
|
15979
|
-
videoModel: "kling"
|
|
16830
|
+
narrativeStyle: "animated_problem_pixar"
|
|
15980
16831
|
},
|
|
15981
16832
|
pixar_sassy: {
|
|
15982
16833
|
videoStyle: "ai_dynamic",
|
|
15983
|
-
narrativeStyle: "sassy_product_pixar"
|
|
15984
|
-
videoModel: "seedance"
|
|
16834
|
+
narrativeStyle: "sassy_product_pixar"
|
|
15985
16835
|
},
|
|
15986
16836
|
product_showcase: {
|
|
15987
16837
|
videoStyle: "product_only",
|
|
15988
|
-
narrativeStyle: "product_showcase"
|
|
15989
|
-
videoModel: "veo"
|
|
16838
|
+
narrativeStyle: "product_showcase"
|
|
15990
16839
|
},
|
|
15991
16840
|
wearable_showcase: {
|
|
15992
16841
|
videoStyle: "ugc",
|
|
15993
|
-
narrativeStyle: "wearable_showcase"
|
|
15994
|
-
videoModel: "veo"
|
|
16842
|
+
narrativeStyle: "wearable_showcase"
|
|
15995
16843
|
},
|
|
15996
16844
|
cinematic: {
|
|
15997
16845
|
videoStyle: "product_only",
|
|
15998
|
-
narrativeStyle: "cinematic"
|
|
15999
|
-
videoModel: "grok"
|
|
16846
|
+
narrativeStyle: "cinematic"
|
|
16000
16847
|
},
|
|
16001
16848
|
wild_card: {
|
|
16002
16849
|
videoStyle: "product_only",
|
|
16003
|
-
narrativeStyle: "wild_card"
|
|
16004
|
-
videoModel: "grok"
|
|
16850
|
+
narrativeStyle: "wild_card"
|
|
16005
16851
|
}
|
|
16006
16852
|
};
|
|
16007
16853
|
function resolveVideoPreset(preset) {
|
|
@@ -16009,7 +16855,7 @@ function resolveVideoPreset(preset) {
|
|
|
16009
16855
|
return VIDEO_PRESET_RESOLUTION[preset] ?? null;
|
|
16010
16856
|
}
|
|
16011
16857
|
__name(resolveVideoPreset, "resolveVideoPreset");
|
|
16012
|
-
var VideoTierEnum =
|
|
16858
|
+
var VideoTierEnum = z73.enum([
|
|
16013
16859
|
"basic"
|
|
16014
16860
|
]);
|
|
16015
16861
|
function resolveVideoTier(_tier) {
|
|
@@ -16049,22 +16895,22 @@ function assertSemanticVideoDurationCompatibility(structure, quality, durationSe
|
|
|
16049
16895
|
}
|
|
16050
16896
|
}
|
|
16051
16897
|
__name(assertSemanticVideoDurationCompatibility, "assertSemanticVideoDurationCompatibility");
|
|
16052
|
-
var VideoResolutionEnum =
|
|
16898
|
+
var VideoResolutionEnum = z73.enum([
|
|
16053
16899
|
"480p",
|
|
16054
16900
|
"720p"
|
|
16055
16901
|
]);
|
|
16056
|
-
var CreativeGenderEnum =
|
|
16902
|
+
var CreativeGenderEnum = z73.enum([
|
|
16057
16903
|
"female",
|
|
16058
16904
|
"male",
|
|
16059
16905
|
"mixed"
|
|
16060
16906
|
]);
|
|
16061
|
-
var VideoStyleEnum =
|
|
16907
|
+
var VideoStyleEnum = z73.enum([
|
|
16062
16908
|
"ugc",
|
|
16063
16909
|
"cartoon_3d",
|
|
16064
16910
|
"product_only",
|
|
16065
16911
|
"ai_dynamic"
|
|
16066
16912
|
]);
|
|
16067
|
-
var NarrativeStyleEnum =
|
|
16913
|
+
var NarrativeStyleEnum = z73.enum([
|
|
16068
16914
|
"review",
|
|
16069
16915
|
"ugc_how_to",
|
|
16070
16916
|
"problem_product_cta",
|
|
@@ -16082,7 +16928,7 @@ var NarrativeStyleEnum = z69.enum([
|
|
|
16082
16928
|
"ugc_demo_review",
|
|
16083
16929
|
"market"
|
|
16084
16930
|
]);
|
|
16085
|
-
var PublicNarrativeStyleEnum =
|
|
16931
|
+
var PublicNarrativeStyleEnum = z73.enum([
|
|
16086
16932
|
"review",
|
|
16087
16933
|
"ugc_how_to",
|
|
16088
16934
|
"ugc_unboxing_chaos",
|
|
@@ -16095,7 +16941,7 @@ var PublicNarrativeStyleEnum = z69.enum([
|
|
|
16095
16941
|
"sassy_product_pixar",
|
|
16096
16942
|
"market"
|
|
16097
16943
|
]);
|
|
16098
|
-
var
|
|
16944
|
+
var TaskVideoModelEnum = z73.enum([
|
|
16099
16945
|
"veo",
|
|
16100
16946
|
"wan",
|
|
16101
16947
|
"bytedance",
|
|
@@ -16103,29 +16949,29 @@ var VideoModelEnum = z69.enum([
|
|
|
16103
16949
|
"grok",
|
|
16104
16950
|
"kling"
|
|
16105
16951
|
]);
|
|
16106
|
-
var ProductReferenceUserChoiceEnum =
|
|
16952
|
+
var ProductReferenceUserChoiceEnum = z73.enum([
|
|
16107
16953
|
"same_product",
|
|
16108
16954
|
"variants",
|
|
16109
16955
|
"different_products",
|
|
16110
16956
|
"combo_distinct"
|
|
16111
16957
|
]);
|
|
16112
|
-
var ProductReferenceCandidateGroupingEnum =
|
|
16958
|
+
var ProductReferenceCandidateGroupingEnum = z73.enum([
|
|
16113
16959
|
"same_product_same_variant",
|
|
16114
16960
|
"same_product_different_variants",
|
|
16115
16961
|
"different_products",
|
|
16116
16962
|
"unclear"
|
|
16117
16963
|
]);
|
|
16118
|
-
var ProductReferenceScopeEnum =
|
|
16964
|
+
var ProductReferenceScopeEnum = z73.enum([
|
|
16119
16965
|
"base",
|
|
16120
16966
|
"video_view_pack"
|
|
16121
16967
|
]);
|
|
16122
|
-
var ProductReferenceResolutionDecisionEnum =
|
|
16968
|
+
var ProductReferenceResolutionDecisionEnum = z73.enum([
|
|
16123
16969
|
"approve",
|
|
16124
16970
|
"reject",
|
|
16125
16971
|
"observed_only",
|
|
16126
16972
|
"correct_view"
|
|
16127
16973
|
]);
|
|
16128
|
-
var ProductReferenceRejectionReasonEnum =
|
|
16974
|
+
var ProductReferenceRejectionReasonEnum = z73.enum([
|
|
16129
16975
|
"replacement_requested",
|
|
16130
16976
|
"wrong_product_identity",
|
|
16131
16977
|
"wrong_variant",
|
|
@@ -16136,13 +16982,13 @@ var ProductReferenceRejectionReasonEnum = z69.enum([
|
|
|
16136
16982
|
"not_a_product_photo",
|
|
16137
16983
|
"other"
|
|
16138
16984
|
]);
|
|
16139
|
-
var GapDurationChoiceMirror =
|
|
16140
|
-
angleIndex:
|
|
16141
|
-
recommendedSec:
|
|
16142
|
-
|
|
16143
|
-
|
|
16985
|
+
var GapDurationChoiceMirror = z73.object({
|
|
16986
|
+
angleIndex: z73.number().int().nonnegative(),
|
|
16987
|
+
recommendedSec: z73.union([
|
|
16988
|
+
z73.literal(15),
|
|
16989
|
+
z73.literal(30)
|
|
16144
16990
|
]),
|
|
16145
|
-
estimatedDeltaCredits:
|
|
16991
|
+
estimatedDeltaCredits: z73.number().int().nonnegative().optional()
|
|
16146
16992
|
});
|
|
16147
16993
|
function buildSelectedImageUrlsHash(urls) {
|
|
16148
16994
|
const input = [
|
|
@@ -16152,13 +16998,13 @@ function buildSelectedImageUrlsHash(urls) {
|
|
|
16152
16998
|
return `fnv1a:${hash.toString(16).padStart(8, "0")}:${urls.length}`;
|
|
16153
16999
|
}
|
|
16154
17000
|
__name(buildSelectedImageUrlsHash, "buildSelectedImageUrlsHash");
|
|
16155
|
-
var ImageCreativeStyleEnum =
|
|
17001
|
+
var ImageCreativeStyleEnum = z73.enum([
|
|
16156
17002
|
"studio",
|
|
16157
17003
|
"floating",
|
|
16158
17004
|
"ingredients",
|
|
16159
17005
|
"in_use"
|
|
16160
17006
|
]);
|
|
16161
|
-
var ImageCreativeArchetypeEnum =
|
|
17007
|
+
var ImageCreativeArchetypeEnum = z73.enum([
|
|
16162
17008
|
"direct_response_product_ad",
|
|
16163
17009
|
"hero_outcome",
|
|
16164
17010
|
"offer_value_prop",
|
|
@@ -16167,20 +17013,20 @@ var ImageCreativeArchetypeEnum = z69.enum([
|
|
|
16167
17013
|
"problem_solution",
|
|
16168
17014
|
"lifestyle_identity"
|
|
16169
17015
|
]);
|
|
16170
|
-
var ImageCreativeVisualTreatmentEnum =
|
|
17016
|
+
var ImageCreativeVisualTreatmentEnum = z73.enum([
|
|
16171
17017
|
"performance_product_ad",
|
|
16172
17018
|
"premium_dtc_carousel"
|
|
16173
17019
|
]);
|
|
16174
|
-
var ImageCreativeAspectRatioEnum =
|
|
17020
|
+
var ImageCreativeAspectRatioEnum = z73.enum([
|
|
16175
17021
|
"1:1",
|
|
16176
17022
|
"4:5",
|
|
16177
17023
|
"9:16",
|
|
16178
17024
|
"16:9"
|
|
16179
17025
|
]);
|
|
16180
|
-
var ImageRefSchema =
|
|
16181
|
-
url:
|
|
16182
|
-
path:
|
|
16183
|
-
assetId:
|
|
17026
|
+
var ImageRefSchema = z73.object({
|
|
17027
|
+
url: z73.string().url().optional().describe('URL p\xFAblica HTTPS de la foto. Ej: una URL de Shopify CDN, Cloudinary, Imgur. \xDAsala cuando el usuario te diga "est\xE1 en X.com/foto.jpg" o cuando la foto ya est\xE9 hospedada.'),
|
|
17028
|
+
path: z73.string().min(1).optional().describe('Ruta del archivo en el computador del usuario. Ej: "/Users/maria/Desktop/foto.jpg", "~/Pictures/camiseta.png", "C:\\Users\\Maria\\Desktop\\foto.jpg". El MCP local la lee del disco y la sube. SOLO funciona cuando el MCP corre local (stdio). NO funciona en mcp.productmaker.app (HTTP) \u2014 ah\xED usa `url`.'),
|
|
17029
|
+
assetId: z73.string().uuid().optional().describe("ID opaco devuelto por check_media_upload. \xDAsalo para una imagen subida desde el MCP App; ProductMaker adopta el archivo directamente y el MCP nunca descarga sus bytes.")
|
|
16184
17030
|
}).refine((v) => [
|
|
16185
17031
|
v.url,
|
|
16186
17032
|
v.path,
|
|
@@ -16188,11 +17034,11 @@ var ImageRefSchema = z69.object({
|
|
|
16188
17034
|
].filter(Boolean).length === 1, {
|
|
16189
17035
|
message: "each image entry must have exactly one of `url`, `path`, or `assetId`"
|
|
16190
17036
|
});
|
|
16191
|
-
var ImagesInput =
|
|
17037
|
+
var ImagesInput = z73.array(ImageRefSchema).min(1).max(5).superRefine((images, ctx) => {
|
|
16192
17038
|
const assetCount = images.filter((image) => Boolean(image.assetId)).length;
|
|
16193
17039
|
if (assetCount > 0 && assetCount !== images.length) {
|
|
16194
17040
|
ctx.addIssue({
|
|
16195
|
-
code:
|
|
17041
|
+
code: z73.ZodIssueCode.custom,
|
|
16196
17042
|
message: "all image entries must use assetId, or all must use URL/path sources"
|
|
16197
17043
|
});
|
|
16198
17044
|
}
|
|
@@ -16255,19 +17101,24 @@ async function submitCreative(api, opts) {
|
|
|
16255
17101
|
const taskId = r.taskId ?? r.jobId;
|
|
16256
17102
|
return asText({
|
|
16257
17103
|
taskId,
|
|
16258
|
-
|
|
16259
|
-
|
|
17104
|
+
// Replay-aware: a keyed retry may land on a task that is already
|
|
17105
|
+
// processing/done — report the real status, not a hopeful "queued".
|
|
17106
|
+
status: r.status ?? "queued",
|
|
17107
|
+
estimatedSeconds: opts.estimatedSeconds,
|
|
17108
|
+
...r.replayed === true ? {
|
|
17109
|
+
replayed: true
|
|
17110
|
+
} : {}
|
|
16260
17111
|
});
|
|
16261
17112
|
}
|
|
16262
17113
|
__name(submitCreative, "submitCreative");
|
|
16263
|
-
var ResearchTargetCountryEnum =
|
|
17114
|
+
var ResearchTargetCountryEnum = z73.enum([
|
|
16264
17115
|
"CO",
|
|
16265
17116
|
"MX",
|
|
16266
17117
|
"PE",
|
|
16267
17118
|
"EC",
|
|
16268
17119
|
"CL"
|
|
16269
17120
|
]);
|
|
16270
|
-
var ResearchCategoryEnum =
|
|
17121
|
+
var ResearchCategoryEnum = z73.enum([
|
|
16271
17122
|
"auto",
|
|
16272
17123
|
"automotive",
|
|
16273
17124
|
"kitchen",
|
|
@@ -16336,7 +17187,7 @@ var OVERWRITES_EXTERNAL = {
|
|
|
16336
17187
|
idempotentHint: false,
|
|
16337
17188
|
openWorldHint: false
|
|
16338
17189
|
};
|
|
16339
|
-
var DailyControlStatusEnum =
|
|
17190
|
+
var DailyControlStatusEnum = z73.enum([
|
|
16340
17191
|
"ok",
|
|
16341
17192
|
"sales_unavailable",
|
|
16342
17193
|
"timezone_unavailable",
|
|
@@ -16349,19 +17200,19 @@ var DailyControlStatusEnum = z69.enum([
|
|
|
16349
17200
|
"product_missing",
|
|
16350
17201
|
"store_unreachable"
|
|
16351
17202
|
]);
|
|
16352
|
-
var DailyControlLightEnum =
|
|
17203
|
+
var DailyControlLightEnum = z73.enum([
|
|
16353
17204
|
"green",
|
|
16354
17205
|
"amber",
|
|
16355
17206
|
"red",
|
|
16356
17207
|
"none"
|
|
16357
17208
|
]);
|
|
16358
|
-
var DailyControlVerdictEnum =
|
|
17209
|
+
var DailyControlVerdictEnum = z73.enum([
|
|
16359
17210
|
"scale",
|
|
16360
17211
|
"hold",
|
|
16361
17212
|
"kill",
|
|
16362
17213
|
"insufficient_sample"
|
|
16363
17214
|
]);
|
|
16364
|
-
var DailyControlSourceEnum =
|
|
17215
|
+
var DailyControlSourceEnum = z73.enum([
|
|
16365
17216
|
"shopify",
|
|
16366
17217
|
"shopify_settling",
|
|
16367
17218
|
"user",
|
|
@@ -17502,29 +18353,29 @@ ${parsed.data.error ? `${escapeMarkdownText(parsed.data.error)}
|
|
|
17502
18353
|
__name(renderVideoScriptMarkdown, "renderVideoScriptMarkdown");
|
|
17503
18354
|
|
|
17504
18355
|
// src/tools/media-presentation.ts
|
|
17505
|
-
import { z as
|
|
17506
|
-
var HttpsPresentationUrlSchema =
|
|
18356
|
+
import { z as z74 } from "zod";
|
|
18357
|
+
var HttpsPresentationUrlSchema = z74.string().url().max(2048).refine((value) => new URL(value).protocol === "https:");
|
|
17507
18358
|
var ProductMakerPreviewUrlSchema = HttpsPresentationUrlSchema.refine((value) => {
|
|
17508
18359
|
const hostname = new URL(value).hostname.toLowerCase();
|
|
17509
18360
|
return hostname === "productmaker.app" || hostname.endsWith(".productmaker.app");
|
|
17510
18361
|
}, "preview URL must be owned by ProductMaker");
|
|
17511
|
-
var positiveIntAtMost = /* @__PURE__ */ __name((maximum) =>
|
|
17512
|
-
var PresentationImageSchema =
|
|
17513
|
-
kind:
|
|
18362
|
+
var positiveIntAtMost = /* @__PURE__ */ __name((maximum) => z74.number().int().positive().max(maximum), "positiveIntAtMost");
|
|
18363
|
+
var PresentationImageSchema = z74.object({
|
|
18364
|
+
kind: z74.literal("image"),
|
|
17514
18365
|
url: HttpsPresentationUrlSchema,
|
|
17515
|
-
mimeType:
|
|
18366
|
+
mimeType: z74.enum([
|
|
17516
18367
|
"image/jpeg",
|
|
17517
18368
|
"image/png"
|
|
17518
18369
|
]),
|
|
17519
18370
|
byteSize: positiveIntAtMost(5 * 1024 * 1024),
|
|
17520
18371
|
width: positiveIntAtMost(16384),
|
|
17521
18372
|
height: positiveIntAtMost(16384),
|
|
17522
|
-
alt:
|
|
18373
|
+
alt: z74.string().trim().min(1).max(240)
|
|
17523
18374
|
}).strict();
|
|
17524
18375
|
var McpMediaPresentationSchema = PresentationImageSchema;
|
|
17525
|
-
var GalleryImageSchema =
|
|
18376
|
+
var GalleryImageSchema = z74.object({
|
|
17526
18377
|
url: ProductMakerPreviewUrlSchema,
|
|
17527
|
-
alt:
|
|
18378
|
+
alt: z74.string().trim().min(1).max(240)
|
|
17528
18379
|
});
|
|
17529
18380
|
var MCP_GALLERY_IMAGE_MAX_BYTES = 10 * 1024 * 1024;
|
|
17530
18381
|
async function imageBlocks(image, transport) {
|
|
@@ -17673,11 +18524,175 @@ ${summary}`,
|
|
|
17673
18524
|
}
|
|
17674
18525
|
__name(requirePaidCreativeConfirmation, "requirePaidCreativeConfirmation");
|
|
17675
18526
|
|
|
18527
|
+
// src/tools/stable-uuid.ts
|
|
18528
|
+
import { createHash as createHash2 } from "crypto";
|
|
18529
|
+
function canonicalize(value) {
|
|
18530
|
+
if (Array.isArray(value)) return value.map(canonicalize);
|
|
18531
|
+
if (value === null || typeof value !== "object") return value;
|
|
18532
|
+
const record = value;
|
|
18533
|
+
return Object.fromEntries(Object.keys(record).sort().filter((key) => record[key] !== void 0).map((key) => [
|
|
18534
|
+
key,
|
|
18535
|
+
canonicalize(record[key])
|
|
18536
|
+
]));
|
|
18537
|
+
}
|
|
18538
|
+
__name(canonicalize, "canonicalize");
|
|
18539
|
+
function canonicalJson(value) {
|
|
18540
|
+
return JSON.stringify(canonicalize(value));
|
|
18541
|
+
}
|
|
18542
|
+
__name(canonicalJson, "canonicalJson");
|
|
18543
|
+
function deriveUuidV5(name, namespace) {
|
|
18544
|
+
const namespaceBytes = Buffer.from(namespace.replaceAll("-", ""), "hex");
|
|
18545
|
+
const digest = createHash2("sha1").update(namespaceBytes).update(name, "utf8").digest();
|
|
18546
|
+
const bytes = Buffer.from(digest.subarray(0, 16));
|
|
18547
|
+
bytes[6] = (bytes[6] ?? 0) & 15 | 80;
|
|
18548
|
+
bytes[8] = (bytes[8] ?? 0) & 63 | 128;
|
|
18549
|
+
const hex = bytes.toString("hex");
|
|
18550
|
+
return [
|
|
18551
|
+
hex.slice(0, 8),
|
|
18552
|
+
hex.slice(8, 12),
|
|
18553
|
+
hex.slice(12, 16),
|
|
18554
|
+
hex.slice(16, 20),
|
|
18555
|
+
hex.slice(20)
|
|
18556
|
+
].join("-");
|
|
18557
|
+
}
|
|
18558
|
+
__name(deriveUuidV5, "deriveUuidV5");
|
|
18559
|
+
|
|
18560
|
+
// src/tools/request-key.ts
|
|
18561
|
+
var PAID_REQUEST_KEY_WINDOW_MS = 15 * 60 * 1e3;
|
|
18562
|
+
var PAID_REQUEST_KEY_NAMESPACE = "8f3d6b1c-2a47-4e5b-9c0d-6e7f8a9b0c1d";
|
|
18563
|
+
var PARAPHRASE_PRONE_FIELDS = /* @__PURE__ */ new Set([
|
|
18564
|
+
"additionalContext",
|
|
18565
|
+
"productContext",
|
|
18566
|
+
"scriptNotes",
|
|
18567
|
+
"creativeDirection",
|
|
18568
|
+
"buyerPersona",
|
|
18569
|
+
"actorDescription",
|
|
18570
|
+
"description",
|
|
18571
|
+
"idempotencyKey",
|
|
18572
|
+
"clientRequestId"
|
|
18573
|
+
]);
|
|
18574
|
+
var URL_FIELDS = /* @__PURE__ */ new Set([
|
|
18575
|
+
"landingUrl",
|
|
18576
|
+
"productUrl",
|
|
18577
|
+
"url",
|
|
18578
|
+
"serviceLandingUrl"
|
|
18579
|
+
]);
|
|
18580
|
+
var TRACKING_PARAM_PATTERN = /^(utm_\w+|fbclid|gclid|msclkid|mc_cid|mc_eid|igshid)$/;
|
|
18581
|
+
var LANGUAGE_FIELDS = /* @__PURE__ */ new Set([
|
|
18582
|
+
"language",
|
|
18583
|
+
"lang"
|
|
18584
|
+
]);
|
|
18585
|
+
var CASE_FOLD_FIELDS = /* @__PURE__ */ new Set([
|
|
18586
|
+
"country",
|
|
18587
|
+
"language",
|
|
18588
|
+
"lang"
|
|
18589
|
+
]);
|
|
18590
|
+
var ORDER_INSIGNIFICANT_ARRAY_FIELDS = /* @__PURE__ */ new Set([
|
|
18591
|
+
"outputs",
|
|
18592
|
+
"selectedOutputs",
|
|
18593
|
+
"features"
|
|
18594
|
+
]);
|
|
18595
|
+
function sortCanonical(items) {
|
|
18596
|
+
return [
|
|
18597
|
+
...items
|
|
18598
|
+
].sort((a, b) => {
|
|
18599
|
+
const ka = canonicalJson(a);
|
|
18600
|
+
const kb = canonicalJson(b);
|
|
18601
|
+
return ka < kb ? -1 : ka > kb ? 1 : 0;
|
|
18602
|
+
});
|
|
18603
|
+
}
|
|
18604
|
+
__name(sortCanonical, "sortCanonical");
|
|
18605
|
+
function isRecord3(value) {
|
|
18606
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
18607
|
+
}
|
|
18608
|
+
__name(isRecord3, "isRecord");
|
|
18609
|
+
function collectLanguageCodes(value, out) {
|
|
18610
|
+
if (Array.isArray(value)) {
|
|
18611
|
+
const items = value;
|
|
18612
|
+
for (const item of items) collectLanguageCodes(item, out);
|
|
18613
|
+
return out;
|
|
18614
|
+
}
|
|
18615
|
+
if (!isRecord3(value)) return out;
|
|
18616
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
18617
|
+
if (LANGUAGE_FIELDS.has(key) && typeof entry === "string") {
|
|
18618
|
+
const base = entry.trim().split(/[-_]/)[0]?.toLowerCase();
|
|
18619
|
+
if (base) out.add(base);
|
|
18620
|
+
}
|
|
18621
|
+
collectLanguageCodes(entry, out);
|
|
18622
|
+
}
|
|
18623
|
+
return out;
|
|
18624
|
+
}
|
|
18625
|
+
__name(collectLanguageCodes, "collectLanguageCodes");
|
|
18626
|
+
function normalizeSearchForKey(search) {
|
|
18627
|
+
if (!search) return "";
|
|
18628
|
+
const params = [
|
|
18629
|
+
...new URLSearchParams(search).entries()
|
|
18630
|
+
].filter(([key]) => !TRACKING_PARAM_PATTERN.test(key.toLowerCase())).sort(([ka, va], [kb, vb]) => ka === kb ? va < vb ? -1 : va > vb ? 1 : 0 : ka < kb ? -1 : 1);
|
|
18631
|
+
if (!params.length) return "";
|
|
18632
|
+
const out = new URLSearchParams();
|
|
18633
|
+
for (const [key, value] of params) out.append(key, value);
|
|
18634
|
+
return `?${out.toString()}`;
|
|
18635
|
+
}
|
|
18636
|
+
__name(normalizeSearchForKey, "normalizeSearchForKey");
|
|
18637
|
+
function normalizeUrlForKey(value, languages) {
|
|
18638
|
+
const trimmed = value.trim();
|
|
18639
|
+
let url;
|
|
18640
|
+
try {
|
|
18641
|
+
url = new URL(trimmed);
|
|
18642
|
+
} catch {
|
|
18643
|
+
return trimmed.toLowerCase();
|
|
18644
|
+
}
|
|
18645
|
+
const host = url.hostname.toLowerCase().replace(/^www\./, "");
|
|
18646
|
+
const port = url.port ? `:${url.port}` : "";
|
|
18647
|
+
const segments = url.pathname.split("/").filter(Boolean);
|
|
18648
|
+
const soleSegment = segments.length === 1 ? segments[0] : void 0;
|
|
18649
|
+
if (soleSegment !== void 0 && languages.has(soleSegment.toLowerCase())) {
|
|
18650
|
+
segments.pop();
|
|
18651
|
+
}
|
|
18652
|
+
const path3 = segments.length ? `/${segments.join("/")}` : "";
|
|
18653
|
+
return host + port + path3 + normalizeSearchForKey(url.search);
|
|
18654
|
+
}
|
|
18655
|
+
__name(normalizeUrlForKey, "normalizeUrlForKey");
|
|
18656
|
+
function normalizeForKey(value, languages) {
|
|
18657
|
+
if (Array.isArray(value)) {
|
|
18658
|
+
const items = value;
|
|
18659
|
+
return items.map((item) => normalizeForKey(item, languages));
|
|
18660
|
+
}
|
|
18661
|
+
if (!isRecord3(value)) return value;
|
|
18662
|
+
const out = {};
|
|
18663
|
+
for (const [key, entry] of Object.entries(value)) {
|
|
18664
|
+
if (PARAPHRASE_PRONE_FIELDS.has(key)) {
|
|
18665
|
+
if (key === "description" && value.mode === "described") {
|
|
18666
|
+
out[key] = normalizeForKey(entry, languages);
|
|
18667
|
+
}
|
|
18668
|
+
continue;
|
|
18669
|
+
}
|
|
18670
|
+
out[key] = URL_FIELDS.has(key) && typeof entry === "string" ? normalizeUrlForKey(entry, languages) : CASE_FOLD_FIELDS.has(key) && typeof entry === "string" ? (
|
|
18671
|
+
// separator too or a host alternating between them splits the key.
|
|
18672
|
+
entry.trim().toLowerCase().replace(/_/g, "-")
|
|
18673
|
+
) : ORDER_INSIGNIFICANT_ARRAY_FIELDS.has(key) && Array.isArray(entry) ? sortCanonical(entry.map((item) => normalizeForKey(item, languages))) : normalizeForKey(entry, languages);
|
|
18674
|
+
}
|
|
18675
|
+
return out;
|
|
18676
|
+
}
|
|
18677
|
+
__name(normalizeForKey, "normalizeForKey");
|
|
18678
|
+
function derivePaidRequestKey(args) {
|
|
18679
|
+
const languages = collectLanguageCodes(args.input, /* @__PURE__ */ new Set());
|
|
18680
|
+
const semanticInput = normalizeForKey(args.input, languages);
|
|
18681
|
+
const bucket = Math.floor(args.nowMs / PAID_REQUEST_KEY_WINDOW_MS);
|
|
18682
|
+
return deriveUuidV5(canonicalJson({
|
|
18683
|
+
user: args.fingerprint,
|
|
18684
|
+
tool: args.tool,
|
|
18685
|
+
input: semanticInput,
|
|
18686
|
+
bucket
|
|
18687
|
+
}), PAID_REQUEST_KEY_NAMESPACE);
|
|
18688
|
+
}
|
|
18689
|
+
__name(derivePaidRequestKey, "derivePaidRequestKey");
|
|
18690
|
+
|
|
17676
18691
|
// src/tools/winning-product-image.ts
|
|
17677
|
-
import { z as
|
|
17678
|
-
var WinnerReferenceInput =
|
|
17679
|
-
runId:
|
|
17680
|
-
candidateSourceId:
|
|
18692
|
+
import { z as z75 } from "zod";
|
|
18693
|
+
var WinnerReferenceInput = z75.object({
|
|
18694
|
+
runId: z75.string().uuid(),
|
|
18695
|
+
candidateSourceId: z75.string().trim().min(1).max(160)
|
|
17681
18696
|
}).strict().describe("Referencia opaca de un producto devuelto por find_winning_products/get_product_research_run.");
|
|
17682
18697
|
async function resolveWinnerImages(api, winnerReference, images) {
|
|
17683
18698
|
if (!winnerReference) return images;
|
|
@@ -17714,59 +18729,59 @@ var createProductTaskSingleOutputDescription = renderCreateProductTaskAvoidWhenF
|
|
|
17714
18729
|
var createServiceVideoGuidance = getProductMakerCapabilityModelGuidance("create_service_video");
|
|
17715
18730
|
var listTasksGuidance = getProductMakerCapabilityModelGuidance("list_tasks");
|
|
17716
18731
|
var editTaskDraftGuidance = getProductMakerCapabilityModelGuidance("edit_task_draft");
|
|
17717
|
-
var CreateProductTaskInput =
|
|
18732
|
+
var CreateProductTaskInput = z76.object({
|
|
17718
18733
|
images: ImagesInput.optional().describe("1\u20135 fotos del mismo producto. Omitir \xFAnicamente cuando projectId apunta a un proyecto propio con imagen guardada."),
|
|
17719
18734
|
winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
|
|
17720
|
-
projectId:
|
|
17721
|
-
productUrl:
|
|
18735
|
+
projectId: z76.string().uuid().optional().describe("Opcional. Proyecto guiado propio. Permite continuar sin volver a subir la imagen guardada; nunca evita cr\xE9ditos, cuotas ni confirmaciones."),
|
|
18736
|
+
productUrl: z76.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."),
|
|
17722
18737
|
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.'),
|
|
17723
18738
|
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.'),
|
|
17724
|
-
price:
|
|
17725
|
-
compareAtPrice:
|
|
17726
|
-
offer:
|
|
17727
|
-
paymentMethods:
|
|
17728
|
-
productContext:
|
|
17729
|
-
productLabel:
|
|
18739
|
+
price: z76.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.'),
|
|
18740
|
+
compareAtPrice: z76.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".'),
|
|
18741
|
+
offer: z76.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.'),
|
|
18742
|
+
paymentMethods: z76.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.'),
|
|
18743
|
+
productContext: z76.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."),
|
|
18744
|
+
productLabel: z76.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.'),
|
|
17730
18745
|
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), excepto "problem_solution", que requiere 30s Multiescena. Opciones: "auto", "ugc_dynamic" (review con experiencia y prueba), "ugc_how_to" (tutorial con pasos y resultado visible), "ugc_unboxing_chaos" (apertura y primera prueba), "problem_solution" (problema concreto, producto como soluci\xF3n y CTA), "product_showcase" (producto ejecutando una funci\xF3n real), "wearable_showcase" (prenda o accesorio modelado), "cinematic" (TV spot con receta cinematogr\xE1fica), "wild_card" (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.'),
|
|
17731
|
-
durationSeconds:
|
|
17732
|
-
|
|
17733
|
-
|
|
18746
|
+
durationSeconds: z76.union([
|
|
18747
|
+
z76.literal(15),
|
|
18748
|
+
z76.literal(30)
|
|
17734
18749
|
]).default(15).describe("Opcional. Duraci\xF3n objetivo del video: 15s (single_call, default) o 30s (Multiescena, aproximadamente 30s y facturado por escena)."),
|
|
17735
|
-
pauseForAngleReview:
|
|
17736
|
-
aiDecidesAll:
|
|
18750
|
+
pauseForAngleReview: z76.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."),
|
|
18751
|
+
aiDecidesAll: z76.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."),
|
|
17737
18752
|
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.'),
|
|
17738
18753
|
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.'),
|
|
17739
18754
|
videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El proveedor se elige internamente. Default: economy.'),
|
|
17740
18755
|
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).'),
|
|
17741
|
-
videoAngleCount:
|
|
18756
|
+
videoAngleCount: z76.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."),
|
|
17742
18757
|
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.'),
|
|
17743
|
-
outputs:
|
|
18758
|
+
outputs: z76.array(z76.enum([
|
|
17744
18759
|
"landing",
|
|
17745
18760
|
"video",
|
|
17746
18761
|
"image"
|
|
17747
18762
|
])).min(2).max(3).optional().describe(`Opcional. Qu\xE9 outputs generar. Default: todos ["landing","video","image"]. Para 2 outputs: ["landing","image"] (sin video), ["video","image"] (sin landing), ["landing","video"] (sin imagen). ${createProductTaskSingleOutputDescription}`),
|
|
17748
|
-
competitorScanEnabled:
|
|
17749
|
-
replicateWinnerWhenFound:
|
|
17750
|
-
brandId:
|
|
17751
|
-
actorId:
|
|
18763
|
+
competitorScanEnabled: z76.boolean().optional().describe("Opcional. Debe enviarse true solo despu\xE9s de que el usuario acepte estudiar la competencia (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. Omitir no autoriza el estudio profundo."),
|
|
18764
|
+
replicateWinnerWhenFound: z76.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."),
|
|
18765
|
+
brandId: z76.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."),
|
|
18766
|
+
actorId: z76.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."),
|
|
17752
18767
|
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.'),
|
|
17753
|
-
creativeDirection:
|
|
17754
|
-
headline:
|
|
17755
|
-
subheadline:
|
|
18768
|
+
creativeDirection: z76.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.'),
|
|
18769
|
+
headline: z76.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."),
|
|
18770
|
+
subheadline: z76.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."),
|
|
17756
18771
|
landingStrategy: LandingStrategyEnum.default("classic").describe('Opcional. Estructura de la landing cl\xE1sica cuando landing est\xE1 entre outputs: "classic" (estructura original probada y recomendada; default del primer rollout), "auto" (la IA decide; experimental), "pain_solution", "social_proof" (Landing Viral: UGC, WhatsApp, Instagram y evidencia social), "benefits_clarity", "offer_value" o "lifestyle_identity". Default "classic".'),
|
|
17757
18772
|
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".')
|
|
17758
18773
|
}).strict();
|
|
17759
|
-
var CreateServiceVideoInput =
|
|
17760
|
-
landingUrl:
|
|
17761
|
-
additionalContext:
|
|
18774
|
+
var CreateServiceVideoInput = z76.object({
|
|
18775
|
+
landingUrl: z76.string().url().describe("URL p\xFAblica de la landing del servicio. Es suficiente para generar el video; los medios son opcionales en la web."),
|
|
18776
|
+
additionalContext: z76.string().max(3e3).optional().describe('Instrucci\xF3n natural prioritaria. Ej.: "adapta el ritmo de estos competidores", "enfatiza reservas de demos" o restricciones de claims.'),
|
|
17762
18777
|
language: Lang.describe("Idioma del video: es, en o pt."),
|
|
17763
|
-
voiceId:
|
|
17764
|
-
brandId:
|
|
17765
|
-
reviewMode:
|
|
18778
|
+
voiceId: z76.string().trim().min(1).optional().describe('Opcional. Voz de ElevenLabs para toda la narraci\xF3n. Usa "auto" para que la IA la alinee con el presentador o env\xEDa un ID concreto de la lista de voces de la web.'),
|
|
18779
|
+
brandId: z76.string().uuid().optional().describe("Marca guardada del usuario. Aplica voz, mensajes, paleta y persona predeterminada."),
|
|
18780
|
+
reviewMode: z76.enum([
|
|
17766
18781
|
"automatic",
|
|
17767
18782
|
"guided"
|
|
17768
18783
|
]).default("automatic").describe("automatic = la IA elige concepto y guion sin pausas; guided = el usuario aprueba concepto y storyboard."),
|
|
17769
|
-
videoPreset:
|
|
18784
|
+
videoPreset: z76.enum([
|
|
17770
18785
|
"auto",
|
|
17771
18786
|
"ugc_dynamic",
|
|
17772
18787
|
"ugc_how_to",
|
|
@@ -17776,128 +18791,128 @@ var CreateServiceVideoInput = z72.object({
|
|
|
17776
18791
|
videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El proveedor se elige internamente. Default: economy.'),
|
|
17777
18792
|
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.')
|
|
17778
18793
|
}).strict();
|
|
17779
|
-
var GetTaskStatusInput =
|
|
17780
|
-
taskId:
|
|
17781
|
-
waitSeconds:
|
|
18794
|
+
var GetTaskStatusInput = z76.object({
|
|
18795
|
+
taskId: z76.string().min(1),
|
|
18796
|
+
waitSeconds: z76.number().int().min(0).max(120).optional()
|
|
17782
18797
|
});
|
|
17783
|
-
var ListTasksInput =
|
|
17784
|
-
limit:
|
|
17785
|
-
offset:
|
|
17786
|
-
search:
|
|
18798
|
+
var ListTasksInput = z76.object({
|
|
18799
|
+
limit: z76.number().int().min(1).max(50).optional(),
|
|
18800
|
+
offset: z76.number().int().min(0).optional(),
|
|
18801
|
+
search: z76.string().optional()
|
|
17787
18802
|
});
|
|
17788
18803
|
var MCP_REVIEW_LIST_FIELD_MAX = 1500;
|
|
17789
18804
|
var MCP_REVIEW_FEATURE_ITEM_MAX = 240;
|
|
17790
|
-
var EditTaskDraftInput =
|
|
17791
|
-
taskId:
|
|
17792
|
-
angleIndex:
|
|
17793
|
-
angle:
|
|
17794
|
-
angle:
|
|
17795
|
-
buyerPersona:
|
|
17796
|
-
actor:
|
|
17797
|
-
actorId:
|
|
17798
|
-
gender:
|
|
18805
|
+
var EditTaskDraftInput = z76.object({
|
|
18806
|
+
taskId: z76.string().min(1),
|
|
18807
|
+
angleIndex: z76.number().int().min(0),
|
|
18808
|
+
angle: z76.object({
|
|
18809
|
+
angle: z76.string().min(1).max(480),
|
|
18810
|
+
buyerPersona: z76.string().min(1).max(360),
|
|
18811
|
+
actor: z76.string().min(1).max(360).optional(),
|
|
18812
|
+
actorId: z76.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."),
|
|
18813
|
+
gender: z76.enum([
|
|
17799
18814
|
"female",
|
|
17800
18815
|
"male"
|
|
17801
18816
|
]).optional(),
|
|
17802
|
-
scriptNotes:
|
|
18817
|
+
scriptNotes: z76.string().max(2e3).optional()
|
|
17803
18818
|
})
|
|
17804
18819
|
});
|
|
17805
|
-
var PendingActionPayload =
|
|
17806
|
-
|
|
17807
|
-
kind:
|
|
18820
|
+
var PendingActionPayload = z76.discriminatedUnion("kind", [
|
|
18821
|
+
z76.object({
|
|
18822
|
+
kind: z76.literal("product_reference_set_approval"),
|
|
17808
18823
|
scope: ProductReferenceScopeEnum.optional(),
|
|
17809
|
-
scopeKey:
|
|
17810
|
-
scopeSnapshotId:
|
|
17811
|
-
expectedScopeHash:
|
|
18824
|
+
scopeKey: z76.string().min(1).max(120).optional(),
|
|
18825
|
+
scopeSnapshotId: z76.string().uuid().optional(),
|
|
18826
|
+
expectedScopeHash: z76.string().min(1).max(128).optional(),
|
|
17812
18827
|
decision: ProductReferenceResolutionDecisionEnum,
|
|
17813
18828
|
reason: ProductReferenceRejectionReasonEnum.optional(),
|
|
17814
|
-
affectedRefKeys:
|
|
17815
|
-
affectedPhotoNumbers:
|
|
17816
|
-
recoveryAction:
|
|
18829
|
+
affectedRefKeys: z76.array(z76.string().min(1).max(200)).min(1).optional(),
|
|
18830
|
+
affectedPhotoNumbers: z76.array(z76.number().int().positive()).min(1).optional(),
|
|
18831
|
+
recoveryAction: z76.enum([
|
|
17817
18832
|
"remove",
|
|
17818
18833
|
"replace",
|
|
17819
18834
|
"upload",
|
|
17820
18835
|
"return_to_selection"
|
|
17821
18836
|
]).optional()
|
|
17822
18837
|
}),
|
|
17823
|
-
|
|
17824
|
-
kind:
|
|
17825
|
-
selectedPhotoNumbers:
|
|
18838
|
+
z76.object({
|
|
18839
|
+
kind: z76.literal("product_reference_confirmation"),
|
|
18840
|
+
selectedPhotoNumbers: z76.array(z76.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."),
|
|
17826
18841
|
userChoice: ProductReferenceUserChoiceEnum.optional(),
|
|
17827
|
-
confirmedProductNames:
|
|
18842
|
+
confirmedProductNames: z76.array(z76.string().min(1).max(120)).min(2).max(8).optional(),
|
|
17828
18843
|
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."),
|
|
17829
18844
|
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."),
|
|
17830
|
-
useMultiSceneShowcase:
|
|
18845
|
+
useMultiSceneShowcase: z76.boolean().optional().describe("Compatibilidad con confirmaciones antiguas: si es true junto con userChoice=variants, conserva el showcase multiescena.")
|
|
17831
18846
|
}),
|
|
17832
|
-
|
|
17833
|
-
kind:
|
|
18847
|
+
z76.object({
|
|
18848
|
+
kind: z76.literal("angle_review_approval"),
|
|
17834
18849
|
// All edits are optional — empty action body just approves the
|
|
17835
18850
|
// backend-generated draft as-is. Field shapes mirror the angle-review
|
|
17836
18851
|
// request contracts in @packages/types/wizard.ts; the handler routes to
|
|
17837
18852
|
// the dedicated video/image/autopilot endpoint based on StatusResponse.kind.
|
|
17838
|
-
customAngle:
|
|
18853
|
+
customAngle: z76.string().min(1).max(480).optional(),
|
|
17839
18854
|
// Keep the shared MCP action within the strictest downstream contract:
|
|
17840
18855
|
// autopilot/image resume endpoints cap these fields at 1500 characters.
|
|
17841
|
-
painPoints:
|
|
17842
|
-
benefits:
|
|
18856
|
+
painPoints: z76.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
|
|
18857
|
+
benefits: z76.string().max(MCP_REVIEW_LIST_FIELD_MAX).optional(),
|
|
17843
18858
|
// Same policy as the two fields above: the strictest downstream contract
|
|
17844
18859
|
// wins. The image endpoint caps each feature at 240 while landing/video
|
|
17845
18860
|
// accept 300, and this single action routes to whichever the task is — so
|
|
17846
18861
|
// accepting 300 here turns a 250-character feature on an image task into
|
|
17847
18862
|
// an opaque HTTP 400 after the model already believed it had been saved.
|
|
17848
|
-
features:
|
|
17849
|
-
buyerPersona:
|
|
18863
|
+
features: z76.array(z76.string().min(1).max(MCP_REVIEW_FEATURE_ITEM_MAX)).max(10).optional(),
|
|
18864
|
+
buyerPersona: z76.string().min(1).max(360).optional(),
|
|
17850
18865
|
narrativeStyle: PublicNarrativeStyleEnum.optional().describe('Narrativa del video. "problem_product_cta" (Problema y Soluci\xF3n) requiere Multiescena de 30s: en un video de 15s en formato Un solo clip el servidor la rechaza.'),
|
|
17851
|
-
actor:
|
|
17852
|
-
actorId:
|
|
17853
|
-
creativeDirection:
|
|
17854
|
-
selectedAngleNumbers:
|
|
17855
|
-
angleEdits:
|
|
17856
|
-
angleNumber:
|
|
17857
|
-
narrativeSelection:
|
|
18866
|
+
actor: z76.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."),
|
|
18867
|
+
actorId: z76.string().max(120).nullable().optional(),
|
|
18868
|
+
creativeDirection: z76.string().max(2e3).optional(),
|
|
18869
|
+
selectedAngleNumbers: z76.array(z76.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."),
|
|
18870
|
+
angleEdits: z76.array(z76.object({
|
|
18871
|
+
angleNumber: z76.number().int().positive(),
|
|
18872
|
+
narrativeSelection: z76.enum([
|
|
17858
18873
|
"market",
|
|
17859
18874
|
"guided"
|
|
17860
18875
|
]).optional().describe("Elecci\xF3n expl\xEDcita: market usa el estudio disponible; guided usa la narrativa elegida para este \xE1ngulo."),
|
|
17861
|
-
angle:
|
|
17862
|
-
buyerPersona:
|
|
18876
|
+
angle: z76.string().min(1).max(480).optional(),
|
|
18877
|
+
buyerPersona: z76.string().min(1).max(360).optional(),
|
|
17863
18878
|
narrativeStyle: PublicNarrativeStyleEnum.optional().describe('Narrativa del video. "problem_product_cta" (Problema y Soluci\xF3n) requiere Multiescena de 30s: en un video de 15s en formato Un solo clip el servidor la rechaza.'),
|
|
17864
|
-
actor:
|
|
17865
|
-
actorId:
|
|
17866
|
-
creativeDirection:
|
|
18879
|
+
actor: z76.string().min(1).max(360).optional(),
|
|
18880
|
+
actorId: z76.string().max(120).nullable().optional(),
|
|
18881
|
+
creativeDirection: z76.string().max(2e3).optional()
|
|
17867
18882
|
}).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)."),
|
|
17868
|
-
gapDurationSeconds:
|
|
17869
|
-
|
|
17870
|
-
|
|
18883
|
+
gapDurationSeconds: z76.union([
|
|
18884
|
+
z76.literal(15),
|
|
18885
|
+
z76.literal(30)
|
|
17871
18886
|
]).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.")
|
|
17872
18887
|
}),
|
|
17873
|
-
|
|
17874
|
-
kind:
|
|
17875
|
-
angleId:
|
|
17876
|
-
angleNumber:
|
|
17877
|
-
content:
|
|
17878
|
-
creativeDirection:
|
|
17879
|
-
actor:
|
|
18888
|
+
z76.object({
|
|
18889
|
+
kind: z76.literal("service_angle_approval"),
|
|
18890
|
+
angleId: z76.string().uuid().optional(),
|
|
18891
|
+
angleNumber: z76.number().int().positive().optional(),
|
|
18892
|
+
content: z76.string().min(1).max(480).optional(),
|
|
18893
|
+
creativeDirection: z76.string().min(1).max(1500).optional(),
|
|
18894
|
+
actor: z76.string().min(1).max(360).optional()
|
|
17880
18895
|
}),
|
|
17881
|
-
|
|
17882
|
-
kind:
|
|
17883
|
-
voiceovers:
|
|
17884
|
-
visualDirections:
|
|
17885
|
-
voiceoversByScene:
|
|
17886
|
-
visualDirectionsByScene:
|
|
18896
|
+
z76.object({
|
|
18897
|
+
kind: z76.literal("service_script_approval"),
|
|
18898
|
+
voiceovers: z76.record(z76.string(), z76.string().min(1).max(600)).optional(),
|
|
18899
|
+
visualDirections: z76.record(z76.string(), z76.string().min(1).max(1200)).optional(),
|
|
18900
|
+
voiceoversByScene: z76.record(z76.string(), z76.string().min(1).max(600)).optional(),
|
|
18901
|
+
visualDirectionsByScene: z76.record(z76.string(), z76.string().min(1).max(1200)).optional()
|
|
17887
18902
|
})
|
|
17888
18903
|
]);
|
|
17889
|
-
var ResolvePendingActionInput =
|
|
17890
|
-
taskId:
|
|
18904
|
+
var ResolvePendingActionInput = z76.object({
|
|
18905
|
+
taskId: z76.string().min(1),
|
|
17891
18906
|
action: PendingActionPayload
|
|
17892
18907
|
}).strict();
|
|
17893
18908
|
function resolveVariantConfirmVideoTier(action) {
|
|
17894
18909
|
return action.useMultiSceneShowcase && action.userChoice === "variants" ? "standard" : void 0;
|
|
17895
18910
|
}
|
|
17896
18911
|
__name(resolveVariantConfirmVideoTier, "resolveVariantConfirmVideoTier");
|
|
17897
|
-
var StatusForResolveSchema =
|
|
18912
|
+
var StatusForResolveSchema = z76.object({
|
|
17898
18913
|
// Metadata used to select the backend resume contract. Older API responses
|
|
17899
18914
|
// may omit these fields, so the resolver keeps the generic fallback.
|
|
17900
|
-
kind:
|
|
18915
|
+
kind: z76.enum([
|
|
17901
18916
|
"autopilot",
|
|
17902
18917
|
"video",
|
|
17903
18918
|
"image",
|
|
@@ -17905,18 +18920,18 @@ var StatusForResolveSchema = z72.object({
|
|
|
17905
18920
|
"mix",
|
|
17906
18921
|
"service"
|
|
17907
18922
|
]).optional(),
|
|
17908
|
-
selectedOutputs:
|
|
18923
|
+
selectedOutputs: z76.array(z76.enum([
|
|
17909
18924
|
"landing",
|
|
17910
18925
|
"video",
|
|
17911
18926
|
"image"
|
|
17912
18927
|
])).optional(),
|
|
17913
|
-
videoAngleCount:
|
|
17914
|
-
ugcFormat:
|
|
18928
|
+
videoAngleCount: z76.number().int().min(1).max(3).optional(),
|
|
18929
|
+
ugcFormat: z76.enum([
|
|
17915
18930
|
"single_8s",
|
|
17916
18931
|
"single_15s",
|
|
17917
18932
|
"double_30s"
|
|
17918
18933
|
]).optional(),
|
|
17919
|
-
videoStyle:
|
|
18934
|
+
videoStyle: z76.enum([
|
|
17920
18935
|
"ugc",
|
|
17921
18936
|
"cartoon_3d",
|
|
17922
18937
|
"product_only",
|
|
@@ -17925,79 +18940,72 @@ var StatusForResolveSchema = z72.object({
|
|
|
17925
18940
|
videoStructure: VideoStructureEnum.optional(),
|
|
17926
18941
|
videoQuality: VideoQualityEnum.optional(),
|
|
17927
18942
|
videoRouteId: VideoRouteIdEnum.optional(),
|
|
17928
|
-
videoModel:
|
|
17929
|
-
|
|
17930
|
-
"wan",
|
|
17931
|
-
"bytedance",
|
|
17932
|
-
"seedance",
|
|
17933
|
-
"grok",
|
|
17934
|
-
"kling"
|
|
17935
|
-
]).optional(),
|
|
17936
|
-
videoTier: z72.enum([
|
|
18943
|
+
videoModel: TaskVideoModelEnum.optional(),
|
|
18944
|
+
videoTier: z76.enum([
|
|
17937
18945
|
"legacy",
|
|
17938
18946
|
"standard",
|
|
17939
18947
|
"pro",
|
|
17940
18948
|
"single_call"
|
|
17941
18949
|
]).optional(),
|
|
17942
|
-
videoResolution:
|
|
18950
|
+
videoResolution: z76.enum([
|
|
17943
18951
|
"480p",
|
|
17944
18952
|
"720p"
|
|
17945
18953
|
]).optional(),
|
|
17946
18954
|
narrativeStyle: NarrativeStyleEnum.optional(),
|
|
17947
|
-
pauseForVideoScriptReview:
|
|
17948
|
-
pendingUserAction:
|
|
17949
|
-
kind:
|
|
17950
|
-
candidateGrouping:
|
|
17951
|
-
selectedImageUrls:
|
|
17952
|
-
proposedProductNames:
|
|
18955
|
+
pauseForVideoScriptReview: z76.boolean().optional(),
|
|
18956
|
+
pendingUserAction: z76.object({
|
|
18957
|
+
kind: z76.string(),
|
|
18958
|
+
candidateGrouping: z76.string().optional(),
|
|
18959
|
+
selectedImageUrls: z76.array(z76.string()).optional(),
|
|
18960
|
+
proposedProductNames: z76.array(z76.string()).optional(),
|
|
17953
18961
|
// Adaptive reference questions are server-owned. Echo only the evidence
|
|
17954
18962
|
// identity and the choices shown by the current snapshot; never accept a
|
|
17955
18963
|
// client-supplied reference set as authorization.
|
|
17956
|
-
options:
|
|
17957
|
-
mode:
|
|
18964
|
+
options: z76.array(ProductReferenceUserChoiceEnum).max(4).optional(),
|
|
18965
|
+
mode: z76.enum([
|
|
17958
18966
|
"question",
|
|
17959
18967
|
"visual_recovery"
|
|
17960
18968
|
]).optional(),
|
|
17961
18969
|
/** Hand-mirrored from packages/types result.ts — see CLAUDE.md § MCP Server Sync. */
|
|
17962
|
-
canKeepSelection:
|
|
17963
|
-
decisionKey:
|
|
17964
|
-
questionOrdinal:
|
|
17965
|
-
questionCeiling:
|
|
17966
|
-
|
|
17967
|
-
|
|
18970
|
+
canKeepSelection: z76.boolean().optional(),
|
|
18971
|
+
decisionKey: z76.string().optional(),
|
|
18972
|
+
questionOrdinal: z76.number().int().min(1).max(5).optional(),
|
|
18973
|
+
questionCeiling: z76.union([
|
|
18974
|
+
z76.literal(3),
|
|
18975
|
+
z76.literal(5)
|
|
17968
18976
|
]).optional(),
|
|
17969
|
-
referenceEvidenceVersion:
|
|
17970
|
-
expectedEvidenceHash:
|
|
17971
|
-
question:
|
|
17972
|
-
prompt:
|
|
17973
|
-
helpText:
|
|
17974
|
-
options:
|
|
18977
|
+
referenceEvidenceVersion: z76.number().int().positive().optional(),
|
|
18978
|
+
expectedEvidenceHash: z76.string().optional(),
|
|
18979
|
+
question: z76.object({
|
|
18980
|
+
prompt: z76.string().min(1).max(240),
|
|
18981
|
+
helpText: z76.string().min(1).max(300).optional(),
|
|
18982
|
+
options: z76.array(z76.object({
|
|
17975
18983
|
value: ProductReferenceUserChoiceEnum,
|
|
17976
|
-
label:
|
|
17977
|
-
description:
|
|
18984
|
+
label: z76.string().min(1).max(120),
|
|
18985
|
+
description: z76.string().min(1).max(240).optional()
|
|
17978
18986
|
})).min(2).max(4)
|
|
17979
18987
|
}).optional(),
|
|
17980
18988
|
scope: ProductReferenceScopeEnum.optional(),
|
|
17981
|
-
scopeKey:
|
|
17982
|
-
scopeSnapshotId:
|
|
17983
|
-
scopeHash:
|
|
17984
|
-
baseReferenceSetHash:
|
|
17985
|
-
phase:
|
|
18989
|
+
scopeKey: z76.string().optional(),
|
|
18990
|
+
scopeSnapshotId: z76.string().uuid().optional(),
|
|
18991
|
+
scopeHash: z76.string().optional(),
|
|
18992
|
+
baseReferenceSetHash: z76.string().optional(),
|
|
18993
|
+
phase: z76.enum([
|
|
17986
18994
|
"preparation",
|
|
17987
18995
|
"final"
|
|
17988
18996
|
]).optional(),
|
|
17989
|
-
selectedRefKeys:
|
|
17990
|
-
allowedDecisions:
|
|
17991
|
-
previews:
|
|
17992
|
-
refKey:
|
|
18997
|
+
selectedRefKeys: z76.array(z76.string().min(1).max(200)).optional(),
|
|
18998
|
+
allowedDecisions: z76.array(ProductReferenceResolutionDecisionEnum).optional(),
|
|
18999
|
+
previews: z76.array(z76.object({
|
|
19000
|
+
refKey: z76.string().min(1).max(200)
|
|
17993
19001
|
}).passthrough()).optional(),
|
|
17994
|
-
customAngleDraft:
|
|
17995
|
-
painPointsDraft:
|
|
17996
|
-
benefitsDraft:
|
|
17997
|
-
featuresDraft:
|
|
17998
|
-
angleOptions:
|
|
17999
|
-
index:
|
|
18000
|
-
angle:
|
|
19002
|
+
customAngleDraft: z76.string().optional(),
|
|
19003
|
+
painPointsDraft: z76.string().optional(),
|
|
19004
|
+
benefitsDraft: z76.string().optional(),
|
|
19005
|
+
featuresDraft: z76.array(z76.string()).optional(),
|
|
19006
|
+
angleOptions: z76.array(z76.object({
|
|
19007
|
+
index: z76.number().int().nonnegative(),
|
|
19008
|
+
angle: z76.string().min(1)
|
|
18001
19009
|
}).passthrough()).min(1).max(5).optional(),
|
|
18002
19010
|
// Recommendation consumed only when the caller explicitly sends
|
|
18003
19011
|
// gapDurationSeconds: 30 in the angle approval action.
|
|
@@ -18007,17 +19015,17 @@ var StatusForResolveSchema = z72.object({
|
|
|
18007
19015
|
// keys. `actorId` (the saved custom actor the picker stored) was silently
|
|
18008
19016
|
// dropped here, so the approval handler below could not echo it back on the
|
|
18009
19017
|
// PATCH — the selection looked accepted and reached no render.
|
|
18010
|
-
angles:
|
|
18011
|
-
id:
|
|
18012
|
-
content:
|
|
18013
|
-
creativeDirection:
|
|
18014
|
-
actor:
|
|
18015
|
-
actorId:
|
|
19018
|
+
angles: z76.array(z76.object({
|
|
19019
|
+
id: z76.string().uuid(),
|
|
19020
|
+
content: z76.string(),
|
|
19021
|
+
creativeDirection: z76.string(),
|
|
19022
|
+
actor: z76.string(),
|
|
19023
|
+
actorId: z76.string().nullable().optional()
|
|
18016
19024
|
}).passthrough()).optional(),
|
|
18017
|
-
panels:
|
|
18018
|
-
beatId:
|
|
18019
|
-
voiceover:
|
|
18020
|
-
visualDirection:
|
|
19025
|
+
panels: z76.array(z76.object({
|
|
19026
|
+
beatId: z76.string(),
|
|
19027
|
+
voiceover: z76.string(),
|
|
19028
|
+
visualDirection: z76.string()
|
|
18021
19029
|
}).passthrough()).optional()
|
|
18022
19030
|
}).optional()
|
|
18023
19031
|
}).passthrough();
|
|
@@ -18216,10 +19224,25 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
|
|
|
18216
19224
|
};
|
|
18217
19225
|
const r = await api.postMultipart("/v1/ingest", {
|
|
18218
19226
|
images: parts
|
|
18219
|
-
}, fields
|
|
19227
|
+
}, fields, {
|
|
19228
|
+
// LLM hosts retry paid tools with rephrased arguments — the API's
|
|
19229
|
+
// byte-fingerprint can't see the duplicate, this key can. Derived
|
|
19230
|
+
// from the semantic inputs, not the wire fields, for the same
|
|
19231
|
+
// reason (see request-key.ts, which also canonicalizes the
|
|
19232
|
+
// order-insignificant `outputs` set).
|
|
19233
|
+
idempotencyKey: derivePaidRequestKey({
|
|
19234
|
+
fingerprint: api.fingerprint(),
|
|
19235
|
+
tool: "create_product_task",
|
|
19236
|
+
input,
|
|
19237
|
+
nowMs: Date.now()
|
|
19238
|
+
})
|
|
19239
|
+
});
|
|
18220
19240
|
return asText({
|
|
18221
19241
|
taskId: r.taskId,
|
|
18222
|
-
status: "queued",
|
|
19242
|
+
status: r.status ?? "queued",
|
|
19243
|
+
...r.replayed ? {
|
|
19244
|
+
replayed: true
|
|
19245
|
+
} : {},
|
|
18223
19246
|
estimatedSeconds: 300,
|
|
18224
19247
|
outputs: selectedOutputs,
|
|
18225
19248
|
outputMode: "single_task",
|
|
@@ -18256,26 +19279,56 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
|
|
|
18256
19279
|
assets: []
|
|
18257
19280
|
},
|
|
18258
19281
|
appDemoVideos: []
|
|
19282
|
+
}, {
|
|
19283
|
+
// The 2026-09-25 incident: four retries of this exact tool created
|
|
19284
|
+
// four charged service tasks because the host rephrased
|
|
19285
|
+
// `additionalContext` and flipped the landing between `/` and
|
|
19286
|
+
// `/es`. The derived key is stable across both rewrites (see
|
|
19287
|
+
// request-key.ts).
|
|
19288
|
+
idempotencyKey: derivePaidRequestKey({
|
|
19289
|
+
fingerprint: api.fingerprint(),
|
|
19290
|
+
tool: "create_service_video",
|
|
19291
|
+
input,
|
|
19292
|
+
nowMs: Date.now()
|
|
19293
|
+
})
|
|
18259
19294
|
});
|
|
18260
19295
|
const angles = await api.postJson(`/v1/tasks/${encodeURIComponent(created.taskId)}/service-angles`, {});
|
|
18261
19296
|
const first = angles[0];
|
|
19297
|
+
const replayed = created.replayed === true;
|
|
18262
19298
|
if (input.reviewMode === "automatic") {
|
|
18263
19299
|
if (!first) throw new Error("ProductMaker no pudo crear un concepto para este servicio.");
|
|
18264
|
-
|
|
18265
|
-
|
|
18266
|
-
|
|
18267
|
-
|
|
18268
|
-
|
|
19300
|
+
if (!(replayed && created.status !== "queued")) {
|
|
19301
|
+
await api.postJson(`/v1/tasks/${encodeURIComponent(created.taskId)}/service-angles/select`, {
|
|
19302
|
+
angleIds: [
|
|
19303
|
+
first.id
|
|
19304
|
+
]
|
|
19305
|
+
});
|
|
19306
|
+
}
|
|
18269
19307
|
return asText({
|
|
18270
19308
|
taskId: created.taskId,
|
|
18271
|
-
status: "processing",
|
|
19309
|
+
status: replayed ? created.status ?? "processing" : "processing",
|
|
19310
|
+
...replayed ? {
|
|
19311
|
+
replayed: true
|
|
19312
|
+
} : {},
|
|
18272
19313
|
reviewMode: input.reviewMode,
|
|
18273
19314
|
selectedConcept: first
|
|
18274
19315
|
});
|
|
18275
19316
|
}
|
|
19317
|
+
if (replayed && created.status !== "queued") {
|
|
19318
|
+
return asText({
|
|
19319
|
+
taskId: created.taskId,
|
|
19320
|
+
status: created.status,
|
|
19321
|
+
replayed: true,
|
|
19322
|
+
reviewMode: input.reviewMode,
|
|
19323
|
+
angles
|
|
19324
|
+
});
|
|
19325
|
+
}
|
|
18276
19326
|
return asText({
|
|
18277
19327
|
taskId: created.taskId,
|
|
18278
19328
|
status: "waiting_for_user",
|
|
19329
|
+
...replayed ? {
|
|
19330
|
+
replayed: true
|
|
19331
|
+
} : {},
|
|
18279
19332
|
reviewMode: input.reviewMode,
|
|
18280
19333
|
pendingUserAction: {
|
|
18281
19334
|
kind: "service_angle_approval",
|
|
@@ -18851,8 +19904,7 @@ ANTES de invocar, resume outputs, cantidad de videos y datos comerciales, explic
|
|
|
18851
19904
|
__name(registerTaskTools, "registerTaskTools");
|
|
18852
19905
|
|
|
18853
19906
|
// src/tools/creatives.ts
|
|
18854
|
-
import {
|
|
18855
|
-
import { z as z73 } from "zod";
|
|
19907
|
+
import { z as z77 } from "zod";
|
|
18856
19908
|
var generateFreeVideoGuidance = getProductMakerCapabilityModelGuidance("generate_free_video");
|
|
18857
19909
|
var generateVideoCreativeGuidance = getProductMakerCapabilityModelGuidance("generate_video_creative");
|
|
18858
19910
|
var generateImageCreativesGuidance = getProductMakerCapabilityModelGuidance("generate_image_creatives");
|
|
@@ -18862,70 +19914,70 @@ var CreativeRefs = {
|
|
|
18862
19914
|
images: ImagesInput,
|
|
18863
19915
|
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.'),
|
|
18864
19916
|
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.'),
|
|
18865
|
-
price:
|
|
18866
|
-
offer:
|
|
18867
|
-
compareAtPrice:
|
|
18868
|
-
productContext:
|
|
18869
|
-
productLabel:
|
|
18870
|
-
buyerPersona:
|
|
18871
|
-
isCombo:
|
|
18872
|
-
competitorScanEnabled:
|
|
18873
|
-
brandId:
|
|
19917
|
+
price: z77.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.'),
|
|
19918
|
+
offer: z77.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.'),
|
|
19919
|
+
compareAtPrice: z77.string().min(1).max(120).optional().describe('Opcional. Precio anterior o de referencia para mostrar descuento. Ej. "$129.000" cuando price="$89.900".'),
|
|
19920
|
+
productContext: z77.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."),
|
|
19921
|
+
productLabel: z77.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.'),
|
|
19922
|
+
buyerPersona: z77.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.'),
|
|
19923
|
+
isCombo: z77.boolean().optional().describe("Opcional. Si true, el creativo presenta el producto como combo/pack. Default false."),
|
|
19924
|
+
competitorScanEnabled: z77.boolean().optional().describe("Opcional. Debe enviarse true solo despu\xE9s de que el usuario acepte estudiar la competencia (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. Omitir no autoriza el estudio profundo."),
|
|
19925
|
+
brandId: z77.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.")
|
|
18874
19926
|
};
|
|
18875
|
-
var VideoPresenter =
|
|
18876
|
-
|
|
18877
|
-
mode:
|
|
19927
|
+
var VideoPresenter = z77.discriminatedUnion("mode", [
|
|
19928
|
+
z77.object({
|
|
19929
|
+
mode: z77.literal("none")
|
|
18878
19930
|
}).strict(),
|
|
18879
|
-
|
|
18880
|
-
mode:
|
|
18881
|
-
actorId:
|
|
19931
|
+
z77.object({
|
|
19932
|
+
mode: z77.literal("saved_actor"),
|
|
19933
|
+
actorId: z77.string().trim().min(1).max(120).describe("ID devuelto por list_actors para un actor guardado del usuario.")
|
|
18882
19934
|
}).strict(),
|
|
18883
|
-
|
|
18884
|
-
mode:
|
|
18885
|
-
description:
|
|
19935
|
+
z77.object({
|
|
19936
|
+
mode: z77.literal("described"),
|
|
19937
|
+
description: z77.string().trim().min(1).max(500).describe("Descripci\xF3n concreta de la persona que presenta el producto.")
|
|
18886
19938
|
}).strict()
|
|
18887
19939
|
]);
|
|
18888
|
-
var VideoCreativeSetup =
|
|
18889
|
-
|
|
18890
|
-
mode:
|
|
19940
|
+
var VideoCreativeSetup = z77.discriminatedUnion("mode", [
|
|
19941
|
+
z77.object({
|
|
19942
|
+
mode: z77.literal("automatic").describe('S\xF3lo cuando el usuario pidi\xF3 expl\xEDcitamente "decide todo".')
|
|
18891
19943
|
}).strict(),
|
|
18892
|
-
|
|
18893
|
-
mode:
|
|
19944
|
+
z77.object({
|
|
19945
|
+
mode: z77.literal("guided"),
|
|
18894
19946
|
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. "problem_solution" requiere 30s.'),
|
|
18895
|
-
buyerPersona:
|
|
19947
|
+
buyerPersona: z77.string().trim().min(1).max(360),
|
|
18896
19948
|
presenter: VideoPresenter,
|
|
18897
|
-
creativeDirection:
|
|
19949
|
+
creativeDirection: z77.string().trim().min(1).max(500).nullable().describe("Direcci\xF3n visual elegida. null significa que el usuario deleg\xF3 expl\xEDcitamente esta decisi\xF3n.")
|
|
18898
19950
|
}).strict()
|
|
18899
19951
|
]);
|
|
18900
|
-
var VideoInput =
|
|
19952
|
+
var VideoInput = z77.object({
|
|
18901
19953
|
images: CreativeRefs.images.optional(),
|
|
18902
19954
|
winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
|
|
18903
|
-
title:
|
|
18904
|
-
primaryAngle:
|
|
19955
|
+
title: z77.string().min(1).describe('T\xEDtulo corto del producto. Aparece en la primera vista del video. Ej. "Crema Anti-Edad Premium".'),
|
|
19956
|
+
primaryAngle: z77.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".'),
|
|
18905
19957
|
language: CreativeRefs.language,
|
|
18906
19958
|
country: CreativeRefs.country,
|
|
18907
|
-
aspectRatio:
|
|
19959
|
+
aspectRatio: z77.enum([
|
|
18908
19960
|
"9:16",
|
|
18909
19961
|
"16:9",
|
|
18910
19962
|
"Auto"
|
|
18911
19963
|
]).describe('Relaci\xF3n de aspecto. "9:16" = vertical (TikTok/Reels \u2014 default recomendado para ads). "16:9" = horizontal (YouTube). "Auto" = decide la IA.'),
|
|
18912
|
-
durationSeconds:
|
|
18913
|
-
videoAngleCount:
|
|
19964
|
+
durationSeconds: z77.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."),
|
|
19965
|
+
videoAngleCount: z77.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."),
|
|
18914
19966
|
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.'),
|
|
18915
19967
|
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."),
|
|
18916
19968
|
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.'),
|
|
18917
19969
|
videoQuality: VideoQualityEnum.default("economy").describe('Opcional. Calidad: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro. El sistema elige el proveedor internamente. Default: economy.'),
|
|
18918
19970
|
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.'),
|
|
18919
|
-
features:
|
|
19971
|
+
features: z77.array(z77.string()).optional().describe('Opcional. Lista de features/beneficios clave a mencionar. Ej. ["resistente al agua", "bater\xEDa 24h", "carga inal\xE1mbrica"].'),
|
|
18920
19972
|
price: CreativeRefs.price,
|
|
18921
19973
|
offer: CreativeRefs.offer,
|
|
18922
19974
|
productContext: CreativeRefs.productContext,
|
|
18923
19975
|
productLabel: CreativeRefs.productLabel,
|
|
18924
|
-
cta:
|
|
18925
|
-
scriptNotes:
|
|
19976
|
+
cta: z77.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.'),
|
|
19977
|
+
scriptNotes: z77.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.'),
|
|
18926
19978
|
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.'),
|
|
18927
19979
|
competitorScanEnabled: CreativeRefs.competitorScanEnabled,
|
|
18928
|
-
replicateWinnerWhenFound:
|
|
19980
|
+
replicateWinnerWhenFound: z77.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."),
|
|
18929
19981
|
brandId: CreativeRefs.brandId
|
|
18930
19982
|
}).strict();
|
|
18931
19983
|
var FreeVideoQualityEnum = VideoQualityEnum;
|
|
@@ -18943,7 +19995,7 @@ var FREE_VIDEO_DURATIONS_BY_QUALITY = {
|
|
|
18943
19995
|
length: 29
|
|
18944
19996
|
}, (_, index) => index + 2)
|
|
18945
19997
|
};
|
|
18946
|
-
var FreeVideoModelIdEnum =
|
|
19998
|
+
var FreeVideoModelIdEnum = z77.enum([
|
|
18947
19999
|
"grok-imagine-video-1-5-preview",
|
|
18948
20000
|
"minimax-h3/reference-to-video",
|
|
18949
20001
|
"wan/3-0-video",
|
|
@@ -18954,70 +20006,65 @@ var FREE_SELECTABLE_MODEL_IDS = [
|
|
|
18954
20006
|
"minimax-h3/reference-to-video",
|
|
18955
20007
|
"wan/3-0-video"
|
|
18956
20008
|
];
|
|
18957
|
-
var FreeVideoInput =
|
|
20009
|
+
var FreeVideoInput = z77.object({
|
|
18958
20010
|
images: ImagesInput.optional().describe("Opcional. 1-5 fotos del producto. Om\xEDtelo para generar desde texto puro."),
|
|
18959
|
-
rawPrompt:
|
|
20011
|
+
rawPrompt: z77.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."),
|
|
18960
20012
|
language: CreativeRefs.language,
|
|
18961
20013
|
quality: FreeVideoQualityEnum.describe('Calidad del video: "economy" = Econ\xF3mico, "medium" = Medio o "pro" = Pro (Wan).'),
|
|
18962
20014
|
// Retired in MCP 7.0.0 (Task 11): kept in the schema, accepted, and
|
|
18963
20015
|
// parsed ONLY so the handler can reject it with a message naming its
|
|
18964
20016
|
// replacement — dropping it silently would turn a caller's explicit
|
|
18965
20017
|
// Pro++ pick into a quiet fallback to Wan.
|
|
18966
|
-
freeProModel:
|
|
20018
|
+
freeProModel: z77.enum([
|
|
18967
20019
|
"wan",
|
|
18968
20020
|
"seedance"
|
|
18969
20021
|
]).optional().describe("ELIMINADO en MCP 7.0.0 \u2014 usa `modelId`. Enviar este campo produce un error."),
|
|
18970
20022
|
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.'),
|
|
18971
|
-
durationSeconds:
|
|
20023
|
+
durationSeconds: z77.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."),
|
|
18972
20024
|
videoResolution: VideoResolutionEnum.describe("Resoluci\xF3n del video: 480p o 720p."),
|
|
18973
|
-
generateAiMusic:
|
|
18974
|
-
addSubtitles:
|
|
18975
|
-
idempotencyKey:
|
|
20025
|
+
generateAiMusic: z77.boolean().default(false).describe("Opcional. Agrega m\xFAsica instrumental IA debajo del audio nativo. Default false."),
|
|
20026
|
+
addSubtitles: z77.boolean().default(false).describe("Opcional. Quema subt\xEDtulos usando el rawPrompt exacto. Default false."),
|
|
20027
|
+
idempotencyKey: z77.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.")
|
|
18976
20028
|
}).strict();
|
|
18977
20029
|
var imageStyleList = ImageCreativeStyleEnum.options.join(" | ");
|
|
18978
|
-
var ImageCreativeSetup =
|
|
18979
|
-
|
|
18980
|
-
mode:
|
|
20030
|
+
var ImageCreativeSetup = z77.discriminatedUnion("mode", [
|
|
20031
|
+
z77.object({
|
|
20032
|
+
mode: z77.literal("automatic")
|
|
18981
20033
|
}).strict(),
|
|
18982
|
-
|
|
18983
|
-
mode:
|
|
18984
|
-
creativeArchetype:
|
|
20034
|
+
z77.object({
|
|
20035
|
+
mode: z77.literal("guided"),
|
|
20036
|
+
creativeArchetype: z77.union([
|
|
18985
20037
|
ImageCreativeArchetypeEnum,
|
|
18986
|
-
|
|
20038
|
+
z77.literal("ai_decides")
|
|
18987
20039
|
]),
|
|
18988
|
-
visualTreatment:
|
|
20040
|
+
visualTreatment: z77.union([
|
|
18989
20041
|
ImageCreativeVisualTreatmentEnum,
|
|
18990
|
-
|
|
20042
|
+
z77.literal("ai_decides")
|
|
18991
20043
|
]),
|
|
18992
20044
|
aspectRatio: ImageCreativeAspectRatioEnum,
|
|
18993
|
-
nVariants:
|
|
18994
|
-
|
|
18995
|
-
|
|
18996
|
-
|
|
18997
|
-
|
|
18998
|
-
|
|
18999
|
-
]),
|
|
19000
|
-
imageModel: z73.enum([
|
|
19001
|
-
"gpt-image-2-5:1k",
|
|
19002
|
-
"gpt-image-2-5:2k",
|
|
19003
|
-
"gpt-image-2:1k",
|
|
19004
|
-
"gpt-image-2:2k"
|
|
20045
|
+
nVariants: z77.union([
|
|
20046
|
+
z77.literal(1),
|
|
20047
|
+
z77.literal(2),
|
|
20048
|
+
z77.literal(3),
|
|
20049
|
+
z77.literal(4),
|
|
20050
|
+
z77.literal(6)
|
|
19005
20051
|
]),
|
|
19006
|
-
|
|
19007
|
-
|
|
19008
|
-
|
|
19009
|
-
|
|
19010
|
-
|
|
19011
|
-
|
|
19012
|
-
|
|
19013
|
-
|
|
20052
|
+
imageModel: z77.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.'),
|
|
20053
|
+
styleMix: z77.boolean().nullable().describe("Decisi\xF3n s\xF3lo para 2\u20134 variantes. Usa null para 1 o 6, cuando la UI no hace esta pregunta."),
|
|
20054
|
+
generateAdCopy: z77.boolean(),
|
|
20055
|
+
competitorScanEnabled: z77.boolean(),
|
|
20056
|
+
productContext: z77.string().trim().min(1).max(3e3).nullable(),
|
|
20057
|
+
creativeDirection: z77.string().trim().min(1).max(500).nullable(),
|
|
20058
|
+
brandColors: z77.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.'),
|
|
20059
|
+
headline: z77.string().trim().min(1).max(120).nullable(),
|
|
20060
|
+
subheadline: z77.string().trim().min(1).max(160).nullable()
|
|
19014
20061
|
}).strict()
|
|
19015
20062
|
]).superRefine((setup, context) => {
|
|
19016
20063
|
if (setup.mode !== "guided") return;
|
|
19017
20064
|
const needsStyleMix = setup.nVariants >= 2 && setup.nVariants <= 4;
|
|
19018
20065
|
if (needsStyleMix && setup.styleMix === null) {
|
|
19019
20066
|
context.addIssue({
|
|
19020
|
-
code:
|
|
20067
|
+
code: z77.ZodIssueCode.custom,
|
|
19021
20068
|
path: [
|
|
19022
20069
|
"styleMix"
|
|
19023
20070
|
],
|
|
@@ -19026,16 +20073,16 @@ var ImageCreativeSetup = z73.discriminatedUnion("mode", [
|
|
|
19026
20073
|
}
|
|
19027
20074
|
if (!needsStyleMix && setup.styleMix !== null) {
|
|
19028
20075
|
context.addIssue({
|
|
19029
|
-
code:
|
|
20076
|
+
code: z77.ZodIssueCode.custom,
|
|
19030
20077
|
path: [
|
|
19031
20078
|
"styleMix"
|
|
19032
20079
|
],
|
|
19033
20080
|
message: "styleMix debe ser null cuando nVariants es 1 o 6."
|
|
19034
20081
|
});
|
|
19035
20082
|
}
|
|
19036
|
-
if ((setup.imageModel === "
|
|
20083
|
+
if (imageResolutionOf(setup.imageModel) === "2k" && setup.aspectRatio === "4:5") {
|
|
19037
20084
|
context.addIssue({
|
|
19038
|
-
code:
|
|
20085
|
+
code: z77.ZodIssueCode.custom,
|
|
19039
20086
|
path: [
|
|
19040
20087
|
"aspectRatio"
|
|
19041
20088
|
],
|
|
@@ -19043,53 +20090,53 @@ var ImageCreativeSetup = z73.discriminatedUnion("mode", [
|
|
|
19043
20090
|
});
|
|
19044
20091
|
}
|
|
19045
20092
|
});
|
|
19046
|
-
var LandingCreativeSetup =
|
|
19047
|
-
|
|
19048
|
-
mode:
|
|
20093
|
+
var LandingCreativeSetup = z77.discriminatedUnion("mode", [
|
|
20094
|
+
z77.object({
|
|
20095
|
+
mode: z77.literal("automatic")
|
|
19049
20096
|
}).strict(),
|
|
19050
|
-
|
|
19051
|
-
mode:
|
|
20097
|
+
z77.object({
|
|
20098
|
+
mode: z77.literal("guided"),
|
|
19052
20099
|
landingStrategy: LandingStrategyEnum,
|
|
19053
20100
|
landingImageFormat: LandingImageFormatEnum,
|
|
19054
|
-
competitorScanEnabled:
|
|
19055
|
-
paymentMethods:
|
|
19056
|
-
productContext:
|
|
19057
|
-
creativeDirection:
|
|
19058
|
-
headline:
|
|
19059
|
-
subheadline:
|
|
20101
|
+
competitorScanEnabled: z77.boolean(),
|
|
20102
|
+
paymentMethods: z77.string().trim().min(1).max(240).nullable(),
|
|
20103
|
+
productContext: z77.string().trim().min(1).max(3e3).nullable(),
|
|
20104
|
+
creativeDirection: z77.string().trim().min(1).max(500).nullable(),
|
|
20105
|
+
headline: z77.string().trim().min(1).max(120).nullable(),
|
|
20106
|
+
subheadline: z77.string().trim().min(1).max(160).nullable()
|
|
19060
20107
|
}).strict()
|
|
19061
20108
|
]);
|
|
19062
|
-
var ImageInput =
|
|
20109
|
+
var ImageInput = z77.object({
|
|
19063
20110
|
images: CreativeRefs.images.optional(),
|
|
19064
20111
|
winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
|
|
19065
|
-
productTitle:
|
|
19066
|
-
primaryAngle:
|
|
20112
|
+
productTitle: z77.string().min(1).describe('Nombre del producto. Ej. "Crema Anti-Edad Premium".'),
|
|
20113
|
+
primaryAngle: z77.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.'),
|
|
19067
20114
|
buyerPersona: CreativeRefs.buyerPersona,
|
|
19068
20115
|
language: CreativeRefs.language,
|
|
19069
20116
|
country: CreativeRefs.country,
|
|
19070
20117
|
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."),
|
|
19071
20118
|
imageStyle: ImageCreativeStyleEnum.optional().describe(`Opcional. Estilo del shot del producto. Valores: ${imageStyleList}. Si se omite, la IA escoge seg\xFAn el archetype.`),
|
|
19072
|
-
features:
|
|
20119
|
+
features: z77.array(z77.string()).optional().describe('Opcional. Features/beneficios a destacar visualmente. Ej. ["resistente al agua", "ultra liviano"].'),
|
|
19073
20120
|
price: CreativeRefs.price,
|
|
19074
|
-
omitPrice:
|
|
20121
|
+
omitPrice: z77.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."),
|
|
19075
20122
|
compareAtPrice: CreativeRefs.compareAtPrice,
|
|
19076
20123
|
offer: CreativeRefs.offer,
|
|
19077
20124
|
productLabel: CreativeRefs.productLabel,
|
|
19078
20125
|
isCombo: CreativeRefs.isCombo,
|
|
19079
20126
|
brandId: CreativeRefs.brandId
|
|
19080
20127
|
});
|
|
19081
|
-
var EditImageCreativeInput =
|
|
19082
|
-
taskId:
|
|
19083
|
-
variantIndex:
|
|
19084
|
-
instruction:
|
|
20128
|
+
var EditImageCreativeInput = z77.object({
|
|
20129
|
+
taskId: z77.string().uuid().describe("ID de la tarea de imagen ya finalizada."),
|
|
20130
|
+
variantIndex: z77.number().int().min(0).max(10).describe("\xCDndice de la variante a corregir (0 = primera imagen)."),
|
|
20131
|
+
instruction: z77.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".')
|
|
19085
20132
|
});
|
|
19086
|
-
var LandingInput =
|
|
20133
|
+
var LandingInput = z77.object({
|
|
19087
20134
|
images: CreativeRefs.images.optional(),
|
|
19088
20135
|
winnerReference: WinnerReferenceInput.optional().describe(WINNER_IMAGE_CHOICE_GUIDANCE),
|
|
19089
20136
|
language: CreativeRefs.language,
|
|
19090
20137
|
country: CreativeRefs.country,
|
|
19091
20138
|
creativeSetup: LandingCreativeSetup.describe("Configuraci\xF3n obligatoria de landing cl\xE1sica equivalente al wizard web. No expone landing editable/code mientras siga siendo admin-only."),
|
|
19092
|
-
salesAngle:
|
|
20139
|
+
salesAngle: z77.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.'),
|
|
19093
20140
|
buyerPersona: CreativeRefs.buyerPersona,
|
|
19094
20141
|
price: CreativeRefs.price,
|
|
19095
20142
|
compareAtPrice: CreativeRefs.compareAtPrice,
|
|
@@ -19108,7 +20155,7 @@ function resolveImageSetup(setup) {
|
|
|
19108
20155
|
},
|
|
19109
20156
|
aspectRatio: setup.aspectRatio,
|
|
19110
20157
|
nVariants: setup.nVariants,
|
|
19111
|
-
imageModel: setup.imageModel,
|
|
20158
|
+
imageModel: canonicalImageModelInput(setup.imageModel),
|
|
19112
20159
|
...setup.nVariants === 6 ? {
|
|
19113
20160
|
styleMix: true
|
|
19114
20161
|
} : setup.styleMix === null ? {} : {
|
|
@@ -19199,7 +20246,16 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
|
|
|
19199
20246
|
addSubtitles: input.addSubtitles
|
|
19200
20247
|
},
|
|
19201
20248
|
allowEmptyImages: true,
|
|
19202
|
-
|
|
20249
|
+
// Always derived — never `input.idempotencyKey ??`: a host that
|
|
20250
|
+
// mints a fresh UUID per retry would defeat the dedupe entirely.
|
|
20251
|
+
// The semantic key is also a strictly better retry identity: a
|
|
20252
|
+
// reused caller key still lands on it (see request-key.ts).
|
|
20253
|
+
idempotencyKey: derivePaidRequestKey({
|
|
20254
|
+
fingerprint: api.fingerprint(),
|
|
20255
|
+
tool: "generate_free_video",
|
|
20256
|
+
input,
|
|
20257
|
+
nowMs: Date.now()
|
|
20258
|
+
}),
|
|
19203
20259
|
transport
|
|
19204
20260
|
});
|
|
19205
20261
|
} catch (e) {
|
|
@@ -19264,6 +20320,12 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
|
|
|
19264
20320
|
path: "/v1/creatives/videos",
|
|
19265
20321
|
estimatedSeconds: 300,
|
|
19266
20322
|
input: wirePayload,
|
|
20323
|
+
idempotencyKey: derivePaidRequestKey({
|
|
20324
|
+
fingerprint: api.fingerprint(),
|
|
20325
|
+
tool: "generate_video_creative",
|
|
20326
|
+
input,
|
|
20327
|
+
nowMs: Date.now()
|
|
20328
|
+
}),
|
|
19267
20329
|
transport
|
|
19268
20330
|
});
|
|
19269
20331
|
} catch (e) {
|
|
@@ -19298,6 +20360,12 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
|
|
|
19298
20360
|
pauseForAngleReview: true
|
|
19299
20361
|
}
|
|
19300
20362
|
},
|
|
20363
|
+
idempotencyKey: derivePaidRequestKey({
|
|
20364
|
+
fingerprint: api.fingerprint(),
|
|
20365
|
+
tool: "generate_image_creatives",
|
|
20366
|
+
input,
|
|
20367
|
+
nowMs: Date.now()
|
|
20368
|
+
}),
|
|
19301
20369
|
transport
|
|
19302
20370
|
});
|
|
19303
20371
|
} catch (e) {
|
|
@@ -19341,6 +20409,12 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
|
|
|
19341
20409
|
pauseForAngleReview: true
|
|
19342
20410
|
}
|
|
19343
20411
|
},
|
|
20412
|
+
idempotencyKey: derivePaidRequestKey({
|
|
20413
|
+
fingerprint: api.fingerprint(),
|
|
20414
|
+
tool: "generate_landing",
|
|
20415
|
+
input,
|
|
20416
|
+
nowMs: Date.now()
|
|
20417
|
+
}),
|
|
19344
20418
|
transport
|
|
19345
20419
|
});
|
|
19346
20420
|
} catch (e) {
|
|
@@ -19351,10 +20425,10 @@ function registerCreativeTools(server, api, { transport = "http" } = {}) {
|
|
|
19351
20425
|
__name(registerCreativeTools, "registerCreativeTools");
|
|
19352
20426
|
|
|
19353
20427
|
// src/tools/creative-variants.ts
|
|
19354
|
-
import { z as
|
|
20428
|
+
import { z as z78 } from "zod";
|
|
19355
20429
|
var estimateCreativeVariantGuidance = getProductMakerCapabilityModelGuidance("estimate_creative_variant");
|
|
19356
20430
|
var createCreativeVariantGuidance = getProductMakerCapabilityModelGuidance("create_creative_variant");
|
|
19357
|
-
var LandingSectionKeyEnum =
|
|
20431
|
+
var LandingSectionKeyEnum = z78.enum([
|
|
19358
20432
|
"problem_hook",
|
|
19359
20433
|
"problem_cost",
|
|
19360
20434
|
"solution_mechanism",
|
|
@@ -19394,24 +20468,24 @@ var LandingSectionKeyEnum = z74.enum([
|
|
|
19394
20468
|
"lifestyle_fit",
|
|
19395
20469
|
"join_lifestyle"
|
|
19396
20470
|
]);
|
|
19397
|
-
var CreativeVariantKindEnum =
|
|
20471
|
+
var CreativeVariantKindEnum = z78.enum([
|
|
19398
20472
|
"video",
|
|
19399
20473
|
"image",
|
|
19400
20474
|
"landing"
|
|
19401
20475
|
]);
|
|
19402
|
-
var EstimateCreativeVariantInputBase =
|
|
19403
|
-
sourceTaskId:
|
|
20476
|
+
var EstimateCreativeVariantInputBase = z78.object({
|
|
20477
|
+
sourceTaskId: z78.string().uuid().describe("ID de la tarea original completada."),
|
|
19404
20478
|
kind: CreativeVariantKindEnum,
|
|
19405
20479
|
videoPreset: TaskCreativeVariantVideoPresetEnum.optional().describe("Opcional para video. Solo cambia el preset p\xFAblico; el servidor conserva el modelo/tier del task origen."),
|
|
19406
20480
|
videoResolution: VideoResolutionEnum.optional().describe("Opcional para video. Resoluci\xF3n del nuevo render."),
|
|
19407
|
-
nVariants:
|
|
20481
|
+
nVariants: z78.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
|
|
19408
20482
|
sectionKey: LandingSectionKeyEnum.optional().describe("Opcional para landing. Si ya conoces la secci\xF3n, evita cotizar la clasificaci\xF3n con IA."),
|
|
19409
|
-
instructions:
|
|
20483
|
+
instructions: z78.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.")
|
|
19410
20484
|
}).strict();
|
|
19411
20485
|
var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine((input, ctx) => {
|
|
19412
20486
|
if (input.kind === "video" && input.nVariants !== void 0) {
|
|
19413
20487
|
ctx.addIssue({
|
|
19414
|
-
code:
|
|
20488
|
+
code: z78.ZodIssueCode.custom,
|
|
19415
20489
|
path: [
|
|
19416
20490
|
"nVariants"
|
|
19417
20491
|
],
|
|
@@ -19421,7 +20495,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
|
|
|
19421
20495
|
if (input.kind !== "video") {
|
|
19422
20496
|
if (input.videoPreset !== void 0) {
|
|
19423
20497
|
ctx.addIssue({
|
|
19424
|
-
code:
|
|
20498
|
+
code: z78.ZodIssueCode.custom,
|
|
19425
20499
|
path: [
|
|
19426
20500
|
"videoPreset"
|
|
19427
20501
|
],
|
|
@@ -19430,7 +20504,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
|
|
|
19430
20504
|
}
|
|
19431
20505
|
if (input.videoResolution !== void 0) {
|
|
19432
20506
|
ctx.addIssue({
|
|
19433
|
-
code:
|
|
20507
|
+
code: z78.ZodIssueCode.custom,
|
|
19434
20508
|
path: [
|
|
19435
20509
|
"videoResolution"
|
|
19436
20510
|
],
|
|
@@ -19440,7 +20514,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
|
|
|
19440
20514
|
}
|
|
19441
20515
|
if (input.kind !== "image" && input.nVariants !== void 0) {
|
|
19442
20516
|
ctx.addIssue({
|
|
19443
|
-
code:
|
|
20517
|
+
code: z78.ZodIssueCode.custom,
|
|
19444
20518
|
path: [
|
|
19445
20519
|
"nVariants"
|
|
19446
20520
|
],
|
|
@@ -19450,7 +20524,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
|
|
|
19450
20524
|
if (input.kind !== "landing") {
|
|
19451
20525
|
if (input.sectionKey !== void 0) {
|
|
19452
20526
|
ctx.addIssue({
|
|
19453
|
-
code:
|
|
20527
|
+
code: z78.ZodIssueCode.custom,
|
|
19454
20528
|
path: [
|
|
19455
20529
|
"sectionKey"
|
|
19456
20530
|
],
|
|
@@ -19459,7 +20533,7 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
|
|
|
19459
20533
|
}
|
|
19460
20534
|
if (input.instructions !== void 0) {
|
|
19461
20535
|
ctx.addIssue({
|
|
19462
|
-
code:
|
|
20536
|
+
code: z78.ZodIssueCode.custom,
|
|
19463
20537
|
path: [
|
|
19464
20538
|
"instructions"
|
|
19465
20539
|
],
|
|
@@ -19468,31 +20542,31 @@ var EstimateCreativeVariantInput = EstimateCreativeVariantInputBase.superRefine(
|
|
|
19468
20542
|
}
|
|
19469
20543
|
}
|
|
19470
20544
|
});
|
|
19471
|
-
var CreateCreativeVariantInputBase =
|
|
19472
|
-
sourceTaskId:
|
|
20545
|
+
var CreateCreativeVariantInputBase = z78.object({
|
|
20546
|
+
sourceTaskId: z78.string().uuid().describe("ID de la tarea original completada."),
|
|
19473
20547
|
kind: CreativeVariantKindEnum,
|
|
19474
|
-
confirm:
|
|
19475
|
-
clientRequestId:
|
|
19476
|
-
angle:
|
|
19477
|
-
buyerPersona:
|
|
19478
|
-
scriptNotes:
|
|
19479
|
-
creativeDirection:
|
|
20548
|
+
confirm: z78.literal(true).describe("Confirmaci\xF3n expl\xEDcita del usuario despu\xE9s de mostrarle el estimado de cr\xE9ditos."),
|
|
20549
|
+
clientRequestId: z78.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."),
|
|
20550
|
+
angle: z78.string().trim().min(1).max(500).optional().describe("\xC1ngulo nuevo para video o imagen."),
|
|
20551
|
+
buyerPersona: z78.string().trim().min(1).max(360).optional().describe("Buyer persona coherente con el \xE1ngulo."),
|
|
20552
|
+
scriptNotes: z78.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n breve del guion para una variante de video."),
|
|
20553
|
+
creativeDirection: z78.string().trim().min(1).max(2e3).optional().describe("Direcci\xF3n creativa para una variante de imagen."),
|
|
19480
20554
|
videoPreset: TaskCreativeVariantVideoPresetEnum.optional().describe("Opcional para video. Preset p\xFAblico; el servidor resuelve modelo/tier desde el task origen."),
|
|
19481
20555
|
videoResolution: VideoResolutionEnum.optional().describe("Opcional para video."),
|
|
19482
|
-
generateAiMusic:
|
|
19483
|
-
nVariants:
|
|
20556
|
+
generateAiMusic: z78.boolean().optional().describe("Opcional para video."),
|
|
20557
|
+
nVariants: z78.number().int().min(1).max(3).optional().describe("Opcional para imagen. N\xFAmero de im\xE1genes adicionales (1-3)."),
|
|
19484
20558
|
imageStyle: ImageCreativeStyleEnum.optional().describe("Opcional para imagen."),
|
|
19485
20559
|
creativeArchetype: ImageCreativeArchetypeEnum.optional().describe("Opcional para imagen."),
|
|
19486
20560
|
visualTreatment: ImageCreativeVisualTreatmentEnum.optional().describe("Opcional para imagen."),
|
|
19487
20561
|
aspectRatio: ImageCreativeAspectRatioEnum.optional().describe("Opcional para imagen."),
|
|
19488
|
-
styleMix:
|
|
20562
|
+
styleMix: z78.boolean().optional().describe("Opcional para imagen."),
|
|
19489
20563
|
sectionKey: LandingSectionKeyEnum.optional().describe("Opcional para landing. Si se omite, se clasifica con IA a partir de instructions."),
|
|
19490
|
-
instructions:
|
|
20564
|
+
instructions: z78.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.")
|
|
19491
20565
|
}).strict();
|
|
19492
20566
|
var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((input, ctx) => {
|
|
19493
20567
|
if ((input.kind === "video" || input.kind === "image") && !input.angle) {
|
|
19494
20568
|
ctx.addIssue({
|
|
19495
|
-
code:
|
|
20569
|
+
code: z78.ZodIssueCode.custom,
|
|
19496
20570
|
path: [
|
|
19497
20571
|
"angle"
|
|
19498
20572
|
],
|
|
@@ -19501,7 +20575,7 @@ var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((inp
|
|
|
19501
20575
|
}
|
|
19502
20576
|
if (input.kind === "landing" && !input.sectionKey && !input.instructions) {
|
|
19503
20577
|
ctx.addIssue({
|
|
19504
|
-
code:
|
|
20578
|
+
code: z78.ZodIssueCode.custom,
|
|
19505
20579
|
path: [
|
|
19506
20580
|
"instructions"
|
|
19507
20581
|
],
|
|
@@ -19547,7 +20621,7 @@ var CreateCreativeVariantInput = CreateCreativeVariantInputBase.superRefine((inp
|
|
|
19547
20621
|
for (const field of fieldsByKind[input.kind]) {
|
|
19548
20622
|
if (input[field] !== void 0) {
|
|
19549
20623
|
ctx.addIssue({
|
|
19550
|
-
code:
|
|
20624
|
+
code: z78.ZodIssueCode.custom,
|
|
19551
20625
|
path: [
|
|
19552
20626
|
field
|
|
19553
20627
|
],
|
|
@@ -19594,7 +20668,7 @@ function registerCreativeVariantTools(server, api) {
|
|
|
19594
20668
|
throw translateError(error);
|
|
19595
20669
|
}
|
|
19596
20670
|
});
|
|
19597
|
-
server.tool("create_creative_variant", createCreativeVariantGuidance.summary + " ES UNA ACCI\xD3N DE PAGO: primero llama estimate_creative_variant, muestra el rango de cr\xE9ditos al usuario y solo despu\xE9s invoca este tool con confirm=true. Las recomendaciones IA tambi\xE9n son acciones pagas a 2x del costo real. clientRequestId es obligatorio: genera un UUID por intenci\xF3n
|
|
20671
|
+
server.tool("create_creative_variant", createCreativeVariantGuidance.summary + " ES UNA ACCI\xD3N DE PAGO: primero llama estimate_creative_variant, muestra el rango de cr\xE9ditos al usuario y solo despu\xE9s invoca este tool con confirm=true. Las recomendaciones IA tambi\xE9n son acciones pagas a 2x del costo real. clientRequestId es obligatorio por contrato: genera un UUID por intenci\xF3n. El servidor deriva la identidad real del request desde los argumentos sem\xE1nticos, as\xED que un UUID nuevo NO desbloquea un intento distinto \u2014 si recibes status=error, pide confirmaci\xF3n al usuario y reinvoca con los mismos argumentos. Reutiliza el producto y referencias del task origen; crea un child task independiente y devuelve variantTaskId. Para landing puedes enviar instructions en texto libre y omitir sectionKey: el backend lo clasifica con IA. No expone ni permite cambiar videoModel, videoTier, videoStyle o narrativeStyle; esos valores se heredan del task origen.", CreateCreativeVariantInputBase.shape, CREATES_PAID, async (input) => {
|
|
19598
20672
|
try {
|
|
19599
20673
|
const validatedInput = parseVariantInput(CreateCreativeVariantInput, input);
|
|
19600
20674
|
const estimateInput = EstimateCreativeVariantInput.parse({
|
|
@@ -19621,8 +20695,16 @@ function registerCreativeVariantTools(server, api) {
|
|
|
19621
20695
|
});
|
|
19622
20696
|
sectionKey = LandingSectionKeyEnum.parse(recommendation.value);
|
|
19623
20697
|
}
|
|
20698
|
+
const derivedClientRequestId = derivePaidRequestKey({
|
|
20699
|
+
fingerprint: api.fingerprint(),
|
|
20700
|
+
tool: "create_creative_variant",
|
|
20701
|
+
input: {
|
|
20702
|
+
...validatedInput
|
|
20703
|
+
},
|
|
20704
|
+
nowMs: Date.now()
|
|
20705
|
+
});
|
|
19624
20706
|
const payload = {
|
|
19625
|
-
clientRequestId:
|
|
20707
|
+
clientRequestId: derivedClientRequestId,
|
|
19626
20708
|
kind: validatedInput.kind,
|
|
19627
20709
|
...validatedInput.kind !== "landing" ? {
|
|
19628
20710
|
angle: validatedInput.angle,
|
|
@@ -19648,7 +20730,7 @@ function registerCreativeVariantTools(server, api) {
|
|
|
19648
20730
|
};
|
|
19649
20731
|
const created = await api.postJson(`/v1/tasks/${encodeURIComponent(validatedInput.sourceTaskId)}/creative-variants`, payload);
|
|
19650
20732
|
if (created.status === "error") {
|
|
19651
|
-
throw mcp(McpErrorCode.CREATIVE_VARIANT_FAILED, "La variante anterior termin\xF3 con error. Pide confirmaci\xF3n para un intento nuevo
|
|
20733
|
+
throw mcp(McpErrorCode.CREATIVE_VARIANT_FAILED, "La variante anterior termin\xF3 con error. Pide confirmaci\xF3n al usuario y reinvoca con los mismos argumentos para un intento nuevo.", {
|
|
19652
20734
|
variantTaskId: created.variantTaskId
|
|
19653
20735
|
});
|
|
19654
20736
|
}
|
|
@@ -19664,32 +20746,32 @@ function registerCreativeVariantTools(server, api) {
|
|
|
19664
20746
|
__name(registerCreativeVariantTools, "registerCreativeVariantTools");
|
|
19665
20747
|
|
|
19666
20748
|
// src/tools/script-review.ts
|
|
19667
|
-
import { z as
|
|
20749
|
+
import { z as z79 } from "zod";
|
|
19668
20750
|
var getVideoScriptGuidance = getProductMakerCapabilityModelGuidance("get_video_script");
|
|
19669
20751
|
var regenerateVideoScriptGuidance = getProductMakerCapabilityModelGuidance("regenerate_video_script");
|
|
19670
20752
|
var approveVideoScriptGuidance = getProductMakerCapabilityModelGuidance("approve_video_script");
|
|
19671
|
-
var GetVideoScriptInput =
|
|
19672
|
-
taskId:
|
|
19673
|
-
angleKey:
|
|
20753
|
+
var GetVideoScriptInput = z79.object({
|
|
20754
|
+
taskId: z79.string().min(1).describe("ID de la tarea (la misma que devolvi\xF3 create_product_task / generate_video_creative)."),
|
|
20755
|
+
angleKey: z79.string().min(1).optional().describe('Clave del \xE1ngulo cuyo guion se quiere leer (formato "angle_0", "angle_1", ...). REQUERIDO para tareas multi-angle: si se omite, el backend resuelve a "angle_0" LITERAL (no "el primer pendiente"), as\xED que en multi-angle donde angle_0 ya est\xE9 aprobado/saltado obtendr\xEDas status="approved" y nunca alcanzar\xEDas el \xE1ngulo realmente pendiente. Para single-angle puede omitirse.')
|
|
19674
20756
|
}).strict();
|
|
19675
20757
|
var VIDEO_SCRIPT_APPROVAL_MAX_SCENES2 = 50;
|
|
19676
20758
|
var VIDEO_SCRIPT_APPROVAL_MAX_DIALOGUE_CHARS2 = 2e3;
|
|
19677
|
-
var ApproveSceneEdit =
|
|
19678
|
-
index:
|
|
19679
|
-
dialogue:
|
|
20759
|
+
var ApproveSceneEdit = z79.object({
|
|
20760
|
+
index: z79.number().int().nonnegative().describe("\xCDndice de la escena (0-based, mismo que devuelve get_video_script)."),
|
|
20761
|
+
dialogue: z79.string().min(1).max(VIDEO_SCRIPT_APPROVAL_MAX_DIALOGUE_CHARS2).refine((v) => v.trim().length > 0, {
|
|
19680
20762
|
message: "dialogue no puede ser s\xF3lo espacios"
|
|
19681
20763
|
}).describe("Di\xE1logo final de la escena. NO puede estar vac\xEDo ni ser s\xF3lo espacios. Puede ser el original sin cambios o la edici\xF3n del usuario.")
|
|
19682
20764
|
}).strict();
|
|
19683
|
-
var ApproveVideoScriptInput =
|
|
19684
|
-
taskId:
|
|
19685
|
-
angleKey:
|
|
19686
|
-
scenes:
|
|
20765
|
+
var ApproveVideoScriptInput = z79.object({
|
|
20766
|
+
taskId: z79.string().min(1).describe("ID de la tarea."),
|
|
20767
|
+
angleKey: z79.string().trim().min(1).max(120).optional().describe('Mismo angleKey usado en get_video_script. REQUERIDO en multi-angle (si se omite el backend resuelve a "angle_0" literal). En single-angle puede omitirse.'),
|
|
20768
|
+
scenes: z79.array(ApproveSceneEdit).min(1).max(VIDEO_SCRIPT_APPROVAL_MAX_SCENES2).describe("Escenas con los di\xE1logos finales. El backend mergea por `index` \u2014 las escenas NO incluidas conservan el di\xE1logo original. Debe haber entre 1 y 50 entradas. Para cada entrada que mandes con un dialogue distinto del original, el backend valida minWords \u2264 words \u2264 maxWords y rechaza con 400 si te sales del rango.")
|
|
19687
20769
|
}).strict();
|
|
19688
|
-
var RegenerateVideoScriptInput =
|
|
19689
|
-
taskId:
|
|
19690
|
-
angleKey:
|
|
20770
|
+
var RegenerateVideoScriptInput = z79.object({
|
|
20771
|
+
taskId: z79.string().min(1).describe("ID de la tarea."),
|
|
20772
|
+
angleKey: z79.string().min(1).describe('Clave del \xE1ngulo a regenerar. Single-angle: pasa "angle_0". Multi-angle: el mismo que devuelve get_video_script. NO se puede omitir \u2014 el backend lo exige siempre.'),
|
|
19691
20773
|
narrativeStyle: NarrativeStyleEnum.describe('Narrativa para el nuevo guion. Incluye valores hist\xF3ricos porque esta herramienta tambi\xE9n regenera tareas antiguas. REQUERIDO \u2014 el backend NO acepta "mantener la actual"; siempre tienes que elegir una. Si el usuario quiere re-rolear con la misma narrativa, pasa la que ya tiene el \xE1ngulo (la ves en get_video_script o en get_task_status).'),
|
|
19692
|
-
narrativeSelection:
|
|
20774
|
+
narrativeSelection: z79.enum([
|
|
19693
20775
|
"market",
|
|
19694
20776
|
"guided"
|
|
19695
20777
|
]).optional().describe("Elecci\xF3n expl\xEDcita del usuario: market usa el estudio de mercado disponible; guided usa la narrativa elegida. Omitir conserva el comportamiento existente.")
|
|
@@ -19770,14 +20852,14 @@ function registerScriptReviewTools(server, api) {
|
|
|
19770
20852
|
__name(registerScriptReviewTools, "registerScriptReviewTools");
|
|
19771
20853
|
|
|
19772
20854
|
// src/tools/connections.ts
|
|
19773
|
-
import { z as
|
|
20855
|
+
import { z as z80 } from "zod";
|
|
19774
20856
|
var listShopifyShopsGuidance = getProductMakerCapabilityModelGuidance("list_shopify_shops");
|
|
19775
20857
|
var listShopifyProductsGuidance = getProductMakerCapabilityModelGuidance("list_shopify_products");
|
|
19776
20858
|
var listMetaAdAccountsGuidance = getProductMakerCapabilityModelGuidance("list_meta_ad_accounts");
|
|
19777
20859
|
var listMetaDestinationsGuidance = getProductMakerCapabilityModelGuidance("list_meta_destinations");
|
|
19778
20860
|
var listTikTokAdvertisersGuidance = getProductMakerCapabilityModelGuidance("list_tiktok_advertisers");
|
|
19779
20861
|
function registerConnectionTools(server, api) {
|
|
19780
|
-
server.tool("list_shopify_shops", listShopifyShopsGuidance.summary + " Si la lista est\xE1 vac\xEDa, dile al usuario que conecte una tienda en productmaker.app/integrations antes de intentar publicar.",
|
|
20862
|
+
server.tool("list_shopify_shops", listShopifyShopsGuidance.summary + " Si la lista est\xE1 vac\xEDa, dile al usuario que conecte una tienda en productmaker.app/integrations antes de intentar publicar.", z80.object({}).shape, READS_INTERNAL, async () => {
|
|
19781
20863
|
try {
|
|
19782
20864
|
const r = await api.getJson("/v1/shopify/shops");
|
|
19783
20865
|
return asText(r);
|
|
@@ -19785,10 +20867,10 @@ function registerConnectionTools(server, api) {
|
|
|
19785
20867
|
throw translateError(e);
|
|
19786
20868
|
}
|
|
19787
20869
|
});
|
|
19788
|
-
server.tool("list_shopify_products", 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.',
|
|
19789
|
-
shopDomain:
|
|
19790
|
-
query:
|
|
19791
|
-
taskId:
|
|
20870
|
+
server.tool("list_shopify_products", 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.', z80.object({
|
|
20871
|
+
shopDomain: z80.string().min(3).max(120),
|
|
20872
|
+
query: z80.string().trim().max(120).optional(),
|
|
20873
|
+
taskId: z80.string().uuid().optional()
|
|
19792
20874
|
}).shape, READS_EXTERNAL, async ({ shopDomain, query, taskId }) => {
|
|
19793
20875
|
try {
|
|
19794
20876
|
const params = new URLSearchParams({
|
|
@@ -19802,7 +20884,7 @@ function registerConnectionTools(server, api) {
|
|
|
19802
20884
|
throw translateError(e);
|
|
19803
20885
|
}
|
|
19804
20886
|
});
|
|
19805
|
-
server.tool("list_meta_ad_accounts", 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.",
|
|
20887
|
+
server.tool("list_meta_ad_accounts", 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.", z80.object({}).shape, READS_EXTERNAL, async () => {
|
|
19806
20888
|
try {
|
|
19807
20889
|
const r = await api.getJson("/v1/facebook/ad-accounts");
|
|
19808
20890
|
return asText(r);
|
|
@@ -19812,7 +20894,7 @@ function registerConnectionTools(server, api) {
|
|
|
19812
20894
|
});
|
|
19813
20895
|
server.registerTool("list_meta_destinations", {
|
|
19814
20896
|
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.",
|
|
19815
|
-
inputSchema:
|
|
20897
|
+
inputSchema: z80.object({}).shape,
|
|
19816
20898
|
annotations: READS_EXTERNAL,
|
|
19817
20899
|
_meta: {
|
|
19818
20900
|
"openai/widgetAccessible": true
|
|
@@ -19825,7 +20907,7 @@ function registerConnectionTools(server, api) {
|
|
|
19825
20907
|
throw translateError(e);
|
|
19826
20908
|
}
|
|
19827
20909
|
});
|
|
19828
|
-
server.tool("list_tiktok_advertisers", listTikTokAdvertisersGuidance.summary + " Si est\xE1 vac\xEDa, ind\xEDcale al usuario conectar TikTok en productmaker.app/integrations.",
|
|
20910
|
+
server.tool("list_tiktok_advertisers", listTikTokAdvertisersGuidance.summary + " Si est\xE1 vac\xEDa, ind\xEDcale al usuario conectar TikTok en productmaker.app/integrations.", z80.object({}).shape, READS_EXTERNAL, async () => {
|
|
19829
20911
|
try {
|
|
19830
20912
|
const r = await api.getJson("/v1/tiktok/advertisers");
|
|
19831
20913
|
return asText(r);
|
|
@@ -19837,10 +20919,10 @@ function registerConnectionTools(server, api) {
|
|
|
19837
20919
|
__name(registerConnectionTools, "registerConnectionTools");
|
|
19838
20920
|
|
|
19839
20921
|
// src/tools/actors.ts
|
|
19840
|
-
import { z as
|
|
20922
|
+
import { z as z81 } from "zod";
|
|
19841
20923
|
var listActorsGuidance = getProductMakerCapabilityModelGuidance("list_actors");
|
|
19842
20924
|
function registerActorTools(server, api) {
|
|
19843
|
-
server.tool("list_actors", listActorsGuidance.summary + " Devuelve id, nombre, descripci\xF3n, g\xE9nero y voz. Usa el `id` como `actorId` al crear o editar una tarea. Solo aparecen los personajes listos para usar; si la lista est\xE1 vac\xEDa, dile al usuario que cree uno en productmaker.app antes de intentar asignarlo. No modifica nada.",
|
|
20925
|
+
server.tool("list_actors", listActorsGuidance.summary + " Devuelve id, nombre, descripci\xF3n, g\xE9nero y voz. Usa el `id` como `actorId` al crear o editar una tarea. Solo aparecen los personajes listos para usar; si la lista est\xE1 vac\xEDa, dile al usuario que cree uno en productmaker.app antes de intentar asignarlo. No modifica nada.", z81.object({}).shape, READS_INTERNAL, async () => {
|
|
19844
20926
|
try {
|
|
19845
20927
|
const rows = await api.getJson("/v1/actors");
|
|
19846
20928
|
const actors = (Array.isArray(rows) ? rows : []).filter((actor) => actor.status === "ready").map(({ id, name, description, gender, voiceId }) => ({
|
|
@@ -19861,40 +20943,7 @@ function registerActorTools(server, api) {
|
|
|
19861
20943
|
__name(registerActorTools, "registerActorTools");
|
|
19862
20944
|
|
|
19863
20945
|
// src/tools/publish.ts
|
|
19864
|
-
import { z as
|
|
19865
|
-
|
|
19866
|
-
// src/tools/stable-uuid.ts
|
|
19867
|
-
import { createHash as createHash2 } from "crypto";
|
|
19868
|
-
function canonicalize(value) {
|
|
19869
|
-
if (Array.isArray(value)) return value.map(canonicalize);
|
|
19870
|
-
if (value === null || typeof value !== "object") return value;
|
|
19871
|
-
const record = value;
|
|
19872
|
-
return Object.fromEntries(Object.keys(record).sort().filter((key) => record[key] !== void 0).map((key) => [
|
|
19873
|
-
key,
|
|
19874
|
-
canonicalize(record[key])
|
|
19875
|
-
]));
|
|
19876
|
-
}
|
|
19877
|
-
__name(canonicalize, "canonicalize");
|
|
19878
|
-
function canonicalJson(value) {
|
|
19879
|
-
return JSON.stringify(canonicalize(value));
|
|
19880
|
-
}
|
|
19881
|
-
__name(canonicalJson, "canonicalJson");
|
|
19882
|
-
function deriveUuidV5(name, namespace) {
|
|
19883
|
-
const namespaceBytes = Buffer.from(namespace.replaceAll("-", ""), "hex");
|
|
19884
|
-
const digest = createHash2("sha1").update(namespaceBytes).update(name, "utf8").digest();
|
|
19885
|
-
const bytes = Buffer.from(digest.subarray(0, 16));
|
|
19886
|
-
bytes[6] = (bytes[6] ?? 0) & 15 | 80;
|
|
19887
|
-
bytes[8] = (bytes[8] ?? 0) & 63 | 128;
|
|
19888
|
-
const hex = bytes.toString("hex");
|
|
19889
|
-
return [
|
|
19890
|
-
hex.slice(0, 8),
|
|
19891
|
-
hex.slice(8, 12),
|
|
19892
|
-
hex.slice(12, 16),
|
|
19893
|
-
hex.slice(16, 20),
|
|
19894
|
-
hex.slice(20)
|
|
19895
|
-
].join("-");
|
|
19896
|
-
}
|
|
19897
|
-
__name(deriveUuidV5, "deriveUuidV5");
|
|
20946
|
+
import { z as z82 } from "zod";
|
|
19898
20947
|
|
|
19899
20948
|
// src/tools/meta-publish-attempt-id.ts
|
|
19900
20949
|
var META_PUBLISH_NAMESPACE = "7b19c9ac-b4eb-4db1-970e-c2f24ce30b98";
|
|
@@ -19933,40 +20982,40 @@ var publishToShopifyGuidance = getProductMakerCapabilityModelGuidance("publish_t
|
|
|
19933
20982
|
var publishToMetaGuidance = getProductMakerCapabilityModelGuidance("publish_to_meta");
|
|
19934
20983
|
var publishCreativesToMetaGuidance = getProductMakerCapabilityModelGuidance("publish_creatives_to_meta");
|
|
19935
20984
|
var publishToTikTokGuidance = getProductMakerCapabilityModelGuidance("publish_to_tiktok");
|
|
19936
|
-
var ShopifyInput =
|
|
19937
|
-
taskId:
|
|
19938
|
-
shopDomain:
|
|
20985
|
+
var ShopifyInput = z82.object({
|
|
20986
|
+
taskId: z82.string().min(1),
|
|
20987
|
+
shopDomain: z82.string().min(1),
|
|
19939
20988
|
/** Override: number of landing images to include. Default = ALL images the
|
|
19940
20989
|
* task generated (the MCP fetches /v1/results first to count). Bounded
|
|
19941
20990
|
* generously here; the backend validates each index against
|
|
19942
20991
|
* landing.images.length and rejects out-of-range. */
|
|
19943
|
-
numLandingImages:
|
|
19944
|
-
variantIndex:
|
|
20992
|
+
numLandingImages: z82.number().int().min(1).max(20).optional(),
|
|
20993
|
+
variantIndex: z82.number().int().min(0).optional(),
|
|
19945
20994
|
/** ASK THE USER before setting: "¿Tu producto tiene variantes (talla, color, etc.)?".
|
|
19946
20995
|
* When true, the landing renders variant-picker pills; when false, it ships
|
|
19947
20996
|
* a single-option product page. Defaults to false. */
|
|
19948
|
-
showVariantPicker:
|
|
20997
|
+
showVariantPicker: z82.boolean().optional(),
|
|
19949
20998
|
/** Default `auto` updates the product previously published for this task and
|
|
19950
20999
|
* shop. Use `existing` with targetProductId to choose another product, or
|
|
19951
21000
|
* `new` only when the user explicitly wants a duplicate/new listing. */
|
|
19952
|
-
publicationMode:
|
|
21001
|
+
publicationMode: z82.enum([
|
|
19953
21002
|
"auto",
|
|
19954
21003
|
"existing",
|
|
19955
21004
|
"new"
|
|
19956
21005
|
]).optional(),
|
|
19957
21006
|
/** Shopify product GID, numeric id, or admin product URL. Required when
|
|
19958
21007
|
* publicationMode is `existing`. */
|
|
19959
|
-
targetProductId:
|
|
21008
|
+
targetProductId: z82.string().trim().min(1).max(300).optional(),
|
|
19960
21009
|
/** Add an announcement bar text above add-to-cart (optional). */
|
|
19961
|
-
announcementBarEnabled:
|
|
19962
|
-
announcementBarText:
|
|
21010
|
+
announcementBarEnabled: z82.boolean().optional(),
|
|
21011
|
+
announcementBarText: z82.string().trim().min(1).max(SHOPIFY_ANNOUNCEMENT_BAR_MAX_LENGTH).optional(),
|
|
19963
21012
|
commerceCorrection: PublishCommerceCorrectionSchema.optional().describe("Complete seller-confirmed commerce values, with the revision and fingerprint returned in recovery. Never invent missing prices or convert currency."),
|
|
19964
|
-
confirmed:
|
|
21013
|
+
confirmed: z82.boolean().optional().describe("Required as true only when submitting commerceCorrection, after showing its values and obtaining explicit seller confirmation.")
|
|
19965
21014
|
});
|
|
19966
21015
|
var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value, ctx) => {
|
|
19967
21016
|
if (value.commerceCorrection && value.confirmed !== true) {
|
|
19968
21017
|
ctx.addIssue({
|
|
19969
|
-
code:
|
|
21018
|
+
code: z82.ZodIssueCode.custom,
|
|
19970
21019
|
path: [
|
|
19971
21020
|
"confirmed"
|
|
19972
21021
|
],
|
|
@@ -19975,7 +21024,7 @@ var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value,
|
|
|
19975
21024
|
}
|
|
19976
21025
|
if (value.announcementBarEnabled && !value.announcementBarText) {
|
|
19977
21026
|
ctx.addIssue({
|
|
19978
|
-
code:
|
|
21027
|
+
code: z82.ZodIssueCode.custom,
|
|
19979
21028
|
path: [
|
|
19980
21029
|
"announcementBarText"
|
|
19981
21030
|
],
|
|
@@ -19984,7 +21033,7 @@ var ShopifyInputWithAnnouncementBarValidation = ShopifyInput.superRefine((value,
|
|
|
19984
21033
|
}
|
|
19985
21034
|
if (!value.announcementBarEnabled && value.announcementBarText) {
|
|
19986
21035
|
ctx.addIssue({
|
|
19987
|
-
code:
|
|
21036
|
+
code: z82.ZodIssueCode.custom,
|
|
19988
21037
|
path: [
|
|
19989
21038
|
"announcementBarText"
|
|
19990
21039
|
],
|
|
@@ -19998,91 +21047,91 @@ function parseShopifyInput(rawInput) {
|
|
|
19998
21047
|
return parsed.data;
|
|
19999
21048
|
}
|
|
20000
21049
|
__name(parseShopifyInput, "parseShopifyInput");
|
|
20001
|
-
var McpCampaignConfig =
|
|
21050
|
+
var McpCampaignConfig = z82.object({
|
|
20002
21051
|
/** ALWAYS in US dollars, whatever the ad account's currency is. ProductMaker
|
|
20003
21052
|
* converts to the account currency server-side. Do NOT pre-convert: on a COP
|
|
20004
21053
|
* account the user's "60.000 al día" is `dailyBudgetUsd: 15`, not 60000. */
|
|
20005
|
-
dailyBudgetUsd:
|
|
21054
|
+
dailyBudgetUsd: z82.number().positive().optional(),
|
|
20006
21055
|
/** ISO-3166-1 alpha-2 country codes or resolvable names (CountryIso2Schema
|
|
20007
21056
|
* normalizes at validation). Meta accepts max 1 (single-country ad set).
|
|
20008
21057
|
* TikTok takes only the first entry. */
|
|
20009
|
-
targetCountries:
|
|
20010
|
-
campaignName:
|
|
21058
|
+
targetCountries: z82.array(CountryIso2Schema).max(1).optional(),
|
|
21059
|
+
campaignName: z82.string().trim().min(1).max(100).optional()
|
|
20011
21060
|
});
|
|
20012
21061
|
var McpAdAccountId = MetaAdAccountId.describe('Meta ad account id. Accepts "act_1234567890" or the bare numeric id "1234567890".');
|
|
20013
|
-
var MetaInput =
|
|
20014
|
-
taskId:
|
|
21062
|
+
var MetaInput = z82.object({
|
|
21063
|
+
taskId: z82.string().min(1),
|
|
20015
21064
|
/** Exact Meta Business portfolio selected from `list_meta_destinations`. */
|
|
20016
|
-
portfolioId:
|
|
21065
|
+
portfolioId: z82.string().trim().min(1),
|
|
20017
21066
|
/** Exact Facebook Page selected from `list_meta_destinations`. */
|
|
20018
|
-
pageId:
|
|
21067
|
+
pageId: z82.string().trim().min(1),
|
|
20019
21068
|
adAccountId: McpAdAccountId,
|
|
20020
|
-
pixelId:
|
|
20021
|
-
landingUrl:
|
|
21069
|
+
pixelId: z82.string().min(1).optional(),
|
|
21070
|
+
landingUrl: z82.string().url().optional(),
|
|
20022
21071
|
/** Select which angles to publish by 0-based index. Omit to publish all
|
|
20023
21072
|
* successful angles. Example: a task with 3 angles → `[0,2]` publishes #0 + #2. */
|
|
20024
|
-
angleIndexes:
|
|
21073
|
+
angleIndexes: z82.array(z82.number().int().nonnegative()).optional(),
|
|
20025
21074
|
campaignConfig: McpCampaignConfig.optional(),
|
|
20026
21075
|
/** Override the ad's primary text (body copy). If omitted, ProductMaker
|
|
20027
21076
|
* uses the auto-generated copy attached to the task. Capped at 500 chars
|
|
20028
21077
|
* (Meta's primary-text limit). */
|
|
20029
|
-
primaryText:
|
|
21078
|
+
primaryText: z82.string().trim().min(1).max(500).optional(),
|
|
20030
21079
|
/** Optional WhatsApp number. When set, the ad button opens a WhatsApp chat
|
|
20031
21080
|
* (wa.me) instead of a landing page. */
|
|
20032
|
-
phoneNumber:
|
|
21081
|
+
phoneNumber: z82.string().min(8).max(32).optional()
|
|
20033
21082
|
});
|
|
20034
|
-
var GroupedTaskSource =
|
|
20035
|
-
type:
|
|
20036
|
-
taskId:
|
|
20037
|
-
angleIndex:
|
|
20038
|
-
videoVariant:
|
|
21083
|
+
var GroupedTaskSource = z82.object({
|
|
21084
|
+
type: z82.literal("task"),
|
|
21085
|
+
taskId: z82.string().min(1),
|
|
21086
|
+
angleIndex: z82.number().int().min(0).optional(),
|
|
21087
|
+
videoVariant: z82.enum([
|
|
20039
21088
|
"with_subtitles",
|
|
20040
21089
|
"without_subtitles"
|
|
20041
21090
|
]).optional(),
|
|
20042
|
-
imageVariantIndex:
|
|
20043
|
-
});
|
|
20044
|
-
var GroupedMediaSource =
|
|
20045
|
-
type:
|
|
20046
|
-
url:
|
|
20047
|
-
path:
|
|
20048
|
-
thumbnailUrl:
|
|
20049
|
-
thumbnailPath:
|
|
21091
|
+
imageVariantIndex: z82.number().int().min(0).optional()
|
|
21092
|
+
});
|
|
21093
|
+
var GroupedMediaSource = z82.object({
|
|
21094
|
+
type: z82.literal("media"),
|
|
21095
|
+
url: z82.string().url().optional().describe("Public HTTPS media URL. For a file on the user laptop, use request_media_upload on the hosted MCP instead."),
|
|
21096
|
+
path: z82.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".'),
|
|
21097
|
+
thumbnailUrl: z82.string().url().optional(),
|
|
21098
|
+
thumbnailPath: z82.string().min(1).optional()
|
|
20050
21099
|
}).refine((value) => Boolean(value.url) !== Boolean(value.path), {
|
|
20051
21100
|
message: "media source needs exactly one of `url` or `path`"
|
|
20052
21101
|
}).refine((value) => !(value.thumbnailUrl && value.thumbnailPath), {
|
|
20053
21102
|
message: "media source needs at most one of `thumbnailUrl` or `thumbnailPath`"
|
|
20054
21103
|
});
|
|
20055
|
-
var GroupedUploadedAssetSource =
|
|
20056
|
-
type:
|
|
21104
|
+
var GroupedUploadedAssetSource = z82.object({
|
|
21105
|
+
type: z82.literal("asset"),
|
|
20057
21106
|
/** Returned by check_media_upload. ProductMaker resolves ownership server-side. */
|
|
20058
|
-
assetId:
|
|
20059
|
-
thumbnailAssetId:
|
|
21107
|
+
assetId: z82.string().uuid(),
|
|
21108
|
+
thumbnailAssetId: z82.string().uuid().optional()
|
|
20060
21109
|
});
|
|
20061
|
-
var GroupedCreative =
|
|
20062
|
-
type:
|
|
21110
|
+
var GroupedCreative = z82.object({
|
|
21111
|
+
type: z82.enum([
|
|
20063
21112
|
"image",
|
|
20064
21113
|
"video"
|
|
20065
21114
|
]),
|
|
20066
|
-
source:
|
|
21115
|
+
source: z82.union([
|
|
20067
21116
|
GroupedTaskSource,
|
|
20068
21117
|
GroupedMediaSource,
|
|
20069
21118
|
GroupedUploadedAssetSource
|
|
20070
21119
|
]),
|
|
20071
|
-
title:
|
|
20072
|
-
description:
|
|
21120
|
+
title: z82.string().max(120).optional(),
|
|
21121
|
+
description: z82.string().max(500).optional(),
|
|
20073
21122
|
cta: MetaCtaType.optional(),
|
|
20074
|
-
creativeId:
|
|
21123
|
+
creativeId: z82.string().min(1).optional()
|
|
20075
21124
|
});
|
|
20076
|
-
var GroupedCampaignConfigBase =
|
|
21125
|
+
var GroupedCampaignConfigBase = z82.object({
|
|
20077
21126
|
campaignType: MetaCampaignType.default("sales"),
|
|
20078
21127
|
optimizationMode: MetaOptimizationMode.default("advantage_plus"),
|
|
20079
21128
|
budgetMode: MetaBudgetMode.optional(),
|
|
20080
|
-
campaignDailyBudget:
|
|
20081
|
-
adSets:
|
|
20082
|
-
tempId:
|
|
20083
|
-
name:
|
|
20084
|
-
dailyBudget:
|
|
20085
|
-
creativeIds:
|
|
21129
|
+
campaignDailyBudget: z82.number().int().positive().optional(),
|
|
21130
|
+
adSets: z82.array(z82.object({
|
|
21131
|
+
tempId: z82.string().min(1).max(80),
|
|
21132
|
+
name: z82.string().min(1).max(100),
|
|
21133
|
+
dailyBudget: z82.number().int().positive().optional(),
|
|
21134
|
+
creativeIds: z82.array(z82.string().min(1)).min(1)
|
|
20086
21135
|
})).min(1).max(CAMPAIGN_LIMITS.MAX_AD_SETS),
|
|
20087
21136
|
/**
|
|
20088
21137
|
* Valid values are 'landing' and 'whatsapp' — there is no 'website'. This
|
|
@@ -20090,17 +21139,17 @@ var GroupedCampaignConfigBase = z78.object({
|
|
|
20090
21139
|
* opaque `invalid_literal` and made the WhatsApp destination — supported by
|
|
20091
21140
|
* the API since #849 — unreachable from this tool.
|
|
20092
21141
|
*/
|
|
20093
|
-
destination:
|
|
20094
|
-
|
|
20095
|
-
type:
|
|
20096
|
-
landingUrl:
|
|
21142
|
+
destination: z82.discriminatedUnion("type", [
|
|
21143
|
+
z82.object({
|
|
21144
|
+
type: z82.literal("landing"),
|
|
21145
|
+
landingUrl: z82.string().url()
|
|
20097
21146
|
}),
|
|
20098
|
-
|
|
20099
|
-
type:
|
|
20100
|
-
phoneNumber:
|
|
21147
|
+
z82.object({
|
|
21148
|
+
type: z82.literal("whatsapp"),
|
|
21149
|
+
phoneNumber: z82.string().min(8).max(32)
|
|
20101
21150
|
})
|
|
20102
21151
|
]),
|
|
20103
|
-
saveAsDefault:
|
|
21152
|
+
saveAsDefault: z82.boolean().default(false),
|
|
20104
21153
|
budgetPolicy: MetaBudgetPolicy.optional()
|
|
20105
21154
|
});
|
|
20106
21155
|
function resolveBudgetMode(value) {
|
|
@@ -20114,7 +21163,7 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
|
|
|
20114
21163
|
const budgetMode = resolveBudgetMode(value);
|
|
20115
21164
|
if (budgetMode === "campaign" && value.campaignDailyBudget === void 0) {
|
|
20116
21165
|
ctx.addIssue({
|
|
20117
|
-
code:
|
|
21166
|
+
code: z82.ZodIssueCode.custom,
|
|
20118
21167
|
path: [
|
|
20119
21168
|
"campaignDailyBudget"
|
|
20120
21169
|
],
|
|
@@ -20125,7 +21174,7 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
|
|
|
20125
21174
|
value.adSets.forEach((adSet, index) => {
|
|
20126
21175
|
if (adSet.dailyBudget === void 0) {
|
|
20127
21176
|
ctx.addIssue({
|
|
20128
|
-
code:
|
|
21177
|
+
code: z82.ZodIssueCode.custom,
|
|
20129
21178
|
path: [
|
|
20130
21179
|
"adSets",
|
|
20131
21180
|
index,
|
|
@@ -20140,28 +21189,28 @@ var GroupedCampaignConfig = GroupedCampaignConfigBase.superRefine((value, ctx) =
|
|
|
20140
21189
|
...value,
|
|
20141
21190
|
budgetMode: resolveBudgetMode(value)
|
|
20142
21191
|
}));
|
|
20143
|
-
var PublishCreativesToMetaInputBase =
|
|
20144
|
-
creatives:
|
|
21192
|
+
var PublishCreativesToMetaInputBase = z82.object({
|
|
21193
|
+
creatives: z82.array(GroupedCreative).min(1).max(CAMPAIGN_LIMITS.MAX_CREATIVES),
|
|
20145
21194
|
/** Exact Meta Business portfolio selected from `list_meta_destinations`. */
|
|
20146
|
-
portfolioId:
|
|
21195
|
+
portfolioId: z82.string().trim().min(1),
|
|
20147
21196
|
/** Exact Facebook Page selected from `list_meta_destinations`. */
|
|
20148
|
-
pageId:
|
|
21197
|
+
pageId: z82.string().trim().min(1),
|
|
20149
21198
|
adAccountId: McpAdAccountId,
|
|
20150
|
-
pixelId:
|
|
21199
|
+
pixelId: z82.string().min(1).optional(),
|
|
20151
21200
|
/** Required unless `campaignConfig.destination` is whatsapp — see the
|
|
20152
21201
|
* superRefine below. Mirrors the API's `FacebookCreateCampaignFromTasksBodySchema`. */
|
|
20153
|
-
landingUrl:
|
|
21202
|
+
landingUrl: z82.string().url().optional(),
|
|
20154
21203
|
/** ISO-2 code or resolvable country name — mirrors the API contract
|
|
20155
21204
|
* (CountryIso2Schema), which normalizes names to alpha-2 at validation. */
|
|
20156
21205
|
targetCountry: CountryIso2Schema,
|
|
20157
|
-
campaignName:
|
|
21206
|
+
campaignName: z82.string().trim().min(1).max(100),
|
|
20158
21207
|
campaignConfig: GroupedCampaignConfig.optional()
|
|
20159
21208
|
});
|
|
20160
21209
|
var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((value, ctx) => {
|
|
20161
21210
|
const destination = value.campaignConfig?.destination;
|
|
20162
21211
|
if (destination?.type !== "whatsapp" && destination?.type !== "landing" && !value.landingUrl) {
|
|
20163
21212
|
ctx.addIssue({
|
|
20164
|
-
code:
|
|
21213
|
+
code: z82.ZodIssueCode.custom,
|
|
20165
21214
|
path: [
|
|
20166
21215
|
"landingUrl"
|
|
20167
21216
|
],
|
|
@@ -20170,7 +21219,7 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
|
|
|
20170
21219
|
}
|
|
20171
21220
|
if (destination?.type === "landing" && value.landingUrl && destination.landingUrl !== value.landingUrl) {
|
|
20172
21221
|
ctx.addIssue({
|
|
20173
|
-
code:
|
|
21222
|
+
code: z82.ZodIssueCode.custom,
|
|
20174
21223
|
path: [
|
|
20175
21224
|
"campaignConfig",
|
|
20176
21225
|
"destination",
|
|
@@ -20189,16 +21238,16 @@ var PublishCreativesToMetaInput = PublishCreativesToMetaInputBase.superRefine((v
|
|
|
20189
21238
|
}
|
|
20190
21239
|
return value;
|
|
20191
21240
|
});
|
|
20192
|
-
var PresignUploadResponseSchema =
|
|
20193
|
-
uploadUrl:
|
|
21241
|
+
var PresignUploadResponseSchema = z82.object({
|
|
21242
|
+
uploadUrl: z82.string().url().refine((value) => {
|
|
20194
21243
|
const url = new URL(value);
|
|
20195
21244
|
return !url.username && !url.password && url.protocol === "https:";
|
|
20196
21245
|
}, "presigned upload URL must be HTTPS without embedded credentials"),
|
|
20197
|
-
publicUrl:
|
|
21246
|
+
publicUrl: z82.string().url().refine((value) => {
|
|
20198
21247
|
const url = new URL(value);
|
|
20199
21248
|
return !url.username && !url.password;
|
|
20200
21249
|
}, "public media URL must not contain embedded credentials"),
|
|
20201
|
-
stagingAssetId:
|
|
21250
|
+
stagingAssetId: z82.string().uuid()
|
|
20202
21251
|
});
|
|
20203
21252
|
async function uploadResolvedMedia(api, media, assetRole) {
|
|
20204
21253
|
if (!media.buffer) throw new ResolveMediaError("INVALID_INPUT", "resolved media has no bytes");
|
|
@@ -20223,16 +21272,16 @@ async function resolveAndUploadMedia(api, ref, expectedKind, assetRole, transpor
|
|
|
20223
21272
|
return uploadResolvedMedia(api, media, assetRole);
|
|
20224
21273
|
}
|
|
20225
21274
|
__name(resolveAndUploadMedia, "resolveAndUploadMedia");
|
|
20226
|
-
var TikTokInput =
|
|
20227
|
-
taskId:
|
|
20228
|
-
advertiserId:
|
|
20229
|
-
pixelId:
|
|
20230
|
-
landingUrl:
|
|
20231
|
-
angleIndexes:
|
|
21275
|
+
var TikTokInput = z82.object({
|
|
21276
|
+
taskId: z82.string().min(1),
|
|
21277
|
+
advertiserId: z82.string().min(1),
|
|
21278
|
+
pixelId: z82.string().min(1).optional(),
|
|
21279
|
+
landingUrl: z82.string().url().optional(),
|
|
21280
|
+
angleIndexes: z82.array(z82.number().int().nonnegative()).optional(),
|
|
20232
21281
|
campaignConfig: McpCampaignConfig.optional(),
|
|
20233
21282
|
/** Override the ad's description (TikTok's body copy). If omitted,
|
|
20234
21283
|
* ProductMaker uses the auto-generated copy attached to the task. */
|
|
20235
|
-
primaryText:
|
|
21284
|
+
primaryText: z82.string().trim().min(1).max(500).optional()
|
|
20236
21285
|
});
|
|
20237
21286
|
function registerPublishTools(server, api, opts = {}) {
|
|
20238
21287
|
const transport = opts.transport ?? "http";
|
|
@@ -20560,39 +21609,39 @@ __name(toTikTokCampaignConfig, "toTikTokCampaignConfig");
|
|
|
20560
21609
|
|
|
20561
21610
|
// src/tools/meta-upload.ts
|
|
20562
21611
|
import { registerAppTool } from "@modelcontextprotocol/ext-apps/server";
|
|
20563
|
-
import { z as
|
|
21612
|
+
import { z as z83 } from "zod";
|
|
20564
21613
|
var requestMediaUploadGuidance = getProductMakerCapabilityModelGuidance("request_media_upload");
|
|
20565
|
-
var UploadSessionInputBase =
|
|
20566
|
-
mediaKind:
|
|
21614
|
+
var UploadSessionInputBase = z83.object({
|
|
21615
|
+
mediaKind: z83.enum([
|
|
20567
21616
|
"image",
|
|
20568
21617
|
"video",
|
|
20569
21618
|
"mixed"
|
|
20570
21619
|
]).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."),
|
|
20571
|
-
assetRole:
|
|
21620
|
+
assetRole: z83.enum([
|
|
20572
21621
|
"media",
|
|
20573
21622
|
"thumbnail"
|
|
20574
21623
|
]).default("media").describe("Use media for the creative itself; thumbnail only for an image thumbnail."),
|
|
20575
|
-
uploadPurpose:
|
|
21624
|
+
uploadPurpose: z83.enum([
|
|
20576
21625
|
"product_reference",
|
|
20577
21626
|
"creative",
|
|
20578
21627
|
"generic"
|
|
20579
21628
|
]).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."),
|
|
20580
|
-
maxFiles:
|
|
21629
|
+
maxFiles: z83.number().int().min(1).max(10).optional().describe("Optional batch limit: image accepts 1-5, video exactly 1, and mixed 1-10.")
|
|
20581
21630
|
});
|
|
20582
|
-
var OpenAiFileReference =
|
|
20583
|
-
download_url:
|
|
20584
|
-
file_id:
|
|
20585
|
-
mime_type:
|
|
20586
|
-
file_name:
|
|
21631
|
+
var OpenAiFileReference = z83.object({
|
|
21632
|
+
download_url: z83.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."),
|
|
21633
|
+
file_id: z83.string().min(1),
|
|
21634
|
+
mime_type: z83.string().min(1).optional(),
|
|
21635
|
+
file_name: z83.string().min(1).optional()
|
|
20587
21636
|
});
|
|
20588
21637
|
var UploadSessionToolInputShape = {
|
|
20589
21638
|
...UploadSessionInputBase.shape,
|
|
20590
|
-
files:
|
|
21639
|
+
files: z83.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.")
|
|
20591
21640
|
};
|
|
20592
|
-
var UploadSessionToolInput =
|
|
21641
|
+
var UploadSessionToolInput = z83.object(UploadSessionToolInputShape).superRefine((value, ctx) => {
|
|
20593
21642
|
if (value.assetRole === "thumbnail" && value.mediaKind !== "image") {
|
|
20594
21643
|
ctx.addIssue({
|
|
20595
|
-
code:
|
|
21644
|
+
code: z83.ZodIssueCode.custom,
|
|
20596
21645
|
path: [
|
|
20597
21646
|
"mediaKind"
|
|
20598
21647
|
],
|
|
@@ -20601,7 +21650,7 @@ var UploadSessionToolInput = z79.object(UploadSessionToolInputShape).superRefine
|
|
|
20601
21650
|
}
|
|
20602
21651
|
if (value.mediaKind === "video" && value.maxFiles !== void 0 && value.maxFiles !== 1) {
|
|
20603
21652
|
ctx.addIssue({
|
|
20604
|
-
code:
|
|
21653
|
+
code: z83.ZodIssueCode.custom,
|
|
20605
21654
|
path: [
|
|
20606
21655
|
"maxFiles"
|
|
20607
21656
|
],
|
|
@@ -20610,7 +21659,7 @@ var UploadSessionToolInput = z79.object(UploadSessionToolInputShape).superRefine
|
|
|
20610
21659
|
}
|
|
20611
21660
|
if (value.mediaKind === "image" && (value.maxFiles ?? 1) > 5) {
|
|
20612
21661
|
ctx.addIssue({
|
|
20613
|
-
code:
|
|
21662
|
+
code: z83.ZodIssueCode.custom,
|
|
20614
21663
|
path: [
|
|
20615
21664
|
"maxFiles"
|
|
20616
21665
|
],
|
|
@@ -20618,38 +21667,38 @@ var UploadSessionToolInput = z79.object(UploadSessionToolInputShape).superRefine
|
|
|
20618
21667
|
});
|
|
20619
21668
|
}
|
|
20620
21669
|
});
|
|
20621
|
-
var UploadSessionResponse =
|
|
20622
|
-
sessionId:
|
|
20623
|
-
uploadPageUrl:
|
|
20624
|
-
mediaKind:
|
|
21670
|
+
var UploadSessionResponse = z83.object({
|
|
21671
|
+
sessionId: z83.string().uuid(),
|
|
21672
|
+
uploadPageUrl: z83.string().url(),
|
|
21673
|
+
mediaKind: z83.enum([
|
|
20625
21674
|
"image",
|
|
20626
21675
|
"video",
|
|
20627
21676
|
"mixed"
|
|
20628
21677
|
]),
|
|
20629
|
-
assetRole:
|
|
21678
|
+
assetRole: z83.enum([
|
|
20630
21679
|
"media",
|
|
20631
21680
|
"thumbnail"
|
|
20632
21681
|
]),
|
|
20633
|
-
maxFiles:
|
|
20634
|
-
expiresAt:
|
|
21682
|
+
maxFiles: z83.number().int().positive(),
|
|
21683
|
+
expiresAt: z83.string().datetime()
|
|
20635
21684
|
});
|
|
20636
|
-
var UploadStatusInput =
|
|
20637
|
-
sessionId:
|
|
21685
|
+
var UploadStatusInput = z83.object({
|
|
21686
|
+
sessionId: z83.string().uuid().describe("The sessionId returned by request_media_upload.")
|
|
20638
21687
|
});
|
|
20639
|
-
var UniversalUploadStatusResponse =
|
|
20640
|
-
|
|
20641
|
-
status:
|
|
20642
|
-
assets:
|
|
21688
|
+
var UniversalUploadStatusResponse = z83.discriminatedUnion("status", [
|
|
21689
|
+
z83.object({
|
|
21690
|
+
status: z83.literal("pending"),
|
|
21691
|
+
assets: z83.array(z83.never()).length(0)
|
|
20643
21692
|
}),
|
|
20644
|
-
|
|
20645
|
-
status:
|
|
20646
|
-
assets:
|
|
20647
|
-
assetId:
|
|
20648
|
-
mediaKind:
|
|
21693
|
+
z83.object({
|
|
21694
|
+
status: z83.literal("uploaded"),
|
|
21695
|
+
assets: z83.array(z83.object({
|
|
21696
|
+
assetId: z83.string().uuid(),
|
|
21697
|
+
mediaKind: z83.enum([
|
|
20649
21698
|
"image",
|
|
20650
21699
|
"video"
|
|
20651
21700
|
]),
|
|
20652
|
-
assetRole:
|
|
21701
|
+
assetRole: z83.enum([
|
|
20653
21702
|
"media",
|
|
20654
21703
|
"thumbnail"
|
|
20655
21704
|
])
|
|
@@ -20657,13 +21706,13 @@ var UniversalUploadStatusResponse = z79.discriminatedUnion("status", [
|
|
|
20657
21706
|
})
|
|
20658
21707
|
]);
|
|
20659
21708
|
var UniversalUploadStructuredResponse = UploadSessionResponse.extend({
|
|
20660
|
-
uploadPurpose:
|
|
21709
|
+
uploadPurpose: z83.enum([
|
|
20661
21710
|
"product_reference",
|
|
20662
21711
|
"creative",
|
|
20663
21712
|
"generic"
|
|
20664
21713
|
]),
|
|
20665
|
-
checkToolName:
|
|
20666
|
-
resolveEndpoint:
|
|
21714
|
+
checkToolName: z83.literal("check_media_upload"),
|
|
21715
|
+
resolveEndpoint: z83.string().url()
|
|
20667
21716
|
});
|
|
20668
21717
|
function contextualizeUploadPageUrl(uploadPageUrl, uploadPurpose) {
|
|
20669
21718
|
const url = new URL(uploadPageUrl);
|
|
@@ -20754,15 +21803,15 @@ function registerMediaUploadTools(server, api) {
|
|
|
20754
21803
|
__name(registerMediaUploadTools, "registerMediaUploadTools");
|
|
20755
21804
|
|
|
20756
21805
|
// src/tools/campaigns.ts
|
|
20757
|
-
import { z as
|
|
21806
|
+
import { z as z84 } from "zod";
|
|
20758
21807
|
var getMetaCampaignStatusGuidance = getProductMakerCapabilityModelGuidance("get_meta_campaign_status");
|
|
20759
21808
|
var getTikTokCampaignStatusGuidance = getProductMakerCapabilityModelGuidance("get_tiktok_campaign_status");
|
|
20760
|
-
var MetaStatusInput =
|
|
20761
|
-
campaignId:
|
|
21809
|
+
var MetaStatusInput = z84.object({
|
|
21810
|
+
campaignId: z84.string().min(1).describe("Meta campaign ID returned by publish_to_meta.")
|
|
20762
21811
|
});
|
|
20763
|
-
var TikTokStatusInput =
|
|
20764
|
-
campaignId:
|
|
20765
|
-
advertiserId:
|
|
21812
|
+
var TikTokStatusInput = z84.object({
|
|
21813
|
+
campaignId: z84.string().min(1).describe("TikTok campaign ID returned by publish_to_tiktok."),
|
|
21814
|
+
advertiserId: z84.string().min(1).describe("The same advertiserId used to publish the campaign.")
|
|
20766
21815
|
});
|
|
20767
21816
|
function registerCampaignTools(server, api) {
|
|
20768
21817
|
server.tool("get_meta_campaign_status", getMetaCampaignStatusGuidance.summary + " Llama esto DESPU\xC9S de `publish_to_meta` para confirmar que la campa\xF1a se cre\xF3 correctamente y para reportar performance al usuario. Es read-only \u2014 no modifica nada en Meta Ads Manager.", MetaStatusInput.shape, READS_EXTERNAL, async (input) => {
|
|
@@ -20859,10 +21908,10 @@ function renderTikTokStatusMarkdown(r) {
|
|
|
20859
21908
|
__name(renderTikTokStatusMarkdown, "renderTikTokStatusMarkdown");
|
|
20860
21909
|
|
|
20861
21910
|
// ../../packages/product-economics/src/product-costing.ts
|
|
20862
|
-
import { z as
|
|
21911
|
+
import { z as z86 } from "zod";
|
|
20863
21912
|
|
|
20864
21913
|
// ../../packages/product-economics/src/product-costing-countries.ts
|
|
20865
|
-
import { z as
|
|
21914
|
+
import { z as z85 } from "zod";
|
|
20866
21915
|
|
|
20867
21916
|
// ../../packages/product-economics/src/product-costing-shipping-references.json
|
|
20868
21917
|
var product_costing_shipping_references_default = {
|
|
@@ -20926,21 +21975,21 @@ var product_costing_shipping_references_default = {
|
|
|
20926
21975
|
};
|
|
20927
21976
|
|
|
20928
21977
|
// ../../packages/product-economics/src/product-costing-countries.ts
|
|
20929
|
-
var ShippingReferenceSchema =
|
|
20930
|
-
reference:
|
|
20931
|
-
min:
|
|
20932
|
-
max:
|
|
20933
|
-
updatedAt:
|
|
20934
|
-
confidence:
|
|
21978
|
+
var ShippingReferenceSchema = z85.object({
|
|
21979
|
+
reference: z85.number().positive(),
|
|
21980
|
+
min: z85.number().nonnegative(),
|
|
21981
|
+
max: z85.number().positive(),
|
|
21982
|
+
updatedAt: z85.string().date(),
|
|
21983
|
+
confidence: z85.enum([
|
|
20935
21984
|
"high",
|
|
20936
21985
|
"medium",
|
|
20937
21986
|
"medium-low"
|
|
20938
21987
|
]),
|
|
20939
|
-
sources:
|
|
21988
|
+
sources: z85.array(z85.string().url().startsWith("https://")).min(1).max(3)
|
|
20940
21989
|
}).superRefine(({ reference, min, max }, context) => {
|
|
20941
21990
|
if (min > reference || reference > max) {
|
|
20942
21991
|
context.addIssue({
|
|
20943
|
-
code:
|
|
21992
|
+
code: z85.ZodIssueCode.custom,
|
|
20944
21993
|
message: "shipping_reference_outside_range",
|
|
20945
21994
|
path: [
|
|
20946
21995
|
"reference"
|
|
@@ -20948,7 +21997,7 @@ var ShippingReferenceSchema = z81.object({
|
|
|
20948
21997
|
});
|
|
20949
21998
|
}
|
|
20950
21999
|
});
|
|
20951
|
-
var SHIPPING_REFERENCES =
|
|
22000
|
+
var SHIPPING_REFERENCES = z85.record(ShippingReferenceSchema).parse(product_costing_shipping_references_default);
|
|
20952
22001
|
var PRODUCT_COSTING_COUNTRY_CODES = Object.freeze(Object.keys(SHIPPING_REFERENCES));
|
|
20953
22002
|
var SPANISH_LOCALE_COUNTRIES = /* @__PURE__ */ new Set([
|
|
20954
22003
|
"MX",
|
|
@@ -21130,18 +22179,18 @@ function getProductCostingCountryName(country) {
|
|
|
21130
22179
|
__name(getProductCostingCountryName, "getProductCostingCountryName");
|
|
21131
22180
|
|
|
21132
22181
|
// ../../packages/product-economics/src/product-costing.ts
|
|
21133
|
-
var ProductCostingInputSchema =
|
|
21134
|
-
country:
|
|
21135
|
-
supplierCost:
|
|
21136
|
-
shippingCost:
|
|
21137
|
-
returnRate:
|
|
21138
|
-
cancellationRate:
|
|
21139
|
-
adsManagerCpa:
|
|
21140
|
-
desiredMargin:
|
|
22182
|
+
var ProductCostingInputSchema = z86.object({
|
|
22183
|
+
country: z86.string().refine(isProductCostingCountryCode, "unsupported_country"),
|
|
22184
|
+
supplierCost: z86.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").positive("supplier_cost_positive"),
|
|
22185
|
+
shippingCost: z86.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("shipping_cost_nonnegative"),
|
|
22186
|
+
returnRate: z86.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
|
|
22187
|
+
cancellationRate: z86.number().finite().min(0, "rate_nonnegative").lt(1, "rate_below_one"),
|
|
22188
|
+
adsManagerCpa: z86.number().finite().max(Number.MAX_SAFE_INTEGER, "amount_too_large").nonnegative("cpa_nonnegative"),
|
|
22189
|
+
desiredMargin: z86.number().finite().min(0, "margin_nonnegative").lt(1, "margin_below_one")
|
|
21141
22190
|
}).superRefine(({ returnRate, cancellationRate }, context) => {
|
|
21142
22191
|
if (returnRate + cancellationRate >= 1) {
|
|
21143
22192
|
context.addIssue({
|
|
21144
|
-
code:
|
|
22193
|
+
code: z86.ZodIssueCode.custom,
|
|
21145
22194
|
message: "delivery_rate_positive",
|
|
21146
22195
|
path: [
|
|
21147
22196
|
"cancellationRate"
|
|
@@ -21238,15 +22287,15 @@ function calculateProductCosting(rawInput) {
|
|
|
21238
22287
|
__name(calculateProductCosting, "calculateProductCosting");
|
|
21239
22288
|
|
|
21240
22289
|
// src/tools/product-costing.ts
|
|
21241
|
-
import { z as
|
|
22290
|
+
import { z as z87 } from "zod";
|
|
21242
22291
|
var costProductGuidance = getProductMakerCapabilityModelGuidance("cost_product");
|
|
21243
|
-
var optionalAmount = /* @__PURE__ */ __name((description) =>
|
|
21244
|
-
var optionalPercent = /* @__PURE__ */ __name((description) =>
|
|
21245
|
-
var ProductCostingToolInput =
|
|
21246
|
-
country:
|
|
22292
|
+
var optionalAmount = /* @__PURE__ */ __name((description) => z87.number().finite().max(Number.MAX_SAFE_INTEGER).nonnegative().optional().describe(description), "optionalAmount");
|
|
22293
|
+
var optionalPercent = /* @__PURE__ */ __name((description) => z87.number().finite().min(0).lt(100).optional().describe(description), "optionalPercent");
|
|
22294
|
+
var ProductCostingToolInput = z87.object({
|
|
22295
|
+
country: z87.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
|
|
21247
22296
|
message: "Pa\xEDs no soportado por ProductMaker."
|
|
21248
22297
|
}).optional().describe("C\xF3digo ISO-2 de cualquiera de los pa\xEDses disponibles en ProductMaker. Omite para Colombia."),
|
|
21249
|
-
supplierCost:
|
|
22298
|
+
supplierCost: z87.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."),
|
|
21250
22299
|
supplierCostCop: optionalAmount("Alias anterior para costo del proveedor en Colombia. Prefiere supplierCost."),
|
|
21251
22300
|
shippingCost: optionalAmount("Costo de un env\xEDo en la moneda del pa\xEDs. Omite para usar el valor gu\xEDa vigente."),
|
|
21252
22301
|
shippingCostCop: optionalAmount("Alias anterior para flete en Colombia. Prefiere shippingCost."),
|
|
@@ -21405,7 +22454,7 @@ function formatPercent(value) {
|
|
|
21405
22454
|
__name(formatPercent, "formatPercent");
|
|
21406
22455
|
|
|
21407
22456
|
// src/tools/product-research.ts
|
|
21408
|
-
import { z as
|
|
22457
|
+
import { z as z88 } from "zod";
|
|
21409
22458
|
|
|
21410
22459
|
// src/tools/product-research-idempotency.ts
|
|
21411
22460
|
var RESEARCH_IDEMPOTENCY_WINDOW_MS = 2 * 60 * 60 * 1e3;
|
|
@@ -21776,35 +22825,35 @@ var TERMINAL2 = /* @__PURE__ */ new Set([
|
|
|
21776
22825
|
]);
|
|
21777
22826
|
var POLL_INTERVAL_MS = 5e3;
|
|
21778
22827
|
var MAX_WAIT_SECONDS = 120;
|
|
21779
|
-
var FindInput =
|
|
22828
|
+
var FindInput = z88.object({
|
|
21780
22829
|
targetCountry: ResearchTargetCountryEnum.describe("Pa\xEDs objetivo. S\xF3lo CO, MX, PE, EC y CL tienen cobertura de investigaci\xF3n."),
|
|
21781
22830
|
categoryKey: ResearchCategoryEnum.default("auto").describe('Categor\xEDa a investigar. Usa "auto" para que la IA elija seg\xFAn el mercado.'),
|
|
21782
|
-
confirmed:
|
|
21783
|
-
waitSeconds:
|
|
22831
|
+
confirmed: z88.boolean().describe(`Ponlo en true SOLO despu\xE9s de que el usuario haya aceptado el cargo de ${PRICE_CREDITS} cr\xE9ditos. No lo asumas.`),
|
|
22832
|
+
waitSeconds: z88.number().int().min(0).max(MAX_WAIT_SECONDS).optional().describe("Segundos a esperar el reporte antes de devolver el runId. M\xE1ximo 120.")
|
|
21784
22833
|
});
|
|
21785
|
-
var GetInput =
|
|
21786
|
-
runId:
|
|
22834
|
+
var GetInput = z88.object({
|
|
22835
|
+
runId: z88.string().uuid().describe("ID del run devuelto por find_winning_products.")
|
|
21787
22836
|
});
|
|
21788
|
-
var ListInput =
|
|
21789
|
-
limit:
|
|
22837
|
+
var ListInput = z88.object({
|
|
22838
|
+
limit: z88.number().int().min(1).max(20).default(10)
|
|
21790
22839
|
});
|
|
21791
|
-
function textResult(
|
|
22840
|
+
function textResult(text2) {
|
|
21792
22841
|
return {
|
|
21793
22842
|
content: [
|
|
21794
22843
|
{
|
|
21795
22844
|
type: "text",
|
|
21796
|
-
text
|
|
22845
|
+
text: text2
|
|
21797
22846
|
}
|
|
21798
22847
|
]
|
|
21799
22848
|
};
|
|
21800
22849
|
}
|
|
21801
22850
|
__name(textResult, "textResult");
|
|
21802
|
-
function researchResult(run,
|
|
22851
|
+
function researchResult(run, text2) {
|
|
21803
22852
|
return {
|
|
21804
22853
|
content: [
|
|
21805
22854
|
{
|
|
21806
22855
|
type: "text",
|
|
21807
|
-
text
|
|
22856
|
+
text: text2
|
|
21808
22857
|
}
|
|
21809
22858
|
],
|
|
21810
22859
|
structuredContent: run
|
|
@@ -21909,17 +22958,17 @@ _Esta llamada no cobr\xF3 cr\xE9ditos: se reutiliz\xF3 una investigaci\xF3n reci
|
|
|
21909
22958
|
__name(registerProductResearchTools, "registerProductResearchTools");
|
|
21910
22959
|
|
|
21911
22960
|
// src/tools/dropshipping-projects.ts
|
|
21912
|
-
import { z as
|
|
22961
|
+
import { z as z89 } from "zod";
|
|
21913
22962
|
var startDropshippingProjectGuidance = getProductMakerCapabilityModelGuidance("start_dropshipping_project");
|
|
21914
22963
|
var costDropshippingProjectGuidance = getProductMakerCapabilityModelGuidance("cost_dropshipping_project");
|
|
21915
22964
|
var guideDropshippingLaunchGuidance = getProductMakerCapabilityModelGuidance("guide_dropshipping_launch");
|
|
21916
|
-
var ProjectId =
|
|
21917
|
-
var DropshippingProjectStatus =
|
|
22965
|
+
var ProjectId = z89.string().uuid();
|
|
22966
|
+
var DropshippingProjectStatus = z89.enum([
|
|
21918
22967
|
"active",
|
|
21919
22968
|
"completed",
|
|
21920
22969
|
"archived"
|
|
21921
22970
|
]);
|
|
21922
|
-
var DropshippingProjectPhase =
|
|
22971
|
+
var DropshippingProjectPhase = z89.enum([
|
|
21923
22972
|
"research",
|
|
21924
22973
|
"costing",
|
|
21925
22974
|
"media",
|
|
@@ -21928,21 +22977,21 @@ var DropshippingProjectPhase = z85.enum([
|
|
|
21928
22977
|
"advertising",
|
|
21929
22978
|
"complete"
|
|
21930
22979
|
]);
|
|
21931
|
-
var DropshippingRewardMilestone =
|
|
22980
|
+
var DropshippingRewardMilestone = z89.enum([
|
|
21932
22981
|
"product_selected",
|
|
21933
22982
|
"costing_saved",
|
|
21934
22983
|
"product_media_ready",
|
|
21935
22984
|
"creatives_completed",
|
|
21936
22985
|
"campaign_created"
|
|
21937
22986
|
]);
|
|
21938
|
-
var TargetCountry =
|
|
22987
|
+
var TargetCountry = z89.enum([
|
|
21939
22988
|
"CO",
|
|
21940
22989
|
"MX",
|
|
21941
22990
|
"PE",
|
|
21942
22991
|
"EC",
|
|
21943
22992
|
"CL"
|
|
21944
22993
|
]);
|
|
21945
|
-
var ResearchCategory =
|
|
22994
|
+
var ResearchCategory = z89.enum([
|
|
21946
22995
|
"auto",
|
|
21947
22996
|
"automotive",
|
|
21948
22997
|
"kitchen",
|
|
@@ -21957,7 +23006,7 @@ var ResearchCategory = z85.enum([
|
|
|
21957
23006
|
"garden",
|
|
21958
23007
|
"cleaning"
|
|
21959
23008
|
]);
|
|
21960
|
-
var HttpUrl3 =
|
|
23009
|
+
var HttpUrl3 = z89.string().url().max(2e3).refine((value) => {
|
|
21961
23010
|
try {
|
|
21962
23011
|
return [
|
|
21963
23012
|
"http:",
|
|
@@ -21967,45 +23016,45 @@ var HttpUrl3 = z85.string().url().max(2e3).refine((value) => {
|
|
|
21967
23016
|
return false;
|
|
21968
23017
|
}
|
|
21969
23018
|
}, "URL must use HTTP(S)");
|
|
21970
|
-
var ResearchCandidateOrigin =
|
|
21971
|
-
type:
|
|
23019
|
+
var ResearchCandidateOrigin = z89.object({
|
|
23020
|
+
type: z89.literal("research_candidate"),
|
|
21972
23021
|
runId: ProjectId,
|
|
21973
|
-
candidateSourceId:
|
|
23022
|
+
candidateSourceId: z89.string().min(1).max(160)
|
|
21974
23023
|
});
|
|
21975
|
-
var TaskOrigin =
|
|
21976
|
-
type:
|
|
23024
|
+
var TaskOrigin = z89.object({
|
|
23025
|
+
type: z89.literal("task"),
|
|
21977
23026
|
taskId: ProjectId
|
|
21978
23027
|
});
|
|
21979
|
-
var ManualOrigin =
|
|
21980
|
-
type:
|
|
23028
|
+
var ManualOrigin = z89.object({
|
|
23029
|
+
type: z89.literal("manual"),
|
|
21981
23030
|
clientRequestId: ProjectId,
|
|
21982
|
-
country:
|
|
23031
|
+
country: z89.string().min(2).max(3).optional()
|
|
21983
23032
|
});
|
|
21984
|
-
var StartProjectInput =
|
|
21985
|
-
origin:
|
|
23033
|
+
var StartProjectInput = z89.object({
|
|
23034
|
+
origin: z89.discriminatedUnion("type", [
|
|
21986
23035
|
ResearchCandidateOrigin,
|
|
21987
23036
|
TaskOrigin,
|
|
21988
23037
|
ManualOrigin
|
|
21989
23038
|
]),
|
|
21990
|
-
productName:
|
|
23039
|
+
productName: z89.string().trim().min(1).max(240).optional(),
|
|
21991
23040
|
productUrl: HttpUrl3.optional(),
|
|
21992
|
-
country:
|
|
21993
|
-
languageCode:
|
|
23041
|
+
country: z89.string().min(2).max(3).optional(),
|
|
23042
|
+
languageCode: z89.string().min(2).max(16).optional()
|
|
21994
23043
|
}).strict();
|
|
21995
|
-
var CostProjectInput =
|
|
23044
|
+
var CostProjectInput = z89.object({
|
|
21996
23045
|
projectId: ProjectId,
|
|
21997
|
-
version:
|
|
21998
|
-
country:
|
|
23046
|
+
version: z89.number().int().positive().describe("Version le\xEDda del proyecto. Copia la \xFAltima que viste; no se la pidas al usuario."),
|
|
23047
|
+
country: z89.string().trim().toUpperCase().refine(isProductCostingCountryCode, {
|
|
21999
23048
|
message: "Pa\xEDs no soportado por ProductMaker."
|
|
22000
23049
|
}).describe("C\xF3digo ISO-2 del pa\xEDs del proyecto. Usa el `targetCountry` que devuelve el proyecto."),
|
|
22001
|
-
supplierCost:
|
|
22002
|
-
shippingCost:
|
|
22003
|
-
returnRate:
|
|
22004
|
-
cancellationRate:
|
|
22005
|
-
adsManagerCpa:
|
|
22006
|
-
desiredMargin:
|
|
22007
|
-
});
|
|
22008
|
-
var GuideInput =
|
|
23050
|
+
supplierCost: z89.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."),
|
|
23051
|
+
shippingCost: z89.number().finite().nonnegative().optional().describe("Costo de un env\xEDo. Omite para usar el valor gu\xEDa del pa\xEDs en vez de inventarlo."),
|
|
23052
|
+
returnRate: z89.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."),
|
|
23053
|
+
cancellationRate: z89.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."),
|
|
23054
|
+
adsManagerCpa: z89.number().finite().nonnegative().optional().describe("Costo por compra de Ads Manager. Omite para usar el valor gu\xEDa del pa\xEDs."),
|
|
23055
|
+
desiredMargin: z89.number().finite().min(0).lt(1).optional().describe("Margen deseado (0.1 = 10%). Omite para usar el valor gu\xEDa del pa\xEDs.")
|
|
23056
|
+
});
|
|
23057
|
+
var GuideInput = z89.object({
|
|
22009
23058
|
projectId: ProjectId.optional()
|
|
22010
23059
|
}).strict();
|
|
22011
23060
|
var NEXT_ACTION_KINDS = [
|
|
@@ -22023,29 +23072,29 @@ var NEXT_ACTION_KINDS = [
|
|
|
22023
23072
|
"repair_meta_campaign",
|
|
22024
23073
|
"review_paused_campaign"
|
|
22025
23074
|
];
|
|
22026
|
-
var DropshippingProjectNextAction =
|
|
22027
|
-
kind:
|
|
22028
|
-
href:
|
|
23075
|
+
var DropshippingProjectNextAction = z89.discriminatedUnion("kind", NEXT_ACTION_KINDS.map((kind) => z89.object({
|
|
23076
|
+
kind: z89.literal(kind),
|
|
23077
|
+
href: z89.string().min(1)
|
|
22029
23078
|
})));
|
|
22030
|
-
var CostingInputSchema =
|
|
22031
|
-
country:
|
|
22032
|
-
supplierCost:
|
|
22033
|
-
shippingCost:
|
|
22034
|
-
returnRate:
|
|
22035
|
-
cancellationRate:
|
|
22036
|
-
adsManagerCpa:
|
|
22037
|
-
desiredMargin:
|
|
23079
|
+
var CostingInputSchema = z89.object({
|
|
23080
|
+
country: z89.string().min(2).max(3),
|
|
23081
|
+
supplierCost: z89.number().finite().positive(),
|
|
23082
|
+
shippingCost: z89.number().finite().nonnegative(),
|
|
23083
|
+
returnRate: z89.number().finite().min(0).lt(1),
|
|
23084
|
+
cancellationRate: z89.number().finite().min(0).lt(1),
|
|
23085
|
+
adsManagerCpa: z89.number().finite().nonnegative(),
|
|
23086
|
+
desiredMargin: z89.number().finite().min(0).lt(1)
|
|
22038
23087
|
}).superRefine(({ returnRate, cancellationRate }, context) => {
|
|
22039
23088
|
if (returnRate + cancellationRate >= 1) context.addIssue({
|
|
22040
|
-
code:
|
|
23089
|
+
code: z89.ZodIssueCode.custom,
|
|
22041
23090
|
path: [
|
|
22042
23091
|
"cancellationRate"
|
|
22043
23092
|
]
|
|
22044
23093
|
});
|
|
22045
23094
|
});
|
|
22046
|
-
var FiniteCostingNumber =
|
|
22047
|
-
var CostingResultSchema =
|
|
22048
|
-
country:
|
|
23095
|
+
var FiniteCostingNumber = z89.number().finite();
|
|
23096
|
+
var CostingResultSchema = z89.object({
|
|
23097
|
+
country: z89.string().min(2).max(3),
|
|
22049
23098
|
deliveryRate: FiniteCostingNumber,
|
|
22050
23099
|
adjustedShippingCost: FiniteCostingNumber,
|
|
22051
23100
|
adjustedCpa: FiniteCostingNumber,
|
|
@@ -22058,45 +23107,45 @@ var CostingResultSchema = z85.object({
|
|
|
22058
23107
|
estimatedProfit: FiniteCostingNumber,
|
|
22059
23108
|
actualMargin: FiniteCostingNumber,
|
|
22060
23109
|
breakEvenAdsManagerCpa: FiniteCostingNumber,
|
|
22061
|
-
wasPriceAutoAdjusted:
|
|
22062
|
-
profitabilityStatus:
|
|
22063
|
-
});
|
|
22064
|
-
var RewardProgressSchema =
|
|
22065
|
-
campaignKey:
|
|
22066
|
-
totalCredits:
|
|
22067
|
-
earnedCredits:
|
|
22068
|
-
milestones:
|
|
23110
|
+
wasPriceAutoAdjusted: z89.boolean(),
|
|
23111
|
+
profitabilityStatus: z89.literal("healthy")
|
|
23112
|
+
});
|
|
23113
|
+
var RewardProgressSchema = z89.object({
|
|
23114
|
+
campaignKey: z89.literal("dropshipping-launch-v1"),
|
|
23115
|
+
totalCredits: z89.number().int().positive(),
|
|
23116
|
+
earnedCredits: z89.number().int().nonnegative(),
|
|
23117
|
+
milestones: z89.array(z89.object({
|
|
22069
23118
|
milestone: DropshippingRewardMilestone,
|
|
22070
|
-
credits:
|
|
22071
|
-
available:
|
|
22072
|
-
earned:
|
|
23119
|
+
credits: z89.number().int().positive(),
|
|
23120
|
+
available: z89.boolean().optional(),
|
|
23121
|
+
earned: z89.boolean(),
|
|
22073
23122
|
grantId: ProjectId.nullable(),
|
|
22074
|
-
grantedAt:
|
|
23123
|
+
grantedAt: z89.string().datetime().nullable()
|
|
22075
23124
|
})).length(DropshippingRewardMilestone.options.length)
|
|
22076
23125
|
});
|
|
22077
|
-
var ProjectResponseSchema =
|
|
23126
|
+
var ProjectResponseSchema = z89.object({
|
|
22078
23127
|
id: ProjectId,
|
|
22079
23128
|
taskId: ProjectId.nullable(),
|
|
22080
23129
|
status: DropshippingProjectStatus,
|
|
22081
|
-
originKey:
|
|
23130
|
+
originKey: z89.string().min(1),
|
|
22082
23131
|
researchRunId: ProjectId.nullable(),
|
|
22083
|
-
candidateSourceId:
|
|
22084
|
-
productName:
|
|
23132
|
+
candidateSourceId: z89.string().nullable(),
|
|
23133
|
+
productName: z89.string().nullable(),
|
|
22085
23134
|
productUrl: HttpUrl3.nullable(),
|
|
22086
23135
|
referenceImageUrl: HttpUrl3.nullable(),
|
|
22087
|
-
targetCountry:
|
|
22088
|
-
languageCode:
|
|
22089
|
-
hasReferenceImage:
|
|
22090
|
-
hasWinnerReferenceImage:
|
|
23136
|
+
targetCountry: z89.string().nullable(),
|
|
23137
|
+
languageCode: z89.string().nullable(),
|
|
23138
|
+
hasReferenceImage: z89.boolean(),
|
|
23139
|
+
hasWinnerReferenceImage: z89.boolean(),
|
|
22091
23140
|
costingInput: CostingInputSchema.nullable(),
|
|
22092
23141
|
costingResult: CostingResultSchema.nullable(),
|
|
22093
|
-
costingVersion:
|
|
22094
|
-
version:
|
|
23142
|
+
costingVersion: z89.number().int().positive().nullable(),
|
|
23143
|
+
version: z89.number().int().positive(),
|
|
22095
23144
|
phase: DropshippingProjectPhase,
|
|
22096
23145
|
nextAction: DropshippingProjectNextAction.nullable(),
|
|
22097
23146
|
rewards: RewardProgressSchema,
|
|
22098
|
-
createdAt:
|
|
22099
|
-
updatedAt:
|
|
23147
|
+
createdAt: z89.string().datetime(),
|
|
23148
|
+
updatedAt: z89.string().datetime()
|
|
22100
23149
|
}).passthrough();
|
|
22101
23150
|
var NEXT_ACTION_GUIDANCE = {
|
|
22102
23151
|
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.",
|
|
@@ -22214,58 +23263,58 @@ function registerDropshippingProjectTools(server, api) {
|
|
|
22214
23263
|
__name(registerDropshippingProjectTools, "registerDropshippingProjectTools");
|
|
22215
23264
|
|
|
22216
23265
|
// src/tools/daily-control.ts
|
|
22217
|
-
import { z as
|
|
23266
|
+
import { z as z90 } from "zod";
|
|
22218
23267
|
var getDailyControlGuidance = getProductMakerCapabilityModelGuidance("get_daily_control");
|
|
22219
23268
|
var linkCampaignToProjectGuidance = getProductMakerCapabilityModelGuidance("link_campaign_to_project");
|
|
22220
23269
|
var reportDailyReturnsGuidance = getProductMakerCapabilityModelGuidance("report_daily_returns");
|
|
22221
|
-
var ProviderCampaignIdentifier =
|
|
22222
|
-
var DateOnly =
|
|
22223
|
-
var DailyControlInput =
|
|
23270
|
+
var ProviderCampaignIdentifier = z90.string().min(1).max(64).regex(/^[A-Za-z0-9_-]+$/);
|
|
23271
|
+
var DateOnly = z90.string().regex(/^\d{4}-\d{2}-\d{2}$/);
|
|
23272
|
+
var DailyControlInput = z90.object({
|
|
22224
23273
|
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."),
|
|
22225
|
-
days:
|
|
22226
|
-
projectId:
|
|
23274
|
+
days: z90.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
|
|
23275
|
+
projectId: z90.string().uuid().optional().describe("Opcional: limita el reporte a un solo proyecto en vez de todos los productos activos.")
|
|
22227
23276
|
}).strict();
|
|
22228
|
-
var LinkCampaignInput =
|
|
22229
|
-
projectId:
|
|
22230
|
-
provider:
|
|
23277
|
+
var LinkCampaignInput = z90.object({
|
|
23278
|
+
projectId: z90.string().uuid(),
|
|
23279
|
+
provider: z90.enum([
|
|
22231
23280
|
"meta",
|
|
22232
23281
|
"tiktok"
|
|
22233
23282
|
]),
|
|
22234
23283
|
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."),
|
|
22235
23284
|
campaignId: ProviderCampaignIdentifier
|
|
22236
23285
|
}).strict();
|
|
22237
|
-
var ReportReturnsInput =
|
|
22238
|
-
projectId:
|
|
23286
|
+
var ReportReturnsInput = z90.object({
|
|
23287
|
+
projectId: z90.string().uuid(),
|
|
22239
23288
|
date: DateOnly,
|
|
22240
|
-
returnedOrders:
|
|
22241
|
-
note:
|
|
23289
|
+
returnedOrders: z90.number().int().min(0).max(1e5),
|
|
23290
|
+
note: z90.string().trim().max(280).optional()
|
|
22242
23291
|
}).strict();
|
|
22243
|
-
var DailyControlStatusMirror = DailyControlStatusEnum.or(
|
|
22244
|
-
var DailyControlLightMirror = DailyControlLightEnum.or(
|
|
22245
|
-
var DailyControlSourceMirror = DailyControlSourceEnum.or(
|
|
22246
|
-
var DailyControlVerdictMirror = DailyControlVerdictEnum.or(
|
|
22247
|
-
var DailyControlDayMirror =
|
|
22248
|
-
date:
|
|
22249
|
-
returnedOrders:
|
|
23292
|
+
var DailyControlStatusMirror = DailyControlStatusEnum.or(z90.string());
|
|
23293
|
+
var DailyControlLightMirror = DailyControlLightEnum.or(z90.string());
|
|
23294
|
+
var DailyControlSourceMirror = DailyControlSourceEnum.or(z90.string());
|
|
23295
|
+
var DailyControlVerdictMirror = DailyControlVerdictEnum.or(z90.string());
|
|
23296
|
+
var DailyControlDayMirror = z90.object({
|
|
23297
|
+
date: z90.string(),
|
|
23298
|
+
returnedOrders: z90.number(),
|
|
22250
23299
|
returnedSource: DailyControlSourceMirror,
|
|
22251
23300
|
cancelledSource: DailyControlSourceMirror,
|
|
22252
|
-
hasEstimates:
|
|
23301
|
+
hasEstimates: z90.boolean(),
|
|
22253
23302
|
light: DailyControlLightMirror
|
|
22254
23303
|
}).passthrough();
|
|
22255
|
-
var DailyControlProductMirror =
|
|
22256
|
-
projectId:
|
|
22257
|
-
productName:
|
|
23304
|
+
var DailyControlProductMirror = z90.object({
|
|
23305
|
+
projectId: z90.string().uuid(),
|
|
23306
|
+
productName: z90.string().nullable(),
|
|
22258
23307
|
status: DailyControlStatusMirror,
|
|
22259
|
-
statusMessage:
|
|
22260
|
-
days:
|
|
23308
|
+
statusMessage: z90.string().nullable(),
|
|
23309
|
+
days: z90.array(DailyControlDayMirror),
|
|
22261
23310
|
verdict: DailyControlVerdictMirror.nullable(),
|
|
22262
|
-
rationale:
|
|
23311
|
+
rationale: z90.string().nullable()
|
|
22263
23312
|
}).passthrough();
|
|
22264
|
-
var DailyControlResponseMirror =
|
|
22265
|
-
since:
|
|
22266
|
-
until:
|
|
22267
|
-
products:
|
|
22268
|
-
archivedProjectSpend:
|
|
23313
|
+
var DailyControlResponseMirror = z90.object({
|
|
23314
|
+
since: z90.string(),
|
|
23315
|
+
until: z90.string(),
|
|
23316
|
+
products: z90.array(DailyControlProductMirror),
|
|
23317
|
+
archivedProjectSpend: z90.array(z90.unknown())
|
|
22269
23318
|
}).passthrough();
|
|
22270
23319
|
var MCP_WARNINGS_KEY = "_mcpDailyControlWarnings";
|
|
22271
23320
|
function withWarnings(response) {
|
|
@@ -22349,42 +23398,42 @@ function registerDailyControlTools(server, api) {
|
|
|
22349
23398
|
__name(registerDailyControlTools, "registerDailyControlTools");
|
|
22350
23399
|
|
|
22351
23400
|
// src/tools/product-control.ts
|
|
22352
|
-
import { z as
|
|
23401
|
+
import { z as z91 } from "zod";
|
|
22353
23402
|
var getProductControlGuidance = getProductMakerCapabilityModelGuidance("get_product_control");
|
|
22354
23403
|
var listImportableProductsGuidance = getProductMakerCapabilityModelGuidance("list_importable_products");
|
|
22355
23404
|
var importProductControlsGuidance = getProductMakerCapabilityModelGuidance("import_product_controls");
|
|
22356
23405
|
var setProductCostingGuidance = getProductMakerCapabilityModelGuidance("set_product_costing");
|
|
22357
23406
|
var reportProductCountsGuidance = getProductMakerCapabilityModelGuidance("report_product_counts");
|
|
22358
|
-
var DateOnly2 =
|
|
23407
|
+
var DateOnly2 = z91.string().regex(/^\d{4}-\d{2}-\d{2}$/);
|
|
22359
23408
|
var IMPORT_BATCH_MAX2 = 50;
|
|
22360
|
-
var ProductControlListInput =
|
|
22361
|
-
days:
|
|
23409
|
+
var ProductControlListInput = z91.object({
|
|
23410
|
+
days: z91.number().int().min(1).max(14).default(3).describe("Tama\xF1o de la ventana, 1 a 14 d\xEDas."),
|
|
22362
23411
|
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."),
|
|
22363
|
-
shopDomain:
|
|
23412
|
+
shopDomain: z91.string().min(1).optional().describe("Tienda, si tiene m\xE1s de una conectada.")
|
|
22364
23413
|
}).strict();
|
|
22365
|
-
var ImportableProductsInput =
|
|
22366
|
-
q:
|
|
22367
|
-
after:
|
|
22368
|
-
shopDomain:
|
|
23414
|
+
var ImportableProductsInput = z91.object({
|
|
23415
|
+
q: z91.string().trim().max(120).optional().describe("B\xFAsqueda por t\xEDtulo. Sin esto un cat\xE1logo grande es inrecorrible."),
|
|
23416
|
+
after: z91.string().max(512).optional().describe("Cursor de la p\xE1gina anterior, tal como vino en la respuesta."),
|
|
23417
|
+
shopDomain: z91.string().min(1).optional()
|
|
22369
23418
|
}).strict();
|
|
22370
|
-
var ImportProductControlsInput =
|
|
22371
|
-
shopifyProductIds:
|
|
23419
|
+
var ImportProductControlsInput = z91.object({
|
|
23420
|
+
shopifyProductIds: z91.array(z91.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."),
|
|
22372
23421
|
// Obligatorio, como en el endpoint: con dos tiendas conectadas, importar
|
|
22373
23422
|
// sin decir a cuál archivaría el producto bajo la tienda equivocada.
|
|
22374
|
-
shopDomain:
|
|
23423
|
+
shopDomain: z91.string().min(1)
|
|
22375
23424
|
}).strict();
|
|
22376
|
-
var SetProductCostingInput =
|
|
22377
|
-
shopDomain:
|
|
22378
|
-
shopifyProductId:
|
|
22379
|
-
targetCountry:
|
|
22380
|
-
supplierCost:
|
|
22381
|
-
shippingCost:
|
|
22382
|
-
returnRate:
|
|
22383
|
-
cancellationRate:
|
|
23425
|
+
var SetProductCostingInput = z91.object({
|
|
23426
|
+
shopDomain: z91.string().min(1),
|
|
23427
|
+
shopifyProductId: z91.string().min(1).max(64),
|
|
23428
|
+
targetCountry: z91.string().length(2).describe("Pa\xEDs de venta en ISO-2, que fija moneda y referencia de flete."),
|
|
23429
|
+
supplierCost: z91.number().finite().positive().describe("Lo que le cuesta el producto al proveedor. Nunca cero."),
|
|
23430
|
+
shippingCost: z91.number().finite().nonnegative(),
|
|
23431
|
+
returnRate: z91.number().finite().min(0).lt(1).describe("Proporci\xF3n 0\u20131, no porcentaje: 0.15 es quince por ciento."),
|
|
23432
|
+
cancellationRate: z91.number().finite().min(0).lt(1)
|
|
22384
23433
|
}).strict();
|
|
22385
|
-
var Count =
|
|
22386
|
-
var ReportProductCountsInput =
|
|
22387
|
-
productControlId:
|
|
23434
|
+
var Count = z91.number().int().min(0).max(1e5).nullable().optional();
|
|
23435
|
+
var ReportProductCountsInput = z91.object({
|
|
23436
|
+
productControlId: z91.string().uuid().describe("El identificador que devuelve get_product_control."),
|
|
22388
23437
|
date: DateOnly2,
|
|
22389
23438
|
orders: Count.describe("Pedidos que entraron ese d\xEDa."),
|
|
22390
23439
|
cancelledOrders: Count,
|