glm-pro-cli 2026.8.11.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
glm_cli/__init__.py ADDED
@@ -0,0 +1,3 @@
1
+ """GLM CLI package."""
2
+
3
+ __version__ = "0.1.0"
glm_cli/__main__.py ADDED
@@ -0,0 +1,6 @@
1
+ """Entry point for python -m glm_cli."""
2
+
3
+ from glm_cli.main import cli
4
+
5
+ if __name__ == "__main__":
6
+ cli()
@@ -0,0 +1 @@
1
+ """GLM CLI commands package."""
@@ -0,0 +1,46 @@
1
+ """Helpers for parsing JSON-valued CLI options."""
2
+
3
+ import json
4
+ from typing import Any
5
+
6
+ import click
7
+
8
+
9
+ def parse_json_value(value: str | None, option_name: str) -> Any:
10
+ """Parse a CLI option as JSON."""
11
+ if value is None:
12
+ return None
13
+ try:
14
+ return json.loads(value)
15
+ except json.JSONDecodeError as exc:
16
+ raise click.BadParameter(f"{option_name} must be valid JSON.") from exc
17
+
18
+
19
+ def parse_json_object(value: str | None, option_name: str) -> dict[str, Any] | None:
20
+ """Parse a CLI option as a JSON object."""
21
+ parsed = parse_json_value(value, option_name)
22
+ if parsed is None:
23
+ return None
24
+ if not isinstance(parsed, dict):
25
+ raise click.BadParameter(f"{option_name} must be a JSON object.")
26
+ return parsed
27
+
28
+
29
+ def parse_json_array(value: str | None, option_name: str) -> list[Any] | None:
30
+ """Parse a CLI option as a JSON array."""
31
+ parsed = parse_json_value(value, option_name)
32
+ if parsed is None:
33
+ return None
34
+ if not isinstance(parsed, list):
35
+ raise click.BadParameter(f"{option_name} must be a JSON array.")
36
+ return parsed
37
+
38
+
39
+ def parse_json_or_string(value: str | None, option_name: str) -> Any:
40
+ """Parse JSON when possible, otherwise keep plain strings."""
41
+ if value is None:
42
+ return None
43
+ stripped = value.strip()
44
+ if stripped.startswith("{") or stripped.startswith("["):
45
+ return parse_json_value(value, option_name)
46
+ return value
@@ -0,0 +1,270 @@
1
+ """Chat completion command."""
2
+
3
+ import click
4
+
5
+ from glm_cli.commands._json import (
6
+ parse_json_array,
7
+ parse_json_object,
8
+ parse_json_or_string,
9
+ )
10
+ from glm_cli.core.client import get_client
11
+ from glm_cli.core.exceptions import GLMError
12
+ from glm_cli.core.output import (
13
+ DEFAULT_MODEL,
14
+ GLM_MODELS,
15
+ print_chat_result,
16
+ print_error,
17
+ print_json,
18
+ )
19
+
20
+
21
+ @click.command()
22
+ @click.argument("prompt")
23
+ @click.option(
24
+ "-m",
25
+ "--model",
26
+ type=click.Choice(GLM_MODELS),
27
+ default=DEFAULT_MODEL,
28
+ show_default=True,
29
+ help="GLM model to use for chat completion.",
30
+ )
31
+ @click.option(
32
+ "-s",
33
+ "--system",
34
+ default=None,
35
+ help="System prompt to set the assistant's behavior.",
36
+ )
37
+ @click.option(
38
+ "--temperature",
39
+ default=None,
40
+ type=float,
41
+ help="Sampling temperature (0-2). Higher values = more random.",
42
+ )
43
+ @click.option(
44
+ "--max-tokens",
45
+ default=None,
46
+ type=int,
47
+ help="Maximum number of tokens to generate.",
48
+ )
49
+ @click.option(
50
+ "--max-completion-tokens",
51
+ default=None,
52
+ type=int,
53
+ help="Upper bound for tokens generated in a completion (including reasoning tokens).",
54
+ )
55
+ @click.option(
56
+ "-n",
57
+ "--count",
58
+ default=None,
59
+ type=int,
60
+ help="Number of completion choices to generate.",
61
+ )
62
+ @click.option(
63
+ "--top-p",
64
+ default=None,
65
+ type=float,
66
+ help="Nucleus sampling probability mass (0-1).",
67
+ )
68
+ @click.option(
69
+ "--frequency-penalty",
70
+ default=None,
71
+ type=float,
72
+ help="Penalize tokens by their frequency in the text so far (-2.0 to 2.0).",
73
+ )
74
+ @click.option(
75
+ "--presence-penalty",
76
+ default=None,
77
+ type=float,
78
+ help="Penalize tokens that have already appeared in the text (-2.0 to 2.0).",
79
+ )
80
+ @click.option(
81
+ "--seed",
82
+ default=None,
83
+ type=int,
84
+ help="Seed for deterministic sampling.",
85
+ )
86
+ @click.option(
87
+ "--stop",
88
+ default=None,
89
+ multiple=True,
90
+ help="Stop sequence(s) where the API will stop generating (repeatable, up to 4).",
91
+ )
92
+ @click.option(
93
+ "--user",
94
+ default=None,
95
+ help="Unique end-user identifier for monitoring and abuse detection.",
96
+ )
97
+ @click.option(
98
+ "--reasoning-effort",
99
+ type=click.Choice(["minimal", "low", "medium", "high"]),
100
+ default=None,
101
+ help="Reasoning effort for extended thinking models.",
102
+ )
103
+ @click.option(
104
+ "--service-tier",
105
+ type=click.Choice(["auto", "default", "flex", "scale", "priority"]),
106
+ default=None,
107
+ help="Processing type for serving the request.",
108
+ )
109
+ @click.option(
110
+ "--store",
111
+ is_flag=True,
112
+ default=False,
113
+ help="Store the output for model distillation or evals.",
114
+ )
115
+ @click.option(
116
+ "--logprobs",
117
+ is_flag=True,
118
+ default=False,
119
+ help="Return log probabilities of the output tokens.",
120
+ )
121
+ @click.option(
122
+ "--top-logprobs",
123
+ default=None,
124
+ type=click.IntRange(0, 20),
125
+ help="Number of most likely tokens (0-20) to return at each token position.",
126
+ )
127
+ @click.option(
128
+ "--parallel-tool-calls",
129
+ is_flag=True,
130
+ default=False,
131
+ help="Enable parallel function calling during tool use.",
132
+ )
133
+ @click.option(
134
+ "--stream", is_flag=True, default=False, help="Stream partial chat completion events."
135
+ )
136
+ @click.option(
137
+ "--response-format",
138
+ default=None,
139
+ help='Response format as JSON (e.g. \'{"type": "json_object"}\').',
140
+ )
141
+ @click.option(
142
+ "--tools",
143
+ default=None,
144
+ help='Tool definitions as a JSON array (e.g. \'[{"type":"function","function":{...}}]\').',
145
+ )
146
+ @click.option(
147
+ "--tool-choice",
148
+ default=None,
149
+ help='Tool selection mode or JSON object (e.g. "auto" or \'{"type":"function","function":{"name":"lookup"}}\').',
150
+ )
151
+ @click.option(
152
+ "--stream-options",
153
+ default=None,
154
+ help="Streaming options as a JSON object (e.g. '{\"include_usage\": true}').",
155
+ )
156
+ @click.option("--metadata", default=None, help="Metadata as a JSON object.")
157
+ @click.option("--logit-bias", default=None, help="Logit bias map as a JSON object.")
158
+ @click.option("--modalities", default=None, help="Requested modalities as a JSON array.")
159
+ @click.option("--audio", default=None, help="Audio output settings as a JSON object.")
160
+ @click.option("--prediction", default=None, help="Prediction settings as a JSON object.")
161
+ @click.option("--web-search-options", default=None, help="Web search settings as a JSON object.")
162
+ @click.option("--json", "output_json", is_flag=True, help="Output raw JSON.")
163
+ @click.pass_context
164
+ def chat(
165
+ ctx: click.Context,
166
+ prompt: str,
167
+ model: str,
168
+ system: str | None,
169
+ temperature: float | None,
170
+ max_tokens: int | None,
171
+ max_completion_tokens: int | None,
172
+ count: int | None,
173
+ top_p: float | None,
174
+ frequency_penalty: float | None,
175
+ presence_penalty: float | None,
176
+ seed: int | None,
177
+ stop: tuple[str, ...],
178
+ user: str | None,
179
+ reasoning_effort: str | None,
180
+ service_tier: str | None,
181
+ store: bool,
182
+ logprobs: bool,
183
+ top_logprobs: int | None,
184
+ parallel_tool_calls: bool,
185
+ stream: bool,
186
+ response_format: str | None,
187
+ tools: str | None,
188
+ tool_choice: str | None,
189
+ stream_options: str | None,
190
+ metadata: str | None,
191
+ logit_bias: str | None,
192
+ modalities: str | None,
193
+ audio: str | None,
194
+ prediction: str | None,
195
+ web_search_options: str | None,
196
+ output_json: bool,
197
+ ) -> None:
198
+ """Chat with a GLM model.
199
+
200
+ PROMPT is the user message to send to the model.
201
+
202
+ \b
203
+ Examples:
204
+ glm chat "What is the capital of France?"
205
+ glm chat "Explain quantum computing" -m glm-5.1
206
+ glm chat "Write a poem" --temperature 0.9
207
+ glm chat "Summarize this" -s "You are a concise summarizer"
208
+ """
209
+ client = get_client(ctx.obj.get("token"))
210
+ messages = []
211
+ if system:
212
+ messages.append({"role": "system", "content": system})
213
+ messages.append({"role": "user", "content": prompt})
214
+
215
+ try:
216
+ parsed_response_format = parse_json_object(response_format, "--response-format")
217
+ parsed_tools = parse_json_array(tools, "--tools")
218
+ parsed_tool_choice = parse_json_or_string(tool_choice, "--tool-choice")
219
+ parsed_stream_options = parse_json_object(stream_options, "--stream-options")
220
+ parsed_metadata = parse_json_object(metadata, "--metadata")
221
+ parsed_logit_bias = parse_json_object(logit_bias, "--logit-bias")
222
+ parsed_modalities = parse_json_array(modalities, "--modalities")
223
+ parsed_audio = parse_json_object(audio, "--audio")
224
+ parsed_prediction = parse_json_object(prediction, "--prediction")
225
+ parsed_web_search_options = parse_json_object(web_search_options, "--web-search-options")
226
+ except click.BadParameter as e:
227
+ print_error(e.format_message())
228
+ raise SystemExit(1) from None
229
+
230
+ payload: dict[str, object] = {
231
+ "model": model,
232
+ "messages": messages,
233
+ "stream": stream or None,
234
+ "temperature": temperature,
235
+ "max_tokens": max_tokens,
236
+ "max_completion_tokens": max_completion_tokens,
237
+ "n": count,
238
+ "response_format": parsed_response_format,
239
+ "tools": parsed_tools,
240
+ "tool_choice": parsed_tool_choice,
241
+ "top_p": top_p,
242
+ "frequency_penalty": frequency_penalty,
243
+ "presence_penalty": presence_penalty,
244
+ "seed": seed,
245
+ "stop": list(stop) if stop else None,
246
+ "stream_options": parsed_stream_options,
247
+ "user": user,
248
+ "reasoning_effort": reasoning_effort,
249
+ "service_tier": service_tier,
250
+ "store": store if store else None,
251
+ "metadata": parsed_metadata,
252
+ "logit_bias": parsed_logit_bias,
253
+ "logprobs": logprobs if logprobs else None,
254
+ "top_logprobs": top_logprobs,
255
+ "parallel_tool_calls": parallel_tool_calls if parallel_tool_calls else None,
256
+ "modalities": parsed_modalities,
257
+ "audio": parsed_audio,
258
+ "prediction": parsed_prediction,
259
+ "web_search_options": parsed_web_search_options,
260
+ }
261
+
262
+ try:
263
+ result = client.chat_completions(**payload) # type: ignore[arg-type]
264
+ if output_json:
265
+ print_json(result)
266
+ else:
267
+ print_chat_result(result)
268
+ except GLMError as e:
269
+ print_error(e.message)
270
+ raise SystemExit(1) from e
@@ -0,0 +1,31 @@
1
+ """Info and utility commands."""
2
+
3
+ import click
4
+
5
+ from glm_cli.core.config import settings
6
+ from glm_cli.core.output import console, print_models
7
+
8
+
9
+ @click.command()
10
+ def models() -> None:
11
+ """List available GLM models."""
12
+ print_models()
13
+
14
+
15
+ @click.command()
16
+ def config() -> None:
17
+ """Show current configuration."""
18
+ from rich.table import Table
19
+
20
+ table = Table(title="GLM CLI Configuration")
21
+ table.add_column("Setting", style="bold cyan")
22
+ table.add_column("Value")
23
+
24
+ table.add_row("API Base URL", settings.api_base_url)
25
+ table.add_row(
26
+ "API Token",
27
+ f"{settings.api_token[:8]}..." if settings.api_token else "[red]Not set[/red]",
28
+ )
29
+ table.add_row("Request Timeout", f"{settings.request_timeout}s")
30
+
31
+ console.print(table)
@@ -0,0 +1 @@
1
+ """GLM CLI core package."""
glm_cli/core/client.py ADDED
@@ -0,0 +1,95 @@
1
+ """HTTP client for GLM API."""
2
+
3
+ from typing import Any
4
+
5
+ import httpx
6
+
7
+ from glm_cli.core.config import settings
8
+ from glm_cli.core.exceptions import (
9
+ GLMAPIError,
10
+ GLMAuthError,
11
+ GLMTimeoutError,
12
+ )
13
+
14
+
15
+ class GLMClient:
16
+ """HTTP client for AceDataCloud GLM API."""
17
+
18
+ def __init__(self, api_token: str | None = None, base_url: str | None = None):
19
+ self.api_token = api_token if api_token is not None else settings.api_token
20
+ self.base_url = base_url or settings.api_base_url
21
+ self.timeout = settings.request_timeout
22
+
23
+ def _get_headers(self) -> dict[str, str]:
24
+ """Get request headers with authentication."""
25
+ if not self.api_token:
26
+ raise GLMAuthError(
27
+ "API token not configured. Set ACEDATACLOUD_API_TOKEN or use --token option."
28
+ )
29
+ return {
30
+ "accept": "application/json",
31
+ "authorization": f"Bearer {self.api_token}",
32
+ "content-type": "application/json",
33
+ }
34
+
35
+ def request(
36
+ self,
37
+ endpoint: str,
38
+ payload: dict[str, Any],
39
+ timeout: float | None = None,
40
+ ) -> dict[str, Any]:
41
+ """Make a POST request to the GLM API."""
42
+ url = f"{self.base_url}{endpoint}"
43
+ request_timeout = timeout or self.timeout
44
+
45
+ # Remove None values from payload
46
+ payload = {k: v for k, v in payload.items() if v is not None}
47
+
48
+ with httpx.Client() as http_client:
49
+ try:
50
+ response = http_client.post(
51
+ url,
52
+ json=payload,
53
+ headers=self._get_headers(),
54
+ timeout=request_timeout,
55
+ )
56
+
57
+ if response.status_code == 401:
58
+ raise GLMAuthError("Invalid API token")
59
+
60
+ if response.status_code == 403:
61
+ raise GLMAuthError("Access denied. Check your API permissions.")
62
+
63
+ response.raise_for_status()
64
+ return response.json() # type: ignore[no-any-return]
65
+
66
+ except httpx.TimeoutException as e:
67
+ raise GLMTimeoutError(
68
+ f"Request to {endpoint} timed out after {request_timeout}s"
69
+ ) from e
70
+
71
+ except GLMAuthError:
72
+ raise
73
+
74
+ except httpx.HTTPStatusError as e:
75
+ raise GLMAPIError(
76
+ message=e.response.text,
77
+ code=f"http_{e.response.status_code}",
78
+ status_code=e.response.status_code,
79
+ ) from e
80
+
81
+ except Exception as e:
82
+ if isinstance(e, GLMAPIError | GLMTimeoutError):
83
+ raise
84
+ raise GLMAPIError(message=str(e)) from e
85
+
86
+ def chat_completions(self, **kwargs: Any) -> dict[str, Any]:
87
+ """Send a chat completion request."""
88
+ return self.request("/glm/chat/completions", kwargs)
89
+
90
+
91
+ def get_client(token: str | None = None) -> GLMClient:
92
+ """Get a GLMClient instance, optionally overriding the token."""
93
+ if token:
94
+ return GLMClient(api_token=token)
95
+ return GLMClient()
glm_cli/core/config.py ADDED
@@ -0,0 +1,39 @@
1
+ """Configuration management for GLM CLI."""
2
+
3
+ import os
4
+ from dataclasses import dataclass, field
5
+
6
+ from dotenv import load_dotenv
7
+
8
+ load_dotenv()
9
+
10
+
11
+ @dataclass
12
+ class Settings:
13
+ """Application settings loaded from environment variables."""
14
+
15
+ api_base_url: str = field(
16
+ default_factory=lambda: os.environ.get(
17
+ "ACEDATACLOUD_API_BASE_URL", "https://api.acedata.cloud"
18
+ )
19
+ )
20
+ api_token: str = field(default_factory=lambda: os.environ.get("ACEDATACLOUD_API_TOKEN", ""))
21
+ request_timeout: float = field(
22
+ default_factory=lambda: float(os.environ.get("GLM_REQUEST_TIMEOUT", "30"))
23
+ )
24
+
25
+ @property
26
+ def is_configured(self) -> bool:
27
+ """Check if the API token is configured."""
28
+ return bool(self.api_token)
29
+
30
+ def validate(self) -> None:
31
+ """Validate configuration. Raises ValueError if API token is missing."""
32
+ if not self.api_token:
33
+ raise ValueError(
34
+ "API token not configured. "
35
+ "Set ACEDATACLOUD_API_TOKEN environment variable or use --token option."
36
+ )
37
+
38
+
39
+ settings = Settings()
@@ -0,0 +1,37 @@
1
+ """Custom exceptions for GLM CLI."""
2
+
3
+
4
+ class GLMError(Exception):
5
+ """Base exception for GLM CLI."""
6
+
7
+ def __init__(self, message: str, code: str = "unknown"):
8
+ self.message = message
9
+ self.code = code
10
+ super().__init__(message)
11
+
12
+
13
+ class GLMAuthError(GLMError):
14
+ """Authentication error."""
15
+
16
+ def __init__(self, message: str = "Authentication failed"):
17
+ super().__init__(message, code="auth_error")
18
+
19
+
20
+ class GLMAPIError(GLMError):
21
+ """API error with HTTP status code."""
22
+
23
+ def __init__(
24
+ self,
25
+ message: str = "API request failed",
26
+ code: str = "api_error",
27
+ status_code: int | None = None,
28
+ ):
29
+ self.status_code = status_code
30
+ super().__init__(message, code)
31
+
32
+
33
+ class GLMTimeoutError(GLMError):
34
+ """Request timeout error."""
35
+
36
+ def __init__(self, message: str = "Request timed out"):
37
+ super().__init__(message, code="timeout_error")
glm_cli/core/output.py ADDED
@@ -0,0 +1,100 @@
1
+ """Rich terminal output formatting for GLM CLI."""
2
+
3
+ import json
4
+ from typing import Any
5
+
6
+ import click
7
+ from rich.console import Console
8
+ from rich.panel import Panel
9
+ from rich.table import Table
10
+
11
+ console = Console()
12
+
13
+ # Available GLM chat models
14
+ GLM_MODELS = [
15
+ "glm-5.2",
16
+ "glm-5",
17
+ "glm-5-turbo",
18
+ "glm-5.1",
19
+ "glm-4.7",
20
+ "glm-4.6",
21
+ "glm-3-turbo",
22
+ ]
23
+
24
+ DEFAULT_MODEL = "glm-4.7"
25
+
26
+
27
+ def print_json(data: Any) -> None:
28
+ """Print data as formatted JSON."""
29
+ click.echo(json.dumps(data, indent=2, ensure_ascii=False))
30
+
31
+
32
+ def print_error(message: str) -> None:
33
+ """Print an error message."""
34
+ console.print(f"[bold red]Error:[/bold red] {message}")
35
+
36
+
37
+ def print_success(message: str) -> None:
38
+ """Print a success message."""
39
+ console.print(f"[bold green]\u2713[/bold green] {message}")
40
+
41
+
42
+ def print_chat_result(data: dict[str, Any]) -> None:
43
+ """Print a chat completion result."""
44
+ choices = data.get("choices", [])
45
+ if choices:
46
+ for i, choice in enumerate(choices, 1):
47
+ message = choice.get("message", {})
48
+ content = message.get("content", "")
49
+ role = message.get("role", "assistant")
50
+ finish_reason = choice.get("finish_reason", "")
51
+ title = (
52
+ f"[bold green]Response #{i}[/bold green]"
53
+ if len(choices) > 1
54
+ else "[bold green]Response[/bold green]"
55
+ )
56
+ console.print(
57
+ Panel(
58
+ content or "[dim](empty)[/dim]",
59
+ title=title,
60
+ subtitle=(
61
+ f"[dim]{role} \u00b7 {finish_reason}[/dim]"
62
+ if finish_reason
63
+ else f"[dim]{role}[/dim]"
64
+ ),
65
+ border_style="green",
66
+ )
67
+ )
68
+ else:
69
+ console.print("[yellow]No response content available.[/yellow]")
70
+
71
+ usage = data.get("usage", {})
72
+ if usage:
73
+ table = Table(show_header=False, box=None, padding=(0, 2))
74
+ table.add_column("Field", style="dim")
75
+ table.add_column("Value", style="dim")
76
+ if usage.get("prompt_tokens"):
77
+ table.add_row("Prompt tokens", str(usage["prompt_tokens"]))
78
+ if usage.get("completion_tokens"):
79
+ table.add_row("Completion tokens", str(usage["completion_tokens"]))
80
+ if usage.get("total_tokens"):
81
+ table.add_row("Total tokens", str(usage["total_tokens"]))
82
+ console.print(table)
83
+
84
+
85
+ def print_models() -> None:
86
+ """Print available GLM models."""
87
+ table = Table(title="Available GLM Models")
88
+ table.add_column("Model", style="bold cyan")
89
+ table.add_column("Notes")
90
+
91
+ table.add_row("glm-5.2", "Latest GLM release")
92
+ table.add_row("glm-5", "GLM-5 base model")
93
+ table.add_row("glm-5-turbo", "GLM-5 Turbo")
94
+ table.add_row("glm-5.1", "Earlier GLM-5 release")
95
+ table.add_row("glm-4.7", "GLM-4 series (default)")
96
+ table.add_row("glm-4.6", "GLM-4 series")
97
+ table.add_row("glm-3-turbo", "GLM-3 Turbo")
98
+
99
+ console.print(table)
100
+ console.print(f"\n[dim]Default model: {DEFAULT_MODEL}[/dim]")
glm_cli/main.py ADDED
@@ -0,0 +1,62 @@
1
+ #!/usr/bin/env python3
2
+ """
3
+ GLM CLI - GLM Chat Completions via AceDataCloud.
4
+
5
+ A command-line tool for GLM chat completions powered by AceDataCloud.
6
+ """
7
+
8
+ from importlib import metadata
9
+
10
+ import click
11
+ from dotenv import load_dotenv
12
+
13
+ from glm_cli.commands.chat import chat
14
+ from glm_cli.commands.info import config, models
15
+
16
+ load_dotenv()
17
+
18
+
19
+ def get_version() -> str:
20
+ """Get the package version."""
21
+ try:
22
+ return metadata.version("glm-pro-cli")
23
+ except metadata.PackageNotFoundError:
24
+ return "dev"
25
+
26
+
27
+ @click.group()
28
+ @click.version_option(version=get_version(), prog_name="glm-cli")
29
+ @click.option(
30
+ "--token",
31
+ envvar="ACEDATACLOUD_API_TOKEN",
32
+ help="API token (or set ACEDATACLOUD_API_TOKEN env var).",
33
+ )
34
+ @click.pass_context
35
+ def cli(ctx: click.Context, token: str | None) -> None:
36
+ """GLM CLI - GLM Chat Completions via AceDataCloud.
37
+
38
+ Chat with GLM models from the command line.
39
+
40
+ Get your API token at https://platform.acedata.cloud
41
+
42
+ \b
43
+ Examples:
44
+ glm chat "What is the capital of France?"
45
+ glm chat "Explain AI" -m glm-5.1
46
+ glm models
47
+
48
+ Set your token:
49
+ export ACEDATACLOUD_API_TOKEN=your_token
50
+ """
51
+ ctx.ensure_object(dict)
52
+ ctx.obj["token"] = token
53
+
54
+
55
+ # Register commands
56
+ cli.add_command(chat)
57
+ cli.add_command(models)
58
+ cli.add_command(config)
59
+
60
+
61
+ if __name__ == "__main__":
62
+ cli()
@@ -0,0 +1,106 @@
1
+ Metadata-Version: 2.1
2
+ Name: glm-pro-cli
3
+ Version: 2026.8.11.0
4
+ Summary: CLI tool for GLM Chat Completions via AceDataCloud
5
+ Project-URL: Homepage, https://github.com/AceDataCloud/Clis
6
+ Project-URL: Repository, https://github.com/AceDataCloud/Clis
7
+ Project-URL: Issues, https://github.com/AceDataCloud/Clis/issues
8
+ Project-URL: Changelog, https://github.com/AceDataCloud/Clis/blob/main/glm/CHANGELOG.md
9
+ Author-email: AceDataCloud <support@acedata.cloud>
10
+ Maintainer-email: AceDataCloud <support@acedata.cloud>
11
+ License: MIT
12
+ License-File: LICENSE
13
+ Keywords: acedata,ai,chat,cli,command-line,glm
14
+ Classifier: Development Status :: 4 - Beta
15
+ Classifier: Environment :: Console
16
+ Classifier: Intended Audience :: Developers
17
+ Classifier: License :: OSI Approved :: MIT License
18
+ Classifier: Operating System :: OS Independent
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3.10
21
+ Classifier: Programming Language :: Python :: 3.11
22
+ Classifier: Programming Language :: Python :: 3.12
23
+ Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
24
+ Requires-Python: >=3.10
25
+ Requires-Dist: click>=8.1.0
26
+ Requires-Dist: httpx>=0.27.0
27
+ Requires-Dist: pydantic>=2.0.0
28
+ Requires-Dist: python-dotenv>=1.0.0
29
+ Requires-Dist: rich>=13.0.0
30
+ Provides-Extra: all
31
+ Requires-Dist: glm-pro-cli[dev,release,test]; extra == 'all'
32
+ Provides-Extra: dev
33
+ Requires-Dist: mypy>=1.10.0; extra == 'dev'
34
+ Requires-Dist: pre-commit>=3.7.0; extra == 'dev'
35
+ Requires-Dist: ruff>=0.4.0; extra == 'dev'
36
+ Provides-Extra: release
37
+ Requires-Dist: build>=1.2.0; extra == 'release'
38
+ Requires-Dist: twine>=6.1.0; extra == 'release'
39
+ Provides-Extra: test
40
+ Requires-Dist: pytest-asyncio>=0.23.0; extra == 'test'
41
+ Requires-Dist: pytest-cov>=5.0.0; extra == 'test'
42
+ Requires-Dist: pytest>=8.0.0; extra == 'test'
43
+ Requires-Dist: respx>=0.21.0; extra == 'test'
44
+ Description-Content-Type: text/markdown
45
+
46
+ # GLM CLI
47
+
48
+ A command-line tool for GLM chat completions via [AceDataCloud](https://platform.acedata.cloud).
49
+
50
+ ## Installation
51
+
52
+ ```bash
53
+ pip install glm-pro-cli
54
+ ```
55
+
56
+ ## Quick Start
57
+
58
+ ```bash
59
+ export ACEDATACLOUD_API_TOKEN=your_token
60
+
61
+ glm chat "What is the capital of France?"
62
+ glm chat "Explain AI" -m glm-5.2
63
+ glm models
64
+ ```
65
+
66
+ ## Commands
67
+
68
+ | Command | Description |
69
+ |---------|-------------|
70
+ | `glm chat <prompt>` | Chat with a GLM model |
71
+ | `glm models` | List available GLM models |
72
+ | `glm config` | Show current configuration |
73
+
74
+ ## Global Options
75
+
76
+ ```
77
+ --token TEXT API token (or set ACEDATACLOUD_API_TOKEN env var)
78
+ --version Show version
79
+ --help Show help message
80
+ ```
81
+
82
+ ## Available Models
83
+
84
+ | Model | Notes |
85
+ |-------|-------|
86
+ | `glm-5.2` | Latest GLM release |
87
+ | `glm-5` | GLM-5 base model |
88
+ | `glm-5-turbo` | GLM-5 Turbo |
89
+ | `glm-5.1` | Earlier GLM-5 release |
90
+ | `glm-4.7` | GLM-4 series (default) |
91
+ | `glm-4.6` | GLM-4 series |
92
+ | `glm-3-turbo` | GLM-3 Turbo |
93
+
94
+ ## Configuration
95
+
96
+ Set environment variables or use a `.env` file:
97
+
98
+ ```bash
99
+ ACEDATACLOUD_API_TOKEN=your_token
100
+ ACEDATACLOUD_API_BASE_URL=https://api.acedata.cloud
101
+ GLM_REQUEST_TIMEOUT=30
102
+ ```
103
+
104
+ ## License
105
+
106
+ MIT
@@ -0,0 +1,17 @@
1
+ glm_cli/__init__.py,sha256=lA__L45NkSnPzAmXU4ZVgIIUw1fFl-zE-wbUNep8RRI,46
2
+ glm_cli/__main__.py,sha256=4jRZFTzwK5Y6cg4WPt0qjPBoqOeyv5Czz1hsrCi3fRQ,109
3
+ glm_cli/main.py,sha256=P1BEpcn_gWEJqWsJ1BBlCk1WB6PPnKWLqI2eiQ8VaoQ,1358
4
+ glm_cli/commands/__init__.py,sha256=2IPOnd3Toj7nhlfbOaXMl7sFRsc6P7Ov1iCIvn3LjAo,32
5
+ glm_cli/commands/_json.py,sha256=mzVd16Pn_Ipf4KnUB9gctG66_7Bvpil6pdro32pg7hY,1454
6
+ glm_cli/commands/chat.py,sha256=oaMQlQgALbm_efIJ1ryWDN1RpdK4nfV7l1XhDI3vlBc,8153
7
+ glm_cli/commands/info.py,sha256=qJaRqV5RTM0w1zi38lBTM6f_RsAua6GpF3e7H8pyd0s,770
8
+ glm_cli/core/__init__.py,sha256=pp6Qaa0tz4CDDes00VjOt_4GchRFLj6ZgaLmB8uxGPk,28
9
+ glm_cli/core/client.py,sha256=3n5_8MlhNIAOy4_9adNaw79nKS6zjHjQniqaMQDz1H0,3117
10
+ glm_cli/core/config.py,sha256=k9yYFgTJQaKLSEhUyD_yz0VGjqk0HY6ni7e0dJH3UEY,1112
11
+ glm_cli/core/exceptions.py,sha256=78h_7_TBQBkHRcyrq4viVj_3ipEECXxj-MBfc8cjh4M,934
12
+ glm_cli/core/output.py,sha256=ZxF7UnBeJoRk56Lv56wgIiWgqL_Fy_cbd0SdWPjFIYE,3132
13
+ glm_pro_cli-2026.8.11.0.dist-info/METADATA,sha256=iXIBu-cRMzGF26xdOPf12KQsV9y7hDM_qNmOtaqlKmI,3049
14
+ glm_pro_cli-2026.8.11.0.dist-info/WHEEL,sha256=TJPnKdtrSue7xZ_AVGkp9YXcvDrobsjBds1du3Nx6dc,87
15
+ glm_pro_cli-2026.8.11.0.dist-info/entry_points.txt,sha256=0al9rl6EWX1f7_DpMbg0VlEozySoEnGY-_3TbQ35BvE,68
16
+ glm_pro_cli-2026.8.11.0.dist-info/licenses/LICENSE,sha256=pi1I0LFwS_WQBwOlBks6BkKATEJxYi54t8Q22FQ7ufo,1069
17
+ glm_pro_cli-2026.8.11.0.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.21.1
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,3 @@
1
+ [console_scripts]
2
+ glm = glm_cli.main:cli
3
+ glm-cli = glm_cli.main:cli
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2025 AceDataCloud
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.