| name | adapter-ops |
| description | Extend LLM and embedding adapters in unstract/sdk1. Use when adding new adapters (LLM or embedding), removing adapters, adding/removing models to existing adapters, or editing adapter configurations. Supports OpenAI-compatible providers, cloud providers (AWS Bedrock, VertexAI, Azure), and self-hosted models (Ollama). |
Unstract Adapter Extension Skill
This skill provides workflows and automation for extending LLM and embedding adapters in the unstract/sdk1 module.
Supported Operations
| Operation | Command | Description |
|---|
| Add LLM Adapter | scripts/init_llm_adapter.py | Create new LLM provider adapter |
| Add Embedding Adapter | scripts/init_embedding_adapter.py | Create new embedding provider adapter |
| Remove Adapter | Manual deletion | Remove adapter files and parameter class |
| Add/Remove Models | scripts/manage_models.py | Modify available models in JSON schema |
| Edit Adapter | Manual edit | Modify existing adapter behavior |
| Check for Updates | scripts/check_adapter_updates.py | Compare adapters against LiteLLM features |
Quick Reference
File Locations
unstract/sdk1/src/unstract/sdk1/adapters/
├── base1.py # Parameter classes (add new ones here)
├── llm1/ # LLM adapters
│ ├── {provider}.py # Adapter implementation
│ └── static/{provider}.json # UI schema
└── embedding1/ # Embedding adapters
├── {provider}.py # Adapter implementation
└── static/{provider}.json # UI schema
ID Format
Adapter IDs follow the pattern: {provider}|{uuid4}
- Example:
openai|502ecf49-e47c-445c-9907-6d4b90c5cd17
- Generate UUID:
python -c "import uuid; print(uuid.uuid4())"
Model Prefix Convention
LiteLLM requires provider prefixes on model names:
| Provider | Prefix | Example |
|---|
| OpenAI | openai/ | openai/gpt-4 |
| Azure | azure/ | azure/gpt-4-deployment |
| Anthropic | anthropic/ | anthropic/claude-3-opus |
| Bedrock | bedrock/ | bedrock/anthropic.claude-v2 |
| VertexAI | vertex_ai/ | vertex_ai/gemini-pro |
| Ollama | ollama_chat/ | ollama_chat/llama2 |
| Mistral | mistral/ | mistral/mistral-large |
| Anyscale | anyscale/ | anyscale/meta-llama/Llama-2-70b |
Workflows
Adding a New LLM Adapter
-
Run initialization script:
python .claude/skills/unstract-adapter-extension/scripts/init_llm_adapter.py \
--provider newprovider \
--name "New Provider" \
--description "New Provider LLM adapter" \
--auto-logo
Logo options:
--auto-logo: Search for potential logo sources (Clearbit, GitHub) and display suggestions. Does NOT auto-download - you must verify and use --logo-url to download.
--logo-url URL: Download logo from a verified URL (supports SVG and raster images)
--logo-file PATH: Copy logo from local file (supports SVG and raster images)
Logo image settings (optimized for sharp rendering):
- SVG conversion: 4800 DPI density, 8-bit depth, 512x512 pixels
- Raster images: Resized to 512x512 with LANCZOS resampling
- Requires ImageMagick for SVG conversion (
sudo pacman -S imagemagick)
GitHub logo URL tip: When downloading logos from GitHub, always use the raw URL:
- ❌
https://github.com/user/repo/blob/main/logo.svg
- ✅
https://raw.githubusercontent.com/user/repo/main/logo.svg
Logos are saved to: frontend/public/icons/adapter-icons/{ProviderName}.png
-
Add parameter class to base1.py (if provider has unique parameters):
class NewProviderLLMParameters(BaseChatCompletionParameters):
"""See https://docs.litellm.ai/docs/providers/newprovider."""
api_key: str
@staticmethod
def validate(adapter_metadata: dict[str, "Any"]) -> dict[str, "Any"]:
adapter_metadata["model"] = NewProviderLLMParameters.validate_model(adapter_metadata)
return NewProviderLLMParameters(**adapter_metadata).model_dump()
@staticmethod
def validate_model(adapter_metadata: dict[str, "Any"]) -> str:
model = adapter_metadata.get("model", "")
if model.startswith("newprovider/"):
return model
return f"newprovider/{model}"
-
Update adapter class to inherit from new parameter class:
from unstract.sdk1.adapters.base1 import BaseAdapter, NewProviderLLMParameters
class NewProviderLLMAdapter(NewProviderLLMParameters, BaseAdapter):
-
Customize JSON schema in llm1/static/newprovider.json for UI configuration
-
Test the adapter:
from unstract.sdk1.adapters.adapterkit import Adapterkit
kit = Adapterkit()
adapters = kit.get_adapters_list()
Adding a New Embedding Adapter
-
Run initialization script:
python .claude/skills/unstract-adapter-extension/scripts/init_embedding_adapter.py \
--provider newprovider \
--name "New Provider" \
--description "New Provider embedding adapter" \
--auto-logo
Same logo options as LLM adapter: --auto-logo (search only), --logo-url, --logo-file
-
Add parameter class to base1.py (if needed):
class NewProviderEmbeddingParameters(BaseEmbeddingParameters):
"""See https://docs.litellm.ai/docs/providers/newprovider."""
api_key: str
embed_batch_size: int | None = 10
@staticmethod
def validate(adapter_metadata: dict[str, "Any"]) -> dict[str, "Any"]:
adapter_metadata["model"] = NewProviderEmbeddingParameters.validate_model(adapter_metadata)
return NewProviderEmbeddingParameters(**adapter_metadata).model_dump()
@staticmethod
def validate_model(adapter_metadata: dict[str, "Any"]) -> str:
return adapter_metadata.get("model", "")
-
Update adapter class and JSON schema
Removing an Adapter
- Delete adapter file:
llm1/{provider}.py or embedding1/{provider}.py
- Delete JSON schema:
llm1/static/{provider}.json or embedding1/static/{provider}.json
- Remove parameter class from
base1.py (if dedicated class exists)
- Verify removal: Run
Adapterkit().get_adapters_list() to confirm
Adding/Removing Models from Existing Adapter
-
Edit JSON schema (static/{provider}.json):
{
"properties": {
"model": {
"type": "string",
"title": "Model",
"default": "new-default-model",
"description": "Available models: model-1, model-2, model-3"
}
}
}
-
For dropdown selection, use enum:
{
"properties": {
"model": {
"type": "string",
"title": "Model",
"enum": ["model-1", "model-2", "model-3"],
"default": "model-1"
}
}
}
-
Run management script for automated updates:
python .claude/skills/unstract-adapter-extension/scripts/manage_models.py \
--adapter llm \
--provider openai \
--action add \
--models "gpt-4-turbo,gpt-4o-mini"
Editing Adapter Behavior
Common modifications:
-
Add reasoning/thinking support:
- Add
enable_thinking boolean field to JSON schema
- Add conditional
thinking config in validate() method
- See
AnthropicLLMParameters in base1.py for reference
-
Add custom field mapping:
@staticmethod
def validate(adapter_metadata: dict[str, "Any"]) -> dict[str, "Any"]:
if "custom_field" in adapter_metadata:
adapter_metadata["expected_field"] = adapter_metadata["custom_field"]
-
Add conditional fields in JSON schema:
{
"allOf": [
{
"if": { "properties": { "feature_enabled": { "const": true } } },
"then": {
"properties": { "feature_config": { "type": "string" } },
"required": ["feature_config"]
}
}
]
}
Checking for Adapter Updates
Compare existing adapter schemas against known LiteLLM features to identify potential updates:
-
Run the update checker:
python .claude/skills/unstract-adapter-extension/scripts/check_adapter_updates.py
python .claude/skills/unstract-adapter-extension/scripts/check_adapter_updates.py --adapter llm
python .claude/skills/unstract-adapter-extension/scripts/check_adapter_updates.py --adapter embedding
python .claude/skills/unstract-adapter-extension/scripts/check_adapter_updates.py --provider openai
python .claude/skills/unstract-adapter-extension/scripts/check_adapter_updates.py --json
-
Review the report:
- 🟡 NEEDS UPDATE: Adapters with missing parameters or outdated features
- ✅ UP TO DATE: Adapters matching known LiteLLM features
- ❌ ERRORS: Adapters that couldn't be analyzed (missing schema, etc.)
-
Common update types identified:
- Missing parameters: New configuration options (e.g.,
dimensions for embeddings)
- Reasoning/Thinking support: Enable reasoning for models like o1, o3, Claude 3.7+, Magistral
- Outdated defaults: Default models that have been superseded
-
After identifying updates:
- Update JSON schema in
static/{provider}.json
- Update parameter class in
base1.py if validation logic changes
- Consult LiteLLM docs for implementation details (URLs provided in report)
-
Update the feature database (check_adapter_updates.py):
- Edit
LITELLM_FEATURES dict to add new providers or parameters
- Keep
known_params, reasoning_models, thinking_models, latest_models current
- Add documentation URLs for reference
Validation Checklist
Before submitting adapter changes:
Provider Name Verification (MANDATORY)
The get_provider() return value is used for cost calculation. It MUST match the litellm_provider field in LiteLLM's pricing data, otherwise costs will show as $0.
Before implementing any adapter, verify the provider name:
curl -s https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json | \
jq 'to_entries | map(select(.value.litellm_provider != null)) |
map({key: .key, provider: .value.litellm_provider}) |
unique_by(.provider) |
sort_by(.provider) |
.[].provider' | sort -u
Common provider name mappings:
| Display Name | get_provider() Value | LiteLLM Provider |
|---|
| OpenAI | openai | openai |
| Anthropic | anthropic | anthropic |
| Azure OpenAI | azure | azure |
| Azure AI Foundry | azure_ai | azure_ai |
| AWS Bedrock | bedrock | bedrock |
| Google VertexAI | vertex_ai | vertex_ai |
| Mistral | mistral | mistral |
| Ollama | ollama | ollama |
Example verification for Azure AI Foundry:
curl -s https://raw.githubusercontent.com/BerriAI/litellm/main/model_prices_and_context_window.json | \
jq 'to_entries | map(select(.key | startswith("azure_ai"))) | .[0].value.litellm_provider'
Why this matters:
The cost calculation in platform-service/src/unstract/platform_service/helper/cost_calculation.py filters models by checking if the provider string is contained in litellm_provider. A mismatch (e.g., returning "azure_ai_foundry" when LiteLLM uses "azure_ai") causes the cost lookup to fail silently, returning $0.
Maintenance Workflow
Periodic maintenance to keep adapters current with LiteLLM features:
Monthly Update Check
-
Run the update checker:
python .claude/skills/unstract-adapter-extension/scripts/check_adapter_updates.py
-
Review LiteLLM changelog for new provider features:
-
Update feature database in check_adapter_updates.py:
- Add new
known_params for each provider
- Update
reasoning_models and thinking_models lists
- Update
latest_models with current defaults
-
Apply updates following priority:
- 🔴 High: Security or breaking changes
- 🟡 Medium: New capabilities (reasoning, dimensions)
- 🟢 Low: Model updates, documentation
After LiteLLM Upgrade
When upgrading LiteLLM dependency:
- Check for API changes in provider parameters
- Verify model prefix requirements haven't changed
- Test thinking/reasoning features still work
- Update default models if deprecated
Adding New Provider Support
When LiteLLM adds a new provider:
- Check LiteLLM docs:
https://docs.litellm.ai/docs/providers/{provider}
- Add feature data to
check_adapter_updates.py
- Run init script to create adapter skeleton
- Customize JSON schema and parameter class
Reference Files
For detailed patterns and examples, see:
references/adapter_patterns.md - Complete code patterns
references/json_schema_guide.md - JSON schema patterns for UI
references/provider_capabilities.md - Provider feature matrix
assets/templates/ - Ready-to-use templates
Troubleshooting
Adapter not appearing in list
- Verify class name ends with
LLMAdapter or EmbeddingAdapter
- Check
is_active: True in metadata
- Ensure file is in correct directory (
llm1/ or embedding1/)
Validation errors
- Check parameter class fields match JSON schema required fields
- Verify
validate() returns properly validated dict
- Ensure model prefix logic is idempotent
Import errors
- Verify imports in adapter file match available classes in
base1.py
- Check for circular imports (use
TYPE_CHECKING guard)