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:
39
README.md
39
README.md
@@ -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.
|
||||
|
||||
---
|
||||
|
||||
|
||||
BIN
public/providers/atomic-chat.png
Normal file
BIN
public/providers/atomic-chat.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 199 KiB |
BIN
public/providers/light/atomic-chat.png
Normal file
BIN
public/providers/light/atomic-chat.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 199 KiB |
@@ -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}
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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' },
|
||||
]
|
||||
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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',
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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',
|
||||
|
||||
Reference in New Issue
Block a user