{"slug": "lean-ai-in-langbear", "title": "Lean AI in LangBear", "summary": "LangBear, a fully bootstrapped application, has developed a lightweight, provider-agnostic AI interface to avoid the maintenance burden and dependency issues of heavier frameworks like LangChain.js. The custom interface, defined by a simple TypeScript type, allows the app to switch between AI providers such as OpenAI, Gemini, Anthropic, and OpenRouter in a single commit. This lean approach enables flexible migration to cheaper AI options without sacrificing functionality.", "body_md": "[LangBear](https://langbear.com) is fully bootstrapped. This means no investors' money to burn, no big budgets. All funding has been coming from my main job's income. This is why I made a decision early on to stay AI provider-agnostic as much as possible to have the flexibility to migrate to cheaper options.\n\nAt first, I tried LangChain.js. It was too heavy and was burdensome to maintain. Too many dependencies. The API wasn't stable and oftentimes broke when I had to bump the version for security fixes.\n\nI decided to write a very lightweight interface that would satisfy all use cases of the app.\n\nI present it to you with all its glory as it is today:\n\n``` python\nimport type z from \"zod/v3\";\n\nexport type AIProvider = {\n\n  generateText<T extends z.ZodTypeAny>(\n    prompt: string,\n    schema: T,\n    options?: AIProviderGenerateTextOptions,\n  ): Promise<z.infer<T>>;\n\n  transcribeAudio(filePath: string): Promise<string>;\n};\n\nexport type AIProviderThinkingConfig =\n  | {\n      // 0 disables thinking, -1 lets the provider choose automatically\n      thinkingBudget: 0 | -1;\n      thinkingLevel?: never;\n    }\n  | {\n      thinkingBudget?: never;\n      thinkingLevel: \"MINIMAL\" | \"LOW\" | \"MEDIUM\" | \"HIGH\";\n    };\n\nexport type AIProviderGenerateTextOptions = {\n  model?: string;\n  thinkingConfig?: AIProviderThinkingConfig;\n};\n```\n\nSo far, I've already tried OpenAI, Gemini, Anthropic, OpenRouter and switching between providers only takes 1 commit.\n\nIn the code, you would use it like this:\n\n```\nfunction translateText(\n  aiProvider: AIProvider,\n  model: string,\n  text: string,\n  targetLang: string,\n): Promise<string> {\n  const { translatedText } = await aiProvider.generateText(\n    getTranslateTextPrompt(text, targetLang),\n    z.object({ translatedText: z.string() }),\n    {\n      model,\n    },\n  );\n\n  return translatedText;\n}\n\nawait translateText(geminiProvider, \"gemini-3.5-flash\", \"hej\", \"en\")\n// hello\n```\n\nImplementation of this interface is trivial. Here's a partial implementation for the Gemini provider for `generateText`\n\nfunction:\n\n```\nasync function generateText<T extends z.ZodTypeAny>(\n  prompt: string,\n  schema: T,\n  { geminiApiKey, model, thinkingConfig }: GenerateTextOptions,\n): Promise<z.infer<T>> {\n  const gemini = new GoogleGenAI({\n    apiKey: geminiApiKey,\n  });\n\n  const config: GenerateContentConfig = {\n    responseMimeType: \"application/json\",\n    responseJsonSchema: zodToJsonSchema(schema),\n  };\n  const geminiThinkingConfig = toGeminiThinkingConfig(thinkingConfig);\n\n  if (geminiThinkingConfig) {\n    config.thinkingConfig = geminiThinkingConfig;\n  }\n\n  const response = await gemini.models.generateContent({\n    model,\n    contents: prompt,\n    config,\n  });\n\n  if (!response.text) {\n    throw new Error(\"no content\");\n  }\n\n  return schema.parse(JSON.parse(response.text));\n}\n```\n\n", "url": "https://wpnews.pro/news/lean-ai-in-langbear", "canonical_source": "https://dev.to/langbear/lean-ai-in-langbear-3oe", "published_at": "2026-06-04 15:40:50+00:00", "updated_at": "2026-06-04 15:42:13.164513+00:00", "lang": "en", "topics": ["ai-tools", "ai-infrastructure", "ai-startups", "ai-products", "large-language-models"], "entities": ["LangBear", "LangChain.js", "OpenAI", "Gemini", "Anthropic", "OpenRouter", "Zod"], "alternates": {"html": "https://wpnews.pro/news/lean-ai-in-langbear", "markdown": "https://wpnews.pro/news/lean-ai-in-langbear.md", "text": "https://wpnews.pro/news/lean-ai-in-langbear.txt", "jsonld": "https://wpnews.pro/news/lean-ai-in-langbear.jsonld"}}