vidspotai-shared 1.0.94 → 1.0.96

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.
Files changed (136) hide show
  1. package/lib/globals/aiModels/enums.d.ts +2 -0
  2. package/lib/globals/aiModels/enums.d.ts.map +1 -1
  3. package/lib/globals/aiModels/enums.js +5 -0
  4. package/lib/globals/aiModels/index.d.ts.map +1 -1
  5. package/lib/globals/aiModels/index.js +2 -0
  6. package/lib/globals/aiModels/providers/hostedAvatars.d.ts +22 -0
  7. package/lib/globals/aiModels/providers/hostedAvatars.d.ts.map +1 -0
  8. package/lib/globals/aiModels/providers/hostedAvatars.js +129 -0
  9. package/lib/globals/types.d.ts +58 -1
  10. package/lib/globals/types.d.ts.map +1 -1
  11. package/lib/globals/types.js +61 -1
  12. package/lib/models/demoVideoProject.model.d.ts +244 -0
  13. package/lib/models/demoVideoProject.model.d.ts.map +1 -0
  14. package/lib/models/demoVideoProject.model.js +2 -0
  15. package/lib/models/githubConnection.model.d.ts +35 -0
  16. package/lib/models/githubConnection.model.d.ts.map +1 -0
  17. package/lib/models/githubConnection.model.js +2 -0
  18. package/lib/models/index.d.ts +3 -0
  19. package/lib/models/index.d.ts.map +1 -1
  20. package/lib/models/index.js +3 -0
  21. package/lib/models/outreach.model.d.ts +175 -0
  22. package/lib/models/outreach.model.d.ts.map +1 -0
  23. package/lib/models/outreach.model.js +2 -0
  24. package/lib/models/video.model.d.ts +4 -0
  25. package/lib/models/video.model.d.ts.map +1 -1
  26. package/lib/schemas/brandKit.schema.d.ts +4 -0
  27. package/lib/schemas/brandKit.schema.d.ts.map +1 -1
  28. package/lib/schemas/brandKit.schema.js +10 -0
  29. package/lib/schemas/demoQuestion.schema.d.ts +286 -0
  30. package/lib/schemas/demoQuestion.schema.d.ts.map +1 -0
  31. package/lib/schemas/demoQuestion.schema.js +210 -0
  32. package/lib/schemas/demoSpec.schema.d.ts +109 -6
  33. package/lib/schemas/demoSpec.schema.d.ts.map +1 -1
  34. package/lib/schemas/demoSpec.schema.js +95 -7
  35. package/lib/schemas/index.d.ts +1 -0
  36. package/lib/schemas/index.d.ts.map +1 -1
  37. package/lib/schemas/index.js +1 -0
  38. package/lib/schemas/videoPlan.schema.d.ts +2 -2
  39. package/lib/schemas/videoPlan.schema.d.ts.map +1 -1
  40. package/lib/schemas/videoPlan.schema.js +11 -1
  41. package/lib/services/agent/providerFallback/chains.d.ts.map +1 -1
  42. package/lib/services/agent/providerFallback/chains.js +9 -1
  43. package/lib/services/agent/taskPoller.d.ts.map +1 -1
  44. package/lib/services/agent/taskPoller.js +17 -6
  45. package/lib/services/agent/tools/generateAvatarVideo.tool.d.ts +21 -9
  46. package/lib/services/agent/tools/generateAvatarVideo.tool.d.ts.map +1 -1
  47. package/lib/services/agent/tools/generateAvatarVideo.tool.js +135 -39
  48. package/lib/services/agent/tools/planVideo.tool.d.ts +2 -2
  49. package/lib/services/aiGen/aiGenFactory.service.d.ts +1 -1
  50. package/lib/services/aiGen/aiGenFactory.service.d.ts.map +1 -1
  51. package/lib/services/aiGen/aiGenFactory.service.js +10 -2
  52. package/lib/services/aiGen/helpers.d.ts.map +1 -1
  53. package/lib/services/aiGen/helpers.js +12 -2
  54. package/lib/services/aiGen/providers/kling/kling.service.d.ts.map +1 -1
  55. package/lib/services/aiGen/providers/kling/kling.service.js +47 -8
  56. package/lib/services/aiGen/providers/pixverse/pixverse.service.d.ts +8 -0
  57. package/lib/services/aiGen/providers/pixverse/pixverse.service.d.ts.map +1 -1
  58. package/lib/services/aiGen/providers/pixverse/pixverse.service.js +55 -2
  59. package/lib/services/avatarGen/IAvatarVideoProvider.d.ts +136 -0
  60. package/lib/services/avatarGen/IAvatarVideoProvider.d.ts.map +1 -0
  61. package/lib/services/avatarGen/IAvatarVideoProvider.js +42 -0
  62. package/lib/services/avatarGen/avatarProviderFactory.d.ts +18 -0
  63. package/lib/services/avatarGen/avatarProviderFactory.d.ts.map +1 -0
  64. package/lib/services/avatarGen/avatarProviderFactory.js +54 -0
  65. package/lib/services/avatarGen/index.d.ts +6 -0
  66. package/lib/services/avatarGen/index.d.ts.map +1 -0
  67. package/lib/services/avatarGen/index.js +21 -0
  68. package/lib/services/avatarGen/providers/heygenAvatarProvider.d.ts +45 -0
  69. package/lib/services/avatarGen/providers/heygenAvatarProvider.d.ts.map +1 -0
  70. package/lib/services/avatarGen/providers/heygenAvatarProvider.js +190 -0
  71. package/lib/services/avatarGen/providers/klingAvatarProvider.d.ts +32 -0
  72. package/lib/services/avatarGen/providers/klingAvatarProvider.d.ts.map +1 -0
  73. package/lib/services/avatarGen/providers/klingAvatarProvider.js +69 -0
  74. package/lib/services/avatarGen/providers/tavusAvatarProvider.d.ts +56 -0
  75. package/lib/services/avatarGen/providers/tavusAvatarProvider.d.ts.map +1 -0
  76. package/lib/services/avatarGen/providers/tavusAvatarProvider.js +183 -0
  77. package/lib/services/demo/demoAuthor.d.ts +45 -0
  78. package/lib/services/demo/demoAuthor.d.ts.map +1 -0
  79. package/lib/services/demo/demoAuthor.js +75 -0
  80. package/lib/services/demo/demoAuthorNormalize.d.ts +49 -0
  81. package/lib/services/demo/demoAuthorNormalize.d.ts.map +1 -0
  82. package/lib/services/demo/demoAuthorNormalize.js +327 -0
  83. package/lib/services/demo/demoAuthorPrompt.d.ts +102 -0
  84. package/lib/services/demo/demoAuthorPrompt.d.ts.map +1 -0
  85. package/lib/services/demo/demoAuthorPrompt.js +243 -0
  86. package/lib/services/demo/demoCredits.d.ts +20 -0
  87. package/lib/services/demo/demoCredits.d.ts.map +1 -0
  88. package/lib/services/demo/demoCredits.js +51 -0
  89. package/lib/services/demo/demoMediaGuard.d.ts +43 -0
  90. package/lib/services/demo/demoMediaGuard.d.ts.map +1 -0
  91. package/lib/services/demo/demoMediaGuard.js +207 -0
  92. package/lib/services/demo/demoMusic.d.ts +13 -0
  93. package/lib/services/demo/demoMusic.d.ts.map +1 -0
  94. package/lib/services/demo/demoMusic.js +93 -0
  95. package/lib/services/demo/demoPrefill.d.ts +76 -0
  96. package/lib/services/demo/demoPrefill.d.ts.map +1 -0
  97. package/lib/services/demo/demoPrefill.js +435 -0
  98. package/lib/services/demo/demoRevisePrompt.d.ts +17 -0
  99. package/lib/services/demo/demoRevisePrompt.d.ts.map +1 -0
  100. package/lib/services/demo/demoRevisePrompt.js +85 -0
  101. package/lib/services/demo/demoReviser.d.ts +63 -0
  102. package/lib/services/demo/demoReviser.d.ts.map +1 -0
  103. package/lib/services/demo/demoReviser.js +81 -0
  104. package/lib/services/demo/demoScriptPrompt.d.ts +63 -0
  105. package/lib/services/demo/demoScriptPrompt.d.ts.map +1 -0
  106. package/lib/services/demo/demoScriptPrompt.js +234 -0
  107. package/lib/services/demo/demoScriptWriter.d.ts +65 -0
  108. package/lib/services/demo/demoScriptWriter.d.ts.map +1 -0
  109. package/lib/services/demo/demoScriptWriter.js +211 -0
  110. package/lib/services/demo/demoTriage.d.ts +65 -0
  111. package/lib/services/demo/demoTriage.d.ts.map +1 -0
  112. package/lib/services/demo/demoTriage.js +130 -0
  113. package/lib/services/demo/githubOAuth.d.ts +78 -0
  114. package/lib/services/demo/githubOAuth.d.ts.map +1 -0
  115. package/lib/services/demo/githubOAuth.js +209 -0
  116. package/lib/services/demo/githubOAuthState.d.ts +10 -0
  117. package/lib/services/demo/githubOAuthState.d.ts.map +1 -0
  118. package/lib/services/demo/githubOAuthState.js +63 -0
  119. package/lib/services/demo/index.d.ts +24 -0
  120. package/lib/services/demo/index.d.ts.map +1 -0
  121. package/lib/services/demo/index.js +39 -0
  122. package/lib/services/firestore.service.d.ts +11 -0
  123. package/lib/services/firestore.service.d.ts.map +1 -1
  124. package/lib/services/firestore.service.js +24 -0
  125. package/lib/services/index.d.ts +2 -0
  126. package/lib/services/index.d.ts.map +1 -1
  127. package/lib/services/index.js +2 -0
  128. package/lib/services/tts/providers/elevenlabs.service.d.ts.map +1 -1
  129. package/lib/services/tts/providers/elevenlabs.service.js +16 -8
  130. package/lib/utils/index.d.ts +1 -0
  131. package/lib/utils/index.d.ts.map +1 -1
  132. package/lib/utils/index.js +1 -0
  133. package/lib/utils/outreachTemplate.d.ts +46 -0
  134. package/lib/utils/outreachTemplate.d.ts.map +1 -0
  135. package/lib/utils/outreachTemplate.js +174 -0
  136. package/package.json +1 -1
@@ -0,0 +1,56 @@
1
+ import { EVideoGenModels } from "../../../globals/aiModels";
2
+ import { AvatarCapabilities, AvatarGenerateRequest, AvatarOption, AvatarStatusQuery, AvatarStatusResult, AvatarSubmitResult, ConsentRecord, EAvatarEngine, IAvatarVideoProvider, ISupportsHostedCatalog, ISupportsReplica, VoiceOption } from "../IAvatarVideoProvider";
3
+ /**
4
+ * Tavus avatar engine — a HOSTED engine driven by a trained "replica"
5
+ * (Tavus's term for a likeness model). The caller supplies a replica_id + a
6
+ * script; Tavus synthesizes the voice (the replica's cloned voice) and lipsyncs
7
+ * natively. Tavus's differentiator is multilingual / dubbing — see the dubbing
8
+ * note at the bottom of this class.
9
+ *
10
+ * Contract (Tavus API, verified 2026-06-26 against docs.tavus.io):
11
+ * • submit : POST /v2/videos { replica_id, script, video_name? }
12
+ * → { video_id, status, hosted_url }
13
+ * • status : GET /v2/videos/{id} → { status: queued|generating|ready|
14
+ * deleted|error, download_url,
15
+ * stream_url, hosted_url, status_details }
16
+ * • replicas: POST /v2/replicas { train_video_url, consent_video_url?,
17
+ * replica_name, callback_url? }
18
+ * → { replica_id, status }
19
+ * GET /v2/replicas → { data: [{ replica_id, replica_name,
20
+ * status, thumbnail_video_url }] }
21
+ * • auth : x-api-key header
22
+ *
23
+ * For Tavus the hosted "avatar" IS the replica, so a hosted request maps
24
+ * `hostedAvatarId` → `replica_id` (`hostedVoiceId` is unused; the replica owns
25
+ * its voice). Standalone class — Tavus has no place in the generic video
26
+ * factory; avatar gen is its own concern (see IAvatarVideoProvider).
27
+ */
28
+ export declare class TavusAvatarProvider implements IAvatarVideoProvider, ISupportsHostedCatalog, ISupportsReplica {
29
+ private readonly modelKey;
30
+ /** Static so callers can branch on capability without constructing (which
31
+ * would require TAVUS_API_KEY just to read the input mode). */
32
+ static readonly CAPABILITIES: AvatarCapabilities;
33
+ readonly engine = EAvatarEngine.TAVUS;
34
+ readonly capabilities: AvatarCapabilities;
35
+ private readonly baseUrl;
36
+ private readonly apiKey;
37
+ private readonly submitTimeout;
38
+ private readonly statusTimeout;
39
+ constructor(modelKey?: EVideoGenModels);
40
+ generate(req: AvatarGenerateRequest): Promise<AvatarSubmitResult>;
41
+ checkStatus(query: AvatarStatusQuery): Promise<AvatarStatusResult>;
42
+ createReplica(trainingMediaUrl: string, consent: ConsentRecord): Promise<{
43
+ replicaId: string;
44
+ }>;
45
+ /** For Tavus the catalog of "avatars" is the account's trained replicas. */
46
+ listAvatars(): Promise<AvatarOption[]>;
47
+ /**
48
+ * Tavus voices are bound to the replica (its cloned voice), so there is no
49
+ * standalone voice catalog to pick from — return empty. Hosted requests leave
50
+ * `hostedVoiceId` unused for Tavus.
51
+ */
52
+ listVoices(): Promise<VoiceOption[]>;
53
+ private request;
54
+ private requestWithRetry;
55
+ }
56
+ //# sourceMappingURL=tavusAvatarProvider.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tavusAvatarProvider.d.ts","sourceRoot":"","sources":["../../../../src/services/avatarGen/providers/tavusAvatarProvider.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,eAAe,EAAE,MAAM,2BAA2B,CAAC;AAG5D,OAAO,EACL,kBAAkB,EAClB,qBAAqB,EACrB,YAAY,EACZ,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,aAAa,EACb,aAAa,EACb,oBAAoB,EACpB,sBAAsB,EACtB,gBAAgB,EAChB,WAAW,EACZ,MAAM,yBAAyB,CAAC;AAEjC;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,qBAAa,mBACX,YAAW,oBAAoB,EAAE,sBAAsB,EAAE,gBAAgB;IAmBvE,OAAO,CAAC,QAAQ,CAAC,QAAQ;IAjB3B;oEACgE;IAChE,MAAM,CAAC,QAAQ,CAAC,YAAY,EAAE,kBAAkB,CAI9C;IAEF,QAAQ,CAAC,MAAM,uBAAuB;IACtC,QAAQ,CAAC,YAAY,qBAAoC;IAEzD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAA0B;IAClD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAS;IAChC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAW;IACzC,OAAO,CAAC,QAAQ,CAAC,aAAa,CAAU;gBAGrB,QAAQ,GAAE,eAA8C;IAQrE,QAAQ,CAAC,GAAG,EAAE,qBAAqB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IA4BjE,WAAW,CAAC,KAAK,EAAE,iBAAiB,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAiClE,aAAa,CACjB,gBAAgB,EAAE,MAAM,EACxB,OAAO,EAAE,aAAa,GACrB,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,CAAA;KAAE,CAAC;IA2BjC,4EAA4E;IACtE,WAAW,IAAI,OAAO,CAAC,YAAY,EAAE,CAAC;IAgB5C;;;;OAIG;IACG,UAAU,IAAI,OAAO,CAAC,WAAW,EAAE,CAAC;YAM5B,OAAO;YA0BP,gBAAgB;CAiE/B"}
@@ -0,0 +1,183 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.TavusAvatarProvider = void 0;
7
+ const axios_1 = __importDefault(require("axios"));
8
+ const aiModels_1 = require("../../../globals/aiModels");
9
+ const types_1 = require("../../../globals/types");
10
+ const logger_1 = require("../../../utils/logger");
11
+ const IAvatarVideoProvider_1 = require("../IAvatarVideoProvider");
12
+ /**
13
+ * Tavus avatar engine — a HOSTED engine driven by a trained "replica"
14
+ * (Tavus's term for a likeness model). The caller supplies a replica_id + a
15
+ * script; Tavus synthesizes the voice (the replica's cloned voice) and lipsyncs
16
+ * natively. Tavus's differentiator is multilingual / dubbing — see the dubbing
17
+ * note at the bottom of this class.
18
+ *
19
+ * Contract (Tavus API, verified 2026-06-26 against docs.tavus.io):
20
+ * • submit : POST /v2/videos { replica_id, script, video_name? }
21
+ * → { video_id, status, hosted_url }
22
+ * • status : GET /v2/videos/{id} → { status: queued|generating|ready|
23
+ * deleted|error, download_url,
24
+ * stream_url, hosted_url, status_details }
25
+ * • replicas: POST /v2/replicas { train_video_url, consent_video_url?,
26
+ * replica_name, callback_url? }
27
+ * → { replica_id, status }
28
+ * GET /v2/replicas → { data: [{ replica_id, replica_name,
29
+ * status, thumbnail_video_url }] }
30
+ * • auth : x-api-key header
31
+ *
32
+ * For Tavus the hosted "avatar" IS the replica, so a hosted request maps
33
+ * `hostedAvatarId` → `replica_id` (`hostedVoiceId` is unused; the replica owns
34
+ * its voice). Standalone class — Tavus has no place in the generic video
35
+ * factory; avatar gen is its own concern (see IAvatarVideoProvider).
36
+ */
37
+ class TavusAvatarProvider {
38
+ constructor(modelKey = aiModels_1.EVideoGenModels.TAVUS_AVATAR) {
39
+ this.modelKey = modelKey;
40
+ this.engine = IAvatarVideoProvider_1.EAvatarEngine.TAVUS;
41
+ this.capabilities = TavusAvatarProvider.CAPABILITIES;
42
+ this.baseUrl = "https://tavusapi.com";
43
+ this.submitTimeout = 120000;
44
+ this.statusTimeout = 60000;
45
+ if (!process.env.TAVUS_API_KEY) {
46
+ throw new Error("Missing TAVUS_API_KEY in environment variables");
47
+ }
48
+ this.apiKey = process.env.TAVUS_API_KEY;
49
+ }
50
+ async generate(req) {
51
+ if (req.mode !== "hosted") {
52
+ throw new Error(`TavusAvatarProvider only supports hosted requests (got "${req.mode}")`);
53
+ }
54
+ const body = {
55
+ replica_id: req.hostedAvatarId, // Tavus: the hosted avatar IS the replica
56
+ script: req.script,
57
+ video_name: `vidspot-${req.hostedAvatarId}-${req.script.slice(0, 24)}`,
58
+ };
59
+ const data = await this.request("/v2/videos", "POST", body, this.submitTimeout);
60
+ const videoId = data?.video_id;
61
+ if (!videoId) {
62
+ throw new Error(`Tavus submit returned no video_id: ${JSON.stringify(data?.message ?? data)}`);
63
+ }
64
+ return { providerTaskId: videoId };
65
+ }
66
+ async checkStatus(query) {
67
+ const data = await this.requestWithRetry(`/v2/videos/${encodeURIComponent(query.providerTaskId)}`, "GET", undefined, this.statusTimeout);
68
+ // Tavus status enum: queued | generating | ready | deleted | error.
69
+ if (data?.status === "ready") {
70
+ return {
71
+ status: types_1.EVideoSceneStatus.COMPLETED,
72
+ // Prefer the direct download URL; fall back to stream/hosted.
73
+ videoUrl: data.download_url ?? data.stream_url ?? data.hosted_url,
74
+ };
75
+ }
76
+ if (data?.status === "error" || data?.status === "deleted") {
77
+ return {
78
+ status: types_1.EVideoSceneStatus.FAILED,
79
+ errorMessage: data.status_details ?? `Tavus render ${data.status}`,
80
+ };
81
+ }
82
+ return { status: types_1.EVideoSceneStatus.PENDING };
83
+ }
84
+ // ─── ISupportsReplica ─────────────────────────────────────────────────────
85
+ async createReplica(trainingMediaUrl, consent) {
86
+ const body = {
87
+ train_video_url: trainingMediaUrl,
88
+ replica_name: `vidspot-${consent.userId}-${consent.capturedAt}`,
89
+ // Tavus accepts a separate consent clip; we pass the same training media
90
+ // when no dedicated consent video exists (the statement is recorded in
91
+ // our own ConsentRecord audit trail regardless).
92
+ consent_video_url: trainingMediaUrl,
93
+ };
94
+ const data = await this.request("/v2/replicas", "POST", body, this.submitTimeout);
95
+ if (!data?.replica_id) {
96
+ throw new Error(`Tavus createReplica returned no replica_id: ${JSON.stringify(data)}`);
97
+ }
98
+ return { replicaId: data.replica_id };
99
+ }
100
+ // ─── ISupportsHostedCatalog ───────────────────────────────────────────────
101
+ /** For Tavus the catalog of "avatars" is the account's trained replicas. */
102
+ async listAvatars() {
103
+ const data = await this.requestWithRetry("/v2/replicas", "GET", undefined, this.statusTimeout);
104
+ return (data?.data ?? []).map((r) => ({
105
+ id: r.replica_id,
106
+ name: r.replica_name ?? r.replica_id,
107
+ previewUrl: r.thumbnail_video_url,
108
+ }));
109
+ }
110
+ /**
111
+ * Tavus voices are bound to the replica (its cloned voice), so there is no
112
+ * standalone voice catalog to pick from — return empty. Hosted requests leave
113
+ * `hostedVoiceId` unused for Tavus.
114
+ */
115
+ async listVoices() {
116
+ return [];
117
+ }
118
+ // ─── Transport ────────────────────────────────────────────────────────────
119
+ async request(endpoint, method, body, timeout = this.submitTimeout) {
120
+ const config = {
121
+ method,
122
+ url: `${this.baseUrl}${endpoint}`,
123
+ headers: {
124
+ "x-api-key": this.apiKey,
125
+ "Content-Type": "application/json",
126
+ },
127
+ timeout,
128
+ data: body,
129
+ };
130
+ const response = await axios_1.default.request(config);
131
+ if (response.status < 200 || response.status >= 300) {
132
+ throw new Error(`Tavus API Error: ${response.status} ${response.statusText} — ${JSON.stringify(response.data)}`);
133
+ }
134
+ return response.data;
135
+ }
136
+ async requestWithRetry(endpoint, method, body, timeout = this.statusTimeout, maxAttempts = 4) {
137
+ for (let attempt = 1; attempt <= maxAttempts; attempt++) {
138
+ try {
139
+ return await this.request(endpoint, method, body, timeout);
140
+ }
141
+ catch (err) {
142
+ const e = err;
143
+ const httpStatus = e.response?.status;
144
+ const isTimeout = e.code === "ECONNABORTED" || (e.message?.includes("timeout") ?? false);
145
+ const isNetworkError = e.code === "ECONNRESET" ||
146
+ e.code === "ECONNREFUSED" ||
147
+ e.code === "ENOTFOUND" ||
148
+ e.code === "ERR_NETWORK";
149
+ const isRateLimit = httpStatus === 429;
150
+ const isRetryable = isTimeout || isNetworkError || isRateLimit;
151
+ if (!isRetryable || attempt === maxAttempts) {
152
+ logger_1.logger.error("Tavus request failed (non-retryable or max attempts)", {
153
+ endpoint,
154
+ attempt,
155
+ maxAttempts,
156
+ httpStatus,
157
+ errorCode: e.code,
158
+ errorMessage: e.message,
159
+ });
160
+ throw err;
161
+ }
162
+ const backoffMs = isRateLimit ? 10000 : 1000;
163
+ logger_1.logger.warn("Tavus request failed — retrying", {
164
+ endpoint,
165
+ attempt,
166
+ maxAttempts,
167
+ httpStatus,
168
+ backoffMs,
169
+ });
170
+ await new Promise((r) => setTimeout(r, backoffMs));
171
+ }
172
+ }
173
+ throw new Error("Unreachable");
174
+ }
175
+ }
176
+ exports.TavusAvatarProvider = TavusAvatarProvider;
177
+ /** Static so callers can branch on capability without constructing (which
178
+ * would require TAVUS_API_KEY just to read the input mode). */
179
+ TavusAvatarProvider.CAPABILITIES = {
180
+ inputMode: "hosted",
181
+ nativeTts: true,
182
+ multiSceneSplit: false,
183
+ };
@@ -0,0 +1,45 @@
1
+ import { LlmCaller } from "../agent/llmCaller";
2
+ import { ModelChoice, ModelRouter } from "../agent/modelRouter";
3
+ import { DemoAuthorInput } from "./demoAuthorPrompt";
4
+ import { NormalizeResult } from "./demoAuthorNormalize";
5
+ export interface DemoAuthorDeps {
6
+ /** LLM caller. Defaults to the host-wired dispatcher. */
7
+ llm?: LlmCaller;
8
+ /** Model router. Defaults to DEFAULT_MODEL_ROUTING. */
9
+ router?: ModelRouter;
10
+ /** Route the planner to the premium tier (Opus) for higher-fidelity authoring. */
11
+ premium?: boolean;
12
+ /** Sampling temperature. Creative-but-structured default. */
13
+ temperature?: number;
14
+ /** Max output tokens — a full DemoSpec with rich scenes can be large. */
15
+ maxTokens?: number;
16
+ /**
17
+ * Allow the planner to propose Layer-B `custom` scenes (with an `intent`
18
+ * brief). Threaded from the worker's `DEMO_CODEGEN_ENABLED` gate; default
19
+ * false, so the author never emits a `custom` scene the pipeline can't fill.
20
+ */
21
+ allowCustomScenes?: boolean;
22
+ /**
23
+ * Allow the planner to commission AI-generated media (`generatedAssets` +
24
+ * `gen://` refs). Default true; the worker passes false only under the
25
+ * DEMO_GEN_ASSETS_DISABLED kill-switch.
26
+ */
27
+ allowGeneratedAssets?: boolean;
28
+ }
29
+ export interface DemoAuthorResult extends NormalizeResult {
30
+ /** Model that produced the spec (primary or fallback). */
31
+ modelUsed: ModelChoice;
32
+ usedFallback?: boolean;
33
+ usage?: {
34
+ promptTokens?: number;
35
+ completionTokens?: number;
36
+ };
37
+ }
38
+ /**
39
+ * Author a render-ready DemoSpec from inputs. Pure orchestration: build the
40
+ * prompt, attach screenshots as vision, call `.structured(DemoSpec)`, then
41
+ * normalize. Throws if the caller is unconfigured or the model returns an
42
+ * unparseable / scene-less spec (the normalize pass is the last guard).
43
+ */
44
+ export declare function authorDemoSpec(input: DemoAuthorInput, deps?: DemoAuthorDeps): Promise<DemoAuthorResult>;
45
+ //# sourceMappingURL=demoAuthor.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"demoAuthor.d.ts","sourceRoot":"","sources":["../../../src/services/demo/demoAuthor.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAE/C,OAAO,EAAE,WAAW,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AAChE,OAAO,EACL,eAAe,EAGhB,MAAM,oBAAoB,CAAC;AAC5B,OAAO,EAAE,eAAe,EAAqB,MAAM,uBAAuB,CAAC;AAqB3E,MAAM,WAAW,cAAc;IAC7B,yDAAyD;IACzD,GAAG,CAAC,EAAE,SAAS,CAAC;IAChB,uDAAuD;IACvD,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,kFAAkF;IAClF,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,6DAA6D;IAC7D,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yEAAyE;IACzE,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B;;;;OAIG;IACH,oBAAoB,CAAC,EAAE,OAAO,CAAC;CAChC;AAED,MAAM,WAAW,gBAAiB,SAAQ,eAAe;IACvD,0DAA0D;IAC1D,SAAS,EAAE,WAAW,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,KAAK,CAAC,EAAE;QAAE,YAAY,CAAC,EAAE,MAAM,CAAC;QAAC,gBAAgB,CAAC,EAAE,MAAM,CAAA;KAAE,CAAC;CAC9D;AAED;;;;;GAKG;AACH,wBAAsB,cAAc,CAClC,KAAK,EAAE,eAAe,EACtB,IAAI,GAAE,cAAmB,GACxB,OAAO,CAAC,gBAAgB,CAAC,CAgD3B"}
@@ -0,0 +1,75 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.authorDemoSpec = authorDemoSpec;
4
+ const demoSpec_schema_1 = require("../../schemas/demoSpec.schema");
5
+ const llmCallerRegistry_1 = require("../agent/llmCallerRegistry");
6
+ const modelRouter_1 = require("../agent/modelRouter");
7
+ const demoAuthorPrompt_1 = require("./demoAuthorPrompt");
8
+ const demoAuthorNormalize_1 = require("./demoAuthorNormalize");
9
+ /**
10
+ * DemoSpec author — the "plan" stage of the SaaS Demo Video pipeline (plan
11
+ * Phase 3 / §4 stage 2).
12
+ *
13
+ * ONE Claude `.structured<DemoSpec>()` call turns the user's product facts +
14
+ * brand tokens + product screenshots (as vision) + wizard answers into a valid,
15
+ * render-ready DemoSpec that the Layer-A engine renders to MP4. This is the
16
+ * equivalent of the agent Planner (`bibleBuilder`/`planner`) but for the demo
17
+ * generator: provider-agnostic (injected `LlmCaller`), model-routed, and
18
+ * hardened by a deterministic normalize pass (see demoAuthorNormalize.ts) that
19
+ * enforces the invariants a prompt can only request.
20
+ *
21
+ * The orchestration worker (Phase 4) calls `authorDemoSpec` at the plan stage;
22
+ * the returned `spec` is persisted on `demoVideoProjects.demoSpec` and rendered.
23
+ */
24
+ /** Cap screenshots sent as vision (and thus citable) to bound token cost (plan §10). */
25
+ const MAX_VISION_SCREENSHOTS = 6;
26
+ /**
27
+ * Author a render-ready DemoSpec from inputs. Pure orchestration: build the
28
+ * prompt, attach screenshots as vision, call `.structured(DemoSpec)`, then
29
+ * normalize. Throws if the caller is unconfigured or the model returns an
30
+ * unparseable / scene-less spec (the normalize pass is the last guard).
31
+ */
32
+ async function authorDemoSpec(input, deps = {}) {
33
+ const llm = deps.llm ?? (0, llmCallerRegistry_1.getLlmCaller)();
34
+ const router = deps.router ?? new modelRouter_1.ModelRouter();
35
+ const model = router.pickFor("planner", { premium: deps.premium });
36
+ const fallbackModel = router.fallbackFor("planner");
37
+ // Cap the screenshot set BEFORE prompting so the citable list matches exactly
38
+ // what the model can see (never advertise a URL we didn't attach as vision).
39
+ const visionScreenshots = (input.screenshotUrls ?? []).slice(0, MAX_VISION_SCREENSHOTS);
40
+ const cappedInput = {
41
+ ...input,
42
+ screenshotUrls: visionScreenshots.length ? visionScreenshots : undefined,
43
+ };
44
+ const system = (0, demoAuthorPrompt_1.buildDemoAuthorSystemPrompt)({
45
+ allowCustomScenes: deps.allowCustomScenes,
46
+ allowGeneratedAssets: deps.allowGeneratedAssets,
47
+ });
48
+ const userText = (0, demoAuthorPrompt_1.buildDemoAuthorUserText)(cappedInput);
49
+ const result = await llm.structured({
50
+ model,
51
+ fallbackModel,
52
+ messages: [
53
+ { role: "system", content: system },
54
+ {
55
+ role: "user",
56
+ content: userText,
57
+ imageUrls: visionScreenshots.length ? visionScreenshots : undefined,
58
+ },
59
+ ],
60
+ schema: demoSpec_schema_1.DemoSpecSchema,
61
+ schemaName: "DemoSpec",
62
+ temperature: deps.temperature ?? 0.5,
63
+ maxTokens: deps.maxTokens ?? 8000,
64
+ });
65
+ // The caller already validated against DemoSpecSchema; parse again defensively
66
+ // to get a concrete typed value before the deterministic normalize pass.
67
+ const raw = demoSpec_schema_1.DemoSpecSchema.parse(result.data);
68
+ const normalized = (0, demoAuthorNormalize_1.normalizeDemoSpec)(raw, cappedInput);
69
+ return {
70
+ ...normalized,
71
+ modelUsed: result.usedFallback && fallbackModel ? fallbackModel : model,
72
+ usedFallback: result.usedFallback,
73
+ usage: result.usage,
74
+ };
75
+ }
@@ -0,0 +1,49 @@
1
+ import { DemoScene, DemoSpec } from "../../schemas/demoSpec.schema";
2
+ import { DemoAuthorInput } from "./demoAuthorPrompt";
3
+ /**
4
+ * Deterministic post-processing for the authored DemoSpec (plan Phase 3).
5
+ *
6
+ * The prompt REQUESTS these invariants; this pass GUARANTEES them, because an
7
+ * LLM can (and occasionally will) drift on exactly the things that break a
8
+ * render or the brand:
9
+ * 1. Wizard pins — any axis the user explicitly locked wins over the model's pick.
10
+ * 2. Screenshot URLs — the model may only cite real uploaded URLs; anything else
11
+ * is stripped (and screenshot-only scenes with no valid URL are dropped).
12
+ * 3. Brand colors — forced back to the user's tokens (copy is the model's, palette isn't).
13
+ * 4. Duration budget — total timeline scaled to land inside the target window.
14
+ * 5. Structural — >=1 scene, correct productName, schema-valid (defaults applied).
15
+ *
16
+ * Everything here is pure + typed (no `any`), so it's unit-testable without an LLM.
17
+ */
18
+ export interface NormalizeResult {
19
+ spec: DemoSpec;
20
+ /** Human-readable notes on what the normalize pass changed (for logs/observability). */
21
+ adjustments: string[];
22
+ }
23
+ /** Hard caps on planner-requested AI media per spec (cost + wall-clock bound). */
24
+ export declare const DEMO_GEN_ASSET_MAX_IMAGES = 4;
25
+ export declare const DEMO_GEN_ASSET_MAX_VIDEOS = 1;
26
+ /** Is this URL-slot value a reference to a declared generated asset? */
27
+ export declare function isGenAssetRef(url: string | undefined): url is string;
28
+ /** `gen://hero-shot` → `hero-shot` (undefined when not a gen ref). */
29
+ export declare function genAssetIdFromRef(url: string): string;
30
+ export interface GenAssetCitations {
31
+ /** Asset ids cited via `gen://<id>`. */
32
+ ids: Set<string>;
33
+ /** Raw string values cited in media slots — lets a READY asset that scenes
34
+ * now cite by its resolved URL still count as referenced. */
35
+ urls: Set<string>;
36
+ }
37
+ /** Every `gen://` ref AND every raw media string cited anywhere in a scene list
38
+ * (typed media slots + custom-scene prop bags, walked deeply so codegen props
39
+ * count as usage). */
40
+ export declare function collectGenAssetRefs(scenes: DemoScene[]): GenAssetCitations;
41
+ /**
42
+ * Run the full deterministic normalize pipeline on a raw authored spec and
43
+ * return a schema-valid, render-ready DemoSpec plus the list of adjustments.
44
+ * Throws only if the model produced something with zero scenes (unrecoverable).
45
+ */
46
+ export declare function normalizeDemoSpec(raw: DemoSpec, input: DemoAuthorInput): NormalizeResult;
47
+ /** Convenience — total timeline of a normalized spec (ms). */
48
+ export declare function specTotalMs(spec: DemoSpec): number;
49
+ //# sourceMappingURL=demoAuthorNormalize.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"demoAuthorNormalize.d.ts","sourceRoot":"","sources":["../../../src/services/demo/demoAuthorNormalize.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,SAAS,EACT,QAAQ,EAIT,MAAM,+BAA+B,CAAC;AAEvC,OAAO,EAAE,eAAe,EAAmC,MAAM,oBAAoB,CAAC;AAEtF;;;;;;;;;;;;;;GAcG;AAEH,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,QAAQ,CAAC;IACf,wFAAwF;IACxF,WAAW,EAAE,MAAM,EAAE,CAAC;CACvB;AA6CD,kFAAkF;AAClF,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAC3C,eAAO,MAAM,yBAAyB,IAAI,CAAC;AAE3C,wEAAwE;AACxE,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,GAAG,GAAG,IAAI,MAAM,CAEpE;AAED,sEAAsE;AACtE,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAErD;AAED,MAAM,WAAW,iBAAiB;IAChC,wCAAwC;IACxC,GAAG,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;IACjB;kEAC8D;IAC9D,IAAI,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;CACnB;AAED;;uBAEuB;AACvB,wBAAgB,mBAAmB,CAAC,MAAM,EAAE,SAAS,EAAE,GAAG,iBAAiB,CA2C1E;AA0MD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,GAAG,EAAE,QAAQ,EAAE,KAAK,EAAE,eAAe,GAAG,eAAe,CAsExF;AAED,8DAA8D;AAC9D,wBAAgB,WAAW,CAAC,IAAI,EAAE,QAAQ,GAAG,MAAM,CAElD"}