@puppetry.com/sdk 0.1.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.
@@ -0,0 +1,1500 @@
1
+ // src/errors.ts
2
+ var PuppetryError = class _PuppetryError extends Error {
3
+ constructor(status, code, message, details, options) {
4
+ super(message);
5
+ this.name = "PuppetryError";
6
+ this.status = status;
7
+ this.code = code;
8
+ this.details = details;
9
+ this.object = options?.object;
10
+ this.retryAfter = options?.retryAfter;
11
+ this.retryable = options?.retryable;
12
+ this.credits = options?.credits;
13
+ this.creationCredits = options?.creationCredits ?? options?.creation_credits;
14
+ this.creation_credits = this.creationCredits;
15
+ this.retryBlockedReason = options?.retryBlockedReason ?? options?.retry_blocked_reason;
16
+ this.retry_blocked_reason = this.retryBlockedReason;
17
+ this.retryBlockCode = options?.retryBlockCode ?? options?.retry_block_code;
18
+ this.retry_block_code = this.retryBlockCode;
19
+ this.jobId = options?.jobId ?? options?.job_id ?? options?.id;
20
+ this.job_id = this.jobId;
21
+ this.id = this.jobId;
22
+ this.operationId = options?.operationId ?? options?.operation_id;
23
+ this.operation_id = this.operationId;
24
+ this.taskId = options?.taskId ?? options?.task_id ?? this.jobId;
25
+ this.task_id = this.taskId;
26
+ this.statusUrl = options?.statusUrl ?? options?.status_url ?? options?.contentLocation ?? options?.content_location;
27
+ this.status_url = this.statusUrl;
28
+ this.contentLocation = options?.contentLocation ?? options?.content_location ?? options?.statusUrl ?? options?.status_url;
29
+ this.content_location = this.contentLocation;
30
+ this.createdAt = options?.createdAt ?? options?.created_at;
31
+ this.created_at = this.createdAt;
32
+ this.expiresAt = options?.expiresAt ?? options?.expires_at;
33
+ this.expires_at = this.expiresAt;
34
+ this.nextPollAt = options?.nextPollAt ?? options?.next_poll_at;
35
+ this.next_poll_at = this.nextPollAt;
36
+ this.source = options?.source ?? options?.requestSource ?? options?.request_source;
37
+ this.requestSource = options?.requestSource ?? options?.request_source ?? this.source;
38
+ this.request_source = this.requestSource;
39
+ this.requestId = options?.requestId ?? options?.request_id;
40
+ this.request_id = this.requestId;
41
+ this.requiredCredits = options?.requiredCredits ?? options?.required_credits;
42
+ this.required_credits = this.requiredCredits;
43
+ this.creditsRemaining = options?.creditsRemaining ?? options?.credits_remaining ?? options?.remainingCredits ?? options?.remaining_credits;
44
+ this.credits_remaining = this.creditsRemaining;
45
+ this.remainingCredits = this.creditsRemaining;
46
+ this.remaining_credits = this.creditsRemaining;
47
+ }
48
+ static fromResponse(status, body, options) {
49
+ return new _PuppetryError(status, body.error, body.message, body.details, {
50
+ ...options,
51
+ ...retryMetadataFromApiError(body),
52
+ ...creditReadinessMetadataFromApiError(body),
53
+ ...jobCorrelationMetadataFromApiError(body)
54
+ });
55
+ }
56
+ };
57
+ var PuppetryTimeoutError = class extends PuppetryError {
58
+ constructor(timeoutMs) {
59
+ super(408, "timeout", `Request timed out after ${timeoutMs}ms`);
60
+ this.name = "PuppetryTimeoutError";
61
+ }
62
+ };
63
+ function retryMetadataFromApiError(body) {
64
+ const readinessDetails = objectFromKeys(
65
+ body.details,
66
+ "video_generation",
67
+ "videoGeneration"
68
+ );
69
+ const readinessBlocker = firstObjectFromArrayKeys(
70
+ readinessDetails,
71
+ "blockers"
72
+ );
73
+ const retryable = typeof body.retryable === "boolean" ? body.retryable : typeof body.details?.retryable === "boolean" ? body.details.retryable : typeof readinessDetails?.retryable === "boolean" ? readinessDetails.retryable : typeof readinessBlocker?.retryable === "boolean" ? readinessBlocker.retryable : void 0;
74
+ const retryBlockedReason = stringFromAliases(body, "retryBlockedReason", "retry_blocked_reason") ?? stringFromAliases(
75
+ body.details,
76
+ "retryBlockedReason",
77
+ "retry_blocked_reason"
78
+ ) ?? stringFromAliases(
79
+ readinessDetails,
80
+ "retryBlockedReason",
81
+ "retry_blocked_reason"
82
+ ) ?? stringFromAliases(
83
+ readinessBlocker,
84
+ "retryBlockedReason",
85
+ "retry_blocked_reason"
86
+ ) ?? stringFromKeys(readinessBlocker, "reason", "code") ?? stringFromKeys(readinessDetails, "reason");
87
+ const retryBlockCode = stringFromAliases(body, "retryBlockCode", "retry_block_code") ?? stringFromAliases(body.details, "retryBlockCode", "retry_block_code") ?? stringFromAliases(readinessDetails, "retryBlockCode", "retry_block_code") ?? stringFromAliases(readinessBlocker, "retryBlockCode", "retry_block_code") ?? stringFromKeys(readinessBlocker, "code");
88
+ return {
89
+ ...retryable !== void 0 ? { retryable } : {},
90
+ ...retryBlockedReason ? {
91
+ retry_blocked_reason: retryBlockedReason,
92
+ retryBlockedReason
93
+ } : {},
94
+ ...retryBlockCode ? {
95
+ retry_block_code: retryBlockCode,
96
+ retryBlockCode
97
+ } : {}
98
+ };
99
+ }
100
+ function jobCorrelationMetadataFromApiError(body) {
101
+ const readinessDetails = objectFromKeys(
102
+ body.details,
103
+ "video_generation",
104
+ "videoGeneration"
105
+ );
106
+ const object = stringFromKeys(body, "object") ?? stringFromKeys(body.details, "object");
107
+ const jobId = stringFromKeys(body, "jobId", "job_id", "id") ?? stringFromKeys(body.details, "jobId", "job_id", "id");
108
+ const operationId = stringFromKeys(body, "operationId", "operation_id") ?? stringFromKeys(body.details, "operationId", "operation_id");
109
+ const taskId = stringFromKeys(body, "taskId", "task_id") ?? stringFromKeys(body.details, "taskId", "task_id") ?? jobId;
110
+ const bodyStatusUrl = stringFromKeys(body, "statusUrl", "status_url") ?? stringFromKeys(body.details, "statusUrl", "status_url");
111
+ const bodyContentLocation = stringFromKeys(body, "contentLocation", "content_location") ?? stringFromKeys(body.details, "contentLocation", "content_location");
112
+ const statusUrl = bodyStatusUrl ?? bodyContentLocation;
113
+ const contentLocation = bodyContentLocation ?? bodyStatusUrl;
114
+ const createdAt = stringFromKeys(body, "createdAt", "created_at") ?? stringFromKeys(body.details, "createdAt", "created_at");
115
+ const expiresAt = stringFromKeys(body, "expiresAt", "expires_at") ?? stringFromKeys(body.details, "expiresAt", "expires_at");
116
+ const nextPollAt = stringFromKeys(body, "nextPollAt", "next_poll_at") ?? stringFromKeys(body.details, "nextPollAt", "next_poll_at") ?? stringFromKeys(readinessDetails, "nextPollAt", "next_poll_at");
117
+ const source = stringFromKeys(body, "source") ?? stringFromKeys(body.details, "source");
118
+ const requestSource = stringFromKeys(body, "requestSource", "request_source") ?? stringFromKeys(body.details, "requestSource", "request_source") ?? source;
119
+ const requestId = stringFromKeys(body, "requestId", "request_id") ?? stringFromKeys(body.details, "requestId", "request_id") ?? stringFromKeys(readinessDetails, "requestId", "request_id");
120
+ const credits = statusCreditsFromKeys(body, "credits") ?? statusCreditsFromKeys(body.details, "credits");
121
+ const creationCredits = creationCreditsFromKeys(body, "creationCredits", "creation_credits") ?? creationCreditsFromKeys(
122
+ body.details,
123
+ "creationCredits",
124
+ "creation_credits"
125
+ );
126
+ return {
127
+ ...object ? { object } : {},
128
+ ...jobId ? { id: jobId, job_id: jobId, jobId } : {},
129
+ ...operationId ? { operation_id: operationId, operationId } : {},
130
+ ...taskId ? { task_id: taskId, taskId } : {},
131
+ ...statusUrl ? { status_url: statusUrl, statusUrl } : {},
132
+ ...contentLocation ? { content_location: contentLocation, contentLocation } : {},
133
+ ...createdAt ? { created_at: createdAt, createdAt } : {},
134
+ ...expiresAt ? { expires_at: expiresAt, expiresAt } : {},
135
+ ...nextPollAt ? { next_poll_at: nextPollAt, nextPollAt } : {},
136
+ ...source ? { source } : {},
137
+ ...requestSource ? { request_source: requestSource, requestSource } : {},
138
+ ...requestId ? { request_id: requestId, requestId } : {},
139
+ ...credits ? { credits } : {},
140
+ ...creationCredits ? { creation_credits: creationCredits, creationCredits } : {}
141
+ };
142
+ }
143
+ function creditReadinessMetadataFromApiError(body) {
144
+ const readinessDetails = objectFromKeys(
145
+ body.details,
146
+ "video_generation",
147
+ "videoGeneration"
148
+ );
149
+ const readinessBlocker = firstObjectFromArrayKeys(
150
+ readinessDetails,
151
+ "blockers"
152
+ );
153
+ const requiredCredits = numberFromKeys(body, "requiredCredits", "required_credits") ?? numberFromKeys(body.details, "requiredCredits", "required_credits") ?? numberFromKeys(readinessDetails, "requiredCredits", "required_credits") ?? numberFromKeys(readinessBlocker, "requiredCredits", "required_credits");
154
+ const creditsRemaining = numberFromKeys(
155
+ body,
156
+ "creditsRemaining",
157
+ "credits_remaining",
158
+ "remainingCredits",
159
+ "remaining_credits"
160
+ ) ?? numberFromKeys(
161
+ body.details,
162
+ "creditsRemaining",
163
+ "credits_remaining",
164
+ "remainingCredits",
165
+ "remaining_credits"
166
+ ) ?? numberFromKeys(readinessDetails, "creditsRemaining", "credits_remaining") ?? numberFromKeys(
167
+ readinessBlocker,
168
+ "creditsRemaining",
169
+ "credits_remaining",
170
+ "remainingCredits",
171
+ "remaining_credits"
172
+ );
173
+ return {
174
+ ...requiredCredits !== void 0 ? { required_credits: requiredCredits, requiredCredits } : {},
175
+ ...creditsRemaining !== void 0 ? {
176
+ credits_remaining: creditsRemaining,
177
+ creditsRemaining,
178
+ remaining_credits: creditsRemaining,
179
+ remainingCredits: creditsRemaining
180
+ } : {}
181
+ };
182
+ }
183
+ function stringFromAliases(record, camelKey, snakeKey) {
184
+ return stringFromKeys(record, camelKey, snakeKey);
185
+ }
186
+ function stringFromKeys(record, ...keys) {
187
+ if (!record) return void 0;
188
+ const source = record;
189
+ const value = keys.map((key) => source[key]).find((item) => item !== void 0);
190
+ if (typeof value !== "string") return void 0;
191
+ const trimmed = value.trim();
192
+ return trimmed || void 0;
193
+ }
194
+ function objectFromKeys(record, ...keys) {
195
+ if (!record) return void 0;
196
+ const source = record;
197
+ const value = keys.map((key) => source[key]).find((item) => item !== void 0);
198
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
199
+ return void 0;
200
+ }
201
+ return value;
202
+ }
203
+ function statusCreditsFromKeys(record, ...keys) {
204
+ const value = objectFromKeys(record, ...keys);
205
+ if (!value) return void 0;
206
+ const charged = numberFromKeys(value, "charged");
207
+ const remaining = nullableNumberFromKeys(value, "remaining");
208
+ if (charged === void 0 || remaining === void 0) return void 0;
209
+ return { charged, remaining };
210
+ }
211
+ function creationCreditsFromKeys(record, ...keys) {
212
+ const value = objectFromKeys(record, ...keys);
213
+ if (!value) return void 0;
214
+ const charged = numberFromKeys(value, "charged");
215
+ const remainingAfterDebit = nullableNumberFromKeys(
216
+ value,
217
+ "remainingAfterDebit",
218
+ "remaining_after_debit"
219
+ );
220
+ if (charged === void 0 || remainingAfterDebit === void 0) {
221
+ return void 0;
222
+ }
223
+ return {
224
+ charged,
225
+ remaining_after_debit: remainingAfterDebit,
226
+ remainingAfterDebit
227
+ };
228
+ }
229
+ function numberFromKeys(record, ...keys) {
230
+ if (!record) return void 0;
231
+ const source = record;
232
+ const value = keys.map((key) => source[key]).find((item) => item !== void 0);
233
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
234
+ }
235
+ function nullableNumberFromKeys(record, ...keys) {
236
+ if (!record) return void 0;
237
+ const source = record;
238
+ const value = keys.map((key) => source[key]).find((item) => item !== void 0);
239
+ if (value === null) return null;
240
+ return typeof value === "number" && Number.isFinite(value) ? value : void 0;
241
+ }
242
+ function firstObjectFromArrayKeys(record, ...keys) {
243
+ if (!record) return void 0;
244
+ const source = record;
245
+ const value = keys.map((key) => source[key]).find((item) => Array.isArray(item));
246
+ const first = Array.isArray(value) ? value[0] : void 0;
247
+ if (!first || typeof first !== "object" || Array.isArray(first)) {
248
+ return void 0;
249
+ }
250
+ return first;
251
+ }
252
+ var PuppetryAuthError = class extends PuppetryError {
253
+ constructor(message = "Invalid or missing API key") {
254
+ super(401, "unauthorized", message);
255
+ this.name = "PuppetryAuthError";
256
+ }
257
+ };
258
+ var PuppetryRateLimitError = class _PuppetryRateLimitError extends PuppetryError {
259
+ constructor(retryAfter, message = "Rate limit exceeded", details, code = "rate_limited", options) {
260
+ super(429, code, message, details, {
261
+ ...options,
262
+ retryAfter,
263
+ retryable: options?.retryable ?? (typeof details?.retryable === "boolean" ? details.retryable : void 0)
264
+ });
265
+ this.name = "PuppetryRateLimitError";
266
+ }
267
+ static fromRateLimitResponse(body, options) {
268
+ return new _PuppetryRateLimitError(
269
+ options?.retryAfter,
270
+ body.message,
271
+ body.details,
272
+ body.error || "rate_limited",
273
+ {
274
+ ...options,
275
+ ...retryMetadataFromApiError(body),
276
+ ...creditReadinessMetadataFromApiError(body),
277
+ ...jobCorrelationMetadataFromApiError(body)
278
+ }
279
+ );
280
+ }
281
+ };
282
+ var PuppetryNetworkError = class extends PuppetryError {
283
+ constructor(message = "Network request failed") {
284
+ super(0, "network_error", message);
285
+ this.name = "PuppetryNetworkError";
286
+ }
287
+ };
288
+ function puppetryErrorData(err) {
289
+ const videoGenerationReadiness = videoGenerationReadinessFromDetails(
290
+ err.details
291
+ );
292
+ return {
293
+ status: err.status,
294
+ statusCode: err.status,
295
+ code: err.code,
296
+ message: err.message,
297
+ ...err.object ? { object: err.object } : {},
298
+ ...err.retryAfter !== void 0 ? {
299
+ retry_after_seconds: err.retryAfter,
300
+ retryAfterSeconds: err.retryAfter,
301
+ retryAfter: err.retryAfter
302
+ } : {},
303
+ ...err.retryable !== void 0 ? { retryable: err.retryable } : {},
304
+ ...err.credits ? { credits: err.credits } : {},
305
+ ...err.creationCredits ? {
306
+ creation_credits: err.creationCredits,
307
+ creationCredits: err.creationCredits
308
+ } : {},
309
+ ...err.retryBlockedReason ? {
310
+ retry_blocked_reason: err.retryBlockedReason,
311
+ retryBlockedReason: err.retryBlockedReason
312
+ } : {},
313
+ ...err.retryBlockCode ? {
314
+ retry_block_code: err.retryBlockCode,
315
+ retryBlockCode: err.retryBlockCode
316
+ } : {},
317
+ ...err.jobId ? { id: err.jobId, job_id: err.jobId, jobId: err.jobId } : {},
318
+ ...err.operationId ? { operation_id: err.operationId, operationId: err.operationId } : {},
319
+ ...err.taskId ? { task_id: err.taskId, taskId: err.taskId } : {},
320
+ ...err.statusUrl ? { status_url: err.statusUrl, statusUrl: err.statusUrl } : {},
321
+ ...err.contentLocation ? {
322
+ content_location: err.contentLocation,
323
+ contentLocation: err.contentLocation
324
+ } : {},
325
+ ...err.createdAt ? { created_at: err.createdAt, createdAt: err.createdAt } : {},
326
+ ...err.expiresAt ? { expires_at: err.expiresAt, expiresAt: err.expiresAt } : {},
327
+ ...err.nextPollAt ? { next_poll_at: err.nextPollAt, nextPollAt: err.nextPollAt } : {},
328
+ ...err.source ? {
329
+ source: err.source,
330
+ request_source: err.requestSource ?? err.source,
331
+ requestSource: err.requestSource ?? err.source
332
+ } : {},
333
+ ...err.requestId ? { request_id: err.requestId, requestId: err.requestId } : {},
334
+ ...err.requiredCredits !== void 0 ? {
335
+ required_credits: err.requiredCredits,
336
+ requiredCredits: err.requiredCredits
337
+ } : {},
338
+ ...err.creditsRemaining !== void 0 ? {
339
+ credits_remaining: err.creditsRemaining,
340
+ creditsRemaining: err.creditsRemaining,
341
+ remaining_credits: err.creditsRemaining,
342
+ remainingCredits: err.creditsRemaining
343
+ } : {},
344
+ ...videoGenerationReadiness ? {
345
+ video_generation: videoGenerationReadiness,
346
+ videoGeneration: videoGenerationReadiness
347
+ } : {},
348
+ ...err.details !== void 0 ? { details: err.details } : {}
349
+ };
350
+ }
351
+ function videoGenerationReadinessFromDetails(details) {
352
+ const readiness = objectFromKeys(
353
+ details,
354
+ "video_generation",
355
+ "videoGeneration"
356
+ );
357
+ if (!readiness) return void 0;
358
+ const canCreate = booleanFromKeys(readiness, "canCreate", "can_create");
359
+ const requiredCredits = numberFromKeys(
360
+ readiness,
361
+ "requiredCredits",
362
+ "required_credits"
363
+ );
364
+ const creditsRemaining = numberFromKeys(
365
+ readiness,
366
+ "creditsRemaining",
367
+ "credits_remaining"
368
+ );
369
+ const retryAfterSeconds = numberFromKeys(
370
+ readiness,
371
+ "retryAfterSeconds",
372
+ "retryAfter",
373
+ "retry_after_seconds"
374
+ );
375
+ const nextPollAt = stringFromKeys(readiness, "nextPollAt", "next_poll_at");
376
+ return {
377
+ ...readiness,
378
+ ...canCreate === void 0 ? {} : { can_create: canCreate, canCreate },
379
+ ...requiredCredits === void 0 ? {} : { required_credits: requiredCredits, requiredCredits },
380
+ ...creditsRemaining === void 0 ? {} : { credits_remaining: creditsRemaining, creditsRemaining },
381
+ ...retryAfterSeconds === void 0 ? {} : {
382
+ retry_after_seconds: retryAfterSeconds,
383
+ retryAfter: retryAfterSeconds,
384
+ retryAfterSeconds
385
+ },
386
+ ...nextPollAt === void 0 ? {} : { next_poll_at: nextPollAt, nextPollAt }
387
+ };
388
+ }
389
+ function booleanFromKeys(record, ...keys) {
390
+ if (!record) return void 0;
391
+ const source = record;
392
+ const value = keys.map((key) => source[key]).find((item) => item !== void 0);
393
+ return typeof value === "boolean" ? value : void 0;
394
+ }
395
+
396
+ // src/agentTools.ts
397
+ var imageUrlAliasRequirement = {
398
+ anyOf: [
399
+ { required: ["image_url"] },
400
+ { required: ["imageUrl"] },
401
+ { required: ["image"] },
402
+ { required: ["portrait"] },
403
+ { required: ["portrait_url"] },
404
+ { required: ["portraitUrl"] },
405
+ { required: ["avatar"] },
406
+ { required: ["avatarUrl"] },
407
+ { required: ["avatar_url"] },
408
+ { required: ["photo"] },
409
+ { required: ["photoUrl"] },
410
+ { required: ["photo_url"] }
411
+ ]
412
+ };
413
+ var textScriptAliasRequirement = {
414
+ anyOf: [
415
+ { required: ["text"] },
416
+ { required: ["script"] },
417
+ { required: ["prompt"] }
418
+ ]
419
+ };
420
+ var audioUrlAliasRequirement = {
421
+ anyOf: [
422
+ { required: ["audio_url"] },
423
+ { required: ["audioUrl"] },
424
+ { required: ["audio"] }
425
+ ]
426
+ };
427
+ var audioUploadReservationRequirement = {
428
+ allOf: [
429
+ {
430
+ anyOf: [
431
+ { required: ["mime_type"] },
432
+ { required: ["mimeType"] },
433
+ { required: ["contentType"] }
434
+ ]
435
+ },
436
+ {
437
+ anyOf: [
438
+ { required: ["content_length"] },
439
+ { required: ["contentLength"] },
440
+ { required: ["sizeBytes"] },
441
+ { required: ["file_size"] },
442
+ { required: ["fileSize"] }
443
+ ]
444
+ }
445
+ ]
446
+ };
447
+ var jobIdAliasRequirement = {
448
+ anyOf: [
449
+ { required: ["jobId"] },
450
+ { required: ["job_id"] },
451
+ { required: ["task_id"] },
452
+ { required: ["taskId"] },
453
+ { required: ["id"] }
454
+ ]
455
+ };
456
+ var waitOptionsProperties = {
457
+ intervalMs: {
458
+ type: "number",
459
+ description: "Polling interval in milliseconds. Defaults to 2000."
460
+ },
461
+ timeoutMs: {
462
+ type: "number",
463
+ description: "Maximum wait time in milliseconds. Defaults to 300000."
464
+ },
465
+ initialDelayMs: {
466
+ type: "number",
467
+ description: "Optional delay before the first status request, useful with Retry-After."
468
+ }
469
+ };
470
+ var readinessPreflightProperties = {
471
+ preflightReadiness: {
472
+ type: "boolean",
473
+ description: "Check video credits and active slots before queueing. Defaults to false on create-only tools and true on create-and-wait tools."
474
+ },
475
+ preflight_readiness: {
476
+ type: "boolean",
477
+ description: "Snake_case alias for preflightReadiness."
478
+ }
479
+ };
480
+ function resolveJobIdAlias(input) {
481
+ const aliases = [
482
+ { name: "jobId", value: input.jobId },
483
+ { name: "job_id", value: input.job_id },
484
+ { name: "task_id", value: input.task_id },
485
+ { name: "taskId", value: input.taskId },
486
+ { name: "id", value: input.id }
487
+ ];
488
+ const provided = aliases.filter((alias) => alias.value);
489
+ const first = provided[0];
490
+ if (!first?.value) {
491
+ throw new PuppetryError(
492
+ 400,
493
+ "invalid_request",
494
+ "Pass one of jobId, job_id, task_id, taskId, id"
495
+ );
496
+ }
497
+ const conflictingAlias = provided.find(
498
+ (alias) => alias.value !== first.value
499
+ );
500
+ if (conflictingAlias) {
501
+ throw new PuppetryError(
502
+ 400,
503
+ "invalid_request",
504
+ "Pass one of jobId, job_id, task_id, taskId, id, not conflicting values"
505
+ );
506
+ }
507
+ return first.value;
508
+ }
509
+ var PUPPETRY_AGENT_TOOLS = [
510
+ {
511
+ name: "puppetry_create_video_from_text",
512
+ resource: "videos.createFromText",
513
+ description: "Create a talking-head video from a portrait image and text.",
514
+ inputSchema: {
515
+ type: "object",
516
+ required: [],
517
+ allOf: [textScriptAliasRequirement, imageUrlAliasRequirement],
518
+ properties: {
519
+ text: {
520
+ type: "string",
521
+ description: "Script to synthesize and animate."
522
+ },
523
+ script: {
524
+ type: "string",
525
+ description: "Alias for text script to synthesize and animate."
526
+ },
527
+ prompt: {
528
+ type: "string",
529
+ description: "Alias for text script, useful for prompt-oriented agents."
530
+ },
531
+ image_url: {
532
+ type: "string",
533
+ description: "Hosted portrait image URL."
534
+ },
535
+ imageUrl: {
536
+ type: "string",
537
+ description: "Hosted portrait image URL alias."
538
+ },
539
+ image: {
540
+ type: "string",
541
+ description: "Hosted portrait image URL alias for agents."
542
+ },
543
+ portrait: {
544
+ type: "string",
545
+ description: "Deprecated hosted portrait image URL alias."
546
+ },
547
+ portrait_url: {
548
+ type: "string",
549
+ description: "Hosted portrait image URL snake_case alias."
550
+ },
551
+ portraitUrl: {
552
+ type: "string",
553
+ description: "Hosted portrait image URL alias."
554
+ },
555
+ avatar: {
556
+ type: "string",
557
+ description: "Hosted avatar image URL alias."
558
+ },
559
+ avatarUrl: {
560
+ type: "string",
561
+ description: "Hosted avatar image URL alias."
562
+ },
563
+ avatar_url: {
564
+ type: "string",
565
+ description: "Hosted avatar image URL snake_case alias."
566
+ },
567
+ photo: {
568
+ type: "string",
569
+ description: "Hosted photo image URL alias."
570
+ },
571
+ photoUrl: {
572
+ type: "string",
573
+ description: "Hosted photo image URL alias."
574
+ },
575
+ photo_url: {
576
+ type: "string",
577
+ description: "Hosted photo image URL snake_case alias."
578
+ },
579
+ voice_id: {
580
+ type: "string",
581
+ description: "Optional Puppetry voice ID from voices.listPuppetry()."
582
+ },
583
+ voiceId: {
584
+ type: "string",
585
+ description: "Optional Puppetry voice ID alias."
586
+ },
587
+ voice: {
588
+ type: "string",
589
+ description: "Optional Puppetry voice ID alias for SDK examples."
590
+ },
591
+ language: {
592
+ type: "string",
593
+ description: "Optional language code, such as en."
594
+ },
595
+ expressiveness: {
596
+ type: "number",
597
+ description: "Optional animation expressiveness from 0 to 2."
598
+ },
599
+ idempotencyKey: {
600
+ type: "string",
601
+ description: "Optional retry key sent as Idempotency-Key."
602
+ },
603
+ idempotency_key: {
604
+ type: "string",
605
+ description: "Optional retry key alias sent as Idempotency-Key."
606
+ },
607
+ ...readinessPreflightProperties
608
+ }
609
+ }
610
+ },
611
+ {
612
+ name: "puppetry_create_video_from_audio",
613
+ resource: "videos.createFromAudio",
614
+ description: "Create a talking-head video from a portrait image and audio.",
615
+ inputSchema: {
616
+ type: "object",
617
+ required: [],
618
+ allOf: [imageUrlAliasRequirement, audioUrlAliasRequirement],
619
+ properties: {
620
+ audio_url: {
621
+ type: "string",
622
+ description: "Hosted audio URL."
623
+ },
624
+ audioUrl: {
625
+ type: "string",
626
+ description: "Hosted audio URL alias."
627
+ },
628
+ audio: {
629
+ type: "string",
630
+ description: "Hosted audio URL alias for agents."
631
+ },
632
+ image_url: {
633
+ type: "string",
634
+ description: "Hosted portrait image URL."
635
+ },
636
+ imageUrl: {
637
+ type: "string",
638
+ description: "Hosted portrait image URL alias."
639
+ },
640
+ image: {
641
+ type: "string",
642
+ description: "Hosted portrait image URL alias for agents."
643
+ },
644
+ portrait: {
645
+ type: "string",
646
+ description: "Deprecated hosted portrait image URL alias."
647
+ },
648
+ portrait_url: {
649
+ type: "string",
650
+ description: "Hosted portrait image URL snake_case alias."
651
+ },
652
+ portraitUrl: {
653
+ type: "string",
654
+ description: "Hosted portrait image URL alias."
655
+ },
656
+ avatar: {
657
+ type: "string",
658
+ description: "Hosted avatar image URL alias."
659
+ },
660
+ avatarUrl: {
661
+ type: "string",
662
+ description: "Hosted avatar image URL alias."
663
+ },
664
+ avatar_url: {
665
+ type: "string",
666
+ description: "Hosted avatar image URL snake_case alias."
667
+ },
668
+ photo: {
669
+ type: "string",
670
+ description: "Hosted photo image URL alias."
671
+ },
672
+ photoUrl: {
673
+ type: "string",
674
+ description: "Hosted photo image URL alias."
675
+ },
676
+ photo_url: {
677
+ type: "string",
678
+ description: "Hosted photo image URL snake_case alias."
679
+ },
680
+ expressiveness: {
681
+ type: "number",
682
+ description: "Optional animation expressiveness from 0 to 2."
683
+ },
684
+ idempotencyKey: {
685
+ type: "string",
686
+ description: "Optional retry key sent as Idempotency-Key."
687
+ },
688
+ idempotency_key: {
689
+ type: "string",
690
+ description: "Optional retry key alias sent as Idempotency-Key."
691
+ },
692
+ ...readinessPreflightProperties
693
+ }
694
+ }
695
+ },
696
+ {
697
+ name: "puppetry_create_video_from_text_and_wait",
698
+ resource: "videos.createFromText.waitForCompletion",
699
+ description: "Create a talking-head video from text and wait for completed or failed status.",
700
+ inputSchema: {
701
+ type: "object",
702
+ required: [],
703
+ allOf: [textScriptAliasRequirement, imageUrlAliasRequirement],
704
+ properties: {
705
+ text: {
706
+ type: "string",
707
+ description: "Script to synthesize and animate."
708
+ },
709
+ script: {
710
+ type: "string",
711
+ description: "Alias for text script to synthesize and animate."
712
+ },
713
+ prompt: {
714
+ type: "string",
715
+ description: "Alias for text script, useful for prompt-oriented agents."
716
+ },
717
+ image_url: {
718
+ type: "string",
719
+ description: "Hosted portrait image URL."
720
+ },
721
+ imageUrl: {
722
+ type: "string",
723
+ description: "Hosted portrait image URL alias."
724
+ },
725
+ image: {
726
+ type: "string",
727
+ description: "Hosted portrait image URL alias for agents."
728
+ },
729
+ portrait: {
730
+ type: "string",
731
+ description: "Deprecated hosted portrait image URL alias."
732
+ },
733
+ portrait_url: {
734
+ type: "string",
735
+ description: "Hosted portrait image URL snake_case alias."
736
+ },
737
+ portraitUrl: {
738
+ type: "string",
739
+ description: "Hosted portrait image URL alias."
740
+ },
741
+ avatar: {
742
+ type: "string",
743
+ description: "Hosted avatar image URL alias."
744
+ },
745
+ avatarUrl: {
746
+ type: "string",
747
+ description: "Hosted avatar image URL alias."
748
+ },
749
+ avatar_url: {
750
+ type: "string",
751
+ description: "Hosted avatar image URL snake_case alias."
752
+ },
753
+ photo: {
754
+ type: "string",
755
+ description: "Hosted photo image URL alias."
756
+ },
757
+ photoUrl: {
758
+ type: "string",
759
+ description: "Hosted photo image URL alias."
760
+ },
761
+ photo_url: {
762
+ type: "string",
763
+ description: "Hosted photo image URL snake_case alias."
764
+ },
765
+ voice_id: {
766
+ type: "string",
767
+ description: "Optional Puppetry voice ID from voices.listPuppetry()."
768
+ },
769
+ voiceId: {
770
+ type: "string",
771
+ description: "Optional Puppetry voice ID alias."
772
+ },
773
+ voice: {
774
+ type: "string",
775
+ description: "Optional Puppetry voice ID alias for SDK examples."
776
+ },
777
+ language: {
778
+ type: "string",
779
+ description: "Optional language code, such as en."
780
+ },
781
+ expressiveness: {
782
+ type: "number",
783
+ description: "Optional animation expressiveness from 0 to 2."
784
+ },
785
+ idempotencyKey: {
786
+ type: "string",
787
+ description: "Optional retry key sent as Idempotency-Key."
788
+ },
789
+ idempotency_key: {
790
+ type: "string",
791
+ description: "Optional retry key alias sent as Idempotency-Key."
792
+ },
793
+ ...readinessPreflightProperties,
794
+ ...waitOptionsProperties
795
+ }
796
+ }
797
+ },
798
+ {
799
+ name: "puppetry_create_video_from_audio_and_wait",
800
+ resource: "videos.createFromAudio.waitForCompletion",
801
+ description: "Create a talking-head video from audio and wait for completed or failed status.",
802
+ inputSchema: {
803
+ type: "object",
804
+ required: [],
805
+ allOf: [imageUrlAliasRequirement, audioUrlAliasRequirement],
806
+ properties: {
807
+ audio_url: {
808
+ type: "string",
809
+ description: "Hosted audio URL."
810
+ },
811
+ audioUrl: {
812
+ type: "string",
813
+ description: "Hosted audio URL alias."
814
+ },
815
+ audio: {
816
+ type: "string",
817
+ description: "Hosted audio URL alias for agents."
818
+ },
819
+ image_url: {
820
+ type: "string",
821
+ description: "Hosted portrait image URL."
822
+ },
823
+ imageUrl: {
824
+ type: "string",
825
+ description: "Hosted portrait image URL alias."
826
+ },
827
+ image: {
828
+ type: "string",
829
+ description: "Hosted portrait image URL alias for agents."
830
+ },
831
+ portrait: {
832
+ type: "string",
833
+ description: "Deprecated hosted portrait image URL alias."
834
+ },
835
+ portrait_url: {
836
+ type: "string",
837
+ description: "Hosted portrait image URL snake_case alias."
838
+ },
839
+ portraitUrl: {
840
+ type: "string",
841
+ description: "Hosted portrait image URL alias."
842
+ },
843
+ avatar: {
844
+ type: "string",
845
+ description: "Hosted avatar image URL alias."
846
+ },
847
+ avatarUrl: {
848
+ type: "string",
849
+ description: "Hosted avatar image URL alias."
850
+ },
851
+ avatar_url: {
852
+ type: "string",
853
+ description: "Hosted avatar image URL snake_case alias."
854
+ },
855
+ photo: {
856
+ type: "string",
857
+ description: "Hosted photo image URL alias."
858
+ },
859
+ photoUrl: {
860
+ type: "string",
861
+ description: "Hosted photo image URL alias."
862
+ },
863
+ photo_url: {
864
+ type: "string",
865
+ description: "Hosted photo image URL snake_case alias."
866
+ },
867
+ expressiveness: {
868
+ type: "number",
869
+ description: "Optional animation expressiveness from 0 to 2."
870
+ },
871
+ idempotencyKey: {
872
+ type: "string",
873
+ description: "Optional retry key sent as Idempotency-Key."
874
+ },
875
+ idempotency_key: {
876
+ type: "string",
877
+ description: "Optional retry key alias sent as Idempotency-Key."
878
+ },
879
+ ...readinessPreflightProperties,
880
+ ...waitOptionsProperties
881
+ }
882
+ }
883
+ },
884
+ {
885
+ name: "puppetry_create_audio_upload_url",
886
+ resource: "uploads.createAudioUrl",
887
+ description: "Reserve a Puppetry-hosted signed audio upload URL for audio-to-video workflows.",
888
+ inputSchema: {
889
+ type: "object",
890
+ required: [],
891
+ ...audioUploadReservationRequirement,
892
+ properties: {
893
+ mime_type: {
894
+ type: "string",
895
+ description: "Audio MIME type, such as audio/wav, audio/mpeg, or audio/mp4."
896
+ },
897
+ mimeType: {
898
+ type: "string",
899
+ description: "Audio MIME type alias."
900
+ },
901
+ contentType: {
902
+ type: "string",
903
+ description: "Audio MIME type alias for signed-upload callers."
904
+ },
905
+ content_length: {
906
+ type: "number",
907
+ description: "Exact byte length of the audio file to upload."
908
+ },
909
+ contentLength: {
910
+ type: "number",
911
+ description: "Exact byte length alias."
912
+ },
913
+ sizeBytes: {
914
+ type: "number",
915
+ description: "Exact byte length alias for agent/runtime callers."
916
+ },
917
+ file_size: {
918
+ type: "number",
919
+ description: "Exact byte length alias for upload metadata callers."
920
+ },
921
+ fileSize: {
922
+ type: "number",
923
+ description: "Exact byte length alias for upload metadata callers."
924
+ },
925
+ idempotencyKey: {
926
+ type: "string",
927
+ description: "Optional retry key sent as Idempotency-Key."
928
+ },
929
+ idempotency_key: {
930
+ type: "string",
931
+ description: "Optional retry key alias sent as Idempotency-Key."
932
+ }
933
+ }
934
+ }
935
+ },
936
+ {
937
+ name: "puppetry_lipsync",
938
+ resource: "videos.createFromAudio",
939
+ description: "Lip sync a portrait or puppet with an existing audio URL.",
940
+ inputSchema: {
941
+ type: "object",
942
+ required: [],
943
+ allOf: [imageUrlAliasRequirement, audioUrlAliasRequirement],
944
+ properties: {
945
+ audio_url: {
946
+ type: "string",
947
+ description: "Hosted audio URL."
948
+ },
949
+ audioUrl: {
950
+ type: "string",
951
+ description: "Hosted audio URL alias."
952
+ },
953
+ audio: {
954
+ type: "string",
955
+ description: "Hosted audio URL alias for agents."
956
+ },
957
+ image_url: {
958
+ type: "string",
959
+ description: "Hosted portrait image URL."
960
+ },
961
+ imageUrl: {
962
+ type: "string",
963
+ description: "Hosted portrait image URL alias."
964
+ },
965
+ image: {
966
+ type: "string",
967
+ description: "Hosted portrait image URL alias for agents."
968
+ },
969
+ portrait: {
970
+ type: "string",
971
+ description: "Deprecated hosted portrait image URL alias."
972
+ },
973
+ portrait_url: {
974
+ type: "string",
975
+ description: "Hosted portrait image URL snake_case alias."
976
+ },
977
+ portraitUrl: {
978
+ type: "string",
979
+ description: "Hosted portrait image URL alias."
980
+ },
981
+ avatar: {
982
+ type: "string",
983
+ description: "Hosted avatar image URL alias."
984
+ },
985
+ avatarUrl: {
986
+ type: "string",
987
+ description: "Hosted avatar image URL alias."
988
+ },
989
+ avatar_url: {
990
+ type: "string",
991
+ description: "Hosted avatar image URL snake_case alias."
992
+ },
993
+ photo: {
994
+ type: "string",
995
+ description: "Hosted photo image URL alias."
996
+ },
997
+ photoUrl: {
998
+ type: "string",
999
+ description: "Hosted photo image URL alias."
1000
+ },
1001
+ photo_url: {
1002
+ type: "string",
1003
+ description: "Hosted photo image URL snake_case alias."
1004
+ },
1005
+ idempotencyKey: {
1006
+ type: "string",
1007
+ description: "Optional retry key sent as Idempotency-Key."
1008
+ },
1009
+ idempotency_key: {
1010
+ type: "string",
1011
+ description: "Optional retry key alias sent as Idempotency-Key."
1012
+ }
1013
+ }
1014
+ }
1015
+ },
1016
+ {
1017
+ name: "puppetry_list_voices",
1018
+ resource: "voices.listPuppetry",
1019
+ description: "List Puppetry-hosted voices with preview text and audio.",
1020
+ inputSchema: {
1021
+ type: "object",
1022
+ properties: {}
1023
+ }
1024
+ },
1025
+ {
1026
+ name: "puppetry_get_job_status",
1027
+ resource: "jobs.get",
1028
+ description: "Fetch a generated video job by ID.",
1029
+ inputSchema: {
1030
+ type: "object",
1031
+ required: [],
1032
+ ...jobIdAliasRequirement,
1033
+ properties: {
1034
+ jobId: {
1035
+ type: "string",
1036
+ description: "Generated video job ID."
1037
+ },
1038
+ job_id: {
1039
+ type: "string",
1040
+ description: "Generated video job ID alias."
1041
+ },
1042
+ task_id: {
1043
+ type: "string",
1044
+ description: "Generated video task ID alias."
1045
+ },
1046
+ taskId: {
1047
+ type: "string",
1048
+ description: "Generated video task ID camelCase alias."
1049
+ },
1050
+ id: {
1051
+ type: "string",
1052
+ description: "Generated video ID alias."
1053
+ }
1054
+ }
1055
+ }
1056
+ },
1057
+ {
1058
+ name: "puppetry_wait_for_video",
1059
+ resource: "videos.waitForCompletion",
1060
+ description: "Poll a generated video job until it reaches completed or failed.",
1061
+ inputSchema: {
1062
+ type: "object",
1063
+ required: [],
1064
+ ...jobIdAliasRequirement,
1065
+ properties: {
1066
+ jobId: {
1067
+ type: "string",
1068
+ description: "Generated video job ID."
1069
+ },
1070
+ job_id: {
1071
+ type: "string",
1072
+ description: "Generated video job ID alias."
1073
+ },
1074
+ task_id: {
1075
+ type: "string",
1076
+ description: "Generated video task ID alias."
1077
+ },
1078
+ taskId: {
1079
+ type: "string",
1080
+ description: "Generated video task ID camelCase alias."
1081
+ },
1082
+ id: {
1083
+ type: "string",
1084
+ description: "Generated video ID alias."
1085
+ },
1086
+ intervalMs: {
1087
+ type: "number",
1088
+ description: "Polling interval in milliseconds. Defaults to 2000."
1089
+ },
1090
+ timeoutMs: {
1091
+ type: "number",
1092
+ description: "Maximum wait time in milliseconds. Defaults to 300000."
1093
+ },
1094
+ initialDelayMs: {
1095
+ type: "number",
1096
+ description: "Optional delay before the first status request, useful with Retry-After."
1097
+ }
1098
+ }
1099
+ }
1100
+ },
1101
+ {
1102
+ name: "puppetry_get_video_readiness",
1103
+ resource: "videos.getReadiness",
1104
+ description: "Check whether credit-backed video creation can run now, including credit and active-slot blockers.",
1105
+ inputSchema: {
1106
+ type: "object",
1107
+ properties: {}
1108
+ }
1109
+ },
1110
+ {
1111
+ name: "puppetry_get_quota",
1112
+ resource: "quota.get",
1113
+ description: "Check current plan, credit usage, and remaining credits.",
1114
+ inputSchema: {
1115
+ type: "object",
1116
+ properties: {}
1117
+ }
1118
+ }
1119
+ ];
1120
+ async function callPuppetryAgentTool(client, name, input) {
1121
+ switch (name) {
1122
+ case "puppetry_create_video_from_text":
1123
+ return createTextVideo(
1124
+ client,
1125
+ input
1126
+ );
1127
+ case "puppetry_create_video_from_audio":
1128
+ return createAudioVideo(
1129
+ client,
1130
+ input
1131
+ );
1132
+ case "puppetry_create_video_from_text_and_wait":
1133
+ return createTextVideoAndWait(
1134
+ client,
1135
+ input
1136
+ );
1137
+ case "puppetry_create_video_from_audio_and_wait":
1138
+ return createAudioVideoAndWait(
1139
+ client,
1140
+ input
1141
+ );
1142
+ case "puppetry_create_audio_upload_url":
1143
+ return client.uploads.createAudioUrl(
1144
+ input
1145
+ );
1146
+ case "puppetry_lipsync":
1147
+ return client.videos.createFromAudio(
1148
+ input
1149
+ );
1150
+ case "puppetry_list_voices":
1151
+ return client.voices.listPuppetry();
1152
+ case "puppetry_get_job_status":
1153
+ return client.jobs.get(
1154
+ resolveJobIdAlias(
1155
+ input
1156
+ )
1157
+ );
1158
+ case "puppetry_wait_for_video": {
1159
+ const waitInput = input;
1160
+ return client.videos.waitForCompletion(resolveJobIdAlias(waitInput), {
1161
+ intervalMs: waitInput.intervalMs,
1162
+ timeoutMs: waitInput.timeoutMs,
1163
+ initialDelayMs: waitInput.initialDelayMs
1164
+ });
1165
+ }
1166
+ case "puppetry_get_video_readiness":
1167
+ return client.videos.getReadiness();
1168
+ case "puppetry_get_quota":
1169
+ return client.quota.get();
1170
+ default:
1171
+ throw new Error(`Unsupported Puppetry agent tool: ${String(name)}`);
1172
+ }
1173
+ }
1174
+ async function createTextVideo(client, input) {
1175
+ const readiness = await preflightVideoReadiness(client, input, false);
1176
+ const job = await client.videos.createFromText(input);
1177
+ return videoCreateResult(job, readiness);
1178
+ }
1179
+ async function createAudioVideo(client, input) {
1180
+ const readiness = await preflightVideoReadiness(client, input, false);
1181
+ const job = await client.videos.createFromAudio(input);
1182
+ return videoCreateResult(job, readiness);
1183
+ }
1184
+ async function createTextVideoAndWait(client, input) {
1185
+ const readiness = await preflightVideoReadiness(client, input, true);
1186
+ const acceptedJob = await client.videos.createFromText(input);
1187
+ const wait = measuredWaitOptions(input);
1188
+ const finalJob = await acceptedJob.waitForCompletion(wait.options);
1189
+ return videoFlowResult(acceptedJob, finalJob, wait.summary(), readiness);
1190
+ }
1191
+ async function createAudioVideoAndWait(client, input) {
1192
+ const readiness = await preflightVideoReadiness(client, input, true);
1193
+ const acceptedJob = await client.videos.createFromAudio(input);
1194
+ const wait = measuredWaitOptions(input);
1195
+ const finalJob = await acceptedJob.waitForCompletion(wait.options);
1196
+ return videoFlowResult(acceptedJob, finalJob, wait.summary(), readiness);
1197
+ }
1198
+ async function preflightVideoReadiness(client, input, defaultValue) {
1199
+ const shouldPreflight = resolveReadinessPreflight(input, defaultValue);
1200
+ if (!shouldPreflight) return void 0;
1201
+ return client.videos.ensureReady();
1202
+ }
1203
+ function resolveReadinessPreflight(input, defaultValue) {
1204
+ const aliases = [
1205
+ { name: "preflightReadiness", value: input.preflightReadiness },
1206
+ { name: "preflight_readiness", value: input.preflight_readiness }
1207
+ ].flatMap((alias) => {
1208
+ if (alias.value === void 0 || alias.value === null) return [];
1209
+ if (typeof alias.value !== "boolean") {
1210
+ throw new PuppetryError(
1211
+ 400,
1212
+ "invalid_request",
1213
+ `${alias.name} must be a boolean`
1214
+ );
1215
+ }
1216
+ return [{ name: alias.name, value: alias.value }];
1217
+ });
1218
+ const first = aliases[0];
1219
+ if (!first) return defaultValue;
1220
+ for (const alias of aliases) {
1221
+ if (alias.value !== first.value) {
1222
+ throw new PuppetryError(
1223
+ 400,
1224
+ "invalid_request",
1225
+ "preflightReadiness and preflight_readiness must describe the same boolean value"
1226
+ );
1227
+ }
1228
+ }
1229
+ return first.value;
1230
+ }
1231
+ function measuredWaitOptions(input) {
1232
+ const startedAt = Date.now();
1233
+ let pollCount = 0;
1234
+ let retryCount = 0;
1235
+ let latestRetryingEvent;
1236
+ const options = {
1237
+ ...input.intervalMs === void 0 ? {} : { intervalMs: input.intervalMs },
1238
+ ...input.timeoutMs === void 0 ? {} : { timeoutMs: input.timeoutMs },
1239
+ ...input.initialDelayMs === void 0 ? {} : { initialDelayMs: input.initialDelayMs },
1240
+ onPoll: () => {
1241
+ pollCount += 1;
1242
+ },
1243
+ onRetrying: (event) => {
1244
+ retryCount += 1;
1245
+ latestRetryingEvent = event;
1246
+ }
1247
+ };
1248
+ return {
1249
+ options,
1250
+ summary: () => ({
1251
+ pollCount,
1252
+ retryCount,
1253
+ ...latestRetryingEvent === void 0 ? {} : { latestRetryingEvent },
1254
+ durationMs: Date.now() - startedAt
1255
+ })
1256
+ };
1257
+ }
1258
+ function videoFlowResult(acceptedJob, finalJob, wait, readiness) {
1259
+ const operationId = nonDefaultOperationId(finalJob) ?? nonDefaultOperationId(acceptedJob) ?? finalJob.operationId ?? finalJob.operation_id ?? acceptedJob.operationId ?? acceptedJob.operation_id ?? finalJob.id;
1260
+ const requestId = finalJob.requestId ?? finalJob.request_id ?? acceptedJob.requestId ?? acceptedJob.request_id;
1261
+ const videoUrl = finalJob.videoUrl ?? finalJob.video_url ?? finalJob.url;
1262
+ const acceptedCredits = videoCreditEvidence(acceptedJob.credits);
1263
+ const finalCredits = videoCreditEvidence(finalJob.credits);
1264
+ const creationCredits = videoCreationCreditEvidence(finalJob) ?? videoCreationCreditEvidence(acceptedJob);
1265
+ return {
1266
+ object: "video_flow",
1267
+ accepted_job: acceptedJob,
1268
+ acceptedJob,
1269
+ final_job: finalJob,
1270
+ finalJob,
1271
+ ...acceptedCredits === void 0 ? {} : { accepted_credits: acceptedCredits, acceptedCredits },
1272
+ ...finalCredits === void 0 ? {} : {
1273
+ final_credits: finalCredits,
1274
+ finalCredits,
1275
+ credits: finalCredits
1276
+ },
1277
+ ...creationCredits === void 0 ? {} : { creation_credits: creationCredits, creationCredits },
1278
+ job_id: finalJob.id,
1279
+ jobId: finalJob.id,
1280
+ operation_id: operationId,
1281
+ operationId,
1282
+ ...requestId === void 0 ? {} : { request_id: requestId, requestId },
1283
+ status: finalJob.status,
1284
+ completed: finalJob.status === "completed",
1285
+ ...readiness === void 0 ? {} : { readiness: videoReadinessEvidence(readiness) },
1286
+ readiness_checked: readiness !== void 0,
1287
+ readinessChecked: readiness !== void 0,
1288
+ poll_count: wait.pollCount,
1289
+ pollCount: wait.pollCount,
1290
+ retry_count: wait.retryCount,
1291
+ retryCount: wait.retryCount,
1292
+ ...wait.latestRetryingEvent === void 0 ? {} : {
1293
+ latest_retrying_event: wait.latestRetryingEvent,
1294
+ latestRetryingEvent: wait.latestRetryingEvent
1295
+ },
1296
+ duration_ms: wait.durationMs,
1297
+ durationMs: wait.durationMs,
1298
+ ...videoUrl === void 0 ? {} : { video_url: videoUrl, videoUrl }
1299
+ };
1300
+ }
1301
+ function videoCreateResult(job, readiness) {
1302
+ const result = job;
1303
+ result.readiness_checked = readiness !== void 0;
1304
+ result.readinessChecked = readiness !== void 0;
1305
+ if (readiness !== void 0) {
1306
+ result.readiness = videoReadinessEvidence(readiness);
1307
+ }
1308
+ return result;
1309
+ }
1310
+ function videoCreditEvidence(credits) {
1311
+ if (!credits || typeof credits !== "object") return void 0;
1312
+ if (typeof credits.charged !== "number" || !Number.isFinite(credits.charged)) {
1313
+ return void 0;
1314
+ }
1315
+ return {
1316
+ charged: credits.charged,
1317
+ remaining: typeof credits.remaining === "number" && Number.isFinite(credits.remaining) ? credits.remaining : null
1318
+ };
1319
+ }
1320
+ function videoCreationCreditEvidence(job) {
1321
+ const raw = job.creationCredits ?? job.creation_credits;
1322
+ if (!raw || typeof raw !== "object") return void 0;
1323
+ if (typeof raw.charged !== "number" || !Number.isFinite(raw.charged)) {
1324
+ return void 0;
1325
+ }
1326
+ const remainingAfterDebit = raw.remainingAfterDebit ?? raw.remaining_after_debit ?? null;
1327
+ const normalizedRemainingAfterDebit = typeof remainingAfterDebit === "number" && Number.isFinite(remainingAfterDebit) ? remainingAfterDebit : null;
1328
+ return {
1329
+ charged: raw.charged,
1330
+ remaining_after_debit: normalizedRemainingAfterDebit,
1331
+ remainingAfterDebit: normalizedRemainingAfterDebit
1332
+ };
1333
+ }
1334
+ function videoReadinessEvidence(readiness) {
1335
+ const canCreate = readiness.canCreate ?? readiness.can_create;
1336
+ const requiredCredits = readiness.requiredCredits ?? readiness.required_credits;
1337
+ const creditsRemaining = readiness.creditsRemaining ?? readiness.credits_remaining;
1338
+ const concurrentJobs = readiness.concurrentJobs ?? readiness.concurrent_jobs;
1339
+ const activeJobs = readiness.activeJobs ?? readiness.active_jobs;
1340
+ const availableSlots = readiness.availableSlots ?? readiness.available_slots;
1341
+ const activeJobExpiresInSeconds = readiness.activeJobExpiresInSeconds ?? readiness.active_job_expires_in_seconds;
1342
+ const retryAfterSeconds = readiness.retryAfterSeconds ?? readiness.retryAfter ?? readiness.retry_after_seconds;
1343
+ const nextPollAt = readiness.nextPollAt ?? readiness.next_poll_at;
1344
+ return {
1345
+ ...readiness,
1346
+ can_create: canCreate,
1347
+ canCreate,
1348
+ required_credits: requiredCredits,
1349
+ requiredCredits,
1350
+ credits_remaining: creditsRemaining,
1351
+ creditsRemaining,
1352
+ ...concurrentJobs === void 0 ? {} : { concurrent_jobs: concurrentJobs, concurrentJobs },
1353
+ ...activeJobs === void 0 ? {} : { active_jobs: activeJobs, activeJobs },
1354
+ ...availableSlots === void 0 ? {} : { available_slots: availableSlots, availableSlots },
1355
+ ...activeJobExpiresInSeconds === void 0 ? {} : {
1356
+ active_job_expires_in_seconds: activeJobExpiresInSeconds,
1357
+ activeJobExpiresInSeconds
1358
+ },
1359
+ ...retryAfterSeconds === void 0 ? {} : {
1360
+ retry_after_seconds: retryAfterSeconds,
1361
+ retryAfter: readiness.retryAfter ?? retryAfterSeconds,
1362
+ retryAfterSeconds
1363
+ },
1364
+ ...nextPollAt === void 0 ? {} : { next_poll_at: nextPollAt, nextPollAt }
1365
+ };
1366
+ }
1367
+ function nonDefaultOperationId(job) {
1368
+ const operationId = job.operationId ?? job.operation_id;
1369
+ return operationId && operationId !== job.id ? operationId : void 0;
1370
+ }
1371
+ async function safeCallPuppetryAgentTool(client, name, input) {
1372
+ try {
1373
+ return {
1374
+ ok: true,
1375
+ data: await callPuppetryAgentTool(client, name, input)
1376
+ };
1377
+ } catch (err) {
1378
+ if (err instanceof PuppetryError) {
1379
+ return {
1380
+ ok: false,
1381
+ error: puppetryErrorData(err)
1382
+ };
1383
+ }
1384
+ return {
1385
+ ok: false,
1386
+ error: {
1387
+ status: 500,
1388
+ statusCode: 500,
1389
+ code: "internal_error",
1390
+ message: err instanceof Error ? err.message : "Internal error"
1391
+ }
1392
+ };
1393
+ }
1394
+ }
1395
+
1396
+ // src/mcp.ts
1397
+ var SERVER_INFO = {
1398
+ name: "puppetry",
1399
+ version: "0.1.0"
1400
+ };
1401
+ var TOOL_NAMES = new Set(
1402
+ PUPPETRY_AGENT_TOOLS.map((tool) => tool.name)
1403
+ );
1404
+ async function handlePuppetryMcpRequest(client, request) {
1405
+ if (request.id === void 0 && request.method === "notifications/initialized") {
1406
+ return null;
1407
+ }
1408
+ try {
1409
+ switch (request.method) {
1410
+ case "initialize":
1411
+ return success(request.id, {
1412
+ protocolVersion: requestedProtocolVersion(request.params),
1413
+ capabilities: { tools: {} },
1414
+ serverInfo: SERVER_INFO
1415
+ });
1416
+ case "ping":
1417
+ return success(request.id, {});
1418
+ case "tools/list":
1419
+ return success(request.id, {
1420
+ tools: PUPPETRY_AGENT_TOOLS.map(
1421
+ ({ name, description, inputSchema }) => ({
1422
+ name,
1423
+ description,
1424
+ inputSchema
1425
+ })
1426
+ )
1427
+ });
1428
+ case "tools/call":
1429
+ return success(request.id, await callTool(client, request.params));
1430
+ default:
1431
+ return error(request.id, -32601, `Method not found: ${request.method}`);
1432
+ }
1433
+ } catch (err) {
1434
+ if (err instanceof PuppetryError) {
1435
+ return error(request.id, -32603, err.message, puppetryErrorData(err));
1436
+ }
1437
+ return error(
1438
+ request.id,
1439
+ -32603,
1440
+ err instanceof Error ? err.message : "Internal error"
1441
+ );
1442
+ }
1443
+ }
1444
+ async function callTool(client, params) {
1445
+ if (!isObject(params) || typeof params.name !== "string") {
1446
+ throw new Error("tools/call requires a tool name");
1447
+ }
1448
+ if (!TOOL_NAMES.has(params.name)) {
1449
+ throw new Error(`Unsupported Puppetry MCP tool: ${params.name}`);
1450
+ }
1451
+ const result = await callPuppetryAgentTool(
1452
+ client,
1453
+ params.name,
1454
+ isObject(params.arguments) ? params.arguments : {}
1455
+ );
1456
+ return {
1457
+ content: [
1458
+ {
1459
+ type: "text",
1460
+ text: JSON.stringify(result, null, 2)
1461
+ }
1462
+ ]
1463
+ };
1464
+ }
1465
+ function requestedProtocolVersion(params) {
1466
+ if (isObject(params) && typeof params.protocolVersion === "string") {
1467
+ return params.protocolVersion;
1468
+ }
1469
+ return "2024-11-05";
1470
+ }
1471
+ function success(id, result) {
1472
+ return {
1473
+ jsonrpc: "2.0",
1474
+ id: id ?? null,
1475
+ result
1476
+ };
1477
+ }
1478
+ function error(id, code, message, data) {
1479
+ return {
1480
+ jsonrpc: "2.0",
1481
+ id: id ?? null,
1482
+ error: data === void 0 ? { code, message } : { code, message, data }
1483
+ };
1484
+ }
1485
+ function isObject(value) {
1486
+ return typeof value === "object" && value !== null && !Array.isArray(value);
1487
+ }
1488
+
1489
+ export {
1490
+ PuppetryError,
1491
+ PuppetryTimeoutError,
1492
+ PuppetryAuthError,
1493
+ PuppetryRateLimitError,
1494
+ PuppetryNetworkError,
1495
+ puppetryErrorData,
1496
+ PUPPETRY_AGENT_TOOLS,
1497
+ callPuppetryAgentTool,
1498
+ safeCallPuppetryAgentTool,
1499
+ handlePuppetryMcpRequest
1500
+ };