WilmerAI is a middleware system that acts as an orchestration engine between front-end applications and various Large Language Model (LLM) backends. It allows you to build complex, multi-step AI behaviors using a node-based workflow system, all while presenting a simple, industry-standard API to your existing tools.
Instead of being a single model, WilmerAI is a highly configurable engine that lets you chain together different models, tools, and memory systems to process a single user request.
At the heart of WilmerAI is a node-based workflow engine. A workflow is a JSON file that defines a sequence of steps, or "nodes," to be executed in order. This allows you to create multi-step logic that goes far beyond a simple single-LLM response.
- Nodes as Building Blocks: Each node in a workflow performs a specific task, such as calling an LLM, searching a database, running a Python script, or retrieving conversational memory.
- Sequential Data Flow: The output of one node is automatically made available to all subsequent nodes. For example, the first node could extract keywords from a user's prompt, and the second node could use those keywords to perform a vector memory search. The third node could then take the search results and the original prompt to generate a final, context-aware answer.
- Flexibility and Control: This architecture gives you precise control over the entire request-response lifecycle, allowing for the creation of specialized agents, Retrieval-Augmented Generation (RAG) pipelines, and dynamic, multi-tool automations.
WilmerAI integrates several features into its workflow engine, enabling you to build highly customized and intelligent systems.
WilmerAI emulates the APIs of popular services like OpenAI and Ollama. This allows you to connect your existing front-end applications directly to WilmerAI without any code changes. The client application believes it is communicating with a standard LLM service, while WilmerAI orchestrates complex workflows in the background.
How a client application should format its requests depends on the type of endpoint it is connecting to.
-
Chat Completion Endpoints (e.g.,
/v1/chat/completions): When using these endpoints, the client sends a structured array of messages (e.g., with "role" and "content" pairs). WilmerAI processes this format directly. Generation parameters like temperature, top_k, etc., are controlled by the WilmerAI workflow, overriding most settings configured in the client application. -
Text Completion Endpoints (e.g.,
/v1/completionsor/api/generate): When connecting to these legacy-style endpoints, WilmerAI requires the client to format the prompt using a specific structure. This allows the middleware to correctly parse the conversation history. The format uses tags to separate the system prompt, user messages, and assistant messages, with no spaces or newlines between the tags.- Tag Structure:
[Beg_Sys]: Marks the beginning of the system prompt.[Beg_User]: Marks the beginning of a user's turn.[Beg_Assistant]: Marks the beginning of the assistant's turn.
- Example:
[Beg_Sys]You are an intelligent AI Assistant.[Beg_User]SomeOddCodeGuy: Hey there![Beg_Assistant]Wilmer: Hello![Beg_User]SomeOddCodeGuy: This is a test[Beg_Assistant]
- Tag Structure:
You are not locked into a single LLM provider. WilmerAI's Adaptable LLM Connector can interface with any LLM backend, including local models via Ollama or KoboldCpp and cloud services from OpenAI. Furthermore, different nodes within a single workflow can be configured to use different models, allowing you to optimize for cost, speed, and capability at each step of a process.
WilmerAI provides two layers of routing for creating dynamic and adaptable agents:
- Prompt Routing: An initial routing engine can analyze the user's intent and direct the incoming request to the most appropriate workflow. For example, it can automatically send coding questions to a coding-specific workflow and factual queries to a research-focused one.
- In-Workflow Routing: Within a workflow, conditional "if/then" logic can be implemented. A node can make a decision based on the output of a previous step and execute a specific sub-workflow, enabling non-linear execution paths.
Workflows can be nested, allowing you to build a task once and reuse it anywhere. A common process, such as summarizing text or searching a database, can be encapsulated in its own "child" workflow. This child workflow can then be called as a single node from any "parent" workflow, simplifying design and eliminating redundant logic.
WilmerAI includes a four-part memory system that provides long-term context for conversations. By including a
[DiscussionId] in your request, you can enable:
- Long-Term Memory File: Chronological, summarized chunks of the conversation.
- Rolling Chat Summary: A continuously updated high-level summary of the entire discussion.
- Searchable Vector Memory: A dedicated full-text search database for the discussion, allowing for efficient keyword-based search to retrieve relevant information, with optional embedding-based semantic or hybrid search when an embeddings endpoint is configured.
- State Document: A continuously updated markdown snapshot of what is currently true in the conversation (a user profile, world state, etc.), maintained by the vector memory pipeline and readable by workflows at any time.
When a client sends an Authorization: Bearer <key> header, WilmerAI stores all discussion files in an isolated
directory derived from the API key. This allows multiple users or applications to share a single WilmerAI instance
without risk of data leakage. Directory isolation activates automatically based on the presence of the header. To also
encrypt files at rest, set "encryptUsingApiKey": true in your user configuration file. Without an API key, behavior
is unchanged. See Per-User Encryption and Data Isolation for full details.
The workflow engine can be extended with custom tools. This includes nodes for running local Python scripts or connecting to external services. A built-in example is the Offline Wikipedia Integration, which allows a workflow to query a local Wikipedia database to provide factual context for a response.
Front-ends that use OpenAI-style tool calling work through WilmerAI end to end: tool definitions pass through to the
backend, tool call responses relay back, and multi-round tool loops work reliably through authored-prompt workflows
via native delivery of the live tool exchange. On backends with constrained decoding, demanded tool calls
(tool_choice forced or "required") are grammar-enforced, and any workflow node can pin its output to a JSON
Schema so downstream nodes consume guaranteed-parseable JSON. See
Tool Calling and Structured Output.
- Standard API Request: A client application sends a request to one of WilmerAI's API endpoints (e.g.,
/v1/chat/completions) in a standard format. - Workflow Selection: The engine receives the request. If configured, the Prompt Routing engine analyzes the prompt's intent to select the most appropriate workflow file.
- Node Execution: The Workflow Engine begins executing the nodes defined in the selected workflow, one by one.
- Orchestration: As the workflow runs, nodes might call different LLMs, query the vector memory database for relevant context, execute a nested sub-workflow for a specialized task, or run a Python script. The output from each step is passed along for the next step to use.
- Response Generation: One node in the workflow is designated as the "responder." Its final output is captured by the engine.
- Formatted API Response: WilmerAI formats the responder's output into the API schema the original client application expects (e.g., an OpenAI-compliant JSON object) and sends it back, completing the cycle.
WilmerAI
│
├─ Middleware
│
├─ Public
│ └─ Configs
│ ├─ ApiTypes
│ ├─ Endpoints
│ │ ├─ folders named after usernames
│ │ └─ ...
│ ├─ Presets
│ │ ├─ folders named for specific types
│ │ │ ├─ folders named after usernames
│ │ │ └─ ...
│ │ └─ ...
│ ├─ PromptTemplates
│ ├─ Routing
│ ├─ Users
│ └─ Workflows
│ ├─ folders named after usernames
│ └─ ...
│
├─ run_macos.sh
├─ run_windows.bat
└─ server.py
This is the application's core logic. The code for the application can be found within here. This is essentially the src folder
Contains all user-facing JSON configuration files.
ApiTypes/: Contains json files that define the schemas for different LLM APIs, specifying property names for things likestreamingormax_tokens. These are utilized in the Endpoint configsEndpoints/: Contains json files that specify connection details for an LLM API (e.g., URL, API Type) that Wilmer will make calls to. Every LLM that the user intends to use in their workflows must be specified here. Every workflow node can specify a different endpoint.Presets/: Contains json files with LLM generation parameters (temperature, top_k, etc.). These are applied per workflow node.PromptTemplates/: Contains the json files that specify various prompt templates. Used in Endpoint configsRouting/: Contains json files that specify the central semantic router instructions for users/workflows that do routing. You specify the domains you are routing to here, and what workflows they correspond with.Users/: Contains json files with all of the specific settings for a user, including things like what port the app runs on, where to connect to things like the offline wikipedia api, and where certain files are saved, go here.Workflows/: Contains json files that define the sequence of nodes for each workflow. Workflows are organized into subfolders, typically named after each user (e.g.,Workflows/<username>/). The subfolder used can be customized via theworkflowConfigsSubDirectoryOverridesetting in the User config._shared/: A special folder for shared workflows. Workflows placed directly in_shared/are listed by the/v1/modelsand/api/tagsendpoints, allowing front-end applications to select them via the model dropdown. See "Workflow Selection via Model Field" below for details.
Scripts to automatically generate a venv, install the requirements.txt for the app, and run the application by calling server.py. Takes the following optional parameters:
--ConfigDirectory: String input that specifies where the Public/Configs folder is at.--User: String input that specifies the name of the user you'd like to start the app as. Can be repeated for multi-user mode.--port: Integer input that specifies the port to listen on. In single-user mode, falls back to the user's config. In multi-user mode, defaults to 5050.--listen: Listen on the network. With no value, binds to 0.0.0.0 (all interfaces). Optionally accepts a specific address.--concurrency: Integer input that sets the max concurrent requests (or LLM calls in endpoint mode). 0 = no limit. Default: 1.--concurrency-timeout: Integer input that sets the seconds to wait for a concurrency slot before returning 503. Default: 900.--concurrency-level:wilmerorendpoint. Selects where the gate is enforced.wilmer(default) gates at the request boundary;endpointlifts the request gate and serializes only outbound LLM API calls, allowing reentrant requests (workflows that call back into the same Wilmer instance) to make progress. Default:wilmer.--file-logging: Enable file logging. In single-user mode, falls back to the user's useFileLogging config setting. In multi-user mode, defaults to off.--LoggingDirectory: Directory for log files. When unset, defaults to{PublicDirectory}/logs/if--PublicDirectoryis provided, otherwise{install_dir}/Public/logs/. The default is install-pinned (derived from the location ofserver.pyon disk) and does not depend on the current working directory.
Main script of the app.
When loading a user that has allowSharedWorkflows set to true, WilmerAI allows front-end applications to select
specific workflows by using the model field in API requests. This enables users to switch between different workflows
directly from their front-end's model dropdown without changing configuration files.
-
Models List Endpoints: The
/v1/models(OpenAI) and/api/tags(Ollama) endpoints return a list of available models. In single-user mode, these are workflows from_shared/inusername:workflowformat. In multi-user mode, models are aggregated from all configured users. -
Workflow Selection: When your front-end sends a request with a model field like
"model": "chat-ui:general", WilmerAI extracts the workflow name and executes that workflow directly from the_sharedfolder. In multi-user mode, ifchat-uimatches a configured user, that user's config is used for the request. -
Response Format: Responses include the model in
username:workflowformat when a workflow override is active, allowing your front-end to maintain the selected workflow across requests.
A single Wilmer instance can serve multiple users. Instead of running separate instances for each user, start one
instance with multiple --User flags:
bash run_macos.sh --User user-one --User user-two --User user-threeEach user must have a configuration file in Public/Configs/Users/ (e.g., user-one.json, user-two.json).
In multi-user mode, the per-user port setting is ignored; use --port on the command line (defaults to 5050).
All users share the same concurrency gate, which serializes requests to shared LLM hardware regardless of which
user they belong to.
The models endpoint will list models from all configured users. A front-end can target a specific user by sending
"model": "user-two" or "model": "user-two:general" in the request.
Public/Configs/Workflows/
├── _shared/
│ ├── general/ # Listed by models endpoint as folder name
│ │ └── _DefaultWorkflow.json # Workflow loaded when folder is selected
│ ├── fast/
│ │ └── _DefaultWorkflow.json
│ ├── general-reasoning/
│ │ └── _DefaultWorkflow.json
│ ├── fast-reasoning/
│ │ └── _DefaultWorkflow.json
│ └── task/
│ └── _DefaultWorkflow.json
├── example-user/ # A user's own workflow folder (optional)
│ └── ...
- Create a folder in
Public/Configs/Workflows/_shared/with your workflow name (e.g.,general/) - Place a
_DefaultWorkflow.jsonfile inside the folder - Folder names become the selectable model names (e.g.,
general/→chat-ui:general) - Query
/v1/modelsor/api/tagsfrom your front-end to see available workflows - Select a workflow from the model dropdown in your front-end application
The API accepts these model field formats:
| Format | Example | Behavior |
|---|---|---|
username:workflow |
chat-ui:general |
Uses the specified workflow (and user in multi-user mode) |
username |
chat-ui |
In multi-user mode, routes to that user's default workflow |
workflow |
general |
Uses workflow if it exists in _shared/ |
| Anything else | gpt-4 |
Falls back to normal routing |
The workflowConfigsSubDirectoryOverride user config setting loads workflows from a named subfolder under
Public/Configs/Workflows/ instead of the username folder. For example, setting
"workflowConfigsSubDirectoryOverride": "coding-workflows" loads workflows from Public/Configs/Workflows/coding-workflows/.
Upgrade note: this setting previously resolved under Public/Configs/Workflows/_overrides/<value>/. It now
resolves directly under Public/Configs/Workflows/<value>/; if you used the old location, move your override
folder up out of _overrides/.