vidpipe 1.2.2 → 1.2.3

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 (161) hide show
  1. package/dist/index.d.ts +2 -2
  2. package/dist/index.js +4766 -123
  3. package/dist/index.js.map +1 -1
  4. package/package.json +4 -2
  5. package/dist/agents/BaseAgent.d.ts +0 -52
  6. package/dist/agents/BaseAgent.d.ts.map +0 -1
  7. package/dist/agents/BaseAgent.js +0 -102
  8. package/dist/agents/BaseAgent.js.map +0 -1
  9. package/dist/agents/BlogAgent.d.ts +0 -3
  10. package/dist/agents/BlogAgent.d.ts.map +0 -1
  11. package/dist/agents/BlogAgent.js +0 -163
  12. package/dist/agents/BlogAgent.js.map +0 -1
  13. package/dist/agents/ChapterAgent.d.ts +0 -11
  14. package/dist/agents/ChapterAgent.d.ts.map +0 -1
  15. package/dist/agents/ChapterAgent.js +0 -191
  16. package/dist/agents/ChapterAgent.js.map +0 -1
  17. package/dist/agents/MediumVideoAgent.d.ts +0 -3
  18. package/dist/agents/MediumVideoAgent.d.ts.map +0 -1
  19. package/dist/agents/MediumVideoAgent.js +0 -219
  20. package/dist/agents/MediumVideoAgent.js.map +0 -1
  21. package/dist/agents/ShortsAgent.d.ts +0 -3
  22. package/dist/agents/ShortsAgent.d.ts.map +0 -1
  23. package/dist/agents/ShortsAgent.js +0 -243
  24. package/dist/agents/ShortsAgent.js.map +0 -1
  25. package/dist/agents/SilenceRemovalAgent.d.ts +0 -9
  26. package/dist/agents/SilenceRemovalAgent.d.ts.map +0 -1
  27. package/dist/agents/SilenceRemovalAgent.js +0 -209
  28. package/dist/agents/SilenceRemovalAgent.js.map +0 -1
  29. package/dist/agents/SocialMediaAgent.d.ts +0 -4
  30. package/dist/agents/SocialMediaAgent.d.ts.map +0 -1
  31. package/dist/agents/SocialMediaAgent.js +0 -248
  32. package/dist/agents/SocialMediaAgent.js.map +0 -1
  33. package/dist/agents/SummaryAgent.d.ts +0 -11
  34. package/dist/agents/SummaryAgent.d.ts.map +0 -1
  35. package/dist/agents/SummaryAgent.js +0 -333
  36. package/dist/agents/SummaryAgent.js.map +0 -1
  37. package/dist/commands/doctor.d.ts +0 -4
  38. package/dist/commands/doctor.d.ts.map +0 -1
  39. package/dist/commands/doctor.js +0 -230
  40. package/dist/commands/doctor.js.map +0 -1
  41. package/dist/config/brand.d.ts +0 -29
  42. package/dist/config/brand.d.ts.map +0 -1
  43. package/dist/config/brand.js +0 -83
  44. package/dist/config/brand.js.map +0 -1
  45. package/dist/config/environment.d.ts +0 -39
  46. package/dist/config/environment.d.ts.map +0 -1
  47. package/dist/config/environment.js +0 -47
  48. package/dist/config/environment.js.map +0 -1
  49. package/dist/config/ffmpegResolver.d.ts +0 -3
  50. package/dist/config/ffmpegResolver.d.ts.map +0 -1
  51. package/dist/config/ffmpegResolver.js +0 -37
  52. package/dist/config/ffmpegResolver.js.map +0 -1
  53. package/dist/config/logger.d.ts +0 -5
  54. package/dist/config/logger.d.ts.map +0 -1
  55. package/dist/config/logger.js +0 -13
  56. package/dist/config/logger.js.map +0 -1
  57. package/dist/config/pricing.d.ts +0 -34
  58. package/dist/config/pricing.d.ts.map +0 -1
  59. package/dist/config/pricing.js +0 -71
  60. package/dist/config/pricing.js.map +0 -1
  61. package/dist/index.d.ts.map +0 -1
  62. package/dist/pipeline.d.ts +0 -57
  63. package/dist/pipeline.d.ts.map +0 -1
  64. package/dist/pipeline.js +0 -324
  65. package/dist/pipeline.js.map +0 -1
  66. package/dist/providers/ClaudeProvider.d.ts +0 -14
  67. package/dist/providers/ClaudeProvider.d.ts.map +0 -1
  68. package/dist/providers/ClaudeProvider.js +0 -182
  69. package/dist/providers/ClaudeProvider.js.map +0 -1
  70. package/dist/providers/CopilotProvider.d.ts +0 -17
  71. package/dist/providers/CopilotProvider.d.ts.map +0 -1
  72. package/dist/providers/CopilotProvider.js +0 -149
  73. package/dist/providers/CopilotProvider.js.map +0 -1
  74. package/dist/providers/OpenAIProvider.d.ts +0 -14
  75. package/dist/providers/OpenAIProvider.d.ts.map +0 -1
  76. package/dist/providers/OpenAIProvider.js +0 -175
  77. package/dist/providers/OpenAIProvider.js.map +0 -1
  78. package/dist/providers/index.d.ts +0 -18
  79. package/dist/providers/index.d.ts.map +0 -1
  80. package/dist/providers/index.js +0 -61
  81. package/dist/providers/index.js.map +0 -1
  82. package/dist/providers/types.d.ts +0 -112
  83. package/dist/providers/types.d.ts.map +0 -1
  84. package/dist/providers/types.js +0 -8
  85. package/dist/providers/types.js.map +0 -1
  86. package/dist/services/captionGeneration.d.ts +0 -7
  87. package/dist/services/captionGeneration.d.ts.map +0 -1
  88. package/dist/services/captionGeneration.js +0 -29
  89. package/dist/services/captionGeneration.js.map +0 -1
  90. package/dist/services/costTracker.d.ts +0 -63
  91. package/dist/services/costTracker.d.ts.map +0 -1
  92. package/dist/services/costTracker.js +0 -137
  93. package/dist/services/costTracker.js.map +0 -1
  94. package/dist/services/fileWatcher.d.ts +0 -19
  95. package/dist/services/fileWatcher.d.ts.map +0 -1
  96. package/dist/services/fileWatcher.js +0 -120
  97. package/dist/services/fileWatcher.js.map +0 -1
  98. package/dist/services/gitOperations.d.ts +0 -3
  99. package/dist/services/gitOperations.d.ts.map +0 -1
  100. package/dist/services/gitOperations.js +0 -43
  101. package/dist/services/gitOperations.js.map +0 -1
  102. package/dist/services/socialPosting.d.ts +0 -38
  103. package/dist/services/socialPosting.d.ts.map +0 -1
  104. package/dist/services/socialPosting.js +0 -102
  105. package/dist/services/socialPosting.js.map +0 -1
  106. package/dist/services/transcription.d.ts +0 -3
  107. package/dist/services/transcription.d.ts.map +0 -1
  108. package/dist/services/transcription.js +0 -100
  109. package/dist/services/transcription.js.map +0 -1
  110. package/dist/services/videoIngestion.d.ts +0 -3
  111. package/dist/services/videoIngestion.d.ts.map +0 -1
  112. package/dist/services/videoIngestion.js +0 -104
  113. package/dist/services/videoIngestion.js.map +0 -1
  114. package/dist/tools/captions/captionGenerator.d.ts +0 -84
  115. package/dist/tools/captions/captionGenerator.d.ts.map +0 -1
  116. package/dist/tools/captions/captionGenerator.js +0 -390
  117. package/dist/tools/captions/captionGenerator.js.map +0 -1
  118. package/dist/tools/ffmpeg/aspectRatio.d.ts +0 -101
  119. package/dist/tools/ffmpeg/aspectRatio.d.ts.map +0 -1
  120. package/dist/tools/ffmpeg/aspectRatio.js +0 -339
  121. package/dist/tools/ffmpeg/aspectRatio.js.map +0 -1
  122. package/dist/tools/ffmpeg/audioExtraction.d.ts +0 -16
  123. package/dist/tools/ffmpeg/audioExtraction.d.ts.map +0 -1
  124. package/dist/tools/ffmpeg/audioExtraction.js +0 -87
  125. package/dist/tools/ffmpeg/audioExtraction.js.map +0 -1
  126. package/dist/tools/ffmpeg/captionBurning.d.ts +0 -8
  127. package/dist/tools/ffmpeg/captionBurning.d.ts.map +0 -1
  128. package/dist/tools/ffmpeg/captionBurning.js +0 -72
  129. package/dist/tools/ffmpeg/captionBurning.js.map +0 -1
  130. package/dist/tools/ffmpeg/clipExtraction.d.ts +0 -38
  131. package/dist/tools/ffmpeg/clipExtraction.d.ts.map +0 -1
  132. package/dist/tools/ffmpeg/clipExtraction.js +0 -215
  133. package/dist/tools/ffmpeg/clipExtraction.js.map +0 -1
  134. package/dist/tools/ffmpeg/faceDetection.d.ts +0 -127
  135. package/dist/tools/ffmpeg/faceDetection.d.ts.map +0 -1
  136. package/dist/tools/ffmpeg/faceDetection.js +0 -501
  137. package/dist/tools/ffmpeg/faceDetection.js.map +0 -1
  138. package/dist/tools/ffmpeg/frameCapture.d.ts +0 -10
  139. package/dist/tools/ffmpeg/frameCapture.d.ts.map +0 -1
  140. package/dist/tools/ffmpeg/frameCapture.js +0 -49
  141. package/dist/tools/ffmpeg/frameCapture.js.map +0 -1
  142. package/dist/tools/ffmpeg/silenceDetection.d.ts +0 -10
  143. package/dist/tools/ffmpeg/silenceDetection.d.ts.map +0 -1
  144. package/dist/tools/ffmpeg/silenceDetection.js +0 -56
  145. package/dist/tools/ffmpeg/silenceDetection.js.map +0 -1
  146. package/dist/tools/ffmpeg/singlePassEdit.d.ts +0 -25
  147. package/dist/tools/ffmpeg/singlePassEdit.d.ts.map +0 -1
  148. package/dist/tools/ffmpeg/singlePassEdit.js +0 -124
  149. package/dist/tools/ffmpeg/singlePassEdit.js.map +0 -1
  150. package/dist/tools/search/exaClient.d.ts +0 -8
  151. package/dist/tools/search/exaClient.d.ts.map +0 -1
  152. package/dist/tools/search/exaClient.js +0 -38
  153. package/dist/tools/search/exaClient.js.map +0 -1
  154. package/dist/tools/whisper/whisperClient.d.ts +0 -3
  155. package/dist/tools/whisper/whisperClient.d.ts.map +0 -1
  156. package/dist/tools/whisper/whisperClient.js +0 -77
  157. package/dist/tools/whisper/whisperClient.js.map +0 -1
  158. package/dist/types/index.d.ts +0 -305
  159. package/dist/types/index.d.ts.map +0 -1
  160. package/dist/types/index.js +0 -44
  161. package/dist/types/index.js.map +0 -1
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "vidpipe",
3
- "version": "1.2.2",
3
+ "version": "1.2.3",
4
4
  "description": "AI-powered pipeline that watches for video recordings and generates transcripts, summaries, short clips, and social media posts",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -16,7 +16,8 @@
16
16
  ],
17
17
  "scripts": {
18
18
  "start": "tsx src/index.ts",
19
- "build": "tsc && node -e \"const fs=require('fs');const f='dist/index.js';const c=fs.readFileSync(f,'utf8');if(!c.startsWith('#!')){fs.writeFileSync(f,'#!/usr/bin/env node\\n'+c)}\"",
19
+ "build": "tsup",
20
+ "typecheck": "tsc --noEmit",
20
21
  "dev": "tsx watch src/index.ts",
21
22
  "test": "vitest run",
22
23
  "test:watch": "vitest",
@@ -60,6 +61,7 @@
60
61
  "@types/sharp": "^0.32.0",
61
62
  "@types/uuid": "^11.0.0",
62
63
  "@vitest/coverage-v8": "^4.0.18",
64
+ "tsup": "^8.5.1",
63
65
  "tsx": "^4.21.0",
64
66
  "vitest": "^4.0.18"
65
67
  },
@@ -1,52 +0,0 @@
1
- import type { LLMProvider, LLMSession, ToolWithHandler } from '../providers/types.js';
2
- /**
3
- * BaseAgent — abstract foundation for all LLM-powered agents.
4
- *
5
- * ### Agent pattern
6
- * Each agent in the pipeline (SummaryAgent, ShortsAgent, BlogAgent, etc.)
7
- * extends BaseAgent and implements two methods:
8
- * - `getTools()` — declares the tools (functions) the LLM can call
9
- * - `handleToolCall()` — dispatches tool invocations to concrete implementations
10
- *
11
- * ### Tool registration
12
- * Tools are declared as JSON Schema objects and passed to the LLMSession
13
- * at creation time. When the LLM decides to call a tool, the provider routes
14
- * the call through the tool handler where the subclass executes the actual
15
- * logic (e.g. reading files, running FFmpeg, querying APIs).
16
- *
17
- * ### Message flow
18
- * 1. `run(userMessage)` lazily creates an LLMSession via the configured
19
- * provider (Copilot, OpenAI, or Claude).
20
- * 2. The user message is sent via `sendAndWait()`, which blocks until the
21
- * LLM produces a final response (with a 5-minute timeout).
22
- * 3. During processing, the LLM may invoke tools multiple times — each call
23
- * is logged via session event handlers.
24
- * 4. The final assistant message text is returned to the caller.
25
- *
26
- * Sessions are reusable: calling `run()` multiple times on the same agent
27
- * sends additional messages within the same conversation context.
28
- */
29
- export declare abstract class BaseAgent {
30
- protected readonly agentName: string;
31
- protected readonly systemPrompt: string;
32
- protected provider: LLMProvider;
33
- protected session: LLMSession | null;
34
- constructor(agentName: string, systemPrompt: string, provider?: LLMProvider);
35
- /** Tools this agent exposes to the LLM. Override in subclasses. */
36
- protected getTools(): ToolWithHandler[];
37
- /** Dispatch a tool call to the concrete agent. Override in subclasses. */
38
- protected abstract handleToolCall(toolName: string, args: Record<string, unknown>): Promise<unknown>;
39
- /**
40
- * Send a user message to the agent and return the final response text.
41
- *
42
- * 1. Lazily creates an LLMSession via the provider
43
- * 2. Registers event listeners for logging
44
- * 3. Calls sendAndWait and records usage via CostTracker
45
- */
46
- run(userMessage: string): Promise<string>;
47
- /** Wire up session event listeners for logging. */
48
- private setupEventHandlers;
49
- /** Tear down the session. */
50
- destroy(): Promise<void>;
51
- }
52
- //# sourceMappingURL=BaseAgent.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BaseAgent.d.ts","sourceRoot":"","sources":["../../src/agents/BaseAgent.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,UAAU,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAA;AAKrF;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,8BAAsB,SAAS;IAK3B,SAAS,CAAC,QAAQ,CAAC,SAAS,EAAE,MAAM;IACpC,SAAS,CAAC,QAAQ,CAAC,YAAY,EAAE,MAAM;IALzC,SAAS,CAAC,QAAQ,EAAE,WAAW,CAAA;IAC/B,SAAS,CAAC,OAAO,EAAE,UAAU,GAAG,IAAI,CAAO;gBAGtB,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACvC,QAAQ,CAAC,EAAE,WAAW;IAKxB,mEAAmE;IACnE,SAAS,CAAC,QAAQ,IAAI,eAAe,EAAE;IAIvC,0EAA0E;IAC1E,SAAS,CAAC,QAAQ,CAAC,cAAc,CAC/B,QAAQ,EAAE,MAAM,EAChB,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC5B,OAAO,CAAC,OAAO,CAAC;IAEnB;;;;;;OAMG;IACG,GAAG,CAAC,WAAW,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAkC/C,mDAAmD;IACnD,OAAO,CAAC,kBAAkB;IAkB1B,6BAA6B;IACvB,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;CAU/B"}
@@ -1,102 +0,0 @@
1
- import { getProvider } from '../providers/index.js';
2
- import { costTracker } from '../services/costTracker.js';
3
- import logger from '../config/logger.js';
4
- /**
5
- * BaseAgent — abstract foundation for all LLM-powered agents.
6
- *
7
- * ### Agent pattern
8
- * Each agent in the pipeline (SummaryAgent, ShortsAgent, BlogAgent, etc.)
9
- * extends BaseAgent and implements two methods:
10
- * - `getTools()` — declares the tools (functions) the LLM can call
11
- * - `handleToolCall()` — dispatches tool invocations to concrete implementations
12
- *
13
- * ### Tool registration
14
- * Tools are declared as JSON Schema objects and passed to the LLMSession
15
- * at creation time. When the LLM decides to call a tool, the provider routes
16
- * the call through the tool handler where the subclass executes the actual
17
- * logic (e.g. reading files, running FFmpeg, querying APIs).
18
- *
19
- * ### Message flow
20
- * 1. `run(userMessage)` lazily creates an LLMSession via the configured
21
- * provider (Copilot, OpenAI, or Claude).
22
- * 2. The user message is sent via `sendAndWait()`, which blocks until the
23
- * LLM produces a final response (with a 5-minute timeout).
24
- * 3. During processing, the LLM may invoke tools multiple times — each call
25
- * is logged via session event handlers.
26
- * 4. The final assistant message text is returned to the caller.
27
- *
28
- * Sessions are reusable: calling `run()` multiple times on the same agent
29
- * sends additional messages within the same conversation context.
30
- */
31
- export class BaseAgent {
32
- agentName;
33
- systemPrompt;
34
- provider;
35
- session = null;
36
- constructor(agentName, systemPrompt, provider) {
37
- this.agentName = agentName;
38
- this.systemPrompt = systemPrompt;
39
- this.provider = provider ?? getProvider();
40
- }
41
- /** Tools this agent exposes to the LLM. Override in subclasses. */
42
- getTools() {
43
- return [];
44
- }
45
- /**
46
- * Send a user message to the agent and return the final response text.
47
- *
48
- * 1. Lazily creates an LLMSession via the provider
49
- * 2. Registers event listeners for logging
50
- * 3. Calls sendAndWait and records usage via CostTracker
51
- */
52
- async run(userMessage) {
53
- if (!this.session) {
54
- this.session = await this.provider.createSession({
55
- systemPrompt: this.systemPrompt,
56
- tools: this.getTools(),
57
- streaming: true,
58
- model: process.env.LLM_MODEL || undefined,
59
- timeoutMs: 300_000, // 5 min timeout
60
- });
61
- this.setupEventHandlers(this.session);
62
- }
63
- logger.info(`[${this.agentName}] Sending message: ${userMessage.substring(0, 80)}…`);
64
- costTracker.setAgent(this.agentName);
65
- const response = await this.session.sendAndWait(userMessage);
66
- // Record usage via CostTracker
67
- costTracker.recordUsage(this.provider.name, response.cost?.model ?? this.provider.getDefaultModel(), response.usage, response.cost, response.durationMs, response.quotaSnapshots
68
- ? Object.values(response.quotaSnapshots)[0]
69
- : undefined);
70
- const content = response.content;
71
- logger.info(`[${this.agentName}] Response received (${content.length} chars)`);
72
- return content;
73
- }
74
- /** Wire up session event listeners for logging. */
75
- setupEventHandlers(session) {
76
- session.on('delta', (event) => {
77
- logger.debug(`[${this.agentName}] delta: ${JSON.stringify(event.data)}`);
78
- });
79
- session.on('tool_start', (event) => {
80
- logger.info(`[${this.agentName}] tool start: ${JSON.stringify(event.data)}`);
81
- });
82
- session.on('tool_end', (event) => {
83
- logger.info(`[${this.agentName}] tool done: ${JSON.stringify(event.data)}`);
84
- });
85
- session.on('error', (event) => {
86
- logger.error(`[${this.agentName}] error: ${JSON.stringify(event.data)}`);
87
- });
88
- }
89
- /** Tear down the session. */
90
- async destroy() {
91
- try {
92
- if (this.session) {
93
- await this.session.close();
94
- this.session = null;
95
- }
96
- }
97
- catch (err) {
98
- logger.error(`[${this.agentName}] Error during destroy: ${err}`);
99
- }
100
- }
101
- }
102
- //# sourceMappingURL=BaseAgent.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BaseAgent.js","sourceRoot":"","sources":["../../src/agents/BaseAgent.ts"],"names":[],"mappings":"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"}
@@ -1,3 +0,0 @@
1
- import type { Transcript, VideoFile, VideoSummary } from '../types';
2
- export declare function generateBlogPost(video: VideoFile, transcript: Transcript, summary: VideoSummary): Promise<string>;
3
- //# sourceMappingURL=BlogAgent.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BlogAgent.d.ts","sourceRoot":"","sources":["../../src/agents/BlogAgent.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,UAAU,CAAA;AA8JnE,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,SAAS,EAChB,UAAU,EAAE,UAAU,EACtB,OAAO,EAAE,YAAY,GACpB,OAAO,CAAC,MAAM,CAAC,CAuCjB"}
@@ -1,163 +0,0 @@
1
- import * as fs from 'fs';
2
- import * as path from 'path';
3
- import { BaseAgent } from './BaseAgent';
4
- import logger from '../config/logger';
5
- import { getBrandConfig } from '../config/brand';
6
- import { searchWeb } from '../tools/search/exaClient';
7
- // ── Build system prompt from brand config ───────────────────────────────────
8
- function buildSystemPrompt() {
9
- const brand = getBrandConfig();
10
- return `You are a technical blog writer for dev.to, writing from the perspective of ${brand.name} (${brand.handle}).
11
-
12
- Voice & style:
13
- - Tone: ${brand.voice.tone}
14
- - Personality: ${brand.voice.personality}
15
- - Style: ${brand.voice.style}
16
-
17
- Content guidelines: ${brand.contentGuidelines.blogFocus}
18
-
19
- Your task is to generate a full dev.to-style technical blog post (800-1500 words) based on a video transcript and summary.
20
-
21
- The blog post MUST include:
22
- 1. dev.to frontmatter (title, published: false, description, tags, cover_image placeholder)
23
- 2. An engaging introduction with a hook
24
- 3. Clear sections covering the main content (e.g. The Problem, The Solution, How It Works)
25
- 4. Code snippets where the video content discusses code — use fenced code blocks with language tags
26
- 5. Key Takeaways section
27
- 6. A conclusion
28
- 7. A footer referencing the original video
29
-
30
- Workflow:
31
- 1. First call "search_web" with key topics to find relevant articles/resources to link to.
32
- 2. Then call "write_blog" with the complete blog post including frontmatter and body.
33
- - Weave the search result links organically into the post text (don't dump them at the end).
34
- - Reference the video and any shorts naturally.
35
-
36
- Always call "write_blog" exactly once with the complete post.`;
37
- }
38
- // ── Agent ────────────────────────────────────────────────────────────────────
39
- class BlogAgent extends BaseAgent {
40
- blogContent = null;
41
- constructor() {
42
- super('BlogAgent', buildSystemPrompt());
43
- }
44
- getTools() {
45
- return [
46
- {
47
- name: 'search_web',
48
- description: 'Search the web for relevant articles and resources to link in the blog post.',
49
- parameters: {
50
- type: 'object',
51
- properties: {
52
- queries: {
53
- type: 'array',
54
- items: { type: 'string' },
55
- description: 'List of search queries for finding relevant links',
56
- },
57
- },
58
- required: ['queries'],
59
- },
60
- handler: async (args) => {
61
- const { queries } = args;
62
- logger.info(`[BlogAgent] search_web called with ${queries.length} queries`);
63
- const allResults = {};
64
- for (const query of queries) {
65
- allResults[query] = await searchWeb(query, 3);
66
- }
67
- return JSON.stringify({ results: allResults });
68
- },
69
- },
70
- {
71
- name: 'write_blog',
72
- description: 'Submit the complete dev.to blog post with frontmatter and markdown body.',
73
- parameters: {
74
- type: 'object',
75
- properties: {
76
- frontmatter: {
77
- type: 'object',
78
- properties: {
79
- title: { type: 'string' },
80
- description: { type: 'string' },
81
- tags: { type: 'array', items: { type: 'string' } },
82
- cover_image: { type: 'string' },
83
- },
84
- required: ['title', 'description', 'tags'],
85
- },
86
- body: {
87
- type: 'string',
88
- description: 'The full markdown body of the blog post (excluding frontmatter)',
89
- },
90
- },
91
- required: ['frontmatter', 'body'],
92
- },
93
- handler: async (args) => {
94
- const blogArgs = args;
95
- this.blogContent = blogArgs;
96
- logger.info(`[BlogAgent] write_blog received post: "${blogArgs.frontmatter.title}"`);
97
- return JSON.stringify({ success: true });
98
- },
99
- },
100
- ];
101
- }
102
- async handleToolCall(toolName, _args) {
103
- logger.warn(`[BlogAgent] Unexpected handleToolCall for "${toolName}"`);
104
- return { error: `Unknown tool: ${toolName}` };
105
- }
106
- getBlogContent() {
107
- return this.blogContent;
108
- }
109
- }
110
- // ── Render the final markdown ───────────────────────────────────────────────
111
- function renderBlogMarkdown(blog) {
112
- const fm = blog.frontmatter;
113
- const tags = fm.tags.map((t) => t.toLowerCase().replace(/[^a-z0-9]/g, '')).join(', ');
114
- const lines = [
115
- '---',
116
- `title: "${fm.title}"`,
117
- 'published: false',
118
- `description: "${fm.description}"`,
119
- `tags: ${tags}`,
120
- `cover_image: ${fm.cover_image || ''}`,
121
- '---',
122
- '',
123
- blog.body,
124
- ];
125
- return lines.join('\n');
126
- }
127
- // ── Public API ──────────────────────────────────────────────────────────────
128
- export async function generateBlogPost(video, transcript, summary) {
129
- const agent = new BlogAgent();
130
- try {
131
- const userMessage = [
132
- '## Video Metadata',
133
- `- **Title:** ${summary.title}`,
134
- `- **Slug:** ${video.slug}`,
135
- `- **Duration:** ${video.duration}s`,
136
- `- **Recorded:** ${video.createdAt.toISOString().split('T')[0]}`,
137
- '',
138
- '## Summary',
139
- summary.overview,
140
- '',
141
- '## Key Topics',
142
- summary.keyTopics.map((t) => `- ${t}`).join('\n'),
143
- '',
144
- '## Transcript (first 6000 chars)',
145
- transcript.text.slice(0, 6000),
146
- ].join('\n');
147
- await agent.run(userMessage);
148
- const blogContent = agent.getBlogContent();
149
- if (!blogContent) {
150
- throw new Error('BlogAgent did not produce any blog content');
151
- }
152
- const outDir = path.join(video.videoDir, 'social-posts');
153
- fs.mkdirSync(outDir, { recursive: true });
154
- const outputPath = path.join(outDir, 'devto.md');
155
- fs.writeFileSync(outputPath, renderBlogMarkdown(blogContent), 'utf-8');
156
- logger.info(`[BlogAgent] Wrote blog post to ${outputPath}`);
157
- return outputPath;
158
- }
159
- finally {
160
- await agent.destroy();
161
- }
162
- }
163
- //# sourceMappingURL=BlogAgent.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BlogAgent.js","sourceRoot":"","sources":["../../src/agents/BlogAgent.ts"],"names":[],"mappings":"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"}
@@ -1,11 +0,0 @@
1
- import type { VideoFile, Transcript, Chapter } from '../types';
2
- /**
3
- * Generate chapters for a video recording.
4
- *
5
- * 1. Creates a ChapterAgent with a `generate_chapters` tool
6
- * 2. Builds a prompt containing the full transcript with timestamps
7
- * 3. Lets the agent analyse the transcript and identify chapter boundaries
8
- * 4. Returns the array of {@link Chapter} objects
9
- */
10
- export declare function generateChapters(video: VideoFile, transcript: Transcript): Promise<Chapter[]>;
11
- //# sourceMappingURL=ChapterAgent.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ChapterAgent.d.ts","sourceRoot":"","sources":["../../src/agents/ChapterAgent.ts"],"names":[],"mappings":"AAOA,OAAO,KAAK,EAAE,SAAS,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AAiM9D;;;;;;;GAOG;AACH,wBAAsB,gBAAgB,CACpC,KAAK,EAAE,SAAS,EAChB,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,OAAO,EAAE,CAAC,CAyCpB"}
@@ -1,191 +0,0 @@
1
- import { promises as fs } from 'fs';
2
- import path from 'path';
3
- import { BaseAgent } from './BaseAgent';
4
- import logger from '../config/logger';
5
- import { getConfig } from '../config/environment';
6
- // ── Helpers ──────────────────────────────────────────────────────────────────
7
- /** Format seconds → "M:SS" or "H:MM:SS" for YouTube timestamps */
8
- function toYouTubeTimestamp(seconds) {
9
- const h = Math.floor(seconds / 3600);
10
- const m = Math.floor((seconds % 3600) / 60);
11
- const s = Math.floor(seconds % 60);
12
- return h > 0
13
- ? `${h}:${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`
14
- : `${m}:${String(s).padStart(2, '0')}`;
15
- }
16
- /** Format seconds → "MM:SS" for table display */
17
- function fmtTime(seconds) {
18
- const m = Math.floor(seconds / 60);
19
- const s = Math.floor(seconds % 60);
20
- return `${String(m).padStart(2, '0')}:${String(s).padStart(2, '0')}`;
21
- }
22
- /** Build a compact transcript block with timestamps for the LLM prompt. */
23
- function buildTranscriptBlock(transcript) {
24
- return transcript.segments
25
- .map((seg) => `[${fmtTime(seg.start)} → ${fmtTime(seg.end)}] ${seg.text.trim()}`)
26
- .join('\n');
27
- }
28
- // ── Output format generators ─────────────────────────────────────────────────
29
- function generateChaptersJSON(chapters) {
30
- return JSON.stringify({ chapters }, null, 2);
31
- }
32
- function generateYouTubeTimestamps(chapters) {
33
- return chapters
34
- .map((ch) => `${toYouTubeTimestamp(ch.timestamp)} ${ch.title}`)
35
- .join('\n');
36
- }
37
- function generateChaptersMarkdown(chapters) {
38
- const rows = chapters
39
- .map((ch) => `| ${toYouTubeTimestamp(ch.timestamp)} | ${ch.title} | ${ch.description} |`)
40
- .join('\n');
41
- return `## Chapters
42
-
43
- | Time | Chapter | Description |
44
- |------|---------|-------------|
45
- ${rows}
46
- `;
47
- }
48
- function generateFFMetadata(chapters, totalDuration) {
49
- let meta = ';FFMETADATA1\n\n';
50
- for (let i = 0; i < chapters.length; i++) {
51
- const ch = chapters[i];
52
- const startMs = Math.round(ch.timestamp * 1000);
53
- const endMs = i < chapters.length - 1
54
- ? Math.round(chapters[i + 1].timestamp * 1000)
55
- : Math.round(totalDuration * 1000);
56
- const escapedTitle = ch.title.replace(/[=;#\\]/g, '\\$&');
57
- meta += `[CHAPTER]\nTIMEBASE=1/1000\nSTART=${startMs}\nEND=${endMs}\ntitle=${escapedTitle}\n\n`;
58
- }
59
- return meta;
60
- }
61
- // ── System prompt ────────────────────────────────────────────────────────────
62
- function buildChapterSystemPrompt() {
63
- return `You are a video chapter generator. Analyze the transcript and identify distinct topic segments.
64
-
65
- Rules:
66
- - First chapter MUST start at 0:00
67
- - Minimum 3 chapters, maximum 10
68
- - Each chapter should be 2-5 minutes long
69
- - Chapter titles should be concise (3-7 words)
70
- - Look for topic transitions, "moving on", "next", "now let's", etc.
71
- - Include a brief 1-sentence description per chapter
72
-
73
- **Output format:**
74
- Call the "generate_chapters" tool with an array of chapter objects.
75
- Each chapter: { timestamp (seconds from start), title (short, 3-7 words), description (1-sentence summary) }
76
-
77
- **Title style:**
78
- - Use title case: "Setting Up the Database"
79
- - Be specific: "Configuring PostgreSQL" not "Database Stuff"
80
- - Include the action when relevant: "Building the API Routes"
81
- - Keep under 50 characters`;
82
- }
83
- // ── ChapterAgent ─────────────────────────────────────────────────────────────
84
- class ChapterAgent extends BaseAgent {
85
- outputDir;
86
- totalDuration;
87
- constructor(outputDir, totalDuration) {
88
- super('ChapterAgent', buildChapterSystemPrompt());
89
- this.outputDir = outputDir;
90
- this.totalDuration = totalDuration;
91
- }
92
- get chaptersDir() {
93
- return path.join(this.outputDir, 'chapters');
94
- }
95
- getTools() {
96
- return [
97
- {
98
- name: 'generate_chapters',
99
- description: 'Write the identified chapters to disk in all formats. ' +
100
- 'Provide: chapters (array of { timestamp, title, description }).',
101
- parameters: {
102
- type: 'object',
103
- properties: {
104
- chapters: {
105
- type: 'array',
106
- items: {
107
- type: 'object',
108
- properties: {
109
- timestamp: { type: 'number', description: 'Seconds from video start' },
110
- title: { type: 'string', description: 'Short chapter title (3-7 words)' },
111
- description: { type: 'string', description: '1-sentence summary' },
112
- },
113
- required: ['timestamp', 'title', 'description'],
114
- },
115
- },
116
- },
117
- required: ['chapters'],
118
- },
119
- handler: async (rawArgs) => {
120
- const args = rawArgs;
121
- return this.handleGenerateChapters(args);
122
- },
123
- },
124
- ];
125
- }
126
- async handleToolCall(toolName, args) {
127
- switch (toolName) {
128
- case 'generate_chapters':
129
- return this.handleGenerateChapters(args);
130
- default:
131
- throw new Error(`Unknown tool: ${toolName}`);
132
- }
133
- }
134
- async handleGenerateChapters(args) {
135
- const { chapters } = args;
136
- await fs.mkdir(this.chaptersDir, { recursive: true });
137
- // Write all 4 formats in parallel
138
- await Promise.all([
139
- fs.writeFile(path.join(this.chaptersDir, 'chapters.json'), generateChaptersJSON(chapters), 'utf-8'),
140
- fs.writeFile(path.join(this.chaptersDir, 'chapters-youtube.txt'), generateYouTubeTimestamps(chapters), 'utf-8'),
141
- fs.writeFile(path.join(this.chaptersDir, 'chapters.md'), generateChaptersMarkdown(chapters), 'utf-8'),
142
- fs.writeFile(path.join(this.chaptersDir, 'chapters.ffmetadata'), generateFFMetadata(chapters, this.totalDuration), 'utf-8'),
143
- ]);
144
- logger.info(`[ChapterAgent] Wrote ${chapters.length} chapters in 4 formats → ${this.chaptersDir}`);
145
- return `Chapters written: ${chapters.length} chapters in 4 formats to ${this.chaptersDir}`;
146
- }
147
- }
148
- // ── Public API ───────────────────────────────────────────────────────────────
149
- /**
150
- * Generate chapters for a video recording.
151
- *
152
- * 1. Creates a ChapterAgent with a `generate_chapters` tool
153
- * 2. Builds a prompt containing the full transcript with timestamps
154
- * 3. Lets the agent analyse the transcript and identify chapter boundaries
155
- * 4. Returns the array of {@link Chapter} objects
156
- */
157
- export async function generateChapters(video, transcript) {
158
- const config = getConfig();
159
- const outputDir = path.join(config.OUTPUT_DIR, video.slug);
160
- const agent = new ChapterAgent(outputDir, video.duration);
161
- const transcriptBlock = buildTranscriptBlock(transcript);
162
- const userPrompt = [
163
- `**Video:** ${video.filename}`,
164
- `**Duration:** ${fmtTime(video.duration)} (${Math.round(video.duration)} seconds)`,
165
- '',
166
- '---',
167
- '',
168
- '**Transcript:**',
169
- '',
170
- transcriptBlock,
171
- ].join('\n');
172
- let capturedChapters;
173
- // Intercept generate_chapters args to capture the result
174
- // Uses `as any` to access private method — required by the intercept-and-capture pattern
175
- const origHandler = agent.handleGenerateChapters.bind(agent);
176
- agent.handleGenerateChapters = async (args) => {
177
- capturedChapters = args.chapters;
178
- return origHandler(args);
179
- };
180
- try {
181
- await agent.run(userPrompt);
182
- if (!capturedChapters) {
183
- throw new Error('ChapterAgent did not call generate_chapters');
184
- }
185
- return capturedChapters;
186
- }
187
- finally {
188
- await agent.destroy();
189
- }
190
- }
191
- //# sourceMappingURL=ChapterAgent.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ChapterAgent.js","sourceRoot":"","sources":["../../src/agents/ChapterAgent.ts"],"names":[],"mappings":"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"}
@@ -1,3 +0,0 @@
1
- import { VideoFile, Transcript, MediumClip } from '../types';
2
- export declare function generateMediumClips(video: VideoFile, transcript: Transcript): Promise<MediumClip[]>;
3
- //# sourceMappingURL=MediumVideoAgent.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"MediumVideoAgent.d.ts","sourceRoot":"","sources":["../../src/agents/MediumVideoAgent.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAiB,MAAM,UAAU,CAAA;AAyJ3E,wBAAsB,mBAAmB,CACvC,KAAK,EAAE,SAAS,EAChB,UAAU,EAAE,UAAU,GACrB,OAAO,CAAC,UAAU,EAAE,CAAC,CAiHvB"}