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,89 @@
|
|
|
1
|
+
"""CLI entry point for the ACP WebSocket server bridge.
|
|
2
|
+
|
|
3
|
+
Usage:
|
|
4
|
+
python -m acp.bridge.ws_server_cli "uv run agentpool serve-acp"
|
|
5
|
+
python -m acp.bridge.ws_server_cli --port 8765 -- uv run agentpool serve-acp
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
from __future__ import annotations
|
|
9
|
+
|
|
10
|
+
import argparse
|
|
11
|
+
import contextlib
|
|
12
|
+
import logging
|
|
13
|
+
import sys
|
|
14
|
+
|
|
15
|
+
import anyio
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def main() -> None:
|
|
19
|
+
"""Run the ACP WebSocket server bridge from command line."""
|
|
20
|
+
parser = argparse.ArgumentParser(
|
|
21
|
+
description="Bridge a stdio ACP agent to WebSocket transport.",
|
|
22
|
+
epilog=(
|
|
23
|
+
"Examples:\n"
|
|
24
|
+
' acp-ws-server "uv run agentpool serve-acp"\n'
|
|
25
|
+
" acp-ws-server --port 8765 -- uv run agentpool serve-acp\n"
|
|
26
|
+
" acp-ws-server -H 0.0.0.0 -p 9000 -- uv run my-agent\n"
|
|
27
|
+
),
|
|
28
|
+
formatter_class=argparse.RawTextHelpFormatter,
|
|
29
|
+
)
|
|
30
|
+
|
|
31
|
+
parser.add_argument("command", help="Command to spawn the ACP agent.")
|
|
32
|
+
parser.add_argument("args", nargs="*", help="Arguments for the agent command.")
|
|
33
|
+
parser.add_argument(
|
|
34
|
+
"-p",
|
|
35
|
+
"--port",
|
|
36
|
+
type=int,
|
|
37
|
+
default=8765,
|
|
38
|
+
help="Port for the WebSocket server. Default: 8765",
|
|
39
|
+
)
|
|
40
|
+
parser.add_argument(
|
|
41
|
+
"-H",
|
|
42
|
+
"--host",
|
|
43
|
+
default="localhost",
|
|
44
|
+
help="Host to bind the server to. Default: localhost",
|
|
45
|
+
)
|
|
46
|
+
parser.add_argument(
|
|
47
|
+
"--log-level",
|
|
48
|
+
choices=["DEBUG", "INFO", "WARNING", "ERROR"],
|
|
49
|
+
default="INFO",
|
|
50
|
+
help="Log level. Default: INFO",
|
|
51
|
+
)
|
|
52
|
+
parser.add_argument(
|
|
53
|
+
"--cwd",
|
|
54
|
+
default=None,
|
|
55
|
+
help="Working directory for the agent subprocess.",
|
|
56
|
+
)
|
|
57
|
+
|
|
58
|
+
parsed = parser.parse_args()
|
|
59
|
+
|
|
60
|
+
if not parsed.command:
|
|
61
|
+
parser.print_help()
|
|
62
|
+
sys.exit(1)
|
|
63
|
+
|
|
64
|
+
logging.basicConfig(
|
|
65
|
+
level=getattr(logging, parsed.log_level),
|
|
66
|
+
format="%(asctime)s [%(levelname)s] %(name)s: %(message)s",
|
|
67
|
+
)
|
|
68
|
+
# Reduce websockets noise
|
|
69
|
+
logging.getLogger("websockets").setLevel(logging.WARNING)
|
|
70
|
+
|
|
71
|
+
from acp.bridge.ws_server import ACPWebSocketServer
|
|
72
|
+
|
|
73
|
+
server = ACPWebSocketServer(
|
|
74
|
+
command=parsed.command,
|
|
75
|
+
args=parsed.args,
|
|
76
|
+
host=parsed.host,
|
|
77
|
+
port=parsed.port,
|
|
78
|
+
cwd=parsed.cwd,
|
|
79
|
+
)
|
|
80
|
+
|
|
81
|
+
print(f"🔗 ACP WebSocket bridge starting on ws://{parsed.host}:{parsed.port}")
|
|
82
|
+
print(f" Agent command: {parsed.command} {' '.join(parsed.args)}")
|
|
83
|
+
|
|
84
|
+
with contextlib.suppress(KeyboardInterrupt):
|
|
85
|
+
anyio.run(server.serve)
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
if __name__ == "__main__":
|
|
89
|
+
main()
|
acp/client/connection.py
CHANGED
|
@@ -7,8 +7,35 @@ from typing import TYPE_CHECKING, Any, Self
|
|
|
7
7
|
|
|
8
8
|
import logfire
|
|
9
9
|
|
|
10
|
+
from acp.agent.protocol import Agent
|
|
11
|
+
from acp.connection import Connection
|
|
12
|
+
from acp.exceptions import RequestError
|
|
13
|
+
from acp.schema import (
|
|
14
|
+
AuthenticateResponse,
|
|
15
|
+
CreateTerminalRequest,
|
|
16
|
+
ForkSessionResponse,
|
|
17
|
+
InitializeResponse,
|
|
18
|
+
KillTerminalCommandRequest,
|
|
19
|
+
ListSessionsResponse,
|
|
20
|
+
LoadSessionResponse,
|
|
21
|
+
NewSessionResponse,
|
|
22
|
+
PromptResponse,
|
|
23
|
+
ReadTextFileRequest,
|
|
24
|
+
ReleaseTerminalRequest,
|
|
25
|
+
RequestPermissionRequest,
|
|
26
|
+
ResumeSessionResponse,
|
|
27
|
+
SessionNotification,
|
|
28
|
+
SetSessionConfigOptionResponse,
|
|
29
|
+
SetSessionModelResponse,
|
|
30
|
+
SetSessionModeResponse,
|
|
31
|
+
TerminalOutputRequest,
|
|
32
|
+
WaitForTerminalExitRequest,
|
|
33
|
+
WriteTextFileRequest,
|
|
34
|
+
)
|
|
35
|
+
|
|
10
36
|
|
|
11
37
|
if TYPE_CHECKING:
|
|
38
|
+
from collections.abc import Callable
|
|
12
39
|
from types import TracebackType
|
|
13
40
|
|
|
14
41
|
from anyio.abc import ByteReceiveStream, ByteSendStream
|
|
@@ -31,6 +58,7 @@ if TYPE_CHECKING:
|
|
|
31
58
|
ReleaseTerminalResponse,
|
|
32
59
|
RequestPermissionResponse,
|
|
33
60
|
ResumeSessionRequest,
|
|
61
|
+
SetSessionConfigOptionRequest,
|
|
34
62
|
SetSessionModelRequest,
|
|
35
63
|
SetSessionModeRequest,
|
|
36
64
|
TerminalOutputResponse,
|
|
@@ -38,35 +66,6 @@ if TYPE_CHECKING:
|
|
|
38
66
|
WriteTextFileResponse,
|
|
39
67
|
)
|
|
40
68
|
|
|
41
|
-
from acp.agent.protocol import Agent
|
|
42
|
-
from acp.connection import Connection
|
|
43
|
-
from acp.exceptions import RequestError
|
|
44
|
-
from acp.schema import (
|
|
45
|
-
AuthenticateResponse,
|
|
46
|
-
CreateTerminalRequest,
|
|
47
|
-
ForkSessionResponse,
|
|
48
|
-
InitializeResponse,
|
|
49
|
-
KillTerminalCommandRequest,
|
|
50
|
-
ListSessionsResponse,
|
|
51
|
-
LoadSessionResponse,
|
|
52
|
-
NewSessionResponse,
|
|
53
|
-
PromptResponse,
|
|
54
|
-
ReadTextFileRequest,
|
|
55
|
-
ReleaseTerminalRequest,
|
|
56
|
-
RequestPermissionRequest,
|
|
57
|
-
ResumeSessionResponse,
|
|
58
|
-
SessionNotification,
|
|
59
|
-
SetSessionModelResponse,
|
|
60
|
-
SetSessionModeResponse,
|
|
61
|
-
TerminalOutputRequest,
|
|
62
|
-
WaitForTerminalExitRequest,
|
|
63
|
-
WriteTextFileRequest,
|
|
64
|
-
)
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
if TYPE_CHECKING:
|
|
68
|
-
from collections.abc import Callable
|
|
69
|
-
|
|
70
69
|
|
|
71
70
|
class ClientSideConnection(Agent):
|
|
72
71
|
"""Client-side connection.
|
|
@@ -151,6 +150,16 @@ class ClientSideConnection(Agent):
|
|
|
151
150
|
payload = resp if isinstance(resp, dict) else {}
|
|
152
151
|
return SetSessionModelResponse.model_validate(payload)
|
|
153
152
|
|
|
153
|
+
async def set_session_config_option(
|
|
154
|
+
self, params: SetSessionConfigOptionRequest
|
|
155
|
+
) -> SetSessionConfigOptionResponse:
|
|
156
|
+
dct = params.model_dump(
|
|
157
|
+
mode="json", by_alias=True, exclude_none=True, exclude_defaults=True
|
|
158
|
+
)
|
|
159
|
+
resp = await self._conn.send_request("session/set_config_option", dct)
|
|
160
|
+
payload = resp if isinstance(resp, dict) else {}
|
|
161
|
+
return SetSessionConfigOptionResponse.model_validate(payload)
|
|
162
|
+
|
|
154
163
|
async def authenticate(self, params: AuthenticateRequest) -> AuthenticateResponse:
|
|
155
164
|
dct = params.model_dump(
|
|
156
165
|
mode="json", by_alias=True, exclude_none=True, exclude_defaults=True
|
|
@@ -9,9 +9,10 @@ from __future__ import annotations
|
|
|
9
9
|
from pathlib import Path
|
|
10
10
|
from typing import TYPE_CHECKING, Any
|
|
11
11
|
|
|
12
|
+
import structlog
|
|
13
|
+
|
|
12
14
|
from acp.client import Client
|
|
13
15
|
from acp.schema import ReadTextFileResponse, RequestPermissionResponse, WriteTextFileResponse
|
|
14
|
-
from agentpool import log
|
|
15
16
|
|
|
16
17
|
|
|
17
18
|
if TYPE_CHECKING:
|
|
@@ -34,7 +35,7 @@ if TYPE_CHECKING:
|
|
|
34
35
|
WriteTextFileRequest,
|
|
35
36
|
)
|
|
36
37
|
|
|
37
|
-
logger =
|
|
38
|
+
logger = structlog.get_logger(__name__)
|
|
38
39
|
|
|
39
40
|
|
|
40
41
|
class DefaultACPClient(Client):
|
|
@@ -12,6 +12,7 @@ from typing import TYPE_CHECKING, Any
|
|
|
12
12
|
import uuid
|
|
13
13
|
|
|
14
14
|
from anyenv import ProcessManager
|
|
15
|
+
import structlog
|
|
15
16
|
|
|
16
17
|
from acp.client.protocol import Client
|
|
17
18
|
from acp.schema import (
|
|
@@ -24,7 +25,6 @@ from acp.schema import (
|
|
|
24
25
|
WaitForTerminalExitResponse,
|
|
25
26
|
WriteTextFileResponse,
|
|
26
27
|
)
|
|
27
|
-
from agentpool.log import get_logger
|
|
28
28
|
|
|
29
29
|
|
|
30
30
|
if TYPE_CHECKING:
|
|
@@ -40,7 +40,7 @@ if TYPE_CHECKING:
|
|
|
40
40
|
WriteTextFileRequest,
|
|
41
41
|
)
|
|
42
42
|
|
|
43
|
-
logger = get_logger(__name__)
|
|
43
|
+
logger = structlog.get_logger(__name__)
|
|
44
44
|
|
|
45
45
|
|
|
46
46
|
class HeadlessACPClient(Client):
|
acp/connection.py
CHANGED
|
@@ -15,6 +15,7 @@ import anyenv
|
|
|
15
15
|
import anyio
|
|
16
16
|
from anyio.streams.text import TextReceiveStream
|
|
17
17
|
from pydantic import BaseModel, ValidationError
|
|
18
|
+
import structlog
|
|
18
19
|
|
|
19
20
|
from acp.exceptions import RequestError
|
|
20
21
|
from acp.task import (
|
|
@@ -31,7 +32,6 @@ from acp.task import (
|
|
|
31
32
|
RpcTaskKind,
|
|
32
33
|
TaskSupervisor,
|
|
33
34
|
)
|
|
34
|
-
from agentpool import log
|
|
35
35
|
|
|
36
36
|
|
|
37
37
|
if TYPE_CHECKING:
|
|
@@ -49,7 +49,7 @@ DispatcherFactory = Callable[
|
|
|
49
49
|
]
|
|
50
50
|
|
|
51
51
|
|
|
52
|
-
logger =
|
|
52
|
+
logger = structlog.get_logger(__name__)
|
|
53
53
|
|
|
54
54
|
|
|
55
55
|
StreamDirection = Literal["incoming", "outgoing"]
|
acp/notifications.py
CHANGED
|
@@ -6,6 +6,7 @@ from collections.abc import Sequence
|
|
|
6
6
|
from typing import TYPE_CHECKING, Any, assert_never
|
|
7
7
|
|
|
8
8
|
from pydantic_ai import ModelRequest, ModelResponse, ToolReturnPart, UserPromptPart
|
|
9
|
+
import structlog
|
|
9
10
|
|
|
10
11
|
from acp.schema import (
|
|
11
12
|
AgentMessageChunk,
|
|
@@ -33,7 +34,7 @@ from acp.schema import (
|
|
|
33
34
|
from acp.schema.tool_call import ToolCallLocation
|
|
34
35
|
from acp.tool_call_reporter import ToolCallReporter
|
|
35
36
|
from acp.utils import generate_tool_title, infer_tool_kind, to_acp_content_blocks
|
|
36
|
-
from agentpool.
|
|
37
|
+
from agentpool.utils.pydantic_ai_helpers import safe_args_as_dict
|
|
37
38
|
|
|
38
39
|
|
|
39
40
|
if TYPE_CHECKING:
|
|
@@ -52,7 +53,7 @@ if TYPE_CHECKING:
|
|
|
52
53
|
|
|
53
54
|
ContentType = Sequence[ToolCallContent | str]
|
|
54
55
|
|
|
55
|
-
logger = get_logger(__name__)
|
|
56
|
+
logger = structlog.get_logger(__name__)
|
|
56
57
|
|
|
57
58
|
|
|
58
59
|
class ACPNotifications:
|
|
@@ -133,11 +134,11 @@ class ACPNotifications:
|
|
|
133
134
|
async def tool_call(
|
|
134
135
|
self,
|
|
135
136
|
tool_name: str,
|
|
137
|
+
tool_call_id: str,
|
|
136
138
|
*,
|
|
137
139
|
tool_input: dict[str, Any],
|
|
138
140
|
tool_output: Any,
|
|
139
141
|
status: ToolCallStatus = "completed",
|
|
140
|
-
tool_call_id: str | None = None,
|
|
141
142
|
) -> None:
|
|
142
143
|
"""Send tool execution as ACP tool call update.
|
|
143
144
|
|
|
@@ -175,11 +176,10 @@ class ACPNotifications:
|
|
|
175
176
|
|
|
176
177
|
# Generate a descriptive title from tool name and inputs
|
|
177
178
|
title = generate_tool_title(tool_name, tool_input)
|
|
178
|
-
|
|
179
179
|
# Use appropriate notification type based on status
|
|
180
180
|
if status == "pending":
|
|
181
181
|
await self.tool_call_start(
|
|
182
|
-
tool_call_id=tool_call_id
|
|
182
|
+
tool_call_id=tool_call_id,
|
|
183
183
|
title=title,
|
|
184
184
|
kind=infer_tool_kind(tool_name),
|
|
185
185
|
locations=locations or None,
|
|
@@ -189,7 +189,7 @@ class ACPNotifications:
|
|
|
189
189
|
else:
|
|
190
190
|
# For in_progress, completed, and failed statuses
|
|
191
191
|
await self.tool_call_progress(
|
|
192
|
-
tool_call_id=tool_call_id
|
|
192
|
+
tool_call_id=tool_call_id,
|
|
193
193
|
title=title,
|
|
194
194
|
status=status,
|
|
195
195
|
locations=locations or None,
|
|
@@ -606,36 +606,24 @@ class ACPNotifications:
|
|
|
606
606
|
match block:
|
|
607
607
|
case TextContentBlock(text=text):
|
|
608
608
|
await self.send_user_message(text)
|
|
609
|
-
case ImageContentBlock() as img_block:
|
|
609
|
+
case ImageContentBlock(annotations=annots) as img_block:
|
|
610
610
|
await self.send_user_image(
|
|
611
611
|
data=img_block.data,
|
|
612
612
|
mime_type=img_block.mime_type,
|
|
613
613
|
uri=img_block.uri,
|
|
614
|
-
audience=
|
|
615
|
-
if
|
|
616
|
-
else None,
|
|
617
|
-
last_modified=img_block.annotations.last_modified
|
|
618
|
-
if img_block.annotations
|
|
619
|
-
else None,
|
|
620
|
-
priority=img_block.annotations.priority
|
|
621
|
-
if img_block.annotations
|
|
622
|
-
else None,
|
|
614
|
+
audience=annots.audience if annots else None,
|
|
615
|
+
last_modified=annots.last_modified if annots else None,
|
|
616
|
+
priority=annots.priority if annots else None,
|
|
623
617
|
)
|
|
624
|
-
case AudioContentBlock() as audio_block:
|
|
618
|
+
case AudioContentBlock(annotations=annots) as audio_block:
|
|
625
619
|
await self.send_user_audio(
|
|
626
620
|
data=audio_block.data,
|
|
627
621
|
mime_type=audio_block.mime_type,
|
|
628
|
-
audience=
|
|
629
|
-
if
|
|
630
|
-
else None,
|
|
631
|
-
last_modified=audio_block.annotations.last_modified
|
|
632
|
-
if audio_block.annotations
|
|
633
|
-
else None,
|
|
634
|
-
priority=audio_block.annotations.priority
|
|
635
|
-
if audio_block.annotations
|
|
636
|
-
else None,
|
|
622
|
+
audience=annots.audience if annots else None,
|
|
623
|
+
last_modified=annots.last_modified if annots else None,
|
|
624
|
+
priority=annots.priority if annots else None,
|
|
637
625
|
)
|
|
638
|
-
case ResourceContentBlock() as resource_block:
|
|
626
|
+
case ResourceContentBlock(annotations=annots) as resource_block:
|
|
639
627
|
await self.send_user_resource(
|
|
640
628
|
uri=resource_block.uri,
|
|
641
629
|
name=resource_block.name,
|
|
@@ -643,15 +631,9 @@ class ACPNotifications:
|
|
|
643
631
|
mime_type=resource_block.mime_type,
|
|
644
632
|
size=resource_block.size,
|
|
645
633
|
title=resource_block.title,
|
|
646
|
-
audience=
|
|
647
|
-
if
|
|
648
|
-
else None,
|
|
649
|
-
last_modified=resource_block.annotations.last_modified
|
|
650
|
-
if resource_block.annotations
|
|
651
|
-
else None,
|
|
652
|
-
priority=resource_block.annotations.priority
|
|
653
|
-
if resource_block.annotations
|
|
654
|
-
else None,
|
|
634
|
+
audience=annots.audience if annots else None,
|
|
635
|
+
last_modified=annots.last_modified if annots else None,
|
|
636
|
+
priority=annots.priority if annots else None,
|
|
655
637
|
)
|
|
656
638
|
case EmbeddedResourceContentBlock() as embedded_block:
|
|
657
639
|
# Handle embedded resources with proper
|
|
@@ -677,14 +659,12 @@ class ACPNotifications:
|
|
|
677
659
|
tool_input = self._tool_call_inputs.get(tool_call_id, {})
|
|
678
660
|
await self.tool_call(
|
|
679
661
|
tool_name=tool_name,
|
|
662
|
+
tool_call_id=tool_call_id,
|
|
680
663
|
tool_input=tool_input,
|
|
681
664
|
tool_output=converted_content,
|
|
682
665
|
status="completed",
|
|
683
|
-
tool_call_id=tool_call_id,
|
|
684
666
|
)
|
|
685
|
-
# Clean up stored input
|
|
686
667
|
self._tool_call_inputs.pop(tool_call_id, None)
|
|
687
|
-
|
|
688
668
|
case _:
|
|
689
669
|
typ = type(part).__name__
|
|
690
670
|
self.log.debug("Unhandled request part type", part_type=typ)
|
|
@@ -703,7 +683,7 @@ class ACPNotifications:
|
|
|
703
683
|
|
|
704
684
|
case ToolCallPart(tool_call_id=tool_call_id):
|
|
705
685
|
# Store tool call inputs for later use with ToolReturnPart
|
|
706
|
-
tool_input = part
|
|
686
|
+
tool_input = safe_args_as_dict(part)
|
|
707
687
|
self._tool_call_inputs[tool_call_id] = tool_input
|
|
708
688
|
# Skip sending notification - ACP protocol overrides previous
|
|
709
689
|
# tool call state
|
|
@@ -753,16 +733,6 @@ class ACPNotifications:
|
|
|
753
733
|
notification = SessionNotification(session_id=self.id, update=update)
|
|
754
734
|
await self.client.session_update(notification) # pyright: ignore[reportArgumentType] # ty: ignore[invalid-argument-type]
|
|
755
735
|
|
|
756
|
-
# async def update_session_model(self, model_id: str) -> None:
|
|
757
|
-
# """Send a session model update notification.
|
|
758
|
-
|
|
759
|
-
# Args:
|
|
760
|
-
# model_id: Unique identifier for the model
|
|
761
|
-
# """
|
|
762
|
-
# update = CurrentModelUpdate(current_model_id=model_id)
|
|
763
|
-
# notification = SessionNotification(session_id=self.id, update=update)
|
|
764
|
-
# await self.client.session_update(notification)
|
|
765
|
-
|
|
766
736
|
async def send_agent_audio(
|
|
767
737
|
self,
|
|
768
738
|
data: str | bytes,
|
acp/schema/__init__.py
CHANGED
|
@@ -96,6 +96,7 @@ from acp.schema.notifications import (
|
|
|
96
96
|
from acp.schema.session_state import (
|
|
97
97
|
ModelInfo,
|
|
98
98
|
SessionConfigOption,
|
|
99
|
+
SessionConfigOptionCategory,
|
|
99
100
|
SessionConfigSelect,
|
|
100
101
|
SessionConfigSelectGroup,
|
|
101
102
|
SessionConfigSelectOption,
|
|
@@ -222,6 +223,7 @@ __all__ = [
|
|
|
222
223
|
"ResumeSessionResponse",
|
|
223
224
|
"SessionCapabilities",
|
|
224
225
|
"SessionConfigOption",
|
|
226
|
+
"SessionConfigOptionCategory",
|
|
225
227
|
"SessionConfigSelect",
|
|
226
228
|
"SessionConfigSelectGroup",
|
|
227
229
|
"SessionConfigSelectOption",
|
acp/schema/agent_responses.py
CHANGED
|
@@ -9,6 +9,7 @@ from acp.schema.base import Response
|
|
|
9
9
|
from acp.schema.capabilities import AgentCapabilities
|
|
10
10
|
from acp.schema.common import AuthMethod, Implementation # noqa: TC001
|
|
11
11
|
from acp.schema.session_state import ( # noqa: TC001
|
|
12
|
+
SessionConfigOption,
|
|
12
13
|
SessionInfo,
|
|
13
14
|
SessionModelState,
|
|
14
15
|
SessionModeState,
|
|
@@ -58,6 +59,14 @@ class NewSessionResponse(Response):
|
|
|
58
59
|
See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
|
|
59
60
|
"""
|
|
60
61
|
|
|
62
|
+
config_options: Sequence[SessionConfigOption] | None = None
|
|
63
|
+
"""**UNSTABLE**
|
|
64
|
+
|
|
65
|
+
Configuration options for this session.
|
|
66
|
+
|
|
67
|
+
See RFD: Session Config Options
|
|
68
|
+
"""
|
|
69
|
+
|
|
61
70
|
session_id: str
|
|
62
71
|
"""Unique identifier for the created session.
|
|
63
72
|
|
|
@@ -82,6 +91,9 @@ class LoadSessionResponse(Response):
|
|
|
82
91
|
See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
|
|
83
92
|
"""
|
|
84
93
|
|
|
94
|
+
config_options: Sequence[SessionConfigOption] = []
|
|
95
|
+
"""The full list of config options with updated values."""
|
|
96
|
+
|
|
85
97
|
|
|
86
98
|
class ForkSessionResponse(Response):
|
|
87
99
|
"""**UNSTABLE**: This capability is not part of the spec yet.
|
|
@@ -106,6 +118,9 @@ class ForkSessionResponse(Response):
|
|
|
106
118
|
session_id: str
|
|
107
119
|
"""Unique identifier for the newly created forked session."""
|
|
108
120
|
|
|
121
|
+
config_options: Sequence[SessionConfigOption] = []
|
|
122
|
+
"""The full list of config options with updated values."""
|
|
123
|
+
|
|
109
124
|
|
|
110
125
|
class ResumeSessionResponse(Response):
|
|
111
126
|
"""**UNSTABLE**: This capability is not part of the spec yet.
|
|
@@ -127,6 +142,9 @@ class ResumeSessionResponse(Response):
|
|
|
127
142
|
See protocol docs: [Session Modes](https://agentclientprotocol.com/protocol/session-modes)
|
|
128
143
|
"""
|
|
129
144
|
|
|
145
|
+
config_options: Sequence[SessionConfigOption] = []
|
|
146
|
+
"""The full list of config options with updated values."""
|
|
147
|
+
|
|
130
148
|
|
|
131
149
|
class SetSessionModeResponse(Response):
|
|
132
150
|
"""Response to `session/set_mode` method."""
|
|
@@ -135,6 +153,9 @@ class SetSessionModeResponse(Response):
|
|
|
135
153
|
class SetSessionConfigOptionResponse(Response):
|
|
136
154
|
"""Response to `session/set_config_option` method."""
|
|
137
155
|
|
|
156
|
+
config_options: Sequence[SessionConfigOption] = []
|
|
157
|
+
"""The full list of config options with updated values."""
|
|
158
|
+
|
|
138
159
|
|
|
139
160
|
class PromptResponse(Response):
|
|
140
161
|
"""Response from processing a user prompt.
|
acp/schema/client_requests.py
CHANGED
|
@@ -33,7 +33,7 @@ class NewSessionRequest(Request):
|
|
|
33
33
|
cwd: str
|
|
34
34
|
"""The working directory for this session. Must be an absolute path."""
|
|
35
35
|
|
|
36
|
-
mcp_servers: Sequence[McpServer]
|
|
36
|
+
mcp_servers: Sequence[McpServer] | None = None
|
|
37
37
|
"""List of MCP (Model Context Protocol) servers the agent should connect to."""
|
|
38
38
|
|
|
39
39
|
|
|
@@ -48,7 +48,7 @@ class LoadSessionRequest(Request):
|
|
|
48
48
|
cwd: str
|
|
49
49
|
"""The working directory for this session."""
|
|
50
50
|
|
|
51
|
-
mcp_servers: Sequence[McpServer]
|
|
51
|
+
mcp_servers: Sequence[McpServer] | None = None
|
|
52
52
|
"""List of MCP servers to connect to for this session."""
|
|
53
53
|
|
|
54
54
|
session_id: str
|
|
@@ -176,7 +176,7 @@ class SetSessionConfigOptionRequest(Request):
|
|
|
176
176
|
session_id: str
|
|
177
177
|
"""The ID of the session to set the config option for."""
|
|
178
178
|
|
|
179
|
-
|
|
179
|
+
value: str = Field(serialization_alias="valueId")
|
|
180
180
|
"""The ID of the value to set for this configuration option."""
|
|
181
181
|
|
|
182
182
|
|
acp/schema/session_state.py
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
from __future__ import annotations
|
|
4
4
|
|
|
5
5
|
from collections.abc import Sequence
|
|
6
|
-
from typing import
|
|
6
|
+
from typing import Literal
|
|
7
7
|
|
|
8
8
|
from pydantic import Field
|
|
9
9
|
|
|
@@ -21,6 +21,24 @@ SessionConfigGroupId = str
|
|
|
21
21
|
"""Unique identifier for a group of values within a configuration option."""
|
|
22
22
|
|
|
23
23
|
|
|
24
|
+
SessionConfigOptionCategory = Literal["mode", "model", "thought_level", "other"]
|
|
25
|
+
"""**UNSTABLE**: This capability is not part of the spec yet.
|
|
26
|
+
|
|
27
|
+
Semantic category for a session configuration option.
|
|
28
|
+
|
|
29
|
+
This is intended to help Clients distinguish broadly common selectors (e.g. model selector vs
|
|
30
|
+
session mode selector vs thought/reasoning level) for UX purposes (keyboard shortcuts, icons,
|
|
31
|
+
placement). It MUST NOT be required for correctness. Clients MUST handle missing or unknown
|
|
32
|
+
categories gracefully (treat as `other`).
|
|
33
|
+
|
|
34
|
+
Values:
|
|
35
|
+
- "mode": Session mode selector
|
|
36
|
+
- "model": Model selector
|
|
37
|
+
- "thought_level": Thought/reasoning level selector
|
|
38
|
+
- "other": Unknown / uncategorized selector
|
|
39
|
+
"""
|
|
40
|
+
|
|
41
|
+
|
|
24
42
|
class ModelInfo(AnnotatedObject):
|
|
25
43
|
"""**UNSTABLE**: This capability is not part of the spec yet.
|
|
26
44
|
|
|
@@ -98,63 +116,79 @@ class SessionInfo(AnnotatedObject):
|
|
|
98
116
|
class SessionConfigSelectOption(AnnotatedObject):
|
|
99
117
|
"""A possible value for a configuration selector."""
|
|
100
118
|
|
|
101
|
-
|
|
102
|
-
"""Unique identifier for this value."""
|
|
119
|
+
value: SessionConfigValueId
|
|
120
|
+
"""Unique identifier for this option value."""
|
|
103
121
|
|
|
104
|
-
|
|
105
|
-
"""Human-readable label for this value."""
|
|
122
|
+
name: str
|
|
123
|
+
"""Human-readable label for this option value."""
|
|
106
124
|
|
|
107
125
|
description: str | None = None
|
|
108
|
-
"""Optional description
|
|
126
|
+
"""Optional description for this option value."""
|
|
109
127
|
|
|
110
128
|
|
|
111
129
|
class SessionConfigSelectGroup(AnnotatedObject):
|
|
112
130
|
"""A group of possible values for a configuration selector."""
|
|
113
131
|
|
|
114
|
-
|
|
132
|
+
group: SessionConfigGroupId
|
|
115
133
|
"""Unique identifier for this group."""
|
|
116
134
|
|
|
117
|
-
|
|
135
|
+
name: str
|
|
118
136
|
"""Human-readable label for this group."""
|
|
119
137
|
|
|
120
138
|
options: Sequence[SessionConfigSelectOption]
|
|
121
|
-
"""The
|
|
139
|
+
"""The set of option values in this group."""
|
|
122
140
|
|
|
123
141
|
|
|
124
|
-
SessionConfigSelectOptions =
|
|
142
|
+
SessionConfigSelectOptions = (
|
|
143
|
+
Sequence[SessionConfigSelectOption] | Sequence[SessionConfigSelectGroup]
|
|
144
|
+
)
|
|
125
145
|
"""The possible values for a configuration selector, optionally organized into groups."""
|
|
126
146
|
|
|
127
147
|
|
|
128
148
|
class SessionConfigSelect(AnnotatedObject):
|
|
129
|
-
"""A
|
|
149
|
+
"""A single-value selector (dropdown) session configuration option payload."""
|
|
150
|
+
|
|
151
|
+
current_value: SessionConfigValueId
|
|
152
|
+
"""The currently selected value."""
|
|
153
|
+
|
|
154
|
+
options: SessionConfigSelectOptions
|
|
155
|
+
"""The set of selectable options."""
|
|
130
156
|
|
|
131
|
-
|
|
132
|
-
|
|
157
|
+
|
|
158
|
+
class SessionConfigKind(AnnotatedObject):
|
|
159
|
+
"""Type-specific session configuration option payload."""
|
|
133
160
|
|
|
134
161
|
type: Literal["select"] = Field(default="select", init=False)
|
|
135
162
|
"""Discriminator for the config option type."""
|
|
136
163
|
|
|
164
|
+
# Flattened SessionConfigSelect fields
|
|
165
|
+
current_value: SessionConfigValueId
|
|
166
|
+
"""The currently selected value."""
|
|
167
|
+
|
|
168
|
+
options: SessionConfigSelectOptions
|
|
169
|
+
"""The set of selectable options."""
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
class SessionConfigOption(AnnotatedObject):
|
|
173
|
+
"""A session configuration option selector and its current state."""
|
|
174
|
+
|
|
137
175
|
id: SessionConfigId
|
|
138
|
-
"""Unique identifier for
|
|
176
|
+
"""Unique identifier for the configuration option."""
|
|
139
177
|
|
|
140
|
-
|
|
141
|
-
"""Human-readable label for
|
|
178
|
+
name: str
|
|
179
|
+
"""Human-readable label for the option."""
|
|
142
180
|
|
|
143
181
|
description: str | None = None
|
|
144
|
-
"""Optional description
|
|
182
|
+
"""Optional description for the Client to display to the user."""
|
|
145
183
|
|
|
146
|
-
|
|
147
|
-
"""
|
|
148
|
-
|
|
149
|
-
value: SessionConfigValueId
|
|
150
|
-
"""The currently selected value ID."""
|
|
184
|
+
category: SessionConfigOptionCategory | None = None
|
|
185
|
+
"""Optional semantic category for this option (UX only)."""
|
|
151
186
|
|
|
187
|
+
type: Literal["select"] = Field(default="select", init=False)
|
|
188
|
+
"""Discriminator for the config option type (flattened from kind)."""
|
|
152
189
|
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
Field(discriminator="type"),
|
|
156
|
-
]
|
|
157
|
-
"""A session configuration option.
|
|
190
|
+
current_value: SessionConfigValueId
|
|
191
|
+
"""The currently selected value (flattened from kind.select)."""
|
|
158
192
|
|
|
159
|
-
|
|
160
|
-
"""
|
|
193
|
+
options: SessionConfigSelectOptions
|
|
194
|
+
"""The set of selectable options (flattened from kind.select)."""
|