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