Initial commit

This commit is contained in:
Zhongwei Li
2025-11-29 18:26:08 +08:00
commit 8f22ddf339
295 changed files with 59710 additions and 0 deletions

View File

@@ -0,0 +1,96 @@
name: config.validate.router
version: 0.1.0
description: Validates Claude Code Router configuration inputs for correctness, completeness, and schema compliance
status: active
inputs:
- name: llm_backends
type: array
required: true
description: List of backend provider configurations
schema:
type: array
items:
type: object
properties:
name:
type: string
description: Provider name (e.g., openrouter, ollama, claude)
api_base_url:
type: string
description: Base URL for the provider API
api_key:
type: string
description: API key (optional for local providers)
models:
type: array
items:
type: string
description: List of model identifiers
required:
- name
- api_base_url
- models
- name: routing_rules
type: object
required: true
description: Dictionary mapping Claude routing contexts to provider/model pairs
schema:
type: object
properties:
default:
type: object
think:
type: object
background:
type: object
longContext:
type: object
additionalProperties: true
outputs:
- name: validation_result
type: object
description: Validation result with status and errors
schema:
type: object
properties:
valid:
type: boolean
errors:
type: array
items:
type: string
warnings:
type: array
items:
type: string
artifact_metadata:
consumes:
- type: router-config-input
description: Raw router configuration input before validation
content_type: application/json
schema: schemas/router-config-input.json
produces:
- type: validation-report
description: Validation report with errors and warnings
file_pattern: "*-validation-report.json"
content_type: application/json
schema: schemas/validation-report.json
entrypoints:
- command: /skill/config/validate/router
handler: validate_router.py
runtime: python
permissions:
- filesystem:read
tags:
- validation
- config
- router
- llm

View File

@@ -0,0 +1,195 @@
#!/usr/bin/env python3
"""
Skill: config.validate.router
Validates Claude Code Router configuration inputs
"""
import json
import sys
from typing import Dict, List, Any
class RouterConfigValidator:
"""Validates router configuration for Claude Code Router"""
# Claude Code Router supports these routing contexts
VALID_ROUTING_CONTEXTS = {"default", "think", "background", "longContext", "webSearch", "image"}
REQUIRED_PROVIDER_FIELDS = {"name", "api_base_url", "models"}
REQUIRED_ROUTING_FIELDS = {"provider", "model"}
def __init__(self):
self.errors: List[str] = []
self.warnings: List[str] = []
def validate(self, llm_backends: List[Dict[str, Any]], routing_rules: Dict[str, Any]) -> Dict[str, Any]:
"""
Validate router configuration
Args:
llm_backends: List of backend provider configs
routing_rules: Dictionary of routing context mappings
Returns:
Validation result with status, errors, and warnings
"""
self.errors = []
self.warnings = []
# Validate backends
self._validate_backends(llm_backends)
# Validate routing rules
self._validate_routing_rules(routing_rules, llm_backends)
return {
"valid": len(self.errors) == 0,
"errors": self.errors,
"warnings": self.warnings
}
def _validate_backends(self, backends: List[Dict[str, Any]]) -> None:
"""Validate backend provider configurations"""
if not backends:
self.errors.append("llm_backends cannot be empty")
return
seen_names = set()
for idx, backend in enumerate(backends):
# Check required fields
missing = self.REQUIRED_PROVIDER_FIELDS - set(backend.keys())
if missing:
self.errors.append(f"Backend {idx}: missing required fields {missing}")
# Check name uniqueness
name = backend.get("name")
if name:
if name in seen_names:
self.errors.append(f"Duplicate backend name: {name}")
seen_names.add(name)
# Validate models list
models = backend.get("models", [])
if not isinstance(models, list):
self.errors.append(f"Backend {name or idx}: 'models' must be a list")
elif not models:
self.errors.append(f"Backend {name or idx}: 'models' cannot be empty")
# Validate API base URL format
api_base_url = backend.get("api_base_url", "")
if api_base_url and not (api_base_url.startswith("http://") or
api_base_url.startswith("https://")):
self.warnings.append(
f"Backend {name or idx}: api_base_url should start with http:// or https://"
)
# Check for API key in local providers
if "localhost" in api_base_url or "127.0.0.1" in api_base_url:
if backend.get("api_key"):
self.warnings.append(
f"Backend {name or idx}: Local provider has api_key (may be unnecessary)"
)
elif not backend.get("api_key"):
self.warnings.append(
f"Backend {name or idx}: Remote provider missing api_key"
)
def _validate_routing_rules(
self,
routing_rules: Dict[str, Any],
backends: List[Dict[str, Any]]
) -> None:
"""Validate routing rule mappings"""
if not routing_rules:
self.errors.append("routing_rules cannot be empty")
return
# Build provider-model map
provider_models = {}
for backend in backends:
name = backend.get("name")
models = backend.get("models", [])
if name:
provider_models[name] = set(models)
# Validate each routing context
for context, rule in routing_rules.items():
# Warn about unknown contexts
if context not in self.VALID_ROUTING_CONTEXTS:
self.warnings.append(f"Unknown routing context: {context}")
# Check required fields
if not isinstance(rule, dict):
self.errors.append(f"Routing rule '{context}' must be an object")
continue
missing = self.REQUIRED_ROUTING_FIELDS - set(rule.keys())
if missing:
self.errors.append(
f"Routing rule '{context}': missing required fields {missing}"
)
continue
provider = rule.get("provider")
model = rule.get("model")
# Validate provider exists
if provider not in provider_models:
self.errors.append(
f"Routing rule '{context}': unknown provider '{provider}'"
)
continue
# Validate model exists for provider
if model not in provider_models[provider]:
self.errors.append(
f"Routing rule '{context}': model '{model}' not available "
f"in provider '{provider}'"
)
# Check for missing essential contexts
essential = {"default"}
missing_essential = essential - set(routing_rules.keys())
if missing_essential:
self.errors.append(f"Missing essential routing contexts: {missing_essential}")
def main():
"""CLI entrypoint"""
if len(sys.argv) < 2:
print(json.dumps({
"valid": False,
"errors": ["Usage: validate_router.py <config_json>"],
"warnings": []
}))
sys.exit(1)
try:
config = json.loads(sys.argv[1])
validator = RouterConfigValidator()
result = validator.validate(
llm_backends=config.get("llm_backends", []),
routing_rules=config.get("routing_rules", {})
)
print(json.dumps(result, indent=2))
sys.exit(0 if result["valid"] else 1)
except json.JSONDecodeError as e:
print(json.dumps({
"valid": False,
"errors": [f"Invalid JSON: {e}"],
"warnings": []
}))
sys.exit(1)
except Exception as e:
print(json.dumps({
"valid": False,
"errors": [f"Validation error: {e}"],
"warnings": []
}))
sys.exit(1)
if __name__ == "__main__":
main()