glaip-sdk 0.0.4__py3-none-any.whl → 0.0.5b1__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 +5 -5
- glaip_sdk/branding.py +18 -17
- glaip_sdk/cli/__init__.py +1 -1
- glaip_sdk/cli/agent_config.py +82 -0
- glaip_sdk/cli/commands/__init__.py +3 -3
- glaip_sdk/cli/commands/agents.py +570 -673
- glaip_sdk/cli/commands/configure.py +2 -2
- glaip_sdk/cli/commands/mcps.py +148 -143
- glaip_sdk/cli/commands/models.py +1 -1
- glaip_sdk/cli/commands/tools.py +250 -179
- glaip_sdk/cli/display.py +244 -0
- glaip_sdk/cli/io.py +106 -0
- glaip_sdk/cli/main.py +14 -18
- glaip_sdk/cli/resolution.py +59 -0
- glaip_sdk/cli/utils.py +305 -264
- glaip_sdk/cli/validators.py +235 -0
- glaip_sdk/client/__init__.py +3 -224
- glaip_sdk/client/agents.py +631 -191
- glaip_sdk/client/base.py +66 -4
- glaip_sdk/client/main.py +226 -0
- glaip_sdk/client/mcps.py +143 -18
- glaip_sdk/client/tools.py +146 -11
- glaip_sdk/config/constants.py +10 -1
- glaip_sdk/models.py +42 -2
- glaip_sdk/rich_components.py +29 -0
- glaip_sdk/utils/__init__.py +18 -171
- glaip_sdk/utils/agent_config.py +181 -0
- glaip_sdk/utils/client_utils.py +159 -79
- glaip_sdk/utils/display.py +100 -0
- glaip_sdk/utils/general.py +94 -0
- glaip_sdk/utils/import_export.py +140 -0
- glaip_sdk/utils/rendering/formatting.py +6 -1
- glaip_sdk/utils/rendering/renderer/__init__.py +67 -8
- glaip_sdk/utils/rendering/renderer/base.py +340 -247
- glaip_sdk/utils/rendering/renderer/debug.py +3 -2
- glaip_sdk/utils/rendering/renderer/panels.py +11 -10
- glaip_sdk/utils/rendering/steps.py +1 -1
- glaip_sdk/utils/resource_refs.py +192 -0
- glaip_sdk/utils/rich_utils.py +29 -0
- glaip_sdk/utils/serialization.py +285 -0
- glaip_sdk/utils/validation.py +273 -0
- {glaip_sdk-0.0.4.dist-info → glaip_sdk-0.0.5b1.dist-info}/METADATA +22 -21
- glaip_sdk-0.0.5b1.dist-info/RECORD +55 -0
- {glaip_sdk-0.0.4.dist-info → glaip_sdk-0.0.5b1.dist-info}/WHEEL +1 -1
- glaip_sdk-0.0.5b1.dist-info/entry_points.txt +3 -0
- glaip_sdk/cli/commands/init.py +0 -93
- glaip_sdk-0.0.4.dist-info/RECORD +0 -41
- glaip_sdk-0.0.4.dist-info/entry_points.txt +0 -2
glaip_sdk/cli/commands/tools.py
CHANGED
|
@@ -6,20 +6,40 @@ Authors:
|
|
|
6
6
|
|
|
7
7
|
import json
|
|
8
8
|
import re
|
|
9
|
+
from pathlib import Path
|
|
9
10
|
|
|
10
11
|
import click
|
|
11
12
|
from rich.console import Console
|
|
12
|
-
from rich.panel import Panel
|
|
13
13
|
from rich.text import Text
|
|
14
14
|
|
|
15
|
-
from
|
|
15
|
+
from glaip_sdk.cli.display import (
|
|
16
|
+
display_api_error,
|
|
17
|
+
display_confirmation_prompt,
|
|
18
|
+
display_creation_success,
|
|
19
|
+
display_deletion_success,
|
|
20
|
+
display_update_success,
|
|
21
|
+
handle_json_output,
|
|
22
|
+
handle_rich_output,
|
|
23
|
+
)
|
|
24
|
+
from glaip_sdk.cli.io import (
|
|
25
|
+
export_resource_to_file_with_validation as export_resource_to_file,
|
|
26
|
+
)
|
|
27
|
+
from glaip_sdk.cli.io import (
|
|
28
|
+
fetch_raw_resource_details,
|
|
29
|
+
)
|
|
30
|
+
from glaip_sdk.cli.io import (
|
|
31
|
+
load_resource_from_file_with_validation as load_resource_from_file,
|
|
32
|
+
)
|
|
33
|
+
from glaip_sdk.cli.resolution import resolve_resource_reference
|
|
34
|
+
from glaip_sdk.cli.utils import (
|
|
16
35
|
coerce_to_row,
|
|
17
36
|
get_client,
|
|
18
37
|
output_flags,
|
|
19
38
|
output_list,
|
|
20
39
|
output_result,
|
|
21
|
-
resolve_resource,
|
|
22
40
|
)
|
|
41
|
+
from glaip_sdk.utils import format_datetime
|
|
42
|
+
from glaip_sdk.utils.import_export import merge_import_with_cli_args
|
|
23
43
|
|
|
24
44
|
console = Console()
|
|
25
45
|
|
|
@@ -32,12 +52,14 @@ def tools_group():
|
|
|
32
52
|
|
|
33
53
|
def _resolve_tool(ctx, client, ref, select=None):
|
|
34
54
|
"""Resolve tool reference (ID or name) with ambiguity handling."""
|
|
35
|
-
return
|
|
55
|
+
return resolve_resource_reference(
|
|
36
56
|
ctx,
|
|
57
|
+
client,
|
|
37
58
|
ref,
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
59
|
+
"tool",
|
|
60
|
+
client.get_tool,
|
|
61
|
+
client.find_tools,
|
|
62
|
+
"Tool",
|
|
41
63
|
select=select,
|
|
42
64
|
)
|
|
43
65
|
|
|
@@ -91,12 +113,19 @@ def _parse_tags(tags: str | None) -> list[str]:
|
|
|
91
113
|
|
|
92
114
|
@tools_group.command(name="list")
|
|
93
115
|
@output_flags()
|
|
116
|
+
@click.option(
|
|
117
|
+
"--type",
|
|
118
|
+
"tool_type",
|
|
119
|
+
help="Filter tools by type (e.g., custom, native)",
|
|
120
|
+
type=str,
|
|
121
|
+
required=False,
|
|
122
|
+
)
|
|
94
123
|
@click.pass_context
|
|
95
|
-
def list_tools(ctx):
|
|
124
|
+
def list_tools(ctx, tool_type):
|
|
96
125
|
"""List all tools."""
|
|
97
126
|
try:
|
|
98
127
|
client = get_client(ctx)
|
|
99
|
-
tools = client.list_tools()
|
|
128
|
+
tools = client.list_tools(tool_type=tool_type)
|
|
100
129
|
|
|
101
130
|
# Define table columns: (data_key, header, style, width)
|
|
102
131
|
columns = [
|
|
@@ -137,19 +166,59 @@ def list_tools(ctx):
|
|
|
137
166
|
"--tags",
|
|
138
167
|
help="Comma-separated tags for the tool",
|
|
139
168
|
)
|
|
169
|
+
@click.option(
|
|
170
|
+
"--import",
|
|
171
|
+
"import_file",
|
|
172
|
+
type=click.Path(exists=True, dir_okay=False),
|
|
173
|
+
help="Import tool configuration from JSON file",
|
|
174
|
+
)
|
|
140
175
|
@output_flags()
|
|
141
176
|
@click.pass_context
|
|
142
|
-
def create(ctx, file_arg, file, name, description, tags):
|
|
143
|
-
"""Create a new tool.
|
|
177
|
+
def create(ctx, file_arg, file, name, description, tags, import_file):
|
|
178
|
+
"""Create a new tool.
|
|
179
|
+
|
|
180
|
+
Examples:
|
|
181
|
+
aip tools create --name "My Tool" --description "A helpful tool"
|
|
182
|
+
aip tools create tool.py # Create from file
|
|
183
|
+
aip tools create --import tool.json # Create from exported configuration
|
|
184
|
+
"""
|
|
144
185
|
try:
|
|
145
186
|
client = get_client(ctx)
|
|
146
187
|
|
|
188
|
+
# Initialize merged_data for cases without import_file
|
|
189
|
+
merged_data = {}
|
|
190
|
+
|
|
191
|
+
# Handle import from file
|
|
192
|
+
if import_file:
|
|
193
|
+
import_data = load_resource_from_file(Path(import_file), "tool")
|
|
194
|
+
|
|
195
|
+
# Merge CLI args with imported data
|
|
196
|
+
cli_args = {
|
|
197
|
+
"name": name,
|
|
198
|
+
"description": description,
|
|
199
|
+
"tags": tags,
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
merged_data = merge_import_with_cli_args(import_data, cli_args)
|
|
203
|
+
else:
|
|
204
|
+
# No import file - use CLI args directly
|
|
205
|
+
merged_data = {
|
|
206
|
+
"name": name,
|
|
207
|
+
"description": description,
|
|
208
|
+
"tags": tags,
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
# Extract merged values
|
|
212
|
+
name = merged_data.get("name")
|
|
213
|
+
description = merged_data.get("description")
|
|
214
|
+
tags = merged_data.get("tags")
|
|
215
|
+
|
|
147
216
|
# Allow positional file argument for better DX (matches examples)
|
|
148
217
|
if not file and file_arg:
|
|
149
218
|
file = file_arg
|
|
150
219
|
|
|
151
220
|
# Validate required parameters based on creation method
|
|
152
|
-
if not file:
|
|
221
|
+
if not file and not import_file:
|
|
153
222
|
# Metadata-only tool creation
|
|
154
223
|
if not name:
|
|
155
224
|
raise click.ClickException(
|
|
@@ -168,14 +237,14 @@ def create(ctx, file_arg, file, name, description, tags):
|
|
|
168
237
|
|
|
169
238
|
# Upload the plugin code as-is (no rewrite)
|
|
170
239
|
tool = client.create_tool_from_code(
|
|
171
|
-
tool_name,
|
|
172
|
-
code_content,
|
|
240
|
+
name=tool_name,
|
|
241
|
+
code=code_content,
|
|
173
242
|
framework="langchain", # Always langchain
|
|
174
243
|
description=description,
|
|
175
|
-
tags=_parse_tags(tags),
|
|
244
|
+
tags=_parse_tags(tags) if tags else None,
|
|
176
245
|
)
|
|
177
246
|
else:
|
|
178
|
-
# Metadata-only tool creation
|
|
247
|
+
# Metadata-only tool creation or import from file
|
|
179
248
|
tool_kwargs = {}
|
|
180
249
|
if name:
|
|
181
250
|
tool_kwargs["name"] = name
|
|
@@ -186,60 +255,141 @@ def create(ctx, file_arg, file, name, description, tags):
|
|
|
186
255
|
if tags:
|
|
187
256
|
tool_kwargs["tags"] = _parse_tags(tags)
|
|
188
257
|
|
|
258
|
+
# If importing from file, include all other detected attributes
|
|
259
|
+
if import_file:
|
|
260
|
+
# Add all other attributes from import data (excluding already handled ones)
|
|
261
|
+
excluded_fields = {
|
|
262
|
+
"name",
|
|
263
|
+
"description",
|
|
264
|
+
"tags",
|
|
265
|
+
# System-only fields that shouldn't be passed to create_tool
|
|
266
|
+
"id",
|
|
267
|
+
"created_at",
|
|
268
|
+
"updated_at",
|
|
269
|
+
"tool_type",
|
|
270
|
+
"framework",
|
|
271
|
+
"version",
|
|
272
|
+
}
|
|
273
|
+
for key, value in merged_data.items():
|
|
274
|
+
if key not in excluded_fields and value is not None:
|
|
275
|
+
tool_kwargs[key] = value
|
|
276
|
+
|
|
189
277
|
tool = client.create_tool(**tool_kwargs)
|
|
190
278
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
)
|
|
207
|
-
console.print(panel)
|
|
279
|
+
# Handle JSON output
|
|
280
|
+
handle_json_output(ctx, tool.model_dump())
|
|
281
|
+
|
|
282
|
+
# Handle Rich output
|
|
283
|
+
creation_method = "file upload (custom)" if file else "metadata only (native)"
|
|
284
|
+
rich_panel = display_creation_success(
|
|
285
|
+
"Tool",
|
|
286
|
+
tool.name,
|
|
287
|
+
tool.id,
|
|
288
|
+
Framework=getattr(tool, "framework", "N/A"),
|
|
289
|
+
Type=getattr(tool, "tool_type", "N/A"),
|
|
290
|
+
Description=getattr(tool, "description", "No description"),
|
|
291
|
+
Method=creation_method,
|
|
292
|
+
)
|
|
293
|
+
handle_rich_output(ctx, rich_panel)
|
|
208
294
|
|
|
209
295
|
except Exception as e:
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
console.print(Text(f"[red]Error creating tool: {e}[/red]"))
|
|
296
|
+
handle_json_output(ctx, error=e)
|
|
297
|
+
if ctx.obj.get("view") != "json":
|
|
298
|
+
display_api_error(e, "tool creation")
|
|
214
299
|
raise click.ClickException(str(e))
|
|
215
300
|
|
|
216
301
|
|
|
217
302
|
@tools_group.command()
|
|
218
303
|
@click.argument("tool_ref")
|
|
219
304
|
@click.option("--select", type=int, help="Choose among ambiguous matches (1-based)")
|
|
305
|
+
@click.option(
|
|
306
|
+
"--export",
|
|
307
|
+
type=click.Path(dir_okay=False, writable=True),
|
|
308
|
+
help="Export complete tool configuration to file (format auto-detected from .json/.yaml extension)",
|
|
309
|
+
)
|
|
220
310
|
@output_flags()
|
|
221
311
|
@click.pass_context
|
|
222
|
-
def get(ctx, tool_ref, select):
|
|
223
|
-
"""Get tool details.
|
|
312
|
+
def get(ctx, tool_ref, select, export):
|
|
313
|
+
"""Get tool details.
|
|
314
|
+
|
|
315
|
+
Examples:
|
|
316
|
+
aip tools get my-tool
|
|
317
|
+
aip tools get my-tool --export tool.json # Exports complete configuration as JSON
|
|
318
|
+
aip tools get my-tool --export tool.yaml # Exports complete configuration as YAML
|
|
319
|
+
"""
|
|
224
320
|
try:
|
|
225
321
|
client = get_client(ctx)
|
|
226
322
|
|
|
227
323
|
# Resolve tool with ambiguity handling
|
|
228
324
|
tool = _resolve_tool(ctx, client, tool_ref, select)
|
|
229
325
|
|
|
230
|
-
#
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
326
|
+
# Handle export option
|
|
327
|
+
if export:
|
|
328
|
+
export_path = Path(export)
|
|
329
|
+
# Auto-detect format from file extension
|
|
330
|
+
if export_path.suffix.lower() in [".yaml", ".yml"]:
|
|
331
|
+
detected_format = "yaml"
|
|
332
|
+
else:
|
|
333
|
+
detected_format = "json"
|
|
334
|
+
|
|
335
|
+
# Always export comprehensive data - re-fetch tool with full details if needed
|
|
336
|
+
try:
|
|
337
|
+
tool = client.get_tool_by_id(tool.id)
|
|
338
|
+
except Exception as e:
|
|
339
|
+
console.print(
|
|
340
|
+
Text(f"[yellow]⚠️ Could not fetch full tool details: {e}[/yellow]")
|
|
341
|
+
)
|
|
342
|
+
console.print(
|
|
343
|
+
Text("[yellow]⚠️ Proceeding with available data[/yellow]")
|
|
344
|
+
)
|
|
345
|
+
|
|
346
|
+
export_resource_to_file(tool, export_path, detected_format)
|
|
347
|
+
console.print(
|
|
348
|
+
Text(
|
|
349
|
+
f"[green]✅ Complete tool configuration exported to: {export_path} (format: {detected_format})[/green]"
|
|
350
|
+
)
|
|
351
|
+
)
|
|
352
|
+
|
|
353
|
+
# Try to fetch raw API data first to preserve ALL fields
|
|
354
|
+
raw_tool_data = fetch_raw_resource_details(client, tool, "tools")
|
|
355
|
+
|
|
356
|
+
if raw_tool_data:
|
|
357
|
+
# Use raw API data - this preserves ALL fields
|
|
358
|
+
# Format dates for better display (minimal postprocessing)
|
|
359
|
+
formatted_data = raw_tool_data.copy()
|
|
360
|
+
if "created_at" in formatted_data:
|
|
361
|
+
formatted_data["created_at"] = format_datetime(
|
|
362
|
+
formatted_data["created_at"]
|
|
363
|
+
)
|
|
364
|
+
if "updated_at" in formatted_data:
|
|
365
|
+
formatted_data["updated_at"] = format_datetime(
|
|
366
|
+
formatted_data["updated_at"]
|
|
367
|
+
)
|
|
368
|
+
|
|
369
|
+
# Display using output_result with raw data
|
|
370
|
+
output_result(
|
|
371
|
+
ctx,
|
|
372
|
+
formatted_data,
|
|
373
|
+
title="Tool Details",
|
|
374
|
+
panel_title=f"🔧 {raw_tool_data.get('name', 'Unknown')}",
|
|
375
|
+
)
|
|
376
|
+
else:
|
|
377
|
+
# Fall back to original method if raw fetch fails
|
|
378
|
+
console.print("[yellow]Falling back to Pydantic model data[/yellow]")
|
|
379
|
+
|
|
380
|
+
# Create result data with all available fields from backend
|
|
381
|
+
result_data = {
|
|
382
|
+
"id": str(getattr(tool, "id", "N/A")),
|
|
383
|
+
"name": getattr(tool, "name", "N/A"),
|
|
384
|
+
"tool_type": getattr(tool, "tool_type", "N/A"),
|
|
385
|
+
"framework": getattr(tool, "framework", "N/A"),
|
|
386
|
+
"version": getattr(tool, "version", "N/A"),
|
|
387
|
+
"description": getattr(tool, "description", "N/A"),
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
output_result(
|
|
391
|
+
ctx, result_data, title="Tool Details", panel_title=f"🔧 {tool.name}"
|
|
392
|
+
)
|
|
243
393
|
|
|
244
394
|
except Exception as e:
|
|
245
395
|
raise click.ClickException(str(e))
|
|
@@ -248,7 +398,9 @@ def get(ctx, tool_ref, select):
|
|
|
248
398
|
@tools_group.command()
|
|
249
399
|
@click.argument("tool_id")
|
|
250
400
|
@click.option(
|
|
251
|
-
"--file",
|
|
401
|
+
"--file",
|
|
402
|
+
type=click.Path(exists=True),
|
|
403
|
+
help="New tool file for code update (custom tools only)",
|
|
252
404
|
)
|
|
253
405
|
@click.option("--description", help="New description")
|
|
254
406
|
@click.option("--tags", help="Comma-separated tags")
|
|
@@ -265,41 +417,44 @@ def update(ctx, tool_id, file, description, tags):
|
|
|
265
417
|
except Exception as e:
|
|
266
418
|
raise click.ClickException(f"Tool with ID '{tool_id}' not found: {e}")
|
|
267
419
|
|
|
420
|
+
# Prepare update data
|
|
268
421
|
update_data = {}
|
|
269
|
-
|
|
270
422
|
if description:
|
|
271
423
|
update_data["description"] = description
|
|
272
|
-
|
|
273
424
|
if tags:
|
|
274
425
|
update_data["tags"] = [tag.strip() for tag in tags.split(",")]
|
|
275
426
|
|
|
276
427
|
if file:
|
|
277
|
-
# Update code
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
428
|
+
# Update code via file upload (custom tools only)
|
|
429
|
+
if tool.tool_type != "custom":
|
|
430
|
+
raise click.ClickException(
|
|
431
|
+
f"File updates are only supported for custom tools. Tool '{tool.name}' is of type '{tool.tool_type}'."
|
|
432
|
+
)
|
|
433
|
+
updated_tool = client.tools.update_tool_via_file(
|
|
434
|
+
tool.id, file, framework=tool.framework
|
|
435
|
+
)
|
|
436
|
+
handle_rich_output(
|
|
437
|
+
ctx, Text(f"[green]✓[/green] Tool code updated from {file}")
|
|
438
|
+
)
|
|
281
439
|
elif update_data:
|
|
282
|
-
# Update metadata
|
|
440
|
+
# Update metadata only (native tools only)
|
|
441
|
+
if tool.tool_type != "native":
|
|
442
|
+
raise click.ClickException(
|
|
443
|
+
f"Metadata updates are only supported for native tools. Tool '{tool.name}' is of type '{tool.tool_type}'."
|
|
444
|
+
)
|
|
283
445
|
updated_tool = tool.update(**update_data)
|
|
284
|
-
|
|
285
|
-
console.print(Text("[green]✓[/green] Tool metadata updated"))
|
|
446
|
+
handle_rich_output(ctx, Text("[green]✓[/green] Tool metadata updated"))
|
|
286
447
|
else:
|
|
287
|
-
|
|
288
|
-
console.print(Text("[yellow]No updates specified[/yellow]"))
|
|
448
|
+
handle_rich_output(ctx, Text("[yellow]No updates specified[/yellow]"))
|
|
289
449
|
return
|
|
290
450
|
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
else:
|
|
294
|
-
console.print(
|
|
295
|
-
f"[green]✅ Tool '{updated_tool.name}' updated successfully[/green]"
|
|
296
|
-
)
|
|
451
|
+
handle_json_output(ctx, updated_tool.model_dump())
|
|
452
|
+
handle_rich_output(ctx, display_update_success("Tool", updated_tool.name))
|
|
297
453
|
|
|
298
454
|
except Exception as e:
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
console.print(Text(f"[red]Error updating tool: {e}[/red]"))
|
|
455
|
+
handle_json_output(ctx, error=e)
|
|
456
|
+
if ctx.obj.get("view") != "json":
|
|
457
|
+
display_api_error(e, "tool update")
|
|
303
458
|
raise click.ClickException(str(e))
|
|
304
459
|
|
|
305
460
|
|
|
@@ -319,37 +474,29 @@ def delete(ctx, tool_id, yes):
|
|
|
319
474
|
except Exception as e:
|
|
320
475
|
raise click.ClickException(f"Tool with ID '{tool_id}' not found: {e}")
|
|
321
476
|
|
|
322
|
-
# Confirm deletion
|
|
323
|
-
if not yes and not
|
|
324
|
-
f"Are you sure you want to delete tool '{tool.name}'?"
|
|
325
|
-
):
|
|
326
|
-
if ctx.obj.get("view") != "json":
|
|
327
|
-
console.print(Text("Deletion cancelled."))
|
|
477
|
+
# Confirm deletion via centralized display helper
|
|
478
|
+
if not yes and not display_confirmation_prompt("Tool", tool.name):
|
|
328
479
|
return
|
|
329
480
|
|
|
330
481
|
tool.delete()
|
|
331
482
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
console.print(
|
|
341
|
-
Text(f"[green]✅ Tool '{tool.name}' deleted successfully[/green]")
|
|
342
|
-
)
|
|
483
|
+
handle_json_output(
|
|
484
|
+
ctx,
|
|
485
|
+
{
|
|
486
|
+
"success": True,
|
|
487
|
+
"message": f"Tool '{tool.name}' deleted",
|
|
488
|
+
},
|
|
489
|
+
)
|
|
490
|
+
handle_rich_output(ctx, display_deletion_success("Tool", tool.name))
|
|
343
491
|
|
|
344
492
|
except Exception as e:
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
console.print(Text(f"[red]Error deleting tool: {e}[/red]"))
|
|
493
|
+
handle_json_output(ctx, error=e)
|
|
494
|
+
if ctx.obj.get("view") != "json":
|
|
495
|
+
display_api_error(e, "tool deletion")
|
|
349
496
|
raise click.ClickException(str(e))
|
|
350
497
|
|
|
351
498
|
|
|
352
|
-
@tools_group.command()
|
|
499
|
+
@tools_group.command("script")
|
|
353
500
|
@click.argument("tool_id")
|
|
354
501
|
@output_flags()
|
|
355
502
|
@click.pass_context
|
|
@@ -357,92 +504,16 @@ def script(ctx, tool_id):
|
|
|
357
504
|
"""Get tool script content."""
|
|
358
505
|
try:
|
|
359
506
|
client = get_client(ctx)
|
|
360
|
-
|
|
361
|
-
# Get tool by ID (no ambiguity handling needed)
|
|
362
|
-
try:
|
|
363
|
-
tool = client.get_tool_by_id(tool_id)
|
|
364
|
-
except Exception as e:
|
|
365
|
-
raise click.ClickException(f"Tool with ID '{tool_id}' not found: {e}")
|
|
366
|
-
|
|
367
|
-
# Get tool script content
|
|
368
|
-
script_content = client.tools.get_tool_script(tool_id)
|
|
369
|
-
|
|
370
|
-
if ctx.obj.get("view") == "json":
|
|
371
|
-
click.echo(
|
|
372
|
-
json.dumps(
|
|
373
|
-
{
|
|
374
|
-
"tool_id": tool_id,
|
|
375
|
-
"tool_name": tool.name,
|
|
376
|
-
"script": script_content,
|
|
377
|
-
},
|
|
378
|
-
indent=2,
|
|
379
|
-
)
|
|
380
|
-
)
|
|
381
|
-
elif ctx.obj.get("output"):
|
|
382
|
-
# Save to file
|
|
383
|
-
output_file = ctx.obj.get("output")
|
|
384
|
-
with open(output_file, "w", encoding="utf-8") as f:
|
|
385
|
-
f.write(script_content)
|
|
386
|
-
console.print(f"[green]✅ Tool script saved to {output_file}[/green]")
|
|
387
|
-
else:
|
|
388
|
-
# Display in terminal
|
|
389
|
-
console.print(
|
|
390
|
-
Panel(
|
|
391
|
-
script_content,
|
|
392
|
-
title=f"🔧 Tool Script: {tool.name}",
|
|
393
|
-
border_style="cyan",
|
|
394
|
-
)
|
|
395
|
-
)
|
|
396
|
-
|
|
397
|
-
except Exception as e:
|
|
398
|
-
if ctx.obj.get("view") == "json":
|
|
399
|
-
click.echo(json.dumps({"error": str(e)}, indent=2))
|
|
400
|
-
else:
|
|
401
|
-
console.print(f"[red]Error getting tool script: {e}[/red]")
|
|
402
|
-
raise click.ClickException(str(e))
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
@tools_group.command()
|
|
406
|
-
@click.argument("tool_id")
|
|
407
|
-
@click.option(
|
|
408
|
-
"--file",
|
|
409
|
-
type=click.Path(exists=True),
|
|
410
|
-
required=True,
|
|
411
|
-
help="New tool file for code update",
|
|
412
|
-
)
|
|
413
|
-
@click.option("--name", help="New tool name")
|
|
414
|
-
@click.option("--description", help="New description")
|
|
415
|
-
@click.option("--tags", help="Comma-separated tags")
|
|
416
|
-
@output_flags()
|
|
417
|
-
@click.pass_context
|
|
418
|
-
def upload_update(ctx, tool_id, file, name, description, tags):
|
|
419
|
-
"""Update a tool plugin via file upload."""
|
|
420
|
-
try:
|
|
421
|
-
client = get_client(ctx)
|
|
422
|
-
|
|
423
|
-
# Prepare update data
|
|
424
|
-
update_data = {}
|
|
425
|
-
if name:
|
|
426
|
-
update_data["name"] = name
|
|
427
|
-
if description:
|
|
428
|
-
update_data["description"] = description
|
|
429
|
-
if tags:
|
|
430
|
-
update_data["tags"] = [tag.strip() for tag in tags.split(",")]
|
|
431
|
-
|
|
432
|
-
# Update tool via file upload
|
|
433
|
-
updated_tool = client.tools.update_tool_via_file(tool_id, file, **update_data)
|
|
507
|
+
script_content = client.get_tool_script(tool_id)
|
|
434
508
|
|
|
435
509
|
if ctx.obj.get("view") == "json":
|
|
436
|
-
click.echo(json.dumps(
|
|
510
|
+
click.echo(json.dumps({"script": script_content}, indent=2))
|
|
437
511
|
else:
|
|
438
|
-
console.print(
|
|
439
|
-
|
|
440
|
-
)
|
|
441
|
-
console.print(f"[blue]📁 File: {file}[/blue]")
|
|
512
|
+
console.print(f"[green]📜 Tool Script for '{tool_id}':[/green]")
|
|
513
|
+
console.print(script_content)
|
|
442
514
|
|
|
443
515
|
except Exception as e:
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
console.print(Text(f"[red]Error updating tool: {e}[/red]"))
|
|
516
|
+
handle_json_output(ctx, error=e)
|
|
517
|
+
if ctx.obj.get("view") != "json":
|
|
518
|
+
console.print(Text(f"[red]Error getting tool script: {e}[/red]"))
|
|
448
519
|
raise click.ClickException(str(e))
|