agentpool 2.1.9__py3-none-any.whl → 2.5.0__py3-none-any.whl
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.
- acp/__init__.py +13 -4
- acp/acp_requests.py +20 -77
- acp/agent/connection.py +8 -0
- acp/agent/implementations/debug_server/debug_server.py +6 -2
- acp/agent/protocol.py +6 -0
- acp/bridge/README.md +15 -2
- acp/bridge/__init__.py +3 -2
- acp/bridge/__main__.py +60 -19
- acp/bridge/ws_server.py +173 -0
- acp/bridge/ws_server_cli.py +89 -0
- acp/client/connection.py +38 -29
- acp/client/implementations/default_client.py +3 -2
- acp/client/implementations/headless_client.py +2 -2
- acp/connection.py +2 -2
- acp/notifications.py +20 -50
- acp/schema/__init__.py +2 -0
- acp/schema/agent_responses.py +21 -0
- acp/schema/client_requests.py +3 -3
- acp/schema/session_state.py +63 -29
- acp/stdio.py +39 -9
- acp/task/supervisor.py +2 -2
- acp/transports.py +362 -2
- acp/utils.py +17 -4
- agentpool/__init__.py +6 -1
- agentpool/agents/__init__.py +2 -0
- agentpool/agents/acp_agent/acp_agent.py +407 -277
- agentpool/agents/acp_agent/acp_converters.py +196 -38
- agentpool/agents/acp_agent/client_handler.py +191 -26
- agentpool/agents/acp_agent/session_state.py +17 -6
- agentpool/agents/agent.py +607 -572
- agentpool/agents/agui_agent/__init__.py +0 -2
- agentpool/agents/agui_agent/agui_agent.py +176 -110
- agentpool/agents/agui_agent/agui_converters.py +0 -131
- agentpool/agents/agui_agent/helpers.py +3 -4
- agentpool/agents/base_agent.py +632 -17
- agentpool/agents/claude_code_agent/FORKING.md +191 -0
- agentpool/agents/claude_code_agent/__init__.py +13 -1
- agentpool/agents/claude_code_agent/claude_code_agent.py +1058 -291
- agentpool/agents/claude_code_agent/converters.py +74 -143
- agentpool/agents/claude_code_agent/history.py +474 -0
- agentpool/agents/claude_code_agent/models.py +77 -0
- agentpool/agents/claude_code_agent/static_info.py +100 -0
- agentpool/agents/claude_code_agent/usage.py +242 -0
- agentpool/agents/context.py +40 -0
- agentpool/agents/events/__init__.py +24 -0
- agentpool/agents/events/builtin_handlers.py +67 -1
- agentpool/agents/events/event_emitter.py +32 -2
- agentpool/agents/events/events.py +104 -3
- agentpool/agents/events/infer_info.py +145 -0
- agentpool/agents/events/processors.py +254 -0
- agentpool/agents/interactions.py +41 -6
- agentpool/agents/modes.py +67 -0
- agentpool/agents/slashed_agent.py +5 -4
- agentpool/agents/tool_call_accumulator.py +213 -0
- agentpool/agents/tool_wrapping.py +18 -6
- agentpool/common_types.py +56 -21
- agentpool/config_resources/__init__.py +38 -1
- agentpool/config_resources/acp_assistant.yml +2 -2
- agentpool/config_resources/agents.yml +3 -0
- agentpool/config_resources/agents_template.yml +1 -0
- agentpool/config_resources/claude_code_agent.yml +10 -6
- agentpool/config_resources/external_acp_agents.yml +2 -1
- agentpool/delegation/base_team.py +4 -30
- agentpool/delegation/pool.py +136 -289
- agentpool/delegation/team.py +58 -57
- agentpool/delegation/teamrun.py +51 -55
- agentpool/diagnostics/__init__.py +53 -0
- agentpool/diagnostics/lsp_manager.py +1593 -0
- agentpool/diagnostics/lsp_proxy.py +41 -0
- agentpool/diagnostics/lsp_proxy_script.py +229 -0
- agentpool/diagnostics/models.py +398 -0
- agentpool/functional/run.py +10 -4
- agentpool/mcp_server/__init__.py +0 -2
- agentpool/mcp_server/client.py +76 -32
- agentpool/mcp_server/conversions.py +54 -13
- agentpool/mcp_server/manager.py +34 -54
- agentpool/mcp_server/registries/official_registry_client.py +35 -1
- agentpool/mcp_server/tool_bridge.py +186 -139
- agentpool/messaging/__init__.py +0 -2
- agentpool/messaging/compaction.py +72 -197
- agentpool/messaging/connection_manager.py +11 -10
- agentpool/messaging/event_manager.py +5 -5
- agentpool/messaging/message_container.py +6 -30
- agentpool/messaging/message_history.py +99 -8
- agentpool/messaging/messagenode.py +52 -14
- agentpool/messaging/messages.py +54 -35
- agentpool/messaging/processing.py +12 -22
- agentpool/models/__init__.py +1 -1
- agentpool/models/acp_agents/base.py +6 -24
- agentpool/models/acp_agents/mcp_capable.py +126 -157
- agentpool/models/acp_agents/non_mcp.py +129 -95
- agentpool/models/agents.py +98 -76
- agentpool/models/agui_agents.py +1 -1
- agentpool/models/claude_code_agents.py +144 -19
- agentpool/models/file_parsing.py +0 -1
- agentpool/models/manifest.py +113 -50
- agentpool/prompts/conversion_manager.py +1 -1
- agentpool/prompts/prompts.py +5 -2
- agentpool/repomap.py +1 -1
- agentpool/resource_providers/__init__.py +11 -1
- agentpool/resource_providers/aggregating.py +56 -5
- agentpool/resource_providers/base.py +70 -4
- agentpool/resource_providers/codemode/code_executor.py +72 -5
- agentpool/resource_providers/codemode/helpers.py +2 -2
- agentpool/resource_providers/codemode/provider.py +64 -12
- agentpool/resource_providers/codemode/remote_mcp_execution.py +2 -2
- agentpool/resource_providers/codemode/remote_provider.py +9 -12
- agentpool/resource_providers/filtering.py +3 -1
- agentpool/resource_providers/mcp_provider.py +89 -12
- agentpool/resource_providers/plan_provider.py +228 -46
- agentpool/resource_providers/pool.py +7 -3
- agentpool/resource_providers/resource_info.py +111 -0
- agentpool/resource_providers/static.py +4 -2
- agentpool/sessions/__init__.py +4 -1
- agentpool/sessions/manager.py +33 -5
- agentpool/sessions/models.py +59 -6
- agentpool/sessions/protocol.py +28 -0
- agentpool/sessions/session.py +11 -55
- agentpool/skills/registry.py +13 -8
- agentpool/storage/manager.py +572 -49
- agentpool/talk/registry.py +4 -4
- agentpool/talk/talk.py +9 -10
- agentpool/testing.py +538 -20
- agentpool/tool_impls/__init__.py +6 -0
- agentpool/tool_impls/agent_cli/__init__.py +42 -0
- agentpool/tool_impls/agent_cli/tool.py +95 -0
- agentpool/tool_impls/bash/__init__.py +64 -0
- agentpool/tool_impls/bash/helpers.py +35 -0
- agentpool/tool_impls/bash/tool.py +171 -0
- agentpool/tool_impls/delete_path/__init__.py +70 -0
- agentpool/tool_impls/delete_path/tool.py +142 -0
- agentpool/tool_impls/download_file/__init__.py +80 -0
- agentpool/tool_impls/download_file/tool.py +183 -0
- agentpool/tool_impls/execute_code/__init__.py +55 -0
- agentpool/tool_impls/execute_code/tool.py +163 -0
- agentpool/tool_impls/grep/__init__.py +80 -0
- agentpool/tool_impls/grep/tool.py +200 -0
- agentpool/tool_impls/list_directory/__init__.py +73 -0
- agentpool/tool_impls/list_directory/tool.py +197 -0
- agentpool/tool_impls/question/__init__.py +42 -0
- agentpool/tool_impls/question/tool.py +127 -0
- agentpool/tool_impls/read/__init__.py +104 -0
- agentpool/tool_impls/read/tool.py +305 -0
- agentpool/tools/__init__.py +2 -1
- agentpool/tools/base.py +114 -34
- agentpool/tools/manager.py +57 -1
- agentpool/ui/base.py +2 -2
- agentpool/ui/mock_provider.py +2 -2
- agentpool/ui/stdlib_provider.py +2 -2
- agentpool/utils/file_watcher.py +269 -0
- agentpool/utils/identifiers.py +121 -0
- agentpool/utils/pydantic_ai_helpers.py +46 -0
- agentpool/utils/streams.py +616 -2
- agentpool/utils/subprocess_utils.py +155 -0
- agentpool/utils/token_breakdown.py +461 -0
- agentpool/vfs_registry.py +7 -2
- {agentpool-2.1.9.dist-info → agentpool-2.5.0.dist-info}/METADATA +41 -27
- agentpool-2.5.0.dist-info/RECORD +579 -0
- {agentpool-2.1.9.dist-info → agentpool-2.5.0.dist-info}/WHEEL +1 -1
- agentpool_cli/__main__.py +24 -0
- agentpool_cli/create.py +1 -1
- agentpool_cli/serve_acp.py +100 -21
- agentpool_cli/serve_agui.py +87 -0
- agentpool_cli/serve_opencode.py +119 -0
- agentpool_cli/ui.py +557 -0
- agentpool_commands/__init__.py +42 -5
- agentpool_commands/agents.py +75 -2
- agentpool_commands/history.py +62 -0
- agentpool_commands/mcp.py +176 -0
- agentpool_commands/models.py +56 -3
- agentpool_commands/pool.py +260 -0
- agentpool_commands/session.py +1 -1
- agentpool_commands/text_sharing/__init__.py +119 -0
- agentpool_commands/text_sharing/base.py +123 -0
- agentpool_commands/text_sharing/github_gist.py +80 -0
- agentpool_commands/text_sharing/opencode.py +462 -0
- agentpool_commands/text_sharing/paste_rs.py +59 -0
- agentpool_commands/text_sharing/pastebin.py +116 -0
- agentpool_commands/text_sharing/shittycodingagent.py +112 -0
- agentpool_commands/tools.py +57 -0
- agentpool_commands/utils.py +80 -30
- agentpool_config/__init__.py +30 -2
- agentpool_config/agentpool_tools.py +498 -0
- agentpool_config/builtin_tools.py +77 -22
- agentpool_config/commands.py +24 -1
- agentpool_config/compaction.py +258 -0
- agentpool_config/converters.py +1 -1
- agentpool_config/event_handlers.py +42 -0
- agentpool_config/events.py +1 -1
- agentpool_config/forward_targets.py +1 -4
- agentpool_config/jinja.py +3 -3
- agentpool_config/mcp_server.py +132 -6
- agentpool_config/nodes.py +1 -1
- agentpool_config/observability.py +44 -0
- agentpool_config/session.py +0 -3
- agentpool_config/storage.py +82 -38
- agentpool_config/task.py +3 -3
- agentpool_config/tools.py +11 -22
- agentpool_config/toolsets.py +109 -233
- agentpool_server/a2a_server/agent_worker.py +307 -0
- agentpool_server/a2a_server/server.py +23 -18
- agentpool_server/acp_server/acp_agent.py +234 -181
- agentpool_server/acp_server/commands/acp_commands.py +151 -156
- agentpool_server/acp_server/commands/docs_commands/fetch_repo.py +18 -17
- agentpool_server/acp_server/event_converter.py +651 -0
- agentpool_server/acp_server/input_provider.py +53 -10
- agentpool_server/acp_server/server.py +24 -90
- agentpool_server/acp_server/session.py +173 -331
- agentpool_server/acp_server/session_manager.py +8 -34
- agentpool_server/agui_server/server.py +3 -1
- agentpool_server/mcp_server/server.py +5 -2
- agentpool_server/opencode_server/.rules +95 -0
- agentpool_server/opencode_server/ENDPOINTS.md +401 -0
- agentpool_server/opencode_server/OPENCODE_UI_TOOLS_COMPLETE.md +202 -0
- agentpool_server/opencode_server/__init__.py +19 -0
- agentpool_server/opencode_server/command_validation.py +172 -0
- agentpool_server/opencode_server/converters.py +975 -0
- agentpool_server/opencode_server/dependencies.py +24 -0
- agentpool_server/opencode_server/input_provider.py +421 -0
- agentpool_server/opencode_server/models/__init__.py +250 -0
- agentpool_server/opencode_server/models/agent.py +53 -0
- agentpool_server/opencode_server/models/app.py +72 -0
- agentpool_server/opencode_server/models/base.py +26 -0
- agentpool_server/opencode_server/models/common.py +23 -0
- agentpool_server/opencode_server/models/config.py +37 -0
- agentpool_server/opencode_server/models/events.py +821 -0
- agentpool_server/opencode_server/models/file.py +88 -0
- agentpool_server/opencode_server/models/mcp.py +44 -0
- agentpool_server/opencode_server/models/message.py +179 -0
- agentpool_server/opencode_server/models/parts.py +323 -0
- agentpool_server/opencode_server/models/provider.py +81 -0
- agentpool_server/opencode_server/models/pty.py +43 -0
- agentpool_server/opencode_server/models/question.py +56 -0
- agentpool_server/opencode_server/models/session.py +111 -0
- agentpool_server/opencode_server/routes/__init__.py +29 -0
- agentpool_server/opencode_server/routes/agent_routes.py +473 -0
- agentpool_server/opencode_server/routes/app_routes.py +202 -0
- agentpool_server/opencode_server/routes/config_routes.py +302 -0
- agentpool_server/opencode_server/routes/file_routes.py +571 -0
- agentpool_server/opencode_server/routes/global_routes.py +94 -0
- agentpool_server/opencode_server/routes/lsp_routes.py +319 -0
- agentpool_server/opencode_server/routes/message_routes.py +761 -0
- agentpool_server/opencode_server/routes/permission_routes.py +63 -0
- agentpool_server/opencode_server/routes/pty_routes.py +300 -0
- agentpool_server/opencode_server/routes/question_routes.py +128 -0
- agentpool_server/opencode_server/routes/session_routes.py +1276 -0
- agentpool_server/opencode_server/routes/tui_routes.py +139 -0
- agentpool_server/opencode_server/server.py +475 -0
- agentpool_server/opencode_server/state.py +151 -0
- agentpool_server/opencode_server/time_utils.py +8 -0
- agentpool_storage/__init__.py +12 -0
- agentpool_storage/base.py +184 -2
- agentpool_storage/claude_provider/ARCHITECTURE.md +433 -0
- agentpool_storage/claude_provider/__init__.py +42 -0
- agentpool_storage/claude_provider/provider.py +1089 -0
- agentpool_storage/file_provider.py +278 -15
- agentpool_storage/memory_provider.py +193 -12
- agentpool_storage/models.py +3 -0
- agentpool_storage/opencode_provider/ARCHITECTURE.md +386 -0
- agentpool_storage/opencode_provider/__init__.py +16 -0
- agentpool_storage/opencode_provider/helpers.py +414 -0
- agentpool_storage/opencode_provider/provider.py +895 -0
- agentpool_storage/project_store.py +325 -0
- agentpool_storage/session_store.py +26 -6
- agentpool_storage/sql_provider/__init__.py +4 -2
- agentpool_storage/sql_provider/models.py +48 -0
- agentpool_storage/sql_provider/sql_provider.py +269 -3
- agentpool_storage/sql_provider/utils.py +12 -13
- agentpool_storage/zed_provider/__init__.py +16 -0
- agentpool_storage/zed_provider/helpers.py +281 -0
- agentpool_storage/zed_provider/models.py +130 -0
- agentpool_storage/zed_provider/provider.py +442 -0
- agentpool_storage/zed_provider.py +803 -0
- agentpool_toolsets/__init__.py +0 -2
- agentpool_toolsets/builtin/__init__.py +2 -12
- agentpool_toolsets/builtin/code.py +96 -57
- agentpool_toolsets/builtin/debug.py +118 -48
- agentpool_toolsets/builtin/execution_environment.py +115 -230
- agentpool_toolsets/builtin/file_edit/file_edit.py +115 -7
- agentpool_toolsets/builtin/skills.py +9 -4
- agentpool_toolsets/builtin/subagent_tools.py +64 -51
- agentpool_toolsets/builtin/workers.py +4 -2
- agentpool_toolsets/composio_toolset.py +2 -2
- agentpool_toolsets/entry_points.py +3 -1
- agentpool_toolsets/fsspec_toolset/__init__.py +13 -1
- agentpool_toolsets/fsspec_toolset/diagnostics.py +860 -73
- agentpool_toolsets/fsspec_toolset/grep.py +99 -7
- agentpool_toolsets/fsspec_toolset/helpers.py +3 -2
- agentpool_toolsets/fsspec_toolset/image_utils.py +161 -0
- agentpool_toolsets/fsspec_toolset/toolset.py +500 -95
- agentpool_toolsets/mcp_discovery/__init__.py +5 -0
- agentpool_toolsets/mcp_discovery/data/mcp_servers.parquet +0 -0
- agentpool_toolsets/mcp_discovery/toolset.py +511 -0
- agentpool_toolsets/mcp_run_toolset.py +87 -12
- agentpool_toolsets/notifications.py +33 -33
- agentpool_toolsets/openapi.py +3 -1
- agentpool_toolsets/search_toolset.py +3 -1
- agentpool-2.1.9.dist-info/RECORD +0 -474
- agentpool_config/resources.py +0 -33
- agentpool_server/acp_server/acp_tools.py +0 -43
- agentpool_server/acp_server/commands/spawn.py +0 -210
- agentpool_storage/text_log_provider.py +0 -275
- agentpool_toolsets/builtin/agent_management.py +0 -239
- agentpool_toolsets/builtin/chain.py +0 -288
- agentpool_toolsets/builtin/history.py +0 -36
- agentpool_toolsets/builtin/integration.py +0 -85
- agentpool_toolsets/builtin/tool_management.py +0 -90
- agentpool_toolsets/builtin/user_interaction.py +0 -52
- agentpool_toolsets/semantic_memory_toolset.py +0 -536
- {agentpool-2.1.9.dist-info → agentpool-2.5.0.dist-info}/entry_points.txt +0 -0
- {agentpool-2.1.9.dist-info → agentpool-2.5.0.dist-info}/licenses/LICENSE +0 -0
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
"""Config and provider routes."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
from collections import defaultdict
|
|
6
|
+
from datetime import timedelta
|
|
7
|
+
from typing import TYPE_CHECKING
|
|
8
|
+
|
|
9
|
+
from fastapi import APIRouter
|
|
10
|
+
|
|
11
|
+
from agentpool_server.opencode_server.dependencies import StateDep
|
|
12
|
+
from agentpool_server.opencode_server.models import (
|
|
13
|
+
Config,
|
|
14
|
+
Mode,
|
|
15
|
+
Model,
|
|
16
|
+
ModelCost,
|
|
17
|
+
ModelLimit,
|
|
18
|
+
Provider,
|
|
19
|
+
ProviderListResponse,
|
|
20
|
+
ProvidersResponse,
|
|
21
|
+
)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
if TYPE_CHECKING:
|
|
25
|
+
from tokonomics.model_discovery.model_info import ModelInfo as TokoModelInfo
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
router = APIRouter(tags=["config"])
|
|
29
|
+
|
|
30
|
+
# Provider display names and environment variable mappings
|
|
31
|
+
PROVIDER_INFO: dict[str, tuple[str, list[str]]] = {
|
|
32
|
+
"anthropic": ("Anthropic", ["ANTHROPIC_API_KEY"]),
|
|
33
|
+
"openai": ("OpenAI", ["OPENAI_API_KEY"]),
|
|
34
|
+
"google": ("Google", ["GOOGLE_API_KEY", "GEMINI_API_KEY"]),
|
|
35
|
+
"mistral": ("Mistral", ["MISTRAL_API_KEY"]),
|
|
36
|
+
"groq": ("Groq", ["GROQ_API_KEY"]),
|
|
37
|
+
"deepseek": ("DeepSeek", ["DEEPSEEK_API_KEY"]),
|
|
38
|
+
"xai": ("xAI", ["XAI_API_KEY"]),
|
|
39
|
+
"together": ("Together AI", ["TOGETHER_API_KEY"]),
|
|
40
|
+
"perplexity": ("Perplexity", ["PERPLEXITY_API_KEY"]),
|
|
41
|
+
"cohere": ("Cohere", ["COHERE_API_KEY"]),
|
|
42
|
+
"fireworks": ("Fireworks AI", ["FIREWORKS_API_KEY"]),
|
|
43
|
+
"openrouter": ("OpenRouter", ["OPENROUTER_API_KEY"]),
|
|
44
|
+
"bedrock": ("AWS Bedrock", ["AWS_ACCESS_KEY_ID", "AWS_SECRET_ACCESS_KEY"]),
|
|
45
|
+
"azure": ("Azure OpenAI", ["AZURE_OPENAI_API_KEY", "AZURE_OPENAI_ENDPOINT"]),
|
|
46
|
+
"vertex": ("Google Vertex AI", ["GOOGLE_APPLICATION_CREDENTIALS"]),
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
def _convert_toko_model_to_opencode(model: TokoModelInfo) -> Model:
|
|
51
|
+
"""Convert a tokonomics ModelInfo to an OpenCode Model."""
|
|
52
|
+
# Convert pricing (tokonomics uses per-token, OpenCode uses per-million-token)
|
|
53
|
+
input_cost = 0.0
|
|
54
|
+
output_cost = 0.0
|
|
55
|
+
cache_read = None
|
|
56
|
+
cache_write = None
|
|
57
|
+
|
|
58
|
+
if model.pricing:
|
|
59
|
+
# tokonomics pricing is per-token, convert to per-million-tokens
|
|
60
|
+
if model.pricing.prompt is not None:
|
|
61
|
+
input_cost = model.pricing.prompt * 1_000_000
|
|
62
|
+
if model.pricing.completion is not None:
|
|
63
|
+
output_cost = model.pricing.completion * 1_000_000
|
|
64
|
+
if model.pricing.input_cache_read is not None:
|
|
65
|
+
cache_read = model.pricing.input_cache_read * 1_000_000
|
|
66
|
+
if model.pricing.input_cache_write is not None:
|
|
67
|
+
cache_write = model.pricing.input_cache_write * 1_000_000
|
|
68
|
+
|
|
69
|
+
cost = ModelCost(
|
|
70
|
+
input=input_cost,
|
|
71
|
+
output=output_cost,
|
|
72
|
+
cache_read=cache_read,
|
|
73
|
+
cache_write=cache_write,
|
|
74
|
+
)
|
|
75
|
+
|
|
76
|
+
# Convert limits
|
|
77
|
+
context = float(model.context_window) if model.context_window else 128000.0
|
|
78
|
+
output = float(model.max_output_tokens) if model.max_output_tokens else 4096.0
|
|
79
|
+
limit = ModelLimit(context=context, output=output)
|
|
80
|
+
|
|
81
|
+
# Determine capabilities from modalities and metadata
|
|
82
|
+
has_vision = "image" in model.input_modalities
|
|
83
|
+
has_reasoning = "reasoning" in model.output_modalities or "thinking" in model.name.lower()
|
|
84
|
+
|
|
85
|
+
# Format release date if available
|
|
86
|
+
release_date = ""
|
|
87
|
+
if model.created_at:
|
|
88
|
+
release_date = model.created_at.strftime("%Y-%m-%d")
|
|
89
|
+
|
|
90
|
+
return Model(
|
|
91
|
+
id=model.id,
|
|
92
|
+
name=model.name,
|
|
93
|
+
attachment=has_vision,
|
|
94
|
+
cost=cost,
|
|
95
|
+
limit=limit,
|
|
96
|
+
reasoning=has_reasoning,
|
|
97
|
+
release_date=release_date,
|
|
98
|
+
temperature=True,
|
|
99
|
+
tool_call=True, # Assume most models support tool calling
|
|
100
|
+
)
|
|
101
|
+
|
|
102
|
+
|
|
103
|
+
def _group_models_by_provider(
|
|
104
|
+
models: list[TokoModelInfo],
|
|
105
|
+
) -> dict[str, list[TokoModelInfo]]:
|
|
106
|
+
"""Group models by their provider."""
|
|
107
|
+
grouped: dict[str, list[TokoModelInfo]] = defaultdict(list)
|
|
108
|
+
for model in models:
|
|
109
|
+
# Skip embedding models - OpenCode is for chat/agent models
|
|
110
|
+
if model.is_embedding:
|
|
111
|
+
continue
|
|
112
|
+
grouped[model.provider].append(model)
|
|
113
|
+
return grouped
|
|
114
|
+
|
|
115
|
+
|
|
116
|
+
def _build_providers(models: list[TokoModelInfo]) -> list[Provider]:
|
|
117
|
+
"""Build Provider list from tokonomics models."""
|
|
118
|
+
grouped = _group_models_by_provider(models)
|
|
119
|
+
providers: list[Provider] = []
|
|
120
|
+
|
|
121
|
+
for provider_id, provider_models in sorted(grouped.items()):
|
|
122
|
+
# Get provider display info
|
|
123
|
+
display_name, env_vars = PROVIDER_INFO.get(
|
|
124
|
+
provider_id, (provider_id.title(), [f"{provider_id.upper()}_API_KEY"])
|
|
125
|
+
)
|
|
126
|
+
|
|
127
|
+
# Convert models to OpenCode format
|
|
128
|
+
models_dict: dict[str, Model] = {}
|
|
129
|
+
for toko_model in provider_models:
|
|
130
|
+
opencode_model = _convert_toko_model_to_opencode(toko_model)
|
|
131
|
+
models_dict[toko_model.id] = opencode_model
|
|
132
|
+
|
|
133
|
+
provider = Provider(
|
|
134
|
+
id=provider_id,
|
|
135
|
+
name=display_name,
|
|
136
|
+
env=env_vars,
|
|
137
|
+
models=models_dict,
|
|
138
|
+
)
|
|
139
|
+
providers.append(provider)
|
|
140
|
+
|
|
141
|
+
return providers
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
async def _get_available_models() -> list[TokoModelInfo]:
|
|
145
|
+
"""Fetch available models using tokonomics."""
|
|
146
|
+
from tokonomics.model_discovery import get_all_models
|
|
147
|
+
|
|
148
|
+
max_age = timedelta(days=7) # Cache for a week
|
|
149
|
+
return await get_all_models(max_age=max_age)
|
|
150
|
+
|
|
151
|
+
|
|
152
|
+
@router.get("/config")
|
|
153
|
+
async def get_config(state: StateDep) -> Config:
|
|
154
|
+
"""Get server configuration."""
|
|
155
|
+
import os
|
|
156
|
+
|
|
157
|
+
# Initialize config if not yet set
|
|
158
|
+
if state.config is None:
|
|
159
|
+
state.config = Config()
|
|
160
|
+
|
|
161
|
+
# Set a default model if not already configured
|
|
162
|
+
if state.config.model is None:
|
|
163
|
+
try:
|
|
164
|
+
# Get available models
|
|
165
|
+
toko_models = await state.agent.get_available_models()
|
|
166
|
+
if toko_models:
|
|
167
|
+
providers = _build_providers(toko_models)
|
|
168
|
+
|
|
169
|
+
# Find first connected provider and use its first model
|
|
170
|
+
for provider in providers:
|
|
171
|
+
if any(os.environ.get(env) for env in provider.env) and provider.models:
|
|
172
|
+
first_model = next(iter(provider.models.keys()))
|
|
173
|
+
state.config.model = f"{provider.id}/{first_model}"
|
|
174
|
+
break
|
|
175
|
+
except Exception: # noqa: BLE001
|
|
176
|
+
pass # If we can't set a default, that's okay
|
|
177
|
+
|
|
178
|
+
return state.config
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
@router.patch("/config")
|
|
182
|
+
async def update_config(state: StateDep, config_update: Config) -> Config:
|
|
183
|
+
"""Update server configuration.
|
|
184
|
+
|
|
185
|
+
Only updates fields that are provided (non-None).
|
|
186
|
+
Returns the complete updated config.
|
|
187
|
+
"""
|
|
188
|
+
# Initialize config if not yet set
|
|
189
|
+
if state.config is None:
|
|
190
|
+
state.config = Config()
|
|
191
|
+
|
|
192
|
+
# Update only the fields that were provided
|
|
193
|
+
update_data = config_update.model_dump(exclude_unset=True)
|
|
194
|
+
for field_name, value in update_data.items():
|
|
195
|
+
setattr(state.config, field_name, value)
|
|
196
|
+
|
|
197
|
+
return state.config
|
|
198
|
+
|
|
199
|
+
|
|
200
|
+
def _get_dummy_providers() -> list[Provider]:
|
|
201
|
+
"""Return a single dummy provider for testing."""
|
|
202
|
+
dummy_model = Model(
|
|
203
|
+
id="gpt-4o",
|
|
204
|
+
name="GPT-4o",
|
|
205
|
+
attachment=True,
|
|
206
|
+
cost=ModelCost(input=5.0, output=15.0),
|
|
207
|
+
limit=ModelLimit(context=128000.0, output=4096.0),
|
|
208
|
+
reasoning=False,
|
|
209
|
+
release_date="2024-05-13",
|
|
210
|
+
temperature=True,
|
|
211
|
+
tool_call=True,
|
|
212
|
+
)
|
|
213
|
+
dummy_provider = Provider(
|
|
214
|
+
id="openai",
|
|
215
|
+
name="OpenAI",
|
|
216
|
+
env=["OPENAI_API_KEY"],
|
|
217
|
+
models={"gpt-4o": dummy_model},
|
|
218
|
+
)
|
|
219
|
+
return [dummy_provider]
|
|
220
|
+
|
|
221
|
+
|
|
222
|
+
@router.get("/config/providers")
|
|
223
|
+
async def get_providers(state: StateDep) -> ProvidersResponse:
|
|
224
|
+
"""Get available providers and models from agent."""
|
|
225
|
+
import os
|
|
226
|
+
|
|
227
|
+
providers: list[Provider] = []
|
|
228
|
+
|
|
229
|
+
# Try to get models from the agent
|
|
230
|
+
try:
|
|
231
|
+
toko_models = await state.agent.get_available_models()
|
|
232
|
+
if toko_models:
|
|
233
|
+
providers = _build_providers(toko_models)
|
|
234
|
+
except Exception: # noqa: BLE001
|
|
235
|
+
pass # Fall through to dummy providers
|
|
236
|
+
|
|
237
|
+
# Fall back to dummy providers if no models available
|
|
238
|
+
if not providers:
|
|
239
|
+
providers = _get_dummy_providers()
|
|
240
|
+
|
|
241
|
+
# Build default models map: use first model for each connected provider
|
|
242
|
+
default_models: dict[str, str] = {}
|
|
243
|
+
connected_providers = [
|
|
244
|
+
provider.id for provider in providers if any(os.environ.get(env) for env in provider.env)
|
|
245
|
+
]
|
|
246
|
+
|
|
247
|
+
for provider in providers:
|
|
248
|
+
if provider.id in connected_providers and provider.models:
|
|
249
|
+
# Simply use the first available model
|
|
250
|
+
default_models[provider.id] = next(iter(provider.models.keys()))
|
|
251
|
+
|
|
252
|
+
return ProvidersResponse(providers=providers, default=default_models)
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
@router.get("/provider")
|
|
256
|
+
async def list_providers(state: StateDep) -> ProviderListResponse:
|
|
257
|
+
"""List all providers."""
|
|
258
|
+
import os
|
|
259
|
+
|
|
260
|
+
providers: list[Provider] = []
|
|
261
|
+
|
|
262
|
+
# Try to get models from the agent
|
|
263
|
+
try:
|
|
264
|
+
toko_models = await state.agent.get_available_models()
|
|
265
|
+
if toko_models:
|
|
266
|
+
providers = _build_providers(toko_models)
|
|
267
|
+
except Exception: # noqa: BLE001
|
|
268
|
+
pass # Fall through to dummy providers
|
|
269
|
+
|
|
270
|
+
# Fall back to dummy providers if no models available
|
|
271
|
+
if not providers:
|
|
272
|
+
providers = _get_dummy_providers()
|
|
273
|
+
|
|
274
|
+
# Determine which providers are "connected" based on env vars
|
|
275
|
+
connected = [
|
|
276
|
+
provider.id for provider in providers if any(os.environ.get(env) for env in provider.env)
|
|
277
|
+
]
|
|
278
|
+
|
|
279
|
+
# Build default models map: use first model for each connected provider
|
|
280
|
+
default_models: dict[str, str] = {}
|
|
281
|
+
for provider in providers:
|
|
282
|
+
if provider.id in connected and provider.models:
|
|
283
|
+
# Simply use the first available model
|
|
284
|
+
default_models[provider.id] = next(iter(provider.models.keys()))
|
|
285
|
+
|
|
286
|
+
return ProviderListResponse(
|
|
287
|
+
all=providers,
|
|
288
|
+
default=default_models,
|
|
289
|
+
connected=connected,
|
|
290
|
+
)
|
|
291
|
+
|
|
292
|
+
|
|
293
|
+
@router.get("/mode")
|
|
294
|
+
async def list_modes(state: StateDep) -> list[Mode]:
|
|
295
|
+
"""List available modes."""
|
|
296
|
+
_ = state # unused for now
|
|
297
|
+
return [
|
|
298
|
+
Mode(
|
|
299
|
+
name="default",
|
|
300
|
+
tools={},
|
|
301
|
+
)
|
|
302
|
+
]
|