glaip-sdk 0.0.16__py3-none-any.whl → 0.0.18__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))
@@ -194,28 +194,43 @@ def _iter_command_completions(
194
194
  prefix = text[1:]
195
195
  seen: set[str] = set()
196
196
 
197
- if (
198
- session.get_contextual_commands()
199
- and not session.should_include_global_commands()
200
- ):
197
+ # Early return for contextual commands scenario
198
+ if not _should_include_commands(session):
201
199
  return []
202
200
 
203
201
  commands = sorted(session._unique_commands.values(), key=lambda c: c.name)
204
202
 
205
203
  for cmd in commands:
206
- for alias in (cmd.name, *cmd.aliases):
207
- if alias in seen or alias.startswith("?"):
208
- continue
209
- if prefix and not alias.startswith(prefix):
210
- continue
211
- seen.add(alias)
212
- label = f"/{alias}"
213
- yield Completion(
214
- text=label,
215
- start_position=-len(text),
216
- display=label,
217
- display_meta=cmd.help,
218
- )
204
+ yield from _generate_command_completions(cmd, prefix, text, seen)
205
+
206
+
207
+ def _should_include_commands(session: SlashSession) -> bool:
208
+ """Check if commands should be included in completions."""
209
+ return not (
210
+ session.get_contextual_commands()
211
+ and not session.should_include_global_commands()
212
+ )
213
+
214
+
215
+ def _generate_command_completions(
216
+ cmd: Any, prefix: str, text: str, seen: set[str]
217
+ ) -> Iterable[Completion]:
218
+ """Generate completion items for a single command."""
219
+ for alias in (cmd.name, *cmd.aliases):
220
+ if alias in seen or alias.startswith("?"):
221
+ continue
222
+
223
+ if prefix and not alias.startswith(prefix):
224
+ continue
225
+
226
+ seen.add(alias)
227
+ label = f"/{alias}"
228
+ yield Completion(
229
+ text=label,
230
+ start_position=-len(text),
231
+ display=label,
232
+ display_meta=cmd.help,
233
+ )
219
234
 
220
235
 
221
236
  def _iter_contextual_completions(
@@ -297,51 +297,80 @@ class SlashSession:
297
297
  return True
298
298
 
299
299
  def _cmd_agents(self, args: list[str], _invoked_from_agent: bool) -> bool:
300
+ client = self._get_client_or_fail()
301
+ if not client:
302
+ return True
303
+
304
+ agents = self._get_agents_or_fail(client)
305
+ if not agents:
306
+ return True
307
+
308
+ picked_agent = self._resolve_or_pick_agent(client, agents, args)
309
+
310
+ if not picked_agent:
311
+ return True
312
+
313
+ return self._run_agent_session(picked_agent)
314
+
315
+ def _get_client_or_fail(self) -> Any:
316
+ """Get client or handle failure and return None."""
300
317
  try:
301
- client = self._get_client()
318
+ return self._get_client()
302
319
  except click.ClickException as exc:
303
320
  self.console.print(f"[red]{exc}[/red]")
304
- return True
321
+ return None
305
322
 
323
+ def _get_agents_or_fail(self, client: Any) -> list:
324
+ """Get agents list or handle failure and return empty list."""
306
325
  try:
307
326
  agents = client.list_agents()
327
+ if not agents:
328
+ self._handle_no_agents()
329
+ return agents
308
330
  except Exception as exc: # pragma: no cover - API failures
309
331
  self.console.print(f"[red]Failed to load agents: {exc}[/red]")
310
- return True
332
+ return []
311
333
 
312
- if not agents:
313
- hint = command_hint("agents create", slash_command=None, ctx=self.ctx)
314
- if hint:
315
- self.console.print(
316
- f"[yellow]No agents available. Use `{hint}` to add one.[/yellow]"
317
- )
318
- else:
319
- self.console.print("[yellow]No agents available.[/yellow]")
320
- return True
334
+ def _handle_no_agents(self) -> None:
335
+ """Handle case when no agents are available."""
336
+ hint = command_hint("agents create", slash_command=None, ctx=self.ctx)
337
+ if hint:
338
+ self.console.print(
339
+ f"[yellow]No agents available. Use `{hint}` to add one.[/yellow]"
340
+ )
341
+ else:
342
+ self.console.print("[yellow]No agents available.[/yellow]")
321
343
 
344
+ def _resolve_or_pick_agent(self, client: Any, agents: list, args: list[str]) -> Any:
345
+ """Resolve agent from args or pick interactively."""
322
346
  if args:
323
347
  picked_agent = self._resolve_agent_from_ref(client, agents, args[0])
324
348
  if picked_agent is None:
325
349
  self.console.print(
326
350
  f"[yellow]Could not resolve agent '{args[0]}'. Try `/agents` to browse interactively.[/yellow]"
327
351
  )
328
- return True
352
+ return None
329
353
  else:
330
354
  picked_agent = _fuzzy_pick_for_resources(agents, "agent", "")
331
355
 
332
- if not picked_agent:
333
- return True
356
+ return picked_agent
334
357
 
358
+ def _run_agent_session(self, picked_agent: Any) -> bool:
359
+ """Run agent session and show follow-up actions."""
335
360
  self._remember_agent(picked_agent)
336
-
337
361
  AgentRunSession(self, picked_agent).run()
338
362
 
339
- # Refresh the main palette header and surface follow-up actions so the
340
- # user has immediate cues after leaving the agent context.
363
+ # Refresh the main palette header and surface follow-up actions
341
364
  self._render_header()
342
365
 
366
+ self._show_agent_followup_actions(picked_agent)
367
+ return True
368
+
369
+ def _show_agent_followup_actions(self, picked_agent: Any) -> None:
370
+ """Show follow-up action hints after agent session."""
343
371
  agent_id = str(getattr(picked_agent, "id", ""))
344
372
  agent_label = getattr(picked_agent, "name", "") or agent_id or "this agent"
373
+
345
374
  hints: list[tuple[str, str]] = []
346
375
  if agent_id:
347
376
  hints.append((f"/agents {agent_id}", f"Reopen {agent_label}"))
@@ -351,8 +380,8 @@ class SlashSession:
351
380
  (self.STATUS_COMMAND, "Check connection"),
352
381
  ]
353
382
  )
383
+
354
384
  self._show_quick_actions(hints, title="Next actions")
355
- return True
356
385
 
357
386
  def _cmd_exit(self, _args: list[str], invoked_from_agent: bool) -> bool:
358
387
  if invoked_from_agent:
@@ -710,12 +739,12 @@ class SlashSession:
710
739
 
711
740
  if full:
712
741
  lines = [
713
- self._branding.get_welcome_banner(),
714
- "",
715
- f"[dim]API URL[/dim]: {api_url or 'Not configured'}",
716
- f"[dim]Credentials[/dim]: {status}",
717
- f"[dim]Verbose mode[/dim]: {'on' if self._verbose_enabled else 'off'}",
718
- "[dim]Tip[/dim]: Press Ctrl+T or run `/verbose` to toggle verbose streaming.",
742
+ f"GL AIP v{self._branding.version} · GDP Labs AI Agents Package",
743
+ f"API: {api_url or 'Not configured'} · Credentials: {status}",
744
+ (
745
+ f"Verbose: {'on' if self._verbose_enabled else 'off'} "
746
+ "(Ctrl+T toggles verbose streaming)"
747
+ ),
719
748
  ]
720
749
  extra: list[str] = []
721
750
  self._add_agent_info_to_header(extra, active_agent)
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
  )