glaip-sdk 0.1.0__py3-none-any.whl → 0.1.1__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.
Files changed (63) hide show
  1. glaip_sdk/_version.py +1 -3
  2. glaip_sdk/branding.py +2 -6
  3. glaip_sdk/cli/agent_config.py +2 -6
  4. glaip_sdk/cli/auth.py +11 -30
  5. glaip_sdk/cli/commands/agents.py +45 -107
  6. glaip_sdk/cli/commands/configure.py +12 -36
  7. glaip_sdk/cli/commands/mcps.py +26 -63
  8. glaip_sdk/cli/commands/models.py +2 -4
  9. glaip_sdk/cli/commands/tools.py +22 -35
  10. glaip_sdk/cli/commands/update.py +3 -8
  11. glaip_sdk/cli/config.py +1 -3
  12. glaip_sdk/cli/display.py +4 -12
  13. glaip_sdk/cli/io.py +8 -14
  14. glaip_sdk/cli/main.py +10 -30
  15. glaip_sdk/cli/mcp_validators.py +5 -15
  16. glaip_sdk/cli/pager.py +3 -9
  17. glaip_sdk/cli/parsers/json_input.py +11 -22
  18. glaip_sdk/cli/resolution.py +3 -9
  19. glaip_sdk/cli/rich_helpers.py +1 -3
  20. glaip_sdk/cli/slash/agent_session.py +5 -10
  21. glaip_sdk/cli/slash/prompt.py +3 -10
  22. glaip_sdk/cli/slash/session.py +46 -95
  23. glaip_sdk/cli/transcript/cache.py +6 -19
  24. glaip_sdk/cli/transcript/capture.py +6 -20
  25. glaip_sdk/cli/transcript/launcher.py +1 -3
  26. glaip_sdk/cli/transcript/viewer.py +11 -40
  27. glaip_sdk/cli/update_notifier.py +165 -21
  28. glaip_sdk/cli/utils.py +33 -84
  29. glaip_sdk/cli/validators.py +11 -12
  30. glaip_sdk/client/_agent_payloads.py +10 -30
  31. glaip_sdk/client/agents.py +33 -63
  32. glaip_sdk/client/base.py +6 -22
  33. glaip_sdk/client/mcps.py +1 -3
  34. glaip_sdk/client/run_rendering.py +6 -14
  35. glaip_sdk/client/tools.py +8 -24
  36. glaip_sdk/client/validators.py +20 -48
  37. glaip_sdk/exceptions.py +1 -3
  38. glaip_sdk/models.py +14 -33
  39. glaip_sdk/payload_schemas/agent.py +1 -3
  40. glaip_sdk/utils/agent_config.py +4 -14
  41. glaip_sdk/utils/client_utils.py +7 -21
  42. glaip_sdk/utils/display.py +2 -6
  43. glaip_sdk/utils/general.py +1 -3
  44. glaip_sdk/utils/import_export.py +3 -9
  45. glaip_sdk/utils/rendering/formatting.py +2 -5
  46. glaip_sdk/utils/rendering/models.py +2 -6
  47. glaip_sdk/utils/rendering/renderer/__init__.py +1 -3
  48. glaip_sdk/utils/rendering/renderer/base.py +63 -189
  49. glaip_sdk/utils/rendering/renderer/debug.py +4 -14
  50. glaip_sdk/utils/rendering/renderer/panels.py +1 -3
  51. glaip_sdk/utils/rendering/renderer/progress.py +3 -11
  52. glaip_sdk/utils/rendering/renderer/stream.py +7 -19
  53. glaip_sdk/utils/rendering/renderer/toggle.py +1 -3
  54. glaip_sdk/utils/rendering/step_tree_state.py +1 -3
  55. glaip_sdk/utils/rendering/steps.py +29 -83
  56. glaip_sdk/utils/resource_refs.py +4 -13
  57. glaip_sdk/utils/serialization.py +14 -46
  58. glaip_sdk/utils/validation.py +4 -4
  59. {glaip_sdk-0.1.0.dist-info → glaip_sdk-0.1.1.dist-info}/METADATA +1 -1
  60. glaip_sdk-0.1.1.dist-info/RECORD +82 -0
  61. glaip_sdk-0.1.0.dist-info/RECORD +0 -82
  62. {glaip_sdk-0.1.0.dist-info → glaip_sdk-0.1.1.dist-info}/WHEEL +0 -0
  63. {glaip_sdk-0.1.0.dist-info → glaip_sdk-0.1.1.dist-info}/entry_points.txt +0 -0
glaip_sdk/cli/utils.py CHANGED
@@ -147,9 +147,7 @@ def format_command_hint(
147
147
 
148
148
  highlighted = f"[{HINT_COMMAND_STYLE}]{command}[/]"
149
149
  if description:
150
- highlighted += (
151
- f" [{HINT_DESCRIPTION_COLOR}]{description}[/{HINT_DESCRIPTION_COLOR}]"
152
- )
150
+ highlighted += f" [{HINT_DESCRIPTION_COLOR}]{description}[/{HINT_DESCRIPTION_COLOR}]"
153
151
  return highlighted
154
152
 
155
153
 
@@ -234,7 +232,7 @@ _spinner_stop = stop_spinner
234
232
  def get_client(ctx: Any) -> Client: # pragma: no cover
235
233
  """Get configured client from context, env, and config file (ctx > env > file)."""
236
234
  module = importlib.import_module("glaip_sdk")
237
- client_class = cast("type[Client]", getattr(module, "Client"))
235
+ client_class = cast("type[Client]", module.Client)
238
236
  file_config = load_config() or {}
239
237
  context_config_obj = getattr(ctx, "obj", None)
240
238
  context_config = context_config_obj or {}
@@ -419,9 +417,7 @@ def _prompt_with_auto_select(
419
417
  reserve_space_for_menu=8,
420
418
  )
421
419
  except Exception as exc: # pragma: no cover - depends on prompt_toolkit
422
- logger.debug(
423
- "PromptSession init failed (%s); falling back to basic prompt.", exc
424
- )
420
+ logger.debug("PromptSession init failed (%s); falling back to basic prompt.", exc)
425
421
  return _basic_prompt(message, completer)
426
422
 
427
423
  buffer = session.default_buffer
@@ -447,9 +443,7 @@ def _prompt_with_auto_select(
447
443
  except (KeyboardInterrupt, EOFError):
448
444
  return None
449
445
  except Exception as exc: # pragma: no cover - defensive
450
- logger.debug(
451
- "PromptSession prompt failed (%s); falling back to basic prompt.", exc
452
- )
446
+ logger.debug("PromptSession prompt failed (%s); falling back to basic prompt.", exc)
453
447
  return _basic_prompt(message, completer)
454
448
  finally:
455
449
  if handler_attached:
@@ -465,9 +459,7 @@ class _FuzzyCompleter:
465
459
  def __init__(self, words: list[str]) -> None:
466
460
  self.words = words
467
461
 
468
- def get_completions(
469
- self, document: Any, _complete_event: Any
470
- ) -> Any: # pragma: no cover
462
+ def get_completions(self, document: Any, _complete_event: Any) -> Any: # pragma: no cover
471
463
  word = document.get_word_before_cursor()
472
464
  if not word:
473
465
  return
@@ -492,9 +484,7 @@ class _FuzzyCompleter:
492
484
  return False
493
485
 
494
486
 
495
- def _perform_fuzzy_search(
496
- answer: str, labels: list[str], by_label: dict[str, dict[str, Any]]
497
- ) -> dict[str, Any] | None:
487
+ def _perform_fuzzy_search(answer: str, labels: list[str], by_label: dict[str, dict[str, Any]]) -> dict[str, Any] | None:
498
488
  """Perform fuzzy search fallback and return best match."""
499
489
  # Exact label match
500
490
  if answer in by_label:
@@ -615,7 +605,7 @@ def _coerce_result_payload(result: Any) -> Any:
615
605
 
616
606
 
617
607
  def _ensure_displayable(payload: Any) -> Any:
618
- if isinstance(payload, dict | list | str | int | float | bool) or payload is None:
608
+ if isinstance(payload, (dict, list, str, int, float, bool)) or payload is None:
619
609
  return payload
620
610
 
621
611
  if hasattr(payload, "__dict__"):
@@ -686,9 +676,7 @@ def output_result(
686
676
  # _PICK_THRESHOLD = int(os.getenv("AIP_PICK_THRESHOLD", "5") or "5")
687
677
 
688
678
 
689
- def _normalise_rows(
690
- items: list[Any], transform_func: Callable[[Any], dict[str, Any]] | None
691
- ) -> list[dict[str, Any]]:
679
+ def _normalise_rows(items: list[Any], transform_func: Callable[[Any], dict[str, Any]] | None) -> list[dict[str, Any]]:
692
680
  try:
693
681
  rows: list[dict[str, Any]] = []
694
682
  for item in items:
@@ -707,9 +695,7 @@ def _normalise_rows(
707
695
  return []
708
696
 
709
697
 
710
- def _render_plain_list(
711
- rows: list[dict[str, Any]], title: str, columns: list[tuple]
712
- ) -> None:
698
+ def _render_plain_list(rows: list[dict[str, Any]], title: str, columns: list[tuple]) -> None:
713
699
  if not rows:
714
700
  click.echo(f"No {title.lower()} found.")
715
701
  return
@@ -718,9 +704,7 @@ def _render_plain_list(
718
704
  click.echo(row_str)
719
705
 
720
706
 
721
- def _render_markdown_list(
722
- rows: list[dict[str, Any]], title: str, columns: list[tuple]
723
- ) -> None:
707
+ def _render_markdown_list(rows: list[dict[str, Any]], title: str, columns: list[tuple]) -> None:
724
708
  if not rows:
725
709
  click.echo(f"No {title.lower()} found.")
726
710
  return
@@ -748,9 +732,7 @@ def _create_table(columns: list[tuple[str, str, str, int | None]], title: str) -
748
732
  return table
749
733
 
750
734
 
751
- def _build_table_group(
752
- rows: list[dict[str, Any]], columns: list[tuple], title: str
753
- ) -> Group:
735
+ def _build_table_group(rows: list[dict[str, Any]], columns: list[tuple], title: str) -> Group:
754
736
  table = _create_table(columns, title)
755
737
  for row in rows:
756
738
  table.add_row(*[str(row.get(key, "N/A")) for key, _, _, _ in columns])
@@ -760,24 +742,16 @@ def _build_table_group(
760
742
 
761
743
  def _handle_json_output(items: list[Any], rows: list[dict[str, Any]]) -> None:
762
744
  """Handle JSON output format."""
763
- data = (
764
- rows
765
- if rows
766
- else [it.to_dict() if hasattr(it, "to_dict") else it for it in items]
767
- )
745
+ data = rows if rows else [it.to_dict() if hasattr(it, "to_dict") else it for it in items]
768
746
  click.echo(json.dumps(data, indent=2, default=str))
769
747
 
770
748
 
771
- def _handle_plain_output(
772
- rows: list[dict[str, Any]], title: str, columns: list[tuple]
773
- ) -> None:
749
+ def _handle_plain_output(rows: list[dict[str, Any]], title: str, columns: list[tuple]) -> None:
774
750
  """Handle plain text output format."""
775
751
  _render_plain_list(rows, title, columns)
776
752
 
777
753
 
778
- def _handle_markdown_output(
779
- rows: list[dict[str, Any]], title: str, columns: list[tuple]
780
- ) -> None:
754
+ def _handle_markdown_output(rows: list[dict[str, Any]], title: str, columns: list[tuple]) -> None:
781
755
  """Handle markdown output format."""
782
756
  _render_markdown_list(rows, title, columns)
783
757
 
@@ -792,9 +766,7 @@ def _should_use_fuzzy_picker() -> bool:
792
766
  return console.is_terminal and os.isatty(1)
793
767
 
794
768
 
795
- def _try_fuzzy_pick(
796
- rows: list[dict[str, Any]], columns: list[tuple], title: str
797
- ) -> dict[str, Any] | None:
769
+ def _try_fuzzy_pick(rows: list[dict[str, Any]], columns: list[tuple], title: str) -> dict[str, Any] | None:
798
770
  """Best-effort fuzzy selection; returns None if the picker fails."""
799
771
  if not _should_use_fuzzy_picker():
800
772
  return None
@@ -825,14 +797,10 @@ def _print_selection_tip(title: str) -> None:
825
797
  """Print the contextual follow-up tip after a fuzzy selection."""
826
798
  tip_cmd = _resource_tip_command(title)
827
799
  if tip_cmd:
828
- console.print(
829
- markup_text(f"\n[dim]Tip: use `{tip_cmd} <ID>` for details[/dim]")
830
- )
800
+ console.print(markup_text(f"\n[dim]Tip: use `{tip_cmd} <ID>` for details[/dim]"))
831
801
 
832
802
 
833
- def _handle_fuzzy_pick_selection(
834
- rows: list[dict[str, Any]], columns: list[tuple], title: str
835
- ) -> bool:
803
+ def _handle_fuzzy_pick_selection(rows: list[dict[str, Any]], columns: list[tuple], title: str) -> bool:
836
804
  """Handle fuzzy picker selection, returns True if selection was made."""
837
805
  picked = _try_fuzzy_pick(rows, columns, title)
838
806
  if picked is None:
@@ -855,9 +823,7 @@ def _handle_table_output(
855
823
  """Handle table output with paging."""
856
824
  content = _build_table_group(rows, columns, title)
857
825
  should_page = (
858
- pager._should_page_output(len(rows), console.is_terminal and os.isatty(1))
859
- if use_pager is None
860
- else use_pager
826
+ pager._should_page_output(len(rows), console.is_terminal and os.isatty(1)) if use_pager is None else use_pager
861
827
  )
862
828
 
863
829
  if should_page:
@@ -989,9 +955,7 @@ def build_renderer(
989
955
 
990
956
  # Create the renderer instance
991
957
  renderer = RichStreamRenderer(
992
- working_console.original_console
993
- if isinstance(working_console, CapturingConsole)
994
- else working_console,
958
+ working_console.original_console if isinstance(working_console, CapturingConsole) else working_console,
995
959
  cfg=renderer_cfg,
996
960
  verbose=verbose,
997
961
  )
@@ -1079,22 +1043,14 @@ def _resolve_by_name_multiple_with_select(matches: list[Any], select: int) -> An
1079
1043
  return matches[idx]
1080
1044
 
1081
1045
 
1082
- def _resolve_by_name_multiple_fuzzy(
1083
- ctx: Any, ref: str, matches: list[Any], label: str
1084
- ) -> Any:
1046
+ def _resolve_by_name_multiple_fuzzy(ctx: Any, ref: str, matches: list[Any], label: str) -> Any:
1085
1047
  """Resolve multiple matches preferring the fuzzy picker interface."""
1086
- return handle_ambiguous_resource(
1087
- ctx, label.lower(), ref, matches, interface_preference="fuzzy"
1088
- )
1048
+ return handle_ambiguous_resource(ctx, label.lower(), ref, matches, interface_preference="fuzzy")
1089
1049
 
1090
1050
 
1091
- def _resolve_by_name_multiple_questionary(
1092
- ctx: Any, ref: str, matches: list[Any], label: str
1093
- ) -> Any:
1051
+ def _resolve_by_name_multiple_questionary(ctx: Any, ref: str, matches: list[Any], label: str) -> Any:
1094
1052
  """Resolve multiple matches preferring the questionary interface."""
1095
- return handle_ambiguous_resource(
1096
- ctx, label.lower(), ref, matches, interface_preference="questionary"
1097
- )
1053
+ return handle_ambiguous_resource(ctx, label.lower(), ref, matches, interface_preference="questionary")
1098
1054
 
1099
1055
 
1100
1056
  def resolve_resource(
@@ -1139,9 +1095,7 @@ def resolve_resource(
1139
1095
  raise click.ClickException(f"{label} '{ref}' not found")
1140
1096
 
1141
1097
  # Find resources by name
1142
- _spinner_update(
1143
- spinner, f"[bold blue]Searching {label}s matching '{ref}'…[/bold blue]"
1144
- )
1098
+ _spinner_update(spinner, f"[bold blue]Searching {label}s matching '{ref}'…[/bold blue]")
1145
1099
  matches = find_by_name(name=ref)
1146
1100
  if not matches:
1147
1101
  _spinner_stop(spinner)
@@ -1172,9 +1126,7 @@ def _handle_json_view_ambiguity(matches: list[Any]) -> Any:
1172
1126
  return matches[0]
1173
1127
 
1174
1128
 
1175
- def _handle_questionary_ambiguity(
1176
- resource_type: str, ref: str, matches: list[Any]
1177
- ) -> Any:
1129
+ def _handle_questionary_ambiguity(resource_type: str, ref: str, matches: list[Any]) -> Any:
1178
1130
  """Handle ambiguity using questionary interactive interface."""
1179
1131
  if not (questionary and os.getenv("TERM") and os.isatty(0) and os.isatty(1)):
1180
1132
  raise click.ClickException("Interactive selection not available")
@@ -1187,7 +1139,10 @@ def _handle_questionary_ambiguity(
1187
1139
  f"Multiple {safe_resource_type}s match '{safe_ref}'. Pick one:",
1188
1140
  choices=[
1189
1141
  questionary.Choice(
1190
- title=f"{getattr(m, 'name', '—').replace('{', '{{').replace('}', '}}')} — {getattr(m, 'id', '').replace('{', '{{').replace('}', '}}')}",
1142
+ title=(
1143
+ f"{getattr(m, 'name', '—').replace('{', '{{').replace('}', '}}')} — "
1144
+ f"{getattr(m, 'id', '').replace('{', '{{').replace('}', '}}')}"
1145
+ ),
1191
1146
  value=i,
1192
1147
  )
1193
1148
  for i, m in enumerate(matches)
@@ -1201,19 +1156,13 @@ def _handle_questionary_ambiguity(
1201
1156
  return matches[picked_idx]
1202
1157
 
1203
1158
 
1204
- def _handle_fallback_numeric_ambiguity(
1205
- resource_type: str, ref: str, matches: list[Any]
1206
- ) -> Any:
1159
+ def _handle_fallback_numeric_ambiguity(resource_type: str, ref: str, matches: list[Any]) -> Any:
1207
1160
  """Handle ambiguity using numeric prompt fallback."""
1208
1161
  # Escape special characters for display
1209
1162
  safe_resource_type = resource_type.replace("{", "{{").replace("}", "}}")
1210
1163
  safe_ref = ref.replace("{", "{{").replace("}", "}}")
1211
1164
 
1212
- console.print(
1213
- markup_text(
1214
- f"[{WARNING_STYLE}]Multiple {safe_resource_type}s found matching '{safe_ref}':[/]"
1215
- )
1216
- )
1165
+ console.print(markup_text(f"[{WARNING_STYLE}]Multiple {safe_resource_type}s found matching '{safe_ref}':[/]"))
1217
1166
  table = AIPTable(
1218
1167
  title=f"Select {safe_resource_type.title()}",
1219
1168
  )
@@ -1228,8 +1177,8 @@ def _handle_fallback_numeric_ambiguity(
1228
1177
  )
1229
1178
  try:
1230
1179
  choice = int(choice_str)
1231
- except ValueError:
1232
- raise click.ClickException("Invalid selection")
1180
+ except ValueError as err:
1181
+ raise click.ClickException("Invalid selection") from err
1233
1182
  if 1 <= choice <= len(matches):
1234
1183
  return matches[choice - 1]
1235
1184
  raise click.ClickException("Invalid selection")
@@ -42,7 +42,7 @@ def validate_agent_name_cli(name: str) -> str:
42
42
  try:
43
43
  return validate_agent_name(name)
44
44
  except ValueError as e:
45
- raise click.ClickException(str(e))
45
+ raise click.ClickException(str(e)) from e
46
46
 
47
47
 
48
48
  def validate_agent_instruction_cli(instruction: str) -> str:
@@ -60,7 +60,7 @@ def validate_agent_instruction_cli(instruction: str) -> str:
60
60
  try:
61
61
  return validate_agent_instruction(instruction)
62
62
  except ValueError as e:
63
- raise click.ClickException(str(e))
63
+ raise click.ClickException(str(e)) from e
64
64
 
65
65
 
66
66
  def validate_timeout_cli(timeout: int) -> int:
@@ -78,7 +78,7 @@ def validate_timeout_cli(timeout: int) -> int:
78
78
  try:
79
79
  return validate_timeout(timeout)
80
80
  except ValueError as e:
81
- raise click.ClickException(str(e))
81
+ raise click.ClickException(str(e)) from e
82
82
 
83
83
 
84
84
  def validate_tool_name_cli(name: str) -> str:
@@ -96,7 +96,7 @@ def validate_tool_name_cli(name: str) -> str:
96
96
  try:
97
97
  return validate_tool_name(name)
98
98
  except ValueError as e:
99
- raise click.ClickException(str(e))
99
+ raise click.ClickException(str(e)) from e
100
100
 
101
101
 
102
102
  def validate_mcp_name_cli(name: str) -> str:
@@ -114,7 +114,7 @@ def validate_mcp_name_cli(name: str) -> str:
114
114
  try:
115
115
  return validate_mcp_name(name)
116
116
  except ValueError as e:
117
- raise click.ClickException(str(e))
117
+ raise click.ClickException(str(e)) from e
118
118
 
119
119
 
120
120
  def validate_file_path_cli(file_path: str | Path, must_exist: bool = True) -> Path:
@@ -133,7 +133,7 @@ def validate_file_path_cli(file_path: str | Path, must_exist: bool = True) -> Pa
133
133
  try:
134
134
  return validate_file_path(file_path, must_exist)
135
135
  except ValueError as e:
136
- raise click.ClickException(str(e))
136
+ raise click.ClickException(str(e)) from e
137
137
 
138
138
 
139
139
  def validate_directory_path_cli(dir_path: str | Path, must_exist: bool = True) -> Path:
@@ -152,7 +152,7 @@ def validate_directory_path_cli(dir_path: str | Path, must_exist: bool = True) -
152
152
  try:
153
153
  return validate_directory_path(dir_path, must_exist)
154
154
  except ValueError as e:
155
- raise click.ClickException(str(e))
155
+ raise click.ClickException(str(e)) from e
156
156
 
157
157
 
158
158
  def validate_url_cli(url: str) -> str:
@@ -170,7 +170,7 @@ def validate_url_cli(url: str) -> str:
170
170
  try:
171
171
  return validate_url(url)
172
172
  except ValueError as e:
173
- raise click.ClickException(str(e))
173
+ raise click.ClickException(str(e)) from e
174
174
 
175
175
 
176
176
  def validate_api_key_cli(api_key: str) -> str:
@@ -188,7 +188,7 @@ def validate_api_key_cli(api_key: str) -> str:
188
188
  try:
189
189
  return validate_api_key(api_key)
190
190
  except ValueError as e:
191
- raise click.ClickException(str(e))
191
+ raise click.ClickException(str(e)) from e
192
192
 
193
193
 
194
194
  def coerce_timeout_cli(value: int | float | str) -> int:
@@ -206,7 +206,7 @@ def coerce_timeout_cli(value: int | float | str) -> int:
206
206
  try:
207
207
  return coerce_timeout(value)
208
208
  except ValueError as e:
209
- raise click.ClickException(str(e))
209
+ raise click.ClickException(str(e)) from e
210
210
 
211
211
 
212
212
  def validate_name_uniqueness_cli(
@@ -230,8 +230,7 @@ def validate_name_uniqueness_cli(
230
230
  existing = finder_func(name=name)
231
231
  if existing:
232
232
  raise click.ClickException(
233
- f"A {resource_type.lower()} named '{name}' already exists. "
234
- "Please choose a unique name."
233
+ f"A {resource_type.lower()} named '{name}' already exists. Please choose a unique name."
235
234
  )
236
235
  except click.ClickException:
237
236
  raise
@@ -348,9 +348,7 @@ class AgentCreateRequest:
348
348
  payload["tool_configs"] = _copy_structure(self.tool_configs)
349
349
 
350
350
  effective_agent_config = _sanitize_agent_config(self.agent_config)
351
- effective_agent_config = _merge_execution_timeout(
352
- effective_agent_config, self.timeout
353
- )
351
+ effective_agent_config = _merge_execution_timeout(effective_agent_config, self.timeout)
354
352
  if effective_agent_config:
355
353
  payload["agent_config"] = effective_agent_config
356
354
 
@@ -407,31 +405,19 @@ __all__ = [
407
405
  ]
408
406
 
409
407
 
410
- def _build_base_update_payload(
411
- request: AgentUpdateRequest, current_agent: Any
412
- ) -> dict[str, Any]:
408
+ def _build_base_update_payload(request: AgentUpdateRequest, current_agent: Any) -> dict[str, Any]:
413
409
  return {
414
- "name": request.name.strip()
415
- if request.name is not None
416
- else getattr(current_agent, "name", None),
410
+ "name": request.name.strip() if request.name is not None else getattr(current_agent, "name", None),
417
411
  "instruction": request.instruction.strip()
418
412
  if request.instruction is not None
419
413
  else getattr(current_agent, "instruction", None),
420
- "type": request.agent_type
421
- or getattr(current_agent, "type", None)
422
- or DEFAULT_AGENT_TYPE,
423
- "framework": request.framework
424
- or getattr(current_agent, "framework", None)
425
- or DEFAULT_AGENT_FRAMEWORK,
426
- "version": request.version
427
- or getattr(current_agent, "version", None)
428
- or DEFAULT_AGENT_VERSION,
414
+ "type": request.agent_type or getattr(current_agent, "type", None) or DEFAULT_AGENT_TYPE,
415
+ "framework": request.framework or getattr(current_agent, "framework", None) or DEFAULT_AGENT_FRAMEWORK,
416
+ "version": request.version or getattr(current_agent, "version", None) or DEFAULT_AGENT_VERSION,
429
417
  }
430
418
 
431
419
 
432
- def _resolve_update_language_model_fields(
433
- request: AgentUpdateRequest, current_agent: Any
434
- ) -> dict[str, Any]:
420
+ def _resolve_update_language_model_fields(request: AgentUpdateRequest, current_agent: Any) -> dict[str, Any]:
435
421
  fields = resolve_language_model_fields(
436
422
  model=request.model,
437
423
  language_model_id=request.language_model_id,
@@ -443,9 +429,7 @@ def _resolve_update_language_model_fields(
443
429
  return fields
444
430
 
445
431
 
446
- def _collect_optional_update_fields(
447
- request: AgentUpdateRequest, current_agent: Any
448
- ) -> dict[str, Any]:
432
+ def _collect_optional_update_fields(request: AgentUpdateRequest, current_agent: Any) -> dict[str, Any]:
449
433
  result: dict[str, Any] = {}
450
434
 
451
435
  for field_name, value in (
@@ -483,9 +467,7 @@ def _collect_optional_update_fields(
483
467
  return result
484
468
 
485
469
 
486
- def _collect_relationship_fields(
487
- request: AgentUpdateRequest, current_agent: Any
488
- ) -> dict[str, Any]:
470
+ def _collect_relationship_fields(request: AgentUpdateRequest, current_agent: Any) -> dict[str, Any]:
489
471
  return {
490
472
  "tools": _resolve_relation_ids(request.tools, current_agent, "tools"),
491
473
  "agents": _resolve_relation_ids(request.agents, current_agent, "agents"),
@@ -493,9 +475,7 @@ def _collect_relationship_fields(
493
475
  }
494
476
 
495
477
 
496
- def _resolve_agent_config_update(
497
- request: AgentUpdateRequest, current_agent: Any
498
- ) -> dict[str, Any] | None:
478
+ def _resolve_agent_config_update(request: AgentUpdateRequest, current_agent: Any) -> dict[str, Any] | None:
499
479
  effective_agent_config = _sanitize_agent_config(request.agent_config)
500
480
  if effective_agent_config is not None:
501
481
  return effective_agent_config