glaip-sdk 0.2.0__py3-none-any.whl → 0.2.2__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14,6 +14,7 @@ import click
14
14
  from glaip_sdk.branding import ERROR_STYLE, HINT_PREFIX_STYLE
15
15
  from glaip_sdk.cli.commands.agents import get as agents_get_command
16
16
  from glaip_sdk.cli.commands.agents import run as agents_run_command
17
+ from glaip_sdk.cli.constants import DEFAULT_AGENT_INSTRUCTION_PREVIEW_LIMIT
17
18
  from glaip_sdk.cli.slash.prompt import _HAS_PROMPT_TOOLKIT, FormattedText
18
19
  from glaip_sdk.cli.utils import format_command_hint
19
20
 
@@ -38,11 +39,12 @@ class AgentRunSession:
38
39
  self._agent_name = getattr(agent, "name", "") or self._agent_id
39
40
  self._prompt_placeholder: str = "Chat with this agent here; use / for shortcuts. Alt+Enter inserts a newline."
40
41
  self._contextual_completion_help: dict[str, str] = {
41
- "details": "Show this agent's full configuration.",
42
+ "details": "Show this agent's configuration (+ expands prompt).",
42
43
  "help": "Display this context-aware menu.",
43
44
  "exit": "Return to the command palette.",
44
45
  "q": "Return to the command palette.",
45
46
  }
47
+ self._instruction_preview_limit = DEFAULT_AGENT_INSTRUCTION_PREVIEW_LIMIT
46
48
 
47
49
  def run(self) -> None:
48
50
  """Run the interactive agent session loop."""
@@ -86,6 +88,7 @@ class AgentRunSession:
86
88
  try:
87
89
 
88
90
  def _prompt_message() -> Any:
91
+ """Get formatted prompt message for agent session."""
89
92
  prompt_prefix = f"{self._agent_name} ({self._agent_id}) "
90
93
 
91
94
  # Use FormattedText if prompt_toolkit is available, otherwise use simple string
@@ -122,7 +125,7 @@ class AgentRunSession:
122
125
  if raw in {"/exit", "/back", "/q"}:
123
126
  return self._handle_exit_command()
124
127
 
125
- if raw in {"/details", "/detail"}:
128
+ if raw == "/details":
126
129
  return self._handle_details_command(agent_id)
127
130
 
128
131
  if raw in {"/help", "/?"}:
@@ -151,16 +154,59 @@ class AgentRunSession:
151
154
  self.session.handle_command(raw, invoked_from_agent=True)
152
155
  return not self.session._should_exit
153
156
 
154
- def _show_details(self, agent_id: str) -> None:
157
+ def _show_details(self, agent_id: str, *, enable_prompt: bool = True) -> None:
158
+ """Render the agent's configuration export inside the command palette."""
155
159
  try:
156
- self.session.ctx.invoke(agents_get_command, agent_ref=agent_id)
157
- self.console.print(
158
- f"[{HINT_PREFIX_STYLE}]Tip:[/] Continue the conversation in this prompt, or use "
159
- f"{format_command_hint('/help') or '/help'} for shortcuts."
160
+ self.session.ctx.invoke(
161
+ agents_get_command,
162
+ agent_ref=agent_id,
163
+ instruction_preview=self._instruction_preview_limit,
160
164
  )
165
+ if enable_prompt:
166
+ self._prompt_instruction_view_toggle(agent_id)
167
+ self.console.print(
168
+ f"[{HINT_PREFIX_STYLE}]Tip:[/] Continue the conversation in this prompt, or use "
169
+ f"{format_command_hint('/help') or '/help'} for shortcuts."
170
+ )
161
171
  except click.ClickException as exc:
162
172
  self.console.print(f"[{ERROR_STYLE}]{exc}[/]")
163
173
 
174
+ def _prompt_instruction_view_toggle(self, agent_id: str) -> None:
175
+ """Offer a prompt to expand or collapse the instruction preview after details."""
176
+ if not getattr(self.console, "is_terminal", False):
177
+ return
178
+
179
+ while True:
180
+ mode = "expanded" if self._instruction_preview_limit == 0 else "trimmed"
181
+ self.console.print(f"[dim]Instruction view is {mode}. Press Ctrl+T to toggle, Enter to continue.[/dim]")
182
+ try:
183
+ ch = click.getchar()
184
+ except (EOFError, KeyboardInterrupt): # pragma: no cover - defensive guard
185
+ return
186
+
187
+ if not self._handle_instruction_toggle_input(agent_id, ch):
188
+ break
189
+
190
+ if self._instruction_preview_limit == 0:
191
+ self._instruction_preview_limit = DEFAULT_AGENT_INSTRUCTION_PREVIEW_LIMIT
192
+ self.console.print("")
193
+
194
+ def _handle_instruction_toggle_input(self, agent_id: str, ch: str) -> bool:
195
+ """Process a single toggle keypress; return False when the loop should exit."""
196
+ if ch in {"\r", "\n"}:
197
+ return False
198
+
199
+ lowered = ch.lower()
200
+ if lowered == "t" or ch == "\x14": # support literal 't' or Ctrl+T
201
+ self._instruction_preview_limit = (
202
+ DEFAULT_AGENT_INSTRUCTION_PREVIEW_LIMIT if self._instruction_preview_limit == 0 else 0
203
+ )
204
+ self._show_details(agent_id, enable_prompt=False)
205
+ return True
206
+
207
+ # Ignore other keys and continue prompting.
208
+ return True
209
+
164
210
  def _after_agent_run(self) -> None:
165
211
  """Handle transcript viewer behaviour after a successful run."""
166
212
  payload, manifest = self.session._get_last_transcript()
@@ -221,6 +267,7 @@ class AgentRunSession:
221
267
  ctx_obj["_slash_session"] = previous_session
222
268
 
223
269
  def _run_agent(self, agent_id: str, message: str) -> None:
270
+ """Execute the agents run command for the active agent."""
224
271
  if not message:
225
272
  return
226
273
 
@@ -123,6 +123,11 @@ def _create_key_bindings(_session: SlashSession) -> Any:
123
123
  bindings = KeyBindings()
124
124
 
125
125
  def _refresh_completions(buffer: Any) -> None: # type: ignore[no-any-return]
126
+ """Refresh completions when slash command is typed.
127
+
128
+ Args:
129
+ buffer: Prompt buffer instance.
130
+ """
126
131
  text = buffer.document.text_before_cursor or ""
127
132
  if text.startswith("/") and " " not in text:
128
133
  buffer.start_completion(select_first=False)
@@ -153,9 +153,15 @@ class SlashSession:
153
153
  # ------------------------------------------------------------------
154
154
  # Session orchestration
155
155
  # ------------------------------------------------------------------
156
- def refresh_branding(self, sdk_version: str | None = None) -> None:
156
+ def refresh_branding(
157
+ self,
158
+ sdk_version: str | None = None,
159
+ *,
160
+ branding_cls: type[AIPBranding] | None = None,
161
+ ) -> None:
157
162
  """Refresh branding assets after an in-session SDK upgrade."""
158
- self._branding = AIPBranding.create_from_sdk(
163
+ branding_type = branding_cls or AIPBranding
164
+ self._branding = branding_type.create_from_sdk(
159
165
  sdk_version=sdk_version,
160
166
  package_name="glaip-sdk",
161
167
  )
@@ -165,6 +171,7 @@ class SlashSession:
165
171
  self._render_header(initial=True)
166
172
 
167
173
  def _setup_prompt_toolkit(self) -> None:
174
+ """Initialize prompt_toolkit session and style."""
168
175
  session, style = setup_prompt_toolkit(self, interactive=self._interactive)
169
176
  self._ptk_session = session
170
177
  self._ptk_style = style
@@ -304,6 +311,15 @@ class SlashSession:
304
311
  # Command handlers
305
312
  # ------------------------------------------------------------------
306
313
  def _cmd_help(self, _args: list[str], invoked_from_agent: bool) -> bool:
314
+ """Handle the /help command.
315
+
316
+ Args:
317
+ _args: Command arguments (unused).
318
+ invoked_from_agent: Whether invoked from agent context.
319
+
320
+ Returns:
321
+ True to continue session.
322
+ """
307
323
  try:
308
324
  if invoked_from_agent:
309
325
  self._render_agent_help()
@@ -316,11 +332,12 @@ class SlashSession:
316
332
  return True
317
333
 
318
334
  def _render_agent_help(self) -> None:
335
+ """Render help text for agent context commands."""
319
336
  table = AIPTable()
320
337
  table.add_column("Input", style=HINT_COMMAND_STYLE, no_wrap=True)
321
338
  table.add_column("What happens", style=HINT_DESCRIPTION_COLOR)
322
339
  table.add_row("<message>", "Run the active agent once with that prompt.")
323
- table.add_row("/details", "Show the full agent export and metadata.")
340
+ table.add_row("/details", "Show the agent export (prompts to expand instructions).")
324
341
  table.add_row(self.STATUS_COMMAND, "Display connection status without leaving.")
325
342
  table.add_row("/export [path]", "Export the latest agent transcript as JSONL.")
326
343
  table.add_row("/exit (/back)", "Return to the slash home screen.")
@@ -344,6 +361,7 @@ class SlashSession:
344
361
  )
345
362
 
346
363
  def _render_global_help(self) -> None:
364
+ """Render help text for global slash commands."""
347
365
  table = AIPTable()
348
366
  table.add_column("Command", style=HINT_COMMAND_STYLE, no_wrap=True)
349
367
  table.add_column("Description", style=HINT_DESCRIPTION_COLOR)
@@ -370,6 +388,15 @@ class SlashSession:
370
388
  )
371
389
 
372
390
  def _cmd_login(self, _args: list[str], _invoked_from_agent: bool) -> bool:
391
+ """Handle the /login command.
392
+
393
+ Args:
394
+ _args: Command arguments (unused).
395
+ _invoked_from_agent: Whether invoked from agent context (unused).
396
+
397
+ Returns:
398
+ True to continue session.
399
+ """
373
400
  self.console.print(f"[{ACCENT_STYLE}]Launching configuration wizard...[/]")
374
401
  try:
375
402
  self.ctx.invoke(configure_command)
@@ -385,6 +412,15 @@ class SlashSession:
385
412
  return self._continue_session()
386
413
 
387
414
  def _cmd_status(self, _args: list[str], _invoked_from_agent: bool) -> bool:
415
+ """Handle the /status command.
416
+
417
+ Args:
418
+ _args: Command arguments (unused).
419
+ _invoked_from_agent: Whether invoked from agent context (unused).
420
+
421
+ Returns:
422
+ True to continue session.
423
+ """
388
424
  ctx_obj = self.ctx.obj if isinstance(self.ctx.obj, dict) else None
389
425
  previous_console = None
390
426
  try:
@@ -414,6 +450,15 @@ class SlashSession:
414
450
  return self._continue_session()
415
451
 
416
452
  def _cmd_transcripts(self, args: list[str], _invoked_from_agent: bool) -> bool:
453
+ """Handle the /transcripts command.
454
+
455
+ Args:
456
+ args: Command arguments (limit or detail/show with run_id).
457
+ _invoked_from_agent: Whether invoked from agent context (unused).
458
+
459
+ Returns:
460
+ True to continue session.
461
+ """
417
462
  if args and args[0].lower() in {"detail", "show"}:
418
463
  if len(args) < 2:
419
464
  self.console.print(f"[{WARNING_STYLE}]Usage: /transcripts detail <run_id>[/]")
@@ -434,6 +479,14 @@ class SlashSession:
434
479
  return self._continue_session()
435
480
 
436
481
  def _parse_transcripts_limit(self, args: list[str]) -> tuple[int | None, bool]:
482
+ """Parse limit argument from transcripts command.
483
+
484
+ Args:
485
+ args: Command arguments.
486
+
487
+ Returns:
488
+ Tuple of (limit value or None, success boolean).
489
+ """
437
490
  if not args:
438
491
  return None, True
439
492
  try:
@@ -447,6 +500,15 @@ class SlashSession:
447
500
  return limit, True
448
501
 
449
502
  def _handle_transcripts_empty(self, snapshot: Any, limit: int | None) -> bool:
503
+ """Handle empty transcript snapshot cases.
504
+
505
+ Args:
506
+ snapshot: Transcript snapshot object.
507
+ limit: Limit value or None.
508
+
509
+ Returns:
510
+ True if empty case was handled, False otherwise.
511
+ """
450
512
  if snapshot.cached_entries == 0:
451
513
  self.console.print(f"[{WARNING_STYLE}]No cached transcripts yet. Run an agent first.[/]")
452
514
  for warning in snapshot.warnings:
@@ -458,6 +520,11 @@ class SlashSession:
458
520
  return False
459
521
 
460
522
  def _render_transcripts_snapshot(self, snapshot: Any) -> None:
523
+ """Render transcript snapshot table and metadata.
524
+
525
+ Args:
526
+ snapshot: Transcript snapshot object to render.
527
+ """
461
528
  size_text = format_size(snapshot.total_size_bytes)
462
529
  header = f"[dim]Manifest: {snapshot.manifest_path} · {snapshot.total_entries} runs · {size_text} used[/]"
463
530
  self.console.print(header)
@@ -523,6 +590,15 @@ class SlashSession:
523
590
  self.console.print(view, markup=False, highlight=False, soft_wrap=True, end="")
524
591
 
525
592
  def _cmd_agents(self, args: list[str], _invoked_from_agent: bool) -> bool:
593
+ """Handle the /agents command.
594
+
595
+ Args:
596
+ args: Command arguments (optional agent reference).
597
+ _invoked_from_agent: Whether invoked from agent context (unused).
598
+
599
+ Returns:
600
+ True to continue session.
601
+ """
526
602
  client = self._get_client_or_fail()
527
603
  if not client:
528
604
  return True
@@ -608,6 +684,15 @@ class SlashSession:
608
684
  self._show_quick_actions(hints, title="Next actions")
609
685
 
610
686
  def _cmd_exit(self, _args: list[str], invoked_from_agent: bool) -> bool:
687
+ """Handle the /exit command.
688
+
689
+ Args:
690
+ _args: Command arguments (unused).
691
+ invoked_from_agent: Whether invoked from agent context.
692
+
693
+ Returns:
694
+ False to exit session, True to continue.
695
+ """
611
696
  if invoked_from_agent:
612
697
  # Returning False would stop the full session; we only want to exit
613
698
  # the agent context. Raising a custom flag keeps the outer loop
@@ -621,6 +706,7 @@ class SlashSession:
621
706
  # Utilities
622
707
  # ------------------------------------------------------------------
623
708
  def _register_defaults(self) -> None:
709
+ """Register default slash commands."""
624
710
  self._register(
625
711
  SlashCommand(
626
712
  name="help",
@@ -682,6 +768,11 @@ class SlashSession:
682
768
  )
683
769
 
684
770
  def _register(self, command: SlashCommand) -> None:
771
+ """Register a slash command.
772
+
773
+ Args:
774
+ command: SlashCommand to register.
775
+ """
685
776
  self._unique_commands[command.name] = command
686
777
  for key in (command.name, *command.aliases):
687
778
  self._commands[key] = command
@@ -710,6 +801,14 @@ class SlashSession:
710
801
  )
711
802
 
712
803
  def _export(destination: Path) -> Path:
804
+ """Export cached transcript to destination.
805
+
806
+ Args:
807
+ destination: Path to export transcript to.
808
+
809
+ Returns:
810
+ Path to exported transcript file.
811
+ """
713
812
  return export_cached_transcript(destination=destination, run_id=run_id)
714
813
 
715
814
  try:
@@ -806,6 +905,14 @@ class SlashSession:
806
905
  pass
807
906
 
808
907
  def _parse(self, raw: str) -> tuple[str, list[str]]:
908
+ """Parse a raw command string into verb and arguments.
909
+
910
+ Args:
911
+ raw: Raw command string.
912
+
913
+ Returns:
914
+ Tuple of (verb, args).
915
+ """
809
916
  try:
810
917
  tokens = shlex.split(raw)
811
918
  except ValueError:
@@ -821,6 +928,14 @@ class SlashSession:
821
928
  return head, tokens[1:]
822
929
 
823
930
  def _suggest(self, verb: str) -> str | None:
931
+ """Suggest a similar command name for an unknown verb.
932
+
933
+ Args:
934
+ verb: Unknown command verb.
935
+
936
+ Returns:
937
+ Suggested command name or None.
938
+ """
824
939
  keys = [cmd.name for cmd in self._unique_commands.values()]
825
940
  match = get_close_matches(verb, keys, n=1)
826
941
  return match[0] if match else None
@@ -849,6 +964,7 @@ class SlashSession:
849
964
  if callable(message):
850
965
 
851
966
  def prompt_text() -> Any:
967
+ """Get formatted prompt text from callable message."""
852
968
  return self._convert_message(message())
853
969
  else:
854
970
  prompt_text = self._convert_message(message)
@@ -894,6 +1010,11 @@ class SlashSession:
894
1010
  return self._prompt_with_basic_input(message, placeholder)
895
1011
 
896
1012
  def _get_client(self) -> Any: # type: ignore[no-any-return]
1013
+ """Get or create the API client instance.
1014
+
1015
+ Returns:
1016
+ API client instance.
1017
+ """
897
1018
  if self._client is None:
898
1019
  self._client = get_client(self.ctx)
899
1020
  return self._client
@@ -912,6 +1033,11 @@ class SlashSession:
912
1033
  return self._contextual_include_global
913
1034
 
914
1035
  def _remember_agent(self, agent: Any) -> None: # type: ignore[no-any-return]
1036
+ """Remember an agent in recent agents list.
1037
+
1038
+ Args:
1039
+ agent: Agent object to remember.
1040
+ """
915
1041
  agent_data = {
916
1042
  "id": str(getattr(agent, "id", "")),
917
1043
  "name": getattr(agent, "name", "") or "",
@@ -929,6 +1055,13 @@ class SlashSession:
929
1055
  focus_agent: bool = False,
930
1056
  initial: bool = False,
931
1057
  ) -> None:
1058
+ """Render the session header with branding and status.
1059
+
1060
+ Args:
1061
+ active_agent: Optional active agent to display.
1062
+ focus_agent: Whether to focus on agent display.
1063
+ initial: Whether this is the initial render.
1064
+ """
932
1065
  if focus_agent and active_agent is not None:
933
1066
  self._render_focused_agent_header(active_agent)
934
1067
  return
@@ -1033,7 +1166,7 @@ class SlashSession:
1033
1166
 
1034
1167
  keybar.add_row(
1035
1168
  format_command_hint("/help", "Show commands") or "",
1036
- format_command_hint("/details", "Agent config") or "",
1169
+ format_command_hint("/details", "Agent config (expand prompt)") or "",
1037
1170
  format_command_hint("/exit", "Back") or "",
1038
1171
  )
1039
1172
 
@@ -1092,6 +1225,7 @@ class SlashSession:
1092
1225
  return None
1093
1226
 
1094
1227
  def _show_default_quick_actions(self) -> None:
1228
+ """Show default quick action hints for new and evergreen commands."""
1095
1229
  new_hints = self._collect_quick_action_hints(NEW_QUICK_ACTIONS, highlight_new=True)
1096
1230
  evergreen_hints = self._collect_quick_action_hints(DEFAULT_QUICK_ACTIONS)
1097
1231
  if new_hints or evergreen_hints:
@@ -1106,6 +1240,15 @@ class SlashSession:
1106
1240
  *,
1107
1241
  highlight_new: bool = False,
1108
1242
  ) -> list[tuple[str, str]]:
1243
+ """Collect quick action hints from action definitions.
1244
+
1245
+ Args:
1246
+ actions: Iterable of action dictionaries.
1247
+ highlight_new: Whether to highlight new actions.
1248
+
1249
+ Returns:
1250
+ List of (command, description) tuples.
1251
+ """
1109
1252
  collected: list[tuple[str, str]] = []
1110
1253
  for action in sorted(actions, key=lambda payload: payload.get("priority", 0), reverse=True):
1111
1254
  hint = self._build_quick_action_hint(action, highlight_new=highlight_new)
@@ -1119,6 +1262,15 @@ class SlashSession:
1119
1262
  *,
1120
1263
  highlight_new: bool = False,
1121
1264
  ) -> tuple[str, str] | None:
1265
+ """Build a quick action hint from an action definition.
1266
+
1267
+ Args:
1268
+ action: Action dictionary.
1269
+ highlight_new: Whether to highlight as new.
1270
+
1271
+ Returns:
1272
+ Tuple of (command, description) or None.
1273
+ """
1122
1274
  command = command_hint(action.get("cli"), slash_command=action.get("slash"), ctx=self.ctx)
1123
1275
  if not command:
1124
1276
  return None
@@ -1131,6 +1283,12 @@ class SlashSession:
1131
1283
  return command, description
1132
1284
 
1133
1285
  def _render_quick_action_group(self, hints: list[tuple[str, str]], title: str) -> None:
1286
+ """Render a group of quick action hints.
1287
+
1288
+ Args:
1289
+ hints: List of (command, description) tuples.
1290
+ title: Group title.
1291
+ """
1134
1292
  if not hints:
1135
1293
  return
1136
1294
  formatted_tokens: list[str] = []
@@ -1147,10 +1305,20 @@ class SlashSession:
1147
1305
  self.console.print(" " + " ".join(chunk))
1148
1306
 
1149
1307
  def _chunk_tokens(self, tokens: list[str], *, size: int) -> Iterable[list[str]]:
1308
+ """Chunk tokens into groups of specified size.
1309
+
1310
+ Args:
1311
+ tokens: List of tokens to chunk.
1312
+ size: Size of each chunk.
1313
+
1314
+ Yields:
1315
+ Lists of tokens.
1316
+ """
1150
1317
  for index in range(0, len(tokens), size):
1151
1318
  yield tokens[index : index + size]
1152
1319
 
1153
1320
  def _render_home_hint(self) -> None:
1321
+ """Render hint text for home screen."""
1154
1322
  if self._home_hint_shown:
1155
1323
  return
1156
1324
  hint_text = (
@@ -1168,6 +1336,13 @@ class SlashSession:
1168
1336
  title: str = "Quick actions",
1169
1337
  inline: bool = False,
1170
1338
  ) -> None:
1339
+ """Show quick action hints.
1340
+
1341
+ Args:
1342
+ hints: Iterable of (command, description) tuples.
1343
+ title: Title for the hints.
1344
+ inline: Whether to render inline or in a panel.
1345
+ """
1171
1346
  hint_list = self._normalize_quick_action_hints(hints)
1172
1347
  if not hint_list:
1173
1348
  return
@@ -1179,9 +1354,23 @@ class SlashSession:
1179
1354
  self._render_panel_quick_actions(hint_list, title)
1180
1355
 
1181
1356
  def _normalize_quick_action_hints(self, hints: Iterable[tuple[str, str]]) -> list[tuple[str, str]]:
1357
+ """Normalize quick action hints by filtering out empty commands.
1358
+
1359
+ Args:
1360
+ hints: Iterable of (command, description) tuples.
1361
+
1362
+ Returns:
1363
+ List of normalized hints.
1364
+ """
1182
1365
  return [(command, description) for command, description in hints if command]
1183
1366
 
1184
1367
  def _render_inline_quick_actions(self, hint_list: list[tuple[str, str]], title: str) -> None:
1368
+ """Render quick actions inline.
1369
+
1370
+ Args:
1371
+ hint_list: List of (command, description) tuples.
1372
+ title: Title for the hints.
1373
+ """
1185
1374
  tokens: list[str] = []
1186
1375
  for command, description in hint_list:
1187
1376
  formatted = format_command_hint(command, description)
@@ -1195,6 +1384,12 @@ class SlashSession:
1195
1384
  self.console.print(text.strip())
1196
1385
 
1197
1386
  def _render_panel_quick_actions(self, hint_list: list[tuple[str, str]], title: str) -> None:
1387
+ """Render quick actions in a panel.
1388
+
1389
+ Args:
1390
+ hint_list: List of (command, description) tuples.
1391
+ title: Panel title.
1392
+ """
1198
1393
  body_lines: list[Text] = []
1199
1394
  for command, description in hint_list:
1200
1395
  formatted = format_command_hint(command, description)
@@ -1206,6 +1401,11 @@ class SlashSession:
1206
1401
  self.console.print(AIPPanel(panel_content, title=title, border_style=SECONDARY_LIGHT, expand=False))
1207
1402
 
1208
1403
  def _load_config(self) -> dict[str, Any]:
1404
+ """Load configuration with caching.
1405
+
1406
+ Returns:
1407
+ Configuration dictionary.
1408
+ """
1209
1409
  if self._config_cache is None:
1210
1410
  try:
1211
1411
  self._config_cache = load_config() or {}
@@ -1214,6 +1414,16 @@ class SlashSession:
1214
1414
  return self._config_cache
1215
1415
 
1216
1416
  def _resolve_agent_from_ref(self, client: Any, available_agents: list[Any], ref: str) -> Any | None:
1417
+ """Resolve an agent from a reference string.
1418
+
1419
+ Args:
1420
+ client: API client instance.
1421
+ available_agents: List of available agents.
1422
+ ref: Reference string (ID or name).
1423
+
1424
+ Returns:
1425
+ Resolved agent or None.
1426
+ """
1217
1427
  ref = ref.strip()
1218
1428
  if not ref:
1219
1429
  return None