cometapi-cli 0.3.5__py3-none-any.whl → 0.3.6__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.
- cometapi_cli/__init__.py +1 -1
- cometapi_cli/client.py +27 -3
- cometapi_cli/commands/logs.py +10 -86
- {cometapi_cli-0.3.5.dist-info → cometapi_cli-0.3.6.dist-info}/METADATA +4 -4
- {cometapi_cli-0.3.5.dist-info → cometapi_cli-0.3.6.dist-info}/RECORD +8 -8
- {cometapi_cli-0.3.5.dist-info → cometapi_cli-0.3.6.dist-info}/WHEEL +0 -0
- {cometapi_cli-0.3.5.dist-info → cometapi_cli-0.3.6.dist-info}/entry_points.txt +0 -0
- {cometapi_cli-0.3.5.dist-info → cometapi_cli-0.3.6.dist-info}/licenses/LICENSE +0 -0
cometapi_cli/__init__.py
CHANGED
cometapi_cli/client.py
CHANGED
|
@@ -161,7 +161,6 @@ class CometClient(openai.OpenAI):
|
|
|
161
161
|
start_timestamp: int | None = None,
|
|
162
162
|
end_timestamp: int | None = None,
|
|
163
163
|
group: str | None = None,
|
|
164
|
-
request_id: str | None = None,
|
|
165
164
|
) -> dict:
|
|
166
165
|
"""List the user's usage logs (requires access token)."""
|
|
167
166
|
params: dict[str, Any] = {"p": page, "page_size": page_size}
|
|
@@ -177,10 +176,35 @@ class CometClient(openai.OpenAI):
|
|
|
177
176
|
params["end_timestamp"] = end_timestamp
|
|
178
177
|
if group:
|
|
179
178
|
params["group"] = group
|
|
180
|
-
if request_id:
|
|
181
|
-
params["request_id"] = request_id
|
|
182
179
|
return self._account_request("GET", "/api/log/self", params=params)
|
|
183
180
|
|
|
181
|
+
def lookup_log(
|
|
182
|
+
self,
|
|
183
|
+
*,
|
|
184
|
+
request_id: str,
|
|
185
|
+
log_type: int | None = None,
|
|
186
|
+
model_name: str | None = None,
|
|
187
|
+
token_name: str | None = None,
|
|
188
|
+
start_timestamp: int | None = None,
|
|
189
|
+
end_timestamp: int | None = None,
|
|
190
|
+
group: str | None = None,
|
|
191
|
+
) -> dict:
|
|
192
|
+
"""Look up one usage log by request ID using the indexed operator endpoint."""
|
|
193
|
+
params: dict[str, Any] = {"p": 1, "page_size": 1, "request_id": request_id}
|
|
194
|
+
if log_type is not None:
|
|
195
|
+
params["type"] = log_type
|
|
196
|
+
if model_name:
|
|
197
|
+
params["model_name"] = model_name
|
|
198
|
+
if token_name:
|
|
199
|
+
params["token_name"] = token_name
|
|
200
|
+
if start_timestamp is not None:
|
|
201
|
+
params["start_timestamp"] = start_timestamp
|
|
202
|
+
if end_timestamp is not None:
|
|
203
|
+
params["end_timestamp"] = end_timestamp
|
|
204
|
+
if group:
|
|
205
|
+
params["group"] = group
|
|
206
|
+
return self._account_request("GET", "/api/log/", params=params)
|
|
207
|
+
|
|
184
208
|
def search_logs(self, keyword: str) -> dict:
|
|
185
209
|
"""Search usage logs by keyword (requires access token)."""
|
|
186
210
|
return self._account_request("GET", "/api/log/self/search", params={"keyword": keyword})
|
cometapi_cli/commands/logs.py
CHANGED
|
@@ -4,7 +4,6 @@ from __future__ import annotations
|
|
|
4
4
|
|
|
5
5
|
import json as _json
|
|
6
6
|
import sys
|
|
7
|
-
from datetime import datetime, time, timedelta, timezone
|
|
8
7
|
from typing import Annotated
|
|
9
8
|
|
|
10
9
|
import typer
|
|
@@ -32,9 +31,6 @@ LOG_TYPE_MAP = {
|
|
|
32
31
|
}
|
|
33
32
|
|
|
34
33
|
_LOG_TYPE_NAMES = {v: k for k, v in LOG_TYPE_MAP.items()}
|
|
35
|
-
REQUEST_ID_PAGE_SIZE = 100
|
|
36
|
-
REQUEST_ID_DEFAULT_MAX_PAGES = 10
|
|
37
|
-
REQUEST_ID_LOCAL_TZ = timezone(timedelta(hours=8))
|
|
38
34
|
|
|
39
35
|
|
|
40
36
|
def _parse_other(other_raw: str | None) -> dict:
|
|
@@ -48,21 +44,6 @@ def _parse_other(other_raw: str | None) -> dict:
|
|
|
48
44
|
return {}
|
|
49
45
|
|
|
50
46
|
|
|
51
|
-
def _request_id_date_window(request_id: str) -> tuple[int, int] | None:
|
|
52
|
-
"""Infer the local request day from a CometAPI request ID prefix."""
|
|
53
|
-
prefix = request_id[:14]
|
|
54
|
-
if len(prefix) != 14 or not prefix.isdigit():
|
|
55
|
-
return None
|
|
56
|
-
try:
|
|
57
|
-
local_dt = datetime.strptime(prefix, "%Y%m%d%H%M%S").replace(tzinfo=REQUEST_ID_LOCAL_TZ)
|
|
58
|
-
except ValueError:
|
|
59
|
-
return None
|
|
60
|
-
|
|
61
|
-
local_day_start = datetime.combine(local_dt.date(), time.min, tzinfo=REQUEST_ID_LOCAL_TZ)
|
|
62
|
-
local_day_end = local_day_start + timedelta(days=1) - timedelta(seconds=1)
|
|
63
|
-
return int(local_day_start.timestamp()), int(local_day_end.timestamp())
|
|
64
|
-
|
|
65
|
-
|
|
66
47
|
def _exact_request_id_match(items: list, request_id: str) -> dict | None:
|
|
67
48
|
for item in items:
|
|
68
49
|
if isinstance(item, dict) and item.get("request_id") == request_id:
|
|
@@ -80,59 +61,18 @@ def _lookup_log_by_id(
|
|
|
80
61
|
start_timestamp: int | None = None,
|
|
81
62
|
end_timestamp: int | None = None,
|
|
82
63
|
group: str | None = None,
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
"used_server_filter": False,
|
|
88
|
-
"used_inferred_window": False,
|
|
89
|
-
"scanned_pages": 0,
|
|
90
|
-
"max_pages": max_pages,
|
|
91
|
-
}
|
|
92
|
-
|
|
93
|
-
# Older backends may ignore request_id, so verify the returned item matches
|
|
94
|
-
# before trusting this direct lookup.
|
|
95
|
-
resp = client.list_logs( # type: ignore[union-attr]
|
|
96
|
-
page=1,
|
|
97
|
-
page_size=REQUEST_ID_PAGE_SIZE,
|
|
64
|
+
) -> dict | None:
|
|
65
|
+
"""Look up a log entry by request ID without falling back to page scans."""
|
|
66
|
+
resp = client.lookup_log( # type: ignore[union-attr]
|
|
67
|
+
request_id=request_id,
|
|
98
68
|
log_type=log_type,
|
|
99
69
|
model_name=model_name,
|
|
100
70
|
token_name=token_name,
|
|
101
71
|
start_timestamp=start_timestamp,
|
|
102
72
|
end_timestamp=end_timestamp,
|
|
103
73
|
group=group,
|
|
104
|
-
request_id=request_id,
|
|
105
74
|
)
|
|
106
|
-
|
|
107
|
-
if match := _exact_request_id_match(extract_items(resp), request_id):
|
|
108
|
-
return match, meta
|
|
109
|
-
|
|
110
|
-
scan_start = start_timestamp
|
|
111
|
-
scan_end = end_timestamp
|
|
112
|
-
if scan_start is None and scan_end is None:
|
|
113
|
-
inferred = _request_id_date_window(request_id)
|
|
114
|
-
if inferred:
|
|
115
|
-
scan_start, scan_end = inferred
|
|
116
|
-
meta["used_inferred_window"] = True
|
|
117
|
-
|
|
118
|
-
for pg in range(1, max_pages + 1):
|
|
119
|
-
resp = client.list_logs( # type: ignore[union-attr]
|
|
120
|
-
page=pg,
|
|
121
|
-
page_size=REQUEST_ID_PAGE_SIZE,
|
|
122
|
-
log_type=log_type,
|
|
123
|
-
model_name=model_name,
|
|
124
|
-
token_name=token_name,
|
|
125
|
-
start_timestamp=scan_start,
|
|
126
|
-
end_timestamp=scan_end,
|
|
127
|
-
group=group,
|
|
128
|
-
)
|
|
129
|
-
meta["scanned_pages"] = pg
|
|
130
|
-
items = extract_items(resp)
|
|
131
|
-
if not items:
|
|
132
|
-
break
|
|
133
|
-
if match := _exact_request_id_match(items, request_id):
|
|
134
|
-
return match, meta
|
|
135
|
-
return None, meta
|
|
75
|
+
return _exact_request_id_match(extract_items(resp), request_id)
|
|
136
76
|
|
|
137
77
|
|
|
138
78
|
def _build_log_record(log: dict) -> dict:
|
|
@@ -284,14 +224,6 @@ def logs(
|
|
|
284
224
|
str | None,
|
|
285
225
|
typer.Option("--request-id", help="Look up cost by request ID (X-Cometapi-Request-Id header)."),
|
|
286
226
|
] = None,
|
|
287
|
-
request_id_max_pages: Annotated[
|
|
288
|
-
int,
|
|
289
|
-
typer.Option(
|
|
290
|
-
"--request-id-max-pages",
|
|
291
|
-
min=1,
|
|
292
|
-
help="Fallback pages to scan when direct request-ID lookup is unavailable.",
|
|
293
|
-
),
|
|
294
|
-
] = REQUEST_ID_DEFAULT_MAX_PAGES,
|
|
295
227
|
detail: Annotated[
|
|
296
228
|
bool,
|
|
297
229
|
typer.Option("--detail", help="Show extended columns (request ID, pricing ratios)."),
|
|
@@ -325,7 +257,7 @@ def logs(
|
|
|
325
257
|
if log_type:
|
|
326
258
|
type_int = LOG_TYPE_MAP.get(log_type.lower())
|
|
327
259
|
|
|
328
|
-
log_entry
|
|
260
|
+
log_entry = _lookup_log_by_id(
|
|
329
261
|
client,
|
|
330
262
|
request_id=request_id,
|
|
331
263
|
log_type=type_int,
|
|
@@ -334,22 +266,15 @@ def logs(
|
|
|
334
266
|
start_timestamp=start_ts,
|
|
335
267
|
end_timestamp=end_ts,
|
|
336
268
|
group=group,
|
|
337
|
-
max_pages=request_id_max_pages,
|
|
338
269
|
)
|
|
339
270
|
|
|
340
271
|
if log_entry is None:
|
|
341
|
-
if lookup_meta["used_inferred_window"]:
|
|
342
|
-
scan_note = (
|
|
343
|
-
f"Then scanned {lookup_meta['scanned_pages']} page(s) in the request ID's "
|
|
344
|
-
"inferred local date window."
|
|
345
|
-
)
|
|
346
|
-
else:
|
|
347
|
-
scan_note = f"Then scanned {lookup_meta['scanned_pages']} fallback page(s)."
|
|
348
272
|
err_console.print(
|
|
349
273
|
f"[red]No log found for request_id=[/]{request_id}\n"
|
|
350
|
-
"[dim]Tried
|
|
351
|
-
|
|
352
|
-
"
|
|
274
|
+
"[dim]Tried one indexed lookup against /api/log with request_id. "
|
|
275
|
+
"No fallback page scan was performed because /api/log/self does not "
|
|
276
|
+
"currently apply request_id filtering. Use an operations/admin access token "
|
|
277
|
+
"or update the backend self-log endpoint to support request_id filtering.[/]"
|
|
353
278
|
)
|
|
354
279
|
raise typer.Exit(code=1)
|
|
355
280
|
|
|
@@ -399,7 +324,6 @@ def logs(
|
|
|
399
324
|
start_timestamp=start_ts,
|
|
400
325
|
end_timestamp=end_ts,
|
|
401
326
|
group=group,
|
|
402
|
-
request_id=None,
|
|
403
327
|
)
|
|
404
328
|
|
|
405
329
|
data = extract_items(resp)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: cometapi-cli
|
|
3
|
-
Version: 0.3.
|
|
3
|
+
Version: 0.3.6
|
|
4
4
|
Summary: CometAPI CLI — official command-line interface for the CometAPI AI gateway
|
|
5
5
|
Project-URL: Homepage, https://pypi.org/project/cometapi-cli/
|
|
6
6
|
Project-URL: Documentation, https://apidoc.cometapi.com/libraries/cli/overview
|
|
@@ -156,9 +156,9 @@ cometapi logs --type consume --start 2026-06-01 --json
|
|
|
156
156
|
cometapi logs --request-id 20260617165550885561292gJBlzjtp
|
|
157
157
|
```
|
|
158
158
|
|
|
159
|
-
`logs --request-id`
|
|
160
|
-
|
|
161
|
-
|
|
159
|
+
`logs --request-id` performs one indexed lookup against the operator log endpoint and
|
|
160
|
+
accepts only an exact `request_id` match. The CLI does not scan fallback log pages,
|
|
161
|
+
because the self-log endpoint does not currently apply `request_id` filtering.
|
|
162
162
|
|
|
163
163
|
## Models
|
|
164
164
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
cometapi_cli/__init__.py,sha256=
|
|
1
|
+
cometapi_cli/__init__.py,sha256=vXkHbUQYPVVuqrSa6Fz9KuR8AU-NkIpO2liuMYMO0Ow,92
|
|
2
2
|
cometapi_cli/app.py,sha256=d2IZJabWmdZtPtFNOB4YiuSJ1GYvO0hgIOkjm4gQjxA,2948
|
|
3
3
|
cometapi_cli/catalog.py,sha256=Pc0XGoskMEKIzfbU2H_0Yi8zecLzKl1ss8fd2mV7778,4929
|
|
4
|
-
cometapi_cli/client.py,sha256=
|
|
4
|
+
cometapi_cli/client.py,sha256=zg0QEjDOxvZkkZ0XHXoiQ_A_yooDU1kokbIL61p_NmQ,10903
|
|
5
5
|
cometapi_cli/config.py,sha256=oJXQidKCOsKNYPnE8OfLLoOfsv0MSZEDICB6VShJRSA,3307
|
|
6
6
|
cometapi_cli/console.py,sha256=HFSU1gL9SDmwjBvgVgDraoaU50oTwCRpsAwYXYlVP9o,163
|
|
7
7
|
cometapi_cli/constants.py,sha256=UPfU36fnRTl4JdcyjySQ0UEVign3i_UTNH9mQ-Gb4ls,1826
|
|
@@ -16,7 +16,7 @@ cometapi_cli/commands/chat.py,sha256=xQgsjFQ33kVRfSnU5t3fbahjZE8nmVSa_w8qUTPeacE
|
|
|
16
16
|
cometapi_cli/commands/chat_repl.py,sha256=b9lkYnbbaOb0AlSpRcq3wWHmnhtTXvaqeJiUImsMEBY,8176
|
|
17
17
|
cometapi_cli/commands/config_cmd.py,sha256=OqR0TuAq6gQXw8nJIt5AAv_Fk4zdfbg-KhNLuUsrEsU,8619
|
|
18
18
|
cometapi_cli/commands/doctor.py,sha256=s9XzRIkF9FIMAWSc7b3c6v3g8Px9kb0k6WDucOrdXY8,5360
|
|
19
|
-
cometapi_cli/commands/logs.py,sha256=
|
|
19
|
+
cometapi_cli/commands/logs.py,sha256=VxUND6YIbzN4K2u0FHnFh6nmbyD4Hs2OmSuamJmpmGw,13318
|
|
20
20
|
cometapi_cli/commands/model.py,sha256=YyMRt6enCAZfxW_dVcNvdNgYSl-J4iOqPlSsv14nfJs,2654
|
|
21
21
|
cometapi_cli/commands/models.py,sha256=1TQC8LJ6JASErkLG5XtaZyRrq4vr4sVWH7eo426FeNs,8824
|
|
22
22
|
cometapi_cli/commands/repl.py,sha256=b5z1jmEXOsCrb6fwEUyv-IKot929NIPQQAbA1uas1D4,4283
|
|
@@ -24,8 +24,8 @@ cometapi_cli/commands/run.py,sha256=JQQ1DFSyJoD4pByLmhMht1-XhDDZpV94F0hshXL7hKY,
|
|
|
24
24
|
cometapi_cli/commands/stats.py,sha256=bEVywsom7bm8AGKGWlgAWTFjOp4NTJxDk6YEEvECM6U,1411
|
|
25
25
|
cometapi_cli/commands/tasks.py,sha256=NBKOKrDow52sVjoM0ezwS9IhVRltlqYLmpamoEUbAWA,4718
|
|
26
26
|
cometapi_cli/commands/tokens.py,sha256=U0AI8T690NJxAKFBwrWrsr3izXIiB_PZ9avmwpdgM9A,3042
|
|
27
|
-
cometapi_cli-0.3.
|
|
28
|
-
cometapi_cli-0.3.
|
|
29
|
-
cometapi_cli-0.3.
|
|
30
|
-
cometapi_cli-0.3.
|
|
31
|
-
cometapi_cli-0.3.
|
|
27
|
+
cometapi_cli-0.3.6.dist-info/METADATA,sha256=ykOW7C9QdwBX2anfx1S6q2vm4oQuI-rkZrwVDWAo0t0,10630
|
|
28
|
+
cometapi_cli-0.3.6.dist-info/WHEEL,sha256=mffPy8wBnZQn2VnJUU5jE99KsxaSfiyMHV9Yt0aLVxs,87
|
|
29
|
+
cometapi_cli-0.3.6.dist-info/entry_points.txt,sha256=xoiE2ZVNNWXTq0JRBtzC8hJ2JkdKuaBNz_fEd8OJpLs,50
|
|
30
|
+
cometapi_cli-0.3.6.dist-info/licenses/LICENSE,sha256=-rBwHQzkmLbty07abmGvQvsRrvDeEQUkPDhNJfTcjdE,1065
|
|
31
|
+
cometapi_cli-0.3.6.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|
|
File without changes
|