From 52c510501dfc3c3f3dccceea844798044ad4f531 Mon Sep 17 00:00:00 2001 From: catlog22 Date: Mon, 12 Jan 2026 11:41:04 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E6=B7=BB=E5=8A=A0=E5=B7=A5=E5=85=B7?= =?UTF-8?q?=E7=B1=BB=E5=9E=8B=E5=92=8C=E7=94=A8=E6=B3=95=E8=AF=B4=E6=98=8E?= =?UTF-8?q?=EF=BC=8C=E6=94=AF=E6=8C=81=E8=87=AA=E5=AE=9A=E4=B9=89=20API=20?= =?UTF-8?q?=E5=A4=B4=E9=83=A8=E8=AE=BE=E7=BD=AE?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .claude/workflows/cli-tools-usage.md | 10 ++++++++++ .../src/ccw_litellm/clients/litellm_llm.py | 18 ++++++++++++++++-- ccw/src/tools/litellm-executor.ts | 8 ++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/.claude/workflows/cli-tools-usage.md b/.claude/workflows/cli-tools-usage.md index ee7d2972..8476d987 100644 --- a/.claude/workflows/cli-tools-usage.md +++ b/.claude/workflows/cli-tools-usage.md @@ -54,6 +54,16 @@ All tool availability, model selection, and routing are defined in this configur | `secondaryModel` | Fallback model | | `tags` | Capability tags for routing | +### Tool Types + +| Type | Usage | Capabilities | +|------|-------|--------------| +| `builtin` | `--tool gemini` | Full (analysis + write tools) | +| `cli-wrapper` | `--tool doubao` | Full (analysis + write tools) | +| `api-endpoint` | `--tool g25` | **Analysis only** (no file write tools) | + +> **Note**: `api-endpoint` tools only support analysis and code generation responses. They cannot create, modify, or delete files. + --- ## Tool Selection diff --git a/ccw-litellm/src/ccw_litellm/clients/litellm_llm.py b/ccw-litellm/src/ccw_litellm/clients/litellm_llm.py index 7164ffdf..489d2615 100644 --- a/ccw-litellm/src/ccw_litellm/clients/litellm_llm.py +++ b/ccw-litellm/src/ccw_litellm/clients/litellm_llm.py @@ -2,7 +2,9 @@ from __future__ import annotations +import json import logging +import os from typing import Any, Sequence import litellm @@ -132,10 +134,22 @@ class LiteLLMClient(AbstractLLMClient): # Merge kwargs completion_kwargs = {**self._litellm_kwargs, **kwargs} - # Override User-Agent to avoid being blocked by some API proxies - # that detect and block OpenAI SDK's default User-Agent + # Build extra_headers from multiple sources if "extra_headers" not in completion_kwargs: completion_kwargs["extra_headers"] = {} + + # 1. Load custom headers from environment variable (set by CCW) + env_headers = os.environ.get("CCW_LITELLM_EXTRA_HEADERS") + if env_headers: + try: + custom_headers = json.loads(env_headers) + completion_kwargs["extra_headers"].update(custom_headers) + except json.JSONDecodeError: + logger.warning(f"Invalid JSON in CCW_LITELLM_EXTRA_HEADERS: {env_headers}") + + # 2. Override User-Agent to avoid being blocked by some API proxies + # that detect and block OpenAI SDK's default User-Agent + # This is a fallback - user can override via custom headers if "User-Agent" not in completion_kwargs["extra_headers"]: completion_kwargs["extra_headers"]["User-Agent"] = "python-httpx/0.27" diff --git a/ccw/src/tools/litellm-executor.ts b/ccw/src/tools/litellm-executor.ts index b2046979..a08c0c28 100644 --- a/ccw/src/tools/litellm-executor.ts +++ b/ccw/src/tools/litellm-executor.ts @@ -198,6 +198,14 @@ export async function executeLiteLLMEndpoint( } } + // Set custom headers from provider advanced settings + if (provider.advancedSettings?.customHeaders) { + process.env['CCW_LITELLM_EXTRA_HEADERS'] = JSON.stringify(provider.advancedSettings.customHeaders); + } else { + // Clear any previous custom headers + delete process.env['CCW_LITELLM_EXTRA_HEADERS']; + } + // Use litellm-client to call chat const response = await callWithRetries( () => client.chat(finalPrompt, endpoint.model),