vidspotai-shared 1.0.53 → 1.0.55

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 (230) hide show
  1. package/lib/globals/aiModels/providers/alibaba.d.ts +4 -0
  2. package/lib/globals/aiModels/providers/alibaba.d.ts.map +1 -0
  3. package/lib/globals/aiModels/providers/alibaba.js +183 -0
  4. package/lib/globals/aiModels/providers/elevenlabs.d.ts +13 -0
  5. package/lib/globals/aiModels/providers/elevenlabs.d.ts.map +1 -0
  6. package/lib/globals/aiModels/providers/elevenlabs.js +25 -0
  7. package/lib/globals/aiModels/providers/pixverseTemplates.d.ts +36 -0
  8. package/lib/globals/aiModels/providers/pixverseTemplates.d.ts.map +1 -0
  9. package/lib/globals/aiModels/providers/pixverseTemplates.js +42 -0
  10. package/lib/globals/aiModels/tierHelpers.d.ts +27 -0
  11. package/lib/globals/aiModels/tierHelpers.d.ts.map +1 -0
  12. package/lib/globals/aiModels/tierHelpers.js +73 -0
  13. package/lib/globals/ttsModels/providers/minimax.d.ts +8 -0
  14. package/lib/globals/ttsModels/providers/minimax.d.ts.map +1 -0
  15. package/lib/globals/ttsModels/providers/minimax.js +18 -0
  16. package/lib/globals/ttsModels/providers/openai.d.ts +8 -0
  17. package/lib/globals/ttsModels/providers/openai.d.ts.map +1 -0
  18. package/lib/globals/ttsModels/providers/openai.js +18 -0
  19. package/lib/globals/types.d.ts +2 -1
  20. package/lib/globals/types.d.ts.map +1 -1
  21. package/lib/globals/types.js +1 -0
  22. package/lib/models/agent.model.d.ts +117 -0
  23. package/lib/models/agent.model.d.ts.map +1 -0
  24. package/lib/models/agent.model.js +13 -0
  25. package/lib/models/analytics.model.d.ts +4 -0
  26. package/lib/models/analytics.model.d.ts.map +1 -1
  27. package/lib/models/cachedAsset.model.d.ts +18 -0
  28. package/lib/models/cachedAsset.model.d.ts.map +1 -0
  29. package/lib/models/cachedAsset.model.js +2 -0
  30. package/lib/models/cachedRawAsset.model.d.ts +20 -0
  31. package/lib/models/cachedRawAsset.model.d.ts.map +1 -0
  32. package/lib/models/cachedRawAsset.model.js +2 -0
  33. package/lib/models/video.model.d.ts +1 -0
  34. package/lib/models/video.model.d.ts.map +1 -1
  35. package/lib/schemas/agentPersona.schema.d.ts +10 -0
  36. package/lib/schemas/agentPersona.schema.d.ts.map +1 -0
  37. package/lib/schemas/agentPersona.schema.js +11 -0
  38. package/lib/schemas/brandKit.schema.d.ts +101 -0
  39. package/lib/schemas/brandKit.schema.d.ts.map +1 -0
  40. package/lib/schemas/brandKit.schema.js +46 -0
  41. package/lib/schemas/brief.schema.d.ts +216 -0
  42. package/lib/schemas/brief.schema.d.ts.map +1 -0
  43. package/lib/schemas/brief.schema.js +118 -0
  44. package/lib/schemas/index.d.ts +6 -0
  45. package/lib/schemas/index.d.ts.map +1 -0
  46. package/lib/schemas/index.js +21 -0
  47. package/lib/schemas/project.schema.d.ts +1005 -0
  48. package/lib/schemas/project.schema.d.ts.map +1 -0
  49. package/lib/schemas/project.schema.js +238 -0
  50. package/lib/schemas/videoPlan.schema.d.ts +145 -0
  51. package/lib/schemas/videoPlan.schema.d.ts.map +1 -0
  52. package/lib/schemas/videoPlan.schema.js +109 -0
  53. package/lib/services/agent/beatSnap.d.ts +10 -0
  54. package/lib/services/agent/beatSnap.d.ts.map +1 -0
  55. package/lib/services/agent/beatSnap.js +128 -0
  56. package/lib/services/agent/costPreflight.d.ts +22 -0
  57. package/lib/services/agent/costPreflight.d.ts.map +1 -0
  58. package/lib/services/agent/costPreflight.js +75 -0
  59. package/lib/services/agent/critic.d.ts +103 -0
  60. package/lib/services/agent/critic.d.ts.map +1 -0
  61. package/lib/services/agent/critic.js +132 -0
  62. package/lib/services/agent/eval/index.d.ts +5 -0
  63. package/lib/services/agent/eval/index.d.ts.map +1 -0
  64. package/lib/services/agent/eval/index.js +20 -0
  65. package/lib/services/agent/eval/judge.d.ts +14 -0
  66. package/lib/services/agent/eval/judge.d.ts.map +1 -0
  67. package/lib/services/agent/eval/judge.js +95 -0
  68. package/lib/services/agent/eval/recorder.d.ts +17 -0
  69. package/lib/services/agent/eval/recorder.d.ts.map +1 -0
  70. package/lib/services/agent/eval/recorder.js +65 -0
  71. package/lib/services/agent/eval/seedBriefs.d.ts +16 -0
  72. package/lib/services/agent/eval/seedBriefs.d.ts.map +1 -0
  73. package/lib/services/agent/eval/seedBriefs.js +1188 -0
  74. package/lib/services/agent/eval/types.d.ts +196 -0
  75. package/lib/services/agent/eval/types.d.ts.map +1 -0
  76. package/lib/services/agent/eval/types.js +65 -0
  77. package/lib/services/agent/executor.d.ts +50 -0
  78. package/lib/services/agent/executor.d.ts.map +1 -0
  79. package/lib/services/agent/executor.js +188 -0
  80. package/lib/services/agent/index.d.ts +15 -0
  81. package/lib/services/agent/index.d.ts.map +1 -0
  82. package/lib/services/agent/index.js +30 -0
  83. package/lib/services/agent/llmCaller.d.ts +77 -0
  84. package/lib/services/agent/llmCaller.d.ts.map +1 -0
  85. package/lib/services/agent/llmCaller.js +16 -0
  86. package/lib/services/agent/llmCallerGateway.d.ts +39 -0
  87. package/lib/services/agent/llmCallerGateway.d.ts.map +1 -0
  88. package/lib/services/agent/llmCallerGateway.js +246 -0
  89. package/lib/services/agent/llmCallerRegistry.d.ts +4 -0
  90. package/lib/services/agent/llmCallerRegistry.d.ts.map +1 -0
  91. package/lib/services/agent/llmCallerRegistry.js +19 -0
  92. package/lib/services/agent/modelRouter.d.ts +41 -0
  93. package/lib/services/agent/modelRouter.d.ts.map +1 -0
  94. package/lib/services/agent/modelRouter.js +57 -0
  95. package/lib/services/agent/musicSelect.d.ts +23 -0
  96. package/lib/services/agent/musicSelect.d.ts.map +1 -0
  97. package/lib/services/agent/musicSelect.js +65 -0
  98. package/lib/services/agent/personas.d.ts +60 -0
  99. package/lib/services/agent/personas.d.ts.map +1 -0
  100. package/lib/services/agent/personas.js +156 -0
  101. package/lib/services/agent/planner.d.ts +56 -0
  102. package/lib/services/agent/planner.d.ts.map +1 -0
  103. package/lib/services/agent/planner.js +237 -0
  104. package/lib/services/agent/toolRegistry.d.ts +64 -0
  105. package/lib/services/agent/toolRegistry.d.ts.map +1 -0
  106. package/lib/services/agent/toolRegistry.js +78 -0
  107. package/lib/services/agent/tools/analyzeReference.tool.d.ts +36 -0
  108. package/lib/services/agent/tools/analyzeReference.tool.d.ts.map +1 -0
  109. package/lib/services/agent/tools/analyzeReference.tool.js +44 -0
  110. package/lib/services/agent/tools/animateImage.tool.d.ts +23 -0
  111. package/lib/services/agent/tools/animateImage.tool.d.ts.map +1 -0
  112. package/lib/services/agent/tools/animateImage.tool.js +58 -0
  113. package/lib/services/agent/tools/animateImageWithMotionBrush.tool.d.ts +30 -0
  114. package/lib/services/agent/tools/animateImageWithMotionBrush.tool.d.ts.map +1 -0
  115. package/lib/services/agent/tools/animateImageWithMotionBrush.tool.js +90 -0
  116. package/lib/services/agent/tools/composeScene.tool.d.ts +948 -0
  117. package/lib/services/agent/tools/composeScene.tool.d.ts.map +1 -0
  118. package/lib/services/agent/tools/composeScene.tool.js +90 -0
  119. package/lib/services/agent/tools/estimateCost.tool.d.ts +342 -0
  120. package/lib/services/agent/tools/estimateCost.tool.d.ts.map +1 -0
  121. package/lib/services/agent/tools/estimateCost.tool.js +62 -0
  122. package/lib/services/agent/tools/generateAvatarVideo.tool.d.ts +32 -0
  123. package/lib/services/agent/tools/generateAvatarVideo.tool.d.ts.map +1 -0
  124. package/lib/services/agent/tools/generateAvatarVideo.tool.js +112 -0
  125. package/lib/services/agent/tools/generateImage.tool.d.ts +28 -0
  126. package/lib/services/agent/tools/generateImage.tool.d.ts.map +1 -0
  127. package/lib/services/agent/tools/generateImage.tool.js +97 -0
  128. package/lib/services/agent/tools/generateVideo.tool.d.ts +30 -0
  129. package/lib/services/agent/tools/generateVideo.tool.d.ts.map +1 -0
  130. package/lib/services/agent/tools/generateVideo.tool.js +84 -0
  131. package/lib/services/agent/tools/generateVoiceover.tool.d.ts +18 -0
  132. package/lib/services/agent/tools/generateVoiceover.tool.d.ts.map +1 -0
  133. package/lib/services/agent/tools/generateVoiceover.tool.js +72 -0
  134. package/lib/services/agent/tools/index.d.ts +19 -0
  135. package/lib/services/agent/tools/index.d.ts.map +1 -0
  136. package/lib/services/agent/tools/index.js +34 -0
  137. package/lib/services/agent/tools/planVideo.tool.d.ts +191 -0
  138. package/lib/services/agent/tools/planVideo.tool.d.ts.map +1 -0
  139. package/lib/services/agent/tools/planVideo.tool.js +46 -0
  140. package/lib/services/agent/tools/render.tool.d.ts +357 -0
  141. package/lib/services/agent/tools/render.tool.d.ts.map +1 -0
  142. package/lib/services/agent/tools/render.tool.js +48 -0
  143. package/lib/services/agent/tools/searchMusic.tool.d.ts +49 -0
  144. package/lib/services/agent/tools/searchMusic.tool.d.ts.map +1 -0
  145. package/lib/services/agent/tools/searchMusic.tool.js +74 -0
  146. package/lib/services/agent/tools/searchStock.tool.d.ts +37 -0
  147. package/lib/services/agent/tools/searchStock.tool.d.ts.map +1 -0
  148. package/lib/services/agent/tools/searchStock.tool.js +101 -0
  149. package/lib/services/agent/tools/searchUserLibrary.tool.d.ts +59 -0
  150. package/lib/services/agent/tools/searchUserLibrary.tool.d.ts.map +1 -0
  151. package/lib/services/agent/tools/searchUserLibrary.tool.js +58 -0
  152. package/lib/services/aiGen/canonicalAdapters/cameraControl.types.d.ts +31 -0
  153. package/lib/services/aiGen/canonicalAdapters/cameraControl.types.d.ts.map +1 -0
  154. package/lib/services/aiGen/canonicalAdapters/cameraControl.types.js +2 -0
  155. package/lib/services/aiGen/canonicalAdapters/index.d.ts +3 -0
  156. package/lib/services/aiGen/canonicalAdapters/index.d.ts.map +1 -0
  157. package/lib/services/aiGen/canonicalAdapters/index.js +18 -0
  158. package/lib/services/aiGen/canonicalAdapters/multiShot.types.d.ts +23 -0
  159. package/lib/services/aiGen/canonicalAdapters/multiShot.types.d.ts.map +1 -0
  160. package/lib/services/aiGen/canonicalAdapters/multiShot.types.js +12 -0
  161. package/lib/services/aiGen/providers/elevenlabs/elevenlabs.service.d.ts +18 -0
  162. package/lib/services/aiGen/providers/elevenlabs/elevenlabs.service.d.ts.map +1 -0
  163. package/lib/services/aiGen/providers/elevenlabs/elevenlabs.service.js +100 -0
  164. package/lib/services/aiGen/providers/fal/falImage.service.d.ts +9 -0
  165. package/lib/services/aiGen/providers/fal/falImage.service.d.ts.map +1 -0
  166. package/lib/services/aiGen/providers/fal/falImage.service.js +102 -0
  167. package/lib/services/aiGen/providers/fal/index.d.ts +2 -0
  168. package/lib/services/aiGen/providers/fal/index.d.ts.map +1 -0
  169. package/lib/services/aiGen/providers/fal/index.js +17 -0
  170. package/lib/services/aiGen/providers/kling/cameraAdapter.d.ts +4 -0
  171. package/lib/services/aiGen/providers/kling/cameraAdapter.d.ts.map +1 -0
  172. package/lib/services/aiGen/providers/kling/cameraAdapter.js +53 -0
  173. package/lib/services/aiGen/providers/pexels/index.d.ts +2 -0
  174. package/lib/services/aiGen/providers/pexels/index.d.ts.map +1 -0
  175. package/lib/services/aiGen/providers/pexels/index.js +17 -0
  176. package/lib/services/aiGen/providers/pexels/pexels.service.d.ts +11 -0
  177. package/lib/services/aiGen/providers/pexels/pexels.service.d.ts.map +1 -0
  178. package/lib/services/aiGen/providers/pexels/pexels.service.js +118 -0
  179. package/lib/services/aiGen/providers/runway/cameraAdapter.d.ts +3 -0
  180. package/lib/services/aiGen/providers/runway/cameraAdapter.d.ts.map +1 -0
  181. package/lib/services/aiGen/providers/runway/cameraAdapter.js +46 -0
  182. package/lib/services/analytics.service.d.ts +10 -0
  183. package/lib/services/analytics.service.d.ts.map +1 -1
  184. package/lib/services/analytics.service.js +27 -0
  185. package/lib/services/asr/assemblyai.service.d.ts +72 -0
  186. package/lib/services/asr/assemblyai.service.d.ts.map +1 -0
  187. package/lib/services/asr/assemblyai.service.js +89 -0
  188. package/lib/services/asr/index.d.ts +2 -0
  189. package/lib/services/asr/index.d.ts.map +1 -0
  190. package/lib/services/asr/index.js +17 -0
  191. package/lib/services/assetCache.service.d.ts +54 -0
  192. package/lib/services/assetCache.service.d.ts.map +1 -0
  193. package/lib/services/assetCache.service.js +96 -0
  194. package/lib/services/audioAnalysis/index.d.ts +2 -0
  195. package/lib/services/audioAnalysis/index.d.ts.map +1 -0
  196. package/lib/services/audioAnalysis/index.js +17 -0
  197. package/lib/services/audioAnalysis/onsetDetection.service.d.ts +50 -0
  198. package/lib/services/audioAnalysis/onsetDetection.service.d.ts.map +1 -0
  199. package/lib/services/audioAnalysis/onsetDetection.service.js +136 -0
  200. package/lib/services/editor/designToProject.d.ts +60 -0
  201. package/lib/services/editor/designToProject.d.ts.map +1 -0
  202. package/lib/services/editor/designToProject.js +194 -0
  203. package/lib/services/musicGen/index.d.ts +6 -0
  204. package/lib/services/musicGen/index.d.ts.map +1 -0
  205. package/lib/services/musicGen/index.js +26 -0
  206. package/lib/services/musicGen/musicSearchFactory.service.d.ts +14 -0
  207. package/lib/services/musicGen/musicSearchFactory.service.d.ts.map +1 -0
  208. package/lib/services/musicGen/musicSearchFactory.service.js +59 -0
  209. package/lib/services/musicGen/providers/curated.service.d.ts +22 -0
  210. package/lib/services/musicGen/providers/curated.service.d.ts.map +1 -0
  211. package/lib/services/musicGen/providers/curated.service.js +171 -0
  212. package/lib/services/musicGen/providers/jamendo.service.d.ts +8 -0
  213. package/lib/services/musicGen/providers/jamendo.service.d.ts.map +1 -0
  214. package/lib/services/musicGen/providers/jamendo.service.js +93 -0
  215. package/lib/services/musicGen/providers/mubert.service.d.ts +9 -0
  216. package/lib/services/musicGen/providers/mubert.service.d.ts.map +1 -0
  217. package/lib/services/musicGen/providers/mubert.service.js +113 -0
  218. package/lib/services/musicGen/types.d.ts +42 -0
  219. package/lib/services/musicGen/types.d.ts.map +1 -0
  220. package/lib/services/musicGen/types.js +10 -0
  221. package/lib/services/tts/providers/minimax.service.d.ts +14 -0
  222. package/lib/services/tts/providers/minimax.service.d.ts.map +1 -0
  223. package/lib/services/tts/providers/minimax.service.js +78 -0
  224. package/lib/services/tts/providers/openai.service.d.ts +14 -0
  225. package/lib/services/tts/providers/openai.service.d.ts.map +1 -0
  226. package/lib/services/tts/providers/openai.service.js +71 -0
  227. package/lib/utils/helpers.d.ts +1 -0
  228. package/lib/utils/helpers.d.ts.map +1 -1
  229. package/lib/utils/helpers.js +26 -12
  230. package/package.json +1 -1
@@ -0,0 +1,156 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.PersonaRouter = exports.PERSONA_PACKS = exports.AgentPersonaSchema = void 0;
4
+ const zod_1 = require("zod");
5
+ const agentPersona_schema_1 = require("../../schemas/agentPersona.schema");
6
+ Object.defineProperty(exports, "AgentPersonaSchema", { enumerable: true, get: function () { return agentPersona_schema_1.AgentPersonaSchema; } });
7
+ const modelRouter_1 = require("./modelRouter");
8
+ exports.PERSONA_PACKS = {
9
+ "ugc-ad": {
10
+ id: "ugc-ad",
11
+ label: "UGC Ad",
12
+ blurb: "Hook-first 9:16 ads with creator energy and punchy product reveals.",
13
+ defaults: {
14
+ aspect: "9:16",
15
+ durationSec: 30,
16
+ tone: "warm",
17
+ pacing: "fast",
18
+ hookStyle: "pattern-interrupt",
19
+ tierBudget: "T2",
20
+ },
21
+ plannerPrompt: [
22
+ "UGC ad rules:",
23
+ "- First 3s MUST be a problem-statement or pattern-interrupt hook (no logos, no slow b-roll).",
24
+ "- Cut every 1.5–2.5s after the hook.",
25
+ "- Voiceover or talking-head drives the script; visuals support, not lead.",
26
+ "- End with a one-sentence CTA + product name burned in.",
27
+ "- Avoid medical / unverifiable claims (legal risk).",
28
+ ].join("\n"),
29
+ defaultBpm: 110,
30
+ criticEmphasis: { hookStrength: 0.3, brandSafety: 0.2 },
31
+ },
32
+ "faceless-yt": {
33
+ id: "faceless-yt",
34
+ label: "Faceless YouTube",
35
+ blurb: "Educational 16:9 explainers built mostly from cheap stock + voiceover.",
36
+ defaults: {
37
+ aspect: "16:9",
38
+ durationSec: 60,
39
+ tone: "informational",
40
+ pacing: "medium",
41
+ hookStyle: "bold-claim",
42
+ tierBudget: "T0",
43
+ },
44
+ plannerPrompt: [
45
+ "Faceless YouTube rules:",
46
+ "- Mostly T0 (stock + Ken Burns) to keep cost <$0.10/video.",
47
+ "- Hook = counter-intuitive claim or surprising stat in first 8s.",
48
+ "- Captions burned in; assume sound-off viewing.",
49
+ "- 1 voiceover line per scene; visuals illustrate the line literally.",
50
+ "- Avoid copyrighted footage; prefer stock and AI-generated stills.",
51
+ ].join("\n"),
52
+ criticEmphasis: { costVsTier: 0.25, voVisualSync: 0.25 },
53
+ },
54
+ "product-demo": {
55
+ id: "product-demo",
56
+ label: "Product Demo",
57
+ blurb: "Square e-comm demos with hero shot first and crisp end-cards.",
58
+ defaults: {
59
+ aspect: "1:1",
60
+ durationSec: 20,
61
+ tone: "energetic",
62
+ pacing: "fast",
63
+ hookStyle: "demo",
64
+ tierBudget: "T2",
65
+ },
66
+ plannerPrompt: [
67
+ "Product demo rules:",
68
+ "- Hero product shot in first 3s (T2 image-to-video on the hero only).",
69
+ "- T0 stock or T1 AI image+motion for filler scenes between.",
70
+ "- Background music ducked under voiceover; no music-only sections.",
71
+ "- End-card with logo + CTA; aspect MUST match brief (default 1:1).",
72
+ ].join("\n"),
73
+ criticEmphasis: { intentMatch: 0.3, brandSafety: 0.15 },
74
+ },
75
+ "talking-head": {
76
+ id: "talking-head",
77
+ label: "Talking-Head Educator",
78
+ blurb: "Authority-driven explainers using a presenter avatar + b-roll cutaways.",
79
+ defaults: {
80
+ aspect: "16:9",
81
+ durationSec: 45,
82
+ tone: "professional",
83
+ pacing: "medium",
84
+ hookStyle: "question",
85
+ tierBudget: "T1",
86
+ },
87
+ plannerPrompt: [
88
+ "Talking-head educator rules:",
89
+ "- Persona is on-camera (avatar or stock talking-head); cut to b-roll for emphasis only.",
90
+ "- Open with a question the viewer has googled.",
91
+ "- One key insight per 10s; recap at end.",
92
+ "- Prefer T1 (image+motion) for b-roll; T0 stock fallbacks if budget tight.",
93
+ ].join("\n"),
94
+ criticEmphasis: { intentMatch: 0.25, voVisualSync: 0.25 },
95
+ },
96
+ "social-recap": {
97
+ id: "social-recap",
98
+ label: "Social Recap",
99
+ blurb: "Fast multi-clip recaps for news, sports, listicles — beat-cut energy.",
100
+ defaults: {
101
+ aspect: "9:16",
102
+ durationSec: 30,
103
+ tone: "energetic",
104
+ pacing: "very-fast",
105
+ hookStyle: "stat",
106
+ tierBudget: "T0",
107
+ },
108
+ plannerPrompt: [
109
+ "Social recap rules:",
110
+ "- Cuts on the music beat; assume an upbeat track at 110–130 BPM.",
111
+ "- 1 sentence per clip max; on-screen text mirrors voice.",
112
+ "- Mostly T0 stock; use AI generation sparingly for transitions.",
113
+ "- Hook = the most surprising stat or the punchline up front.",
114
+ ].join("\n"),
115
+ defaultBpm: 120,
116
+ criticEmphasis: { pacingFit: 0.3, costVsTier: 0.2 },
117
+ },
118
+ };
119
+ const RoutedPersonaSchema = zod_1.z.object({
120
+ persona: agentPersona_schema_1.AgentPersonaSchema,
121
+ confidence: zod_1.z.number().min(0).max(1),
122
+ reason: zod_1.z.string(),
123
+ });
124
+ class PersonaRouter {
125
+ constructor(llm, router = new modelRouter_1.ModelRouter()) {
126
+ this.llm = llm;
127
+ this.router = router;
128
+ }
129
+ async route(rawPrompt) {
130
+ const model = this.router.pickFor("router");
131
+ const personaList = Object.values(exports.PERSONA_PACKS)
132
+ .map((p) => `- ${p.id}: ${p.blurb}`)
133
+ .join("\n");
134
+ const result = await this.llm.structured({
135
+ model,
136
+ schema: RoutedPersonaSchema,
137
+ schemaName: "RoutedPersona",
138
+ temperature: 0,
139
+ messages: [
140
+ {
141
+ role: "system",
142
+ content: [
143
+ "Classify the user's video request into ONE persona.",
144
+ "Personas:",
145
+ personaList,
146
+ "",
147
+ "Pick the closest fit. confidence 0..1; reason in <20 words.",
148
+ ].join("\n"),
149
+ },
150
+ { role: "user", content: rawPrompt },
151
+ ],
152
+ });
153
+ return result.data;
154
+ }
155
+ }
156
+ exports.PersonaRouter = PersonaRouter;
@@ -0,0 +1,56 @@
1
+ import { AgentPersona } from "../../schemas/agentPersona.schema";
2
+ import { VideoBrief } from "../../schemas/brief.schema";
3
+ import { VideoPlan } from "../../schemas/videoPlan.schema";
4
+ import { IBrandKitModel, IStyleMemoryModel } from "../../models/agent.model";
5
+ import { LlmCaller } from "./llmCaller";
6
+ import { ModelRouter } from "./modelRouter";
7
+ /**
8
+ * Planner — turns a VideoBrief into a Zod-validated VideoPlan.
9
+ *
10
+ * Plan-then-execute architecture (not free-form ReAct): the planner runs in a
11
+ * single structured-output call, the executor runs the plan, the critic QA's
12
+ * after. This split is what makes Claude Code reliable and applies the same
13
+ * shape here.
14
+ *
15
+ * Validation strategy: structured-output is enforced at the LLM layer; this
16
+ * class additionally re-validates against VideoPlanSchema and retries up to
17
+ * `maxRetries` times feeding the validation errors back as correction context.
18
+ */
19
+ export interface PlannerOptions {
20
+ llm: LlmCaller;
21
+ router?: ModelRouter;
22
+ maxRetries?: number;
23
+ }
24
+ export declare class Planner {
25
+ private readonly opts;
26
+ private readonly router;
27
+ private readonly maxRetries;
28
+ constructor(opts: PlannerOptions);
29
+ plan(brief: VideoBrief, opts?: {
30
+ persona?: AgentPersona;
31
+ brandKit?: IBrandKitModel | null;
32
+ styleMemory?: IStyleMemoryModel | null;
33
+ }): Promise<VideoPlan>;
34
+ /**
35
+ * Streaming variant of `plan()`. Yields raw token chunks from the model so
36
+ * the host (SSE endpoint) can forward them to the drawer for token-by-token
37
+ * rendering, then resolves to the validated VideoPlan once the structured
38
+ * payload is complete. Falls back to a single-shot call (one chunk = full
39
+ * text) when the LLM caller doesn't implement `structuredStream`.
40
+ *
41
+ * Retries are NOT streamed: only the first attempt is exposed to the UI;
42
+ * if validation fails we re-call `plan()` (non-streaming) and emit the
43
+ * final retry as a single chunk. Streaming retries would confuse callers
44
+ * who already painted partial JSON for the first attempt.
45
+ */
46
+ planStream(brief: VideoBrief, opts?: {
47
+ persona?: AgentPersona;
48
+ brandKit?: IBrandKitModel | null;
49
+ styleMemory?: IStyleMemoryModel | null;
50
+ }): {
51
+ tokens: AsyncIterable<string>;
52
+ result: Promise<VideoPlan>;
53
+ };
54
+ private buildMessages;
55
+ }
56
+ //# sourceMappingURL=planner.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"planner.d.ts","sourceRoot":"","sources":["../../../src/services/agent/planner.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,mCAAmC,CAAC;AACjE,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAC;AACxD,OAAO,EAAE,SAAS,EAAmB,MAAM,gCAAgC,CAAC;AAC5E,OAAO,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAE7E,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC;AAG5C;;;;;;;;;;;GAWG;AAEH,MAAM,WAAW,cAAc;IAC7B,GAAG,EAAE,SAAS,CAAC;IACf,MAAM,CAAC,EAAE,WAAW,CAAC;IACrB,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB;AAED,qBAAa,OAAO;IAIN,OAAO,CAAC,QAAQ,CAAC,IAAI;IAHjC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;gBAEP,IAAI,EAAE,cAAc;IAK3C,IAAI,CACR,KAAK,EAAE,UAAU,EACjB,IAAI,GAAE;QACJ,OAAO,CAAC,EAAE,YAAY,CAAC;QACvB,QAAQ,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;QACjC,WAAW,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;KACnC,GACL,OAAO,CAAC,SAAS,CAAC;IAqCrB;;;;;;;;;;;OAWG;IACH,UAAU,CACR,KAAK,EAAE,UAAU,EACjB,IAAI,GAAE;QACJ,OAAO,CAAC,EAAE,YAAY,CAAC;QACvB,QAAQ,CAAC,EAAE,cAAc,GAAG,IAAI,CAAC;QACjC,WAAW,CAAC,EAAE,iBAAiB,GAAG,IAAI,CAAC;KACnC,GACL;QAAE,MAAM,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;QAAC,MAAM,EAAE,OAAO,CAAC,SAAS,CAAC,CAAA;KAAE;IA+ChE,OAAO,CAAC,aAAa;CAiFtB"}
@@ -0,0 +1,237 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.Planner = void 0;
4
+ const videoPlan_schema_1 = require("../../schemas/videoPlan.schema");
5
+ const tierHelpers_1 = require("../../globals/aiModels/tierHelpers");
6
+ const modelRouter_1 = require("./modelRouter");
7
+ const personas_1 = require("./personas");
8
+ class Planner {
9
+ constructor(opts) {
10
+ this.opts = opts;
11
+ this.router = opts.router ?? new modelRouter_1.ModelRouter();
12
+ this.maxRetries = opts.maxRetries ?? 2;
13
+ }
14
+ async plan(brief, opts = {}) {
15
+ const model = this.router.pickFor("planner", {
16
+ premium: brief.tierBudget === "T3",
17
+ });
18
+ let lastErrors;
19
+ for (let attempt = 0; attempt <= this.maxRetries; attempt++) {
20
+ const messages = this.buildMessages(brief, opts.persona, opts.brandKit ?? null, opts.styleMemory ?? null, lastErrors);
21
+ const result = await this.opts.llm.structured({
22
+ model,
23
+ messages,
24
+ schema: videoPlan_schema_1.VideoPlanSchema,
25
+ schemaName: "VideoPlan",
26
+ temperature: attempt === 0 ? 0.4 : 0.2,
27
+ });
28
+ // Defense-in-depth: re-validate even though structured() should have.
29
+ const reparsed = videoPlan_schema_1.VideoPlanSchema.safeParse(result.data);
30
+ if (reparsed.success)
31
+ return reparsed.data;
32
+ lastErrors = reparsed.error.issues
33
+ .map((i) => `${i.path.join(".")}: ${i.message}`)
34
+ .join("; ");
35
+ }
36
+ throw new Error(`Planner failed to produce a valid VideoPlan after ${this.maxRetries + 1} attempts. Last errors: ${lastErrors}`);
37
+ }
38
+ /**
39
+ * Streaming variant of `plan()`. Yields raw token chunks from the model so
40
+ * the host (SSE endpoint) can forward them to the drawer for token-by-token
41
+ * rendering, then resolves to the validated VideoPlan once the structured
42
+ * payload is complete. Falls back to a single-shot call (one chunk = full
43
+ * text) when the LLM caller doesn't implement `structuredStream`.
44
+ *
45
+ * Retries are NOT streamed: only the first attempt is exposed to the UI;
46
+ * if validation fails we re-call `plan()` (non-streaming) and emit the
47
+ * final retry as a single chunk. Streaming retries would confuse callers
48
+ * who already painted partial JSON for the first attempt.
49
+ */
50
+ planStream(brief, opts = {}) {
51
+ const model = this.router.pickFor("planner", {
52
+ premium: brief.tierBudget === "T3",
53
+ });
54
+ const messages = this.buildMessages(brief, opts.persona, opts.brandKit ?? null, opts.styleMemory ?? null);
55
+ if (!this.opts.llm.structuredStream) {
56
+ // Fallback path — emit the whole plan as one chunk after non-streaming call.
57
+ const result = this.plan(brief, opts);
58
+ const tokens = {
59
+ async *[Symbol.asyncIterator]() {
60
+ const plan = await result;
61
+ yield JSON.stringify(plan);
62
+ },
63
+ };
64
+ return { tokens, result };
65
+ }
66
+ const stream = this.opts.llm.structuredStream({
67
+ model,
68
+ messages,
69
+ schema: videoPlan_schema_1.VideoPlanSchema,
70
+ schemaName: "VideoPlan",
71
+ temperature: 0.4,
72
+ });
73
+ const planner = this;
74
+ const result = (async () => {
75
+ try {
76
+ const r = await stream.result;
77
+ const reparsed = videoPlan_schema_1.VideoPlanSchema.safeParse(r.data);
78
+ if (reparsed.success)
79
+ return reparsed.data;
80
+ // Validation tripped on a streamed payload — fall back to retry pass.
81
+ return planner.plan(brief, opts);
82
+ }
83
+ catch {
84
+ return planner.plan(brief, opts);
85
+ }
86
+ })();
87
+ return { tokens: stream.tokens, result };
88
+ }
89
+ buildMessages(brief, persona, brandKit, styleMemory, lastErrors) {
90
+ const personaSection = persona
91
+ ? [
92
+ "",
93
+ `Selected persona: ${persona}.`,
94
+ `Set plan.persona to "${persona}" in the output.`,
95
+ "Persona-specific structural rules (apply on top of the global tier rules):",
96
+ personas_1.PERSONA_PACKS[persona].plannerPrompt,
97
+ ].join("\n")
98
+ : "";
99
+ const brandKitSection = buildBrandKitSection(brandKit);
100
+ const styleMemorySection = buildStyleMemorySection(styleMemory);
101
+ const modelCatalogSection = buildModelCatalogSection();
102
+ const system = [
103
+ "You are a video-production planner.",
104
+ "Given a VideoBrief, produce a VideoPlan: an ordered list of scenes",
105
+ "with per-scene asset strategy, tier, prompt, duration, and voiceover.",
106
+ "",
107
+ "Tier rules — respect brief.tierBudget as the maximum tier:",
108
+ " T0: stock footage / image with Ken-Burns motion.",
109
+ " T1: AI-generated still + camera motion.",
110
+ " T2: AI image-to-video on key frames only.",
111
+ " T3: full text-to-video (most expensive — use sparingly).",
112
+ "",
113
+ "talking-head-avatar is wired and runs the kling-avatar pipeline (face",
114
+ "still + TTS lipsync). Pick it ONLY when the brand kit exposes a",
115
+ "presenterFaceUrl — set scene.avatarFaceUrl to that URL on every avatar",
116
+ "scene. If no presenter face is available, fall back to ai-image-to-video",
117
+ "or stock-video of a presenter instead.",
118
+ "",
119
+ "user-asset is wired and reuses the requesting user's existing library",
120
+ "(their previously generated images / videos / audio) instead of spending",
121
+ "credits to make a new asset. Pick user-asset when the brief mentions a",
122
+ "recurring brand subject (their product photo, spokesperson, b-roll) —",
123
+ "the executor falls back to stock-video if no library match scores high",
124
+ "enough, so picking it is safe.",
125
+ "",
126
+ "Keep total estimated credits as low as possible while honoring the",
127
+ "brief. Mix tiers within a single video where it helps cost without",
128
+ "harming quality (e.g. T2 hero shot + T0 b-roll between).",
129
+ "",
130
+ "Smart model routing — set preferredModel per scene from the catalog:",
131
+ " - Hero / opening-hook / product-reveal scenes: pick the highest-",
132
+ " quality model in the chosen tier (most expensive in that tier).",
133
+ " - B-roll / filler / transition scenes: pick the cheapest model in",
134
+ " the chosen tier — the audience won't notice the difference and",
135
+ " cost drops 3–5x.",
136
+ " - When in doubt for a non-hero scene, pick the median-cost model.",
137
+ " - preferredModel must match a key from the catalog below; the",
138
+ " executor will swap on rate-limit, so picking is best-effort, not",
139
+ " a hard contract.",
140
+ modelCatalogSection,
141
+ personaSection,
142
+ brandKitSection,
143
+ styleMemorySection,
144
+ ]
145
+ .filter(Boolean)
146
+ .join("\n");
147
+ const user = [
148
+ `Brief:\n${JSON.stringify(brief, null, 2)}`,
149
+ lastErrors
150
+ ? `\nYour previous attempt failed validation: ${lastErrors}\nFix the structure and try again.`
151
+ : "",
152
+ ]
153
+ .filter(Boolean)
154
+ .join("\n");
155
+ return [
156
+ { role: "system", content: system },
157
+ { role: "user", content: user },
158
+ ];
159
+ }
160
+ }
161
+ exports.Planner = Planner;
162
+ function buildModelCatalogSection() {
163
+ // Today the agent ships text-to-video and image-to-video providers; both
164
+ // share the same per-tier shape, and t2v is the most common executor path.
165
+ // Image-gen models live under a separate tool (generate_image) so they
166
+ // don't belong in this catalog.
167
+ const t2v = (0, tierHelpers_1.summarizeModelsForPlanner)("text-to-video");
168
+ const i2v = (0, tierHelpers_1.summarizeModelsForPlanner)("image-to-video");
169
+ const sections = [];
170
+ if (t2v)
171
+ sections.push("", "Text-to-video models by tier (cheapest first):", t2v);
172
+ if (i2v)
173
+ sections.push("", "Image-to-video models by tier (cheapest first):", i2v);
174
+ return sections.join("\n");
175
+ }
176
+ function buildBrandKitSection(brandKit) {
177
+ if (!brandKit)
178
+ return "";
179
+ const lines = [];
180
+ if (brandKit.brandName)
181
+ lines.push(` Brand: ${brandKit.brandName}`);
182
+ if (brandKit.primaryColorHex || brandKit.secondaryColorHex) {
183
+ const palette = [brandKit.primaryColorHex, brandKit.secondaryColorHex]
184
+ .filter(Boolean)
185
+ .join(" / ");
186
+ lines.push(` Palette: ${palette}`);
187
+ }
188
+ if (brandKit.fontFamily)
189
+ lines.push(` Font: ${brandKit.fontFamily}`);
190
+ if (brandKit.voiceId)
191
+ lines.push(` Preferred TTS voice id: ${brandKit.voiceId}`);
192
+ if (brandKit.presenterFaceUrl) {
193
+ lines.push(` Presenter face URL (use as scene.avatarFaceUrl on talking-head-avatar scenes): ${brandKit.presenterFaceUrl}`);
194
+ }
195
+ if (brandKit.musicMoods?.length) {
196
+ lines.push(` Music moods: ${brandKit.musicMoods.join(", ")}`);
197
+ }
198
+ if (brandKit.preferredClaims?.length) {
199
+ lines.push(` Preferred phrasing: ${brandKit.preferredClaims.join("; ")}`);
200
+ }
201
+ if (brandKit.bannedClaims?.length) {
202
+ lines.push(` NEVER produce these phrases: ${brandKit.bannedClaims.join("; ")}`);
203
+ }
204
+ if (!lines.length)
205
+ return "";
206
+ return [
207
+ "",
208
+ "Brand kit (set once by the user — apply on every scene):",
209
+ ...lines,
210
+ ].join("\n");
211
+ }
212
+ function buildStyleMemorySection(memory) {
213
+ if (!memory)
214
+ return "";
215
+ const accepted = (memory.acceptedScenes ?? []).slice(-3);
216
+ const rejected = (memory.rejectedScenes ?? []).slice(-3);
217
+ if (!accepted.length && !rejected.length)
218
+ return "";
219
+ const fmt = (entry) => {
220
+ try {
221
+ return JSON.stringify(entry.scene);
222
+ }
223
+ catch {
224
+ return "[unserializable scene]";
225
+ }
226
+ };
227
+ const sections = ["", "Style memory (recent decisions by this user):"];
228
+ if (accepted.length) {
229
+ sections.push(" Bias toward shapes like these (accepted):");
230
+ accepted.forEach((s) => sections.push(` - ${fmt(s)}`));
231
+ }
232
+ if (rejected.length) {
233
+ sections.push(" Avoid shapes like these (rejected):");
234
+ rejected.forEach((s) => sections.push(` - ${fmt(s)}`));
235
+ }
236
+ return sections.join("\n");
237
+ }
@@ -0,0 +1,64 @@
1
+ import { z } from "zod";
2
+ /**
3
+ * MCP-shaped tool registry.
4
+ *
5
+ * Tools are defined once here and consumed in two ways:
6
+ * 1. Internally by the agent (planner/executor/critic) via `getTool(name)`
7
+ * and `runTool(name, input)` — no network hop.
8
+ * 2. Externally as an MCP server endpoint, by reading `listTools()` and
9
+ * JSON-RPC dispatching to `runTool` (wired in a later commit).
10
+ *
11
+ * Each tool ships with:
12
+ * - name: stable identifier the LLM uses
13
+ * - description: written for LLMs (when to use, when NOT to use, examples)
14
+ * - inputSchema / outputSchema: Zod, validated on every call
15
+ * - handler: pure async function over validated input → validated output
16
+ *
17
+ * Idempotency, cost preflight, and rate limiting are implemented as wrappers
18
+ * around `runTool` rather than per-tool, so we don't repeat ourselves.
19
+ */
20
+ export interface ToolDefinition<I extends z.ZodTypeAny, O extends z.ZodTypeAny> {
21
+ name: string;
22
+ description: string;
23
+ inputSchema: I;
24
+ outputSchema: O;
25
+ handler: (input: z.infer<I>, ctx: ToolContext) => Promise<z.infer<O>>;
26
+ /** If true, identical (name, idempotencyKey) calls return cached result. */
27
+ idempotent?: boolean;
28
+ /** Tier-aware cost estimate; called when input.dry_run is true. */
29
+ estimateCost?: (input: z.infer<I>) => Promise<number>;
30
+ }
31
+ export interface ToolContext {
32
+ /** User the agent is acting on behalf of. */
33
+ userId: string;
34
+ /** Agent run id, for tracing and replay. */
35
+ agentRunId: string;
36
+ /** Project the tool is operating on, if applicable. */
37
+ projectId?: string;
38
+ /** Idempotency key for generation tools. */
39
+ idempotencyKey?: string;
40
+ /** Trace logger; replaced with structured logger by the host. */
41
+ log?: (event: string, data?: Record<string, unknown>) => void;
42
+ }
43
+ export interface ToolResult<O = unknown> {
44
+ ok: true;
45
+ output: O;
46
+ durationMs: number;
47
+ }
48
+ export interface ToolError {
49
+ ok: false;
50
+ error: {
51
+ code: string;
52
+ message: string;
53
+ };
54
+ durationMs: number;
55
+ }
56
+ export type ToolOutcome<O = unknown> = ToolResult<O> | ToolError;
57
+ export declare function registerTool<I extends z.ZodTypeAny, O extends z.ZodTypeAny>(def: ToolDefinition<I, O>): void;
58
+ export declare function getTool(name: string): ToolDefinition<z.ZodTypeAny, z.ZodTypeAny> | undefined;
59
+ export declare function listTools(): ToolDefinition<z.ZodTypeAny, z.ZodTypeAny>[];
60
+ /** Execute a tool by name with structured validation + error wrapping. */
61
+ export declare function runTool<O = unknown>(name: string, rawInput: unknown, ctx: ToolContext): Promise<ToolOutcome<O>>;
62
+ /** Test-only: drop all registered tools. */
63
+ export declare function _clearToolsForTesting(): void;
64
+ //# sourceMappingURL=toolRegistry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"toolRegistry.d.ts","sourceRoot":"","sources":["../../../src/services/agent/toolRegistry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB;;;;;;;;;;;;;;;;;GAiBG;AAEH,MAAM,WAAW,cAAc,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,EAAE,CAAC,SAAS,CAAC,CAAC,UAAU;IAC5E,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,CAAC,CAAC;IACf,YAAY,EAAE,CAAC,CAAC;IAChB,OAAO,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,WAAW,KAAK,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;IACtE,4EAA4E;IAC5E,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,mEAAmE;IACnE,YAAY,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,OAAO,CAAC,MAAM,CAAC,CAAC;CACvD;AAED,MAAM,WAAW,WAAW;IAC1B,6CAA6C;IAC7C,MAAM,EAAE,MAAM,CAAC;IACf,4CAA4C;IAC5C,UAAU,EAAE,MAAM,CAAC;IACnB,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,4CAA4C;IAC5C,cAAc,CAAC,EAAE,MAAM,CAAC;IACxB,iEAAiE;IACjE,GAAG,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,KAAK,IAAI,CAAC;CAC/D;AAED,MAAM,WAAW,UAAU,CAAC,CAAC,GAAG,OAAO;IACrC,EAAE,EAAE,IAAI,CAAC;IACT,MAAM,EAAE,CAAC,CAAC;IACV,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,SAAS;IACxB,EAAE,EAAE,KAAK,CAAC;IACV,KAAK,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IACzC,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,MAAM,WAAW,CAAC,CAAC,GAAG,OAAO,IAAI,UAAU,CAAC,CAAC,CAAC,GAAG,SAAS,CAAC;AAIjE,wBAAgB,YAAY,CAAC,CAAC,SAAS,CAAC,CAAC,UAAU,EAAE,CAAC,SAAS,CAAC,CAAC,UAAU,EACzE,GAAG,EAAE,cAAc,CAAC,CAAC,EAAE,CAAC,CAAC,GACxB,IAAI,CAKN;AAED,wBAAgB,OAAO,CACrB,IAAI,EAAE,MAAM,GACX,cAAc,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,UAAU,CAAC,GAAG,SAAS,CAExD;AAED,wBAAgB,SAAS,IAAI,cAAc,CAAC,CAAC,CAAC,UAAU,EAAE,CAAC,CAAC,UAAU,CAAC,EAAE,CAExE;AAED,0EAA0E;AAC1E,wBAAsB,OAAO,CAAC,CAAC,GAAG,OAAO,EACvC,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,OAAO,EACjB,GAAG,EAAE,WAAW,GACf,OAAO,CAAC,WAAW,CAAC,CAAC,CAAC,CAAC,CAqDzB;AAED,4CAA4C;AAC5C,wBAAgB,qBAAqB,IAAI,IAAI,CAE5C"}
@@ -0,0 +1,78 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.registerTool = registerTool;
4
+ exports.getTool = getTool;
5
+ exports.listTools = listTools;
6
+ exports.runTool = runTool;
7
+ exports._clearToolsForTesting = _clearToolsForTesting;
8
+ const tools = new Map();
9
+ function registerTool(def) {
10
+ if (tools.has(def.name)) {
11
+ throw new Error(`Tool already registered: ${def.name}`);
12
+ }
13
+ tools.set(def.name, def);
14
+ }
15
+ function getTool(name) {
16
+ return tools.get(name);
17
+ }
18
+ function listTools() {
19
+ return Array.from(tools.values());
20
+ }
21
+ /** Execute a tool by name with structured validation + error wrapping. */
22
+ async function runTool(name, rawInput, ctx) {
23
+ const start = Date.now();
24
+ const tool = tools.get(name);
25
+ if (!tool) {
26
+ return {
27
+ ok: false,
28
+ error: { code: "TOOL_NOT_FOUND", message: `Unknown tool: ${name}` },
29
+ durationMs: Date.now() - start,
30
+ };
31
+ }
32
+ const parsed = tool.inputSchema.safeParse(rawInput);
33
+ if (!parsed.success) {
34
+ return {
35
+ ok: false,
36
+ error: {
37
+ code: "INPUT_INVALID",
38
+ message: parsed.error.issues
39
+ .map((i) => `${i.path.join(".")}: ${i.message}`)
40
+ .join("; "),
41
+ },
42
+ durationMs: Date.now() - start,
43
+ };
44
+ }
45
+ try {
46
+ const output = await tool.handler(parsed.data, ctx);
47
+ const validatedOutput = tool.outputSchema.safeParse(output);
48
+ if (!validatedOutput.success) {
49
+ return {
50
+ ok: false,
51
+ error: {
52
+ code: "OUTPUT_INVALID",
53
+ message: `Tool ${name} returned malformed output: ${validatedOutput.error.message}`,
54
+ },
55
+ durationMs: Date.now() - start,
56
+ };
57
+ }
58
+ return {
59
+ ok: true,
60
+ output: validatedOutput.data,
61
+ durationMs: Date.now() - start,
62
+ };
63
+ }
64
+ catch (err) {
65
+ return {
66
+ ok: false,
67
+ error: {
68
+ code: "TOOL_THREW",
69
+ message: err instanceof Error ? err.message : String(err),
70
+ },
71
+ durationMs: Date.now() - start,
72
+ };
73
+ }
74
+ }
75
+ /** Test-only: drop all registered tools. */
76
+ function _clearToolsForTesting() {
77
+ tools.clear();
78
+ }
@@ -0,0 +1,36 @@
1
+ import { z } from "zod";
2
+ import { ToolDefinition } from "../toolRegistry";
3
+ /**
4
+ * Reference grounding — single highest-leverage accuracy multiplier.
5
+ *
6
+ * Pulls a TikTok / IG / YT video URL, runs scene detection + transcript +
7
+ * beat detection, returns structural features the planner can use as priors:
8
+ * pacing (cuts/sec), hook structure (where the first cut lands), shot count,
9
+ * music tempo, transcript excerpt.
10
+ *
11
+ * Heavy lifting (download, ffmpeg, scene detection) is host-side. Tool layer
12
+ * is host-agnostic, so the host wires the analyzer fn at boot.
13
+ */
14
+ export type ReferenceAnalyzerFn = (url: string) => Promise<{
15
+ durationMs: number;
16
+ sceneCount: number;
17
+ hookMs: number;
18
+ cutsPerSecond: number;
19
+ bpm?: number;
20
+ transcriptExcerpt?: string;
21
+ }>;
22
+ export declare function setReferenceAnalyzer(fn: ReferenceAnalyzerFn): void;
23
+ declare const InputSchema: z.ZodObject<{
24
+ url: z.ZodString;
25
+ }, z.core.$strip>;
26
+ declare const OutputSchema: z.ZodObject<{
27
+ durationMs: z.ZodNumber;
28
+ sceneCount: z.ZodNumber;
29
+ hookMs: z.ZodNumber;
30
+ cutsPerSecond: z.ZodNumber;
31
+ bpm: z.ZodOptional<z.ZodNumber>;
32
+ transcriptExcerpt: z.ZodOptional<z.ZodString>;
33
+ }, z.core.$strip>;
34
+ export declare const analyzeReferenceTool: ToolDefinition<typeof InputSchema, typeof OutputSchema>;
35
+ export {};
36
+ //# sourceMappingURL=analyzeReference.tool.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"analyzeReference.tool.d.ts","sourceRoot":"","sources":["../../../../src/services/agent/tools/analyzeReference.tool.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EAAgB,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAE/D;;;;;;;;;;GAUG;AAEH,MAAM,MAAM,mBAAmB,GAAG,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;IACzD,UAAU,EAAE,MAAM,CAAC;IACnB,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,iBAAiB,CAAC,EAAE,MAAM,CAAC;CAC5B,CAAC,CAAC;AAGH,wBAAgB,oBAAoB,CAAC,EAAE,EAAE,mBAAmB,GAAG,IAAI,CAElE;AAED,QAAA,MAAM,WAAW;;iBAKf,CAAC;AAEH,QAAA,MAAM,YAAY;;;;;;;iBAOhB,CAAC;AAEH,eAAO,MAAM,oBAAoB,EAAE,cAAc,CAC/C,OAAO,WAAW,EAClB,OAAO,YAAY,CAqBpB,CAAC"}