Add local host mode and configurable LLM providers
This commit is contained in:
@@ -8,6 +8,7 @@ DEFAULT_PROVIDER = "anthropic"
|
||||
DEFAULT_MODEL_BY_PROVIDER = {
|
||||
"anthropic": "claude-sonnet-5",
|
||||
"openai": "gpt-5.6",
|
||||
"openai_compatible": "local-model",
|
||||
}
|
||||
DEFAULT_TIMEOUT_SECONDS = 30.0
|
||||
|
||||
@@ -16,6 +17,8 @@ PROVIDER_ENV = "AI_PLANNER_PROVIDER"
|
||||
MODEL_ENV = "AI_PLANNER_MODEL"
|
||||
TIMEOUT_ENV = "AI_PLANNER_TIMEOUT_SECONDS"
|
||||
THINKING_BUDGET_ENV = "AI_PLANNER_THINKING_BUDGET_TOKENS"
|
||||
API_KEY_ENV = "AI_PLANNER_API_KEY"
|
||||
BASE_URL_ENV = "AI_PLANNER_BASE_URL"
|
||||
|
||||
SUPPORTED_PROVIDERS = frozenset(DEFAULT_MODEL_BY_PROVIDER)
|
||||
|
||||
@@ -27,6 +30,8 @@ class PlannerConfig:
|
||||
model: str = ""
|
||||
timeout: float = DEFAULT_TIMEOUT_SECONDS
|
||||
thinking_budget_tokens: int | None = None
|
||||
api_key: str | None = None
|
||||
base_url: str | None = None
|
||||
|
||||
def resolved_model(self) -> str:
|
||||
return self.model or DEFAULT_MODEL_BY_PROVIDER[self.provider]
|
||||
@@ -40,6 +45,8 @@ def load_config(env: Mapping[str, str] | None = None) -> PlannerConfig:
|
||||
model=values.get(MODEL_ENV) or "",
|
||||
timeout=_parse_timeout(values.get(TIMEOUT_ENV)),
|
||||
thinking_budget_tokens=_parse_thinking_budget(values.get(THINKING_BUDGET_ENV)),
|
||||
api_key=values.get(API_KEY_ENV) or _provider_key(values),
|
||||
base_url=values.get(BASE_URL_ENV) or None,
|
||||
)
|
||||
|
||||
|
||||
@@ -53,6 +60,8 @@ def _parse_provider(value: str | None) -> str:
|
||||
if value is None:
|
||||
return DEFAULT_PROVIDER
|
||||
provider = value.strip().lower()
|
||||
if provider in {"openai-compatible", "openai_compatible", "local"}:
|
||||
return "openai_compatible"
|
||||
return provider if provider in SUPPORTED_PROVIDERS else DEFAULT_PROVIDER
|
||||
|
||||
|
||||
@@ -74,3 +83,12 @@ def _parse_thinking_budget(value: str | None) -> int | None:
|
||||
except ValueError:
|
||||
return None
|
||||
return budget if budget > 0 else None
|
||||
|
||||
|
||||
def _provider_key(values: Mapping[str, str]) -> str | None:
|
||||
provider = (values.get(PROVIDER_ENV) or DEFAULT_PROVIDER).strip().lower()
|
||||
if provider == "openai":
|
||||
return values.get("OPENAI_API_KEY") or None
|
||||
if provider == "anthropic":
|
||||
return values.get("ANTHROPIC_API_KEY") or None
|
||||
return None
|
||||
|
||||
@@ -288,10 +288,14 @@ class OpenAIToolCallingClient:
|
||||
|
||||
def build_client(config: PlannerConfig) -> ToolCallingClient:
|
||||
model = config.resolved_model()
|
||||
if config.provider == "openai":
|
||||
return OpenAIToolCallingClient(model=model)
|
||||
if config.provider in {"openai", "openai_compatible"}:
|
||||
return OpenAIToolCallingClient(
|
||||
model=model, api_key=config.api_key, base_url=config.base_url
|
||||
)
|
||||
return AnthropicToolCallingClient(
|
||||
model=model,
|
||||
api_key=config.api_key,
|
||||
base_url=config.base_url,
|
||||
thinking_budget_tokens=config.thinking_budget_tokens,
|
||||
)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user