glaip-sdk 0.1.3__py3-none-any.whl → 0.2.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.
- glaip_sdk/__init__.py +1 -1
- glaip_sdk/_version.py +1 -0
- glaip_sdk/cli/commands/__init__.py +2 -2
- glaip_sdk/cli/commands/agents.py +22 -37
- glaip_sdk/cli/commands/configure.py +69 -9
- glaip_sdk/cli/commands/mcps.py +19 -23
- glaip_sdk/cli/commands/tools.py +17 -41
- glaip_sdk/cli/commands/transcripts.py +747 -0
- glaip_sdk/cli/config.py +6 -1
- glaip_sdk/cli/display.py +1 -0
- glaip_sdk/cli/main.py +17 -37
- glaip_sdk/cli/parsers/__init__.py +1 -3
- glaip_sdk/cli/slash/__init__.py +0 -9
- glaip_sdk/cli/slash/prompt.py +2 -0
- glaip_sdk/cli/slash/session.py +251 -88
- glaip_sdk/cli/transcript/__init__.py +12 -52
- glaip_sdk/cli/transcript/cache.py +255 -44
- glaip_sdk/cli/transcript/capture.py +32 -0
- glaip_sdk/cli/transcript/history.py +815 -0
- glaip_sdk/cli/transcript/viewer.py +6 -2
- glaip_sdk/cli/utils.py +187 -0
- glaip_sdk/client/_agent_payloads.py +5 -0
- glaip_sdk/payload_schemas/__init__.py +1 -13
- glaip_sdk/utils/__init__.py +12 -7
- glaip_sdk/utils/datetime_helpers.py +58 -0
- glaip_sdk/utils/general.py +0 -33
- glaip_sdk/utils/import_export.py +9 -1
- glaip_sdk/utils/rendering/renderer/__init__.py +0 -20
- glaip_sdk/utils/rendering/renderer/debug.py +3 -20
- glaip_sdk/utils/rendering/steps.py +5 -6
- glaip_sdk/utils/resource_refs.py +2 -1
- glaip_sdk/utils/serialization.py +2 -0
- {glaip_sdk-0.1.3.dist-info → glaip_sdk-0.2.0.dist-info}/METADATA +1 -1
- {glaip_sdk-0.1.3.dist-info → glaip_sdk-0.2.0.dist-info}/RECORD +36 -33
- {glaip_sdk-0.1.3.dist-info → glaip_sdk-0.2.0.dist-info}/WHEEL +0 -0
- {glaip_sdk-0.1.3.dist-info → glaip_sdk-0.2.0.dist-info}/entry_points.txt +0 -0
glaip_sdk/__init__.py
CHANGED
|
@@ -9,4 +9,4 @@ from glaip_sdk.client import Client
|
|
|
9
9
|
from glaip_sdk.exceptions import AIPError
|
|
10
10
|
from glaip_sdk.models import MCP, Agent, Tool
|
|
11
11
|
|
|
12
|
-
__all__ = ["
|
|
12
|
+
__all__ = ["Client", "Agent", "Tool", "MCP", "AIPError", "__version__"]
|
glaip_sdk/_version.py
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"""CLI commands package exports."""
|
|
2
2
|
|
|
3
|
-
from glaip_sdk.cli.commands import agents, configure, mcps, models, tools, update
|
|
3
|
+
from glaip_sdk.cli.commands import agents, configure, mcps, models, tools, transcripts, update
|
|
4
4
|
|
|
5
|
-
__all__ = ["agents", "configure", "mcps", "models", "tools", "update"]
|
|
5
|
+
__all__ = ["agents", "configure", "mcps", "models", "tools", "transcripts", "update"]
|
glaip_sdk/cli/commands/agents.py
CHANGED
|
@@ -32,7 +32,7 @@ from glaip_sdk.cli.agent_config import (
|
|
|
32
32
|
from glaip_sdk.cli.agent_config import (
|
|
33
33
|
sanitize_agent_config_for_cli as sanitize_agent_config,
|
|
34
34
|
)
|
|
35
|
-
from glaip_sdk.cli.context import
|
|
35
|
+
from glaip_sdk.cli.context import get_ctx_value, output_flags
|
|
36
36
|
from glaip_sdk.cli.display import (
|
|
37
37
|
build_resource_result_data,
|
|
38
38
|
display_agent_run_suggestions,
|
|
@@ -44,9 +44,6 @@ from glaip_sdk.cli.display import (
|
|
|
44
44
|
handle_rich_output,
|
|
45
45
|
print_api_error,
|
|
46
46
|
)
|
|
47
|
-
from glaip_sdk.cli.io import (
|
|
48
|
-
export_resource_to_file_with_validation as export_resource_to_file,
|
|
49
|
-
)
|
|
50
47
|
from glaip_sdk.cli.io import (
|
|
51
48
|
fetch_raw_resource_details,
|
|
52
49
|
)
|
|
@@ -360,6 +357,7 @@ def agents_group() -> None:
|
|
|
360
357
|
pass
|
|
361
358
|
|
|
362
359
|
|
|
360
|
+
# pylint: disable=duplicate-code
|
|
363
361
|
def _resolve_agent(
|
|
364
362
|
ctx: Any,
|
|
365
363
|
client: Any,
|
|
@@ -493,8 +491,9 @@ def list_agents(
|
|
|
493
491
|
@output_flags()
|
|
494
492
|
@click.pass_context
|
|
495
493
|
def get(ctx: Any, agent_ref: str, select: int | None, export: str | None) -> None:
|
|
496
|
-
"""Get agent details.
|
|
494
|
+
r"""Get agent details.
|
|
497
495
|
|
|
496
|
+
\b
|
|
498
497
|
Examples:
|
|
499
498
|
aip agents get my-agent
|
|
500
499
|
aip agents get my-agent --export agent.json # Exports complete configuration as JSON
|
|
@@ -508,35 +507,15 @@ def get(ctx: Any, agent_ref: str, select: int | None, export: str | None) -> Non
|
|
|
508
507
|
|
|
509
508
|
# Handle export option
|
|
510
509
|
if export:
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
# Always export comprehensive data - re-fetch agent with full details
|
|
516
|
-
try:
|
|
517
|
-
with spinner_context(
|
|
518
|
-
ctx,
|
|
519
|
-
"[bold blue]Fetching complete agent data…[/bold blue]",
|
|
520
|
-
console_override=console,
|
|
521
|
-
):
|
|
522
|
-
agent = client.agents.get_agent_by_id(agent.id)
|
|
523
|
-
except Exception as e:
|
|
524
|
-
handle_rich_output(
|
|
525
|
-
ctx,
|
|
526
|
-
markup_text(f"[{WARNING_STYLE}]⚠️ Could not fetch full agent details: {e}[/]"),
|
|
527
|
-
)
|
|
528
|
-
handle_rich_output(
|
|
529
|
-
ctx,
|
|
530
|
-
markup_text(f"[{WARNING_STYLE}]⚠️ Proceeding with available data[/]"),
|
|
531
|
-
)
|
|
532
|
-
|
|
533
|
-
export_resource_to_file(agent, export_path, detected_format)
|
|
534
|
-
handle_rich_output(
|
|
510
|
+
from glaip_sdk.cli.utils import handle_resource_export
|
|
511
|
+
|
|
512
|
+
handle_resource_export(
|
|
535
513
|
ctx,
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
514
|
+
agent,
|
|
515
|
+
Path(export),
|
|
516
|
+
resource_type="agent",
|
|
517
|
+
get_by_id_func=client.agents.get_agent_by_id,
|
|
518
|
+
console_override=console,
|
|
540
519
|
)
|
|
541
520
|
|
|
542
521
|
# Display full agent details using the standardized helper
|
|
@@ -706,10 +685,11 @@ def run(
|
|
|
706
685
|
files: tuple[str, ...] | None,
|
|
707
686
|
verbose: bool,
|
|
708
687
|
) -> None:
|
|
709
|
-
"""Run an agent with input text.
|
|
688
|
+
r"""Run an agent with input text.
|
|
710
689
|
|
|
711
690
|
Usage: aip agents run <agent_ref> <input_text> [OPTIONS]
|
|
712
691
|
|
|
692
|
+
\b
|
|
713
693
|
Examples:
|
|
714
694
|
aip agents run my-agent "Hello world"
|
|
715
695
|
aip agents run agent-123 "Process this data" --timeout 600
|
|
@@ -778,11 +758,13 @@ def run(
|
|
|
778
758
|
|
|
779
759
|
|
|
780
760
|
def _running_in_slash_mode(ctx: Any) -> bool:
|
|
761
|
+
"""Return True if the command is executing inside the slash session."""
|
|
781
762
|
ctx_obj = getattr(ctx, "obj", None)
|
|
782
763
|
return isinstance(ctx_obj, dict) and bool(ctx_obj.get("_slash_session"))
|
|
783
764
|
|
|
784
765
|
|
|
785
766
|
def _emit_verbose_guidance(ctx: Any) -> None:
|
|
767
|
+
"""Explain the modern alternative to the deprecated --verbose flag."""
|
|
786
768
|
if _running_in_slash_mode(ctx):
|
|
787
769
|
message = (
|
|
788
770
|
"[dim]Tip:[/] Verbose streaming has been retired in the command palette. Run the agent normally and open "
|
|
@@ -1037,8 +1019,9 @@ def create(
|
|
|
1037
1019
|
timeout: float | None,
|
|
1038
1020
|
import_file: str | None,
|
|
1039
1021
|
) -> None:
|
|
1040
|
-
"""Create a new agent.
|
|
1022
|
+
r"""Create a new agent.
|
|
1041
1023
|
|
|
1024
|
+
\b
|
|
1042
1025
|
Examples:
|
|
1043
1026
|
aip agents create --name "My Agent" --instruction "You are a helpful assistant"
|
|
1044
1027
|
aip agents create --import agent.json
|
|
@@ -1232,8 +1215,9 @@ def update(
|
|
|
1232
1215
|
timeout: float | None,
|
|
1233
1216
|
import_file: str | None,
|
|
1234
1217
|
) -> None:
|
|
1235
|
-
"""Update an existing agent.
|
|
1218
|
+
r"""Update an existing agent.
|
|
1236
1219
|
|
|
1220
|
+
\b
|
|
1237
1221
|
Examples:
|
|
1238
1222
|
aip agents update my-agent --instruction "New instruction"
|
|
1239
1223
|
aip agents update my-agent --import agent.json
|
|
@@ -1327,7 +1311,7 @@ def delete(ctx: Any, agent_id: str, yes: bool) -> None:
|
|
|
1327
1311
|
@output_flags()
|
|
1328
1312
|
@click.pass_context
|
|
1329
1313
|
def sync_langflow(ctx: Any, base_url: str | None, api_key: str | None) -> None:
|
|
1330
|
-
"""Sync agents with LangFlow server flows.
|
|
1314
|
+
r"""Sync agents with LangFlow server flows.
|
|
1331
1315
|
|
|
1332
1316
|
This command fetches all flows from the configured LangFlow server and
|
|
1333
1317
|
creates/updates corresponding agents in the platform.
|
|
@@ -1336,6 +1320,7 @@ def sync_langflow(ctx: Any, base_url: str | None, api_key: str | None) -> None:
|
|
|
1336
1320
|
- Command options (--base-url, --api-key)
|
|
1337
1321
|
- Environment variables (LANGFLOW_BASE_URL, LANGFLOW_API_KEY)
|
|
1338
1322
|
|
|
1323
|
+
\b
|
|
1339
1324
|
Examples:
|
|
1340
1325
|
aip agents sync-langflow
|
|
1341
1326
|
aip agents sync-langflow --base-url https://my-langflow.com --api-key my-key
|
|
@@ -11,7 +11,6 @@ from rich.console import Console
|
|
|
11
11
|
from rich.text import Text
|
|
12
12
|
|
|
13
13
|
from glaip_sdk import Client
|
|
14
|
-
from glaip_sdk._version import __version__ as _SDK_VERSION
|
|
15
14
|
from glaip_sdk.branding import (
|
|
16
15
|
ACCENT_STYLE,
|
|
17
16
|
ERROR_STYLE,
|
|
@@ -24,7 +23,7 @@ from glaip_sdk.branding import (
|
|
|
24
23
|
)
|
|
25
24
|
from glaip_sdk.cli.config import CONFIG_FILE, load_config, save_config
|
|
26
25
|
from glaip_sdk.cli.rich_helpers import markup_text
|
|
27
|
-
from glaip_sdk.cli.utils import command_hint, format_command_hint
|
|
26
|
+
from glaip_sdk.cli.utils import command_hint, format_command_hint, sdk_version
|
|
28
27
|
from glaip_sdk.icons import ICON_TOOL
|
|
29
28
|
from glaip_sdk.rich_components import AIPTable
|
|
30
29
|
|
|
@@ -49,25 +48,76 @@ def list_config() -> None:
|
|
|
49
48
|
_render_config_table(config)
|
|
50
49
|
|
|
51
50
|
|
|
51
|
+
CONFIG_VALUE_TYPES: dict[str, str] = {
|
|
52
|
+
"api_url": "string",
|
|
53
|
+
"api_key": "string",
|
|
54
|
+
"timeout": "float",
|
|
55
|
+
"history_default_limit": "int",
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
|
|
59
|
+
def _parse_bool_config(value: str) -> bool:
|
|
60
|
+
"""Parse boolean-like CLI input."""
|
|
61
|
+
normalized = value.strip().lower()
|
|
62
|
+
if normalized in {"1", "true", "yes", "on"}:
|
|
63
|
+
return True
|
|
64
|
+
if normalized in {"0", "false", "no", "off"}:
|
|
65
|
+
return False
|
|
66
|
+
raise click.ClickException("Invalid boolean value. Use one of: true, false, yes, no, 1, 0.")
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
def _parse_int_config(value: str) -> int:
|
|
70
|
+
"""Parse integer CLI input with non-negative enforcement."""
|
|
71
|
+
try:
|
|
72
|
+
parsed = int(value, 10)
|
|
73
|
+
except ValueError as exc:
|
|
74
|
+
raise click.ClickException("Invalid integer value.") from exc
|
|
75
|
+
if parsed < 0:
|
|
76
|
+
raise click.ClickException("Value must be greater than or equal to 0.")
|
|
77
|
+
return parsed
|
|
78
|
+
|
|
79
|
+
|
|
80
|
+
def _parse_float_config(value: str) -> float:
|
|
81
|
+
"""Parse float CLI input with non-negative enforcement."""
|
|
82
|
+
try:
|
|
83
|
+
parsed = float(value)
|
|
84
|
+
except ValueError as exc:
|
|
85
|
+
raise click.ClickException("Invalid float value.") from exc
|
|
86
|
+
if parsed < 0:
|
|
87
|
+
raise click.ClickException("Value must be greater than or equal to 0.")
|
|
88
|
+
return parsed
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
def _coerce_config_value(key: str, raw_value: str) -> str | bool | int | float:
|
|
92
|
+
"""Convert CLI string values to their target config types."""
|
|
93
|
+
kind = CONFIG_VALUE_TYPES.get(key, "string")
|
|
94
|
+
if kind == "bool":
|
|
95
|
+
return _parse_bool_config(raw_value)
|
|
96
|
+
if kind == "int":
|
|
97
|
+
return _parse_int_config(raw_value)
|
|
98
|
+
if kind == "float":
|
|
99
|
+
return _parse_float_config(raw_value)
|
|
100
|
+
return raw_value
|
|
101
|
+
|
|
102
|
+
|
|
52
103
|
@config_group.command("set")
|
|
53
104
|
@click.argument("key")
|
|
54
105
|
@click.argument("value")
|
|
55
106
|
def set_config(key: str, value: str) -> None:
|
|
56
107
|
"""Set a configuration value."""
|
|
57
|
-
valid_keys =
|
|
108
|
+
valid_keys = tuple(CONFIG_VALUE_TYPES.keys())
|
|
58
109
|
|
|
59
110
|
if key not in valid_keys:
|
|
60
111
|
console.print(f"[{ERROR_STYLE}]Error: Invalid key '{key}'. Valid keys are: {', '.join(valid_keys)}[/]")
|
|
61
112
|
raise click.ClickException(f"Invalid configuration key: {key}")
|
|
62
113
|
|
|
114
|
+
coerced_value = _coerce_config_value(key, value)
|
|
63
115
|
config = load_config()
|
|
64
|
-
config[key] =
|
|
116
|
+
config[key] = coerced_value
|
|
65
117
|
save_config(config)
|
|
66
118
|
|
|
67
|
-
if key == "api_key"
|
|
68
|
-
|
|
69
|
-
else:
|
|
70
|
-
console.print(Text(f"✅ Set {key} = {value}", style=SUCCESS_STYLE))
|
|
119
|
+
display_value = _mask_api_key(coerced_value) if key == "api_key" else str(coerced_value)
|
|
120
|
+
console.print(Text(f"✅ Set {key} = {display_value}", style=SUCCESS_STYLE))
|
|
71
121
|
|
|
72
122
|
|
|
73
123
|
@config_group.command("get")
|
|
@@ -170,12 +220,14 @@ def configure_command() -> None:
|
|
|
170
220
|
|
|
171
221
|
|
|
172
222
|
def _mask_api_key(value: str | None) -> str:
|
|
223
|
+
"""Return a redacted API key string suitable for display."""
|
|
173
224
|
if not value:
|
|
174
225
|
return ""
|
|
175
226
|
return "***" + value[-4:] if len(value) > 4 else "***"
|
|
176
227
|
|
|
177
228
|
|
|
178
229
|
def _print_missing_config_hint() -> None:
|
|
230
|
+
"""Show guidance when no configuration file exists."""
|
|
179
231
|
hint = command_hint("config configure", slash_command="login")
|
|
180
232
|
if hint:
|
|
181
233
|
console.print(f"[{WARNING_STYLE}]No configuration found.[/] Run {format_command_hint(hint) or hint} to set up.")
|
|
@@ -184,6 +236,7 @@ def _print_missing_config_hint() -> None:
|
|
|
184
236
|
|
|
185
237
|
|
|
186
238
|
def _render_config_table(config: dict[str, str]) -> None:
|
|
239
|
+
"""Render the current configuration in a friendly table."""
|
|
187
240
|
table = AIPTable(title=f"{ICON_TOOL} AIP Configuration")
|
|
188
241
|
table.add_column("Setting", style=INFO, width=20)
|
|
189
242
|
table.add_column("Value", style=SUCCESS)
|
|
@@ -196,7 +249,8 @@ def _render_config_table(config: dict[str, str]) -> None:
|
|
|
196
249
|
|
|
197
250
|
|
|
198
251
|
def _render_configuration_header() -> None:
|
|
199
|
-
|
|
252
|
+
"""Display the interactive configuration heading/banner."""
|
|
253
|
+
branding = AIPBranding.create_from_sdk(sdk_version=sdk_version(), package_name="glaip-sdk")
|
|
200
254
|
heading = "[bold]>_ GDP Labs AI Agents Package (AIP CLI)[/bold]"
|
|
201
255
|
console.print(heading)
|
|
202
256
|
console.print()
|
|
@@ -205,6 +259,7 @@ def _render_configuration_header() -> None:
|
|
|
205
259
|
|
|
206
260
|
|
|
207
261
|
def _prompt_configuration_inputs(config: dict[str, str]) -> None:
|
|
262
|
+
"""Interactively prompt for configuration values."""
|
|
208
263
|
console.print("\n[bold]Enter your AIP configuration:[/bold]")
|
|
209
264
|
console.print("(Leave blank to keep current values)")
|
|
210
265
|
console.print("─" * 50)
|
|
@@ -214,6 +269,7 @@ def _prompt_configuration_inputs(config: dict[str, str]) -> None:
|
|
|
214
269
|
|
|
215
270
|
|
|
216
271
|
def _prompt_api_url(config: dict[str, str]) -> None:
|
|
272
|
+
"""Ask the user for the API URL, preserving existing values by default."""
|
|
217
273
|
current_url = config.get("api_url", "")
|
|
218
274
|
suffix = f"(current: {current_url})" if current_url else ""
|
|
219
275
|
console.print(f"\n[{ACCENT_STYLE}]AIP API URL[/] {suffix}:")
|
|
@@ -225,6 +281,7 @@ def _prompt_api_url(config: dict[str, str]) -> None:
|
|
|
225
281
|
|
|
226
282
|
|
|
227
283
|
def _prompt_api_key(config: dict[str, str]) -> None:
|
|
284
|
+
"""Prompt the user for the API key while masking previous input."""
|
|
228
285
|
current_key_masked = _mask_api_key(config.get("api_key"))
|
|
229
286
|
suffix = f"(current: {current_key_masked})" if current_key_masked else ""
|
|
230
287
|
console.print(f"\n[{ACCENT_STYLE}]AIP API Key[/] {suffix}:")
|
|
@@ -234,11 +291,13 @@ def _prompt_api_key(config: dict[str, str]) -> None:
|
|
|
234
291
|
|
|
235
292
|
|
|
236
293
|
def _save_configuration(config: dict[str, str]) -> None:
|
|
294
|
+
"""Persist the collected configuration to disk."""
|
|
237
295
|
save_config(config)
|
|
238
296
|
console.print(Text(f"\n✅ Configuration saved to: {CONFIG_FILE}", style=SUCCESS_STYLE))
|
|
239
297
|
|
|
240
298
|
|
|
241
299
|
def _test_and_report_connection(config: dict[str, str]) -> None:
|
|
300
|
+
"""Sanity-check the provided credentials against the backend."""
|
|
242
301
|
console.print("\n🔌 Testing connection...")
|
|
243
302
|
client: Client | None = None
|
|
244
303
|
try:
|
|
@@ -271,6 +330,7 @@ def _test_and_report_connection(config: dict[str, str]) -> None:
|
|
|
271
330
|
|
|
272
331
|
|
|
273
332
|
def _print_post_configuration_hints() -> None:
|
|
333
|
+
"""Offer next-step guidance after configuration completes."""
|
|
274
334
|
console.print("\n💡 You can now use AIP CLI commands!")
|
|
275
335
|
hint_status = command_hint("status", slash_command="status")
|
|
276
336
|
if hint_status:
|
glaip_sdk/cli/commands/mcps.py
CHANGED
|
@@ -53,7 +53,6 @@ from glaip_sdk.config.constants import (
|
|
|
53
53
|
)
|
|
54
54
|
from glaip_sdk.icons import ICON_TOOL
|
|
55
55
|
from glaip_sdk.rich_components import AIPPanel
|
|
56
|
-
from glaip_sdk.utils import format_datetime
|
|
57
56
|
from glaip_sdk.utils.import_export import convert_export_to_import_format
|
|
58
57
|
from glaip_sdk.utils.serialization import (
|
|
59
58
|
build_mcp_export_payload,
|
|
@@ -299,7 +298,7 @@ def mcps_group() -> None:
|
|
|
299
298
|
pass
|
|
300
299
|
|
|
301
300
|
|
|
302
|
-
def _resolve_mcp(ctx: Any, client: Any, ref: str, select: int | None = None) -> Any | None:
|
|
301
|
+
def _resolve_mcp(ctx: Any, client: Any, ref: str, select: int | None = None) -> Any | None: # pylint: disable=duplicate-code
|
|
303
302
|
"""Resolve MCP reference (ID or name) with ambiguity handling.
|
|
304
303
|
|
|
305
304
|
Args:
|
|
@@ -575,7 +574,7 @@ def create(
|
|
|
575
574
|
auth: str | None,
|
|
576
575
|
import_file: str | None,
|
|
577
576
|
) -> None:
|
|
578
|
-
"""Create a new MCP with specified configuration.
|
|
577
|
+
r"""Create a new MCP with specified configuration.
|
|
579
578
|
|
|
580
579
|
You can create an MCP by providing all parameters via CLI options, or by
|
|
581
580
|
importing from a file and optionally overriding specific fields.
|
|
@@ -593,6 +592,7 @@ def create(
|
|
|
593
592
|
Raises:
|
|
594
593
|
ClickException: If JSON parsing fails or API request fails
|
|
595
594
|
|
|
595
|
+
\b
|
|
596
596
|
Examples:
|
|
597
597
|
Create from CLI options:
|
|
598
598
|
aip mcps create --name my-mcp --transport http --config '{"url": "https://api.example.com"}'
|
|
@@ -696,19 +696,15 @@ def _handle_mcp_export(
|
|
|
696
696
|
detected_format = detect_export_format(export_path)
|
|
697
697
|
|
|
698
698
|
# Always export comprehensive data - re-fetch with full details
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
708
|
-
f"[{WARNING_STYLE}]⚠️ Could not fetch full MCP details: {e}[/]",
|
|
709
|
-
console=console,
|
|
710
|
-
)
|
|
711
|
-
print_markup(f"[{WARNING_STYLE}]⚠️ Proceeding with available data[/]", console=console)
|
|
699
|
+
from glaip_sdk.cli.utils import fetch_resource_for_export
|
|
700
|
+
|
|
701
|
+
mcp = fetch_resource_for_export(
|
|
702
|
+
ctx,
|
|
703
|
+
mcp,
|
|
704
|
+
resource_type="MCP",
|
|
705
|
+
get_by_id_func=client.mcps.get_mcp_by_id,
|
|
706
|
+
console_override=console,
|
|
707
|
+
)
|
|
712
708
|
|
|
713
709
|
# Determine if we should prompt for secrets
|
|
714
710
|
prompt_for_secrets = not no_auth_prompt and sys.stdin.isatty()
|
|
@@ -779,11 +775,9 @@ def _display_mcp_details(ctx: Any, client: Any, mcp: Any) -> None:
|
|
|
779
775
|
|
|
780
776
|
if raw_mcp_data:
|
|
781
777
|
# Use raw API data - this preserves ALL fields
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
if "updated_at" in formatted_data:
|
|
786
|
-
formatted_data["updated_at"] = format_datetime(formatted_data["updated_at"])
|
|
778
|
+
from glaip_sdk.cli.utils import format_datetime_fields
|
|
779
|
+
|
|
780
|
+
formatted_data = format_datetime_fields(raw_mcp_data)
|
|
787
781
|
|
|
788
782
|
output_result(
|
|
789
783
|
ctx,
|
|
@@ -832,7 +826,7 @@ def get(
|
|
|
832
826
|
no_auth_prompt: bool,
|
|
833
827
|
auth_placeholder: str,
|
|
834
828
|
) -> None:
|
|
835
|
-
"""Get MCP details and optionally export configuration to file.
|
|
829
|
+
r"""Get MCP details and optionally export configuration to file.
|
|
836
830
|
|
|
837
831
|
Args:
|
|
838
832
|
ctx: Click context containing output format preferences
|
|
@@ -844,6 +838,7 @@ def get(
|
|
|
844
838
|
Raises:
|
|
845
839
|
ClickException: If MCP not found or export fails
|
|
846
840
|
|
|
841
|
+
\b
|
|
847
842
|
Examples:
|
|
848
843
|
aip mcps get my-mcp
|
|
849
844
|
aip mcps get my-mcp --export mcp.json # Export as JSON
|
|
@@ -1050,7 +1045,7 @@ def update(
|
|
|
1050
1045
|
import_file: str | None,
|
|
1051
1046
|
y: bool,
|
|
1052
1047
|
) -> None:
|
|
1053
|
-
"""Update an existing MCP with new configuration values.
|
|
1048
|
+
r"""Update an existing MCP with new configuration values.
|
|
1054
1049
|
|
|
1055
1050
|
You can update an MCP by providing individual fields via CLI options, or by
|
|
1056
1051
|
importing from a file and optionally overriding specific fields.
|
|
@@ -1075,6 +1070,7 @@ def update(
|
|
|
1075
1070
|
CLI options override imported values when both are specified.
|
|
1076
1071
|
Uses PATCH for import-based updates, PUT/PATCH for CLI-only updates.
|
|
1077
1072
|
|
|
1073
|
+
\b
|
|
1078
1074
|
Examples:
|
|
1079
1075
|
Update with CLI options:
|
|
1080
1076
|
aip mcps update my-mcp --name new-name --transport sse
|
glaip_sdk/cli/commands/tools.py
CHANGED
|
@@ -4,6 +4,7 @@ Authors:
|
|
|
4
4
|
Raymond Christopher (raymond.christopher@gdplabs.id)
|
|
5
5
|
"""
|
|
6
6
|
|
|
7
|
+
# pylint: disable=duplicate-code
|
|
7
8
|
import json
|
|
8
9
|
import re
|
|
9
10
|
from pathlib import Path
|
|
@@ -19,7 +20,7 @@ from glaip_sdk.branding import (
|
|
|
19
20
|
SUCCESS_STYLE,
|
|
20
21
|
WARNING_STYLE,
|
|
21
22
|
)
|
|
22
|
-
from glaip_sdk.cli.context import
|
|
23
|
+
from glaip_sdk.cli.context import get_ctx_value, output_flags
|
|
23
24
|
from glaip_sdk.cli.display import (
|
|
24
25
|
display_api_error,
|
|
25
26
|
display_confirmation_prompt,
|
|
@@ -29,9 +30,6 @@ from glaip_sdk.cli.display import (
|
|
|
29
30
|
handle_json_output,
|
|
30
31
|
handle_rich_output,
|
|
31
32
|
)
|
|
32
|
-
from glaip_sdk.cli.io import (
|
|
33
|
-
export_resource_to_file_with_validation as export_resource_to_file,
|
|
34
|
-
)
|
|
35
33
|
from glaip_sdk.cli.io import (
|
|
36
34
|
fetch_raw_resource_details,
|
|
37
35
|
)
|
|
@@ -48,7 +46,6 @@ from glaip_sdk.cli.utils import (
|
|
|
48
46
|
spinner_context,
|
|
49
47
|
)
|
|
50
48
|
from glaip_sdk.icons import ICON_TOOL
|
|
51
|
-
from glaip_sdk.utils import format_datetime
|
|
52
49
|
from glaip_sdk.utils.import_export import merge_import_with_cli_args
|
|
53
50
|
|
|
54
51
|
console = Console()
|
|
@@ -60,6 +57,7 @@ def tools_group() -> None:
|
|
|
60
57
|
pass
|
|
61
58
|
|
|
62
59
|
|
|
60
|
+
# pylint: disable=duplicate-code
|
|
63
61
|
def _resolve_tool(ctx: Any, client: Any, ref: str, select: int | None = None) -> Any | None:
|
|
64
62
|
"""Resolve tool reference (ID or name) with ambiguity handling."""
|
|
65
63
|
return resolve_resource_reference(
|
|
@@ -118,6 +116,7 @@ def _check_duplicate_name(client: Any, tool_name: str) -> None:
|
|
|
118
116
|
|
|
119
117
|
|
|
120
118
|
def _parse_tags(tags: str | None) -> list[str]:
|
|
119
|
+
"""Return a cleaned list of tag strings from a comma-separated input."""
|
|
121
120
|
return [t.strip() for t in (tags.split(",") if tags else []) if t.strip()]
|
|
122
121
|
|
|
123
122
|
|
|
@@ -259,8 +258,9 @@ def create(
|
|
|
259
258
|
tags: tuple[str, ...] | None,
|
|
260
259
|
import_file: str | None,
|
|
261
260
|
) -> None:
|
|
262
|
-
"""Create a new tool.
|
|
261
|
+
r"""Create a new tool.
|
|
263
262
|
|
|
263
|
+
\b
|
|
264
264
|
Examples:
|
|
265
265
|
aip tools create tool.py # Create from file
|
|
266
266
|
aip tools create --import tool.json # Create from exported configuration
|
|
@@ -325,8 +325,9 @@ def create(
|
|
|
325
325
|
@output_flags()
|
|
326
326
|
@click.pass_context
|
|
327
327
|
def get(ctx: Any, tool_ref: str, select: int | None, export: str | None) -> None:
|
|
328
|
-
"""Get tool details.
|
|
328
|
+
r"""Get tool details.
|
|
329
329
|
|
|
330
|
+
\b
|
|
330
331
|
Examples:
|
|
331
332
|
aip tools get my-tool
|
|
332
333
|
aip tools get my-tool --export tool.json # Exports complete configuration as JSON
|
|
@@ -340,38 +341,15 @@ def get(ctx: Any, tool_ref: str, select: int | None, export: str | None) -> None
|
|
|
340
341
|
|
|
341
342
|
# Handle export option
|
|
342
343
|
if export:
|
|
343
|
-
|
|
344
|
-
# Auto-detect format from file extension
|
|
345
|
-
detected_format = detect_export_format(export_path)
|
|
346
|
-
|
|
347
|
-
# Always export comprehensive data - re-fetch tool with full details if needed
|
|
348
|
-
try:
|
|
349
|
-
with spinner_context(
|
|
350
|
-
ctx,
|
|
351
|
-
"[bold blue]Fetching complete tool details…[/bold blue]",
|
|
352
|
-
console_override=console,
|
|
353
|
-
):
|
|
354
|
-
tool = client.get_tool_by_id(tool.id)
|
|
355
|
-
except Exception as e:
|
|
356
|
-
print_markup(
|
|
357
|
-
f"[{WARNING_STYLE}]⚠️ Could not fetch full tool details: {e}[/]",
|
|
358
|
-
console=console,
|
|
359
|
-
)
|
|
360
|
-
print_markup(
|
|
361
|
-
f"[{WARNING_STYLE}]⚠️ Proceeding with available data[/]",
|
|
362
|
-
console=console,
|
|
363
|
-
)
|
|
344
|
+
from glaip_sdk.cli.utils import handle_resource_export
|
|
364
345
|
|
|
365
|
-
|
|
346
|
+
handle_resource_export(
|
|
366
347
|
ctx,
|
|
367
|
-
|
|
348
|
+
tool,
|
|
349
|
+
Path(export),
|
|
350
|
+
resource_type="tool",
|
|
351
|
+
get_by_id_func=client.get_tool_by_id,
|
|
368
352
|
console_override=console,
|
|
369
|
-
):
|
|
370
|
-
export_resource_to_file(tool, export_path, detected_format)
|
|
371
|
-
print_markup(
|
|
372
|
-
f"[{SUCCESS_STYLE}]✅ Complete tool configuration exported to: {export_path} "
|
|
373
|
-
f"(format: {detected_format})[/]",
|
|
374
|
-
console=console,
|
|
375
353
|
)
|
|
376
354
|
|
|
377
355
|
# Try to fetch raw API data first to preserve ALL fields
|
|
@@ -385,11 +363,9 @@ def get(ctx: Any, tool_ref: str, select: int | None, export: str | None) -> None
|
|
|
385
363
|
if raw_tool_data:
|
|
386
364
|
# Use raw API data - this preserves ALL fields
|
|
387
365
|
# Format dates for better display (minimal postprocessing)
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
if "updated_at" in formatted_data:
|
|
392
|
-
formatted_data["updated_at"] = format_datetime(formatted_data["updated_at"])
|
|
366
|
+
from glaip_sdk.cli.utils import format_datetime_fields
|
|
367
|
+
|
|
368
|
+
formatted_data = format_datetime_fields(raw_tool_data)
|
|
393
369
|
|
|
394
370
|
# Display using output_result with raw data
|
|
395
371
|
output_result(
|