Skip to content
Open
Show file tree
Hide file tree
Changes from 9 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion .env.example
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
# API Keys - At least one is required
#
# IMPORTANT: Choose ONE approach:
# - Native APIs (Gemini/OpenAI/XAI) for direct access
# - Native APIs (Gemini/OpenAI/XAI/ZAI) for direct access
# - DIAL for unified enterprise access
# - OpenRouter for unified cloud access
# Having multiple unified providers creates ambiguity about which serves each model.
Expand All @@ -29,6 +29,9 @@ AZURE_OPENAI_ENDPOINT=https://your-resource.openai.azure.com/
# Get your X.AI API key from: https://console.x.ai/
XAI_API_KEY=your_xai_api_key_here

# Get your Z.AI API key from: https://z.ai/manage-apikey/apikey-list
ZAI_API_KEY=your_zai_api_key_here
Comment thread
petems marked this conversation as resolved.
Comment thread
petems marked this conversation as resolved.

# Get your DIAL API key and configure host URL
# DIAL provides unified access to multiple AI models through a single API
DIAL_API_KEY=your_dial_api_key_here
Expand Down Expand Up @@ -105,6 +108,12 @@ DEFAULT_THINKING_MODE_THINKDEEP=high
# - grok3 (shorthand for grok-3)
# - grokfast (shorthand for grok-3-fast)
#
# Supported Z.AI GLM models:
# - glm-4.6 (200K context, reasoning/coding)
# - glm (shorthand for glm-4.6)
# - glm-4 (shorthand for glm-4.6)
# - glm4.6 (shorthand for glm-4.6)
#
# Supported DIAL models (when available in your DIAL deployment):
# - o3-2025-04-16 (200K context, latest O3 release)
# - o4-mini-2025-04-16 (200K context, latest O4 mini)
Expand Down Expand Up @@ -133,6 +142,7 @@ DEFAULT_THINKING_MODE_THINKDEEP=high
# OPENAI_ALLOWED_MODELS=o4-mini # Single model standardization
# GOOGLE_ALLOWED_MODELS=flash,pro # Allow both Gemini models
# XAI_ALLOWED_MODELS=grok,grok-3-fast # Allow both GROK variants
# ZAI_ALLOWED_MODELS=glm,glm-4.6 # Allow GLM aliases/models
# DIAL_ALLOWED_MODELS=o3,o4-mini # Only allow O3/O4 models via DIAL
# DIAL_ALLOWED_MODELS=opus-4.1,sonnet-4.1 # Only Claude 4.1 models (without thinking)
# DIAL_ALLOWED_MODELS=opus-4.1-thinking,sonnet-4.1-thinking # Only Claude 4.1 with thinking mode
Expand All @@ -142,6 +152,7 @@ DEFAULT_THINKING_MODE_THINKDEEP=high
# OPENAI_ALLOWED_MODELS=
# GOOGLE_ALLOWED_MODELS=
# XAI_ALLOWED_MODELS=
# ZAI_ALLOWED_MODELS=
# DIAL_ALLOWED_MODELS=

# Optional: Custom model configuration file path
Expand Down
5 changes: 3 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
[Claude Code](https://www.anthropic.com/claude-code) · [Gemini CLI](https://github.com/google-gemini/gemini-cli) · [Codex CLI](https://github.com/openai/codex) · [Qwen Code CLI](https://qwenlm.github.io/qwen-code-docs/) · [Cursor](https://cursor.com) · _and more_

**With multiple models within a single prompt:**
Gemini · OpenAI · Anthropic · Grok · Azure · Ollama · OpenRouter · DIAL · On-Device Model
Gemini · OpenAI · Anthropic · Grok · GLM · Azure · Ollama · OpenRouter · DIAL · On-Device Model

</div>

Expand Down Expand Up @@ -150,6 +150,7 @@ For best results when using [Codex CLI](https://developers.openai.com/codex/cli)
- **[OpenAI](https://platform.openai.com/api-keys)** - O3, GPT-5 series
- **[Azure OpenAI](https://learn.microsoft.com/azure/ai-services/openai/)** - Enterprise deployments of GPT-4o, GPT-4.1, GPT-5 family
- **[X.AI](https://console.x.ai/)** - Grok models
- **[Z.AI](https://z.ai/manage-apikey/apikey-list)** - GLM models
- **[DIAL](https://dialx.ai/)** - Vendor-agnostic model access
- **[Ollama](https://ollama.ai/)** - Local models (free)

Expand Down Expand Up @@ -381,7 +382,7 @@ DISABLED_TOOLS=
- **[Context revival](docs/context-revival.md)** - Continue conversations even after context resets

**Model Support**
- **Multiple providers** - Gemini, OpenAI, Azure, X.AI, OpenRouter, DIAL, Ollama
- **Multiple providers** - Gemini, OpenAI, Azure, X.AI, Z.AI, OpenRouter, DIAL, Ollama
- **Latest models** - GPT-5, Gemini 3.0 Pro, O3, Grok-4, local Llama
- **[Thinking modes](docs/advanced-usage.md#thinking-modes)** - Control reasoning depth vs cost
- **Vision support** - Analyze images, diagrams, screenshots
Expand Down
56 changes: 56 additions & 0 deletions conf/zai_models.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
{
"_README": {
"description": "Model metadata for Z.AI GLM API access.",
"documentation": "https://github.com/BeehiveInnovations/pal-mcp-server/blob/main/docs/custom_models.md",
"usage": "Models listed here are exposed directly through the Z.AI provider. Aliases are case-insensitive.",
"field_notes": "Matches providers/shared/model_capabilities.py.",
"field_descriptions": {
"model_name": "The model identifier (e.g., 'glm-4.6')",
"aliases": "Array of short names users can type instead of the full model name",
"context_window": "Total number of tokens the model can process (input + output combined)",
"max_output_tokens": "Maximum number of tokens the model can generate in a single response",
"supports_extended_thinking": "Whether the model supports extended reasoning tokens",
"supports_json_mode": "Whether the model can guarantee valid JSON output",
"supports_function_calling": "Whether the model supports function/tool calling",
"supports_images": "Whether the model can process images/visual input",
"supports_temperature": "Whether the model accepts temperature parameter in API calls",
"temperature_constraint": "Temperature constraint object. Z.AI chat completions require temperature in [0.0, 1.0].",
"description": "Human-readable description of the model",
"intelligence_score": "1-20 human rating used as the primary signal for auto-mode model ordering"
},
"verification_sources": {
"model_overview": "https://docs.z.ai/guides/llm/glm-4.6",
"api_reference": "https://docs.z.ai/api-reference/llm/chat-completion",
"announcement": "https://z.ai/blog/glm-4.6"
}
},
"models": [
{
"model_name": "glm-4.6",
"friendly_name": "Z.AI (GLM-4.6)",
"aliases": [
"glm",
"glm-4",
"glm4.6",
"glm-4.6"
],
"intelligence_score": 12,
"description": "GLM-4.6 (200K context) - Z.AI reasoning and coding model",
"context_window": 200000,
"max_output_tokens": 128000,
"supports_extended_thinking": true,
"supports_system_prompts": true,
"supports_streaming": true,
"supports_function_calling": true,
"supports_json_mode": true,
"supports_images": false,
"supports_temperature": true,
"temperature_constraint": {
"type": "range",
"min": 0.0,
"max": 1.0,
"default": 1.0
}
}
]
}
1 change: 1 addition & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ services:
- OPENAI_API_KEY=${OPENAI_API_KEY}
- ANTHROPIC_API_KEY=${ANTHROPIC_API_KEY}
- XAI_API_KEY=${XAI_API_KEY}
- ZAI_API_KEY=${ZAI_API_KEY}
- DIAL_API_KEY=${DIAL_API_KEY}
- DIAL_API_HOST=${DIAL_API_HOST}
- DIAL_API_VERSION=${DIAL_API_VERSION}
Expand Down
5 changes: 3 additions & 2 deletions docker/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
### 1. Prerequisites

- Docker installed (Docker Compose optional)
- At least one API key (Gemini, OpenAI, xAI, etc.)
- At least one API key (Gemini, OpenAI, X.AI, Z.AI, etc.)

### 2. Configuration

Expand All @@ -14,7 +14,7 @@
cp .env.example .env

# Edit with your API keys (at least one required)
# Required: GEMINI_API_KEY or OPENAI_API_KEY or XAI_API_KEY
# Required: GEMINI_API_KEY or OPENAI_API_KEY or XAI_API_KEY or ZAI_API_KEY
nano .env
```

Expand Down Expand Up @@ -293,6 +293,7 @@ DEFAULT_THINKING_MODE_THINKDEEP=high
# Optional API keys (leave empty if not used)
ANTHROPIC_API_KEY=
XAI_API_KEY=
ZAI_API_KEY=
DIAL_API_KEY=
OPENROUTER_API_KEY=
CUSTOM_API_URL=
Expand Down
1 change: 1 addition & 0 deletions docker/scripts/deploy.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ function Test-EnvironmentVariables {
"GOOGLE_API_KEY",
"OPENAI_API_KEY",
"XAI_API_KEY",
"ZAI_API_KEY",
"DIAL_API_KEY",
"OPENROUTER_API_KEY"
)
Expand Down
2 changes: 1 addition & 1 deletion docker/scripts/deploy.sh
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ echo -e "${GREEN}=== Deploying PAL MCP Server ===${NC}"
# Function to check if required environment variables are set
check_env_vars() {
# At least one of these API keys must be set
local required_vars=("GEMINI_API_KEY" "GOOGLE_API_KEY" "OPENAI_API_KEY" "XAI_API_KEY" "DIAL_API_KEY" "OPENROUTER_API_KEY")
local required_vars=("GEMINI_API_KEY" "GOOGLE_API_KEY" "OPENAI_API_KEY" "XAI_API_KEY" "ZAI_API_KEY" "DIAL_API_KEY" "OPENROUTER_API_KEY")

local has_api_key=false
for var in "${required_vars[@]}"; do
Expand Down
1 change: 1 addition & 0 deletions docker/scripts/healthcheck.py
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ def check_environment():
"GOOGLE_API_KEY",
"OPENAI_API_KEY",
"XAI_API_KEY",
"ZAI_API_KEY",
"DIAL_API_KEY",
"OPENROUTER_API_KEY",
]
Expand Down
2 changes: 2 additions & 0 deletions docs/advanced-usage.md
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ Regardless of your default configuration, you can specify models per request:
| **`gpt5-nano`** (GPT-5 Nano) | OpenAI | 400K tokens | Fastest, cheapest GPT-5 variant | Summarization and classification tasks |
| **`grok-4`** | X.AI | 256K tokens | Latest flagship Grok model with reasoning, vision | Complex analysis, reasoning tasks |
| **`grok-4.1-fast-reasoning`** | X.AI | 2M tokens | High-performance Grok 4.1 Fast Reasoning with vision | Fast responses and light reasoning |
| **`glm-4.6`** | Z.AI | 200K tokens | GLM flagship model with extended thinking | Advanced reasoning and coding workflows |
| **`llama`** (Llama 3.2) | Custom/Local | 128K tokens | Local inference, privacy | On-device analysis, cost-free processing |
| **Any model** | OpenRouter | Varies | Access to GPT-4, Claude, Llama, etc. | User-specified or based on task requirements |

Expand All @@ -72,6 +73,7 @@ cloud models (expensive/powerful) AND local models (free/private) in the same co
- **GPT-5 Mini**: Balanced efficiency and capability
- **GPT-5 Nano**: Optimized for fast, low-cost tasks
- **Grok-4 / Grok-4.1-fast-reasoning**: Extended thinking support, vision capabilities (256K / 2M context)
- **GLM-4.6**: Z.AI flagship model with extended thinking support (200K context)

## Model Usage Restrictions

Expand Down
11 changes: 11 additions & 0 deletions docs/configuration.md
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@ OPENAI_API_KEY=your_openai_api_key_here
# X.AI GROK API
XAI_API_KEY=your_xai_api_key_here
# Get from: https://console.x.ai/

# Z.AI GLM API
ZAI_API_KEY=your_zai_api_key_here
# Get from: https://z.ai/manage-apikey/apikey-list
```

**Option 2: OpenRouter (Access multiple models through one API)**
Expand Down Expand Up @@ -71,6 +75,7 @@ DEFAULT_MODEL=auto # Claude picks best model for each task (recommended)
- `conf/openai_models.json` – OpenAI catalogue (can be overridden with `OPENAI_MODELS_CONFIG_PATH`)
- `conf/gemini_models.json` – Gemini catalogue (`GEMINI_MODELS_CONFIG_PATH`)
- `conf/xai_models.json` – X.AI / GROK catalogue (`XAI_MODELS_CONFIG_PATH`)
- `conf/zai_models.json` – Z.AI / GLM catalogue (`ZAI_MODELS_CONFIG_PATH`)
- `conf/openrouter_models.json` – OpenRouter catalogue (`OPENROUTER_MODELS_CONFIG_PATH`)
- `conf/dial_models.json` – DIAL aggregation catalogue (`DIAL_MODELS_CONFIG_PATH`)
- `conf/custom_models.json` – Custom/OpenAI-compatible endpoints (`CUSTOM_MODELS_CONFIG_PATH`)
Expand All @@ -84,6 +89,7 @@ DEFAULT_MODEL=auto # Claude picks best model for each task (recommended)
| OpenAI | `gpt-5.2`, `gpt-5.1-codex`, `gpt-5.1-codex-mini`, `gpt-5`, `gpt-5.2-pro`, `gpt-5-mini`, `gpt-5-nano`, `gpt-5-codex`, `gpt-4.1`, `o3`, `o3-mini`, `o3-pro`, `o4-mini` | `gpt5.2`, `gpt-5.2`, `5.2`, `gpt5.1-codex`, `codex-5.1`, `codex-mini`, `gpt5`, `gpt5pro`, `mini`, `nano`, `codex`, `o3mini`, `o3pro`, `o4mini` |
| Gemini | `gemini-2.5-pro`, `gemini-2.5-flash`, `gemini-2.0-flash`, `gemini-2.0-flash-lite` | `pro`, `gemini-pro`, `flash`, `flash-2.0`, `flashlite` |
| X.AI | `grok-4`, `grok-4.1-fast` | `grok`, `grok4`, `grok-4.1-fast-reasoning` |
| Z.AI | `glm-4.6` | `glm`, `glm-4`, `glm4.6` |
| OpenRouter | See `conf/openrouter_models.json` for the continually evolving catalogue | e.g., `opus`, `sonnet`, `flash`, `pro`, `mistral` |
| Custom | User-managed entries such as `llama3.2` | Define your own aliases per entry |

Expand Down Expand Up @@ -181,6 +187,9 @@ GOOGLE_ALLOWED_MODELS=flash,pro
# X.AI GROK model restrictions
XAI_ALLOWED_MODELS=grok-4,grok-4.1-fast-reasoning

# Z.AI GLM model restrictions
ZAI_ALLOWED_MODELS=glm-4.6

# OpenRouter model restrictions (affects models via custom provider)
OPENROUTER_ALLOWED_MODELS=opus,sonnet,mistral
```
Expand Down Expand Up @@ -209,6 +218,7 @@ GOOGLE_ALLOWED_MODELS=pro
GOOGLE_ALLOWED_MODELS=flash,pro
OPENAI_ALLOWED_MODELS=gpt-5.1-codex-mini,gpt-5-mini,o4-mini
XAI_ALLOWED_MODELS=grok,grok-4.1-fast-reasoning
ZAI_ALLOWED_MODELS=glm-4.6
```

### Advanced Configuration
Expand All @@ -219,6 +229,7 @@ XAI_ALLOWED_MODELS=grok,grok-4.1-fast-reasoning
OPENAI_MODELS_CONFIG_PATH=/path/to/openai_models.json
GEMINI_MODELS_CONFIG_PATH=/path/to/gemini_models.json
XAI_MODELS_CONFIG_PATH=/path/to/xai_models.json
ZAI_MODELS_CONFIG_PATH=/path/to/zai_models.json
OPENROUTER_MODELS_CONFIG_PATH=/path/to/openrouter_models.json
DIAL_MODELS_CONFIG_PATH=/path/to/dial_models.json
CUSTOM_MODELS_CONFIG_PATH=/path/to/custom_models.json
Expand Down
1 change: 1 addition & 0 deletions docs/custom_models.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ PAL ships multiple registries:
- `conf/openai_models.json` – native OpenAI catalogue (override with `OPENAI_MODELS_CONFIG_PATH`)
- `conf/gemini_models.json` – native Google Gemini catalogue (`GEMINI_MODELS_CONFIG_PATH`)
- `conf/xai_models.json` – native X.AI / GROK catalogue (`XAI_MODELS_CONFIG_PATH`)
- `conf/zai_models.json` – native Z.AI / GLM catalogue (`ZAI_MODELS_CONFIG_PATH`)
- `conf/openrouter_models.json` – OpenRouter catalogue (`OPENROUTER_MODELS_CONFIG_PATH`)
- `conf/dial_models.json` – DIAL aggregation catalogue (`DIAL_MODELS_CONFIG_PATH`)
- `conf/custom_models.json` – local/self-hosted OpenAI-compatible catalogue (`CUSTOM_MODELS_CONFIG_PATH`)
Expand Down
5 changes: 4 additions & 1 deletion docs/docker-deployment.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ OPENAI_API_KEY=your_openai_api_key_here
# X.AI GROK
XAI_API_KEY=your_xai_api_key_here

# Z.AI GLM
ZAI_API_KEY=your_zai_api_key_here

# OpenRouter (unified access)
OPENROUTER_API_KEY=your_openrouter_api_key_here

Expand Down Expand Up @@ -252,7 +255,7 @@ cat .env
**4. API key validation errors:**
```bash
# Check environment variables in container
docker exec pal-mcp-server env | grep -E "(GEMINI|OPENAI|XAI)"
docker exec pal-mcp-server env | grep -E "(GEMINI|OPENAI|XAI|ZAI)"
```

### Debug Mode
Expand Down
5 changes: 5 additions & 0 deletions docs/getting-started.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,10 @@ You need at least one API key. Choose based on your needs:
- Visit [X.AI Console](https://console.x.ai/)
- Generate an API key for Grok models

**Z.AI (GLM):**
- Visit [Z.AI API Keys](https://z.ai/manage-apikey/apikey-list)
- Generate an API key for GLM-4.6 models

**DIAL Platform:**
- Visit [DIAL Platform](https://dialx.ai/)
- Generate API key for vendor-agnostic model access
Expand Down Expand Up @@ -289,6 +293,7 @@ Add your API keys (at least one required):
GEMINI_API_KEY=your-gemini-api-key-here # For Gemini models
OPENAI_API_KEY=your-openai-api-key-here # For GPT-5.2, GPT-5.1-Codex, O3
XAI_API_KEY=your-xai-api-key-here # For Grok models
ZAI_API_KEY=your-zai-api-key-here # For GLM models
OPENROUTER_API_KEY=your-openrouter-key # For multiple models

# DIAL Platform (optional)
Expand Down
2 changes: 2 additions & 0 deletions providers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
from .openrouter import OpenRouterProvider
from .registry import ModelProviderRegistry
from .shared import ModelCapabilities, ModelResponse
from .zai import ZAIModelProvider

__all__ = [
"ModelProvider",
Expand All @@ -19,4 +20,5 @@
"OpenAIModelProvider",
"OpenAICompatibleProvider",
"OpenRouterProvider",
"ZAIModelProvider",
]
2 changes: 1 addition & 1 deletion providers/openai_compatible.py
Original file line number Diff line number Diff line change
Expand Up @@ -603,7 +603,7 @@ def generate_content(
# Add any additional OpenAI-specific parameters
# Use capabilities to filter parameters for reasoning models
for key, value in kwargs.items():
if key in ["top_p", "frequency_penalty", "presence_penalty", "seed", "stop", "stream"]:
if key in ["top_p", "frequency_penalty", "presence_penalty", "seed", "stop", "stream", "extra_body"]:
# Reasoning models (those that don't support temperature) also don't support these parameters
if not supports_sampling and key in ["top_p", "frequency_penalty", "presence_penalty", "stream"]:
continue # Skip unsupported parameters for reasoning models
Expand Down
2 changes: 2 additions & 0 deletions providers/registries/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
from .openai import OpenAIModelRegistry
from .openrouter import OpenRouterModelRegistry
from .xai import XAIModelRegistry
from .zai import ZAIModelRegistry

__all__ = [
"AzureModelRegistry",
Expand All @@ -16,4 +17,5 @@
"OpenAIModelRegistry",
"OpenRouterModelRegistry",
"XAIModelRegistry",
"ZAIModelRegistry",
]
15 changes: 14 additions & 1 deletion providers/registries/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
from utils.env import get_env
from utils.file_utils import read_json_file

from ..shared import ModelCapabilities, ProviderType, TemperatureConstraint
from ..shared import ModelCapabilities, ProviderType, RangeTemperatureConstraint, TemperatureConstraint

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -158,6 +158,8 @@ def _convert_entry(self, raw: dict) -> ModelCapabilities | None:
temperature_hint = entry.get("temperature_constraint")
if isinstance(temperature_hint, str):
entry["temperature_constraint"] = TemperatureConstraint.create(temperature_hint)
elif isinstance(temperature_hint, dict):
entry["temperature_constraint"] = self._convert_temperature_constraint(temperature_hint)
elif temperature_hint is None:
entry["temperature_constraint"] = TemperatureConstraint.create("range")

Expand All @@ -178,6 +180,17 @@ def _convert_entry(self, raw: dict) -> ModelCapabilities | None:
def _default_friendly_name(self, model_name: str) -> str:
return model_name

def _convert_temperature_constraint(self, raw: dict) -> TemperatureConstraint:
constraint_type = raw.get("type", "range")
if constraint_type == "range":
return RangeTemperatureConstraint(
float(raw.get("min", 0.0)),
float(raw.get("max", 2.0)),
float(raw.get("default", 0.3)),
)

return TemperatureConstraint.create(constraint_type)

def _extra_keys(self) -> set[str]:
return set()

Expand Down
19 changes: 19 additions & 0 deletions providers/registries/zai.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
"""Registry loader for Z.AI model capabilities."""

from __future__ import annotations

from ..shared import ProviderType
from .base import CapabilityModelRegistry


class ZAIModelRegistry(CapabilityModelRegistry):
"""Capability registry backed by ``conf/zai_models.json``."""

def __init__(self, config_path: str | None = None) -> None:
super().__init__(
env_var_name="ZAI_MODELS_CONFIG_PATH",
default_filename="zai_models.json",
provider=ProviderType.ZAI,
friendly_prefix="Z.AI ({model})",
config_path=config_path,
)
Loading
Loading