glaip-sdk 0.0.16__py3-none-any.whl → 0.0.17__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 CHANGED
@@ -1,4 +1,4 @@
1
- """GL AIP SDK - Python SDK for GDP Labs AI Agent Package.
1
+ """GL AIP - Python SDK for GDP Labs AI Agent Package.
2
2
 
3
3
  Authors:
4
4
  Raymond Christopher (raymond.christopher@gdplabs.id)
glaip_sdk/branding.py CHANGED
@@ -42,7 +42,7 @@ LABEL = "bold"
42
42
 
43
43
 
44
44
  class AIPBranding:
45
- """GL AIP SDK branding utilities with ASCII banner and version display."""
45
+ """GL AIP branding utilities with ASCII banner and version display."""
46
46
 
47
47
  # GL AIP ASCII art - Modern block style with enhanced visibility
48
48
  AIP_LOGO = r"""
@@ -12,7 +12,6 @@ from typing import Any
12
12
 
13
13
  import click
14
14
  from rich.console import Console
15
- from rich.text import Text
16
15
 
17
16
  from glaip_sdk.cli.agent_config import (
18
17
  merge_agent_config_with_cli_args as merge_import_with_cli_args,
@@ -45,6 +44,7 @@ from glaip_sdk.cli.io import (
45
44
  load_resource_from_file_with_validation as load_resource_from_file,
46
45
  )
47
46
  from glaip_sdk.cli.resolution import resolve_resource_reference
47
+ from glaip_sdk.cli.rich_helpers import markup_text, print_markup
48
48
  from glaip_sdk.cli.utils import (
49
49
  _fuzzy_pick_for_resources,
50
50
  build_renderer,
@@ -275,7 +275,7 @@ def _format_fallback_agent_data(client: Any, agent: Any) -> dict:
275
275
  def _display_agent_details(ctx: Any, client: Any, agent: Any) -> None:
276
276
  """Display full agent details using raw API data to preserve ALL fields."""
277
277
  if agent is None:
278
- handle_rich_output(ctx, Text("[red]❌ No agent provided[/red]"))
278
+ handle_rich_output(ctx, markup_text("[red]❌ No agent provided[/red]"))
279
279
  return
280
280
 
281
281
  # Try to fetch and format raw agent data first
@@ -297,7 +297,8 @@ def _display_agent_details(ctx: Any, client: Any, agent: Any) -> None:
297
297
  else:
298
298
  # Fall back to Pydantic model data if raw fetch fails
299
299
  handle_rich_output(
300
- ctx, Text("[yellow]Falling back to Pydantic model data[/yellow]")
300
+ ctx,
301
+ markup_text("[yellow]Falling back to Pydantic model data[/yellow]"),
301
302
  )
302
303
 
303
304
  with spinner_context(
@@ -495,18 +496,19 @@ def get(ctx: Any, agent_ref: str, select: int | None, export: str | None) -> Non
495
496
  except Exception as e:
496
497
  handle_rich_output(
497
498
  ctx,
498
- Text(
499
+ markup_text(
499
500
  f"[yellow]⚠️ Could not fetch full agent details: {e}[/yellow]"
500
501
  ),
501
502
  )
502
503
  handle_rich_output(
503
- ctx, Text("[yellow]⚠️ Proceeding with available data[/yellow]")
504
+ ctx,
505
+ markup_text("[yellow]⚠️ Proceeding with available data[/yellow]"),
504
506
  )
505
507
 
506
508
  export_resource_to_file(agent, export_path, detected_format)
507
509
  handle_rich_output(
508
510
  ctx,
509
- Text(
511
+ markup_text(
510
512
  f"[green]✅ Complete agent configuration exported to: {export_path} (format: {detected_format})[/green]"
511
513
  ),
512
514
  )
@@ -619,7 +621,7 @@ def _save_run_transcript(save: str | None, result: Any, working_console: Any) ->
619
621
 
620
622
  with open(save, "w", encoding="utf-8") as f:
621
623
  f.write(content)
622
- console.print(Text(f"[green]Full debug output saved to: {save}[/green]"))
624
+ print_markup(f"[green]Full debug output saved to: {save}[/green]", console=console)
623
625
 
624
626
 
625
627
  @agents_group.command()
@@ -1306,8 +1308,6 @@ def sync_langflow(ctx: Any, base_url: str | None, api_key: str | None) -> None:
1306
1308
 
1307
1309
  # Show success message for non-JSON output
1308
1310
  if get_ctx_value(ctx, "view") != "json":
1309
- from rich.text import Text
1310
-
1311
1311
  # Extract some useful info from the result
1312
1312
  success_count = result.get("data", {}).get("created_count", 0) + result.get(
1313
1313
  "data", {}
@@ -1316,7 +1316,7 @@ def sync_langflow(ctx: Any, base_url: str | None, api_key: str | None) -> None:
1316
1316
 
1317
1317
  handle_rich_output(
1318
1318
  ctx,
1319
- Text(
1319
+ markup_text(
1320
1320
  f"[green]✅ Successfully synced {success_count} LangFlow agents ({total_count} total processed)[/green]"
1321
1321
  ),
1322
1322
  )
@@ -14,6 +14,7 @@ from glaip_sdk import Client
14
14
  from glaip_sdk._version import __version__ as _SDK_VERSION
15
15
  from glaip_sdk.branding import AIPBranding
16
16
  from glaip_sdk.cli.config import CONFIG_FILE, load_config, save_config
17
+ from glaip_sdk.cli.rich_helpers import markup_text
17
18
  from glaip_sdk.cli.utils import command_hint
18
19
  from glaip_sdk.rich_components import AIPTable
19
20
 
@@ -88,7 +89,9 @@ def get_config(key: str) -> None:
88
89
  config = load_config()
89
90
 
90
91
  if key not in config:
91
- console.print(Text(f"[yellow]Configuration key '{key}' not found.[/yellow]"))
92
+ console.print(
93
+ markup_text(f"[yellow]Configuration key '{key}' not found.[/yellow]")
94
+ )
92
95
  raise click.ClickException(f"Configuration key not found: {key}")
93
96
 
94
97
  value = config[key]
@@ -108,7 +111,9 @@ def unset_config(key: str) -> None:
108
111
  config = load_config()
109
112
 
110
113
  if key not in config:
111
- console.print(Text(f"[yellow]Configuration key '{key}' not found.[/yellow]"))
114
+ console.print(
115
+ markup_text(f"[yellow]Configuration key '{key}' not found.[/yellow]")
116
+ )
112
117
  return
113
118
 
114
119
  del config[key]
@@ -11,7 +11,6 @@ from typing import Any
11
11
 
12
12
  import click
13
13
  from rich.console import Console
14
- from rich.text import Text
15
14
 
16
15
  from glaip_sdk.cli.context import detect_export_format, get_ctx_value, output_flags
17
16
  from glaip_sdk.cli.display import (
@@ -33,6 +32,7 @@ from glaip_sdk.cli.mcp_validators import (
33
32
  )
34
33
  from glaip_sdk.cli.parsers.json_input import parse_json_input
35
34
  from glaip_sdk.cli.resolution import resolve_resource_reference
35
+ from glaip_sdk.cli.rich_helpers import print_markup
36
36
  from glaip_sdk.cli.utils import (
37
37
  coerce_to_row,
38
38
  get_client,
@@ -481,21 +481,23 @@ def _handle_mcp_export(
481
481
  ):
482
482
  mcp = client.mcps.get_mcp_by_id(mcp.id)
483
483
  except Exception as e:
484
- console.print(
485
- Text(f"[yellow]⚠️ Could not fetch full MCP details: {e}[/yellow]")
484
+ print_markup(
485
+ f"[yellow]⚠️ Could not fetch full MCP details: {e}[/yellow]",
486
+ console=console,
487
+ )
488
+ print_markup(
489
+ "[yellow]⚠️ Proceeding with available data[/yellow]", console=console
486
490
  )
487
- console.print(Text("[yellow]⚠️ Proceeding with available data[/yellow]"))
488
491
 
489
492
  # Determine if we should prompt for secrets
490
493
  prompt_for_secrets = not no_auth_prompt and sys.stdin.isatty()
491
494
 
492
495
  # Warn user if non-interactive mode forces placeholder usage
493
496
  if not no_auth_prompt and not sys.stdin.isatty():
494
- console.print(
495
- Text(
496
- "[yellow]⚠️ Non-interactive mode detected. "
497
- "Using placeholder values for secrets.[/yellow]"
498
- )
497
+ print_markup(
498
+ "[yellow]⚠️ Non-interactive mode detected. "
499
+ "Using placeholder values for secrets.[/yellow]",
500
+ console=console,
499
501
  )
500
502
 
501
503
  # Build and write export payload
@@ -528,11 +530,10 @@ def _handle_mcp_export(
528
530
  )
529
531
  write_resource_export(export_path, export_payload, detected_format)
530
532
 
531
- console.print(
532
- Text(
533
- f"[green]✅ Complete MCP configuration exported to: "
534
- f"{export_path} (format: {detected_format})[/green]"
535
- )
533
+ print_markup(
534
+ f"[green]✅ Complete MCP configuration exported to: "
535
+ f"{export_path} (format: {detected_format})[/green]",
536
+ console=console,
536
537
  )
537
538
 
538
539
 
@@ -732,11 +733,9 @@ def connect(ctx: Any, config_file: str) -> None:
732
733
 
733
734
  view = get_ctx_value(ctx, "view", "rich")
734
735
  if view != "json":
735
- console.print(
736
- Text(
737
- f"[yellow]Connecting to MCP with config from "
738
- f"{config_file}...[/yellow]"
739
- )
736
+ print_markup(
737
+ f"[yellow]Connecting to MCP with config from {config_file}...[/yellow]",
738
+ console=console,
740
739
  )
741
740
 
742
741
  # Test connection using config
@@ -11,7 +11,6 @@ from typing import Any
11
11
 
12
12
  import click
13
13
  from rich.console import Console
14
- from rich.text import Text
15
14
 
16
15
  from glaip_sdk.cli.context import detect_export_format, get_ctx_value, output_flags
17
16
  from glaip_sdk.cli.display import (
@@ -33,6 +32,7 @@ from glaip_sdk.cli.io import (
33
32
  load_resource_from_file_with_validation as load_resource_from_file,
34
33
  )
35
34
  from glaip_sdk.cli.resolution import resolve_resource_reference
35
+ from glaip_sdk.cli.rich_helpers import markup_text, print_markup
36
36
  from glaip_sdk.cli.utils import (
37
37
  coerce_to_row,
38
38
  get_client,
@@ -349,11 +349,13 @@ def get(ctx: Any, tool_ref: str, select: int | None, export: str | None) -> None
349
349
  ):
350
350
  tool = client.get_tool_by_id(tool.id)
351
351
  except Exception as e:
352
- console.print(
353
- Text(f"[yellow]⚠️ Could not fetch full tool details: {e}[/yellow]")
352
+ print_markup(
353
+ f"[yellow]⚠️ Could not fetch full tool details: {e}[/yellow]",
354
+ console=console,
354
355
  )
355
- console.print(
356
- Text("[yellow]⚠️ Proceeding with available data[/yellow]")
356
+ print_markup(
357
+ "[yellow]⚠️ Proceeding with available data[/yellow]",
358
+ console=console,
357
359
  )
358
360
 
359
361
  with spinner_context(
@@ -362,10 +364,9 @@ def get(ctx: Any, tool_ref: str, select: int | None, export: str | None) -> None
362
364
  console_override=console,
363
365
  ):
364
366
  export_resource_to_file(tool, export_path, detected_format)
365
- console.print(
366
- Text(
367
- f"[green]✅ Complete tool configuration exported to: {export_path} (format: {detected_format})[/green]"
368
- )
367
+ print_markup(
368
+ f"[green]✅ Complete tool configuration exported to: {export_path} (format: {detected_format})[/green]",
369
+ console=console,
369
370
  )
370
371
 
371
372
  # Try to fetch raw API data first to preserve ALL fields
@@ -473,7 +474,8 @@ def update(
473
474
  tool.id, file, framework=tool.framework
474
475
  )
475
476
  handle_rich_output(
476
- ctx, Text(f"[green]✓[/green] Tool code updated from {file}")
477
+ ctx,
478
+ markup_text(f"[green]✓[/green] Tool code updated from {file}"),
477
479
  )
478
480
  elif update_data:
479
481
  # Update metadata only (native tools only)
@@ -487,9 +489,13 @@ def update(
487
489
  console_override=console,
488
490
  ):
489
491
  updated_tool = tool.update(**update_data)
490
- handle_rich_output(ctx, Text("[green]✓[/green] Tool metadata updated"))
492
+ handle_rich_output(
493
+ ctx, markup_text("[green]✓[/green] Tool metadata updated")
494
+ )
491
495
  else:
492
- handle_rich_output(ctx, Text("[yellow]No updates specified[/yellow]"))
496
+ handle_rich_output(
497
+ ctx, markup_text("[yellow]No updates specified[/yellow]")
498
+ )
493
499
  return
494
500
 
495
501
  handle_json_output(ctx, updated_tool.model_dump())
@@ -574,5 +580,5 @@ def script(ctx: Any, tool_id: str) -> None:
574
580
  except Exception as e:
575
581
  handle_json_output(ctx, error=e)
576
582
  if get_ctx_value(ctx, "view") != "json":
577
- console.print(Text(f"[red]Error getting tool script: {e}[/red]"))
583
+ print_markup(f"[red]Error getting tool script: {e}[/red]", console=console)
578
584
  raise click.ClickException(str(e))
glaip_sdk/cli/display.py CHANGED
@@ -15,6 +15,7 @@ from rich.console import Console
15
15
  from rich.panel import Panel
16
16
  from rich.text import Text
17
17
 
18
+ from glaip_sdk.cli.rich_helpers import markup_text, print_markup
18
19
  from glaip_sdk.cli.utils import command_hint
19
20
  from glaip_sdk.rich_components import AIPPanel
20
21
 
@@ -61,7 +62,7 @@ def display_update_success(resource_type: str, resource_name: str) -> Text:
61
62
  Returns:
62
63
  Rich Text object for display
63
64
  """
64
- return Text(
65
+ return markup_text(
65
66
  f"[green]✅ {resource_type} '{resource_name}' updated successfully[/green]"
66
67
  )
67
68
 
@@ -76,7 +77,7 @@ def display_deletion_success(resource_type: str, resource_name: str) -> Text:
76
77
  Returns:
77
78
  Rich Text object for display
78
79
  """
79
- return Text(
80
+ return markup_text(
80
81
  f"[green]✅ {resource_type} '{resource_name}' deleted successfully[/green]"
81
82
  )
82
83
 
@@ -89,8 +90,8 @@ def display_api_error(error: Exception, operation: str = "operation") -> None:
89
90
  operation: Description of the operation that failed
90
91
  """
91
92
  error_type = type(error).__name__
92
- console.print(Text(f"[red]Error during {operation}: {error}[/red]"))
93
- console.print(Text(f"[dim]Error type: {error_type}[/dim]"))
93
+ print_markup(f"[red]Error during {operation}: {error}[/red]", console=console)
94
+ print_markup(f"[dim]Error type: {error_type}[/dim]", console=console)
94
95
 
95
96
 
96
97
  def print_api_error(e: Exception) -> None:
@@ -0,0 +1,29 @@
1
+ """Shared helpers for creating and printing Rich markup content.
2
+
3
+ Authors:
4
+ Raymond Christopher (raymond.christopher@gdplabs.id)
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from typing import Any
10
+
11
+ from rich.console import Console
12
+ from rich.markup import MarkupError
13
+ from rich.text import Text
14
+
15
+
16
+ def markup_text(message: str, **kwargs: Any) -> Text:
17
+ """Create a Rich Text instance from markup with graceful fallback."""
18
+ try:
19
+ return Text.from_markup(message, **kwargs)
20
+ except MarkupError:
21
+ return Text(message, **kwargs)
22
+
23
+
24
+ def print_markup(
25
+ message: str, *, console: Console | None = None, **kwargs: Any
26
+ ) -> None:
27
+ """Print markup-aware text to the provided console (default: new Console)."""
28
+ target_console = console or Console()
29
+ target_console.print(markup_text(message, **kwargs))
glaip_sdk/cli/utils.py CHANGED
@@ -19,8 +19,8 @@ import click
19
19
  from rich.console import Console, Group
20
20
  from rich.markdown import Markdown
21
21
  from rich.pretty import Pretty
22
- from rich.text import Text
23
22
 
23
+ from glaip_sdk.cli.rich_helpers import markup_text
24
24
  from glaip_sdk.rich_components import AIPPanel
25
25
 
26
26
  # Optional interactive deps (fuzzy palette)
@@ -557,7 +557,7 @@ def output_result(
557
557
  if panel_title:
558
558
  console.print(AIPPanel(renderable, title=panel_title))
559
559
  else:
560
- console.print(Text(f"[cyan]{title}:[/cyan]"))
560
+ console.print(markup_text(f"[cyan]{title}:[/cyan]"))
561
561
  console.print(renderable)
562
562
 
563
563
 
@@ -635,7 +635,7 @@ def _build_table_group(
635
635
  table = _create_table(columns, title)
636
636
  for row in rows:
637
637
  table.add_row(*[str(row.get(key, "N/A")) for key, _, _, _ in columns])
638
- footer = Text.from_markup(f"\n[dim]Total {len(rows)} items[/dim]")
638
+ footer = markup_text(f"\n[dim]Total {len(rows)} items[/dim]")
639
639
  return Group(table, footer)
640
640
 
641
641
 
@@ -665,7 +665,7 @@ def _handle_markdown_output(
665
665
 
666
666
  def _handle_empty_items(title: str) -> None:
667
667
  """Handle case when no items are found."""
668
- console.print(Text.from_markup(f"[yellow]No {title.lower()} found.[/yellow]"))
668
+ console.print(markup_text(f"[yellow]No {title.lower()} found.[/yellow]"))
669
669
 
670
670
 
671
671
  def _should_use_fuzzy_picker() -> bool:
@@ -707,7 +707,7 @@ def _print_selection_tip(title: str) -> None:
707
707
  tip_cmd = _resource_tip_command(title)
708
708
  if tip_cmd:
709
709
  console.print(
710
- Text.from_markup(f"\n[dim]Tip: use `{tip_cmd} <ID>` for details[/dim]")
710
+ markup_text(f"\n[dim]Tip: use `{tip_cmd} <ID>` for details[/dim]")
711
711
  )
712
712
 
713
713
 
@@ -1092,7 +1092,7 @@ def _handle_fallback_numeric_ambiguity(
1092
1092
  safe_ref = ref.replace("{", "{{").replace("}", "}}")
1093
1093
 
1094
1094
  console.print(
1095
- Text(
1095
+ markup_text(
1096
1096
  f"[yellow]Multiple {safe_resource_type}s found matching '{safe_ref}':[/yellow]"
1097
1097
  )
1098
1098
  )
@@ -7,7 +7,9 @@ Authors:
7
7
 
8
8
  import json
9
9
  import logging
10
- from collections.abc import AsyncGenerator, Mapping
10
+ from collections.abc import AsyncGenerator, Callable, Iterator, Mapping
11
+ from os import PathLike
12
+ from pathlib import Path
11
13
  from typing import Any, BinaryIO
12
14
 
13
15
  import httpx
@@ -19,10 +21,12 @@ from glaip_sdk.client._agent_payloads import (
19
21
  AgentUpdateRequest,
20
22
  )
21
23
  from glaip_sdk.client.base import BaseClient
24
+ from glaip_sdk.client.mcps import MCPClient
22
25
  from glaip_sdk.client.run_rendering import (
23
26
  AgentRunRenderingManager,
24
27
  compute_timeout_seconds,
25
28
  )
29
+ from glaip_sdk.client.tools import ToolClient
26
30
  from glaip_sdk.config.constants import (
27
31
  DEFAULT_AGENT_FRAMEWORK,
28
32
  DEFAULT_AGENT_RUN_TIMEOUT,
@@ -32,13 +36,21 @@ from glaip_sdk.config.constants import (
32
36
  )
33
37
  from glaip_sdk.exceptions import NotFoundError
34
38
  from glaip_sdk.models import Agent
39
+ from glaip_sdk.payload_schemas.agent import list_server_only_fields
40
+ from glaip_sdk.utils.agent_config import normalize_agent_config_for_import
35
41
  from glaip_sdk.utils.client_utils import (
36
42
  aiter_sse_events,
37
43
  create_model_instances,
38
44
  find_by_name,
39
45
  prepare_multipart_data,
40
46
  )
47
+ from glaip_sdk.utils.import_export import (
48
+ convert_export_to_import_format,
49
+ merge_import_with_cli_args,
50
+ )
41
51
  from glaip_sdk.utils.rendering.renderer import RichStreamRenderer
52
+ from glaip_sdk.utils.resource_refs import is_uuid
53
+ from glaip_sdk.utils.serialization import load_resource_from_file
42
54
  from glaip_sdk.utils.validation import validate_agent_instruction
43
55
 
44
56
  # API endpoints
@@ -50,6 +62,145 @@ SSE_CONTENT_TYPE = "text/event-stream"
50
62
  # Set up module-level logger
51
63
  logger = logging.getLogger("glaip_sdk.agents")
52
64
 
65
+ _SERVER_ONLY_IMPORT_FIELDS = set(list_server_only_fields()) | {"success", "message"}
66
+ _MERGED_SEQUENCE_FIELDS = ("tools", "agents", "mcps")
67
+
68
+
69
+ def _normalise_sequence(value: Any) -> list[Any] | None:
70
+ """Normalise optional sequence inputs to plain lists."""
71
+ if value is None:
72
+ return None
73
+ if isinstance(value, list):
74
+ return value
75
+ if isinstance(value, (tuple, set)):
76
+ return list(value)
77
+ return [value]
78
+
79
+
80
+ def _normalise_sequence_fields(mapping: dict[str, Any]) -> None:
81
+ """Normalise merged sequence fields in-place."""
82
+ for field in _MERGED_SEQUENCE_FIELDS:
83
+ if field in mapping:
84
+ normalised = _normalise_sequence(mapping[field])
85
+ if normalised is not None:
86
+ mapping[field] = normalised
87
+
88
+
89
+ def _merge_override_maps(
90
+ base_values: Mapping[str, Any],
91
+ extra_values: Mapping[str, Any],
92
+ ) -> dict[str, Any]:
93
+ """Merge override mappings while normalising sequence fields."""
94
+ merged: dict[str, Any] = {}
95
+ for source in (base_values, extra_values):
96
+ for key, value in source.items():
97
+ if value is None:
98
+ continue
99
+ merged[key] = (
100
+ _normalise_sequence(value) if key in _MERGED_SEQUENCE_FIELDS else value
101
+ )
102
+ return merged
103
+
104
+
105
+ def _split_known_and_extra(
106
+ payload: Mapping[str, Any],
107
+ known_fields: Mapping[str, Any],
108
+ ) -> tuple[dict[str, Any], dict[str, Any]]:
109
+ """Split payload mapping into known request fields and extras."""
110
+ known: dict[str, Any] = {}
111
+ extras: dict[str, Any] = {}
112
+ for key, value in payload.items():
113
+ if value is None:
114
+ continue
115
+ if key in known_fields:
116
+ known[key] = value
117
+ else:
118
+ extras[key] = value
119
+ return known, extras
120
+
121
+
122
+ def _load_agent_file_payload(
123
+ file_path: Path, *, model_override: str | None
124
+ ) -> dict[str, Any]:
125
+ """Load agent configuration from disk and normalise legacy fields."""
126
+ if not file_path.exists():
127
+ raise FileNotFoundError(f"Agent configuration file not found: {file_path}")
128
+ if not file_path.is_file():
129
+ raise ValueError(f"Agent configuration path must point to a file: {file_path}")
130
+
131
+ raw_data = load_resource_from_file(file_path)
132
+ if not isinstance(raw_data, Mapping):
133
+ raise ValueError("Agent configuration file must contain a mapping/object.")
134
+
135
+ payload = convert_export_to_import_format(dict(raw_data))
136
+ payload = normalize_agent_config_for_import(payload, model_override)
137
+
138
+ for field in _SERVER_ONLY_IMPORT_FIELDS:
139
+ payload.pop(field, None)
140
+
141
+ return payload
142
+
143
+
144
+ def _prepare_import_payload(
145
+ file_path: Path,
146
+ overrides: Mapping[str, Any],
147
+ *,
148
+ drop_model_fields: bool = False,
149
+ ) -> dict[str, Any]:
150
+ """Prepare merged payload from file contents and explicit overrides."""
151
+ overrides_dict = dict(overrides)
152
+
153
+ raw_definition = load_resource_from_file(file_path)
154
+ original_refs = {
155
+ "tools": list(raw_definition.get("tools") or []),
156
+ "agents": list(raw_definition.get("agents") or []),
157
+ "mcps": list(raw_definition.get("mcps") or []),
158
+ }
159
+
160
+ base_payload = _load_agent_file_payload(
161
+ file_path, model_override=overrides_dict.get("model")
162
+ )
163
+
164
+ cli_args = {
165
+ key: overrides_dict.get(key)
166
+ for key in (
167
+ "name",
168
+ "instruction",
169
+ "model",
170
+ "tools",
171
+ "agents",
172
+ "mcps",
173
+ "timeout",
174
+ )
175
+ if overrides_dict.get(key) is not None
176
+ }
177
+
178
+ for field in _MERGED_SEQUENCE_FIELDS:
179
+ if field in cli_args:
180
+ cli_args[field] = tuple(_normalise_sequence(cli_args[field]) or [])
181
+
182
+ merged = merge_import_with_cli_args(base_payload, cli_args)
183
+
184
+ additional = {
185
+ key: value
186
+ for key, value in overrides_dict.items()
187
+ if value is not None and key not in cli_args
188
+ }
189
+ merged.update(additional)
190
+
191
+ if drop_model_fields:
192
+ if overrides_dict.get("language_model_id") is None:
193
+ merged.pop("language_model_id", None)
194
+ if overrides_dict.get("provider") is None:
195
+ merged.pop("provider", None)
196
+
197
+ merged.setdefault("_tool_refs", original_refs["tools"])
198
+ merged.setdefault("_agent_refs", original_refs["agents"])
199
+ merged.setdefault("_mcp_refs", original_refs["mcps"])
200
+
201
+ _normalise_sequence_fields(merged)
202
+ return merged
203
+
53
204
 
54
205
  class AgentClient(BaseClient):
55
206
  """Client for agent operations."""
@@ -68,6 +219,8 @@ class AgentClient(BaseClient):
68
219
  """
69
220
  super().__init__(parent_client=parent_client, **kwargs)
70
221
  self._renderer_manager = AgentRunRenderingManager(logger)
222
+ self._tool_client: ToolClient | None = None
223
+ self._mcp_client: MCPClient | None = None
71
224
 
72
225
  def list_agents(
73
226
  self,
@@ -219,129 +372,407 @@ class AgentClient(BaseClient):
219
372
  finished_monotonic,
220
373
  )
221
374
 
222
- def create_agent(
375
+ def _get_tool_client(self) -> ToolClient:
376
+ if self._tool_client is None:
377
+ self._tool_client = ToolClient(parent_client=self)
378
+ return self._tool_client
379
+
380
+ def _get_mcp_client(self) -> MCPClient:
381
+ if self._mcp_client is None:
382
+ self._mcp_client = MCPClient(parent_client=self)
383
+ return self._mcp_client
384
+
385
+ def _normalise_reference_entry(
223
386
  self,
224
- name: str,
225
- instruction: str,
226
- model: str = DEFAULT_MODEL,
227
- tools: list[str | Any] | None = None,
228
- agents: list[str | Any] | None = None,
229
- timeout: int = DEFAULT_AGENT_RUN_TIMEOUT,
387
+ entry: Any,
388
+ fallback_iter: Iterator[Any] | None,
389
+ ) -> tuple[str | None, str | None]:
390
+ entry_id: str | None = None
391
+ entry_name: str | None = None
392
+
393
+ if isinstance(entry, str):
394
+ if is_uuid(entry):
395
+ entry_id = entry
396
+ else:
397
+ entry_name = entry
398
+ elif isinstance(entry, dict):
399
+ entry_id = entry.get("id")
400
+ entry_name = entry.get("name")
401
+ else:
402
+ entry_name = str(entry)
403
+
404
+ if entry_name or fallback_iter is None:
405
+ return entry_id, entry_name
406
+
407
+ try:
408
+ ref = next(fallback_iter)
409
+ except StopIteration:
410
+ ref = None
411
+ if isinstance(ref, dict):
412
+ entry_name = ref.get("name") or entry_name
413
+
414
+ return entry_id, entry_name
415
+
416
+ def _resolve_resource_ids(
417
+ self,
418
+ items: list[Any] | None,
419
+ references: list[Any] | None,
230
420
  *,
231
- mcps: list[str | Any] | None = None,
232
- tool_configs: Mapping[str, Any] | None = None,
233
- **kwargs: Any,
234
- ) -> "Agent":
235
- """Create a new agent."""
236
- if not name or not name.strip():
237
- raise ValueError("Agent name cannot be empty or whitespace")
421
+ fetch_by_id: Callable[[str], Any],
422
+ find_by_name: Callable[[str], list[Any]],
423
+ label: str,
424
+ plural_label: str | None = None,
425
+ ) -> list[str] | None:
426
+ if not items:
427
+ return None
428
+
429
+ if references is None:
430
+ return [self._coerce_reference_value(entry) for entry in items]
431
+
432
+ singular = label
433
+ plural = plural_label or f"{label}s"
434
+ fallback_iter = iter(references or [])
435
+
436
+ return [
437
+ self._resolve_single_resource(
438
+ entry,
439
+ fallback_iter,
440
+ fetch_by_id,
441
+ find_by_name,
442
+ singular,
443
+ plural,
444
+ )
445
+ for entry in items
446
+ ]
447
+
448
+ def _resolve_single_resource(
449
+ self,
450
+ entry: Any,
451
+ fallback_iter: Iterator[Any] | None,
452
+ fetch_by_id: Callable[[str], Any],
453
+ find_by_name: Callable[[str], list[Any]],
454
+ singular: str,
455
+ plural: str,
456
+ ) -> str:
457
+ entry_id, entry_name = self._normalise_reference_entry(entry, fallback_iter)
458
+
459
+ validated_id = self._validate_resource_id(fetch_by_id, entry_id)
460
+ if validated_id:
461
+ return validated_id
462
+ if entry_id and entry_name is None:
463
+ return entry_id
464
+
465
+ if entry_name:
466
+ resolved, success = self._resolve_resource_by_name(
467
+ find_by_name, entry_name, singular, plural
468
+ )
469
+ return resolved if success else entry_name
470
+
471
+ raise ValueError(f"{singular} references must include a valid ID or name.")
472
+
473
+ @staticmethod
474
+ def _coerce_reference_value(entry: Any) -> str:
475
+ if isinstance(entry, dict):
476
+ if entry.get("id"):
477
+ return str(entry["id"])
478
+ if entry.get("name"):
479
+ return str(entry["name"])
480
+ return str(entry)
481
+
482
+ @staticmethod
483
+ def _validate_resource_id(
484
+ fetch_by_id: Callable[[str], Any], candidate_id: str | None
485
+ ) -> str | None:
486
+ if not candidate_id:
487
+ return None
488
+ try:
489
+ fetch_by_id(candidate_id)
490
+ except Exception:
491
+ return None
492
+ return candidate_id
493
+
494
+ @staticmethod
495
+ def _resolve_resource_by_name(
496
+ find_by_name: Callable[[str], list[Any]],
497
+ entry_name: str,
498
+ singular: str,
499
+ plural: str,
500
+ ) -> tuple[str, bool]:
501
+ try:
502
+ matches = find_by_name(entry_name)
503
+ except Exception:
504
+ return entry_name, False
505
+
506
+ if not matches:
507
+ raise ValueError(
508
+ f"{singular} '{entry_name}' not found in current workspace."
509
+ )
510
+ if len(matches) > 1:
511
+ exact = [
512
+ m
513
+ for m in matches
514
+ if getattr(m, "name", "").lower() == entry_name.lower()
515
+ ]
516
+ if len(exact) == 1:
517
+ matches = exact
518
+ else:
519
+ raise ValueError(
520
+ f"Multiple {plural} named '{entry_name}'. Please disambiguate."
521
+ )
522
+ return str(matches[0].id), True
238
523
 
239
- instruction = validate_agent_instruction(instruction)
240
-
241
- agent_type = kwargs.pop("agent_type", kwargs.pop("type", DEFAULT_AGENT_TYPE))
242
- framework = kwargs.pop("framework", DEFAULT_AGENT_FRAMEWORK)
243
- version = kwargs.pop("version", DEFAULT_AGENT_VERSION)
244
- language_model_id = kwargs.pop("language_model_id", None)
245
- provider_override = kwargs.pop("provider", None)
246
- model_name_override = kwargs.pop("model_name", None)
247
- account_id = kwargs.pop("account_id", None)
248
- description = kwargs.pop("description", None)
249
- metadata = kwargs.pop("metadata", None)
250
- agent_config = kwargs.pop("agent_config", None)
251
- a2a_profile = kwargs.pop("a2a_profile", None)
252
- mcps = mcps if mcps is not None else kwargs.pop("mcps", None)
253
- tool_configs = (
254
- tool_configs
255
- if tool_configs is not None
256
- else kwargs.pop("tool_configs", None)
524
+ def _resolve_tool_ids(
525
+ self,
526
+ tools: list[Any] | None,
527
+ references: list[Any] | None = None,
528
+ ) -> list[str] | None:
529
+ tool_client = self._get_tool_client()
530
+ return self._resolve_resource_ids(
531
+ tools,
532
+ references,
533
+ fetch_by_id=tool_client.get_tool_by_id,
534
+ find_by_name=tool_client.find_tools,
535
+ label="Tool",
536
+ plural_label="tools",
537
+ )
538
+
539
+ def _resolve_agent_ids(
540
+ self,
541
+ agents: list[Any] | None,
542
+ references: list[Any] | None = None,
543
+ ) -> list[str] | None:
544
+ return self._resolve_resource_ids(
545
+ agents,
546
+ references,
547
+ fetch_by_id=self.get_agent_by_id,
548
+ find_by_name=self.find_agents,
549
+ label="Agent",
550
+ plural_label="agents",
257
551
  )
258
552
 
553
+ def _resolve_mcp_ids(
554
+ self,
555
+ mcps: list[Any] | None,
556
+ references: list[Any] | None = None,
557
+ ) -> list[str] | None:
558
+ mcp_client = self._get_mcp_client()
559
+ return self._resolve_resource_ids(
560
+ mcps,
561
+ references,
562
+ fetch_by_id=mcp_client.get_mcp_by_id,
563
+ find_by_name=mcp_client.find_mcps,
564
+ label="MCP",
565
+ plural_label="MCPs",
566
+ )
567
+
568
+ def _create_agent_from_payload(self, payload: Mapping[str, Any]) -> "Agent":
569
+ """Create an agent using a fully prepared payload mapping."""
570
+ known, extras = _split_known_and_extra(
571
+ payload, AgentCreateRequest.__dataclass_fields__
572
+ )
573
+
574
+ name = known.pop("name", None)
575
+ instruction = known.pop("instruction", None)
576
+ if not name or not str(name).strip():
577
+ raise ValueError("Agent name cannot be empty or whitespace")
578
+ if not instruction or not str(instruction).strip():
579
+ raise ValueError("Agent instruction cannot be empty or whitespace")
580
+
581
+ validated_instruction = validate_agent_instruction(str(instruction))
582
+ _normalise_sequence_fields(known)
583
+
584
+ resolved_model = known.pop("model", None) or DEFAULT_MODEL
585
+ tool_refs = extras.pop("_tool_refs", None)
586
+ agent_refs = extras.pop("_agent_refs", None)
587
+ mcp_refs = extras.pop("_mcp_refs", None)
588
+
589
+ tools_raw = known.pop("tools", None)
590
+ agents_raw = known.pop("agents", None)
591
+ mcps_raw = known.pop("mcps", None)
592
+
593
+ resolved_tools = self._resolve_tool_ids(tools_raw, tool_refs)
594
+ resolved_agents = self._resolve_agent_ids(agents_raw, agent_refs)
595
+ resolved_mcps = self._resolve_mcp_ids(mcps_raw, mcp_refs)
596
+
597
+ final_extras = {**known, **extras}
598
+ final_extras.setdefault("model", resolved_model)
599
+
259
600
  request = AgentCreateRequest(
260
- name=name,
261
- instruction=instruction,
262
- model=model,
263
- language_model_id=language_model_id,
264
- provider=provider_override,
265
- model_name=model_name_override,
266
- agent_type=agent_type,
267
- framework=framework,
268
- version=version,
269
- account_id=account_id,
270
- description=description,
271
- metadata=metadata,
272
- tools=tools,
273
- agents=agents,
274
- mcps=mcps,
275
- tool_configs=tool_configs,
276
- agent_config=agent_config,
277
- timeout=timeout,
278
- a2a_profile=a2a_profile,
279
- extras=kwargs,
601
+ name=str(name).strip(),
602
+ instruction=validated_instruction,
603
+ model=resolved_model,
604
+ language_model_id=known.pop("language_model_id", None),
605
+ provider=known.pop("provider", None),
606
+ model_name=known.pop("model_name", None),
607
+ agent_type=known.pop("agent_type", known.pop("type", DEFAULT_AGENT_TYPE)),
608
+ framework=known.pop("framework", None) or DEFAULT_AGENT_FRAMEWORK,
609
+ version=known.pop("version", None) or DEFAULT_AGENT_VERSION,
610
+ account_id=known.pop("account_id", None),
611
+ description=known.pop("description", None),
612
+ metadata=known.pop("metadata", None),
613
+ tools=resolved_tools,
614
+ agents=resolved_agents,
615
+ mcps=resolved_mcps,
616
+ tool_configs=known.pop("tool_configs", None),
617
+ agent_config=known.pop("agent_config", None),
618
+ timeout=known.pop("timeout", None) or DEFAULT_AGENT_RUN_TIMEOUT,
619
+ a2a_profile=known.pop("a2a_profile", None),
620
+ extras=final_extras,
280
621
  )
281
622
 
282
- payload = request.to_payload()
623
+ payload_dict = request.to_payload()
624
+ payload_dict.setdefault("model", resolved_model)
283
625
 
284
626
  full_agent_data = self._post_then_fetch(
285
627
  id_key="id",
286
628
  post_endpoint=AGENTS_ENDPOINT,
287
629
  get_endpoint_fmt=f"{AGENTS_ENDPOINT}{{id}}",
288
- json=payload,
630
+ json=payload_dict,
289
631
  )
290
632
  return Agent(**full_agent_data)._set_client(self)
291
633
 
292
- def update_agent(
634
+ def create_agent(
293
635
  self,
294
- agent_id: str,
295
636
  name: str | None = None,
296
637
  instruction: str | None = None,
297
638
  model: str | None = None,
639
+ tools: list[str | Any] | None = None,
640
+ agents: list[str | Any] | None = None,
641
+ timeout: int | None = None,
642
+ *,
643
+ file: str | PathLike[str] | None = None,
644
+ mcps: list[str | Any] | None = None,
645
+ tool_configs: Mapping[str, Any] | None = None,
298
646
  **kwargs: Any,
299
647
  ) -> "Agent":
300
- """Update an existing agent."""
301
- current_agent = self.get_agent_by_id(agent_id)
648
+ """Create a new agent, optionally loading configuration from a file."""
649
+ base_overrides = {
650
+ "name": name,
651
+ "instruction": instruction,
652
+ "model": model,
653
+ "tools": tools,
654
+ "agents": agents,
655
+ "timeout": timeout,
656
+ "mcps": mcps,
657
+ "tool_configs": tool_configs,
658
+ }
659
+ overrides = _merge_override_maps(base_overrides, kwargs)
660
+
661
+ if file is not None:
662
+ payload = _prepare_import_payload(
663
+ Path(file).expanduser(), overrides, drop_model_fields=True
664
+ )
665
+ if overrides.get("model") is None:
666
+ payload.pop("model", None)
667
+ else:
668
+ payload = overrides
669
+
670
+ return self._create_agent_from_payload(payload)
302
671
 
303
- language_model_id = kwargs.pop("language_model_id", None)
304
- provider_override = kwargs.pop("provider", None)
305
- model_name_override = kwargs.pop("model_name", None)
306
- agent_type_override = kwargs.pop("agent_type", kwargs.pop("type", None))
307
- framework_override = kwargs.pop("framework", None)
308
- version_override = kwargs.pop("version", None)
309
- account_id = kwargs.pop("account_id", None)
310
- description = kwargs.pop("description", None)
311
- metadata = kwargs.pop("metadata", None)
312
- tools = kwargs.pop("tools", None)
313
- tool_configs = kwargs.pop("tool_configs", None)
314
- agents_value = kwargs.pop("agents", None)
315
- mcps = kwargs.pop("mcps", None)
316
- agent_config = kwargs.pop("agent_config", None)
317
- a2a_profile = kwargs.pop("a2a_profile", None)
672
+ def create_agent_from_file( # pragma: no cover - thin compatibility wrapper
673
+ self,
674
+ file_path: str | PathLike[str],
675
+ **overrides: Any,
676
+ ) -> "Agent":
677
+ """Backward-compatible helper to create an agent from a configuration file."""
678
+ return self.create_agent(file=file_path, **overrides)
679
+
680
+ def _update_agent_from_payload(
681
+ self,
682
+ agent_id: str,
683
+ current_agent: Agent,
684
+ payload: Mapping[str, Any],
685
+ ) -> "Agent":
686
+ """Update an agent using a prepared payload mapping."""
687
+ known, extras = _split_known_and_extra(
688
+ payload, AgentUpdateRequest.__dataclass_fields__
689
+ )
690
+ _normalise_sequence_fields(known)
691
+
692
+ tool_refs = extras.pop("_tool_refs", None)
693
+ agent_refs = extras.pop("_agent_refs", None)
694
+ mcp_refs = extras.pop("_mcp_refs", None)
695
+
696
+ tools_value = known.pop("tools", None)
697
+ agents_value = known.pop("agents", None)
698
+ mcps_value = known.pop("mcps", None)
699
+
700
+ if tools_value is not None:
701
+ tools_value = self._resolve_tool_ids(tools_value, tool_refs)
702
+ if agents_value is not None:
703
+ agents_value = self._resolve_agent_ids(agents_value, agent_refs)
704
+ if mcps_value is not None:
705
+ mcps_value = self._resolve_mcp_ids(mcps_value, mcp_refs) # pragma: no cover
318
706
 
319
707
  request = AgentUpdateRequest(
320
- name=name,
321
- instruction=instruction,
322
- description=description,
323
- model=model,
324
- language_model_id=language_model_id,
325
- provider=provider_override,
326
- model_name=model_name_override,
327
- agent_type=agent_type_override,
328
- framework=framework_override,
329
- version=version_override,
330
- account_id=account_id,
331
- metadata=metadata,
332
- tools=tools,
333
- tool_configs=tool_configs,
708
+ name=known.pop("name", None),
709
+ instruction=known.pop("instruction", None),
710
+ description=known.pop("description", None),
711
+ model=known.pop("model", None),
712
+ language_model_id=known.pop("language_model_id", None),
713
+ provider=known.pop("provider", None),
714
+ model_name=known.pop("model_name", None),
715
+ agent_type=known.pop("agent_type", known.pop("type", None)),
716
+ framework=known.pop("framework", None),
717
+ version=known.pop("version", None),
718
+ account_id=known.pop("account_id", None),
719
+ metadata=known.pop("metadata", None),
720
+ tools=tools_value,
721
+ tool_configs=known.pop("tool_configs", None),
334
722
  agents=agents_value,
335
- mcps=mcps,
336
- agent_config=agent_config,
337
- a2a_profile=a2a_profile,
338
- extras=kwargs,
723
+ mcps=mcps_value,
724
+ agent_config=known.pop("agent_config", None),
725
+ a2a_profile=known.pop("a2a_profile", None),
726
+ extras={**known, **extras},
339
727
  )
340
728
 
341
- payload = request.to_payload(current_agent)
729
+ payload_dict = request.to_payload(current_agent)
342
730
 
343
- data = self._request("PUT", f"/agents/{agent_id}", json=payload)
344
- return Agent(**data)._set_client(self)
731
+ response = self._request("PUT", f"/agents/{agent_id}", json=payload_dict)
732
+ return Agent(**response)._set_client(self)
733
+
734
+ def update_agent(
735
+ self,
736
+ agent_id: str,
737
+ name: str | None = None,
738
+ instruction: str | None = None,
739
+ model: str | None = None,
740
+ *,
741
+ file: str | PathLike[str] | None = None,
742
+ tools: list[str | Any] | None = None,
743
+ agents: list[str | Any] | None = None,
744
+ mcps: list[str | Any] | None = None,
745
+ **kwargs: Any,
746
+ ) -> "Agent":
747
+ """Update an existing agent."""
748
+ base_overrides = {
749
+ "name": name,
750
+ "instruction": instruction,
751
+ "model": model,
752
+ "tools": tools,
753
+ "agents": agents,
754
+ "mcps": mcps,
755
+ }
756
+ overrides = _merge_override_maps(base_overrides, kwargs)
757
+
758
+ if file is not None:
759
+ payload = _prepare_import_payload(
760
+ Path(file).expanduser(), overrides, drop_model_fields=True
761
+ )
762
+ else:
763
+ payload = overrides
764
+
765
+ current_agent = self.get_agent_by_id(agent_id)
766
+ return self._update_agent_from_payload(agent_id, current_agent, payload)
767
+
768
+ def update_agent_from_file( # pragma: no cover - thin compatibility wrapper
769
+ self,
770
+ agent_id: str,
771
+ file_path: str | PathLike[str],
772
+ **overrides: Any,
773
+ ) -> "Agent":
774
+ """Backward-compatible helper to update an agent from a configuration file."""
775
+ return self.update_agent(agent_id, file=file_path, **overrides)
345
776
 
346
777
  def delete_agent(self, agent_id: str) -> None:
347
778
  """Delete an agent."""
glaip_sdk/client/main.py CHANGED
@@ -42,6 +42,10 @@ class Client(BaseClient):
42
42
  """Create a new agent."""
43
43
  return self.agents.create_agent(**kwargs)
44
44
 
45
+ def create_agent_from_file(self, *args, **kwargs) -> Agent:
46
+ """Create a new agent from a JSON or YAML configuration file."""
47
+ return self.agents.create_agent_from_file(*args, **kwargs)
48
+
45
49
  def list_agents(
46
50
  self,
47
51
  agent_type: str | None = None,
@@ -86,6 +90,10 @@ class Client(BaseClient):
86
90
  """Update an existing agent."""
87
91
  return self.agents.update_agent(agent_id, **kwargs)
88
92
 
93
+ def update_agent_from_file(self, agent_id: str, *args, **kwargs) -> Agent:
94
+ """Update an existing agent using a JSON or YAML configuration file."""
95
+ return self.agents.update_agent_from_file(agent_id, *args, **kwargs)
96
+
89
97
  def delete_agent(self, agent_id: str) -> bool:
90
98
  """Delete an agent."""
91
99
  return self.agents.delete_agent(agent_id)
@@ -5,7 +5,7 @@ Authors:
5
5
  """
6
6
 
7
7
  # Default language model configuration
8
- DEFAULT_MODEL = "gpt-4.1"
8
+ DEFAULT_MODEL = "gpt-5-nano"
9
9
  DEFAULT_AGENT_RUN_TIMEOUT = 300
10
10
 
11
11
  # User agent and version
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: glaip-sdk
3
- Version: 0.0.16
3
+ Version: 0.0.17
4
4
  Summary: Python SDK for GL AIP (GDP Labs AI Agent Package) - Simplified CLI Design
5
5
  License: MIT
6
6
  Author: Raymond Christopher
@@ -22,7 +22,7 @@ Requires-Dist: readchar (>=4.2.1,<5.0.0)
22
22
  Requires-Dist: rich (>=13.0.0)
23
23
  Description-Content-Type: text/markdown
24
24
 
25
- # GL AIP SDK — GDP Labs AI Agents Package
25
+ # GL AIP — GDP Labs AI Agents Package
26
26
 
27
27
  [![Python 3.10+](https://img.shields.io/badge/python-3.10+-blue.svg)](https://www.python.org/downloads/)
28
28
  [![Code style: black](https://img.shields.io/badge/code%20style-black-000000.svg)](https://github.com/psf/black)
@@ -1,18 +1,18 @@
1
- glaip_sdk/__init__.py,sha256=FD-oTyFUKsTB9xTuGiqvkhuFXfeZ-TspjkeXERglha8,370
1
+ glaip_sdk/__init__.py,sha256=-Itm_1dz4QwhIUmqagvCwwvSjKYKYJI3lZSHD2bwtko,366
2
2
  glaip_sdk/_version.py,sha256=tGkFWAVu2ry4Hy7j-u7ophGbPRX8y-ngBbXDhN1VBIQ,2007
3
- glaip_sdk/branding.py,sha256=qHHRG4GCyU_fgCJOx4_20CxcRLItkA2Q-aRCOBGagDs,6414
3
+ glaip_sdk/branding.py,sha256=RwXVIc_gMDayKsNN4HBqo8c1fodTMvGFNhPnEZxpRIQ,6410
4
4
  glaip_sdk/cli/__init__.py,sha256=xCCfuF1Yc7mpCDcfhHZTX0vizvtrDSLeT8MJ3V7m5A0,156
5
5
  glaip_sdk/cli/agent_config.py,sha256=VHjebw68wAdhGUzYdPH8qz10oADZPRgUQcPW6F7iHIU,2421
6
6
  glaip_sdk/cli/auth.py,sha256=eYdtGmJ3XgiO96hq_69GF6b3W-aRWZrDQ-6bHuaRX4M,13517
7
7
  glaip_sdk/cli/commands/__init__.py,sha256=x0CZlZbZHoHvuzfoTWIyEch6WmNnbPzxajrox6riYp0,173
8
- glaip_sdk/cli/commands/agents.py,sha256=2NeEDnZ1WctVKSfi2VDmYT1Mqo_Lsa7GWCPUORxw2NQ,41167
9
- glaip_sdk/cli/commands/configure.py,sha256=7bEE6Eo4CCJq5qYbJ-vh6-eXc32d9Mqk4R1rTHZqWZw,7760
10
- glaip_sdk/cli/commands/mcps.py,sha256=fkl_8SFjz9ZH7rBrY59Mc4DDIDaG1-Xy-OL_xKACa9M,28158
8
+ glaip_sdk/cli/commands/agents.py,sha256=FtWGhbl4QRlqxXFNMEnZUpw5mjQ0KPjY0_6o0hYyoaU,41251
9
+ glaip_sdk/cli/commands/configure.py,sha256=h2GgBpnBWYHAhp3zqkAiy8QNgwPD_7pToZBZRpuMoNM,7869
10
+ glaip_sdk/cli/commands/mcps.py,sha256=V41Te3IG8jNFRMb1v1XQV1t461uxpPsrmDFIO6cZPOk,28185
11
11
  glaip_sdk/cli/commands/models.py,sha256=G1ce-wZOfvMP6SMnIVuSQ89CF444Kz8Ja6nrNOQXCqU,1729
12
- glaip_sdk/cli/commands/tools.py,sha256=P3zuKVapoC3yV4rnHGdFPO_snjLGWo5IpfuYHIUfMeU,18711
12
+ glaip_sdk/cli/commands/tools.py,sha256=YfkB7HRBGcAOC6N-wXTV5Ch5XTXqjKTtyq-Cfb0-18c,18908
13
13
  glaip_sdk/cli/config.py,sha256=jCLJxTBAnOU6EJI6JjcpwUTEAWCJRoALbMrhOvvAofc,946
14
14
  glaip_sdk/cli/context.py,sha256=M4weRf8dmp5bMtPLRF3w1StnRB7Lo8FPFq2GQMv3Rv8,3617
15
- glaip_sdk/cli/display.py,sha256=r6gAHg0i__yEq18FjCgb8fzdcURs_ZCiwgM6HV0pjA4,10659
15
+ glaip_sdk/cli/display.py,sha256=fNb2aBEV4V76TaRQ-L6EO-1fwq71VlzekDzZRTYKEPA,10758
16
16
  glaip_sdk/cli/io.py,sha256=GPkw3pQMLBGoD5GH-KlbKpNRlVWFZOXHE17F7V3kQsI,3343
17
17
  glaip_sdk/cli/main.py,sha256=gIF4b2mtLrWktsVdYcoHO91S07twtfn1w4D4RCqAMfc,13499
18
18
  glaip_sdk/cli/masking.py,sha256=BOZjwUqxQf3LQlYgUMwq7UYgve8x4_1Qk04ixiJJPZ8,4399
@@ -21,23 +21,24 @@ glaip_sdk/cli/pager.py,sha256=n9ypOGPPSaseJlwPG1X38qSz1yV3pjRWunzA4xx5E7M,8052
21
21
  glaip_sdk/cli/parsers/__init__.py,sha256=Ycd4HDfYmA7GUGFt0ndBPBo5uTbv15XsXnYUj-a89ug,183
22
22
  glaip_sdk/cli/parsers/json_input.py,sha256=6NqzVM5l8g0pwCNLKeTVL9SeLM9W_Fl4H__X0dfaQEA,4039
23
23
  glaip_sdk/cli/resolution.py,sha256=jXUNpKKhs30n7Ke0uz1Hbny5DTo2_sxvchIhTbeBubE,2393
24
+ glaip_sdk/cli/rich_helpers.py,sha256=ByUOmK16IisoXWE7nEiI55BF1KWDrm6KCYAxqHu0XOU,825
24
25
  glaip_sdk/cli/slash/__init__.py,sha256=Vdv6Y8bu-pA8dxDlyP4XrhudBPivztUozhLAz9vaLig,682
25
26
  glaip_sdk/cli/slash/agent_session.py,sha256=-woZkqH70YUSaEHDF9XpxP-cbh36Jx7yuJW7aA3JszI,7078
26
27
  glaip_sdk/cli/slash/prompt.py,sha256=2CLAfdmX6yQedcNLnwZ4g6QFoV9TVv8il9OF8iaJwdc,7977
27
28
  glaip_sdk/cli/slash/session.py,sha256=JsTHZB8gPFFdcp_bhtw-nig37Z61OWK_okPMx47H86c,31484
28
29
  glaip_sdk/cli/update_notifier.py,sha256=nfQ-jRQKn-nZyt7EhxNfZq9Z7nBrYjZJKAgAtuHffnw,3410
29
- glaip_sdk/cli/utils.py,sha256=fVWiAIfUwcn_ilteIFlCuRyWTfYZ6WwEFk_Gty58uPU,35480
30
+ glaip_sdk/cli/utils.py,sha256=pgbV0f5rdjAHeZ-ULCntH7HUG6FdFB9kODv0a9puB40,35503
30
31
  glaip_sdk/cli/validators.py,sha256=USbBgY86AwuDHO-Q_g8g7hu-ot4NgITBsWjTWIl62ms,5569
31
32
  glaip_sdk/client/__init__.py,sha256=nYLXfBVTTWwKjP0e63iumPYO4k5FifwWaELQPaPIKIg,188
32
33
  glaip_sdk/client/_agent_payloads.py,sha256=sYlMzrfAdd8KC37qxokLy2uDd3aOhzQirnv7UYlvwYc,16385
33
- glaip_sdk/client/agents.py,sha256=KJPl2WTJSYFhPYypvzRpT5X1jCwmvaYbTZrf16ECpaw,21103
34
+ glaip_sdk/client/agents.py,sha256=GpDlxzhUQaMn9IUq_kCsbZo5TBfwWXFYs1bbpPLiSok,35492
34
35
  glaip_sdk/client/base.py,sha256=OPRlAWhZ77rUK0MRGA83-zW5NVhxJ1RgdfcfGOYr8rI,16267
35
- glaip_sdk/client/main.py,sha256=YhStfWSDcA91eN6zNX2MLYRYbtdCJEmp0dZExieA2OA,8190
36
+ glaip_sdk/client/main.py,sha256=tfyyx9utReq7nXdtHKOCXQIUXXeZ1-D6u4OGTu6h8Es,8632
36
37
  glaip_sdk/client/mcps.py,sha256=-O-I15qjbwfSA69mouHY6g5_qgPWC4rM98VJLpOkh1A,8975
37
38
  glaip_sdk/client/run_rendering.py,sha256=fXUj1FBw8n-nAzjI_zaG7-Ap_UXXe0z4tMdL7m2R7Ek,9213
38
39
  glaip_sdk/client/tools.py,sha256=n8DIiOOf1YU_j9JK3Bx2-rDnkpckPi0MI9Ok2s1kwa4,16634
39
40
  glaip_sdk/client/validators.py,sha256=NtPsWjQLjj25LiUnmR-WuS8lL5p4MVRaYT9UVRmj9bo,8809
40
- glaip_sdk/config/constants.py,sha256=dI7hH46700gCl6jWNgpjYr00ZOWl2m1xg8UesjaXcCA,885
41
+ glaip_sdk/config/constants.py,sha256=B9CSlYG8LYjQuo_vNpqy-eSks3ej37FMcvJMy6d_F4U,888
41
42
  glaip_sdk/exceptions.py,sha256=ILquxC4QGPFR9eY6RpeXzkQsblfsvZMGFqz38ZjeW3E,2345
42
43
  glaip_sdk/models.py,sha256=ofhnNOaKK0UK1mDiot73z8qS0-X2IKJXmm7YyOifGzg,8876
43
44
  glaip_sdk/payload_schemas/__init__.py,sha256=fJamlkpS3IfS9xyKAQaUbnalvrtG5Ied69OUVAA3xvs,395
@@ -66,7 +67,7 @@ glaip_sdk/utils/rich_utils.py,sha256=-Ij-1bIJvnVAi6DrfftchIlMcvOTjVmSE0Qqax0EY_s
66
67
  glaip_sdk/utils/run_renderer.py,sha256=d_VMI6LbvHPUUeRmGqh5wK_lHqDEIAcym2iqpbtDad0,1365
67
68
  glaip_sdk/utils/serialization.py,sha256=AFbucakFaCtQDfcgsm2gHZ1iZDA8OaJSZUsS6FhWFR0,12820
68
69
  glaip_sdk/utils/validation.py,sha256=QNORcdyvuliEs4EH2_mkDgmoyT9utgl7YNhaf45SEf8,6992
69
- glaip_sdk-0.0.16.dist-info/METADATA,sha256=9RMf0ol4z-uU8SOE1IXMbrH1_i-5sjv8oV5ZDk9dW5U,5168
70
- glaip_sdk-0.0.16.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
71
- glaip_sdk-0.0.16.dist-info/entry_points.txt,sha256=EGs8NO8J1fdFMWA3CsF7sKBEvtHb_fujdCoNPhfMouE,47
72
- glaip_sdk-0.0.16.dist-info/RECORD,,
70
+ glaip_sdk-0.0.17.dist-info/METADATA,sha256=z1GiwKAgE5eXkCbBfUXrQuMZBUQ14XWuOZhgj5ugyAw,5164
71
+ glaip_sdk-0.0.17.dist-info/WHEEL,sha256=sP946D7jFCHeNz5Iq4fL4Lu-PrWrFsgfLXbbkciIZwg,88
72
+ glaip_sdk-0.0.17.dist-info/entry_points.txt,sha256=EGs8NO8J1fdFMWA3CsF7sKBEvtHb_fujdCoNPhfMouE,47
73
+ glaip_sdk-0.0.17.dist-info/RECORD,,