Download main.ts from Jessedbrown/Docs-Extractor: direct link, hf CLI and curl.
- Browser
- Download file 5.18 kB
-
https://huggingface.co/Jessedbrown/Docs-Extractor/resolve/main/main.ts
- Command line
-
hf download hf://Jessedbrown/Docs-Extractor/main.ts
-
curl -L -o main.ts https://huggingface.co/Jessedbrown/Docs-Extractor/resolve/main/main.ts
5.18 kB
| import "@std/dotenv/load"; | |
| import { | |
| AnthropicModelProvider, | |
| ZypherAgent, | |
| createZypherContext, | |
| } from "@corespeed/zypher"; | |
| import { eachValueFrom } from "rxjs-for-await"; | |
| function getRequiredEnv(name: string): string { | |
| const value = Deno.env.get(name); | |
| if (!value) { | |
| throw new Error(`Environment variable ${name} is not set`); | |
| } | |
| return value; | |
| } | |
| const prompt = `You are a documentation extraction agent. Extract and format documentation as clean markdown. | |
| RULES: | |
| - Output ONLY the final markdown document | |
| - Do NOT include meta-commentary like "I'll help you...", "Let me create...", "Perfect!", etc. | |
| - Do NOT narrate what you're doing | |
| - Start directly with the documentation title | |
| PROCESS: | |
| 1. Crawl the main page (be fast - don't follow multiple links) | |
| 2. Extract: installation, key concepts, 1-2 code examples | |
| 3. Output the markdown document immediately | |
| FORMAT: | |
| # [Document Title] | |
| > Source: [original URL] | |
| [Your extracted content with headings, code blocks, and links] | |
| Be concise and practical. Output the document, not commentary about creating it.`; | |
| export class DocsExtractorAgent { | |
| public zypher: ZypherAgent; | |
| private constructor(agent: ZypherAgent) { | |
| this.zypher = agent; | |
| } | |
| static async create() { | |
| // Initialize the agent execution context | |
| const workingDir = Deno.cwd(); | |
| const homeDir = Deno.env.get("HOME") || Deno.env.get("USERPROFILE") || workingDir; | |
| const zypherContext = await createZypherContext(workingDir, { | |
| zypherDir: `${homeDir}/.zypher`, | |
| enableBuiltInTools: true, // Explicitly enable built-in tools | |
| }); | |
| // Create the agent with Anthropic model provider | |
| const agent = new ZypherAgent( | |
| zypherContext, | |
| new AnthropicModelProvider({ | |
| apiKey: getRequiredEnv("ANTHROPIC_API_KEY"), | |
| }), | |
| { | |
| customInstructions: prompt, | |
| }, | |
| ); | |
| // Register Firecrawl MCP server | |
| try { | |
| await agent.mcp.registerServer({ | |
| id: "firecrawl", | |
| type: "command", | |
| command: { | |
| command: "npx", | |
| args: ["-y", "firecrawl-mcp"], | |
| env: { | |
| FIRECRAWL_API_KEY: getRequiredEnv("FIRECRAWL_API_KEY"), | |
| FIRECRAWL_TIMEOUT: "30000", // 30 second timeout | |
| FIRECRAWL_MAX_DEPTH: "1", // Only crawl 1 level deep | |
| }, | |
| }, | |
| }); | |
| console.log("✅ Registered Firecrawl MCP server"); | |
| } catch (error) { | |
| console.error("⚠️ Failed to register Firecrawl MCP server:", error); | |
| } | |
| return new DocsExtractorAgent(agent); | |
| } | |
| async extract(docsUrl: string, extractionType: string, model: string = "claude-sonnet-4-20250514") { | |
| const userPrompt = `Extract from ${docsUrl}: ${extractionType} | |
| OUTPUT ONLY THE MARKDOWN DOCUMENT. No meta-commentary. | |
| Start with: | |
| # [Title for ${extractionType}] | |
| > Source: ${docsUrl} | |
| Then include: | |
| - Installation/setup (if relevant) | |
| - Key concepts | |
| - 1-2 code examples | |
| - Links to original docs | |
| Keep it concise and practical. Output the document directly.`; | |
| console.log(`🔍 Starting extraction from ${docsUrl}...`); | |
| const event$ = this.zypher.runTask(userPrompt, model); | |
| let responseText = ""; | |
| const toolUses: Array<{ name: string; input: unknown }> = []; | |
| for await (const event of eachValueFrom(event$)) { | |
| switch (event.type) { | |
| case "text": | |
| case "message": | |
| if (event.content?.text) { | |
| responseText += event.content.text; | |
| } else if (typeof event.content === "string") { | |
| responseText += event.content; | |
| } | |
| break; | |
| case "tool_use": | |
| case "tool_use_input": | |
| if (event.content?.name) { | |
| toolUses.push({ | |
| name: event.content.name, | |
| input: event.content.input, | |
| }); | |
| } else if (event.tool || event.name) { | |
| const toolName = event.tool || event.name; | |
| const toolInput = event.input || event.content; | |
| toolUses.push({ name: toolName, input: toolInput }); | |
| } | |
| break; | |
| case "tool_result": | |
| case "tool_use_approved": | |
| default: | |
| break; | |
| } | |
| } | |
| console.log("✅ Extraction completed!"); | |
| // Save the response text to a file | |
| try { | |
| if (responseText) { | |
| const timestamp = new Date().toISOString().replace(/[:.]/g, "-"); | |
| const filename = `extraction-${timestamp}.md`; | |
| const filepath = `./generated-docs/${filename}`; | |
| await Deno.writeTextFile(filepath, responseText); | |
| console.log(`📄 Saved: ${filename}`); | |
| } | |
| } catch (error) { | |
| console.error("❌ Error saving file:", error); | |
| } | |
| return { | |
| response: { | |
| content: [ | |
| { | |
| type: "text", | |
| text: responseText, | |
| }, | |
| ], | |
| }, | |
| toolUses, | |
| }; | |
| } | |
| async cleanup() { | |
| } | |
| } | |
| // Terminal mode: Run agent in interactive CLI | |
| if (import.meta.main) { | |
| const { runAgentInTerminal } = await import("@corespeed/zypher"); | |
| const agent = await DocsExtractorAgent.create(); | |
| await runAgentInTerminal(agent.zypher, "claude-sonnet-4-20250514"); | |
| await agent.cleanup(); | |
| } | |