@j-o-r/hello-dave 0.1.1 → 0.1.5

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 (173) hide show
  1. package/CHANGELOG.md +42 -25
  2. package/README.md +81 -221
  3. package/TODO.md +173 -35
  4. package/agents/agent_creator.js +105 -0
  5. package/agents/agent_creator.prompt.md +371 -0
  6. package/agents/ask_agent.js +64 -127
  7. package/agents/claude_agent.js +68 -0
  8. package/agents/code_agent.js +55 -135
  9. package/agents/code_agent.prompt.md +50 -0
  10. package/agents/echo_agent.js +76 -0
  11. package/agents/financial_expert.js +75 -0
  12. package/agents/gpt_agent.js +52 -103
  13. package/agents/gpt_code.js +81 -0
  14. package/agents/grok_agent.js +58 -114
  15. package/agents/minimax_agent.js +92 -0
  16. package/agents/mureka_agent.js +77 -0
  17. package/agents/planner_agent.js +172 -0
  18. package/agents/stability_agent.js +87 -0
  19. package/agents/test_agent.js +75 -157
  20. package/agents/weather_agent.js +73 -0
  21. package/agents/workflow_agent.js +189 -0
  22. package/bin/dave.js +436 -184
  23. package/docs/bin-dave.md +85 -35
  24. package/docs/cdn-ssh.md +100 -0
  25. package/docs/creating-agents.md +301 -0
  26. package/docs/creating-toolsets.md +336 -0
  27. package/docs/docs-organization.md +48 -0
  28. package/docs/project-overview.md +86 -51
  29. package/lib/API/elevenlabs.io/music.compose.md +441 -0
  30. package/lib/API/elevenlabs.io/music.create-composition-plan.md +370 -0
  31. package/lib/API/elevenlabs.io/music.stream.md +425 -0
  32. package/lib/API/lalal.ai/lalal.js +445 -0
  33. package/lib/API/lalal.ai/openapi.json +2614 -0
  34. package/lib/API/minimax/ImageToolset.js +82 -37
  35. package/lib/API/minimax/MusicToolset.js +125 -79
  36. package/lib/API/minimax/VideoToolset.js +170 -167
  37. package/lib/API/minimax/image.js +5 -1
  38. package/lib/API/minimax/music.js +210 -23
  39. package/lib/API/minimax/video.js +242 -53
  40. package/lib/API/mureka/MusicToolset.js +646 -0
  41. package/lib/API/mureka/README.md +41 -0
  42. package/lib/API/mureka/index.js +7 -0
  43. package/lib/API/mureka/music.js +658 -0
  44. package/lib/API/openai.com/index.js +7 -0
  45. package/lib/API/openai.com/{reponses/text.js → responses.js} +64 -18
  46. package/lib/API/openai.com/video.create.character.md +40 -0
  47. package/lib/API/openai.com/video.create.md +219 -0
  48. package/lib/API/openai.com/video.delete.md +44 -0
  49. package/lib/API/openai.com/video.download.md +31 -0
  50. package/lib/API/openai.com/video.edit.md +155 -0
  51. package/lib/API/openai.com/video.extend.md +166 -0
  52. package/lib/API/openai.com/video.fetch.character.md +43 -0
  53. package/lib/API/openai.com/video.js +784 -0
  54. package/lib/API/openai.com/video.list.md +201 -0
  55. package/lib/API/openai.com/video.remix.md +175 -0
  56. package/lib/API/openai.com/video.retrieve.md +139 -0
  57. package/lib/API/openai.com/videoToolset.js +616 -0
  58. package/lib/API/stability.ai/ImageToolset.js +131 -40
  59. package/lib/API/stability.ai/MusicToolset.js +79 -47
  60. package/lib/API/stability.ai/audio.js +63 -131
  61. package/lib/API/x.ai/chat.responses.md +1040 -0
  62. package/lib/API/x.ai/image.js +229 -59
  63. package/lib/API/x.ai/imageToolset.js +376 -0
  64. package/lib/API/x.ai/index.js +1 -1
  65. package/lib/API/x.ai/responses.js +9 -18
  66. package/lib/Agent.js +271 -0
  67. package/lib/Agent.js.old +284 -0
  68. package/lib/AgentLauncher.js +593 -0
  69. package/lib/Cli.js +87 -13
  70. package/lib/Prompt.js +23 -1
  71. package/lib/Session.js +5 -4
  72. package/lib/ToolSet.js +102 -6
  73. package/lib/agentLoader.js +369 -0
  74. package/lib/cdn.js +67 -231
  75. package/lib/{CdnToolset.js → cdnToolset.js} +47 -64
  76. package/lib/defaultToolsets.js +43 -0
  77. package/lib/fafs.js +1 -1
  78. package/lib/genericToolset.js +442 -119
  79. package/lib/handOffToolset.js +179 -0
  80. package/lib/index.js +34 -27
  81. package/lib/toolsetLoader.js +248 -0
  82. package/package.json +10 -4
  83. package/types/API/lalal.ai/lalal.d.ts +116 -0
  84. package/types/API/minimax/image.d.ts +2 -1
  85. package/types/API/minimax/music.d.ts +189 -26
  86. package/types/API/minimax/video.d.ts +100 -31
  87. package/types/API/mureka/index.d.ts +7 -0
  88. package/types/API/mureka/music.d.ts +472 -0
  89. package/types/API/openai.com/index.d.ts +7 -0
  90. package/types/API/openai.com/{reponses/text.d.ts → responses.d.ts} +11 -11
  91. package/types/API/openai.com/video.d.ts +409 -0
  92. package/types/API/openai.com/videoToolset.d.ts +24 -0
  93. package/types/API/stability.ai/audio.d.ts +14 -103
  94. package/types/API/stability.ai/image.d.ts +2 -2
  95. package/types/API/x.ai/image.d.ts +138 -26
  96. package/types/API/x.ai/imageToolset.d.ts +3 -0
  97. package/types/API/x.ai/index.d.ts +1 -1
  98. package/types/API/x.ai/responses.d.ts +4 -4
  99. package/types/Agent.d.ts +123 -0
  100. package/types/AgentLauncher.d.ts +250 -0
  101. package/types/Cli.d.ts +28 -8
  102. package/types/Prompt.d.ts +23 -5
  103. package/types/Session.d.ts +1 -1
  104. package/types/ToolSet.d.ts +10 -0
  105. package/types/agentLoader.d.ts +78 -0
  106. package/types/cdn.d.ts +15 -90
  107. package/types/defaultToolsets.d.ts +9 -0
  108. package/types/fafs.d.ts +1 -1
  109. package/types/genericToolset.d.ts +1 -1
  110. package/types/handOffToolset.d.ts +28 -0
  111. package/types/index.d.ts +19 -17
  112. package/types/toolsetLoader.d.ts +114 -0
  113. package/utils/format_log.js +101 -23
  114. package/utils/launch_agent.js +18 -0
  115. package/utils/list_sessions.sh +13 -5
  116. package/utils/search_sessions.sh +65 -29
  117. package/utils/toolsets.js +33 -0
  118. package/README.md.bak.1779452127 +0 -240
  119. package/agents/codeserver.sh +0 -47
  120. package/agents/daisy_agent.js +0 -173
  121. package/agents/docs_agent.js +0 -148
  122. package/agents/memory_agent.js +0 -263
  123. package/agents/minimax.js +0 -173
  124. package/agents/npm_agent.js +0 -202
  125. package/agents/prompt_agent.js +0 -133
  126. package/agents/readme_agent.js +0 -148
  127. package/agents/spawn_agent.js +0 -160
  128. package/agents/stability.js +0 -173
  129. package/agents/todo_agent.js +0 -175
  130. package/bin/codeDave +0 -58
  131. package/docs/agent-dave-websocket-protocol.md +0 -180
  132. package/docs/agent-manager.md +0 -244
  133. package/docs/codeserver-pattern.md +0 -191
  134. package/docs/generic-toolset.md +0 -326
  135. package/docs/howtos/agent-networking.md +0 -253
  136. package/docs/howtos/spawn-agents.md.bak +0 -200
  137. package/docs/howtos/spawn-agents.md.bak_new +0 -200
  138. package/docs/multi-agent-clusters.md +0 -265
  139. package/docs/music-toolsets.md +0 -137
  140. package/docs/path-resolution-best-practices.md +0 -104
  141. package/docs/plans/minimax-music-generation.md +0 -80
  142. package/docs/plans/unified-agent-architecture.md +0 -146
  143. package/docs/plans/websocket-streaming-plan.md.bak +0 -317
  144. package/docs/prompt/spawn_agent.md +0 -175
  145. package/docs/prompt/spawn_agent.md.bak +0 -201
  146. package/docs/prompt/task_clarification_and_documentation.md +0 -35
  147. package/docs/prompt-class.md +0 -141
  148. package/docs/todo-archive-infra-2026-04-21.md +0 -15
  149. package/docs/todo-archive-v0.0.8.md +0 -1
  150. package/docs/todo-archive-v0.1.0.md +0 -32
  151. package/docs/todo-archive.md +0 -44
  152. package/docs/tools-syntax-validation.md +0 -121
  153. package/docs/toolset.md +0 -164
  154. package/docs/xai-responses.md +0 -111
  155. package/docs/xai_collections.md +0 -106
  156. package/lib/API/x.ai/ImageToolset.js +0 -165
  157. package/lib/API/x.ai/text.js +0 -415
  158. package/lib/AgentClient.js +0 -248
  159. package/lib/AgentManager.js +0 -245
  160. package/lib/AgentServer.js +0 -404
  161. package/lib/wsCli.js +0 -287
  162. package/lib/wsIO.js +0 -90
  163. package/types/API/x.ai/text.d.ts +0 -286
  164. package/types/AgentClient.d.ts +0 -109
  165. package/types/AgentManager.d.ts +0 -100
  166. package/types/AgentServer.d.ts +0 -89
  167. package/types/wsCli.d.ts +0 -17
  168. package/types/wsIO.d.ts +0 -30
  169. package/utils/test.sh +0 -46
  170. /package/docs/{suggestions.md → _notes/token-counts.md} +0 -0
  171. /package/lib/API/openai.com/{reponses/MESSAGES.md → MESSAGES.md} +0 -0
  172. /package/types/API/{x.ai/ImageToolset.d.ts → mureka/MusicToolset.d.ts} +0 -0
  173. /package/types/{CdnToolset.d.ts → cdnToolset.d.ts} +0 -0
@@ -0,0 +1,616 @@
1
+ /**
2
+ * @file lib/API/openai.com/videoToolset.js
3
+ * @module openai.com/videoToolset
4
+ * @description ToolSet wrapper for the OpenAI video API wrapper.
5
+ *
6
+ * Exposes OpenAI video operations as function-call tools:
7
+ * - create_video_openai
8
+ * - retrieve_video_openai
9
+ * - list_videos_openai
10
+ * - download_video_openai
11
+ * - delete_video_openai
12
+ * - edit_video_openai
13
+ * - extend_video_openai
14
+ * - remix_video_openai
15
+ * - emergency_poll_video_openai
16
+ * - create_character_openai
17
+ * - fetch_character_openai
18
+ *
19
+ * For video creation with a visual reference, prefer `image_url`. The handler
20
+ * maps `image_url` to the wrapper's `input_reference: { image_url }` shape.
21
+ * Use `file_id` only when a URL/data URL is not available.
22
+ *
23
+ * @see ./video.js for the underlying implementation and full JSDoc.
24
+ * @see ./video.create.md
25
+ * @see ./video.retrieve.md
26
+ * @see ./video.download.md
27
+ * @see ./video.edit.md
28
+ * @see ./video.extend.md
29
+ * @see ./video.remix.md
30
+ * @see ./video.list.md
31
+ * @see ./video.delete.md
32
+ * @see ./video.create.character.md
33
+ * @see ./video.fetch.character.md
34
+ */
35
+
36
+ import ToolSet from '../../ToolSet.js';
37
+ import * as openaiVideo from './video.js';
38
+
39
+ const tools = new ToolSet('auto');
40
+
41
+ /**
42
+ * Supported downloadable video asset variants.
43
+ * @typedef {'video'|'thumbnail'|'spritesheet'} VideoAssetVariant
44
+ */
45
+
46
+ /**
47
+ * JSON-serializable summary returned for downloaded media content.
48
+ * @typedef {Object} DownloadSummary
49
+ * @property {string} contentType - Response content type.
50
+ * @property {number} bytes - Number of downloaded bytes.
51
+ * @property {string} [local_path] - Local saved file path when available.
52
+ */
53
+
54
+ /**
55
+ * Extract a compact, JSON-safe summary from a downloaded media result.
56
+ * Avoids serializing raw Buffer bytes into tool responses.
57
+ * @param {{contentType?: string, bytes?: number, local_path?: string}} [content] - Download result from video.js.
58
+ * @returns {DownloadSummary|undefined} JSON-safe media summary.
59
+ */
60
+ function summarizeContent(content) {
61
+ if (!content) return undefined;
62
+ return {
63
+ contentType: content.contentType,
64
+ bytes: content.bytes,
65
+ local_path: content.local_path
66
+ };
67
+ }
68
+
69
+ /**
70
+ * Return an object copy without raw binary content buffers.
71
+ * @param {Record<string, *>} value - API response object.
72
+ * @returns {Record<string, *>} JSON-safe response object.
73
+ */
74
+ function withoutRawBuffers(value) {
75
+ if (!value || typeof value !== 'object') return value;
76
+ const copy = { ...value };
77
+ if (copy.content) copy.content = summarizeContent(copy.content);
78
+ if (copy.buffer) delete copy.buffer;
79
+ return copy;
80
+ }
81
+
82
+ /**
83
+ * Stringify a tool response with stable two-space formatting.
84
+ * @param {Record<string, *>} payload - Response payload.
85
+ * @returns {string} JSON string for function-call response.
86
+ */
87
+ function json(payload) {
88
+ return JSON.stringify(payload, null, 2);
89
+ }
90
+
91
+ /**
92
+ * Build the OpenAI create-video options object from tool parameters.
93
+ * Prefers `image_url` over `file_id` for `input_reference` when both are present.
94
+ * @param {Record<string, *>} params - Tool parameters.
95
+ * @returns {Record<string, *>} Options for createVideo().
96
+ */
97
+ function buildCreateOptions(params) {
98
+ const options = { ...params };
99
+ delete options.prompt;
100
+ delete options.image_url;
101
+ delete options.file_id;
102
+
103
+ if (params.image_url) {
104
+ options.input_reference = { image_url: params.image_url };
105
+ } else if (params.file_id) {
106
+ options.input_reference = { file_id: params.file_id };
107
+ }
108
+
109
+ return options;
110
+ }
111
+
112
+ /**
113
+ * Download the final video asset for a completed video response when requested.
114
+ * @param {Record<string, *>} video - Completed video response.
115
+ * @param {Record<string, *>} params - Tool parameters.
116
+ * @returns {Promise<Record<string, *>>} Video response with optional JSON-safe content summary.
117
+ */
118
+ async function maybeDownloadCompletedVideo(video, params) {
119
+ if (!params.download) return withoutRawBuffers(video);
120
+
121
+ const content = await openaiVideo.downloadVideoContent(video.id, {
122
+ variant: params.variant || 'video',
123
+ save: true,
124
+ filenamePrefix: params.filenamePrefix || 'openai-video',
125
+ userAgent: params.userAgent
126
+ });
127
+
128
+ return withoutRawBuffers({ ...video, content });
129
+ }
130
+
131
+ /* ============================================================
132
+ CREATE VIDEO
133
+ ============================================================ */
134
+
135
+ tools.add(
136
+ 'create_video_openai',
137
+ 'Create an OpenAI Sora video from a text prompt and wait until the job completes. ' +
138
+ 'Optionally provide a visual reference via image_url; this is strongly preferred over file_id and is mapped to input_reference.image_url. ' +
139
+ 'Use a public HTTPS image URL or base64 data URL for image_url. ' +
140
+ 'Returns the completed video metadata including id; that id is the videoId for retrieve/download/edit/extend/remix/delete. ' +
141
+ 'Set download=true to save the completed MP4 locally under .cache/openai/. Video generation can take several minutes.',
142
+ {
143
+ type: 'object',
144
+ properties: {
145
+ prompt: {
146
+ type: 'string',
147
+ description: 'Text prompt describing the video to generate. Be specific about subject, motion, camera movement, style, lighting, and scene changes.'
148
+ },
149
+ image_url: {
150
+ type: 'string',
151
+ description: 'Preferred optional visual reference: fully-qualified image URL or base64 data URL. Internally mapped to input_reference.image_url.'
152
+ },
153
+ file_id: {
154
+ type: 'string',
155
+ description: 'Optional OpenAI file id for an image reference. Use only when image_url is not available.'
156
+ },
157
+ model: {
158
+ type: 'string',
159
+ default: 'sora-2',
160
+ description: 'Video model. Common values: sora-2, sora-2-pro.'
161
+ },
162
+ seconds: {
163
+ type: 'string',
164
+ enum: ['4', '8', '12'],
165
+ default: '4',
166
+ description: 'Clip duration in seconds. Allowed values: 4, 8, 12.'
167
+ },
168
+ size: {
169
+ type: 'string',
170
+ enum: ['720x1280', '1280x720', '1024x1792', '1792x1024'],
171
+ default: '720x1280',
172
+ description: 'Output resolution as width x height.'
173
+ },
174
+ download: {
175
+ type: 'boolean',
176
+ default: false,
177
+ description: 'When true, download and save the completed video locally after generation.'
178
+ },
179
+ variant: {
180
+ type: 'string',
181
+ enum: ['video', 'thumbnail', 'spritesheet'],
182
+ default: 'video',
183
+ description: 'Asset variant to download when download=true.'
184
+ },
185
+ filenamePrefix: {
186
+ type: 'string',
187
+ default: 'openai-video',
188
+ description: 'Local filename prefix when download=true.'
189
+ },
190
+ maxWaitMs: {
191
+ type: 'integer',
192
+ default: 600000,
193
+ description: 'Maximum polling time in milliseconds. Default: 600000 (10 minutes).'
194
+ },
195
+ pollIntervalMs: {
196
+ type: 'integer',
197
+ default: 5000,
198
+ description: 'Delay between polling requests in milliseconds. Default: 5000.'
199
+ }
200
+ },
201
+ required: ['prompt']
202
+ },
203
+ async (params) => {
204
+ const result = await openaiVideo.createVideo(params.prompt, buildCreateOptions(params));
205
+ return json({
206
+ ...withoutRawBuffers(result),
207
+ videoId: result.id,
208
+ note: 'Video created successfully with create_video_openai. Use videoId for follow-up tools.'
209
+ });
210
+ }
211
+ );
212
+
213
+ /* ============================================================
214
+ RETRIEVE / LIST
215
+ ============================================================ */
216
+
217
+ tools.add(
218
+ 'retrieve_video_openai',
219
+ 'Retrieve the latest metadata for an OpenAI video job. Use this to check status, progress, expiry, prompt, size, seconds, and model. Requires videoId.',
220
+ {
221
+ type: 'object',
222
+ properties: {
223
+ videoId: {
224
+ type: 'string',
225
+ description: 'OpenAI video id. This is the id returned by create_video_openai or list_videos_openai.'
226
+ }
227
+ },
228
+ required: ['videoId']
229
+ },
230
+ async (params) => {
231
+ const result = await openaiVideo.retrieveVideo(params.videoId, params);
232
+ return json({
233
+ ...withoutRawBuffers(result),
234
+ videoId: result.id,
235
+ note: 'Video metadata retrieved successfully with retrieve_video_openai.'
236
+ });
237
+ }
238
+ );
239
+
240
+ tools.add(
241
+ 'list_videos_openai',
242
+ 'List recently generated OpenAI videos for the current project. Use this to discover existing videoId values for download, retrieve, edit, extend, remix, or delete.',
243
+ {
244
+ type: 'object',
245
+ properties: {
246
+ after: {
247
+ type: 'string',
248
+ description: 'Pagination cursor: id of the last item from the previous page.'
249
+ },
250
+ limit: {
251
+ type: 'integer',
252
+ minimum: 1,
253
+ description: 'Maximum number of videos to retrieve.'
254
+ },
255
+ order: {
256
+ type: 'string',
257
+ enum: ['asc', 'desc'],
258
+ description: 'Sort order by timestamp.'
259
+ }
260
+ }
261
+ },
262
+ async (params) => {
263
+ const query = {
264
+ after: params.after,
265
+ limit: params.limit,
266
+ order: params.order
267
+ };
268
+ const result = await openaiVideo.listVideos(query, params);
269
+ return json({
270
+ ...result,
271
+ videoIds: Array.isArray(result.data) ? result.data.map(video => video.id).filter(Boolean) : [],
272
+ note: 'Videos listed successfully with list_videos_openai. Each item id is a usable videoId.'
273
+ });
274
+ }
275
+ );
276
+
277
+ /* ============================================================
278
+ DOWNLOAD / DELETE
279
+ ============================================================ */
280
+
281
+ tools.add(
282
+ 'download_video_openai',
283
+ 'Download generated OpenAI video bytes or a preview asset. By default saves the MP4 locally under .cache/openai/ and returns local_path, contentType, and byte count. Requires a completed videoId.',
284
+ {
285
+ type: 'object',
286
+ properties: {
287
+ videoId: {
288
+ type: 'string',
289
+ description: 'OpenAI video id to download. The video should be completed.'
290
+ },
291
+ variant: {
292
+ type: 'string',
293
+ enum: ['video', 'thumbnail', 'spritesheet'],
294
+ default: 'video',
295
+ description: 'Which downloadable asset to return. Defaults to MP4 video.'
296
+ },
297
+ save: {
298
+ type: 'boolean',
299
+ default: true,
300
+ description: 'Save downloaded bytes to .cache/openai/. Defaults to true for tool usage.'
301
+ },
302
+ filenamePrefix: {
303
+ type: 'string',
304
+ default: 'openai-video',
305
+ description: 'Local filename prefix when save=true.'
306
+ }
307
+ },
308
+ required: ['videoId']
309
+ },
310
+ async (params) => {
311
+ const result = await openaiVideo.downloadVideoContent(params.videoId, {
312
+ ...params,
313
+ save: params.save !== false,
314
+ variant: params.variant || 'video',
315
+ filenamePrefix: params.filenamePrefix || 'openai-video'
316
+ });
317
+
318
+ return json({
319
+ videoId: params.videoId,
320
+ ...summarizeContent(result),
321
+ note: 'Video content downloaded successfully with download_video_openai.'
322
+ });
323
+ }
324
+ );
325
+
326
+ tools.add(
327
+ 'delete_video_openai',
328
+ 'Permanently delete a completed or failed OpenAI video and its stored assets. Requires videoId. Use carefully; this cannot be undone.',
329
+ {
330
+ type: 'object',
331
+ properties: {
332
+ videoId: {
333
+ type: 'string',
334
+ description: 'OpenAI video id to delete.'
335
+ }
336
+ },
337
+ required: ['videoId']
338
+ },
339
+ async (params) => {
340
+ const result = await openaiVideo.deleteVideo(params.videoId, params);
341
+ return json({
342
+ ...result,
343
+ videoId: result.id,
344
+ note: 'Video deleted successfully with delete_video_openai.'
345
+ });
346
+ }
347
+ );
348
+
349
+ /* ============================================================
350
+ EDIT / EXTEND / REMIX
351
+ ============================================================ */
352
+
353
+ tools.add(
354
+ 'edit_video_openai',
355
+ 'Create a new OpenAI video by editing a completed source video. Requires source videoId and an edit prompt. Returns the new completed video id. Optionally downloads the result locally.',
356
+ {
357
+ type: 'object',
358
+ properties: {
359
+ videoId: {
360
+ type: 'string',
361
+ description: 'Completed source OpenAI video id to edit.'
362
+ },
363
+ prompt: {
364
+ type: 'string',
365
+ description: 'Natural-language edit instruction describing how to change the source video.'
366
+ },
367
+ download: {
368
+ type: 'boolean',
369
+ default: false,
370
+ description: 'When true, download and save the edited video locally after completion.'
371
+ },
372
+ variant: {
373
+ type: 'string',
374
+ enum: ['video', 'thumbnail', 'spritesheet'],
375
+ default: 'video',
376
+ description: 'Asset variant to download when download=true.'
377
+ },
378
+ maxWaitMs: {
379
+ type: 'integer',
380
+ default: 600000,
381
+ description: 'Maximum polling time in milliseconds.'
382
+ },
383
+ pollIntervalMs: {
384
+ type: 'integer',
385
+ default: 5000,
386
+ description: 'Delay between polling requests in milliseconds.'
387
+ }
388
+ },
389
+ required: ['videoId', 'prompt']
390
+ },
391
+ async (params) => {
392
+ const result = await openaiVideo.editVideo(params.videoId, params.prompt, params);
393
+ const finalResult = await maybeDownloadCompletedVideo(result, params);
394
+ return json({
395
+ ...finalResult,
396
+ sourceVideoId: params.videoId,
397
+ videoId: result.id,
398
+ note: 'Video edited successfully with edit_video_openai. The returned videoId is the new edited video.'
399
+ });
400
+ }
401
+ );
402
+
403
+ tools.add(
404
+ 'extend_video_openai',
405
+ 'Create an extension of a completed OpenAI video. Requires source videoId, prompt, and optional seconds for the new segment. Returns the new completed video id. Optionally downloads the result locally.',
406
+ {
407
+ type: 'object',
408
+ properties: {
409
+ videoId: {
410
+ type: 'string',
411
+ description: 'Completed source OpenAI video id to extend.'
412
+ },
413
+ prompt: {
414
+ type: 'string',
415
+ description: 'Prompt directing the continuation/extension generation.'
416
+ },
417
+ seconds: {
418
+ type: 'string',
419
+ enum: ['4', '8', '12', '16', '20'],
420
+ default: '4',
421
+ description: 'Length of the newly generated extension segment in seconds.'
422
+ },
423
+ download: {
424
+ type: 'boolean',
425
+ default: false,
426
+ description: 'When true, download and save the extended video locally after completion.'
427
+ },
428
+ variant: {
429
+ type: 'string',
430
+ enum: ['video', 'thumbnail', 'spritesheet'],
431
+ default: 'video',
432
+ description: 'Asset variant to download when download=true.'
433
+ },
434
+ maxWaitMs: {
435
+ type: 'integer',
436
+ default: 600000,
437
+ description: 'Maximum polling time in milliseconds.'
438
+ },
439
+ pollIntervalMs: {
440
+ type: 'integer',
441
+ default: 5000,
442
+ description: 'Delay between polling requests in milliseconds.'
443
+ }
444
+ },
445
+ required: ['videoId', 'prompt']
446
+ },
447
+ async (params) => {
448
+ const result = await openaiVideo.extendVideo(params.videoId, params.prompt, params.seconds || '4', params);
449
+ const finalResult = await maybeDownloadCompletedVideo(result, params);
450
+ return json({
451
+ ...finalResult,
452
+ sourceVideoId: params.videoId,
453
+ videoId: result.id,
454
+ note: 'Video extended successfully with extend_video_openai. The returned videoId is the new extended video.'
455
+ });
456
+ }
457
+ );
458
+
459
+ tools.add(
460
+ 'remix_video_openai',
461
+ 'Create a remix of a completed OpenAI video using a refreshed prompt. Requires source videoId and prompt. Returns the new completed video id. Optionally downloads the result locally.',
462
+ {
463
+ type: 'object',
464
+ properties: {
465
+ videoId: {
466
+ type: 'string',
467
+ description: 'Completed source OpenAI video id to remix.'
468
+ },
469
+ prompt: {
470
+ type: 'string',
471
+ description: 'Updated prompt that directs the remix generation.'
472
+ },
473
+ download: {
474
+ type: 'boolean',
475
+ default: false,
476
+ description: 'When true, download and save the remixed video locally after completion.'
477
+ },
478
+ variant: {
479
+ type: 'string',
480
+ enum: ['video', 'thumbnail', 'spritesheet'],
481
+ default: 'video',
482
+ description: 'Asset variant to download when download=true.'
483
+ },
484
+ maxWaitMs: {
485
+ type: 'integer',
486
+ default: 600000,
487
+ description: 'Maximum polling time in milliseconds.'
488
+ },
489
+ pollIntervalMs: {
490
+ type: 'integer',
491
+ default: 5000,
492
+ description: 'Delay between polling requests in milliseconds.'
493
+ }
494
+ },
495
+ required: ['videoId', 'prompt']
496
+ },
497
+ async (params) => {
498
+ const result = await openaiVideo.remixVideo(params.videoId, params.prompt, params);
499
+ const finalResult = await maybeDownloadCompletedVideo(result, params);
500
+ return json({
501
+ ...finalResult,
502
+ sourceVideoId: params.videoId,
503
+ videoId: result.id,
504
+ note: 'Video remixed successfully with remix_video_openai. The returned videoId is the new remixed video.'
505
+ });
506
+ }
507
+ );
508
+
509
+ /* ============================================================
510
+ EMERGENCY POLLING
511
+ ============================================================ */
512
+
513
+ tools.add(
514
+ 'emergency_poll_video_openai',
515
+ 'Continue polling an OpenAI video job after a previous generation/edit/extend/remix timeout. Requires videoId from the original job or thrown timeout metadata. Defaults are long and conservative. Optionally downloads the final asset.',
516
+ {
517
+ type: 'object',
518
+ properties: {
519
+ videoId: {
520
+ type: 'string',
521
+ description: 'OpenAI video id to continue polling.'
522
+ },
523
+ maxWaitMs: {
524
+ type: 'integer',
525
+ default: 3600000,
526
+ description: 'Maximum polling time in milliseconds. Default: 3600000 (1 hour).'
527
+ },
528
+ pollIntervalMs: {
529
+ type: 'integer',
530
+ default: 30000,
531
+ description: 'Delay between polling requests in milliseconds. Default: 30000.'
532
+ },
533
+ download: {
534
+ type: 'boolean',
535
+ default: false,
536
+ description: 'When true, download and save final media after completion.'
537
+ },
538
+ variant: {
539
+ type: 'string',
540
+ enum: ['video', 'thumbnail', 'spritesheet'],
541
+ default: 'video',
542
+ description: 'Asset variant to download when download=true.'
543
+ },
544
+ filenamePrefix: {
545
+ type: 'string',
546
+ default: 'openai-video',
547
+ description: 'Local filename prefix when download=true.'
548
+ }
549
+ },
550
+ required: ['videoId']
551
+ },
552
+ async (params) => {
553
+ const result = await openaiVideo.emergencyPollVideo(params.videoId, params);
554
+ return json({
555
+ ...withoutRawBuffers(result),
556
+ videoId: result.id,
557
+ note: 'Emergency polling completed successfully with emergency_poll_video_openai.'
558
+ });
559
+ }
560
+ );
561
+
562
+ /* ============================================================
563
+ CHARACTERS
564
+ ============================================================ */
565
+
566
+ tools.add(
567
+ 'create_character_openai',
568
+ 'Create an OpenAI video character/cameo from an uploaded video. This endpoint requires a video file input, so image_url is not applicable here.',
569
+ {
570
+ type: 'object',
571
+ properties: {
572
+ name: {
573
+ type: 'string',
574
+ description: 'Display name for the character.'
575
+ },
576
+ video_path: {
577
+ type: 'string',
578
+ description: 'Local path to a video file to upload for character creation.'
579
+ }
580
+ },
581
+ required: ['name', 'video_path']
582
+ },
583
+ async (params) => {
584
+ const result = await openaiVideo.createCharacter(params.name, params.video_path, params);
585
+ return json({
586
+ ...result,
587
+ characterId: result.id,
588
+ note: 'Character created successfully with create_character_openai. Use characterId with fetch_character_openai.'
589
+ });
590
+ }
591
+ );
592
+
593
+ tools.add(
594
+ 'fetch_character_openai',
595
+ 'Fetch an OpenAI video character/cameo by characterId.',
596
+ {
597
+ type: 'object',
598
+ properties: {
599
+ characterId: {
600
+ type: 'string',
601
+ description: 'OpenAI video character id returned by create_character_openai.'
602
+ }
603
+ },
604
+ required: ['characterId']
605
+ },
606
+ async (params) => {
607
+ const result = await openaiVideo.fetchCharacter(params.characterId, params);
608
+ return json({
609
+ ...result,
610
+ characterId: result.id,
611
+ note: 'Character fetched successfully with fetch_character_openai.'
612
+ });
613
+ }
614
+ );
615
+
616
+ export default tools;