mirror of
https://github.com/HKUDS/nanobot.git
synced 2026-05-19 16:12:30 +00:00
feat: add Atomic Chat as OpenAI-compatible local provider
Register atomic_chat in the provider registry with default base URL http://localhost:1337/v1, schema field, docs, and config tests.
This commit is contained in:
parent
9ccef018c2
commit
18072856ec
@ -80,6 +80,7 @@ IMAP_PASSWORD=your-password-here
|
|||||||
| `longcat` | LLM (LongCat) | [longcat.chat](https://longcat.chat/platform/docs/zh/) |
|
| `longcat` | LLM (LongCat) | [longcat.chat](https://longcat.chat/platform/docs/zh/) |
|
||||||
| `ollama` | LLM (local, Ollama) | — |
|
| `ollama` | LLM (local, Ollama) | — |
|
||||||
| `lm_studio` | LLM (local, LM Studio) | — |
|
| `lm_studio` | LLM (local, LM Studio) | — |
|
||||||
|
| `atomic_chat` | LLM (local, [Atomic Chat](https://atomic.chat/)) | — |
|
||||||
| `mistral` | LLM | [docs.mistral.ai](https://docs.mistral.ai/) |
|
| `mistral` | LLM | [docs.mistral.ai](https://docs.mistral.ai/) |
|
||||||
| `stepfun` | LLM (Step Fun/阶跃星辰) | [platform.stepfun.com](https://platform.stepfun.com) |
|
| `stepfun` | LLM (Step Fun/阶跃星辰) | [platform.stepfun.com](https://platform.stepfun.com) |
|
||||||
| `ovms` | LLM (local, OpenVINO Model Server) | [docs.openvino.ai](https://docs.openvino.ai/2026/model-server/ovms_docs_llm_quickstart.html) |
|
| `ovms` | LLM (local, OpenVINO Model Server) | [docs.openvino.ai](https://docs.openvino.ai/2026/model-server/ovms_docs_llm_quickstart.html) |
|
||||||
@ -502,6 +503,36 @@ ollama run llama3.2
|
|||||||
|
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
<details>
|
||||||
|
<summary><b>Atomic Chat (local)</b></summary>
|
||||||
|
|
||||||
|
[Atomic Chat](https://atomic.chat/) is a local-first desktop app that exposes an **OpenAI-compatible** HTTP API (default `http://localhost:1337/v1`). Start Atomic Chat and enable the local API server, then point nanobot at it.
|
||||||
|
|
||||||
|
**1. Add to config** (partial — merge into `~/.nanobot/config.json`):
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"providers": {
|
||||||
|
"atomic_chat": {
|
||||||
|
"apiKey": null,
|
||||||
|
"apiBase": "http://localhost:1337/v1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"agents": {
|
||||||
|
"defaults": {
|
||||||
|
"provider": "atomic_chat",
|
||||||
|
"model": "your-model-id-from-atomic-chat"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
> **Note:** Set `apiKey` to `null` if your Atomic Chat server does not require a key. If it does, set `apiKey` (or the `ATOMIC_CHAT_API_KEY` environment variable) to the value Atomic Chat expects. The `model` string must match the model id Atomic Chat exposes on its OpenAI-compatible endpoint.
|
||||||
|
|
||||||
|
> `provider: "auto"` also works when `providers.atomic_chat.apiBase` is configured, but setting `"provider": "atomic_chat"` is the clearest option.
|
||||||
|
|
||||||
|
</details>
|
||||||
|
|
||||||
<details>
|
<details>
|
||||||
<summary><b>OpenVINO Model Server (local / OpenAI-compatible)</b></summary>
|
<summary><b>OpenVINO Model Server (local / OpenAI-compatible)</b></summary>
|
||||||
|
|
||||||
|
|||||||
@ -197,6 +197,7 @@ class ProvidersConfig(Base):
|
|||||||
vllm: ProviderConfig = Field(default_factory=ProviderConfig)
|
vllm: ProviderConfig = Field(default_factory=ProviderConfig)
|
||||||
ollama: ProviderConfig = Field(default_factory=ProviderConfig) # Ollama local models
|
ollama: ProviderConfig = Field(default_factory=ProviderConfig) # Ollama local models
|
||||||
lm_studio: ProviderConfig = Field(default_factory=ProviderConfig) # LM Studio local models
|
lm_studio: ProviderConfig = Field(default_factory=ProviderConfig) # LM Studio local models
|
||||||
|
atomic_chat: ProviderConfig = Field(default_factory=ProviderConfig) # Atomic Chat local models
|
||||||
ovms: ProviderConfig = Field(default_factory=ProviderConfig) # OpenVINO Model Server (OVMS)
|
ovms: ProviderConfig = Field(default_factory=ProviderConfig) # OpenVINO Model Server (OVMS)
|
||||||
gemini: ProviderConfig = Field(default_factory=ProviderConfig)
|
gemini: ProviderConfig = Field(default_factory=ProviderConfig)
|
||||||
moonshot: ProviderConfig = Field(default_factory=ProviderConfig)
|
moonshot: ProviderConfig = Field(default_factory=ProviderConfig)
|
||||||
|
|||||||
@ -422,6 +422,17 @@ PROVIDERS: tuple[ProviderSpec, ...] = (
|
|||||||
detect_by_base_keyword="1234",
|
detect_by_base_keyword="1234",
|
||||||
default_api_base="http://localhost:1234/v1",
|
default_api_base="http://localhost:1234/v1",
|
||||||
),
|
),
|
||||||
|
# Atomic Chat (local, OpenAI-compatible) — https://atomic.chat/
|
||||||
|
ProviderSpec(
|
||||||
|
name="atomic_chat",
|
||||||
|
keywords=("atomic-chat", "atomic_chat", "atomicchat"),
|
||||||
|
env_key="ATOMIC_CHAT_API_KEY",
|
||||||
|
display_name="Atomic Chat",
|
||||||
|
backend="openai_compat",
|
||||||
|
is_local=True,
|
||||||
|
detect_by_base_keyword="1337",
|
||||||
|
default_api_base="http://localhost:1337/v1",
|
||||||
|
),
|
||||||
# === OpenVINO Model Server (direct, local, OpenAI-compatible at /v3) ===
|
# === OpenVINO Model Server (direct, local, OpenAI-compatible at /v3) ===
|
||||||
ProviderSpec(
|
ProviderSpec(
|
||||||
name="ovms",
|
name="ovms",
|
||||||
|
|||||||
@ -371,6 +371,28 @@ def test_config_accepts_lm_studio_without_api_key_and_uses_default_localhost_api
|
|||||||
assert config.get_api_base() == "http://localhost:1234/v1"
|
assert config.get_api_base() == "http://localhost:1234/v1"
|
||||||
|
|
||||||
|
|
||||||
|
def test_config_accepts_atomic_chat_without_api_key_and_uses_default_localhost_api_base():
|
||||||
|
config = Config.model_validate(
|
||||||
|
{
|
||||||
|
"agents": {
|
||||||
|
"defaults": {
|
||||||
|
"provider": "atomic_chat",
|
||||||
|
"model": "local-model",
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"providers": {
|
||||||
|
"atomicChat": {
|
||||||
|
"apiKey": None,
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
assert config.get_provider_name() == "atomic_chat"
|
||||||
|
assert config.get_api_key() is None
|
||||||
|
assert config.get_api_base() == "http://localhost:1337/v1"
|
||||||
|
|
||||||
|
|
||||||
def test_find_by_name_accepts_camel_case_and_hyphen_aliases():
|
def test_find_by_name_accepts_camel_case_and_hyphen_aliases():
|
||||||
assert find_by_name("volcengineCodingPlan") is not None
|
assert find_by_name("volcengineCodingPlan") is not None
|
||||||
assert find_by_name("volcengineCodingPlan").name == "volcengine_coding_plan"
|
assert find_by_name("volcengineCodingPlan").name == "volcengine_coding_plan"
|
||||||
@ -378,6 +400,8 @@ def test_find_by_name_accepts_camel_case_and_hyphen_aliases():
|
|||||||
assert find_by_name("github-copilot").name == "github_copilot"
|
assert find_by_name("github-copilot").name == "github_copilot"
|
||||||
assert find_by_name("longcat") is not None
|
assert find_by_name("longcat") is not None
|
||||||
assert find_by_name("longcat").name == "longcat"
|
assert find_by_name("longcat").name == "longcat"
|
||||||
|
assert find_by_name("atomic-chat") is not None
|
||||||
|
assert find_by_name("atomic-chat").name == "atomic_chat"
|
||||||
|
|
||||||
|
|
||||||
def test_config_explicit_longcat_provider_resolves_provider_name():
|
def test_config_explicit_longcat_provider_resolves_provider_name():
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user