diff options
| author | Adam Malczewski <[email protected]> | 2026-06-21 15:08:51 +0900 |
|---|---|---|
| committer | Adam Malczewski <[email protected]> | 2026-06-21 15:08:51 +0900 |
| commit | 64823e68e8c6c3bc199f9cb82d97321c830687c3 (patch) | |
| tree | 9340fbaede62f86b0de9f8281d9415778adcda44 /packages/tool-youtube-transcript/src/tool.ts | |
| parent | 4ccdfd34c55bee279ce5e190412afd19cfbb5238 (diff) | |
| download | dispatch-64823e68e8c6c3bc199f9cb82d97321c830687c3.tar.gz dispatch-64823e68e8c6c3bc199f9cb82d97321c830687c3.zip | |
feat(tool-youtube-transcript): write full transcript to /tmp/dispatch on truncation
When the formatted transcript exceeds the 50K char output cap, the tool now
writes the full output to /tmp/dispatch/{video_id}.txt and returns the
truncated output with a notice pointing to the file path. The writeFile dep
is injectable so tests verify without touching the filesystem.
Diffstat (limited to 'packages/tool-youtube-transcript/src/tool.ts')
| -rw-r--r-- | packages/tool-youtube-transcript/src/tool.ts | 22 |
1 files changed, 22 insertions, 0 deletions
diff --git a/packages/tool-youtube-transcript/src/tool.ts b/packages/tool-youtube-transcript/src/tool.ts index 189e42c..a47d693 100644 --- a/packages/tool-youtube-transcript/src/tool.ts +++ b/packages/tool-youtube-transcript/src/tool.ts @@ -7,6 +7,7 @@ * rather than thrown, so the model can react to the message. */ +import { mkdirSync, writeFileSync } from "node:fs"; import type { ToolContract, ToolExecuteContext, ToolResult } from "@dispatch/kernel"; import type { TranscriptClient } from "./client.js"; import { @@ -19,10 +20,13 @@ import { import { validateUrl } from "./validate.js"; const OUTPUT_CAP = 50_000; +const FULL_OUTPUT_DIR = "/tmp/dispatch"; export interface YoutubeTranscriptToolDeps { readonly client: TranscriptClient; readonly outputCap?: number; + /** Injected file writer (defaults to real fs write). */ + readonly writeFile?: (path: string, content: string) => void; } const DESCRIPTION = @@ -41,6 +45,12 @@ const DESCRIPTION = export function createYoutubeTranscriptTool(deps: YoutubeTranscriptToolDeps): ToolContract { const client = deps.client; const cap = deps.outputCap ?? OUTPUT_CAP; + const writeFile = + deps.writeFile ?? + ((path, content) => { + mkdirSync(FULL_OUTPUT_DIR, { recursive: true }); + writeFileSync(path, content, "utf-8"); + }); return { name: "youtube_transcript", @@ -67,17 +77,29 @@ export function createYoutubeTranscriptTool(deps: YoutubeTranscriptToolDeps): To try { const data: TranscriptResponse = await client.getTranscript(url, ctx.signal); let output: string; + let videoId: string | undefined; // Check the single-literal discriminants ("completed"/"failed") first, // so the final else narrows to QueuedResponse — whose `status` is itself // a `"queued" | "processing"` union TS cannot negatively narrow. if (data.status === "completed") { output = formatCompleted(url, data); + videoId = data.video_id; } else if (data.status === "failed") { output = formatFailed(data); } else { output = formatQueued(url, data, Date.now); } span.end(); + + if (output.length > cap && videoId !== undefined) { + const filePath = `${FULL_OUTPUT_DIR}/${videoId}.txt`; + try { + writeFile(filePath, output); + return { content: truncateOutput(output, cap, filePath) }; + } catch { + return { content: truncateOutput(output, cap) }; + } + } return { content: truncateOutput(output, cap) }; } catch (err: unknown) { span.end({ err }); |
