sandboxy 0.0.6__tar.gz → 0.0.7__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- {sandboxy-0.0.6 → sandboxy-0.0.7}/PKG-INFO +1 -1
- {sandboxy-0.0.6 → sandboxy-0.0.7}/local-ui/src/components/ResultDisplay.tsx +4 -2
- {sandboxy-0.0.6 → sandboxy-0.0.7}/local-ui/src/lib/api.ts +2 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/pyproject.toml +1 -1
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/api/app.py +13 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/api/routes/local.py +12 -2
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/cli/main.py +3 -1
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/providers/__init__.py +2 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/providers/registry.py +26 -5
- sandboxy-0.0.6/sandboxy/ui/dist/assets/index-BZFjoK-_.js → sandboxy-0.0.7/sandboxy/ui/dist/assets/index-DfKu4uXt.js +1 -1
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/ui/dist/index.html +1 -1
- {sandboxy-0.0.6 → sandboxy-0.0.7}/.env.example +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/.github/workflows/ci.yml +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/.github/workflows/publish.yml +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/.gitignore +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/CONTRIBUTING.md +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/LICENSE +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/Makefile +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/README.md +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/docs/yaml-tools.md +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/local-ui/index.html +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/local-ui/package-lock.json +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/local-ui/package.json +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/local-ui/postcss.config.js +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/local-ui/src/App.tsx +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/local-ui/src/components/Layout.tsx +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/local-ui/src/components/ModelSelector.tsx +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/local-ui/src/hooks/useScenarioBuilder.ts +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/local-ui/src/hooks/useScenarioRun.ts +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/local-ui/src/hooks/useToolBuilder.ts +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/local-ui/src/index.css +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/local-ui/src/main.tsx +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/local-ui/src/pages/BuilderPage.tsx +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/local-ui/src/pages/DashboardPage.tsx +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/local-ui/src/pages/DatasetPage.tsx +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/local-ui/src/pages/ResultsPage.tsx +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/local-ui/src/pages/RunPage.tsx +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/local-ui/src/pages/ScenarioDetailPage.tsx +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/local-ui/src/pages/ToolBuilderPage.tsx +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/local-ui/tailwind.config.js +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/local-ui/tsconfig.json +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/local-ui/tsconfig.node.json +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/local-ui/vite.config.ts +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/__init__.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/agents/__init__.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/agents/base.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/agents/llm_prompt.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/agents/loader.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/api/__init__.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/api/routes/__init__.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/api/routes/agents.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/api/routes/providers.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/api/routes/tools.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/cli/__init__.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/cli/type_detector.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/config.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/core/__init__.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/core/async_runner.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/core/mdl_parser.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/core/runner.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/core/safe_eval.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/core/state.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/datasets/__init__.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/datasets/loader.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/datasets/runner.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/errors.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/local/context.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/local/results.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/logging.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/mcp/__init__.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/mcp/client.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/mcp/wrapper.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/mlflow/__init__.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/mlflow/artifacts.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/mlflow/config.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/mlflow/exporter.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/mlflow/metrics.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/mlflow/tags.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/mlflow/tracing.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/providers/anthropic_provider.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/providers/base.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/providers/config.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/providers/http_client.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/providers/local.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/providers/openai_provider.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/providers/openrouter.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/scenarios/__init__.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/scenarios/comparison.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/scenarios/loader.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/scenarios/runner.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/scenarios/unified.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/session/__init__.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/session/manager.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/tools/__init__.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/tools/base.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/tools/loader.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/tools/yaml_tools.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/ui/__init__.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/ui/dist/assets/index-Qf7gGJk_.css +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/utils/__init__.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/sandboxy/utils/time.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/scenarios/customer_service.yml +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/tests/__init__.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/tests/conftest.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/tests/factories.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/tests/integration/__init__.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/tests/integration/api/__init__.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/tests/integration/test_mlflow_integration.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/tests/mocks/__init__.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/tests/mocks/providers.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/tests/unit/__init__.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/tests/unit/agents/__init__.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/tests/unit/agents/test_base.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/tests/unit/agents/test_llm_prompt.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/tests/unit/agents/test_loader.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/tests/unit/core/__init__.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/tests/unit/core/test_async_runner.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/tests/unit/core/test_mdl_parser.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/tests/unit/core/test_runner.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/tests/unit/core/test_safe_eval.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/tests/unit/core/test_state.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/tests/unit/mlflow/__init__.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/tests/unit/mlflow/test_artifacts.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/tests/unit/mlflow/test_config.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/tests/unit/mlflow/test_metrics.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/tests/unit/mlflow/test_tags.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/tests/unit/providers/test_openrouter.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/tests/unit/tools/__init__.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/tests/unit/tools/test_base.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/tests/unit/tools/test_loader.py +0 -0
- {sandboxy-0.0.6 → sandboxy-0.0.7}/uv.lock +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: sandboxy
|
|
3
|
-
Version: 0.0.
|
|
3
|
+
Version: 0.0.7
|
|
4
4
|
Summary: Open-source agent simulation and benchmarking platform
|
|
5
5
|
Project-URL: Homepage, https://github.com/sandboxy-ai/sandboxy
|
|
6
6
|
Project-URL: Repository, https://github.com/sandboxy-ai/sandboxy
|
|
@@ -2,8 +2,10 @@ import { useState } from 'react'
|
|
|
2
2
|
import { CheckCircle, XCircle, Trophy, Clock, Zap, DollarSign, Hash, MessageSquare, ChevronDown, ChevronRight, Eye, X, AlertCircle } from 'lucide-react'
|
|
3
3
|
import { RunScenarioResponse, CompareModelsResponse } from '../lib/api'
|
|
4
4
|
|
|
5
|
-
export function formatCost(cost: number | null | undefined): string {
|
|
5
|
+
export function formatCost(cost: number | null | undefined, isLocal?: boolean): string {
|
|
6
6
|
if (cost === null || cost === undefined) return '-'
|
|
7
|
+
// Local models have cost = 0 or is_local flag
|
|
8
|
+
if (isLocal === true || cost === 0) return 'Local'
|
|
7
9
|
if (cost < 0.0001) return '<$0.0001'
|
|
8
10
|
if (cost < 0.01) return `$${cost.toFixed(4)}`
|
|
9
11
|
return `$${cost.toFixed(3)}`
|
|
@@ -73,7 +75,7 @@ export function SingleRunResult({ result }: { result: RunScenarioResponse }) {
|
|
|
73
75
|
<DollarSign className="w-4 h-4" />
|
|
74
76
|
Cost
|
|
75
77
|
</div>
|
|
76
|
-
<div className="text-2xl font-bold text-emerald-300">{formatCost(result.cost_usd)}</div>
|
|
78
|
+
<div className="text-2xl font-bold text-emerald-300">{formatCost(result.cost_usd, result.is_local)}</div>
|
|
77
79
|
</div>
|
|
78
80
|
</div>
|
|
79
81
|
|
|
@@ -36,6 +36,19 @@ def create_local_app(
|
|
|
36
36
|
root_dir: Working directory for scenarios/tools/agents.
|
|
37
37
|
local_ui_path: Path to local UI static files.
|
|
38
38
|
"""
|
|
39
|
+
# Load .env from root_dir to pick up API keys from the project directory
|
|
40
|
+
# This is important when root_dir differs from cwd
|
|
41
|
+
env_file = root_dir / ".env"
|
|
42
|
+
if env_file.exists():
|
|
43
|
+
load_dotenv(env_file, override=True)
|
|
44
|
+
logger.info(f"Loaded environment from {env_file}")
|
|
45
|
+
|
|
46
|
+
# Reset provider registry so it picks up the newly loaded API keys
|
|
47
|
+
from sandboxy.providers.registry import reset_registry
|
|
48
|
+
|
|
49
|
+
reset_registry()
|
|
50
|
+
logger.info("Provider registry reset after loading project .env")
|
|
51
|
+
|
|
39
52
|
from sandboxy.local.context import LocalContext, set_local_context
|
|
40
53
|
|
|
41
54
|
ctx = LocalContext(root_dir=root_dir)
|
|
@@ -493,7 +493,10 @@ async def run_scenario(request: RunScenarioRequest) -> RunScenarioResponse:
|
|
|
493
493
|
experiment_name=mlflow_config.experiment,
|
|
494
494
|
)
|
|
495
495
|
|
|
496
|
-
|
|
496
|
+
# Short run name - just the model (scenario is in experiment name)
|
|
497
|
+
run_name = request.model.split("/")[-1] if "/" in request.model else request.model
|
|
498
|
+
|
|
499
|
+
with mlflow_run_context(mlflow_config, run_name=run_name) as run_id:
|
|
497
500
|
result = await runner.run(
|
|
498
501
|
scenario=spec,
|
|
499
502
|
model=request.model,
|
|
@@ -633,12 +636,17 @@ async def compare_models(request: CompareModelsRequest) -> CompareModelsResponse
|
|
|
633
636
|
scenario_name=spec.name,
|
|
634
637
|
)
|
|
635
638
|
exporter = MLflowExporter(config)
|
|
639
|
+
|
|
640
|
+
# Short run name - just the model
|
|
641
|
+
run_name = result.model.split("/")[-1] if "/" in result.model else result.model
|
|
642
|
+
|
|
636
643
|
exporter.export(
|
|
637
644
|
result=result.to_dict(),
|
|
638
645
|
scenario_path=scenario_path,
|
|
639
646
|
scenario_name=spec.name,
|
|
640
647
|
scenario_id=spec.id,
|
|
641
648
|
agent_name=result.model,
|
|
649
|
+
run_name=run_name,
|
|
642
650
|
)
|
|
643
651
|
except ImportError:
|
|
644
652
|
logger.warning("MLflow not installed, skipping export")
|
|
@@ -1513,7 +1521,9 @@ async def run_with_dataset(request: RunDatasetRequest) -> RunDatasetResponse:
|
|
|
1513
1521
|
if mlflow_config and mlflow_config.enabled:
|
|
1514
1522
|
from sandboxy.mlflow import mlflow_run_context
|
|
1515
1523
|
|
|
1516
|
-
|
|
1524
|
+
# Short run name - model + dataset
|
|
1525
|
+
model_short = request.model.split("/")[-1] if "/" in request.model else request.model
|
|
1526
|
+
run_name = f"{model_short} ({request.dataset_id})"
|
|
1517
1527
|
with mlflow_run_context(mlflow_config, run_name=run_name) as run_id:
|
|
1518
1528
|
result = await run_dataset_benchmark()
|
|
1519
1529
|
|
|
@@ -833,7 +833,9 @@ def scenario(
|
|
|
833
833
|
)
|
|
834
834
|
|
|
835
835
|
# Start run, execute scenario, then log metrics - all connected
|
|
836
|
-
|
|
836
|
+
# Short run name - just the model
|
|
837
|
+
run_name = model_id.split("/")[-1] if "/" in model_id else model_id
|
|
838
|
+
with mlflow_run_context(mlflow_config, run_name=run_name) as run_id:
|
|
837
839
|
runner = ScenarioRunner(scenario=spec, agent=agent)
|
|
838
840
|
result = runner.run(max_turns=max_turns)
|
|
839
841
|
|
|
@@ -40,6 +40,7 @@ from sandboxy.providers.registry import (
|
|
|
40
40
|
get_provider,
|
|
41
41
|
get_registry,
|
|
42
42
|
reload_local_providers,
|
|
43
|
+
reset_registry,
|
|
43
44
|
)
|
|
44
45
|
|
|
45
46
|
__all__ = [
|
|
@@ -53,6 +54,7 @@ __all__ = [
|
|
|
53
54
|
"get_provider",
|
|
54
55
|
"get_registry",
|
|
55
56
|
"reload_local_providers",
|
|
57
|
+
"reset_registry",
|
|
56
58
|
# Local provider
|
|
57
59
|
"LocalProvider",
|
|
58
60
|
"LocalProviderConnectionError",
|
|
@@ -154,23 +154,34 @@ class ProviderRegistry:
|
|
|
154
154
|
if "/" in model_id:
|
|
155
155
|
provider_name, model_name = model_id.split("/", 1)
|
|
156
156
|
|
|
157
|
-
# Check for
|
|
157
|
+
# Priority 1: Check for LOCAL provider with matching name
|
|
158
|
+
# Local providers take precedence over cloud providers
|
|
158
159
|
if provider_name in self.providers:
|
|
159
160
|
provider = self.providers[provider_name]
|
|
160
|
-
#
|
|
161
|
-
if hasattr(provider, "config")
|
|
161
|
+
# Only use if it's a local provider (has config attribute)
|
|
162
|
+
if hasattr(provider, "config"):
|
|
162
163
|
return provider
|
|
163
164
|
|
|
164
|
-
# OpenRouter format (e.g., "openai/gpt-4o")
|
|
165
|
+
# Priority 2: OpenRouter for provider/model format (e.g., "openai/gpt-4o")
|
|
165
166
|
if "openrouter" in self.providers:
|
|
166
167
|
return self.providers["openrouter"]
|
|
167
168
|
|
|
168
|
-
# Fallback to direct provider if
|
|
169
|
+
# Priority 3: Fallback to direct cloud provider if available
|
|
169
170
|
if provider_name == "openai" and "openai" in self.providers:
|
|
170
171
|
return self.providers["openai"]
|
|
171
172
|
if provider_name == "anthropic" and "anthropic" in self.providers:
|
|
172
173
|
return self.providers["anthropic"]
|
|
173
174
|
|
|
175
|
+
# No valid provider found for prefixed model - raise clear error
|
|
176
|
+
available = list(self.providers.keys())
|
|
177
|
+
raise ProviderError(
|
|
178
|
+
f"No provider available for model '{model_id}'. "
|
|
179
|
+
f"The '{provider_name}/' prefix requires OpenRouter (set OPENROUTER_API_KEY) "
|
|
180
|
+
f"or a local provider named '{provider_name}'. "
|
|
181
|
+
f"Available providers: {available}",
|
|
182
|
+
provider="registry",
|
|
183
|
+
)
|
|
184
|
+
|
|
174
185
|
# No prefix - use direct providers
|
|
175
186
|
model_lower = model_id.lower()
|
|
176
187
|
|
|
@@ -280,6 +291,16 @@ def get_registry() -> ProviderRegistry:
|
|
|
280
291
|
return _registry
|
|
281
292
|
|
|
282
293
|
|
|
294
|
+
def reset_registry() -> None:
|
|
295
|
+
"""Reset the global provider registry.
|
|
296
|
+
|
|
297
|
+
Forces re-initialization on next get_registry() call.
|
|
298
|
+
Useful after loading new environment variables.
|
|
299
|
+
"""
|
|
300
|
+
global _registry
|
|
301
|
+
_registry = None
|
|
302
|
+
|
|
303
|
+
|
|
283
304
|
def get_provider(model_id: str) -> BaseProvider:
|
|
284
305
|
"""Get a provider for a model (convenience function).
|
|
285
306
|
|