diff --git a/docs/my-website/docs/providers/openclaw.md b/docs/my-website/docs/providers/openclaw.md new file mode 100644 index 00000000000..7f2cb418110 --- /dev/null +++ b/docs/my-website/docs/providers/openclaw.md @@ -0,0 +1,186 @@ +import Tabs from '@theme/Tabs'; +import TabItem from '@theme/TabItem'; + +# OpenClaw + +[OpenClaw](https://openclaw.ai) is an AI agent framework that exposes an OpenAI-compatible HTTP endpoint. It allows you to interact with AI agents that have access to tools, memory, and custom configurations. + +## Key Features + +- **Agent Targeting**: Route requests to specific agents via the model field (`openclaw/main`, `openclaw/research`) +- **Session Persistence**: Maintain conversation context across requests using the `user` field +- **Full Tool Access**: Agents can execute code, browse the web, manage files, and more +- **Streaming Support**: Real-time SSE streaming responses + +## Quick Start + +```python +import litellm + +response = litellm.completion( + model="openclaw/main", # Target the 'main' agent + api_base="http://localhost:18789", + api_key="your-gateway-token", + messages=[{"role": "user", "content": "Hello!"}] +) +print(response.choices[0].message.content) +``` + +## Environment Variables + +```bash +export OPENCLAW_API_BASE="http://localhost:18789" # Gateway URL +export OPENCLAW_API_KEY="your-gateway-token" # Auth token +``` + +## Usage + +### SDK Usage + + + + +```python +import litellm + +# Basic completion +response = litellm.completion( + model="openclaw/main", + messages=[{"role": "user", "content": "What can you do?"}] +) + +# Streaming +response = litellm.completion( + model="openclaw/main", + messages=[{"role": "user", "content": "Tell me a story"}], + stream=True +) +for chunk in response: + print(chunk.choices[0].delta.content or "", end="") + +# With session persistence (same user = same conversation) +response = litellm.completion( + model="openclaw/main", + messages=[{"role": "user", "content": "Remember my name is Alice"}], + user="alice-session-123" +) +``` + + + + +1. Add to your `config.yaml`: + +```yaml +model_list: + - model_name: openclaw-main + litellm_params: + model: openclaw/main + api_base: http://localhost:18789 + api_key: os.environ/OPENCLAW_API_KEY + + - model_name: openclaw-research + litellm_params: + model: openclaw/research + api_base: http://localhost:18789 + api_key: os.environ/OPENCLAW_API_KEY +``` + +2. Start the proxy: + +```bash +litellm --config config.yaml +``` + +3. Make requests: + +```bash +curl http://localhost:4000/v1/chat/completions \ + -H "Content-Type: application/json" \ + -H "Authorization: Bearer sk-1234" \ + -d '{ + "model": "openclaw-main", + "messages": [{"role": "user", "content": "Hello!"}] + }' +``` + + + + +## Targeting Different Agents + +OpenClaw can run multiple agents with different configurations. Target them via the model field: + +```python +# Main agent (default) +litellm.completion(model="openclaw/main", ...) + +# Research agent with web search tools +litellm.completion(model="openclaw/research", ...) + +# Custom agent +litellm.completion(model="openclaw/my-custom-agent", ...) +``` + +## Supported Parameters + +| Parameter | Type | Description | +|-----------|------|-------------| +| `model` | string | Agent to target: `openclaw/` | +| `messages` | array | Conversation messages | +| `stream` | boolean | Enable SSE streaming | +| `temperature` | float | Sampling temperature | +| `max_tokens` | integer | Maximum tokens to generate | +| `user` | string | Session key for conversation persistence | +| `tools` | array | Tool definitions (agents have built-in tools) | +| `tool_choice` | string/object | Tool selection preference | + +## OpenClaw Setup + +To use OpenClaw with LiteLLM: + +1. Install and start OpenClaw: +```bash +npm install -g openclaw +openclaw gateway +``` + +2. Enable the HTTP endpoint in your OpenClaw config: +```json +{ + "gateway": { + "http": { + "endpoints": { + "chatCompletions": { "enabled": true } + } + } + } +} +``` + +3. Configure authentication (optional but recommended): +```bash +export OPENCLAW_GATEWAY_TOKEN="your-secure-token" +``` + +For more details, see the [OpenClaw documentation](https://docs.openclaw.ai). + +## Troubleshooting + +### Connection Refused +Ensure the OpenClaw gateway is running and the API base URL is correct: +```bash +curl http://localhost:18789/health +``` + +### Authentication Failed +Verify your gateway token matches the one configured in OpenClaw: +```bash +openclaw gateway status +``` + +### Agent Not Found +Check available agents: +```bash +openclaw agents list +``` diff --git a/litellm/__init__.py b/litellm/__init__.py index a74a79635f0..56e6eb0c614 100644 --- a/litellm/__init__.py +++ b/litellm/__init__.py @@ -1426,6 +1426,7 @@ if TYPE_CHECKING: from .llms.llamafile.chat.transformation import LlamafileChatConfig as _LlamafileChatConfig from .llms.lm_studio.chat.transformation import LMStudioChatConfig as _LMStudioChatConfig from .llms.lm_studio.embed.transformation import LmStudioEmbeddingConfig as _LmStudioEmbeddingConfig + from .llms.openclaw.chat.transformation import OpenClawChatConfig as _OpenClawChatConfig from .llms.watsonx.embed.transformation import IBMWatsonXEmbeddingConfig as _IBMWatsonXEmbeddingConfig from .llms.vertex_ai.gemini.vertex_and_google_ai_studio_gemini import VertexGeminiConfig as _VertexGeminiConfig @@ -1444,6 +1445,7 @@ if TYPE_CHECKING: LlamafileChatConfig: Type[_LlamafileChatConfig] LMStudioChatConfig: Type[_LMStudioChatConfig] LmStudioEmbeddingConfig: Type[_LmStudioEmbeddingConfig] + OpenClawChatConfig: Type[_OpenClawChatConfig] IBMWatsonXEmbeddingConfig: Type[_IBMWatsonXEmbeddingConfig] VertexAIConfig: Type[_VertexGeminiConfig] # Alias for VertexGeminiConfig diff --git a/litellm/_lazy_imports_registry.py b/litellm/_lazy_imports_registry.py index 0e52e9a59eb..126f517089a 100644 --- a/litellm/_lazy_imports_registry.py +++ b/litellm/_lazy_imports_registry.py @@ -1022,6 +1022,7 @@ _LLM_CONFIGS_IMPORT_MAP = { "VLLMConfig": (".llms.vllm.completion.transformation", "VLLMConfig"), "DeepSeekChatConfig": (".llms.deepseek.chat.transformation", "DeepSeekChatConfig"), "LMStudioChatConfig": (".llms.lm_studio.chat.transformation", "LMStudioChatConfig"), + "OpenClawChatConfig": (".llms.openclaw.chat.transformation", "OpenClawChatConfig"), "LmStudioEmbeddingConfig": ( ".llms.lm_studio.embed.transformation", "LmStudioEmbeddingConfig", diff --git a/litellm/constants.py b/litellm/constants.py index 3c84547d7ce..1435731041a 100644 --- a/litellm/constants.py +++ b/litellm/constants.py @@ -415,6 +415,7 @@ LITELLM_CHAT_PROVIDERS = [ "hosted_vllm", "llamafile", "lm_studio", + "openclaw", "galadriel", "gradient_ai", "github_copilot", # GitHub Copilot Chat API @@ -619,6 +620,7 @@ openai_compatible_providers: List = [ "hosted_vllm", "llamafile", "lm_studio", + "openclaw", "galadriel", "github_copilot", # GitHub Copilot Chat API "chatgpt", # ChatGPT subscription API diff --git a/litellm/llms/openclaw/chat/transformation.py b/litellm/llms/openclaw/chat/transformation.py new file mode 100644 index 00000000000..e0f442d72a5 --- /dev/null +++ b/litellm/llms/openclaw/chat/transformation.py @@ -0,0 +1,83 @@ +""" +Translate from OpenAI's `/v1/chat/completions` to OpenClaw's `/v1/chat/completions` + +OpenClaw is an AI agent framework that exposes an OpenAI-compatible HTTP endpoint. +https://docs.openclaw.ai + +Key features: +- Target specific agents via model field: `openclaw/main`, `openclaw/research` +- Session persistence via `user` field +- Streaming support (SSE) +""" + +from typing import List, Optional, Tuple + +from litellm.secret_managers.main import get_secret_str + +from ...openai.chat.gpt_transformation import OpenAIGPTConfig + + +class OpenClawChatConfig(OpenAIGPTConfig): + """ + OpenClaw configuration for chat completions. + + OpenClaw agents are targeted via the model field: + - `openclaw/main` -> main agent + - `openclaw/research` -> research agent + - `openclaw/` -> any configured agent + + Environment variables: + - OPENCLAW_API_BASE: Gateway URL (e.g., http://localhost:18789) + - OPENCLAW_API_KEY: Gateway auth token + """ + + def get_supported_openai_params(self, model: str) -> List[str]: + """OpenClaw supports standard OpenAI params plus user for session persistence.""" + return [ + "stream", + "stop", + "temperature", + "top_p", + "max_tokens", + "max_completion_tokens", + "presence_penalty", + "frequency_penalty", + "logit_bias", + "user", # Used for session key derivation + "n", + "tools", + "tool_choice", + "response_format", + ] + + def _get_openai_compatible_provider_info( + self, api_base: Optional[str], api_key: Optional[str] + ) -> Tuple[Optional[str], Optional[str]]: + """ + Get OpenClaw API base and key from environment or parameters. + + OpenClaw requires an auth token when gateway.auth.mode is set. + """ + api_base = api_base or get_secret_str("OPENCLAW_API_BASE") + dynamic_api_key = api_key or get_secret_str("OPENCLAW_API_KEY") or "" + return api_base, dynamic_api_key + + def map_openai_params( + self, + non_default_params: dict, + optional_params: dict, + model: str, + drop_params: bool, + ) -> dict: + """ + Map OpenAI params to OpenClaw format. + + OpenClaw is fully OpenAI-compatible, so minimal transformation needed. + The model field can include agent targeting: openclaw/main -> agent:main + """ + return super().map_openai_params( + non_default_params=non_default_params, + optional_params=optional_params, + model=model, + drop_params=drop_params, + ) diff --git a/litellm/main.py b/litellm/main.py index 13361c644cb..27192781ae7 100644 --- a/litellm/main.py +++ b/litellm/main.py @@ -4813,6 +4813,7 @@ def embedding( # noqa: PLR0915 custom_llm_provider == "openai_like" or custom_llm_provider == "llamafile" or custom_llm_provider == "lm_studio" + or custom_llm_provider == "openclaw" ): api_base = ( api_base or litellm.api_base or get_secret_str("OPENAI_LIKE_API_BASE") diff --git a/litellm/types/utils.py b/litellm/types/utils.py index 6c330d0f83c..4e5e7200513 100644 --- a/litellm/types/utils.py +++ b/litellm/types/utils.py @@ -3107,6 +3107,7 @@ class LlmProviders(str, Enum): POE = "poe" CHUTES = "chutes" XIAOMI_MIMO = "xiaomi_mimo" + OPENCLAW = "openclaw" # Create a set of all provider values for quick lookup diff --git a/litellm/utils.py b/litellm/utils.py index 7c4eec7ba32..42efab6b5ff 100644 --- a/litellm/utils.py +++ b/litellm/utils.py @@ -7832,6 +7832,7 @@ class ProviderConfigManager: LlmProviders.HOSTED_VLLM: (lambda: litellm.HostedVLLMChatConfig(), False), LlmProviders.LLAMAFILE: (lambda: litellm.LlamafileChatConfig(), False), LlmProviders.LM_STUDIO: (lambda: litellm.LMStudioChatConfig(), False), + LlmProviders.OPENCLAW: (lambda: litellm.OpenClawChatConfig(), False), LlmProviders.GALADRIEL: (lambda: litellm.GaladrielChatConfig(), False), LlmProviders.REPLICATE: (lambda: litellm.ReplicateConfig(), False), LlmProviders.HUGGINGFACE: (lambda: litellm.HuggingFaceChatConfig(), False),