diff --git a/python/README.md b/python/README.md index aa82e0c3..45538cba 100644 --- a/python/README.md +++ b/python/README.md @@ -71,19 +71,19 @@ asyncio.run(main()) ### CopilotClient ```python -client = CopilotClient({ - "cli_path": "copilot", # Optional: path to CLI executable - "cli_url": None, # Optional: URL of existing server (e.g., "localhost:8080") - "log_level": "info", # Optional: log level (default: "info") - "auto_start": True, # Optional: auto-start server (default: True) - "auto_restart": True, # Optional: auto-restart on crash (default: True) -}) +client = CopilotClient( + cli_path="/usr/local/bin/copilot", # Optional: path to CLI executable + cli_url=None, # Optional: URL of existing server (e.g., "localhost:8080") + log_level="info", # Optional: log level (default: "info") + auto_start=True, # Optional: auto-start server (default: True) + auto_restart=True, # Optional: auto-restart on crash (default: True) +) await client.start() session = await client.create_session({"model": "gpt-5"}) def on_event(event): - print(f"Event: {event['type']}") + print(f"Event: {event.type.value}") session.on(on_event) await session.send({"prompt": "Hello!"}) @@ -96,16 +96,18 @@ await client.stop() **CopilotClient Options:** -- `cli_path` (str): Path to CLI executable (default: "copilot" or `COPILOT_CLI_PATH` env var) -- `cli_url` (str): URL of existing CLI server (e.g., `"localhost:8080"`, `"http://127.0.0.1:9000"`, or just `"8080"`). When provided, the client will not spawn a CLI process. -- `cwd` (str): Working directory for CLI process +- `cli_path` (str | PathLike | None): Path to CLI executable (default: bundled CLI binary). Accepts strings or path-like objects. +- `cli_args` (list[str] | None): Additional command-line arguments to pass to the CLI process. +- `cli_url` (str | None): URL of existing CLI server (e.g., `"localhost:8080"`, `"http://127.0.0.1:9000"`, or just `"8080"`). When provided, the client will not spawn a CLI process. +- `cwd` (str | PathLike | None): Working directory for CLI process. Accepts strings or path-like objects. - `port` (int): Server port for TCP mode (default: 0 for random) -- `use_stdio` (bool): Use stdio transport instead of TCP (default: True) -- `log_level` (str): Log level (default: "info") +- `use_stdio` (bool | None): Use stdio transport instead of TCP (default: True) +- `log_level` (str): Log level — `"none"`, `"error"`, `"warning"`, `"info"` (default), `"debug"`, or `"all"` - `auto_start` (bool): Auto-start server on first use (default: True) - `auto_restart` (bool): Auto-restart on crash (default: True) -- `github_token` (str): GitHub token for authentication. When provided, takes priority over other auth methods. -- `use_logged_in_user` (bool): Whether to use logged-in user for authentication (default: True, but False when `github_token` is provided). Cannot be used with `cli_url`. +- `github_token` (str | None): GitHub token for authentication. When provided, takes priority over other auth methods. +- `use_logged_in_user` (bool | None): Whether to use logged-in user for authentication (default: True, but False when `github_token` is provided). Cannot be used with `cli_url`. +- `env` (dict[str, str] | None): Environment variables for the CLI process. When provided, replaces the inherited process environment. When omitted, the current process environment is used. **SessionConfig Options (for `create_session`):** diff --git a/python/copilot/__init__.py b/python/copilot/__init__.py index f5f7ed0b..c98de63f 100644 --- a/python/copilot/__init__.py +++ b/python/copilot/__init__.py @@ -13,6 +13,7 @@ CustomAgentConfig, GetAuthStatusResponse, GetStatusResponse, + LogLevel, MCPLocalServerConfig, MCPRemoteServerConfig, MCPServerConfig, @@ -49,6 +50,7 @@ "CustomAgentConfig", "GetAuthStatusResponse", "GetStatusResponse", + "LogLevel", "MCPLocalServerConfig", "MCPRemoteServerConfig", "MCPServerConfig", diff --git a/python/copilot/client.py b/python/copilot/client.py index 90260ffb..9d4bca8e 100644 --- a/python/copilot/client.py +++ b/python/copilot/client.py @@ -21,7 +21,7 @@ import threading from dataclasses import asdict, is_dataclass from pathlib import Path -from typing import Any, Callable, Optional, cast +from typing import Any, Callable, Optional, Union, cast, overload from .generated.rpc import ServerRpc from .generated.session_events import session_event_from_dict @@ -34,6 +34,7 @@ CustomAgentConfig, GetAuthStatusResponse, GetStatusResponse, + LogLevel, ModelInfo, PingResponse, ProviderConfig, @@ -100,44 +101,106 @@ class CopilotClient: >>> await client.stop() >>> # Or connect to an existing server - >>> client = CopilotClient({"cli_url": "localhost:3000"}) + >>> client = CopilotClient(cli_url="localhost:3000") """ - def __init__(self, options: Optional[CopilotClientOptions] = None): + @overload + def __init__( + self, + *, + cli_url: str, + cwd: Union[str, os.PathLike[str], None] = None, + port: int = 0, + log_level: LogLevel = "info", + auto_start: bool = True, + auto_restart: bool = True, + env: Optional[dict[str, str]] = None, + ) -> None: ... + + @overload + def __init__( + self, + *, + cli_path: Union[str, os.PathLike[str], None] = None, + cli_args: Optional[list[str]] = None, + cwd: Union[str, os.PathLike[str], None] = None, + port: int = 0, + use_stdio: Optional[bool] = None, + log_level: LogLevel = "info", + auto_start: bool = True, + auto_restart: bool = True, + github_token: Optional[str] = None, + use_logged_in_user: Optional[bool] = None, + env: Optional[dict[str, str]] = None, + ) -> None: ... + + def __init__( + self, + *, + cli_path: Union[str, os.PathLike[str], None] = None, + cli_args: Optional[list[str]] = None, + cli_url: Optional[str] = None, + cwd: Union[str, os.PathLike[str], None] = None, + port: int = 0, + use_stdio: Optional[bool] = None, + log_level: LogLevel = "info", + auto_start: bool = True, + auto_restart: bool = True, + github_token: Optional[str] = None, + use_logged_in_user: Optional[bool] = None, + env: Optional[dict[str, str]] = None, + ): """ Initialize a new CopilotClient. Args: - options: Optional configuration options for the client. If not provided, - default options are used (spawns CLI server using stdio). + cli_path: Path to the Copilot CLI executable. Accepts strings + or path-like objects. If not provided, uses the bundled + CLI binary. + cli_args: Additional command-line arguments to pass to the CLI + process. + cli_url: URL of an existing Copilot CLI server to connect to. + Format: "host:port", "http://host:port", or just "port". + Mutually exclusive with cli_path and use_stdio. + cwd: Working directory for the CLI process. Accepts strings + or path-like objects (default: current working directory). + port: Port for the CLI server in TCP mode (default: 0 for random). + use_stdio: Use stdio transport instead of TCP (default: True, + forced to False when cli_url is set). + log_level: Log level (default: "info"). + auto_start: Auto-start the CLI server on first use (default: True). + auto_restart: Auto-restart the CLI server if it crashes + (default: True). + github_token: GitHub token for authentication. Takes priority over + other authentication methods. + use_logged_in_user: Whether to use the logged-in user for + authentication (default: True, but False when github_token + is provided). Cannot be used with cli_url. + env: Environment variables for the CLI process. Raises: - ValueError: If mutually exclusive options are provided (e.g., cli_url - with use_stdio or cli_path). + ValueError: If mutually exclusive options are provided (e.g., + cli_url with use_stdio or cli_path). Example: >>> # Default options - spawns CLI server using stdio >>> client = CopilotClient() >>> >>> # Connect to an existing server - >>> client = CopilotClient({"cli_url": "localhost:3000"}) + >>> client = CopilotClient(cli_url="localhost:3000") >>> >>> # Custom CLI path with specific log level - >>> client = CopilotClient({ - ... "cli_path": "/usr/local/bin/copilot", - ... "log_level": "debug" - ... }) + >>> client = CopilotClient( + ... cli_path="/usr/local/bin/copilot", + ... log_level="debug", + ... ) """ - opts = options or {} - # Validate mutually exclusive options - if opts.get("cli_url") and (opts.get("use_stdio") or opts.get("cli_path")): + if cli_url and (use_stdio or cli_path): raise ValueError("cli_url is mutually exclusive with use_stdio and cli_path") # Validate auth options with external server - if opts.get("cli_url") and ( - opts.get("github_token") or opts.get("use_logged_in_user") is not None - ): + if cli_url and (github_token or use_logged_in_user is not None): raise ValueError( "github_token and use_logged_in_user cannot be used with cli_url " "(external server manages its own auth)" @@ -146,8 +209,8 @@ def __init__(self, options: Optional[CopilotClientOptions] = None): # Parse cli_url if provided self._actual_host: str = "localhost" self._is_external_server: bool = False - if opts.get("cli_url"): - self._actual_host, actual_port = self._parse_cli_url(opts["cli_url"]) + if cli_url: + self._actual_host, actual_port = self._parse_cli_url(cli_url) self._actual_port: Optional[int] = actual_port self._is_external_server = True else: @@ -155,10 +218,10 @@ def __init__(self, options: Optional[CopilotClientOptions] = None): # Determine CLI path: explicit option > bundled binary # Not needed when connecting to external server via cli_url - if opts.get("cli_url"): + if cli_url: default_cli_path = "" # Not used for external server - elif opts.get("cli_path"): - default_cli_path = opts["cli_path"] + elif cli_path: + default_cli_path = os.fspath(cli_path) else: bundled_path = _get_bundled_cli_path() if bundled_path: @@ -170,27 +233,25 @@ def __init__(self, options: Optional[CopilotClientOptions] = None): ) # Default use_logged_in_user to False when github_token is provided - github_token = opts.get("github_token") - use_logged_in_user = opts.get("use_logged_in_user") if use_logged_in_user is None: use_logged_in_user = False if github_token else True self.options: CopilotClientOptions = { "cli_path": default_cli_path, - "cwd": opts.get("cwd", os.getcwd()), - "port": opts.get("port", 0), - "use_stdio": False if opts.get("cli_url") else opts.get("use_stdio", True), - "log_level": opts.get("log_level", "info"), - "auto_start": opts.get("auto_start", True), - "auto_restart": opts.get("auto_restart", True), + "cwd": os.fspath(cwd) if cwd else os.getcwd(), + "port": port, + "use_stdio": False if cli_url else (use_stdio if use_stdio is not None else True), + "log_level": log_level, + "auto_start": auto_start, + "auto_restart": auto_restart, "use_logged_in_user": use_logged_in_user, } - if opts.get("cli_args"): - self.options["cli_args"] = opts["cli_args"] - if opts.get("cli_url"): - self.options["cli_url"] = opts["cli_url"] - if opts.get("env"): - self.options["env"] = opts["env"] + if cli_args: + self.options["cli_args"] = list(cli_args) + if cli_url: + self.options["cli_url"] = cli_url + if env: + self.options["env"] = env if github_token: self.options["github_token"] = github_token @@ -273,7 +334,7 @@ async def start(self) -> None: RuntimeError: If the server fails to start or the connection fails. Example: - >>> client = CopilotClient({"auto_start": False}) + >>> client = CopilotClient(auto_start=False) >>> await client.start() >>> # Now ready to create sessions """ diff --git a/python/e2e/test_client.py b/python/e2e/test_client.py index c18764e5..7b35dd38 100644 --- a/python/e2e/test_client.py +++ b/python/e2e/test_client.py @@ -10,7 +10,7 @@ class TestClient: @pytest.mark.asyncio async def test_should_start_and_connect_to_server_using_stdio(self): - client = CopilotClient({"cli_path": CLI_PATH, "use_stdio": True}) + client = CopilotClient(cli_path=CLI_PATH, use_stdio=True) try: await client.start() @@ -28,7 +28,7 @@ async def test_should_start_and_connect_to_server_using_stdio(self): @pytest.mark.asyncio async def test_should_start_and_connect_to_server_using_tcp(self): - client = CopilotClient({"cli_path": CLI_PATH, "use_stdio": False}) + client = CopilotClient(cli_path=CLI_PATH, use_stdio=False) try: await client.start() @@ -48,7 +48,7 @@ async def test_should_start_and_connect_to_server_using_tcp(self): async def test_should_return_errors_on_failed_cleanup(self): import asyncio - client = CopilotClient({"cli_path": CLI_PATH}) + client = CopilotClient(cli_path=CLI_PATH) try: await client.create_session() @@ -67,7 +67,7 @@ async def test_should_return_errors_on_failed_cleanup(self): @pytest.mark.asyncio async def test_should_force_stop_without_cleanup(self): - client = CopilotClient({"cli_path": CLI_PATH}) + client = CopilotClient(cli_path=CLI_PATH) await client.create_session() await client.force_stop() @@ -75,7 +75,7 @@ async def test_should_force_stop_without_cleanup(self): @pytest.mark.asyncio async def test_should_get_status_with_version_and_protocol_info(self): - client = CopilotClient({"cli_path": CLI_PATH, "use_stdio": True}) + client = CopilotClient(cli_path=CLI_PATH, use_stdio=True) try: await client.start() @@ -93,7 +93,7 @@ async def test_should_get_status_with_version_and_protocol_info(self): @pytest.mark.asyncio async def test_should_get_auth_status(self): - client = CopilotClient({"cli_path": CLI_PATH, "use_stdio": True}) + client = CopilotClient(cli_path=CLI_PATH, use_stdio=True) try: await client.start() @@ -111,7 +111,7 @@ async def test_should_get_auth_status(self): @pytest.mark.asyncio async def test_should_list_models_when_authenticated(self): - client = CopilotClient({"cli_path": CLI_PATH, "use_stdio": True}) + client = CopilotClient(cli_path=CLI_PATH, use_stdio=True) try: await client.start() @@ -139,7 +139,7 @@ async def test_should_list_models_when_authenticated(self): @pytest.mark.asyncio async def test_should_cache_models_list(self): """Test that list_models caches results to avoid rate limiting""" - client = CopilotClient({"cli_path": CLI_PATH, "use_stdio": True}) + client = CopilotClient(cli_path=CLI_PATH, use_stdio=True) try: await client.start() @@ -184,11 +184,9 @@ async def test_should_cache_models_list(self): async def test_should_report_error_with_stderr_when_cli_fails_to_start(self): """Test that CLI startup errors include stderr output in the error message.""" client = CopilotClient( - { - "cli_path": CLI_PATH, - "cli_args": ["--nonexistent-flag-for-testing"], - "use_stdio": True, - } + cli_path=CLI_PATH, + cli_args=["--nonexistent-flag-for-testing"], + use_stdio=True, ) try: diff --git a/python/e2e/test_rpc.py b/python/e2e/test_rpc.py index da2ba3eb..bec4fe0d 100644 --- a/python/e2e/test_rpc.py +++ b/python/e2e/test_rpc.py @@ -14,7 +14,7 @@ class TestRpc: @pytest.mark.asyncio async def test_should_call_rpc_ping_with_typed_params(self): """Test calling rpc.ping with typed params and result""" - client = CopilotClient({"cli_path": CLI_PATH, "use_stdio": True}) + client = CopilotClient(cli_path=CLI_PATH, use_stdio=True) try: await client.start() @@ -30,7 +30,7 @@ async def test_should_call_rpc_ping_with_typed_params(self): @pytest.mark.asyncio async def test_should_call_rpc_models_list(self): """Test calling rpc.models.list with typed result""" - client = CopilotClient({"cli_path": CLI_PATH, "use_stdio": True}) + client = CopilotClient(cli_path=CLI_PATH, use_stdio=True) try: await client.start() @@ -53,7 +53,7 @@ async def test_should_call_rpc_models_list(self): @pytest.mark.asyncio async def test_should_call_rpc_account_get_quota(self): """Test calling rpc.account.getQuota when authenticated""" - client = CopilotClient({"cli_path": CLI_PATH, "use_stdio": True}) + client = CopilotClient(cli_path=CLI_PATH, use_stdio=True) try: await client.start() @@ -108,7 +108,7 @@ async def test_get_and_set_session_mode(self): """Test getting and setting session mode""" from copilot.generated.rpc import Mode, SessionModeSetParams - client = CopilotClient({"cli_path": CLI_PATH, "use_stdio": True}) + client = CopilotClient(cli_path=CLI_PATH, use_stdio=True) try: await client.start() @@ -142,7 +142,7 @@ async def test_read_update_and_delete_plan(self): """Test reading, updating, and deleting plan""" from copilot.generated.rpc import SessionPlanUpdateParams - client = CopilotClient({"cli_path": CLI_PATH, "use_stdio": True}) + client = CopilotClient(cli_path=CLI_PATH, use_stdio=True) try: await client.start() @@ -183,7 +183,7 @@ async def test_create_list_and_read_workspace_files(self): SessionWorkspaceReadFileParams, ) - client = CopilotClient({"cli_path": CLI_PATH, "use_stdio": True}) + client = CopilotClient(cli_path=CLI_PATH, use_stdio=True) try: await client.start() diff --git a/python/e2e/test_session.py b/python/e2e/test_session.py index 0998298f..b70d741e 100644 --- a/python/e2e/test_session.py +++ b/python/e2e/test_session.py @@ -162,12 +162,10 @@ async def test_should_resume_a_session_using_a_new_client(self, ctx: E2ETestCont # Resume using a new client github_token = "fake-token-for-e2e-tests" if os.environ.get("CI") == "true" else None new_client = CopilotClient( - { - "cli_path": ctx.cli_path, - "cwd": ctx.work_dir, - "env": ctx.get_env(), - "github_token": github_token, - } + cli_path=ctx.cli_path, + cwd=ctx.work_dir, + env=ctx.get_env(), + github_token=github_token, ) try: diff --git a/python/e2e/testharness/context.py b/python/e2e/testharness/context.py index 4417f567..cc045df0 100644 --- a/python/e2e/testharness/context.py +++ b/python/e2e/testharness/context.py @@ -63,12 +63,10 @@ async def setup(self): # Use fake token in CI to allow cached responses without real auth github_token = "fake-token-for-e2e-tests" if os.environ.get("CI") == "true" else None self._client = CopilotClient( - { - "cli_path": self.cli_path, - "cwd": self.work_dir, - "env": self.get_env(), - "github_token": github_token, - } + cli_path=self.cli_path, + cwd=self.work_dir, + env=self.get_env(), + github_token=github_token, ) async def teardown(self, test_failed: bool = False): diff --git a/python/test_client.py b/python/test_client.py index 0bc99ea6..dc73eb70 100644 --- a/python/test_client.py +++ b/python/test_client.py @@ -4,6 +4,9 @@ This file is for unit tests. Where relevant, prefer to add e2e tests in e2e/*.py instead. """ +import os +from pathlib import Path + import pytest from copilot import CopilotClient @@ -13,7 +16,7 @@ class TestHandleToolCallRequest: @pytest.mark.asyncio async def test_returns_failure_when_tool_not_registered(self): - client = CopilotClient({"cli_path": CLI_PATH}) + client = CopilotClient(cli_path=CLI_PATH) await client.start() try: @@ -36,96 +39,105 @@ async def test_returns_failure_when_tool_not_registered(self): class TestURLParsing: def test_parse_port_only_url(self): - client = CopilotClient({"cli_url": "8080", "log_level": "error"}) + client = CopilotClient(cli_url="8080", log_level="error") assert client._actual_port == 8080 assert client._actual_host == "localhost" assert client._is_external_server def test_parse_host_port_url(self): - client = CopilotClient({"cli_url": "127.0.0.1:9000", "log_level": "error"}) + client = CopilotClient(cli_url="127.0.0.1:9000", log_level="error") assert client._actual_port == 9000 assert client._actual_host == "127.0.0.1" assert client._is_external_server def test_parse_http_url(self): - client = CopilotClient({"cli_url": "http://localhost:7000", "log_level": "error"}) + client = CopilotClient(cli_url="http://localhost:7000", log_level="error") assert client._actual_port == 7000 assert client._actual_host == "localhost" assert client._is_external_server def test_parse_https_url(self): - client = CopilotClient({"cli_url": "https://example.com:443", "log_level": "error"}) + client = CopilotClient(cli_url="https://example.com:443", log_level="error") assert client._actual_port == 443 assert client._actual_host == "example.com" assert client._is_external_server def test_invalid_url_format(self): with pytest.raises(ValueError, match="Invalid cli_url format"): - CopilotClient({"cli_url": "invalid-url", "log_level": "error"}) + CopilotClient(cli_url="invalid-url", log_level="error") def test_invalid_port_too_high(self): with pytest.raises(ValueError, match="Invalid port in cli_url"): - CopilotClient({"cli_url": "localhost:99999", "log_level": "error"}) + CopilotClient(cli_url="localhost:99999", log_level="error") def test_invalid_port_zero(self): with pytest.raises(ValueError, match="Invalid port in cli_url"): - CopilotClient({"cli_url": "localhost:0", "log_level": "error"}) + CopilotClient(cli_url="localhost:0", log_level="error") def test_invalid_port_negative(self): with pytest.raises(ValueError, match="Invalid port in cli_url"): - CopilotClient({"cli_url": "localhost:-1", "log_level": "error"}) + CopilotClient(cli_url="localhost:-1", log_level="error") def test_cli_url_with_use_stdio(self): with pytest.raises(ValueError, match="cli_url is mutually exclusive"): - CopilotClient({"cli_url": "localhost:8080", "use_stdio": True, "log_level": "error"}) + CopilotClient(cli_url="localhost:8080", use_stdio=True, log_level="error") def test_cli_url_with_cli_path(self): with pytest.raises(ValueError, match="cli_url is mutually exclusive"): - CopilotClient( - {"cli_url": "localhost:8080", "cli_path": "/path/to/cli", "log_level": "error"} - ) + CopilotClient(cli_url="localhost:8080", cli_path="/path/to/cli", log_level="error") def test_use_stdio_false_when_cli_url(self): - client = CopilotClient({"cli_url": "8080", "log_level": "error"}) + client = CopilotClient(cli_url="8080", log_level="error") assert not client.options["use_stdio"] def test_is_external_server_true(self): - client = CopilotClient({"cli_url": "localhost:8080", "log_level": "error"}) + client = CopilotClient(cli_url="localhost:8080", log_level="error") assert client._is_external_server +class TestPathLikeArguments: + def test_cli_path_accepts_pathlib_path(self): + cli_path = Path(CLI_PATH) + client = CopilotClient(cli_path=cli_path, log_level="error") + assert client.options["cli_path"] == os.fspath(cli_path) + assert isinstance(client.options["cli_path"], str) + + def test_cwd_accepts_pathlib_path(self): + cwd_path = Path("/tmp") + client = CopilotClient(cli_path=CLI_PATH, cwd=cwd_path, log_level="error") + assert client.options["cwd"] == os.fspath(cwd_path) + assert isinstance(client.options["cwd"], str) + + def test_cli_path_and_cwd_accept_strings(self): + client = CopilotClient(cli_path=CLI_PATH, cwd="/tmp", log_level="error") + assert client.options["cli_path"] == CLI_PATH + assert client.options["cwd"] == "/tmp" + + class TestAuthOptions: def test_accepts_github_token(self): - client = CopilotClient( - {"cli_path": CLI_PATH, "github_token": "gho_test_token", "log_level": "error"} - ) + client = CopilotClient(cli_path=CLI_PATH, github_token="gho_test_token", log_level="error") assert client.options.get("github_token") == "gho_test_token" def test_default_use_logged_in_user_true_without_token(self): - client = CopilotClient({"cli_path": CLI_PATH, "log_level": "error"}) + client = CopilotClient(cli_path=CLI_PATH, log_level="error") assert client.options.get("use_logged_in_user") is True def test_default_use_logged_in_user_false_with_token(self): - client = CopilotClient( - {"cli_path": CLI_PATH, "github_token": "gho_test_token", "log_level": "error"} - ) + client = CopilotClient(cli_path=CLI_PATH, github_token="gho_test_token", log_level="error") assert client.options.get("use_logged_in_user") is False def test_explicit_use_logged_in_user_true_with_token(self): client = CopilotClient( - { - "cli_path": CLI_PATH, - "github_token": "gho_test_token", - "use_logged_in_user": True, - "log_level": "error", - } + cli_path=CLI_PATH, + github_token="gho_test_token", + use_logged_in_user=True, + log_level="error", ) assert client.options.get("use_logged_in_user") is True def test_explicit_use_logged_in_user_false_without_token(self): - client = CopilotClient( - {"cli_path": CLI_PATH, "use_logged_in_user": False, "log_level": "error"} - ) + client = CopilotClient(cli_path=CLI_PATH, use_logged_in_user=False, log_level="error") assert client.options.get("use_logged_in_user") is False def test_github_token_with_cli_url_raises(self): @@ -133,26 +145,22 @@ def test_github_token_with_cli_url_raises(self): ValueError, match="github_token and use_logged_in_user cannot be used with cli_url" ): CopilotClient( - { - "cli_url": "localhost:8080", - "github_token": "gho_test_token", - "log_level": "error", - } + cli_url="localhost:8080", + github_token="gho_test_token", + log_level="error", ) def test_use_logged_in_user_with_cli_url_raises(self): with pytest.raises( ValueError, match="github_token and use_logged_in_user cannot be used with cli_url" ): - CopilotClient( - {"cli_url": "localhost:8080", "use_logged_in_user": False, "log_level": "error"} - ) + CopilotClient(cli_url="localhost:8080", use_logged_in_user=False, log_level="error") class TestSessionConfigForwarding: @pytest.mark.asyncio async def test_create_session_forwards_client_name(self): - client = CopilotClient({"cli_path": CLI_PATH}) + client = CopilotClient(cli_path=CLI_PATH) await client.start() try: @@ -171,7 +179,7 @@ async def mock_request(method, params): @pytest.mark.asyncio async def test_resume_session_forwards_client_name(self): - client = CopilotClient({"cli_path": CLI_PATH}) + client = CopilotClient(cli_path=CLI_PATH) await client.start() try: