diff --git a/all-in-one/clawdbot-integration/plugin/clawdbot.plugin.json b/all-in-one/clawdbot-integration/plugin/clawdbot.plugin.json new file mode 100644 index 0000000..1dca596 --- /dev/null +++ b/all-in-one/clawdbot-integration/plugin/clawdbot.plugin.json @@ -0,0 +1,7 @@ +{ + "id": "higress-ai-gateway", + "name": "Higress AI Gateway", + "description": "Model provider plugin for Higress AI Gateway with auto-routing support", + "providers": ["higress"], + "skills": ["higress-auto-router"] +} diff --git a/all-in-one/clawdbot-integration/plugin/index.ts b/all-in-one/clawdbot-integration/plugin/index.ts new file mode 100644 index 0000000..5ffb8a9 --- /dev/null +++ b/all-in-one/clawdbot-integration/plugin/index.ts @@ -0,0 +1,274 @@ +import { emptyPluginConfigSchema } from "clawdbot/plugin-sdk"; + +const DEFAULT_GATEWAY_URL = "http://localhost:8080"; +const DEFAULT_CONSOLE_URL = "http://localhost:8001"; +const DEFAULT_CONTEXT_WINDOW = 128_000; +const DEFAULT_MAX_TOKENS = 8192; + +// Common models that Higress AI Gateway typically supports +const DEFAULT_MODEL_IDS = [ + // Auto-routing special model + "higress/auto", + // OpenAI models + "gpt-4o", + "gpt-4o-mini", + "gpt-4-turbo", + // Anthropic models + "claude-opus-4.5", + "claude-sonnet-4.5", + "claude-haiku-4.5", + // Qwen models + "qwen-turbo", + "qwen-plus", + "qwen-max", + "qwen-coder", + // DeepSeek models + "deepseek-chat", + "deepseek-coder", + // Other common models + "moonshot-v1-8k", + "glm-4", +] as const; + +function normalizeBaseUrl(value: string): string { + const trimmed = value.trim(); + if (!trimmed) return DEFAULT_GATEWAY_URL; + let normalized = trimmed; + while (normalized.endsWith("/")) normalized = normalized.slice(0, -1); + if (!normalized.endsWith("/v1")) normalized = `${normalized}/v1`; + return normalized; +} + +function validateUrl(value: string): string | undefined { + const normalized = normalizeBaseUrl(value); + try { + new URL(normalized); + } catch { + return "Enter a valid URL"; + } + return undefined; +} + +function parseModelIds(input: string): string[] { + const parsed = input + .split(/[\n,]/) + .map((model) => model.trim()) + .filter(Boolean); + return Array.from(new Set(parsed)); +} + +function buildModelDefinition(modelId: string) { + const isAutoModel = modelId === "higress/auto"; + return { + id: modelId, + name: isAutoModel ? "Higress Auto Router" : modelId, + api: "openai-completions", + reasoning: false, + input: ["text", "image"], + cost: { input: 0, output: 0, cacheRead: 0, cacheWrite: 0 }, + contextWindow: DEFAULT_CONTEXT_WINDOW, + maxTokens: DEFAULT_MAX_TOKENS, + }; +} + +async function testGatewayConnection(gatewayUrl: string): Promise { + try { + const response = await fetch(`${gatewayUrl}/v1/models`, { + method: "GET", + headers: { "Content-Type": "application/json" }, + signal: AbortSignal.timeout(5000), + }); + return response.ok || response.status === 401; // 401 means gateway is up but needs auth + } catch { + return false; + } +} + +async function fetchAvailableModels(consoleUrl: string): Promise { + try { + // Try to get models from Higress Console API + const response = await fetch(`${consoleUrl}/v1/ai/routes`, { + method: "GET", + headers: { "Content-Type": "application/json" }, + signal: AbortSignal.timeout(5000), + }); + if (response.ok) { + const data = (await response.json()) as { data?: { model?: string }[] }; + if (data.data && Array.isArray(data.data)) { + return data.data + .map((route: { model?: string }) => route.model) + .filter((m): m is string => typeof m === "string"); + } + } + } catch { + // Ignore errors, use defaults + } + return []; +} + +const higressPlugin = { + id: "higress-ai-gateway", + name: "Higress AI Gateway", + description: "Model provider plugin for Higress AI Gateway with auto-routing support", + configSchema: emptyPluginConfigSchema(), + register(api) { + api.registerProvider({ + id: "higress", + label: "Higress AI Gateway", + docsPath: "/providers/models", + aliases: ["higress-gateway", "higress-ai"], + auth: [ + { + id: "api-key", + label: "API Key", + hint: "Configure Higress AI Gateway endpoint with optional API key", + kind: "custom", + run: async (ctx) => { + // Step 1: Get Gateway URL + const gatewayUrlInput = await ctx.prompter.text({ + message: "Higress AI Gateway URL", + initialValue: DEFAULT_GATEWAY_URL, + validate: validateUrl, + }); + const gatewayUrl = normalizeBaseUrl(gatewayUrlInput); + + // Step 2: Get Console URL (for auto-router configuration) + const consoleUrlInput = await ctx.prompter.text({ + message: "Higress Console URL (for auto-router config)", + initialValue: DEFAULT_CONSOLE_URL, + validate: validateUrl, + }); + const consoleUrl = normalizeBaseUrl(consoleUrlInput); + + // Step 3: Test connection (create a new spinner) + const spin = ctx.prompter.progress("Testing gateway connection…"); + const isConnected = await testGatewayConnection(gatewayUrl); + if (!isConnected) { + spin.stop("Gateway connection failed"); + await ctx.prompter.note( + [ + "Could not connect to Higress AI Gateway.", + "Make sure the gateway is running and the URL is correct.", + "", + `Tried: ${gatewayUrl}/v1/models`, + ].join("\n"), + "Connection Warning", + ); + } else { + spin.stop("Gateway connected"); + } + + // Step 4: Get API Key (optional for local gateway) + const apiKeyInput = await ctx.prompter.text({ + message: "API Key (leave empty if not required)", + initialValue: "", + }); + const apiKey = apiKeyInput.trim() || "higress-local"; + + // Step 5: Fetch available models (create a new spinner) + const spin2 = ctx.prompter.progress("Fetching available models…"); + const fetchedModels = await fetchAvailableModels(consoleUrl); + const defaultModels = fetchedModels.length > 0 + ? ["higress/auto", ...fetchedModels] + : DEFAULT_MODEL_IDS; + spin2.stop(); + + // Step 6: Let user customize model list + const modelInput = await ctx.prompter.text({ + message: "Model IDs (comma-separated, higress/auto enables auto-routing)", + initialValue: defaultModels.slice(0, 10).join(", "), + validate: (value) => + parseModelIds(value).length > 0 ? undefined : "Enter at least one model id", + }); + + const modelIds = parseModelIds(modelInput); + const hasAutoModel = modelIds.includes("higress/auto"); + + // FIX: Avoid double prefix - if modelId already starts with provider, don't add prefix again + const defaultModelId = hasAutoModel + ? "higress/auto" + : (modelIds[0] ?? "qwen-turbo"); + const defaultModelRef = defaultModelId.startsWith("higress/") + ? defaultModelId + : `higress/${defaultModelId}`; + + // Step 7: Configure default model for auto-routing + let autoRoutingDefaultModel = "qwen-turbo"; + if (hasAutoModel) { + const autoRoutingModelInput = await ctx.prompter.text({ + message: "Default model for auto-routing (when no rule matches)", + initialValue: "qwen-turbo", + }); + autoRoutingDefaultModel = autoRoutingModelInput.trim(); // FIX: Add trim() here + } + + return { + profiles: [ + { + profileId: `higress:${apiKey === "higress-local" ? "local" : "default"}`, + credential: { + type: "token", + provider: "higress", + token: apiKey, + }, + }, + ], + configPatch: { + models: { + providers: { + higress: { + baseUrl: `${gatewayUrl}/v1`, + apiKey: apiKey, + api: "openai-completions", + authHeader: apiKey !== "higress-local", + models: modelIds.map((modelId) => buildModelDefinition(modelId)), + }, + }, + }, + agents: { + defaults: { + models: Object.fromEntries( + modelIds.map((modelId) => { + // FIX: Avoid double prefix - only add provider prefix if not already present + const modelRef = modelId.startsWith("higress/") + ? modelId + : `higress/${modelId}`; + return [modelRef, {}]; + }), + ), + }, + }, + plugins: { + entries: { + "higress-ai-gateway": { + enabled: true, + config: { + gatewayUrl, + consoleUrl, + autoRoutingDefaultModel, + }, + }, + }, + }, + }, + defaultModel: defaultModelRef, + notes: [ + "Higress AI Gateway is now configured as a model provider.", + hasAutoModel + ? `Auto-routing enabled: use model "higress/auto" to route based on message content.` + : "Add 'higress/auto' to models to enable auto-routing.", + `Gateway endpoint: ${gatewayUrl}/v1/chat/completions`, + `Console: ${consoleUrl}`, + "", + "To configure auto-routing rules, use the higress-auto-router skill:", + ' Say: "route to claude-opus-4.5 when solving difficult problems"', + ], + }; + }, + }, + ], + }); + }, +}; + +export default higressPlugin; diff --git a/all-in-one/clawdbot-integration/plugin/package.json b/all-in-one/clawdbot-integration/plugin/package.json new file mode 100644 index 0000000..7c15a41 --- /dev/null +++ b/all-in-one/clawdbot-integration/plugin/package.json @@ -0,0 +1,22 @@ +{ + "name": "@higress/clawdbot-ai-gateway", + "version": "1.0.0", + "description": "Higress AI Gateway model provider plugin for Clawdbot with auto-routing support", + "main": "index.ts", + "clawdbot": { + "extensions": ["./index.ts"] + }, + "keywords": [ + "clawdbot", + "higress", + "ai-gateway", + "model-router", + "auto-routing" + ], + "author": "Higress Team", + "license": "Apache-2.0", + "repository": { + "type": "git", + "url": "https://github.com/higress-group/higress-standalone" + } +} diff --git a/all-in-one/clawdbot-integration/skill/higress-auto-router/SKILL.md b/all-in-one/clawdbot-integration/skill/higress-auto-router/SKILL.md new file mode 100644 index 0000000..7fb580b --- /dev/null +++ b/all-in-one/clawdbot-integration/skill/higress-auto-router/SKILL.md @@ -0,0 +1,263 @@ +# Higress Auto Router SKILL + +Configure automatic model routing based on user's natural language requests. + +## Description + +This skill enables users to configure Higress AI Gateway's model-router plugin through natural language commands. When a user describes their routing preference (e.g., "route to claude-opus-4.5 when solving difficult problems"), this skill will: + +1. Analyze user's request to understand the routing intent +2. Generate appropriate regex patterns that are distinctive and easy to remember +3. Modify model-router configuration file **inside the container** at `/data/wasmplugins/model-router.internal.yaml` +4. Trigger Higress configuration reload (no container restart needed) +5. Confirm the configuration and explain how to trigger the route + +## When to Use + +Use this skill when: +- User wants to configure automatic model routing +- User mentions keywords like "route to", "switch model", "use model when", "auto routing" +- User describes scenarios that should trigger specific models + +## Prerequisites + +- Higress AI Gateway container running +- Container name: `higress-ai-gateway` (default) or user-specified +- Ability to execute `docker exec` commands + +## Configuration Location + +**Inside Container:** `/data/wasmplugins/model-router.internal.yaml` +**Default Container Name:** `higress-ai-gateway` + +## Workflow + +### Step 1: Parse User Intent + +Extract from the user's request: +- **Target model**: The model they want to route to (e.g., `claude-opus-4.5`, `qwen-coder`) +- **Trigger scenario**: When they want this routing to happen (e.g., "difficult problems", "coding tasks") + +### Step 2: Generate Pattern and Trigger Phrase + +Based on the scenario, generate: +- A memorable **trigger phrase** users can use (Chinese and English options) +- A **regex pattern** to match the trigger phrase + +Common mappings: +| Scenario | Trigger Phrases | Pattern | +|----------|-----------------|---------| +| Complex/difficult reasoning | `深入思考`, `deep thinking` | `(?i)^(深入思考|deep thinking)` | +| Coding tasks | `写代码`, `code:`, `coding:` | `(?i)^(写代码|code:|coding:)` | +| Creative writing | `创意写作`, `creative:` | `(?i)^(创意写作|creative:)` | +| Translation | `翻译:`, `translate:` | `(?i)^(翻译:|translate:)` | +| Math problems | `数学题`, `math:` | `(?i)^(数学题|math:)` | +| Image generation | `画图:`, `draw:`, `image:` | `(?i)^(画图:|draw:|image:)` | +| Quick answers | `快速回答`, `quick:` | `(?i)^(快速回答|quick:)` | + +### Step 3: Determine Container Name + +Try to find the Higress container: +1. Default: `higress-ai-gateway` +2. If not found, list running containers and ask user to specify +3. Use `docker ps --filter "name=higress"` to find containers + +### Step 4: Read Existing Configuration + +Read the current `model-router.internal.yaml` file from inside the container: + +```bash +docker exec cat /data/wasmplugins/model-router.internal.yaml +``` + +Example configuration structure: +```yaml +apiVersion: extensions.higress.io/v1alpha1 +kind: WasmPlugin +metadata: + name: model-router.internal + namespace: higress-system +spec: + defaultConfig: + modelToHeader: x-higress-llm-model + autoRouting: + enable: true + defaultModel: qwen-turbo + rules: + - pattern: (?i)^(深入思考|deep thinking) + model: claude-opus-4.5 +``` + +### Step 5: Check for Conflicts + +Before adding a new rule: +- Parse existing rules from config +- Check if the new pattern conflicts with existing ones +- If conflict detected, suggest alternative trigger phrases + +### Step 6: Modify Configuration File Inside Container + +Use `docker exec` to modify the YAML file directly inside the container: + +```bash +# Option 1: Use sed to add rule +docker exec sed -i '/rules:/a\ - pattern: (?i)^(深入思考|deep thinking)\n model: claude-opus-4.5' /data/wasmplugins/model-router.internal.yaml + +# Option 2: Copy file out, modify, copy back (safer) +docker cp :/data/wasmplugins/model-router.internal.yaml /tmp/model-router.yaml +# Edit /tmp/model-router.yaml with new rule +docker cp /tmp/model-router.yaml :/data/wasmplugins/model-router.internal.yaml +``` + +**Recommended approach: Copy out, modify, copy in** for safety and proper YAML formatting. + +**Important:** +- Ensure proper YAML indentation (2 spaces per level) +- Keep existing `modelToHeader` configuration +- Use `(?i)` for case-insensitive patterns +- Use `^` to anchor pattern to message start (prevents false matches) + +### Step 7: Trigger Configuration Reload + +After modifying the configuration, trigger Higress to reload the plugin configuration **without restarting the container**: + +```bash +# Method 1: Touch the configuration file to trigger reload +docker exec touch /data/wasmplugins/model-router.internal.yaml + +# Method 2: Use Higress's configuration reload endpoint (if available) +curl -X POST http://localhost:8001/api/v1/plugins/reload + +# Method 3: Send SIGHUP to the Higress process (if supported) +docker exec kill -HUP 1 +``` + +**Note:** Higress watches configuration files in `/data/wasmplugins/` and automatically reloads when they are modified. The modification itself should trigger a reload. If not, use Method 1 (touch) to ensure the file's timestamp is updated. + +### Step 8: Confirm to User + +After successful configuration, inform the user: + +**Example response:** +``` +✅ 自动路由配置完成! + +已添加规则:当消息以 "深入思考" 或 "deep thinking" 开头时,自动路由到 claude-opus-4.5 模型。 + +配置文件已更新(容器内):/data/wasmplugins/model-router.internal.yaml +配置已自动重载,无需重启容器。 + +使用方式: +- 中文:深入思考 如何优化这段代码的性能? +- English: deep thinking How to optimize this code's performance? + +提示:请确保您的请求中 model 参数设置为 `higress/auto` 才能触发自动路由。 +``` + +## Error Handling + +- **Container not found**: List running containers and ask user to specify the correct container name +- **Pattern conflicts**: Suggest alternative trigger phrases +- **Invalid model name**: List available models from configured providers +- **YAML parsing errors**: Report the issue and suggest reviewing the file manually +- **Permission errors**: Ensure the Docker socket is accessible and the user has necessary permissions + +## Examples + +**User:** 我希望在解决困难问题时路由到claude-opus-4.5的模型 + +**Response:** +``` +已为您配置自动路由规则: + +触发方式:以 "深入思考" 或 "deep thinking" 开头发起请求 +目标模型:claude-opus-4.5 + +配置文件已更新(容器内):/data/wasmplugins/model-router.internal.yaml +配置已自动重载 + +配置已生效。现在您可以这样使用: +- 深入思考 这道算法题应该怎么解? +- deep thinking What's the best architecture for this system? +``` + +**User:** 写代码的时候用qwen-coder + +**Response:** +``` +已为您配置自动路由规则: + +触发方式:以 "写代码" 或 "code:" 开头发起请求 +目标模型:qwen-coder + +配置文件已更新(容器内):/data/wasmplugins/model-router.internal.yaml +配置已自动重载 + +配置已生效。使用示例: +- 写代码 实现一个快速排序算法 +- code: implement a binary search tree in Python +``` + +## Implementation Notes + +When implementing this skill: + +1. **Determine container name**: Use `docker ps` to find the running Higress container +2. **Use docker cp for safety**: Copy the file out, modify with a YAML library, then copy it back +3. **Validate YAML**: Before copying back, validate the YAML syntax +4. **Trigger reload**: Higress automatically watches for file changes in `/data/wasmplugins/` +5. **No restart needed**: Configuration changes are hot-reloaded by Higress +6. **Handle timestamps**: Touch the file after modification to ensure Higress detects the change + +### Example Python Implementation + +```python +import subprocess +import yaml +import tempfile +import os + +CONTAINER_NAME = "higress-ai-gateway" +CONFIG_PATH = "/data/wasmplugins/model-router.internal.yaml" + +def read_container_config(): + result = subprocess.run( + ["docker", "exec", CONTAINER_NAME, "cat", CONFIG_PATH], + capture_output=True, + text=True + ) + return yaml.safe_load(result.stdout) + +def write_container_config(config): + with tempfile.NamedTemporaryFile(mode='w', suffix='.yaml', delete=False) as f: + yaml.dump(config, f, default_flow_style=False) + temp_path = f.name + + # Copy back to container + subprocess.run(["docker", "cp", temp_path, f"{CONTAINER_NAME}:{CONFIG_PATH}"]) + + # Clean up + os.unlink(temp_path) + + # Touch file to trigger reload + subprocess.run(["docker", "exec", CONTAINER_NAME, "touch", CONFIG_PATH]) + +def add_routing_rule(pattern, model): + config = read_container_config() + + # Ensure autoRouting exists + if 'autoRouting' not in config['spec']['defaultConfig']: + config['spec']['defaultConfig']['autoRouting'] = { + 'enable': True, + 'defaultModel': 'qwen-turbo', + 'rules': [] + } + + # Add rule + config['spec']['defaultConfig']['autoRouting']['rules'].append({ + 'pattern': pattern, + 'model': model + }) + + write_container_config(config) +``` diff --git a/all-in-one/get-ai-gateway.sh b/all-in-one/get-ai-gateway.sh index 99ec287..a429ff2 100755 --- a/all-in-one/get-ai-gateway.sh +++ b/all-in-one/get-ai-gateway.sh @@ -41,10 +41,21 @@ KNOWN_COMMANDS=($COMMAND_START, $COMMAND_STOP, $COMMAND_DELETE) cd "$(dirname -- "$0")" ROOT="$(pwd -P)/higress" +SCRIPT_DIR="$(pwd -P)" cd - >/dev/null CONFIGURED_MARK="$ROOT/.configured" +# Clawdbot integration paths +CLAWDBOT_WORKSPACE="$HOME/clawd" +CLAWDBOT_EXTENSIONS_DIR="$HOME/.clawdbot/extensions" +CLAWDBOT_SKILLS_DIR="$CLAWDBOT_WORKSPACE/skills/public" +CLAWDBOT_INTEGRATION_DIR="$SCRIPT_DIR/clawdbot-integration" + +# Auto-routing configuration +ENABLE_AUTO_ROUTING="false" +AUTO_ROUTING_DEFAULT_MODEL="" + initArch() { ARCH=$(uname -m) case $ARCH in @@ -75,6 +86,15 @@ normalizePath() { echo "$(cygpath -m "$1")" } +# Cross-platform sed in-place edit (macOS vs Linux) +sedInPlace() { + if [ "$OS" == "darwin" ]; then + sed -i '' "$@" + else + sed -i "$@" + fi +} + parseArgs() { resetEnv @@ -139,6 +159,170 @@ resetEnv() { LLM_ENVS=() } +# Load saved configuration from config file +loadSavedConfig() { + local CONFIG_FILE="$ROOT/$CONFIG_FILENAME" + if [ -f "$CONFIG_FILE" ]; then + # Read ENABLE_AUTO_ROUTING and AUTO_ROUTING_DEFAULT_MODEL from config + local saved_auto_routing=$(grep "^ENABLE_AUTO_ROUTING=" "$CONFIG_FILE" | cut -d'=' -f2) + local saved_default_model=$(grep "^AUTO_ROUTING_DEFAULT_MODEL=" "$CONFIG_FILE" | cut -d'=' -f2) + if [ -n "$saved_auto_routing" ]; then + ENABLE_AUTO_ROUTING="$saved_auto_routing" + fi + if [ -n "$saved_default_model" ]; then + AUTO_ROUTING_DEFAULT_MODEL="$saved_default_model" + fi + fi +} + +# Check if Clawdbot is installed +checkClawdbot() { + if [ -d "$CLAWDBOT_WORKSPACE" ]; then + return 0 + fi + return 1 +} + +# Generic function to install files to a destination +installFiles() { + local SRC_DIR="$1" + local DEST_DIR="$2" + local NAME="$3" + + if [ ! -d "$SRC_DIR" ]; then + echo "Warning: $NAME source not found at $SRC_DIR" + return 1 + fi + + echo "Installing $NAME..." + + # Create parent directory if not exists + mkdir -p "$(dirname "$DEST_DIR")" + + # Remove existing if present + if [ -d "$DEST_DIR" ]; then + echo "$NAME already exists, updating..." + rm -rf "$DEST_DIR" + fi + + cp -r "$SRC_DIR" "$DEST_DIR" + + echo "✓ $NAME installed at: $DEST_DIR" + return 0 +} + +# Configure Clawdbot integration +configureClawdbotIntegration() { + if ! checkClawdbot; then + return 0 + fi + + echo + echo "=======================================================" + echo " Clawdbot Integration Detected " + echo "=======================================================" + echo + echo "Clawdbot workspace found at: $CLAWDBOT_WORKSPACE" + echo + echo "Higress AI Gateway can integrate with Clawdbot to provide:" + echo " 1. Auto-routing: Automatically route requests to different models" + echo " based on message content (e.g., 'deep thinking' → claude-opus-4.5)" + echo " 2. Model provider: Use Higress as a unified model provider in Clawdbot" + echo + + read -r -u 3 -p "Enable auto-routing feature? (y/N): " enableAutoRouting + case "$enableAutoRouting" in + [yY]|[yY][eE][sS]) + ENABLE_AUTO_ROUTING="true" + + echo + echo "Auto-routing allows you to route requests to different models based on" + echo "keywords in your message. For example:" + echo " - '深入思考 ...' or 'deep thinking ...' → reasoning model" + echo " - '写代码 ...' or 'code: ...' → coding model" + echo + + # Get default model for auto-routing + read -r -u 3 -p "Default model when no routing rule matches (default: qwen-turbo): " defaultModel + if [ -z "$defaultModel" ]; then + AUTO_ROUTING_DEFAULT_MODEL="qwen-turbo" + else + AUTO_ROUTING_DEFAULT_MODEL="$defaultModel" + fi + + echo + echo "You can configure routing rules later using natural language in Clawdbot." + echo "For example, say: 'route to claude-opus-4.5 when solving difficult problems'" + echo + ;; + *) + ENABLE_AUTO_ROUTING="false" + echo "Auto-routing disabled. You can enable it later via Higress Console." + ;; + esac + + # Install Clawdbot plugin and skill using generic function + installFiles "$CLAWDBOT_INTEGRATION_DIR/plugin" "$CLAWDBOT_EXTENSIONS_DIR/higress-ai-gateway" "Higress AI Gateway plugin" + installFiles "$CLAWDBOT_INTEGRATION_DIR/skill/higress-auto-router" "$CLAWDBOT_SKILLS_DIR/higress-auto-router" "Higress Auto Router skill" + + echo + echo "To complete Clawdbot setup, run:" + echo " clawdbot models auth login --provider higress" + echo +} + +# Configure auto-routing in model-router plugin (inside container) +configureAutoRouting() { + if [ "$ENABLE_AUTO_ROUTING" != "true" ]; then + return 0 + fi + + echo "Configuring auto-routing in model-router plugin..." + + local MODEL_ROUTER_FILE="$ROOT/wasmplugins/model-router.internal.yaml" + + # Wait for the file to be created (it's created when the container starts) + local MAX_WAIT=30 + local WAIT_COUNT=0 + while [ ! -f "$MODEL_ROUTER_FILE" ] && [ $WAIT_COUNT -lt $MAX_WAIT ]; do + sleep 1 + WAIT_COUNT=$((WAIT_COUNT + 1)) + done + + if [ ! -f "$MODEL_ROUTER_FILE" ]; then + echo "Warning: Could not find model-router configuration file at $MODEL_ROUTER_FILE" + echo "Auto-routing will be configured manually later." + return 1 + fi + + # Backup the original file + cp "$MODEL_ROUTER_FILE" "${MODEL_ROUTER_FILE}.backup" + + # Create a temp file with the new content + local TEMP_FILE=$(mktemp) + + # Read the file and insert auto-routing config after modelToHeader line + awk -v model="$AUTO_ROUTING_DEFAULT_MODEL" ' + /modelToHeader: x-higress-llm-model/ { + print + print " autoRouting:" + print " enable: true" + print " defaultModel: " model + next + } + { print } + ' "$MODEL_ROUTER_FILE" > "$TEMP_FILE" + + # Replace original with modified version + mv "$TEMP_FILE" "$MODEL_ROUTER_FILE" + + # Trigger config reload inside container by touching the file + $DOCKER_COMMAND exec "$CONTAINER_NAME" touch /data/wasmplugins/model-router.internal.yaml 2>/dev/null || true + + echo "✓ Auto-routing configured with default model: $AUTO_ROUTING_DEFAULT_MODEL" + echo " Configuration file: $MODEL_ROUTER_FILE" +} + # Configuration wizard runConfigWizard() { echo "Provide a key for each LLM provider you want to enable, then press Enter." @@ -234,6 +418,9 @@ runConfigWizard() { echo "Error: Can only configure either OpenAI or Azure OpenAI, not both" exit 1 fi + + # Configure Clawdbot integration if detected + configureClawdbotIntegration } configureAzureProvider() { @@ -451,6 +638,15 @@ writeConfiguration() { LLM_CONFIGS="$LLM_CONFIGS ${env}=${!env}" done + + # Save auto-routing configuration + local AUTO_ROUTING_CONFIG="" + if [ "$ENABLE_AUTO_ROUTING" == "true" ]; then + AUTO_ROUTING_CONFIG=" +ENABLE_AUTO_ROUTING=true +AUTO_ROUTING_DEFAULT_MODEL=${AUTO_ROUTING_DEFAULT_MODEL}" + fi + cat <$DATA_FOLDER/$CONFIG_FILENAME MODE=full O11Y=on @@ -458,7 +654,7 @@ CONFIG_TEMPLATE=ai-gateway GATEWAY_HTTP_PORT=${GATEWAY_HTTP_PORT} GATEWAY_HTTPS_PORT=${GATEWAY_HTTPS_PORT} CONSOLE_PORT=${CONSOLE_PORT} -${LLM_CONFIGS} +${LLM_CONFIGS}${AUTO_ROUTING_CONFIG} EOF } @@ -493,6 +689,34 @@ outputWelcomeMessage() { echo "Higress AI Gateway chat completion endpoint:" echo " http://localhost:$GATEWAY_HTTP_PORT/v1/chat/completions" echo + + # Show auto-routing info if enabled (read from saved config) + if [ "$ENABLE_AUTO_ROUTING" == "true" ]; then + echo "=======================================================" + echo " Auto-Routing Mode " + echo "=======================================================" + echo + echo "Auto-routing is enabled! Use model 'higress/auto' to automatically" + echo "route requests based on message content." + echo + echo "Default model: $AUTO_ROUTING_DEFAULT_MODEL" + echo + echo "Example with auto-routing:" + echo + echo " curl 'http://localhost:$GATEWAY_HTTP_PORT/v1/chat/completions' \\" + echo " -H 'Content-Type: application/json' \\" + echo " -d '{" + echo " \"model\": \"higress/auto\"," + echo ' "messages": [' + echo " {" + echo ' "role": "user",' + echo ' "content": "深入思考 如何设计一个高并发系统?"' + echo " }" + echo " ]" + echo " }'" + echo + fi + echo "You can try it with cURL directly:" echo echo " curl 'http://localhost:$GATEWAY_HTTP_PORT/v1/chat/completions' \\" @@ -515,6 +739,23 @@ outputWelcomeMessage() { echo "Higress Console URL (open with browser):" echo " http://localhost:$CONSOLE_PORT" + # Show Clawdbot integration info if detected + if checkClawdbot; then + echo + echo "=======================================================" + echo " Clawdbot Integration " + echo "=======================================================" + echo + echo "To configure Clawdbot, run:" + echo " clawdbot models auth login --provider higress" + echo + if [ "$ENABLE_AUTO_ROUTING" == "true" ]; then + echo "To configure auto-routing rules, tell Clawdbot:" + echo " '我希望在解决困难问题时路由到claude-opus-4.5的模型'" + echo + fi + fi + echo echo "To stop the gateway run:" echo @@ -540,6 +781,9 @@ tryAwake() { fi fi + # Load saved config to show auto-routing info correctly on restart + loadSavedConfig + outputWelcomeMessage exit 0 } @@ -560,6 +804,13 @@ start() { --mount "type=bind,source=$NORMALIZED_DATA_FOLDER_PATH,target=/data" "$IMAGE_REPO:$IMAGE_TAG" >/dev/null if [ $? -eq 0 ]; then + # Wait a moment for the container to generate initial config files + echo "Waiting for gateway to initialize..." + sleep 5 + + # Configure auto-routing if enabled + configureAutoRouting + outputWelcomeMessage fi }