feat: add Atomic Chat provider support (#60)

* feat: add support for Atomic Chat provider

- Introduced new provider 'Atomic Chat' with associated logo and configuration.
- Updated onboarding and settings components to include Atomic Chat.
- Added necessary files for provider integration, including images and configuration files.
- Updated provider catalog to include details for Atomic Chat.

This enhances the application by allowing users to utilize local LLMs via the Atomic Chat desktop app.

* refactor: remove deprecated configuration files and update README for Atomic Chat

- Deleted obsolete `.pnpm-approved-builds.json` and `mise.toml` files.
- Updated README to reflect the addition of Atomic Chat, including new usage instructions and configuration examples.
- Enhanced onboarding component to support Atomic Chat provider.
- Adjusted provider wizard description to include Atomic Chat alongside Ollama.

---------

Co-authored-by: SankaManka <rita@bagoodex.com>
This commit is contained in:
Mike
2026-04-15 04:43:38 +03:00
committed by GitHub
parent 1c4bc95adc
commit 591e8a2a04
10 changed files with 101 additions and 14 deletions

View File

@@ -106,13 +106,24 @@ ANTHROPIC_API_KEY=your-key-here
---
## 🧠 Local Models (Ollama, LM Studio, vLLM)
## 🧠 Local Models (Ollama, Atomic Chat, LM Studio, vLLM)
Hermes Workspace supports two modes with local models:
### Portable Mode (Easiest)
Point the workspace directly at your local server — no Hermes gateway needed:
Point the workspace directly at your local server — no Hermes gateway needed.
### Atomic Chat
```bash
# Start workspace pointed at Atomic Chat
HERMES_API_URL=http://127.0.0.1:1337/v1 pnpm dev
```
Download [Atomic Chat](https://atomic.chat/), launch the desktop app, and make sure a model is loaded before starting Hermes Workspace.
### Ollama
```bash
# Start Ollama
@@ -126,13 +137,27 @@ Chat works immediately. Sessions, memory, and skills show "Not Available" — th
### Enhanced Mode (Full Features)
Route through the Hermes gateway for sessions, memory, skills, jobs, and tools:
Route through the Hermes gateway for sessions, memory, skills, jobs, and tools.
**1. Configure your local model in `~/.hermes/config.yaml`:**
Here are two explicit `~/.hermes/config.yaml` examples for the local providers we support directly in the workspace:
**Atomic Chat**
```yaml
provider: atomic-chat
model: your-model-name
custom_providers:
- name: atomic-chat
base_url: http://127.0.0.1:1337/v1
api_key: atomic-chat
api_mode: chat_completions
```
**Ollama**
```yaml
provider: ollama
model: qwen2.5:7b # or any model you have pulled
model: qwen3:32b
custom_providers:
- name: ollama
base_url: http://127.0.0.1:11434/v1
@@ -140,6 +165,8 @@ custom_providers:
api_mode: chat_completions
```
You can adapt the same shape for other OpenAI-compatible local runners, but `Atomic Chat` and `Ollama` are the two built-in local paths documented in the workspace UI.
**2. Enable the API server in `~/.hermes/.env`:**
```env
@@ -155,7 +182,7 @@ HERMES_API_URL=http://127.0.0.1:8642 pnpm dev
All workspace features unlock automatically — sessions persist, memory saves across chats, skills are available, and the dashboard shows real usage data.
> **Works with any OpenAI-compatible server** — Ollama, LM Studio, vLLM, llama.cpp, LocalAI, etc. Just change the `base_url` and `model` in the config above.
> **Works with any OpenAI-compatible server** — Atomic Chat, Ollama, LM Studio, vLLM, llama.cpp, LocalAI, etc. Just change the `base_url` and `model` in the config above.
---

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 199 KiB

View File

@@ -12,6 +12,7 @@ const KNOWN_PROVIDER_PREFIXES = [
'openai-codex',
'nous',
'ollama',
'atomic-chat',
'zai',
'kimi-coding',
'minimax',
@@ -86,6 +87,13 @@ const PROVIDERS = [
desc: 'Local models, no key needed',
authType: 'none',
},
{
id: 'atomic-chat',
name: 'Atomic Chat',
logo: '/providers/atomic-chat.png',
desc: 'Local LLMs via Atomic Chat desktop app',
authType: 'none',
},
{
id: 'custom',
name: 'Custom (OpenAI-compat)',
@@ -147,7 +155,9 @@ export function HermesOnboarding() {
const needsApiKey =
provider?.authType === 'api_key' || provider?.authType === 'custom'
const needsBaseUrl =
provider?.id === 'ollama' || provider?.authType === 'custom'
provider?.id === 'ollama' ||
provider?.id === 'atomic-chat' ||
provider?.authType === 'custom'
const isOAuth = provider?.authType === 'oauth'
const capabilities = backendInfo?.capabilities
const canEditConfig = Boolean(capabilities?.config)
@@ -257,7 +267,9 @@ export function HermesOnboarding() {
body.env = { [prov.envKey]: apiKey }
}
if (baseUrl) {
body.config = { model: { provider: selectedProvider, baseUrl } }
body.config = {
model: { provider: selectedProvider, base_url: baseUrl },
}
}
const res = await fetch('/api/hermes-config', {
@@ -334,7 +346,7 @@ export function HermesOnboarding() {
const decoder = new TextDecoder()
let text = ''
while (true) {
for (;;) {
const { done, value } = await reader.read()
if (done) break
const chunk = decoder.decode(value)
@@ -796,7 +808,9 @@ export function HermesOnboarding() {
>
{selectedProvider === 'ollama'
? 'Ollama URL'
: 'Base URL'}
: selectedProvider === 'atomic-chat'
? 'Atomic Chat URL'
: 'Base URL'}
</label>
<input
type="text"
@@ -805,7 +819,9 @@ export function HermesOnboarding() {
placeholder={
selectedProvider === 'ollama'
? 'http://localhost:11434'
: 'https://api.example.com/v1'
: selectedProvider === 'atomic-chat'
? 'http://127.0.0.1:1337/v1'
: 'https://api.example.com/v1'
}
className="w-full rounded-lg px-3 py-2 text-sm outline-none focus:ring-2 focus:ring-accent-500"
style={inputStyle}

View File

@@ -46,6 +46,7 @@ export function ProviderLogo({
anthropic: 'anthropic.png',
openrouter: 'openrouter.png',
ollama: 'ollama.png',
'atomic-chat': 'atomic-chat.png',
kimi: 'kimi.png',
'kimi-coding': 'kimi.png',
minimax: 'minimax.png',

View File

@@ -226,6 +226,13 @@ const PROVIDER_CARDS: Array<{
models: ['llama3.1:70b', 'qwen3:32b', 'deepseek-r1:32b'],
authType: 'none',
},
{
id: 'atomic-chat',
name: 'Atomic Chat',
logo: '/providers/atomic-chat.png',
models: ['llama-3.2-3b', 'qwen2.5-7b', 'gemma-3-4b'],
authType: 'none',
},
{ id: 'custom', name: 'Custom', logo: '', models: [], authType: 'api_key' },
]

View File

@@ -137,6 +137,26 @@ export const PROVIDER_CATALOG: Array<ProviderInfo> = [
2,
),
},
{
id: 'atomic-chat',
name: 'Atomic Chat',
description: 'Local LLMs via Atomic Chat — run Llama, Gemma, Qwen and more on your machine.',
authTypes: ['local'],
docsUrl: 'https://atomic.chat',
configExample: JSON.stringify(
{
auth: {
profiles: {
'atomic-chat:local': {
provider: 'atomic-chat',
},
},
},
},
null,
2,
),
},
]
export function normalizeProviderId(value: string): string {

View File

@@ -67,6 +67,12 @@ const PROVIDERS = [
envKeys: ['XIAOMI_API_KEY'],
},
{ id: 'ollama', name: 'Ollama (Local)', authType: 'none', envKeys: [] },
{
id: 'atomic-chat',
name: 'Atomic Chat (Local)',
authType: 'none',
envKeys: [],
},
{
id: 'custom',
name: 'Custom OpenAI-compatible',
@@ -78,7 +84,10 @@ const PROVIDERS = [
function readConfig(): Record<string, unknown> {
try {
const raw = fs.readFileSync(CONFIG_PATH, 'utf-8')
return (YAML.parse(raw) as Record<string, unknown>) || {}
const parsed = YAML.parse(raw)
return parsed && typeof parsed === 'object' && !Array.isArray(parsed)
? (parsed as Record<string, unknown>)
: {}
} catch {
return {}
}
@@ -296,7 +305,7 @@ export const Route = createFileRoute('/api/hermes-config')({
// Handle env var updates
if (body.env && typeof body.env === 'object') {
const currentEnv = readEnv()
const envUpdates = body.env as Record<string, string>
const envUpdates = body.env as Record<string, string | null>
for (const [key, value] of Object.entries(envUpdates)) {
if (value === '' || value === null) {
delete currentEnv[key]

View File

@@ -93,7 +93,7 @@ function getAuthTypeMeta(authType: ProviderAuthType): AuthTypeMeta {
return {
title: 'Local',
description: 'No auth needed (Ollama)',
description: 'No auth needed for local backends like Ollama or Atomic Chat',
}
}

View File

@@ -59,6 +59,7 @@ const KNOWN_PROVIDER_PREFIXES = [
'openai-codex',
'nous',
'ollama',
'atomic-chat',
'zai',
'kimi-coding',
'minimax',
@@ -787,6 +788,12 @@ const MODEL_PROVIDER_OPTIONS: Array<SelectOption> = [
]
const MODEL_PRESETS = [
{
id: 'atomic-chat',
label: 'Atomic Chat',
provider: 'custom' as const,
baseUrl: 'http://127.0.0.1:1337/v1',
},
{
id: 'ollama',
label: 'Ollama',