Capabilities/AI capabilities

AI capabilities

Structure, providers, and calling Python from the web.

Structure

The ai/ directory houses all Python-based intelligence code. It is designed to be composable and independent. You can write LangChain agents, LlamaIndex RAG pipelines, or direct OpenAI API calls.

ai/ after selecting capabilities
1ai/
2|-- __init__.py
3|-- llm/                      # one folder per provider
4|   `-- anthropic.py          # get_client() -> Anthropic
5|-- agents/                   # agent orchestration (when selected)
6|-- rag/                      # RAG pipelines (when selected)
7|-- tools/                    # custom tools (when selected)
8|-- prompts/                  # prompt templates (when selected)
9`-- mcp/                     # MCP servers (when selected)

Each capability is a thin, composable starting point. The LLM provider template hands you the official SDK client; capabilities build on it without baking combinations into the scaffold:

The provider client
1from anthropic import Anthropic
2
3def get_client() -> Anthropic:
4    return Anthropic()

Providers

The provider is chosen in bionicjs.config.ts under the ai key, and becomes the ai export on @bionicjs/core/server:

PackageProviderClient
@bionicjs/anthropicAnthropicAnthropic SDK
@bionicjs/openaiOpenAIOpenAI SDK
@bionicjs/googleGoogle / GeminiGoogle Gemini SDK
@bionicjs/ollamaOllamaOllama / local models

Capabilities live in ai/, independent of the provider. The same agents/ or rag/ code works whether you wired Anthropic, OpenAI, Google, or Ollama - the provider client is injected, not imported.

Calling from the web

BionicJS does not reinvent AI abstractions; it provides a structured home for them within the full-stack repository. The path from a React button to a Python agent:

  1. The component calls a generated RPC stub by name.
  2. Nitro forwards the call to the Python RPC surface.
  3. The Python function uses the provider client and capabilities in ai/.
  4. The result returns through the boundary with its type intact.
ⓘ
For long-running generation, don't block the web request. Enqueue a background job instead - the same capability, the same boundary, but processed by a worker with a WebSocket completion signal. See background jobs.