glaip-sdk 0.5.1__py3-none-any.whl → 0.5.2__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.
- glaip_sdk/cli/commands/accounts.py +158 -13
- glaip_sdk/cli/commands/agents.py +6 -3
- glaip_sdk/cli/utils.py +9 -7
- {glaip_sdk-0.5.1.dist-info → glaip_sdk-0.5.2.dist-info}/METADATA +1 -1
- {glaip_sdk-0.5.1.dist-info → glaip_sdk-0.5.2.dist-info}/RECORD +7 -7
- {glaip_sdk-0.5.1.dist-info → glaip_sdk-0.5.2.dist-info}/WHEEL +0 -0
- {glaip_sdk-0.5.1.dist-info → glaip_sdk-0.5.2.dist-info}/entry_points.txt +0 -0
|
@@ -106,6 +106,9 @@ def list_accounts(output_json: bool) -> None:
|
|
|
106
106
|
if active_account:
|
|
107
107
|
console.print(f"\n[{SUCCESS_STYLE}]Active account[/]: {active_account}")
|
|
108
108
|
|
|
109
|
+
# Show hint for updating accounts
|
|
110
|
+
console.print(f"\n[{INFO}]💡 Tip[/]: To update an account's URL or key, use: [bold]aip accounts edit <name>[/bold]")
|
|
111
|
+
|
|
109
112
|
|
|
110
113
|
def _check_account_overwrite(name: str, store: AccountStore, overwrite: bool) -> dict[str, str] | None:
|
|
111
114
|
"""Check if account exists and handle overwrite logic.
|
|
@@ -128,13 +131,19 @@ def _check_account_overwrite(name: str, store: AccountStore, overwrite: bool) ->
|
|
|
128
131
|
return existing
|
|
129
132
|
|
|
130
133
|
|
|
131
|
-
def _get_credentials_non_interactive(
|
|
134
|
+
def _get_credentials_non_interactive(
|
|
135
|
+
url: str,
|
|
136
|
+
read_key_from_stdin: bool,
|
|
137
|
+
name: str,
|
|
138
|
+
command_name: str = "aip accounts add",
|
|
139
|
+
) -> tuple[str, str]:
|
|
132
140
|
"""Get credentials in non-interactive mode.
|
|
133
141
|
|
|
134
142
|
Args:
|
|
135
143
|
url: API URL from flag.
|
|
136
144
|
read_key_from_stdin: Whether to read key from stdin.
|
|
137
145
|
name: Account name (for error messages).
|
|
146
|
+
command_name: Command name for guidance text.
|
|
138
147
|
|
|
139
148
|
Returns:
|
|
140
149
|
Tuple of (api_url, api_key).
|
|
@@ -147,7 +156,7 @@ def _get_credentials_non_interactive(url: str, read_key_from_stdin: bool, name:
|
|
|
147
156
|
return url, sys.stdin.read().strip()
|
|
148
157
|
console.print(
|
|
149
158
|
f"[{ERROR_STYLE}]Error: --key requires stdin input. "
|
|
150
|
-
f"Use: cat key.txt |
|
|
159
|
+
f"Use: cat key.txt | {command_name} {name} --url {url} --key[/]",
|
|
151
160
|
)
|
|
152
161
|
raise click.Abort()
|
|
153
162
|
# URL provided, prompt for key
|
|
@@ -178,6 +187,88 @@ def _get_credentials_interactive(read_key_from_stdin: bool, existing: dict[str,
|
|
|
178
187
|
return _prompt_account_inputs(existing)
|
|
179
188
|
|
|
180
189
|
|
|
190
|
+
def _handle_key_rotation(
|
|
191
|
+
name: str,
|
|
192
|
+
existing_url: str,
|
|
193
|
+
command_name: str,
|
|
194
|
+
) -> tuple[str, str]:
|
|
195
|
+
"""Handle key rotation using stored URL.
|
|
196
|
+
|
|
197
|
+
Args:
|
|
198
|
+
name: Account name (for error messages).
|
|
199
|
+
existing_url: Existing account URL.
|
|
200
|
+
command_name: Command name for error messages.
|
|
201
|
+
|
|
202
|
+
Returns:
|
|
203
|
+
Tuple of (api_url, api_key).
|
|
204
|
+
|
|
205
|
+
Raises:
|
|
206
|
+
click.Abort: If existing URL is missing.
|
|
207
|
+
"""
|
|
208
|
+
if not existing_url:
|
|
209
|
+
console.print(f"[{ERROR_STYLE}]Error: Account '{name}' is missing an API URL. Provide --url to set it.[/]")
|
|
210
|
+
raise click.Abort()
|
|
211
|
+
return _get_credentials_non_interactive(existing_url, True, name, command_name)
|
|
212
|
+
|
|
213
|
+
|
|
214
|
+
def _preserve_existing_values(
|
|
215
|
+
api_url: str,
|
|
216
|
+
api_key: str,
|
|
217
|
+
existing_url: str,
|
|
218
|
+
existing_key: str,
|
|
219
|
+
) -> tuple[str, str]:
|
|
220
|
+
"""Preserve stored values when blank input is provided during edit.
|
|
221
|
+
|
|
222
|
+
Args:
|
|
223
|
+
api_url: Collected API URL.
|
|
224
|
+
api_key: Collected API key.
|
|
225
|
+
existing_url: Existing account URL.
|
|
226
|
+
existing_key: Existing account key.
|
|
227
|
+
|
|
228
|
+
Returns:
|
|
229
|
+
Tuple of (api_url, api_key) with preserved values.
|
|
230
|
+
"""
|
|
231
|
+
if not api_url and existing_url:
|
|
232
|
+
api_url = existing_url
|
|
233
|
+
if not api_key and existing_key:
|
|
234
|
+
api_key = existing_key
|
|
235
|
+
return api_url, api_key
|
|
236
|
+
|
|
237
|
+
|
|
238
|
+
def _collect_credentials_from_inputs(
|
|
239
|
+
url: str | None,
|
|
240
|
+
read_key_from_stdin: bool,
|
|
241
|
+
name: str,
|
|
242
|
+
existing: dict[str, str] | None,
|
|
243
|
+
command_name: str,
|
|
244
|
+
existing_url: str,
|
|
245
|
+
) -> tuple[str, str]:
|
|
246
|
+
"""Collect credentials based on input flags and existing data.
|
|
247
|
+
|
|
248
|
+
Args:
|
|
249
|
+
url: Optional URL from flag.
|
|
250
|
+
read_key_from_stdin: Whether to read key from stdin.
|
|
251
|
+
name: Account name (for error messages).
|
|
252
|
+
existing: Existing account data.
|
|
253
|
+
command_name: Command name for error messages.
|
|
254
|
+
existing_url: Existing account URL.
|
|
255
|
+
|
|
256
|
+
Returns:
|
|
257
|
+
Tuple of (api_url, api_key).
|
|
258
|
+
"""
|
|
259
|
+
if url and read_key_from_stdin:
|
|
260
|
+
# Non-interactive: URL from flag, key from stdin
|
|
261
|
+
return _get_credentials_non_interactive(url, True, name, command_name)
|
|
262
|
+
if url:
|
|
263
|
+
# URL provided, prompt for key
|
|
264
|
+
return _get_credentials_non_interactive(url, False, name, command_name)
|
|
265
|
+
if read_key_from_stdin and existing:
|
|
266
|
+
# Key rotation using stored URL
|
|
267
|
+
return _handle_key_rotation(name, existing_url, command_name)
|
|
268
|
+
# Fully interactive or error case
|
|
269
|
+
return _get_credentials_interactive(read_key_from_stdin, existing)
|
|
270
|
+
|
|
271
|
+
|
|
181
272
|
def _collect_account_credentials(
|
|
182
273
|
url: str | None,
|
|
183
274
|
read_key_from_stdin: bool,
|
|
@@ -198,15 +289,16 @@ def _collect_account_credentials(
|
|
|
198
289
|
Raises:
|
|
199
290
|
click.Abort: If credentials cannot be collected or are invalid.
|
|
200
291
|
"""
|
|
201
|
-
if
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
292
|
+
command_name = "aip accounts edit" if existing else "aip accounts add"
|
|
293
|
+
existing_url = existing.get("api_url", "") if existing else ""
|
|
294
|
+
existing_key = existing.get("api_key", "") if existing else ""
|
|
295
|
+
|
|
296
|
+
api_url, api_key = _collect_credentials_from_inputs(
|
|
297
|
+
url, read_key_from_stdin, name, existing, command_name, existing_url
|
|
298
|
+
)
|
|
299
|
+
|
|
300
|
+
# Preserve stored values when blank input is provided during edit
|
|
301
|
+
api_url, api_key = _preserve_existing_values(api_url, api_key, existing_url, existing_key)
|
|
210
302
|
|
|
211
303
|
if not api_url or not api_key:
|
|
212
304
|
console.print(f"[{ERROR_STYLE}]Error: Both API URL and API key are required.[/]")
|
|
@@ -235,12 +327,15 @@ def add_account(
|
|
|
235
327
|
read_key_from_stdin: bool,
|
|
236
328
|
overwrite: bool,
|
|
237
329
|
) -> None:
|
|
238
|
-
"""Add
|
|
330
|
+
"""Add a new account profile.
|
|
239
331
|
|
|
240
332
|
NAME is the account name (1-32 chars, alphanumeric, dash, underscore).
|
|
241
333
|
|
|
242
334
|
By default, this command runs interactively, prompting for API URL and key.
|
|
243
335
|
For non-interactive use, both --url and --key (stdin) are required.
|
|
336
|
+
|
|
337
|
+
If the account already exists, use --yes to overwrite without prompting.
|
|
338
|
+
To update an existing account, use [bold]aip accounts edit <name>[/bold] instead.
|
|
244
339
|
"""
|
|
245
340
|
store = get_account_store()
|
|
246
341
|
|
|
@@ -263,6 +358,55 @@ def add_account(
|
|
|
263
358
|
raise click.Abort() from e
|
|
264
359
|
|
|
265
360
|
|
|
361
|
+
@accounts_group.command("edit")
|
|
362
|
+
@click.argument("name")
|
|
363
|
+
@click.option("--url", help="API URL (optional, leave blank to keep current)")
|
|
364
|
+
@click.option(
|
|
365
|
+
"--key",
|
|
366
|
+
"read_key_from_stdin",
|
|
367
|
+
is_flag=True,
|
|
368
|
+
help="Read API key from stdin (secure, for scripts). Uses stored URL unless --url is provided.",
|
|
369
|
+
)
|
|
370
|
+
def edit_account(
|
|
371
|
+
name: str,
|
|
372
|
+
url: str | None,
|
|
373
|
+
read_key_from_stdin: bool,
|
|
374
|
+
) -> None:
|
|
375
|
+
"""Edit an existing account profile's URL or key.
|
|
376
|
+
|
|
377
|
+
NAME is the account name to edit.
|
|
378
|
+
|
|
379
|
+
By default, this command runs interactively, showing current values and
|
|
380
|
+
prompting for new ones. Leave fields blank to keep current values.
|
|
381
|
+
|
|
382
|
+
For non-interactive use, provide --url to change the URL, --key (stdin) to rotate the key,
|
|
383
|
+
or both. Stored values are reused for any fields not provided.
|
|
384
|
+
"""
|
|
385
|
+
store = get_account_store()
|
|
386
|
+
|
|
387
|
+
# Account must exist for edit
|
|
388
|
+
existing = store.get_account(name)
|
|
389
|
+
if not existing:
|
|
390
|
+
console.print(f"[{ERROR_STYLE}]Error: Account '{name}' not found.[/]")
|
|
391
|
+
console.print(f"Use [bold]aip accounts add {name}[/bold] to create a new account.")
|
|
392
|
+
raise click.Abort()
|
|
393
|
+
|
|
394
|
+
# Collect credentials (will pre-fill existing values in interactive mode)
|
|
395
|
+
api_url, api_key = _collect_account_credentials(url, read_key_from_stdin, name, existing)
|
|
396
|
+
|
|
397
|
+
# Save account
|
|
398
|
+
try:
|
|
399
|
+
store.add_account(name, api_url, api_key, overwrite=True)
|
|
400
|
+
console.print(Text(f"✅ Account '{name}' updated successfully", style=SUCCESS_STYLE))
|
|
401
|
+
_print_active_account_footer(store)
|
|
402
|
+
except InvalidAccountNameError as e:
|
|
403
|
+
console.print(f"[{ERROR_STYLE}]Error: {e}[/]")
|
|
404
|
+
raise click.Abort() from e
|
|
405
|
+
except AccountStoreError as e:
|
|
406
|
+
console.print(f"[{ERROR_STYLE}]Error: {e}[/]")
|
|
407
|
+
raise click.Abort() from e
|
|
408
|
+
|
|
409
|
+
|
|
266
410
|
@accounts_group.command("use")
|
|
267
411
|
@click.argument("name")
|
|
268
412
|
def use_account(name: str) -> None:
|
|
@@ -281,7 +425,8 @@ def use_account(name: str) -> None:
|
|
|
281
425
|
|
|
282
426
|
if not url or not api_key:
|
|
283
427
|
console.print(
|
|
284
|
-
f"[{ERROR_STYLE}]Error: Account '{name}' is missing credentials.
|
|
428
|
+
f"[{ERROR_STYLE}]Error: Account '{name}' is missing credentials. "
|
|
429
|
+
f"Use [bold]aip accounts edit {name}[/bold] to update credentials.[/]"
|
|
285
430
|
)
|
|
286
431
|
raise click.Abort()
|
|
287
432
|
|
glaip_sdk/cli/commands/agents.py
CHANGED
|
@@ -594,9 +594,12 @@ def list_agents(
|
|
|
594
594
|
f"{ICON_AGENT} Available Agents",
|
|
595
595
|
columns,
|
|
596
596
|
transform_agent,
|
|
597
|
-
skip_picker=
|
|
598
|
-
|
|
599
|
-
|
|
597
|
+
skip_picker=(
|
|
598
|
+
not interactive_enabled
|
|
599
|
+
or picker_attempted
|
|
600
|
+
or simple
|
|
601
|
+
or any(param is not None for param in (agent_type, framework, name, version))
|
|
602
|
+
),
|
|
600
603
|
use_pager=False,
|
|
601
604
|
)
|
|
602
605
|
|
glaip_sdk/cli/utils.py
CHANGED
|
@@ -875,10 +875,10 @@ def _strip_spaces_for_matching(value: str) -> str:
|
|
|
875
875
|
return re.sub(r"\s+", "", value)
|
|
876
876
|
|
|
877
877
|
|
|
878
|
-
def _is_fuzzy_match(search: Any, target:
|
|
879
|
-
"""Case-insensitive fuzzy match with optional spaces."""
|
|
878
|
+
def _is_fuzzy_match(search: Any, target: Any) -> bool:
|
|
879
|
+
"""Case-insensitive fuzzy match with optional spaces; returns False for non-string inputs."""
|
|
880
880
|
# Ensure search is a string
|
|
881
|
-
if not isinstance(search, str):
|
|
881
|
+
if not isinstance(search, str) or not isinstance(target, str):
|
|
882
882
|
return False
|
|
883
883
|
|
|
884
884
|
if not search:
|
|
@@ -1000,13 +1000,15 @@ def _rank_labels(labels: list[str], query: Any) -> list[str]:
|
|
|
1000
1000
|
Labels sorted by fuzzy score (descending), then case-insensitive label,
|
|
1001
1001
|
then id suffix for deterministic ordering.
|
|
1002
1002
|
"""
|
|
1003
|
+
suffix_cache = {label: _extract_id_suffix(label) for label in labels}
|
|
1004
|
+
|
|
1003
1005
|
if not query:
|
|
1004
1006
|
# No query: sort by case-insensitive label, then id suffix
|
|
1005
|
-
return sorted(labels, key=lambda lbl: (lbl.lower(),
|
|
1007
|
+
return sorted(labels, key=lambda lbl: (lbl.lower(), suffix_cache[lbl]))
|
|
1006
1008
|
|
|
1007
1009
|
# Ensure query is a string
|
|
1008
1010
|
if not isinstance(query, str):
|
|
1009
|
-
return sorted(labels, key=lambda lbl: (lbl.lower(),
|
|
1011
|
+
return sorted(labels, key=lambda lbl: (lbl.lower(), suffix_cache[lbl]))
|
|
1010
1012
|
|
|
1011
1013
|
query_lower = query.lower()
|
|
1012
1014
|
|
|
@@ -1016,11 +1018,11 @@ def _rank_labels(labels: list[str], query: Any) -> list[str]:
|
|
|
1016
1018
|
label_lower = label.lower()
|
|
1017
1019
|
score = _fuzzy_score(query_lower, label_lower)
|
|
1018
1020
|
if score >= 0: # Only include matches
|
|
1019
|
-
scored_labels.append((score, label_lower,
|
|
1021
|
+
scored_labels.append((score, label_lower, suffix_cache[label], label))
|
|
1020
1022
|
|
|
1021
1023
|
if not scored_labels:
|
|
1022
1024
|
# No fuzzy matches: fall back to deterministic label sorting
|
|
1023
|
-
return sorted(labels, key=lambda lbl: (lbl.lower(),
|
|
1025
|
+
return sorted(labels, key=lambda lbl: (lbl.lower(), suffix_cache[lbl]))
|
|
1024
1026
|
|
|
1025
1027
|
# Sort by: score (desc), label (case-insensitive), id suffix, original label
|
|
1026
1028
|
scored_labels.sort(key=lambda x: (-x[0], x[1], x[2], x[3]))
|
|
@@ -6,8 +6,8 @@ glaip_sdk/cli/account_store.py,sha256=NXuAVPaJS_32Aw1VTaZCNwIID-gADw4F_UMieoWmg3
|
|
|
6
6
|
glaip_sdk/cli/agent_config.py,sha256=YAbFKrTNTRqNA6b0i0Q3pH-01rhHDRi5v8dxSFwGSwM,2401
|
|
7
7
|
glaip_sdk/cli/auth.py,sha256=9hfjZyd4cx2_mImqykJ1sWQsuVTR2gy6D4hFqAQNKL4,24129
|
|
8
8
|
glaip_sdk/cli/commands/__init__.py,sha256=6Z3ASXDut0lAbUX_umBFtxPzzFyqoiZfVeTahThFu1A,219
|
|
9
|
-
glaip_sdk/cli/commands/accounts.py,sha256=
|
|
10
|
-
glaip_sdk/cli/commands/agents.py,sha256=
|
|
9
|
+
glaip_sdk/cli/commands/accounts.py,sha256=B5itsUzqoH_hBRYOVd2m4nPoIuBbPDIoK974zKMm9NE,18635
|
|
10
|
+
glaip_sdk/cli/commands/agents.py,sha256=35Ra1PLZYiSainYTtMBB40Iio5gDY_tyaDpeujoVdHw,47963
|
|
11
11
|
glaip_sdk/cli/commands/common_config.py,sha256=IY13gPkeifXxSdpzRFUvfRin8J7s38p6Y7TYjdGw7w4,2474
|
|
12
12
|
glaip_sdk/cli/commands/configure.py,sha256=8vfgtNEMK2lnEk3i6H1ZevsjxnYA6jAj4evhWmsHi6w,14494
|
|
13
13
|
glaip_sdk/cli/commands/mcps.py,sha256=tttqQnfM89iI9Pm94u8YRhiHMQNYNouecFX0brsT4cQ,42551
|
|
@@ -44,7 +44,7 @@ glaip_sdk/cli/transcript/history.py,sha256=2FBjawxP8CX9gRPMUMP8bDjG50BGM2j2zk6If
|
|
|
44
44
|
glaip_sdk/cli/transcript/launcher.py,sha256=z5ivkPXDQJpATIqtRLUK8jH3p3WIZ72PvOPqYRDMJvw,2327
|
|
45
45
|
glaip_sdk/cli/transcript/viewer.py,sha256=ar1SzRkhKIf3_DgFz1EG1RZGDmd2w2wogAe038DLL_M,13037
|
|
46
46
|
glaip_sdk/cli/update_notifier.py,sha256=qv-GfwTYZdrhlSbC_71I1AvKY9cV4QVBmtees16S2Xg,9807
|
|
47
|
-
glaip_sdk/cli/utils.py,sha256=
|
|
47
|
+
glaip_sdk/cli/utils.py,sha256=fV6PZlQ7K5zckpFWvwh3yLmETGrVylK9AXtN7zKBp-A,57374
|
|
48
48
|
glaip_sdk/cli/validators.py,sha256=d-kq4y7HWMo6Gc7wLXWUsCt8JwFvJX_roZqRm1Nko1I,5622
|
|
49
49
|
glaip_sdk/client/__init__.py,sha256=F-eE_dRSzA0cc1it06oi0tZetZBHmSUjWSHGhJMLCls,263
|
|
50
50
|
glaip_sdk/client/_agent_payloads.py,sha256=VfBHoijuoqUOixGBf2SA2vlQIXQmBsjB3sXHZhXYiec,17681
|
|
@@ -107,7 +107,7 @@ glaip_sdk/utils/resource_refs.py,sha256=vF34kyAtFBLnaKnQVrsr2st1JiSxVbIZ4yq0DelJ
|
|
|
107
107
|
glaip_sdk/utils/run_renderer.py,sha256=d_VMI6LbvHPUUeRmGqh5wK_lHqDEIAcym2iqpbtDad0,1365
|
|
108
108
|
glaip_sdk/utils/serialization.py,sha256=z-qpvWLSBrGK3wbUclcA1UIKLXJedTnMSwPdq-FF4lo,13308
|
|
109
109
|
glaip_sdk/utils/validation.py,sha256=Vt8oSnn7OM6ns5vjOl5FwGIMWBPb0yI6RD5XL_L5_4M,6826
|
|
110
|
-
glaip_sdk-0.5.
|
|
111
|
-
glaip_sdk-0.5.
|
|
112
|
-
glaip_sdk-0.5.
|
|
113
|
-
glaip_sdk-0.5.
|
|
110
|
+
glaip_sdk-0.5.2.dist-info/METADATA,sha256=yYVEtAsyIJBd3p6bgZxlvSIzUeOwSK-tI3DQVPAP0tI,7053
|
|
111
|
+
glaip_sdk-0.5.2.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
|
|
112
|
+
glaip_sdk-0.5.2.dist-info/entry_points.txt,sha256=EGs8NO8J1fdFMWA3CsF7sKBEvtHb_fujdCoNPhfMouE,47
|
|
113
|
+
glaip_sdk-0.5.2.dist-info/RECORD,,
|
|
File without changes
|
|
File without changes
|