doccupine 0.0.41 → 0.0.43

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.
@@ -1 +1 @@
1
- export declare const ragRoutesTemplate = "import { NextResponse } from \"next/server\";\nimport path from \"node:path\";\nimport { getLLMConfig, createChatModel } from \"@/services/llm\";\nimport {\n searchDocs,\n ensureDocsIndex,\n getIndexStatus,\n} from \"@/services/mcp/server\";\n\nconst PROJECT_ROOT = process.cwd();\n\nexport async function POST(req: Request) {\n try {\n const { question, refresh } = await req.json();\n\n let config;\n try {\n config = getLLMConfig();\n } catch (error: unknown) {\n const message =\n error instanceof Error ? error.message : \"LLM configuration error\";\n return NextResponse.json({ error: message }, { status: 500 });\n }\n\n // Use MCP service to ensure docs are indexed\n await ensureDocsIndex(Boolean(refresh));\n\n // Use MCP search_docs tool to find relevant documentation\n const searchResults = await searchDocs(String(question || \"\"), 6);\n\n // Build context from search results\n const context = searchResults\n .map(\n ({ chunk, score }) =>\n `File: ${path.relative(PROJECT_ROOT, chunk.path)}\\nScore: ${score.toFixed(3)}\\n----\\n${chunk.text}`,\n )\n .join(\"\\n\\n================\\n\\n\");\n\n // Create chat model and stream response\n const llm = createChatModel(config);\n const prompt = [\n {\n role: \"system\" as const,\n content:\n \"You are a helpful documentation assistant. Answer strictly from the provided context. If the answer is not in the context, say you don't know and suggest where to look. Make sure the mdx can be nested properly if you show code components within nested ``` it has to be valid md/mdx output.\",\n },\n {\n role: \"user\" as const,\n content: `Question: ${question}\\n\\nContext:\\n${context}`,\n },\n ];\n\n const stream = await llm.stream(prompt);\n\n // Build metadata from MCP search results\n const indexStatus = getIndexStatus();\n const metadata = {\n sources: searchResults.map(({ chunk, score }) => ({\n id: chunk.id,\n path: path.relative(PROJECT_ROOT, chunk.path),\n uri: chunk.uri,\n score,\n })),\n chunkCount: indexStatus.chunkCount,\n };\n\n const encoder = new TextEncoder();\n const readableStream = new ReadableStream({\n async start(controller) {\n try {\n controller.enqueue(\n encoder.encode(\n `data: ${JSON.stringify({ type: \"metadata\", data: metadata })}\\n\\n`,\n ),\n );\n\n for await (const chunk of stream) {\n const content = chunk?.content || \"\";\n if (content) {\n controller.enqueue(\n encoder.encode(\n `data: ${JSON.stringify({ type: \"content\", data: content })}\\n\\n`,\n ),\n );\n }\n }\n\n controller.enqueue(\n encoder.encode(`data: ${JSON.stringify({ type: \"done\" })}\\n\\n`),\n );\n controller.close();\n } catch (error: unknown) {\n const message =\n error instanceof Error ? error.message : \"Stream error\";\n controller.enqueue(\n encoder.encode(\n `data: ${JSON.stringify({ type: \"error\", data: message })}\\n\\n`,\n ),\n );\n controller.close();\n }\n },\n });\n\n return new Response(readableStream, {\n headers: {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n },\n });\n } catch (e: unknown) {\n const message = e instanceof Error ? e.message : \"Unknown error\";\n return NextResponse.json({ error: message }, { status: 500 });\n }\n}\n\nexport async function GET() {\n const status = getIndexStatus();\n return NextResponse.json({\n ready: status.ready,\n chunks: status.chunkCount,\n });\n}\n";
1
+ export declare const ragRoutesTemplate = "import { NextResponse } from \"next/server\";\nimport path from \"node:path\";\nimport { getLLMConfig, createChatModel } from \"@/services/llm\";\nimport {\n searchDocs,\n ensureDocsIndex,\n getIndexStatus,\n} from \"@/services/mcp/server\";\n\nconst PROJECT_ROOT = process.cwd();\n\nconst systemContext = `You are AI Assistant, a documentation assistant for Doccupine.\n\n## Core Rules\n1. Answer ONLY from the provided context. Never fabricate information.\n2. If the answer isn't in the context, say so clearly and suggest relevant sections or pages the user might check.\n3. If the question is ambiguous, ask a brief clarifying question before answering.\n\n## Response Style\n- Be concise and direct. Lead with the answer, then provide details if needed.\n- Use code examples from the context when relevant.\n- Match the technical level of the user's question.\n\n## MDX/Code Formatting\nWhen including code blocks in your response:\n- Never nest fenced code blocks (triple backticks) inside other fenced code blocks.\n- If you need to show MDX source that itself contains code blocks, use indented code blocks or escape the inner backticks.\n- All output must be valid MDX that renders correctly.\n\n## Greetings & Small Talk\nIf the user sends a greeting or non-documentation question, respond briefly and ask how you can help with the documentation.`;\n\nexport async function POST(req: Request) {\n try {\n const { question, refresh } = await req.json();\n\n let config;\n try {\n config = getLLMConfig();\n } catch (error: unknown) {\n const message =\n error instanceof Error ? error.message : \"LLM configuration error\";\n return NextResponse.json({ error: message }, { status: 500 });\n }\n\n // Use MCP service to ensure docs are indexed\n await ensureDocsIndex(Boolean(refresh));\n\n // Use MCP search_docs tool to find relevant documentation\n const searchResults = await searchDocs(String(question || \"\"), 6);\n\n // Build context from search results\n const context = searchResults\n .map(\n ({ chunk, score }) =>\n `File: ${path.relative(PROJECT_ROOT, chunk.path)}\\nScore: ${score.toFixed(3)}\\n----\\n${chunk.text}`,\n )\n .join(\"\\n\\n================\\n\\n\");\n\n // Create chat model and stream response\n const llm = createChatModel(config);\n const prompt = [\n {\n role: \"system\" as const,\n content: systemContext as string,\n },\n {\n role: \"user\" as const,\n content: `Question: ${question}\\n\\nContext:\\n${context}`,\n },\n ];\n\n const stream = await llm.stream(prompt);\n\n // Build metadata from MCP search results\n const indexStatus = getIndexStatus();\n const metadata = {\n sources: searchResults.map(({ chunk, score }) => ({\n id: chunk.id,\n path: path.relative(PROJECT_ROOT, chunk.path),\n uri: chunk.uri,\n score,\n })),\n chunkCount: indexStatus.chunkCount,\n };\n\n const encoder = new TextEncoder();\n const readableStream = new ReadableStream({\n async start(controller) {\n try {\n controller.enqueue(\n encoder.encode(\n `data: ${JSON.stringify({ type: \"metadata\", data: metadata })}\\n\\n`,\n ),\n );\n\n for await (const chunk of stream) {\n const content = chunk?.content || \"\";\n if (content) {\n controller.enqueue(\n encoder.encode(\n `data: ${JSON.stringify({ type: \"content\", data: content })}\\n\\n`,\n ),\n );\n }\n }\n\n controller.enqueue(\n encoder.encode(`data: ${JSON.stringify({ type: \"done\" })}\\n\\n`),\n );\n controller.close();\n } catch (error: unknown) {\n const message =\n error instanceof Error ? error.message : \"Stream error\";\n controller.enqueue(\n encoder.encode(\n `data: ${JSON.stringify({ type: \"error\", data: message })}\\n\\n`,\n ),\n );\n controller.close();\n }\n },\n });\n\n return new Response(readableStream, {\n headers: {\n \"Content-Type\": \"text/event-stream\",\n \"Cache-Control\": \"no-cache\",\n Connection: \"keep-alive\",\n },\n });\n } catch (e: unknown) {\n const message = e instanceof Error ? e.message : \"Unknown error\";\n return NextResponse.json({ error: message }, { status: 500 });\n }\n}\n\nexport async function GET() {\n const status = getIndexStatus();\n return NextResponse.json({\n ready: status.ready,\n chunks: status.chunkCount,\n });\n}\n";
@@ -9,6 +9,27 @@ import {
9
9
 
10
10
  const PROJECT_ROOT = process.cwd();
11
11
 
12
+ const systemContext = \`You are AI Assistant, a documentation assistant for Doccupine.
13
+
14
+ ## Core Rules
15
+ 1. Answer ONLY from the provided context. Never fabricate information.
16
+ 2. If the answer isn't in the context, say so clearly and suggest relevant sections or pages the user might check.
17
+ 3. If the question is ambiguous, ask a brief clarifying question before answering.
18
+
19
+ ## Response Style
20
+ - Be concise and direct. Lead with the answer, then provide details if needed.
21
+ - Use code examples from the context when relevant.
22
+ - Match the technical level of the user's question.
23
+
24
+ ## MDX/Code Formatting
25
+ When including code blocks in your response:
26
+ - Never nest fenced code blocks (triple backticks) inside other fenced code blocks.
27
+ - If you need to show MDX source that itself contains code blocks, use indented code blocks or escape the inner backticks.
28
+ - All output must be valid MDX that renders correctly.
29
+
30
+ ## Greetings & Small Talk
31
+ If the user sends a greeting or non-documentation question, respond briefly and ask how you can help with the documentation.\`;
32
+
12
33
  export async function POST(req: Request) {
13
34
  try {
14
35
  const { question, refresh } = await req.json();
@@ -41,8 +62,7 @@ export async function POST(req: Request) {
41
62
  const prompt = [
42
63
  {
43
64
  role: "system" as const,
44
- content:
45
- "You are a helpful documentation assistant. Answer strictly from the provided context. If the answer is not in the context, say you don't know and suggest where to look. Make sure the mdx can be nested properly if you show code components within nested \`\`\` it has to be valid md/mdx output.",
65
+ content: systemContext as string,
46
66
  },
47
67
  {
48
68
  role: "user" as const,
@@ -1 +1 @@
1
- export declare const envExampleTemplate = "# LLM Provider Configuration\n# Choose your preferred LLM provider: openai, anthropic, or google\nLLM_PROVIDER=openai\n\n# API Keys (set the one matching your provider)\nOPENAI_API_KEY=your_openai_api_key_here\nANTHROPIC_API_KEY=your_anthropic_api_key_here\nGOOGLE_API_KEY=your_google_api_key_here\n\n# Optional: Override default models\n# OpenAI models: gpt-5-mini, gpt-5-nano, gpt-5\n# Anthropic models: claude-sonnet-4-5-20250929, claude-haiku-4-5-20251001, claude-opus-4-5-20251101\n# Google models: gemini-2.5-flash-lite, gemini-2.5-pro, gemini-2.5-flash\n# LLM_CHAT_MODEL=gpt-4.1-nano\n\n# Optional: Override default embedding model\n# OpenAI: text-embedding-3-small, text-embedding-3-large\n# Google: text-embedding-004\n# Note: Anthropic doesn't provide embeddings, will fallback to OpenAI\n# LLM_EMBEDDING_MODEL=text-embedding-3-small\n\n# Optional: Set temperature (0-1, default: 1)\n# LLM_TEMPERATURE=1\n";
1
+ export declare const envExampleTemplate = "# LLM Provider Configuration\n# Choose your preferred LLM provider: openai, anthropic, or google\nLLM_PROVIDER=openai\n\n# API Keys (set the one matching your provider)\nOPENAI_API_KEY=your_openai_api_key_here\nANTHROPIC_API_KEY=your_anthropic_api_key_here\nGOOGLE_API_KEY=your_google_api_key_here\n\n# Optional: Override default models\n# OpenAI models: gpt-4.1-nano, gpt-5-mini, gpt-5-nano, gpt-5\n# Anthropic models: claude-sonnet-4-5-20250929, claude-haiku-4-5-20251001, claude-opus-4-5-20251101\n# Google models: gemini-2.5-flash-lite, gemini-2.5-pro, gemini-2.5-flash\n# LLM_CHAT_MODEL=gpt-4.1-nano\n\n# Optional: Override default embedding model\n# OpenAI: text-embedding-3-small, text-embedding-3-large\n# Google: text-embedding-004\n# Note: Anthropic doesn't provide embeddings, will fallback to OpenAI\n# LLM_EMBEDDING_MODEL=text-embedding-3-small\n\n# Optional: Set temperature (0-1, default: 1)\n# LLM_TEMPERATURE=1\n";
@@ -8,7 +8,7 @@ ANTHROPIC_API_KEY=your_anthropic_api_key_here
8
8
  GOOGLE_API_KEY=your_google_api_key_here
9
9
 
10
10
  # Optional: Override default models
11
- # OpenAI models: gpt-5-mini, gpt-5-nano, gpt-5
11
+ # OpenAI models: gpt-4.1-nano, gpt-5-mini, gpt-5-nano, gpt-5
12
12
  # Anthropic models: claude-sonnet-4-5-20250929, claude-haiku-4-5-20251001, claude-opus-4-5-20251101
13
13
  # Google models: gemini-2.5-flash-lite, gemini-2.5-pro, gemini-2.5-flash
14
14
  # LLM_CHAT_MODEL=gpt-4.1-nano
@@ -1 +1 @@
1
- export declare const aiAssistantMdxTemplate = "---\ntitle: \"AI Assistant\"\ndescription: \"Integrate AI capabilities into your Doccupine documentation using OpenAI, Anthropic, or Google Gemini.\"\ndate: \"2025-01-24\"\ncategory: \"Configuration\"\ncategoryOrder: 3\norder: 7\n---\n# AI Assistant\nDoccupine supports AI integration to enhance your documentation experience. You can use OpenAI, Anthropic, or Google Gemini to power AI features in your documentation site. The AI assistant uses your documentation content as context, allowing users to ask questions about your docs and receive accurate answers based on the documentation.\n\n## Setup\nTo enable AI features, create an `.env` file in the directory where your website is generated. By default, this is the `nextjs-app/` directory.\n\n## Configuration\nCreate an `.env` file with the following configuration options:\n\n```env\n# LLM Provider Configuration\n# Choose your preferred LLM provider: openai, anthropic, or google\nLLM_PROVIDER=openai\n\n# API Keys (set the one matching your provider)\nOPENAI_API_KEY=your_openai_api_key_here\nANTHROPIC_API_KEY=your_anthropic_api_key_here\nGOOGLE_API_KEY=your_google_api_key_here\n\n# Optional: Override default models\n# OpenAI models: gpt-5-mini, gpt-5-nano, gpt-5\n# Anthropic models: claude-sonnet-4-5-20250929, claude-haiku-4-5-20251001, claude-opus-4-5-20251101\n# Google models: gemini-2.5-flash-lite, gemini-2.5-pro, gemini-2.5-flash\n# LLM_CHAT_MODEL=gpt-4.1-nano\n\n# Optional: Override default embedding model\n# OpenAI: text-embedding-3-small, text-embedding-3-large\n# Google: text-embedding-004\n# Note: Anthropic doesn't provide embeddings, will fallback to OpenAI\n# LLM_EMBEDDING_MODEL=text-embedding-3-small\n\n# Optional: Set temperature (0-1, default: 1)\n# LLM_TEMPERATURE=1\n```\n\n## Provider Selection\nSet `LLM_PROVIDER` to one of the following values:\n- `openai` - Use OpenAI's models (GPT-4.1, GPT-4.1-mini, GPT-4.1-nano)\n- `anthropic` - Use Anthropic's models (Claude Sonnet 4.5, Claude Haiku 4.5, Claude Opus 4.5)\n- `google` - Use Google's models (Gemini 2.5 Pro, Gemini 2.5 Flash, Gemini 2.5 Flash-Lite)\n\n## API Keys\nYou need to set the API key that matches your chosen provider:\n- For OpenAI: Set `OPENAI_API_KEY`\n- For Anthropic: Set `ANTHROPIC_API_KEY`\n- For Google: Set `GOOGLE_API_KEY`\n\n<Callout type=\"warning\">\n Keep your API keys secure. Never commit your `.env` file to version control.\n</Callout>\n\n<Callout type=\"note\">\n Doccupine automatically adds `.env` to your `.gitignore` file.\n</Callout>\n\n## Using Anthropic with OpenAI\nIf you want to use Anthropic as your LLM provider, you must also have an OpenAI API key set. Here's why:\n\n### The Situation\nAnthropic (Claude) does not provide an embeddings API. They only offer chat/completion models, not text embeddings.\n\nYour RAG (Retrieval-Augmented Generation) system has two components:\n- **Chat/Completion** - Generates answers, works with Anthropic.\n- **Embeddings** - Creates vector representations of text for search, Anthropic doesn't provide this.\n\nWhen using Anthropic as your `LLM_PROVIDER`, Doccupine will use Anthropic for chat/completion tasks, but will automatically fallback to OpenAI for embeddings. This means you need both API keys configured:\n\n```env\nLLM_PROVIDER=anthropic\nANTHROPIC_API_KEY=your_anthropic_api_key_here\nOPENAI_API_KEY=your_openai_api_key_here\n```\n\nThis hybrid approach allows you to leverage Anthropic's powerful chat models while still having access to embeddings functionality through OpenAI.\n\n## Optional Settings\n\n### Chat Model\nOverride the default chat model by uncommenting and setting `LLM_CHAT_MODEL`. You can use any available model from your chosen provider. Example models include:\n- **OpenAI**: `gpt-4.1-nano`, `gpt-4.1-mini`, `gpt-4.1`\n- **Anthropic**: `claude-sonnet-4-5-20250929`, `claude-haiku-4-5-20251001`, `claude-opus-4-5-20251101`\n- **Google**: `gemini-2.5-flash-lite`, `gemini-2.5-pro`, `gemini-2.5-flash`\n\nFor a complete list of available models, refer to the official documentation:\n- [OpenAI Models](https://platform.openai.com/docs/models)\n- [Anthropic Models](https://docs.anthropic.com/claude/docs/models-overview)\n- [Google Gemini Models](https://ai.google.dev/models/gemini)\n\n### Embedding Model\nOverride the default embedding model by uncommenting and setting `LLM_EMBEDDING_MODEL`:\n- **OpenAI**: `text-embedding-3-small`, `text-embedding-3-large`\n- **Google**: `text-embedding-004`\n- **Anthropic**: Anthropic doesn't provide embeddings. If you use Anthropic as your provider, Doccupine will fallback to OpenAI for embeddings.\n\n### Temperature\nControl the randomness of AI responses by setting `LLM_TEMPERATURE` to a value between 0 and 1:\n- `0` - More deterministic and focused responses (default)\n- `1` - More creative and varied responses";
1
+ export declare const aiAssistantMdxTemplate = "---\ntitle: \"AI Assistant\"\ndescription: \"Integrate AI capabilities into your Doccupine documentation using OpenAI, Anthropic, or Google Gemini.\"\ndate: \"2025-01-24\"\ncategory: \"Configuration\"\ncategoryOrder: 3\norder: 7\n---\n# AI Assistant\nDoccupine supports AI integration to enhance your documentation experience. You can use OpenAI, Anthropic, or Google Gemini to power AI features in your documentation site. The AI assistant uses your documentation content as context, allowing users to ask questions about your docs and receive accurate answers based on the documentation.\n\n## Setup\nTo enable AI features, create an `.env` file in the directory where your website is generated. By default, this is the `nextjs-app/` directory.\n\n## Configuration\nCreate an `.env` file with the following configuration options:\n\n```env\n# LLM Provider Configuration\n# Choose your preferred LLM provider: openai, anthropic, or google\nLLM_PROVIDER=openai\n\n# API Keys (set the one matching your provider)\nOPENAI_API_KEY=your_openai_api_key_here\nANTHROPIC_API_KEY=your_anthropic_api_key_here\nGOOGLE_API_KEY=your_google_api_key_here\n\n# Optional: Override default models\n# OpenAI models: gpt-4.1-nano, gpt-5-mini, gpt-5-nano, gpt-5\n# Anthropic models: claude-sonnet-4-5-20250929, claude-haiku-4-5-20251001, claude-opus-4-5-20251101\n# Google models: gemini-2.5-flash-lite, gemini-2.5-pro, gemini-2.5-flash\n# LLM_CHAT_MODEL=gpt-4.1-nano\n\n# Optional: Override default embedding model\n# OpenAI: text-embedding-3-small, text-embedding-3-large\n# Google: text-embedding-004\n# Note: Anthropic doesn't provide embeddings, will fallback to OpenAI\n# LLM_EMBEDDING_MODEL=text-embedding-3-small\n\n# Optional: Set temperature (0-1, default: 1)\n# LLM_TEMPERATURE=1\n```\n\n## Provider Selection\nSet `LLM_PROVIDER` to one of the following values:\n- `openai` - Use OpenAI's models (GPT-4.1, GPT-4.1-mini, GPT-4.1-nano)\n- `anthropic` - Use Anthropic's models (Claude Sonnet 4.5, Claude Haiku 4.5, Claude Opus 4.5)\n- `google` - Use Google's models (Gemini 2.5 Pro, Gemini 2.5 Flash, Gemini 2.5 Flash-Lite)\n\n## API Keys\nYou need to set the API key that matches your chosen provider:\n- For OpenAI: Set `OPENAI_API_KEY`\n- For Anthropic: Set `ANTHROPIC_API_KEY`\n- For Google: Set `GOOGLE_API_KEY`\n\n<Callout type=\"warning\">\n Keep your API keys secure. Never commit your `.env` file to version control.\n</Callout>\n\n<Callout type=\"note\">\n Doccupine automatically adds `.env` to your `.gitignore` file.\n</Callout>\n\n## Using Anthropic with OpenAI\nIf you want to use Anthropic as your LLM provider, you must also have an OpenAI API key set. Here's why:\n\n### The Situation\nAnthropic (Claude) does not provide an embeddings API. They only offer chat/completion models, not text embeddings.\n\nYour RAG (Retrieval-Augmented Generation) system has two components:\n- **Chat/Completion** - Generates answers, works with Anthropic.\n- **Embeddings** - Creates vector representations of text for search, Anthropic doesn't provide this.\n\nWhen using Anthropic as your `LLM_PROVIDER`, Doccupine will use Anthropic for chat/completion tasks, but will automatically fallback to OpenAI for embeddings. This means you need both API keys configured:\n\n```env\nLLM_PROVIDER=anthropic\nANTHROPIC_API_KEY=your_anthropic_api_key_here\nOPENAI_API_KEY=your_openai_api_key_here\n```\n\nThis hybrid approach allows you to leverage Anthropic's powerful chat models while still having access to embeddings functionality through OpenAI.\n\n## Optional Settings\n\n### Chat Model\nOverride the default chat model by uncommenting and setting `LLM_CHAT_MODEL`. You can use any available model from your chosen provider. Example models include:\n- **OpenAI**: `gpt-4.1-nano`, `gpt-4.1-mini`, `gpt-4.1`\n- **Anthropic**: `claude-sonnet-4-5-20250929`, `claude-haiku-4-5-20251001`, `claude-opus-4-5-20251101`\n- **Google**: `gemini-2.5-flash-lite`, `gemini-2.5-pro`, `gemini-2.5-flash`\n\nFor a complete list of available models, refer to the official documentation:\n- [OpenAI Models](https://platform.openai.com/docs/models)\n- [Anthropic Models](https://docs.anthropic.com/claude/docs/models-overview)\n- [Google Gemini Models](https://ai.google.dev/models/gemini)\n\n### Embedding Model\nOverride the default embedding model by uncommenting and setting `LLM_EMBEDDING_MODEL`:\n- **OpenAI**: `text-embedding-3-small`, `text-embedding-3-large`\n- **Google**: `text-embedding-004`\n- **Anthropic**: Anthropic doesn't provide embeddings. If you use Anthropic as your provider, Doccupine will fallback to OpenAI for embeddings.\n\n### Temperature\nControl the randomness of AI responses by setting `LLM_TEMPERATURE` to a value between 0 and 1:\n- `0` - More deterministic and focused responses (default)\n- `1` - More creative and varied responses";
@@ -26,7 +26,7 @@ ANTHROPIC_API_KEY=your_anthropic_api_key_here
26
26
  GOOGLE_API_KEY=your_google_api_key_here
27
27
 
28
28
  # Optional: Override default models
29
- # OpenAI models: gpt-5-mini, gpt-5-nano, gpt-5
29
+ # OpenAI models: gpt-4.1-nano, gpt-5-mini, gpt-5-nano, gpt-5
30
30
  # Anthropic models: claude-sonnet-4-5-20250929, claude-haiku-4-5-20251001, claude-opus-4-5-20251101
31
31
  # Google models: gemini-2.5-flash-lite, gemini-2.5-pro, gemini-2.5-flash
32
32
  # LLM_CHAT_MODEL=gpt-4.1-nano
@@ -1 +1 @@
1
- export declare const llmConfigTemplate = "import type {\n LLMConfig,\n LLMProvider,\n ProviderDefaults,\n} from \"@/services/llm/types\";\nconst PROVIDER_DEFAULTS: ProviderDefaults = {\n openai: {\n chat: \"gpt-5-nano\",\n embedding: \"text-embedding-3-small\",\n },\n anthropic: {\n chat: \"claude-sonnet-4-5-20250929\",\n embedding: \"text-embedding-3-small\", // Fallback to OpenAI\n },\n google: {\n chat: \"gemini-2.5-flash-lite\",\n embedding: \"text-embedding-004\",\n },\n};\nfunction validateAPIKeys(provider: LLMProvider): void {\n const requiredKeys: Record<LLMProvider, string> = {\n openai: \"OPENAI_API_KEY\",\n anthropic: \"ANTHROPIC_API_KEY\",\n google: \"GOOGLE_API_KEY\",\n };\n const keyName = requiredKeys[provider];\n const keyValue = process.env[keyName];\n if (!keyValue) {\n throw new Error(\n `Missing API key for ${provider}. Please set ${keyName} in your environment variables.`,\n );\n }\n if (provider === \"anthropic\" && !process.env.OPENAI_API_KEY) {\n console.warn(\n \"Anthropic provider requires OPENAI_API_KEY for embeddings. Please set OPENAI_API_KEY in your environment variables.\",\n );\n }\n}\nexport function getLLMConfig(): LLMConfig {\n const provider = (process.env.LLM_PROVIDER || \"openai\") as LLMProvider;\n if (![\"openai\", \"anthropic\", \"google\"].includes(provider)) {\n throw new Error(\n `Invalid LLM_PROVIDER: ${provider}. Must be one of: openai, anthropic, google`,\n );\n }\n validateAPIKeys(provider);\n const defaults = PROVIDER_DEFAULTS[provider];\n return {\n provider,\n chatModel: process.env.LLM_CHAT_MODEL || defaults.chat,\n embeddingModel: process.env.LLM_EMBEDDING_MODEL || defaults.embedding,\n temperature: parseFloat(process.env.LLM_TEMPERATURE || \"1\"),\n };\n}\nexport function getLLMDisplayName(config?: LLMConfig): string {\n const c = config || getLLMConfig();\n const providerNames: Record<LLMProvider, string> = {\n openai: \"OpenAI\",\n anthropic: \"Anthropic\",\n google: \"Google\",\n };\n return `${providerNames[c.provider]} (${c.chatModel})`;\n}\nexport function isLLMConfigured(): boolean {\n try {\n getLLMConfig();\n return true;\n } catch {\n return false;\n }\n}\n";
1
+ export declare const llmConfigTemplate = "import type {\n LLMConfig,\n LLMProvider,\n ProviderDefaults,\n} from \"@/services/llm/types\";\nconst PROVIDER_DEFAULTS: ProviderDefaults = {\n openai: {\n chat: \"gpt-4.1-nano\",\n embedding: \"text-embedding-3-small\",\n },\n anthropic: {\n chat: \"claude-sonnet-4-5-20250929\",\n embedding: \"text-embedding-3-small\", // Fallback to OpenAI\n },\n google: {\n chat: \"gemini-2.5-flash-lite\",\n embedding: \"text-embedding-004\",\n },\n};\nfunction validateAPIKeys(provider: LLMProvider): void {\n const requiredKeys: Record<LLMProvider, string> = {\n openai: \"OPENAI_API_KEY\",\n anthropic: \"ANTHROPIC_API_KEY\",\n google: \"GOOGLE_API_KEY\",\n };\n const keyName = requiredKeys[provider];\n const keyValue = process.env[keyName];\n if (!keyValue) {\n throw new Error(\n `Missing API key for ${provider}. Please set ${keyName} in your environment variables.`,\n );\n }\n if (provider === \"anthropic\" && !process.env.OPENAI_API_KEY) {\n console.warn(\n \"Anthropic provider requires OPENAI_API_KEY for embeddings. Please set OPENAI_API_KEY in your environment variables.\",\n );\n }\n}\nexport function getLLMConfig(): LLMConfig {\n const provider = (process.env.LLM_PROVIDER || \"openai\") as LLMProvider;\n if (![\"openai\", \"anthropic\", \"google\"].includes(provider)) {\n throw new Error(\n `Invalid LLM_PROVIDER: ${provider}. Must be one of: openai, anthropic, google`,\n );\n }\n validateAPIKeys(provider);\n const defaults = PROVIDER_DEFAULTS[provider];\n return {\n provider,\n chatModel: process.env.LLM_CHAT_MODEL || defaults.chat,\n embeddingModel: process.env.LLM_EMBEDDING_MODEL || defaults.embedding,\n temperature: parseFloat(process.env.LLM_TEMPERATURE || \"1\"),\n };\n}\nexport function getLLMDisplayName(config?: LLMConfig): string {\n const c = config || getLLMConfig();\n const providerNames: Record<LLMProvider, string> = {\n openai: \"OpenAI\",\n anthropic: \"Anthropic\",\n google: \"Google\",\n };\n return `${providerNames[c.provider]} (${c.chatModel})`;\n}\nexport function isLLMConfigured(): boolean {\n try {\n getLLMConfig();\n return true;\n } catch {\n return false;\n }\n}\n";
@@ -5,7 +5,7 @@ export const llmConfigTemplate = `import type {
5
5
  } from "@/services/llm/types";
6
6
  const PROVIDER_DEFAULTS: ProviderDefaults = {
7
7
  openai: {
8
- chat: "gpt-5-nano",
8
+ chat: "gpt-4.1-nano",
9
9
  embedding: "text-embedding-3-small",
10
10
  },
11
11
  anthropic: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "doccupine",
3
- "version": "0.0.41",
3
+ "version": "0.0.43",
4
4
  "description": "Document management system that allows you to store, organize, and share your documentation with ease. AI-ready.",
5
5
  "main": "dist/index.js",
6
6
  "bin": {