Skip to main content

Overview

FIM One is built around a set of thin abstract base classes — one per swappable component. Every component has a single responsibility and a minimal interface. You implement the abstract methods, wire the instance into the appropriate registry or injector, and the rest of the system uses your implementation automatically.

Custom LLM provider

BaseLLM has two required methods — chat and stream_chat — plus an optional abilities property that tells the rest of the system what the model can do.

Registration via ModelRegistry

ModelRegistry maps names to BaseLLM instances and resolves by role. The system uses four built-in roles: general, fast, compact, and vision. You can add your own.
The abilities dict is the contract between the LLM and the ReAct engine. When tool_call=True and the agent was created with use_native_tools=True, the engine will use native function calling. Otherwise it falls back to JSON mode automatically.

Custom tool

Tools are the most common extension. BaseTool has three required pieces: name, description, and run. Everything else has sensible defaults.

Auto-discovery

Drop your file in src/fim_one/core/tool/builtin/. The discover_builtin_tools() scanner will find any concrete (non-abstract) BaseTool subclass automatically — no manual registration needed.
The scanner skips classes listed in _SKIP_AUTO_DISCOVER. Use that set for tools that require external configuration (e.g. an API key) and need to be conditionally instantiated at startup.

Signalling unavailability

Override availability() to surface a message in the tool catalog when a dependency is missing:

Rich results with artifacts

Return a ToolResult instead of a plain str when your tool produces files:

Custom memory

BaseMemory is the persistence layer for conversation history. Three methods: add_message, get_messages, clear.
Inject via the agent constructor: ReActAgent(llm=llm, memory=RedisMemory(conv_id, url)).

Custom embedding

BaseEmbedding provides two methods: embed_texts (batch) and embed_query (single), plus a dimension property.
The distinction between embed_texts and embed_query exists because many embedding models (e.g. E5, BGE) use different prefixes for documents vs. queries to improve retrieval quality.

Custom image generation

BaseImageGen has a single method generate. It saves the image to output_dir and returns an ImageResult with the file path and a server-relative URL.

Custom reranker

BaseReranker takes a query and a list of document strings and returns them reordered with scores.

Custom web backends

Web fetch

BaseWebFetch fetches a URL and returns its content as Markdown or plain text.
BaseWebSearch returns a ranked list of SearchResult objects.

Custom RAG components

The RAG pipeline has three independently swappable stages: loading, chunking, and retrieval.

Document loader

BaseLoader turns a file path into a list of LoadedDocument objects. PDF loaders typically return one document per page.

Text chunker

BaseChunker splits text into Chunk objects. MAX_CHUNK_SIZE = 6000 characters is the hard ceiling — chunk sizes above this can overflow the Jina Embeddings v3 token window.

Retriever

BaseRetriever queries any backend and returns ranked Document objects.

Design principles

A few patterns are consistent across all base classes that make custom implementations easier to write correctly: Async-first. Every method is async def. Even if your implementation is synchronous, wrap it with asyncio.to_thread() rather than blocking the event loop. String output from tools. BaseTool.run() returns str (or ToolResult). The LLM only ever sees text — tool implementations are responsible for serializing complex data into a readable format. Minimal interfaces. Each base class defines the smallest contract needed. BaseMemory is three methods; BaseWebFetch is one. You are never required to implement functionality you don’t need. Composition over inheritance. The base classes are interfaces, not frameworks. You inject your implementation at construction time; the runtime never monkey-patches or subclasses it further.