diff --git a/docs/auth/byok.md b/docs/auth/byok.md
index 13ad8b055..fd0a8b93e 100644
--- a/docs/auth/byok.md
+++ b/docs/auth/byok.md
@@ -23,13 +23,13 @@ Azure AI Foundry (formerly Azure OpenAI) is a common BYOK deployment target for
```python
import asyncio
import os
-from copilot import CopilotClient
+import copilot
FOUNDRY_MODEL_URL = "https://your-resource.openai.azure.com/openai/v1/"
# Set FOUNDRY_API_KEY environment variable
async def main():
- client = CopilotClient()
+ client = copilot.cli_client()
await client.start()
session = await client.create_session({
diff --git a/docs/auth/index.md b/docs/auth/index.md
index 9fc65fe28..4c7a585e7 100644
--- a/docs/auth/index.md
+++ b/docs/auth/index.md
@@ -38,10 +38,10 @@ const client = new CopilotClient();
Python
```python
-from copilot import CopilotClient
+import copilot
# Default: uses logged-in user credentials
-client = CopilotClient()
+client = copilot.cli_client()
await client.start()
```
@@ -106,12 +106,11 @@ const client = new CopilotClient({
Python
```python
-from copilot import CopilotClient
+import copilot
-client = CopilotClient({
- "github_token": user_access_token, # Token from OAuth flow
- "use_logged_in_user": False, # Don't use stored CLI credentials
-})
+client = copilot.cli_client(
+ github_token=user_access_token, # Token from OAuth flow
+)
await client.start()
```
@@ -194,10 +193,10 @@ const client = new CopilotClient();
Python
```python
-from copilot import CopilotClient
+import copilot
# Token is read from environment variable automatically
-client = CopilotClient()
+client = copilot.cli_client()
await client.start()
```
@@ -256,9 +255,7 @@ const client = new CopilotClient({
```python
-client = CopilotClient({
- "use_logged_in_user": False, # Only use explicit tokens
-})
+client = copilot.cli_client(use_logged_in_user=False) # Only use explicit tokens
```
diff --git a/docs/debugging.md b/docs/debugging.md
index 6183cccdf..28c666876 100644
--- a/docs/debugging.md
+++ b/docs/debugging.md
@@ -34,9 +34,9 @@ const client = new CopilotClient({
Python
```python
-from copilot import CopilotClient
+import copilot
-client = CopilotClient({"log_level": "debug"})
+client = copilot.cli_client(log_level="debug")
```
@@ -164,7 +164,7 @@ var client = new CopilotClient(new CopilotClientOptions
Python
```python
- client = CopilotClient({"cli_path": "/usr/local/bin/copilot"})
+ client = copilot.cli_client("/usr/local/bin/copilot")
```
@@ -217,7 +217,7 @@ var client = new CopilotClient(new CopilotClientOptions
```python
import os
- client = CopilotClient({"github_token": os.environ.get("GITHUB_TOKEN")})
+ client = copilot.cli_client(github_token=os.environ.get("GITHUB_TOKEN"))
```
diff --git a/docs/getting-started.md b/docs/getting-started.md
index 56c6a9c46..d3955d239 100644
--- a/docs/getting-started.md
+++ b/docs/getting-started.md
@@ -129,10 +129,10 @@ Create `main.py`:
```python
import asyncio
-from copilot import CopilotClient
+import copilot
async def main():
- client = CopilotClient()
+ client = copilot.cli_client()
await client.start()
session = await client.create_session({"model": "gpt-4.1"})
@@ -274,11 +274,11 @@ Update `main.py`:
```python
import asyncio
import sys
-from copilot import CopilotClient
+import copilot
from copilot.generated.session_events import SessionEventType
async def main():
- client = CopilotClient()
+ client = copilot.cli_client()
await client.start()
session = await client.create_session({
@@ -565,7 +565,7 @@ Update `main.py`:
import asyncio
import random
import sys
-from copilot import CopilotClient
+import copilot
from copilot.tools import define_tool
from copilot.generated.session_events import SessionEventType
from pydantic import BaseModel, Field
@@ -585,7 +585,7 @@ async def get_weather(params: GetWeatherParams) -> dict:
return {"city": city, "temperature": f"{temp}°F", "condition": condition}
async def main():
- client = CopilotClient()
+ client = copilot.cli_client()
await client.start()
session = await client.create_session({
@@ -837,7 +837,7 @@ Create `weather_assistant.py`:
import asyncio
import random
import sys
-from copilot import CopilotClient
+import copilot
from copilot.tools import define_tool
from copilot.generated.session_events import SessionEventType
from pydantic import BaseModel, Field
@@ -854,7 +854,7 @@ async def get_weather(params: GetWeatherParams) -> dict:
return {"city": city, "temperature": f"{temp}°F", "condition": condition}
async def main():
- client = CopilotClient()
+ client = copilot.cli_client()
await client.start()
session = await client.create_session({
@@ -1210,11 +1210,10 @@ const session = await client.createSession({ onPermissionRequest: approveAll });
Python
```python
-from copilot import CopilotClient, PermissionHandler
+import copilot
+from copilot import PermissionHandler
-client = CopilotClient({
- "cli_url": "localhost:4321"
-})
+client = copilot.network_client("localhost:4321")
await client.start()
# Use the client normally
diff --git a/docs/guides/session-persistence.md b/docs/guides/session-persistence.md
index 527f5ecc7..115ab70e7 100644
--- a/docs/guides/session-persistence.md
+++ b/docs/guides/session-persistence.md
@@ -46,9 +46,9 @@ await session.sendAndWait({ prompt: "Analyze my codebase" });
### Python
```python
-from copilot import CopilotClient
+import copilot
-client = CopilotClient()
+client = copilot.cli_client()
await client.start()
# Create a session with a meaningful ID
diff --git a/docs/guides/setup/azure-managed-identity.md b/docs/guides/setup/azure-managed-identity.md
index bfafc6f91..7cd67c9aa 100644
--- a/docs/guides/setup/azure-managed-identity.md
+++ b/docs/guides/setup/azure-managed-identity.md
@@ -42,7 +42,8 @@ import asyncio
import os
from azure.identity import DefaultAzureCredential
-from copilot import CopilotClient, ProviderConfig, SessionConfig
+import copilot
+from copilot import ProviderConfig, SessionConfig
COGNITIVE_SERVICES_SCOPE = "https://cognitiveservices.azure.com/.default"
@@ -54,7 +55,7 @@ async def main():
foundry_url = os.environ["AZURE_AI_FOUNDRY_RESOURCE_URL"]
- client = CopilotClient()
+ client = copilot.cli_client()
await client.start()
session = await client.create_session(
@@ -84,7 +85,8 @@ Bearer tokens expire (typically after ~1 hour). For servers or long-running agen
```python
from azure.identity import DefaultAzureCredential
-from copilot import CopilotClient, ProviderConfig, SessionConfig
+import copilot
+from copilot import ProviderConfig, SessionConfig
COGNITIVE_SERVICES_SCOPE = "https://cognitiveservices.azure.com/.default"
@@ -96,7 +98,7 @@ class ManagedIdentityCopilotAgent:
self.foundry_url = foundry_url.rstrip("/")
self.model = model
self.credential = DefaultAzureCredential()
- self.client = CopilotClient()
+ self.client = copilot.cli_client()
def _get_session_config(self) -> SessionConfig:
"""Build a SessionConfig with a fresh bearer token."""
diff --git a/docs/guides/setup/backend-services.md b/docs/guides/setup/backend-services.md
index c9bc13f8d..ed5d07e76 100644
--- a/docs/guides/setup/backend-services.md
+++ b/docs/guides/setup/backend-services.md
@@ -111,11 +111,9 @@ res.json({ content: response?.data.content });
Python
```python
-from copilot import CopilotClient
+import copilot
-client = CopilotClient({
- "cli_url": "localhost:4321",
-})
+client = copilot.network_client("localhost:4321")
await client.start()
session = await client.create_session({
diff --git a/docs/guides/setup/bundled-cli.md b/docs/guides/setup/bundled-cli.md
index 6daf57b56..74fe507aa 100644
--- a/docs/guides/setup/bundled-cli.md
+++ b/docs/guides/setup/bundled-cli.md
@@ -85,12 +85,10 @@ await client.stop();
Python
```python
-from copilot import CopilotClient
+import copilot
from pathlib import Path
-client = CopilotClient({
- "cli_path": str(Path(__file__).parent / "vendor" / "copilot"),
-})
+client = copilot.cli_client(str(Path(__file__).parent / "vendor" / "copilot"))
await client.start()
session = await client.create_session({"model": "gpt-4.1"})
diff --git a/docs/guides/setup/byok.md b/docs/guides/setup/byok.md
index 5b8b8a460..3ae24dfb1 100644
--- a/docs/guides/setup/byok.md
+++ b/docs/guides/setup/byok.md
@@ -93,9 +93,9 @@ await client.stop();
```python
import os
-from copilot import CopilotClient
+import copilot
-client = CopilotClient()
+client = copilot.cli_client()
await client.start()
session = await client.create_session({
diff --git a/docs/guides/setup/github-oauth.md b/docs/guides/setup/github-oauth.md
index 07251c8fb..5482f7f24 100644
--- a/docs/guides/setup/github-oauth.md
+++ b/docs/guides/setup/github-oauth.md
@@ -145,13 +145,13 @@ const response = await session.sendAndWait({ prompt: "Hello!" });
Python
```python
+import copilot
from copilot import CopilotClient
def create_client_for_user(user_token: str) -> CopilotClient:
- return CopilotClient({
- "github_token": user_token,
- "use_logged_in_user": False,
- })
+ return copilot.cli_client(
+ github_token=user_token,
+ )
# Usage
client = create_client_for_user("gho_user_access_token")
diff --git a/docs/guides/setup/local-cli.md b/docs/guides/setup/local-cli.md
index a5fa906b8..8becd1fd3 100644
--- a/docs/guides/setup/local-cli.md
+++ b/docs/guides/setup/local-cli.md
@@ -51,9 +51,9 @@ await client.stop();
Python
```python
-from copilot import CopilotClient
+import copilot
-client = CopilotClient()
+client = copilot.cli_client()
await client.start()
session = await client.create_session({"model": "gpt-4.1"})
diff --git a/docs/guides/skills.md b/docs/guides/skills.md
index b2ea3ae7a..79305bddb 100644
--- a/docs/guides/skills.md
+++ b/docs/guides/skills.md
@@ -42,10 +42,10 @@ await session.sendAndWait({ prompt: "Review this code for security issues" });
Python
```python
-from copilot import CopilotClient
+import copilot
async def main():
- client = CopilotClient()
+ client = copilot.cli_client()
await client.start()
session = await client.create_session({
diff --git a/docs/hooks/overview.md b/docs/hooks/overview.md
index a51ef0464..b57fd9e96 100644
--- a/docs/hooks/overview.md
+++ b/docs/hooks/overview.md
@@ -53,10 +53,10 @@ const session = await client.createSession({
Python
```python
-from copilot import CopilotClient
+import copilot
async def main():
- client = CopilotClient()
+ client = copilot.cli_client()
await client.start()
async def on_pre_tool_use(input_data, invocation):
diff --git a/docs/mcp/overview.md b/docs/mcp/overview.md
index aa2fba668..3f43482cc 100644
--- a/docs/mcp/overview.md
+++ b/docs/mcp/overview.md
@@ -59,10 +59,10 @@ const session = await client.createSession({
```python
import asyncio
-from copilot import CopilotClient
+import copilot
async def main():
- client = CopilotClient()
+ client = copilot.cli_client()
await client.start()
session = await client.create_session({
diff --git a/python/README.md b/python/README.md
index aa82e0c34..b8ee61215 100644
--- a/python/README.md
+++ b/python/README.md
@@ -25,11 +25,11 @@ python chat.py
```python
import asyncio
-from copilot import CopilotClient
+import copilot
async def main():
# Create and start client
- client = CopilotClient()
+ client = copilot.cli_client()
await client.start()
# Create a session
@@ -68,16 +68,54 @@ asyncio.run(main())
## API Reference
-### CopilotClient
+### Client Creation
+
+The SDK provides two factory functions to create a client:
+
+**`copilot.cli_client()`** — Spawns and manages a local CLI process:
+
+```python
+import copilot
+
+# Default: uses bundled CLI binary with stdio transport
+client = copilot.cli_client()
+
+# Custom CLI path with extra arguments
+client = copilot.cli_client("/usr/local/bin/copilot", "--flag")
+
+# With authentication token
+client = copilot.cli_client(github_token="gho_xxx")
+```
+
+Parameters:
+- `path` (str, optional): Path to CLI executable (default: bundled binary).
+- `*args` (str): Extra arguments passed to the CLI executable.
+- `cwd` (str): Working directory for the CLI process (default: current directory).
+- `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 for the CLI server (default: `"info"`).
+- `auto_start` (bool): Auto-connect on first use (default: `True`).
+- `auto_restart` (bool): Auto-restart on crash (default: `True`).
+- `env` (dict[str, str]): Environment variables for the CLI process.
+- `github_token` (str): GitHub token for authentication.
+- `use_logged_in_user` (bool): Use stored OAuth / gh CLI auth (default: `True`, `False` when `github_token` is set).
+
+**`copilot.network_client()`** — Connects to an existing CLI server:
+
+```python
+import copilot
+
+client = copilot.network_client("localhost:8080")
+client = copilot.network_client("http://127.0.0.1:9000")
+client = copilot.network_client("8080") # defaults to localhost
+```
+
+Parameters:
+- `cli_url` (str, required): URL of the CLI server.
+- `log_level` (str): Log level (default: `"info"`).
+- `auto_start` (bool): Auto-connect on first use (default: `True`).
```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)
-})
await client.start()
session = await client.create_session({"model": "gpt-5"})
@@ -94,19 +132,6 @@ await session.destroy()
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
-- `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")
-- `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`.
-
**SessionConfig Options (for `create_session`):**
- `model` (str): Model to use ("gpt-5", "claude-sonnet-4.5", etc.). **Required when using custom provider.**
@@ -155,7 +180,7 @@ Define tools with automatic JSON schema generation using the `@define_tool` deco
```python
from pydantic import BaseModel, Field
-from copilot import CopilotClient, define_tool
+from copilot import define_tool
class LookupIssueParams(BaseModel):
id: str = Field(description="Issue identifier")
@@ -178,7 +203,7 @@ session = await client.create_session({
For users who prefer manual schema definition:
```python
-from copilot import CopilotClient, Tool
+from copilot import Tool
async def lookup_issue(invocation):
issue_id = invocation["arguments"]["id"]
@@ -238,10 +263,10 @@ Enable streaming to receive assistant response chunks as they're generated:
```python
import asyncio
-from copilot import CopilotClient
+import copilot
async def main():
- client = CopilotClient()
+ client = copilot.cli_client()
await client.start()
session = await client.create_session({
diff --git a/python/copilot/__init__.py b/python/copilot/__init__.py
index f5f7ed0b1..4d914a812 100644
--- a/python/copilot/__init__.py
+++ b/python/copilot/__init__.py
@@ -4,7 +4,9 @@
JSON-RPC based SDK for programmatic control of GitHub Copilot CLI
"""
-from .client import CopilotClient
+from __future__ import annotations
+
+from .client import CopilotClient, cli_client, network_client
from .session import CopilotSession
from .tools import define_tool
from .types import (
@@ -13,6 +15,7 @@
CustomAgentConfig,
GetAuthStatusResponse,
GetStatusResponse,
+ LogLevel,
MCPLocalServerConfig,
MCPRemoteServerConfig,
MCPServerConfig,
@@ -41,6 +44,7 @@
__version__ = "0.1.0"
+
__all__ = [
"AzureProviderOptions",
"CopilotClient",
@@ -49,6 +53,7 @@
"CustomAgentConfig",
"GetAuthStatusResponse",
"GetStatusResponse",
+ "LogLevel",
"MCPLocalServerConfig",
"MCPRemoteServerConfig",
"MCPServerConfig",
@@ -73,5 +78,7 @@
"ToolHandler",
"ToolInvocation",
"ToolResult",
+ "cli_client",
"define_tool",
+ "network_client",
]
diff --git a/python/copilot/client.py b/python/copilot/client.py
index 774569afb..88ac25a21 100644
--- a/python/copilot/client.py
+++ b/python/copilot/client.py
@@ -5,13 +5,18 @@
to the Copilot CLI server and provides session management capabilities.
Example:
- >>> from copilot import CopilotClient
+ >>> import copilot
>>>
- >>> async with CopilotClient() as client:
- ... session = await client.create_session()
- ... await session.send({"prompt": "Hello!"})
+ >>> client = copilot.cli_client()
+ >>> await client.start()
+ >>> session = await client.create_session()
+ >>> await session.send({"prompt": "Hello!"})
+ >>> await session.destroy()
+ >>> await client.stop()
"""
+from __future__ import annotations
+
import asyncio
import inspect
import os
@@ -21,7 +26,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
from .generated.rpc import ServerRpc
from .generated.session_events import session_event_from_dict
@@ -30,10 +35,10 @@
from .session import CopilotSession
from .types import (
ConnectionState,
- CopilotClientOptions,
CustomAgentConfig,
GetAuthStatusResponse,
GetStatusResponse,
+ LogLevel,
ModelInfo,
PingResponse,
ProviderConfig,
@@ -48,6 +53,8 @@
ToolHandler,
ToolInvocation,
ToolResult,
+ _CLIClientConfig,
+ _NetworkClientConfig,
)
@@ -79,123 +86,81 @@ class CopilotClient:
methods to create and manage conversation sessions. It can either spawn a CLI
server process or connect to an existing server.
- The client supports both stdio (default) and TCP transport modes for
- communication with the CLI server.
-
- Attributes:
- options: The configuration options for the client.
+ Use the factory functions :func:`copilot.cli_client` and
+ :func:`copilot.network_client` to create instances.
Example:
- >>> # Create a client with default options (spawns CLI server)
- >>> client = CopilotClient()
- >>> await client.start()
+ >>> import copilot
>>>
- >>> # Create a session and send a message
- >>> session = await client.create_session({
- ... "on_permission_request": PermissionHandler.approve_all,
- ... "model": "gpt-4",
- ... })
- >>> session.on(lambda event: print(event.type))
- >>> await session.send({"prompt": "Hello!"})
+ >>> # Create a client that spawns a CLI server
+ >>> client = copilot.cli_client()
+ >>> await client.start()
>>>
- >>> # Clean up
- >>> await session.destroy()
- >>> await client.stop()
-
>>> # Or connect to an existing server
- >>> client = CopilotClient({"cli_url": "localhost:3000"})
+ >>> client = copilot.network_client("localhost:3000")
"""
- def __init__(self, options: Optional[CopilotClientOptions] = None):
+ def __init__(self, config: Union[_CLIClientConfig, _NetworkClientConfig]):
"""
Initialize a new CopilotClient.
Args:
- options: Optional configuration options for the client. If not provided,
- default options are used (spawns CLI server using stdio).
-
- Raises:
- 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"})
- >>>
- >>> # Custom CLI path with specific log level
- >>> client = CopilotClient({
- ... "cli_path": "/usr/local/bin/copilot",
- ... "log_level": "debug"
- ... })
+ config: A ``_CLIClientConfig`` or ``_NetworkClientConfig`` instance.
+ Use :func:`copilot.cli_client` or :func:`copilot.network_client`
+ instead of constructing directly.
"""
- opts = options or {}
-
- # Validate mutually exclusive options
- if opts.get("cli_url") and (opts.get("use_stdio") or opts.get("cli_path")):
- raise ValueError("cli_url is mutually exclusive with use_stdio and cli_path")
+ self._config = config
- # 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
- ):
- raise ValueError(
- "github_token and use_logged_in_user cannot be used with cli_url "
- "(external server manages its own auth)"
- )
-
- # 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 isinstance(config, _NetworkClientConfig):
+ self._actual_host, actual_port = self._parse_cli_url(config.cli_url)
self._actual_port: Optional[int] = actual_port
self._is_external_server = True
+
+ self._cli_path = ""
+ self._cli_args: list[str] = []
+ self._cwd = os.getcwd()
+ self._port = 0
+ self._use_stdio = False
+ self._log_level = config.log_level
+ self._auto_start = config.auto_start
+ self._auto_restart = False
+ self._env: dict[str, str] | None = None
+ self._github_token: str | None = None
+ self._use_logged_in_user = True
else:
self._actual_port = None
- # Determine CLI path: explicit option > bundled binary
- # Not needed when connecting to external server via cli_url
- if opts.get("cli_url"):
- default_cli_path = "" # Not used for external server
- elif opts.get("cli_path"):
- default_cli_path = opts["cli_path"]
- else:
- bundled_path = _get_bundled_cli_path()
- if bundled_path:
- default_cli_path = bundled_path
+ # Determine CLI path: explicit option > bundled binary
+ if config.cli_path:
+ self._cli_path = config.cli_path
else:
- raise RuntimeError(
- "Copilot CLI not found. The bundled CLI binary is not available. "
- "Ensure you installed a platform-specific wheel, or provide cli_path."
- )
-
- # 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),
- "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 github_token:
- self.options["github_token"] = github_token
+ bundled_path = _get_bundled_cli_path()
+ if bundled_path:
+ self._cli_path = bundled_path
+ else:
+ raise RuntimeError(
+ "Copilot CLI not found. The bundled CLI binary is not available. "
+ "Ensure you installed a platform-specific wheel, or provide a path."
+ )
+
+ self._cli_args = list(config.cli_args) if config.cli_args else []
+ self._cwd = config.cwd or os.getcwd()
+ self._port = config.port
+ self._use_stdio = config.use_stdio
+ self._log_level = config.log_level
+ self._auto_start = config.auto_start
+ self._auto_restart = config.auto_restart
+ self._env = config.env
+ self._github_token = config.github_token
+
+ # Default use_logged_in_user to False when github_token is provided
+ if config.use_logged_in_user is None:
+ self._use_logged_in_user = False if config.github_token else True
+ else:
+ self._use_logged_in_user = config.use_logged_in_user
self._process: Optional[subprocess.Popen] = None
self._client: Optional[JsonRpcClient] = None
@@ -448,7 +413,7 @@ async def create_session(self, config: SessionConfig) -> CopilotSession:
... })
"""
if not self._client:
- if self.options["auto_start"]:
+ if self._auto_start:
await self.start()
else:
raise RuntimeError("Client not connected. Call start() first.")
@@ -620,7 +585,7 @@ async def resume_session(self, session_id: str, config: ResumeSessionConfig) ->
... })
"""
if not self._client:
- if self.options["auto_start"]:
+ if self._auto_start:
await self.start()
else:
raise RuntimeError("Client not connected. Call start() first.")
@@ -1174,25 +1139,24 @@ async def _start_cli_server(self) -> None:
Raises:
RuntimeError: If the server fails to start or times out.
"""
- cli_path = self.options["cli_path"]
+ cli_path = self._cli_path
# Verify CLI exists
if not os.path.exists(cli_path):
raise RuntimeError(f"Copilot CLI not found at {cli_path}")
# Start with user-provided cli_args, then add SDK-managed args
- cli_args = self.options.get("cli_args") or []
- args = list(cli_args) + [
+ args = list(self._cli_args) + [
"--headless",
"--no-auto-update",
"--log-level",
- self.options["log_level"],
+ self._log_level,
]
# Add auth-related flags
- if self.options.get("github_token"):
+ if self._github_token:
args.extend(["--auth-token-env", "COPILOT_SDK_AUTH_TOKEN"])
- if not self.options.get("use_logged_in_user", True):
+ if not self._use_logged_in_user:
args.append("--no-auto-login")
# If cli_path is a .js file, run it with node
@@ -1203,21 +1167,21 @@ async def _start_cli_server(self) -> None:
args = [cli_path] + args
# Get environment variables
- env = self.options.get("env")
+ env = self._env
if env is None:
env = dict(os.environ)
else:
env = dict(env)
# Set auth token in environment if provided
- if self.options.get("github_token"):
- env["COPILOT_SDK_AUTH_TOKEN"] = self.options["github_token"]
+ if self._github_token:
+ env["COPILOT_SDK_AUTH_TOKEN"] = self._github_token
# On Windows, hide the console window to avoid distracting users in GUI apps
creationflags = subprocess.CREATE_NO_WINDOW if sys.platform == "win32" else 0
# Choose transport mode
- if self.options["use_stdio"]:
+ if self._use_stdio:
args.append("--stdio")
# Use regular Popen with pipes (buffering=0 for unbuffered)
self._process = subprocess.Popen(
@@ -1226,25 +1190,25 @@ async def _start_cli_server(self) -> None:
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
bufsize=0,
- cwd=self.options["cwd"],
+ cwd=self._cwd,
env=env,
creationflags=creationflags,
)
else:
- if self.options["port"] > 0:
- args.extend(["--port", str(self.options["port"])])
+ if self._port > 0:
+ args.extend(["--port", str(self._port)])
self._process = subprocess.Popen(
args,
stdin=subprocess.DEVNULL,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
- cwd=self.options["cwd"],
+ cwd=self._cwd,
env=env,
creationflags=creationflags,
)
# For stdio mode, we're ready immediately
- if self.options["use_stdio"]:
+ if self._use_stdio:
return
# For TCP mode, wait for port announcement
@@ -1279,7 +1243,7 @@ async def _connect_to_server(self) -> None:
Raises:
RuntimeError: If the connection fails.
"""
- if self.options["use_stdio"]:
+ if self._use_stdio:
await self._connect_via_stdio()
else:
await self._connect_via_tcp()
@@ -1623,3 +1587,88 @@ def _build_unsupported_tool_result(self, tool_name: str) -> ToolResult:
error=f"tool '{tool_name}' not supported",
toolTelemetry={},
)
+
+
+def cli_client(
+ path: str | None = None,
+ *args: str,
+ cwd: str | None = None,
+ port: int = 0,
+ use_stdio: bool = True,
+ log_level: LogLevel = "info",
+ auto_start: bool = True,
+ auto_restart: bool = True,
+ env: dict[str, str] | None = None,
+ github_token: str | None = None,
+ use_logged_in_user: bool | None = None,
+) -> CopilotClient:
+ """Create a :class:`CopilotClient` that spawns and manages a CLI process.
+
+ Args:
+ path: Path to the Copilot CLI executable. If not provided, the bundled
+ CLI binary is used.
+ *args: Extra arguments passed to the CLI executable (inserted before
+ SDK-managed args).
+ cwd: Working directory for the CLI process (default: current directory).
+ port: Port for the CLI server in TCP mode (default: 0 = random).
+ use_stdio: Use stdio transport instead of TCP (default: True).
+ log_level: Log level for the CLI server.
+ auto_start: Auto-start the CLI server on first use (default: True).
+ auto_restart: Auto-restart the CLI server if it crashes (default: True).
+ env: Environment variables for the CLI process.
+ github_token: GitHub token for authentication. Takes priority over
+ other authentication methods.
+ use_logged_in_user: Whether to use stored OAuth / gh CLI auth.
+ Defaults to True, but False when *github_token* is provided.
+
+ Example::
+
+ import copilot
+
+ client = copilot.cli_client()
+ client = copilot.cli_client("/usr/local/bin/copilot", "--flag")
+ client = copilot.cli_client(github_token="gho_xxx")
+ """
+ config = _CLIClientConfig(
+ cli_path=path,
+ cli_args=list(args) or None,
+ cwd=cwd,
+ port=port,
+ use_stdio=use_stdio,
+ log_level=log_level,
+ auto_start=auto_start,
+ auto_restart=auto_restart,
+ env=env,
+ github_token=github_token,
+ use_logged_in_user=use_logged_in_user,
+ )
+ return CopilotClient(config)
+
+
+def network_client(
+ cli_url: str,
+ *,
+ log_level: LogLevel = "info",
+ auto_start: bool = True,
+) -> CopilotClient:
+ """Create a :class:`CopilotClient` that connects to an existing CLI server.
+
+ Args:
+ cli_url: URL of the Copilot CLI server.
+ Formats: ``"host:port"``, ``"http://host:port"``, or ``"port"``.
+ log_level: Log level for the client.
+ auto_start: Auto-connect on first use (default: True).
+
+ Example::
+
+ import copilot
+
+ client = copilot.network_client("localhost:3000")
+ client = copilot.network_client("8080")
+ """
+ config = _NetworkClientConfig(
+ cli_url=cli_url,
+ log_level=log_level,
+ auto_start=auto_start,
+ )
+ return CopilotClient(config)
diff --git a/python/copilot/types.py b/python/copilot/types.py
index 142aee474..4d588c41e 100644
--- a/python/copilot/types.py
+++ b/python/copilot/types.py
@@ -68,35 +68,30 @@ class SelectionAttachment(TypedDict):
Attachment = Union[FileAttachment, DirectoryAttachment, SelectionAttachment]
-# Options for creating a CopilotClient
-class CopilotClientOptions(TypedDict, total=False):
- """Options for creating a CopilotClient"""
-
- cli_path: str # Path to the Copilot CLI executable (default: "copilot")
- # Extra arguments to pass to the CLI executable (inserted before SDK-managed args)
- cli_args: list[str]
- # Working directory for the CLI process (default: current process's cwd)
- cwd: str
- port: int # Port for the CLI server (TCP mode only, default: 0)
- use_stdio: bool # Use stdio transport instead of TCP (default: True)
- cli_url: str # URL of an existing Copilot CLI server to connect to over TCP
- # Format: "host:port" or "http://host:port" or just "port" (defaults to localhost)
- # Examples: "localhost:8080", "http://127.0.0.1:9000", "8080"
- # Mutually exclusive with cli_path, use_stdio
- log_level: LogLevel # Log level
- auto_start: bool # Auto-start the CLI server on first use (default: True)
- # Auto-restart the CLI server if it crashes (default: True)
- auto_restart: bool
- env: dict[str, str] # Environment variables for the CLI process
- # GitHub token to use for authentication.
- # When provided, the token is passed to the CLI server via environment variable.
- # This takes priority over other authentication methods.
- github_token: str
- # Whether to use the logged-in user for authentication.
- # When True, the CLI server will attempt to use stored OAuth tokens or gh CLI auth.
- # When False, only explicit tokens (github_token or environment variables) are used.
- # Default: True (but defaults to False when github_token is provided)
- use_logged_in_user: bool
+@dataclass
+class _CLIClientConfig:
+ """Configuration for a CopilotClient that spawns and manages a CLI process."""
+
+ cli_path: str | None = None
+ cli_args: list[str] | None = None
+ cwd: str | None = None
+ port: int = 0
+ use_stdio: bool = True
+ log_level: LogLevel = "info"
+ auto_start: bool = True
+ auto_restart: bool = True
+ env: dict[str, str] | None = None
+ github_token: str | None = None
+ use_logged_in_user: bool | None = None
+
+
+@dataclass
+class _NetworkClientConfig:
+ """Configuration for a CopilotClient that connects to an existing CLI server."""
+
+ cli_url: str
+ log_level: LogLevel = "info"
+ auto_start: bool = True
ToolResultType = Literal["success", "failure", "rejected", "denied"]
diff --git a/python/e2e/test_agent_and_compact_rpc.py b/python/e2e/test_agent_and_compact_rpc.py
index a960c8426..88ce6a48b 100644
--- a/python/e2e/test_agent_and_compact_rpc.py
+++ b/python/e2e/test_agent_and_compact_rpc.py
@@ -2,7 +2,8 @@
import pytest
-from copilot import CopilotClient, PermissionHandler
+import copilot
+from copilot import PermissionHandler
from copilot.generated.rpc import SessionAgentSelectParams
from .testharness import CLI_PATH, E2ETestContext
@@ -14,7 +15,7 @@ class TestAgentSelectionRpc:
@pytest.mark.asyncio
async def test_should_list_available_custom_agents(self):
"""Test listing available custom agents via RPC."""
- client = CopilotClient({"cli_path": CLI_PATH, "use_stdio": True})
+ client = copilot.cli_client(CLI_PATH)
try:
await client.start()
@@ -54,7 +55,7 @@ async def test_should_list_available_custom_agents(self):
@pytest.mark.asyncio
async def test_should_return_null_when_no_agent_is_selected(self):
"""Test getCurrent returns null when no agent is selected."""
- client = CopilotClient({"cli_path": CLI_PATH, "use_stdio": True})
+ client = copilot.cli_client(CLI_PATH)
try:
await client.start()
@@ -83,7 +84,7 @@ async def test_should_return_null_when_no_agent_is_selected(self):
@pytest.mark.asyncio
async def test_should_select_and_get_current_agent(self):
"""Test selecting an agent and verifying getCurrent returns it."""
- client = CopilotClient({"cli_path": CLI_PATH, "use_stdio": True})
+ client = copilot.cli_client(CLI_PATH)
try:
await client.start()
@@ -122,7 +123,7 @@ async def test_should_select_and_get_current_agent(self):
@pytest.mark.asyncio
async def test_should_deselect_current_agent(self):
"""Test deselecting the current agent."""
- client = CopilotClient({"cli_path": CLI_PATH, "use_stdio": True})
+ client = copilot.cli_client(CLI_PATH)
try:
await client.start()
@@ -156,7 +157,7 @@ async def test_should_deselect_current_agent(self):
@pytest.mark.asyncio
async def test_should_return_empty_list_when_no_custom_agents_configured(self):
"""Test listing agents returns empty when none configured."""
- client = CopilotClient({"cli_path": CLI_PATH, "use_stdio": True})
+ client = copilot.cli_client(CLI_PATH)
try:
await client.start()
diff --git a/python/e2e/test_client.py b/python/e2e/test_client.py
index cc5d31ac6..f2ea60f91 100644
--- a/python/e2e/test_client.py
+++ b/python/e2e/test_client.py
@@ -2,7 +2,8 @@
import pytest
-from copilot import CopilotClient, PermissionHandler
+import copilot
+from copilot import PermissionHandler
from .testharness import CLI_PATH
@@ -10,7 +11,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 = copilot.cli_client(CLI_PATH)
try:
await client.start()
@@ -28,7 +29,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 = copilot.cli_client(CLI_PATH, use_stdio=False)
try:
await client.start()
@@ -48,7 +49,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 = copilot.cli_client(CLI_PATH)
try:
await client.create_session({"on_permission_request": PermissionHandler.approve_all})
@@ -67,7 +68,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 = copilot.cli_client(CLI_PATH)
await client.create_session({"on_permission_request": PermissionHandler.approve_all})
await client.force_stop()
@@ -75,7 +76,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 = copilot.cli_client(CLI_PATH)
try:
await client.start()
@@ -93,7 +94,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 = copilot.cli_client(CLI_PATH)
try:
await client.start()
@@ -111,7 +112,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 = copilot.cli_client(CLI_PATH)
try:
await client.start()
@@ -139,7 +140,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 = copilot.cli_client(CLI_PATH)
try:
await client.start()
@@ -183,13 +184,7 @@ async def test_should_cache_models_list(self):
@pytest.mark.asyncio
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,
- }
- )
+ client = copilot.cli_client(CLI_PATH, "--nonexistent-flag-for-testing")
try:
with pytest.raises(RuntimeError) as exc_info:
diff --git a/python/e2e/test_rpc.py b/python/e2e/test_rpc.py
index 240cd3730..d81bc4862 100644
--- a/python/e2e/test_rpc.py
+++ b/python/e2e/test_rpc.py
@@ -2,7 +2,8 @@
import pytest
-from copilot import CopilotClient, PermissionHandler
+import copilot
+from copilot import PermissionHandler
from copilot.generated.rpc import PingParams
from .testharness import CLI_PATH, E2ETestContext
@@ -14,7 +15,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 = copilot.cli_client(CLI_PATH)
try:
await client.start()
@@ -30,7 +31,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 = copilot.cli_client(CLI_PATH)
try:
await client.start()
@@ -53,7 +54,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 = copilot.cli_client(CLI_PATH)
try:
await client.start()
@@ -112,7 +113,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 = copilot.cli_client(CLI_PATH)
try:
await client.start()
@@ -148,7 +149,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 = copilot.cli_client(CLI_PATH)
try:
await client.start()
@@ -191,7 +192,7 @@ async def test_create_list_and_read_workspace_files(self):
SessionWorkspaceReadFileParams,
)
- client = CopilotClient({"cli_path": CLI_PATH, "use_stdio": True})
+ client = copilot.cli_client(CLI_PATH)
try:
await client.start()
diff --git a/python/e2e/test_session.py b/python/e2e/test_session.py
index 4842d7829..8e4e61963 100644
--- a/python/e2e/test_session.py
+++ b/python/e2e/test_session.py
@@ -4,7 +4,8 @@
import pytest
-from copilot import CopilotClient, PermissionHandler
+import copilot
+from copilot import PermissionHandler
from copilot.types import Tool
from .testharness import E2ETestContext, get_final_assistant_message, get_next_event_of_type
@@ -184,13 +185,11 @@ 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,
- }
+ new_client = copilot.cli_client(
+ 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 4417f567d..7b9255a12 100644
--- a/python/e2e/testharness/context.py
+++ b/python/e2e/testharness/context.py
@@ -11,6 +11,7 @@
from pathlib import Path
from typing import Optional
+import copilot
from copilot import CopilotClient
from .proxy import CapiProxy
@@ -62,13 +63,11 @@ async def setup(self):
# Create the shared client (like Node.js/Go do)
# 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,
- }
+ self._client = copilot.cli_client(
+ 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/samples/chat.py b/python/samples/chat.py
index eb781e4e2..1deb78751 100644
--- a/python/samples/chat.py
+++ b/python/samples/chat.py
@@ -1,13 +1,14 @@
import asyncio
-from copilot import CopilotClient, PermissionHandler
+import copilot
+from copilot import PermissionHandler
BLUE = "\033[34m"
RESET = "\033[0m"
async def main():
- client = CopilotClient()
+ client = copilot.cli_client()
await client.start()
session = await client.create_session(
{
diff --git a/python/test_client.py b/python/test_client.py
index c6ad027f5..6aac63004 100644
--- a/python/test_client.py
+++ b/python/test_client.py
@@ -6,14 +6,15 @@
import pytest
-from copilot import CopilotClient, PermissionHandler
+import copilot
+from copilot import PermissionHandler
from e2e.testharness import CLI_PATH
class TestPermissionHandlerRequired:
@pytest.mark.asyncio
async def test_create_session_raises_without_permission_handler(self):
- client = CopilotClient({"cli_path": CLI_PATH})
+ client = copilot.cli_client(CLI_PATH)
await client.start()
try:
with pytest.raises(ValueError, match="on_permission_request.*is required"):
@@ -23,7 +24,7 @@ async def test_create_session_raises_without_permission_handler(self):
@pytest.mark.asyncio
async def test_resume_session_raises_without_permission_handler(self):
- client = CopilotClient({"cli_path": CLI_PATH})
+ client = copilot.cli_client(CLI_PATH)
await client.start()
try:
session = await client.create_session(
@@ -38,7 +39,7 @@ async def test_resume_session_raises_without_permission_handler(self):
class TestHandleToolCallRequest:
@pytest.mark.asyncio
async def test_returns_failure_when_tool_not_registered(self):
- client = CopilotClient({"cli_path": CLI_PATH})
+ client = copilot.cli_client(CLI_PATH)
await client.start()
try:
@@ -63,123 +64,85 @@ 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 = copilot.network_client("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 = copilot.network_client("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 = copilot.network_client("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 = copilot.network_client("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"})
+ copilot.network_client("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"})
+ copilot.network_client("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"})
+ copilot.network_client("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"})
+ copilot.network_client("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"})
-
- 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"}
- )
-
- def test_use_stdio_false_when_cli_url(self):
- client = CopilotClient({"cli_url": "8080", "log_level": "error"})
- assert not client.options["use_stdio"]
+ def test_use_stdio_false_when_network(self):
+ client = copilot.network_client("8080", log_level="error")
+ assert not client._use_stdio
def test_is_external_server_true(self):
- client = CopilotClient({"cli_url": "localhost:8080", "log_level": "error"})
+ client = copilot.network_client("localhost:8080", log_level="error")
assert client._is_external_server
class TestAuthOptions:
def test_accepts_github_token(self):
- client = CopilotClient(
- {"cli_path": CLI_PATH, "github_token": "gho_test_token", "log_level": "error"}
- )
- assert client.options.get("github_token") == "gho_test_token"
+ client = copilot.cli_client(CLI_PATH, github_token="gho_test_token", log_level="error")
+ assert client._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"})
- assert client.options.get("use_logged_in_user") is True
+ client = copilot.cli_client(CLI_PATH, log_level="error")
+ assert client._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"}
- )
- assert client.options.get("use_logged_in_user") is False
+ client = copilot.cli_client(CLI_PATH, github_token="gho_test_token", log_level="error")
+ assert client._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",
- }
+ client = copilot.cli_client(
+ 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
+ assert client._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"}
- )
- assert client.options.get("use_logged_in_user") is False
-
- def test_github_token_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",
- "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"}
- )
+ client = copilot.cli_client(CLI_PATH, use_logged_in_user=False, log_level="error")
+ assert client._use_logged_in_user is False
class TestSessionConfigForwarding:
@pytest.mark.asyncio
async def test_create_session_forwards_client_name(self):
- client = CopilotClient({"cli_path": CLI_PATH})
+ client = copilot.cli_client(CLI_PATH)
await client.start()
try:
@@ -200,7 +163,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 = copilot.cli_client(CLI_PATH)
await client.start()
try:
diff --git a/test/scenarios/auth/byok-anthropic/python/main.py b/test/scenarios/auth/byok-anthropic/python/main.py
index 7f5e5834c..a2f6106a7 100644
--- a/test/scenarios/auth/byok-anthropic/python/main.py
+++ b/test/scenarios/auth/byok-anthropic/python/main.py
@@ -1,7 +1,7 @@
import asyncio
import os
import sys
-from copilot import CopilotClient
+import copilot
ANTHROPIC_API_KEY = os.environ.get("ANTHROPIC_API_KEY")
ANTHROPIC_MODEL = os.environ.get("ANTHROPIC_MODEL", "claude-sonnet-4-20250514")
@@ -13,10 +13,7 @@
async def main():
- opts = {}
- if os.environ.get("COPILOT_CLI_PATH"):
- opts["cli_path"] = os.environ["COPILOT_CLI_PATH"]
- client = CopilotClient(opts)
+ client = copilot.cli_client(os.environ.get("COPILOT_CLI_PATH"))
try:
session = await client.create_session({
diff --git a/test/scenarios/auth/byok-azure/python/main.py b/test/scenarios/auth/byok-azure/python/main.py
index 5376cac28..119bac29f 100644
--- a/test/scenarios/auth/byok-azure/python/main.py
+++ b/test/scenarios/auth/byok-azure/python/main.py
@@ -1,7 +1,7 @@
import asyncio
import os
import sys
-from copilot import CopilotClient
+import copilot
AZURE_OPENAI_ENDPOINT = os.environ.get("AZURE_OPENAI_ENDPOINT")
AZURE_OPENAI_API_KEY = os.environ.get("AZURE_OPENAI_API_KEY")
@@ -14,10 +14,7 @@
async def main():
- opts = {}
- if os.environ.get("COPILOT_CLI_PATH"):
- opts["cli_path"] = os.environ["COPILOT_CLI_PATH"]
- client = CopilotClient(opts)
+ client = copilot.cli_client(os.environ.get("COPILOT_CLI_PATH"))
try:
session = await client.create_session({
diff --git a/test/scenarios/auth/byok-ollama/python/main.py b/test/scenarios/auth/byok-ollama/python/main.py
index 0f9df7f54..b787b7bb5 100644
--- a/test/scenarios/auth/byok-ollama/python/main.py
+++ b/test/scenarios/auth/byok-ollama/python/main.py
@@ -1,7 +1,7 @@
import asyncio
import os
import sys
-from copilot import CopilotClient
+import copilot
OLLAMA_BASE_URL = os.environ.get("OLLAMA_BASE_URL", "http://localhost:11434/v1")
OLLAMA_MODEL = os.environ.get("OLLAMA_MODEL", "llama3.2:3b")
@@ -12,10 +12,7 @@
async def main():
- opts = {}
- if os.environ.get("COPILOT_CLI_PATH"):
- opts["cli_path"] = os.environ["COPILOT_CLI_PATH"]
- client = CopilotClient(opts)
+ client = copilot.cli_client(os.environ.get("COPILOT_CLI_PATH"))
try:
session = await client.create_session({
diff --git a/test/scenarios/auth/byok-openai/python/main.py b/test/scenarios/auth/byok-openai/python/main.py
index 651a92cd6..9e859da46 100644
--- a/test/scenarios/auth/byok-openai/python/main.py
+++ b/test/scenarios/auth/byok-openai/python/main.py
@@ -1,7 +1,7 @@
import asyncio
import os
import sys
-from copilot import CopilotClient
+import copilot
OPENAI_BASE_URL = os.environ.get("OPENAI_BASE_URL", "https://api.openai.com/v1")
OPENAI_MODEL = os.environ.get("OPENAI_MODEL", "claude-haiku-4.5")
@@ -13,10 +13,7 @@
async def main():
- opts = {}
- if os.environ.get("COPILOT_CLI_PATH"):
- opts["cli_path"] = os.environ["COPILOT_CLI_PATH"]
- client = CopilotClient(opts)
+ client = copilot.cli_client(os.environ.get("COPILOT_CLI_PATH"))
try:
session = await client.create_session({
diff --git a/test/scenarios/auth/gh-app/python/main.py b/test/scenarios/auth/gh-app/python/main.py
index 4568c82b2..dd839685e 100644
--- a/test/scenarios/auth/gh-app/python/main.py
+++ b/test/scenarios/auth/gh-app/python/main.py
@@ -4,7 +4,7 @@
import time
import urllib.request
-from copilot import CopilotClient
+import copilot
DEVICE_CODE_URL = "https://github.com/login/device/code"
@@ -78,10 +78,7 @@ async def main():
display_name = f" ({user.get('name')})" if user.get("name") else ""
print(f"Authenticated as: {user.get('login')}{display_name}")
- opts = {"github_token": token}
- if os.environ.get("COPILOT_CLI_PATH"):
- opts["cli_path"] = os.environ["COPILOT_CLI_PATH"]
- client = CopilotClient(opts)
+ client = copilot.cli_client(os.environ.get("COPILOT_CLI_PATH"), github_token=token)
try:
session = await client.create_session({"model": "claude-haiku-4.5"})
diff --git a/test/scenarios/bundling/app-backend-to-server/python/main.py b/test/scenarios/bundling/app-backend-to-server/python/main.py
index 218505f4a..4bba8d16c 100644
--- a/test/scenarios/bundling/app-backend-to-server/python/main.py
+++ b/test/scenarios/bundling/app-backend-to-server/python/main.py
@@ -5,7 +5,7 @@
import urllib.request
from flask import Flask, request, jsonify
-from copilot import CopilotClient
+import copilot
app = Flask(__name__)
@@ -13,7 +13,7 @@
async def ask_copilot(prompt: str) -> str:
- client = CopilotClient({"cli_url": CLI_URL})
+ client = copilot.network_client(CLI_URL)
try:
session = await client.create_session({"model": "claude-haiku-4.5"})
diff --git a/test/scenarios/bundling/app-direct-server/python/main.py b/test/scenarios/bundling/app-direct-server/python/main.py
index 05aaa9270..1232ebba6 100644
--- a/test/scenarios/bundling/app-direct-server/python/main.py
+++ b/test/scenarios/bundling/app-direct-server/python/main.py
@@ -1,12 +1,10 @@
import asyncio
import os
-from copilot import CopilotClient
+import copilot
async def main():
- client = CopilotClient({
- "cli_url": os.environ.get("COPILOT_CLI_URL", "localhost:3000"),
- })
+ client = copilot.network_client(os.environ.get("COPILOT_CLI_URL", "localhost:3000"))
try:
session = await client.create_session({"model": "claude-haiku-4.5"})
diff --git a/test/scenarios/bundling/container-proxy/python/main.py b/test/scenarios/bundling/container-proxy/python/main.py
index 05aaa9270..1232ebba6 100644
--- a/test/scenarios/bundling/container-proxy/python/main.py
+++ b/test/scenarios/bundling/container-proxy/python/main.py
@@ -1,12 +1,10 @@
import asyncio
import os
-from copilot import CopilotClient
+import copilot
async def main():
- client = CopilotClient({
- "cli_url": os.environ.get("COPILOT_CLI_URL", "localhost:3000"),
- })
+ client = copilot.network_client(os.environ.get("COPILOT_CLI_URL", "localhost:3000"))
try:
session = await client.create_session({"model": "claude-haiku-4.5"})
diff --git a/test/scenarios/bundling/fully-bundled/python/main.py b/test/scenarios/bundling/fully-bundled/python/main.py
index 138bb5646..7ecce366d 100644
--- a/test/scenarios/bundling/fully-bundled/python/main.py
+++ b/test/scenarios/bundling/fully-bundled/python/main.py
@@ -1,13 +1,10 @@
import asyncio
import os
-from copilot import CopilotClient
+import copilot
async def main():
- opts = {"github_token": os.environ.get("GITHUB_TOKEN")}
- if os.environ.get("COPILOT_CLI_PATH"):
- opts["cli_path"] = os.environ["COPILOT_CLI_PATH"]
- client = CopilotClient(opts)
+ client = copilot.cli_client(os.environ.get("COPILOT_CLI_PATH"), github_token=os.environ.get("GITHUB_TOKEN"))
try:
session = await client.create_session({"model": "claude-haiku-4.5"})
diff --git a/test/scenarios/callbacks/hooks/python/main.py b/test/scenarios/callbacks/hooks/python/main.py
index a00c18af7..f79ff2498 100644
--- a/test/scenarios/callbacks/hooks/python/main.py
+++ b/test/scenarios/callbacks/hooks/python/main.py
@@ -1,6 +1,6 @@
import asyncio
import os
-from copilot import CopilotClient
+import copilot
hook_log: list[str] = []
@@ -40,10 +40,7 @@ async def on_error_occurred(input_data, invocation):
async def main():
- opts = {"github_token": os.environ.get("GITHUB_TOKEN")}
- if os.environ.get("COPILOT_CLI_PATH"):
- opts["cli_path"] = os.environ["COPILOT_CLI_PATH"]
- client = CopilotClient(opts)
+ client = copilot.cli_client(os.environ.get("COPILOT_CLI_PATH"), github_token=os.environ.get("GITHUB_TOKEN"))
try:
session = await client.create_session(
diff --git a/test/scenarios/callbacks/permissions/python/main.py b/test/scenarios/callbacks/permissions/python/main.py
index 2da5133fa..7c26f80a8 100644
--- a/test/scenarios/callbacks/permissions/python/main.py
+++ b/test/scenarios/callbacks/permissions/python/main.py
@@ -1,6 +1,6 @@
import asyncio
import os
-from copilot import CopilotClient
+import copilot
# Track which tools requested permission
permission_log: list[str] = []
@@ -16,10 +16,7 @@ async def auto_approve_tool(input_data, invocation):
async def main():
- opts = {"github_token": os.environ.get("GITHUB_TOKEN")}
- if os.environ.get("COPILOT_CLI_PATH"):
- opts["cli_path"] = os.environ["COPILOT_CLI_PATH"]
- client = CopilotClient(opts)
+ client = copilot.cli_client(os.environ.get("COPILOT_CLI_PATH"), github_token=os.environ.get("GITHUB_TOKEN"))
try:
session = await client.create_session(
diff --git a/test/scenarios/callbacks/user-input/python/main.py b/test/scenarios/callbacks/user-input/python/main.py
index fb36eda5c..8fef6b2f4 100644
--- a/test/scenarios/callbacks/user-input/python/main.py
+++ b/test/scenarios/callbacks/user-input/python/main.py
@@ -1,6 +1,6 @@
import asyncio
import os
-from copilot import CopilotClient
+import copilot
input_log: list[str] = []
@@ -20,10 +20,7 @@ async def handle_user_input(request, invocation):
async def main():
- opts = {"github_token": os.environ.get("GITHUB_TOKEN")}
- if os.environ.get("COPILOT_CLI_PATH"):
- opts["cli_path"] = os.environ["COPILOT_CLI_PATH"]
- client = CopilotClient(opts)
+ client = copilot.cli_client(os.environ.get("COPILOT_CLI_PATH"), github_token=os.environ.get("GITHUB_TOKEN"))
try:
session = await client.create_session(
diff --git a/test/scenarios/modes/default/python/main.py b/test/scenarios/modes/default/python/main.py
index 0abc6b709..b21fa8e4d 100644
--- a/test/scenarios/modes/default/python/main.py
+++ b/test/scenarios/modes/default/python/main.py
@@ -1,13 +1,10 @@
import asyncio
import os
-from copilot import CopilotClient
+import copilot
async def main():
- opts = {"github_token": os.environ.get("GITHUB_TOKEN")}
- if os.environ.get("COPILOT_CLI_PATH"):
- opts["cli_path"] = os.environ["COPILOT_CLI_PATH"]
- client = CopilotClient(opts)
+ client = copilot.cli_client(os.environ.get("COPILOT_CLI_PATH"), github_token=os.environ.get("GITHUB_TOKEN"))
try:
session = await client.create_session({
diff --git a/test/scenarios/modes/minimal/python/main.py b/test/scenarios/modes/minimal/python/main.py
index 74a98ba0e..1b6bfc2be 100644
--- a/test/scenarios/modes/minimal/python/main.py
+++ b/test/scenarios/modes/minimal/python/main.py
@@ -1,13 +1,10 @@
import asyncio
import os
-from copilot import CopilotClient
+import copilot
async def main():
- opts = {"github_token": os.environ.get("GITHUB_TOKEN")}
- if os.environ.get("COPILOT_CLI_PATH"):
- opts["cli_path"] = os.environ["COPILOT_CLI_PATH"]
- client = CopilotClient(opts)
+ client = copilot.cli_client(os.environ.get("COPILOT_CLI_PATH"), github_token=os.environ.get("GITHUB_TOKEN"))
try:
session = await client.create_session({
diff --git a/test/scenarios/prompts/attachments/python/main.py b/test/scenarios/prompts/attachments/python/main.py
index acf9c7af1..7cbc00ba4 100644
--- a/test/scenarios/prompts/attachments/python/main.py
+++ b/test/scenarios/prompts/attachments/python/main.py
@@ -1,15 +1,12 @@
import asyncio
import os
-from copilot import CopilotClient
+import copilot
SYSTEM_PROMPT = """You are a helpful assistant. Answer questions about attached files concisely."""
async def main():
- opts = {"github_token": os.environ.get("GITHUB_TOKEN")}
- if os.environ.get("COPILOT_CLI_PATH"):
- opts["cli_path"] = os.environ["COPILOT_CLI_PATH"]
- client = CopilotClient(opts)
+ client = copilot.cli_client(os.environ.get("COPILOT_CLI_PATH"), github_token=os.environ.get("GITHUB_TOKEN"))
try:
session = await client.create_session(
diff --git a/test/scenarios/prompts/reasoning-effort/python/main.py b/test/scenarios/prompts/reasoning-effort/python/main.py
index 74444e7bf..775381090 100644
--- a/test/scenarios/prompts/reasoning-effort/python/main.py
+++ b/test/scenarios/prompts/reasoning-effort/python/main.py
@@ -1,13 +1,10 @@
import asyncio
import os
-from copilot import CopilotClient
+import copilot
async def main():
- opts = {"github_token": os.environ.get("GITHUB_TOKEN")}
- if os.environ.get("COPILOT_CLI_PATH"):
- opts["cli_path"] = os.environ["COPILOT_CLI_PATH"]
- client = CopilotClient(opts)
+ client = copilot.cli_client(os.environ.get("COPILOT_CLI_PATH"), github_token=os.environ.get("GITHUB_TOKEN"))
try:
session = await client.create_session({
diff --git a/test/scenarios/prompts/system-message/python/main.py b/test/scenarios/prompts/system-message/python/main.py
index a3bfccdcf..5612b4980 100644
--- a/test/scenarios/prompts/system-message/python/main.py
+++ b/test/scenarios/prompts/system-message/python/main.py
@@ -1,15 +1,12 @@
import asyncio
import os
-from copilot import CopilotClient
+import copilot
PIRATE_PROMPT = """You are a pirate. Always respond in pirate speak. Say 'Arrr!' in every response. Use nautical terms and pirate slang throughout."""
async def main():
- opts = {"github_token": os.environ.get("GITHUB_TOKEN")}
- if os.environ.get("COPILOT_CLI_PATH"):
- opts["cli_path"] = os.environ["COPILOT_CLI_PATH"]
- client = CopilotClient(opts)
+ client = copilot.cli_client(os.environ.get("COPILOT_CLI_PATH"), github_token=os.environ.get("GITHUB_TOKEN"))
try:
session = await client.create_session(
diff --git a/test/scenarios/sessions/concurrent-sessions/python/main.py b/test/scenarios/sessions/concurrent-sessions/python/main.py
index 171a202e4..62cb025b5 100644
--- a/test/scenarios/sessions/concurrent-sessions/python/main.py
+++ b/test/scenarios/sessions/concurrent-sessions/python/main.py
@@ -1,16 +1,13 @@
import asyncio
import os
-from copilot import CopilotClient
+import copilot
PIRATE_PROMPT = "You are a pirate. Always say Arrr!"
ROBOT_PROMPT = "You are a robot. Always say BEEP BOOP!"
async def main():
- opts = {"github_token": os.environ.get("GITHUB_TOKEN")}
- if os.environ.get("COPILOT_CLI_PATH"):
- opts["cli_path"] = os.environ["COPILOT_CLI_PATH"]
- client = CopilotClient(opts)
+ client = copilot.cli_client(os.environ.get("COPILOT_CLI_PATH"), github_token=os.environ.get("GITHUB_TOKEN"))
try:
session1, session2 = await asyncio.gather(
diff --git a/test/scenarios/sessions/infinite-sessions/python/main.py b/test/scenarios/sessions/infinite-sessions/python/main.py
index fe39a7117..499d68f23 100644
--- a/test/scenarios/sessions/infinite-sessions/python/main.py
+++ b/test/scenarios/sessions/infinite-sessions/python/main.py
@@ -1,13 +1,10 @@
import asyncio
import os
-from copilot import CopilotClient
+import copilot
async def main():
- opts = {"github_token": os.environ.get("GITHUB_TOKEN")}
- if os.environ.get("COPILOT_CLI_PATH"):
- opts["cli_path"] = os.environ["COPILOT_CLI_PATH"]
- client = CopilotClient(opts)
+ client = copilot.cli_client(os.environ.get("COPILOT_CLI_PATH"), github_token=os.environ.get("GITHUB_TOKEN"))
try:
session = await client.create_session({
diff --git a/test/scenarios/sessions/session-resume/python/main.py b/test/scenarios/sessions/session-resume/python/main.py
index b65370b97..d44336af2 100644
--- a/test/scenarios/sessions/session-resume/python/main.py
+++ b/test/scenarios/sessions/session-resume/python/main.py
@@ -1,13 +1,10 @@
import asyncio
import os
-from copilot import CopilotClient
+import copilot
async def main():
- opts = {"github_token": os.environ.get("GITHUB_TOKEN")}
- if os.environ.get("COPILOT_CLI_PATH"):
- opts["cli_path"] = os.environ["COPILOT_CLI_PATH"]
- client = CopilotClient(opts)
+ client = copilot.cli_client(os.environ.get("COPILOT_CLI_PATH"), github_token=os.environ.get("GITHUB_TOKEN"))
try:
# 1. Create a session
diff --git a/test/scenarios/sessions/streaming/python/main.py b/test/scenarios/sessions/streaming/python/main.py
index 2bbc94e78..6acaae6f9 100644
--- a/test/scenarios/sessions/streaming/python/main.py
+++ b/test/scenarios/sessions/streaming/python/main.py
@@ -1,13 +1,10 @@
import asyncio
import os
-from copilot import CopilotClient
+import copilot
async def main():
- opts = {"github_token": os.environ.get("GITHUB_TOKEN")}
- if os.environ.get("COPILOT_CLI_PATH"):
- opts["cli_path"] = os.environ["COPILOT_CLI_PATH"]
- client = CopilotClient(opts)
+ client = copilot.cli_client(os.environ.get("COPILOT_CLI_PATH"), github_token=os.environ.get("GITHUB_TOKEN"))
try:
session = await client.create_session(
diff --git a/test/scenarios/tools/custom-agents/python/main.py b/test/scenarios/tools/custom-agents/python/main.py
index d4e416716..6e4167eeb 100644
--- a/test/scenarios/tools/custom-agents/python/main.py
+++ b/test/scenarios/tools/custom-agents/python/main.py
@@ -1,13 +1,10 @@
import asyncio
import os
-from copilot import CopilotClient
+import copilot
async def main():
- opts = {"github_token": os.environ.get("GITHUB_TOKEN")}
- if os.environ.get("COPILOT_CLI_PATH"):
- opts["cli_path"] = os.environ["COPILOT_CLI_PATH"]
- client = CopilotClient(opts)
+ client = copilot.cli_client(os.environ.get("COPILOT_CLI_PATH"), github_token=os.environ.get("GITHUB_TOKEN"))
try:
session = await client.create_session(
diff --git a/test/scenarios/tools/mcp-servers/python/main.py b/test/scenarios/tools/mcp-servers/python/main.py
index 81d2e39ba..eb0ab4921 100644
--- a/test/scenarios/tools/mcp-servers/python/main.py
+++ b/test/scenarios/tools/mcp-servers/python/main.py
@@ -1,13 +1,10 @@
import asyncio
import os
-from copilot import CopilotClient
+import copilot
async def main():
- opts = {"github_token": os.environ.get("GITHUB_TOKEN")}
- if os.environ.get("COPILOT_CLI_PATH"):
- opts["cli_path"] = os.environ["COPILOT_CLI_PATH"]
- client = CopilotClient(opts)
+ client = copilot.cli_client(os.environ.get("COPILOT_CLI_PATH"), github_token=os.environ.get("GITHUB_TOKEN"))
try:
# MCP server config — demonstrates the configuration pattern.
diff --git a/test/scenarios/tools/no-tools/python/main.py b/test/scenarios/tools/no-tools/python/main.py
index d857183c0..83b8a3e11 100644
--- a/test/scenarios/tools/no-tools/python/main.py
+++ b/test/scenarios/tools/no-tools/python/main.py
@@ -1,6 +1,6 @@
import asyncio
import os
-from copilot import CopilotClient
+import copilot
SYSTEM_PROMPT = """You are a minimal assistant with no tools available.
You cannot execute code, read files, edit files, search, or perform any actions.
@@ -9,10 +9,7 @@
async def main():
- opts = {"github_token": os.environ.get("GITHUB_TOKEN")}
- if os.environ.get("COPILOT_CLI_PATH"):
- opts["cli_path"] = os.environ["COPILOT_CLI_PATH"]
- client = CopilotClient(opts)
+ client = copilot.cli_client(os.environ.get("COPILOT_CLI_PATH"), github_token=os.environ.get("GITHUB_TOKEN"))
try:
session = await client.create_session(
diff --git a/test/scenarios/tools/skills/python/main.py b/test/scenarios/tools/skills/python/main.py
index 5adb74b76..a9f3e99a0 100644
--- a/test/scenarios/tools/skills/python/main.py
+++ b/test/scenarios/tools/skills/python/main.py
@@ -2,14 +2,11 @@
import os
from pathlib import Path
-from copilot import CopilotClient
+import copilot
async def main():
- opts = {"github_token": os.environ.get("GITHUB_TOKEN")}
- if os.environ.get("COPILOT_CLI_PATH"):
- opts["cli_path"] = os.environ["COPILOT_CLI_PATH"]
- client = CopilotClient(opts)
+ client = copilot.cli_client(os.environ.get("COPILOT_CLI_PATH"), github_token=os.environ.get("GITHUB_TOKEN"))
try:
skills_dir = str(Path(__file__).resolve().parent.parent / "sample-skills")
diff --git a/test/scenarios/tools/tool-filtering/python/main.py b/test/scenarios/tools/tool-filtering/python/main.py
index 174be620e..808194eed 100644
--- a/test/scenarios/tools/tool-filtering/python/main.py
+++ b/test/scenarios/tools/tool-filtering/python/main.py
@@ -1,15 +1,12 @@
import asyncio
import os
-from copilot import CopilotClient
+import copilot
SYSTEM_PROMPT = """You are a helpful assistant. You have access to a limited set of tools. When asked about your tools, list exactly which tools you have available."""
async def main():
- opts = {"github_token": os.environ.get("GITHUB_TOKEN")}
- if os.environ.get("COPILOT_CLI_PATH"):
- opts["cli_path"] = os.environ["COPILOT_CLI_PATH"]
- client = CopilotClient(opts)
+ client = copilot.cli_client(os.environ.get("COPILOT_CLI_PATH"), github_token=os.environ.get("GITHUB_TOKEN"))
try:
session = await client.create_session(
diff --git a/test/scenarios/tools/virtual-filesystem/python/main.py b/test/scenarios/tools/virtual-filesystem/python/main.py
index b150c1a2a..503371c04 100644
--- a/test/scenarios/tools/virtual-filesystem/python/main.py
+++ b/test/scenarios/tools/virtual-filesystem/python/main.py
@@ -1,6 +1,7 @@
import asyncio
import os
-from copilot import CopilotClient, define_tool
+import copilot
+from copilot import define_tool
from pydantic import BaseModel, Field
# In-memory virtual filesystem
@@ -46,10 +47,7 @@ async def auto_approve_tool(input_data, invocation):
async def main():
- opts = {"github_token": os.environ.get("GITHUB_TOKEN")}
- if os.environ.get("COPILOT_CLI_PATH"):
- opts["cli_path"] = os.environ["COPILOT_CLI_PATH"]
- client = CopilotClient(opts)
+ client = copilot.cli_client(os.environ.get("COPILOT_CLI_PATH"), github_token=os.environ.get("GITHUB_TOKEN"))
try:
session = await client.create_session(
diff --git a/test/scenarios/transport/reconnect/python/main.py b/test/scenarios/transport/reconnect/python/main.py
index e8aecea50..90f548ff2 100644
--- a/test/scenarios/transport/reconnect/python/main.py
+++ b/test/scenarios/transport/reconnect/python/main.py
@@ -1,13 +1,11 @@
import asyncio
import os
import sys
-from copilot import CopilotClient
+import copilot
async def main():
- client = CopilotClient({
- "cli_url": os.environ.get("COPILOT_CLI_URL", "localhost:3000"),
- })
+ client = copilot.network_client(os.environ.get("COPILOT_CLI_URL", "localhost:3000"))
try:
# First session
diff --git a/test/scenarios/transport/stdio/python/main.py b/test/scenarios/transport/stdio/python/main.py
index 138bb5646..7ecce366d 100644
--- a/test/scenarios/transport/stdio/python/main.py
+++ b/test/scenarios/transport/stdio/python/main.py
@@ -1,13 +1,10 @@
import asyncio
import os
-from copilot import CopilotClient
+import copilot
async def main():
- opts = {"github_token": os.environ.get("GITHUB_TOKEN")}
- if os.environ.get("COPILOT_CLI_PATH"):
- opts["cli_path"] = os.environ["COPILOT_CLI_PATH"]
- client = CopilotClient(opts)
+ client = copilot.cli_client(os.environ.get("COPILOT_CLI_PATH"), github_token=os.environ.get("GITHUB_TOKEN"))
try:
session = await client.create_session({"model": "claude-haiku-4.5"})
diff --git a/test/scenarios/transport/tcp/python/main.py b/test/scenarios/transport/tcp/python/main.py
index 05aaa9270..1232ebba6 100644
--- a/test/scenarios/transport/tcp/python/main.py
+++ b/test/scenarios/transport/tcp/python/main.py
@@ -1,12 +1,10 @@
import asyncio
import os
-from copilot import CopilotClient
+import copilot
async def main():
- client = CopilotClient({
- "cli_url": os.environ.get("COPILOT_CLI_URL", "localhost:3000"),
- })
+ client = copilot.network_client(os.environ.get("COPILOT_CLI_URL", "localhost:3000"))
try:
session = await client.create_session({"model": "claude-haiku-4.5"})