glaip-sdk 0.1.2__py3-none-any.whl → 0.7.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.
Files changed (217) hide show
  1. glaip_sdk/__init__.py +44 -4
  2. glaip_sdk/_version.py +9 -0
  3. glaip_sdk/agents/__init__.py +27 -0
  4. glaip_sdk/agents/base.py +1413 -0
  5. glaip_sdk/branding.py +126 -2
  6. glaip_sdk/cli/account_store.py +555 -0
  7. glaip_sdk/cli/auth.py +260 -15
  8. glaip_sdk/cli/commands/__init__.py +2 -2
  9. glaip_sdk/cli/commands/accounts.py +746 -0
  10. glaip_sdk/cli/commands/agents/__init__.py +116 -0
  11. glaip_sdk/cli/commands/agents/_common.py +562 -0
  12. glaip_sdk/cli/commands/agents/create.py +155 -0
  13. glaip_sdk/cli/commands/agents/delete.py +64 -0
  14. glaip_sdk/cli/commands/agents/get.py +89 -0
  15. glaip_sdk/cli/commands/agents/list.py +129 -0
  16. glaip_sdk/cli/commands/agents/run.py +264 -0
  17. glaip_sdk/cli/commands/agents/sync_langflow.py +72 -0
  18. glaip_sdk/cli/commands/agents/update.py +112 -0
  19. glaip_sdk/cli/commands/common_config.py +104 -0
  20. glaip_sdk/cli/commands/configure.py +728 -113
  21. glaip_sdk/cli/commands/mcps/__init__.py +94 -0
  22. glaip_sdk/cli/commands/mcps/_common.py +459 -0
  23. glaip_sdk/cli/commands/mcps/connect.py +82 -0
  24. glaip_sdk/cli/commands/mcps/create.py +152 -0
  25. glaip_sdk/cli/commands/mcps/delete.py +73 -0
  26. glaip_sdk/cli/commands/mcps/get.py +212 -0
  27. glaip_sdk/cli/commands/mcps/list.py +69 -0
  28. glaip_sdk/cli/commands/mcps/tools.py +235 -0
  29. glaip_sdk/cli/commands/mcps/update.py +190 -0
  30. glaip_sdk/cli/commands/models.py +12 -8
  31. glaip_sdk/cli/commands/shared/__init__.py +21 -0
  32. glaip_sdk/cli/commands/shared/formatters.py +91 -0
  33. glaip_sdk/cli/commands/tools/__init__.py +69 -0
  34. glaip_sdk/cli/commands/tools/_common.py +80 -0
  35. glaip_sdk/cli/commands/tools/create.py +228 -0
  36. glaip_sdk/cli/commands/tools/delete.py +61 -0
  37. glaip_sdk/cli/commands/tools/get.py +103 -0
  38. glaip_sdk/cli/commands/tools/list.py +69 -0
  39. glaip_sdk/cli/commands/tools/script.py +49 -0
  40. glaip_sdk/cli/commands/tools/update.py +102 -0
  41. glaip_sdk/cli/commands/transcripts/__init__.py +90 -0
  42. glaip_sdk/cli/commands/transcripts/_common.py +9 -0
  43. glaip_sdk/cli/commands/transcripts/clear.py +5 -0
  44. glaip_sdk/cli/commands/transcripts/detail.py +5 -0
  45. glaip_sdk/cli/commands/transcripts_original.py +756 -0
  46. glaip_sdk/cli/commands/update.py +163 -17
  47. glaip_sdk/cli/config.py +49 -4
  48. glaip_sdk/cli/constants.py +38 -0
  49. glaip_sdk/cli/context.py +8 -0
  50. glaip_sdk/cli/core/__init__.py +79 -0
  51. glaip_sdk/cli/core/context.py +124 -0
  52. glaip_sdk/cli/core/output.py +851 -0
  53. glaip_sdk/cli/core/prompting.py +649 -0
  54. glaip_sdk/cli/core/rendering.py +187 -0
  55. glaip_sdk/cli/display.py +41 -20
  56. glaip_sdk/cli/entrypoint.py +20 -0
  57. glaip_sdk/cli/hints.py +57 -0
  58. glaip_sdk/cli/io.py +6 -3
  59. glaip_sdk/cli/main.py +340 -143
  60. glaip_sdk/cli/masking.py +21 -33
  61. glaip_sdk/cli/pager.py +12 -13
  62. glaip_sdk/cli/parsers/__init__.py +1 -3
  63. glaip_sdk/cli/resolution.py +2 -1
  64. glaip_sdk/cli/slash/__init__.py +0 -9
  65. glaip_sdk/cli/slash/accounts_controller.py +580 -0
  66. glaip_sdk/cli/slash/accounts_shared.py +75 -0
  67. glaip_sdk/cli/slash/agent_session.py +62 -21
  68. glaip_sdk/cli/slash/prompt.py +21 -0
  69. glaip_sdk/cli/slash/remote_runs_controller.py +568 -0
  70. glaip_sdk/cli/slash/session.py +1105 -153
  71. glaip_sdk/cli/slash/tui/__init__.py +36 -0
  72. glaip_sdk/cli/slash/tui/accounts.tcss +177 -0
  73. glaip_sdk/cli/slash/tui/accounts_app.py +1853 -0
  74. glaip_sdk/cli/slash/tui/background_tasks.py +72 -0
  75. glaip_sdk/cli/slash/tui/clipboard.py +195 -0
  76. glaip_sdk/cli/slash/tui/context.py +92 -0
  77. glaip_sdk/cli/slash/tui/indicators.py +341 -0
  78. glaip_sdk/cli/slash/tui/keybind_registry.py +235 -0
  79. glaip_sdk/cli/slash/tui/layouts/__init__.py +14 -0
  80. glaip_sdk/cli/slash/tui/layouts/harlequin.py +184 -0
  81. glaip_sdk/cli/slash/tui/loading.py +80 -0
  82. glaip_sdk/cli/slash/tui/remote_runs_app.py +760 -0
  83. glaip_sdk/cli/slash/tui/terminal.py +407 -0
  84. glaip_sdk/cli/slash/tui/theme/__init__.py +15 -0
  85. glaip_sdk/cli/slash/tui/theme/catalog.py +79 -0
  86. glaip_sdk/cli/slash/tui/theme/manager.py +112 -0
  87. glaip_sdk/cli/slash/tui/theme/tokens.py +55 -0
  88. glaip_sdk/cli/slash/tui/toast.py +388 -0
  89. glaip_sdk/cli/transcript/__init__.py +12 -52
  90. glaip_sdk/cli/transcript/cache.py +255 -44
  91. glaip_sdk/cli/transcript/capture.py +66 -1
  92. glaip_sdk/cli/transcript/history.py +815 -0
  93. glaip_sdk/cli/transcript/viewer.py +72 -463
  94. glaip_sdk/cli/tui_settings.py +125 -0
  95. glaip_sdk/cli/update_notifier.py +227 -10
  96. glaip_sdk/cli/validators.py +5 -6
  97. glaip_sdk/client/__init__.py +3 -1
  98. glaip_sdk/client/_schedule_payloads.py +89 -0
  99. glaip_sdk/client/agent_runs.py +147 -0
  100. glaip_sdk/client/agents.py +576 -44
  101. glaip_sdk/client/base.py +26 -0
  102. glaip_sdk/client/hitl.py +136 -0
  103. glaip_sdk/client/main.py +25 -14
  104. glaip_sdk/client/mcps.py +165 -24
  105. glaip_sdk/client/payloads/agent/__init__.py +23 -0
  106. glaip_sdk/client/{_agent_payloads.py → payloads/agent/requests.py} +63 -47
  107. glaip_sdk/client/payloads/agent/responses.py +43 -0
  108. glaip_sdk/client/run_rendering.py +546 -92
  109. glaip_sdk/client/schedules.py +439 -0
  110. glaip_sdk/client/shared.py +21 -0
  111. glaip_sdk/client/tools.py +206 -32
  112. glaip_sdk/config/constants.py +33 -2
  113. glaip_sdk/guardrails/__init__.py +80 -0
  114. glaip_sdk/guardrails/serializer.py +89 -0
  115. glaip_sdk/hitl/__init__.py +48 -0
  116. glaip_sdk/hitl/base.py +64 -0
  117. glaip_sdk/hitl/callback.py +43 -0
  118. glaip_sdk/hitl/local.py +121 -0
  119. glaip_sdk/hitl/remote.py +523 -0
  120. glaip_sdk/mcps/__init__.py +21 -0
  121. glaip_sdk/mcps/base.py +345 -0
  122. glaip_sdk/models/__init__.py +136 -0
  123. glaip_sdk/models/_provider_mappings.py +101 -0
  124. glaip_sdk/models/_validation.py +97 -0
  125. glaip_sdk/models/agent.py +48 -0
  126. glaip_sdk/models/agent_runs.py +117 -0
  127. glaip_sdk/models/common.py +42 -0
  128. glaip_sdk/models/constants.py +141 -0
  129. glaip_sdk/models/mcp.py +33 -0
  130. glaip_sdk/models/model.py +170 -0
  131. glaip_sdk/models/schedule.py +224 -0
  132. glaip_sdk/models/tool.py +33 -0
  133. glaip_sdk/payload_schemas/__init__.py +1 -13
  134. glaip_sdk/payload_schemas/agent.py +1 -0
  135. glaip_sdk/payload_schemas/guardrails.py +34 -0
  136. glaip_sdk/registry/__init__.py +55 -0
  137. glaip_sdk/registry/agent.py +164 -0
  138. glaip_sdk/registry/base.py +139 -0
  139. glaip_sdk/registry/mcp.py +253 -0
  140. glaip_sdk/registry/tool.py +445 -0
  141. glaip_sdk/rich_components.py +58 -2
  142. glaip_sdk/runner/__init__.py +76 -0
  143. glaip_sdk/runner/base.py +84 -0
  144. glaip_sdk/runner/deps.py +115 -0
  145. glaip_sdk/runner/langgraph.py +1055 -0
  146. glaip_sdk/runner/logging_config.py +77 -0
  147. glaip_sdk/runner/mcp_adapter/__init__.py +13 -0
  148. glaip_sdk/runner/mcp_adapter/base_mcp_adapter.py +43 -0
  149. glaip_sdk/runner/mcp_adapter/langchain_mcp_adapter.py +257 -0
  150. glaip_sdk/runner/mcp_adapter/mcp_config_builder.py +116 -0
  151. glaip_sdk/runner/tool_adapter/__init__.py +18 -0
  152. glaip_sdk/runner/tool_adapter/base_tool_adapter.py +44 -0
  153. glaip_sdk/runner/tool_adapter/langchain_tool_adapter.py +242 -0
  154. glaip_sdk/schedules/__init__.py +22 -0
  155. glaip_sdk/schedules/base.py +291 -0
  156. glaip_sdk/tools/__init__.py +22 -0
  157. glaip_sdk/tools/base.py +488 -0
  158. glaip_sdk/utils/__init__.py +59 -12
  159. glaip_sdk/utils/a2a/__init__.py +34 -0
  160. glaip_sdk/utils/a2a/event_processor.py +188 -0
  161. glaip_sdk/utils/agent_config.py +8 -2
  162. glaip_sdk/utils/bundler.py +403 -0
  163. glaip_sdk/utils/client.py +111 -0
  164. glaip_sdk/utils/client_utils.py +39 -7
  165. glaip_sdk/utils/datetime_helpers.py +58 -0
  166. glaip_sdk/utils/discovery.py +78 -0
  167. glaip_sdk/utils/display.py +23 -15
  168. glaip_sdk/utils/export.py +143 -0
  169. glaip_sdk/utils/general.py +0 -33
  170. glaip_sdk/utils/import_export.py +12 -7
  171. glaip_sdk/utils/import_resolver.py +524 -0
  172. glaip_sdk/utils/instructions.py +101 -0
  173. glaip_sdk/utils/rendering/__init__.py +115 -1
  174. glaip_sdk/utils/rendering/formatting.py +5 -30
  175. glaip_sdk/utils/rendering/layout/__init__.py +64 -0
  176. glaip_sdk/utils/rendering/{renderer → layout}/panels.py +9 -0
  177. glaip_sdk/utils/rendering/{renderer → layout}/progress.py +70 -1
  178. glaip_sdk/utils/rendering/layout/summary.py +74 -0
  179. glaip_sdk/utils/rendering/layout/transcript.py +606 -0
  180. glaip_sdk/utils/rendering/models.py +1 -0
  181. glaip_sdk/utils/rendering/renderer/__init__.py +9 -47
  182. glaip_sdk/utils/rendering/renderer/base.py +299 -1434
  183. glaip_sdk/utils/rendering/renderer/config.py +1 -5
  184. glaip_sdk/utils/rendering/renderer/debug.py +26 -20
  185. glaip_sdk/utils/rendering/renderer/factory.py +138 -0
  186. glaip_sdk/utils/rendering/renderer/stream.py +4 -33
  187. glaip_sdk/utils/rendering/renderer/summary_window.py +79 -0
  188. glaip_sdk/utils/rendering/renderer/thinking.py +273 -0
  189. glaip_sdk/utils/rendering/renderer/tool_panels.py +442 -0
  190. glaip_sdk/utils/rendering/renderer/transcript_mode.py +162 -0
  191. glaip_sdk/utils/rendering/state.py +204 -0
  192. glaip_sdk/utils/rendering/steps/__init__.py +34 -0
  193. glaip_sdk/utils/rendering/{steps.py → steps/event_processor.py} +53 -440
  194. glaip_sdk/utils/rendering/steps/format.py +176 -0
  195. glaip_sdk/utils/rendering/steps/manager.py +387 -0
  196. glaip_sdk/utils/rendering/timing.py +36 -0
  197. glaip_sdk/utils/rendering/viewer/__init__.py +21 -0
  198. glaip_sdk/utils/rendering/viewer/presenter.py +184 -0
  199. glaip_sdk/utils/resource_refs.py +25 -13
  200. glaip_sdk/utils/runtime_config.py +426 -0
  201. glaip_sdk/utils/serialization.py +18 -0
  202. glaip_sdk/utils/sync.py +162 -0
  203. glaip_sdk/utils/tool_detection.py +301 -0
  204. glaip_sdk/utils/tool_storage_provider.py +140 -0
  205. glaip_sdk/utils/validation.py +16 -24
  206. {glaip_sdk-0.1.2.dist-info → glaip_sdk-0.7.17.dist-info}/METADATA +69 -23
  207. glaip_sdk-0.7.17.dist-info/RECORD +224 -0
  208. {glaip_sdk-0.1.2.dist-info → glaip_sdk-0.7.17.dist-info}/WHEEL +2 -1
  209. glaip_sdk-0.7.17.dist-info/entry_points.txt +2 -0
  210. glaip_sdk-0.7.17.dist-info/top_level.txt +1 -0
  211. glaip_sdk/cli/commands/agents.py +0 -1369
  212. glaip_sdk/cli/commands/mcps.py +0 -1187
  213. glaip_sdk/cli/commands/tools.py +0 -584
  214. glaip_sdk/cli/utils.py +0 -1278
  215. glaip_sdk/models.py +0 -240
  216. glaip_sdk-0.1.2.dist-info/RECORD +0 -82
  217. glaip_sdk-0.1.2.dist-info/entry_points.txt +0 -3
@@ -0,0 +1,155 @@
1
+ """Create agent command.
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
+ import click
12
+
13
+ from glaip_sdk.cli.context import output_flags
14
+ from glaip_sdk.cli.core.context import get_client
15
+ from glaip_sdk.cli.display import (
16
+ display_agent_run_suggestions,
17
+ display_creation_success,
18
+ handle_json_output,
19
+ handle_rich_output,
20
+ )
21
+ from glaip_sdk.cli.validators import (
22
+ validate_agent_instruction_cli as validate_agent_instruction,
23
+ )
24
+ from glaip_sdk.cli.validators import validate_agent_name_cli as validate_agent_name
25
+ from glaip_sdk.cli.validators import validate_timeout_cli as validate_timeout
26
+ from glaip_sdk.config.constants import DEFAULT_AGENT_RUN_TIMEOUT
27
+ from glaip_sdk.utils.validation import coerce_timeout
28
+
29
+ from ._common import (
30
+ _get_language_model_display_name,
31
+ _handle_command_exception,
32
+ _prepare_agent_output,
33
+ _resolve_resources_by_name,
34
+ _split_comma_separated_refs,
35
+ agents_group,
36
+ )
37
+
38
+
39
+ def _handle_successful_creation(ctx: Any, agent: Any, model: str | None) -> None:
40
+ """Handle successful agent creation output."""
41
+ handle_json_output(ctx, _prepare_agent_output(agent))
42
+
43
+ lm_display = _get_language_model_display_name(agent, model)
44
+
45
+ handle_rich_output(
46
+ ctx,
47
+ display_creation_success(
48
+ "Agent",
49
+ agent.name,
50
+ agent.id,
51
+ Model=lm_display,
52
+ Type=getattr(agent, "type", "config"),
53
+ Framework=getattr(agent, "framework", "langchain"),
54
+ Version=getattr(agent, "version", "1.0"),
55
+ ),
56
+ )
57
+ handle_rich_output(ctx, display_agent_run_suggestions(agent))
58
+
59
+
60
+ def _handle_creation_exception(ctx: Any, e: Exception) -> None:
61
+ """Handle exceptions during agent creation."""
62
+ _handle_command_exception(ctx, e)
63
+
64
+
65
+ @agents_group.command()
66
+ @click.option("--name", help="Agent name")
67
+ @click.option("--instruction", help="Agent instruction (prompt)")
68
+ @click.option(
69
+ "--model",
70
+ help=(
71
+ "Language model in 'provider/model' format "
72
+ "(e.g., openai/gpt-4o-mini, bedrock/us.anthropic.claude-sonnet-4-20250514-v1:0). "
73
+ "Use 'aip models list' to see available models."
74
+ ),
75
+ )
76
+ @click.option("--tools", multiple=True, help="Tool names or IDs to attach")
77
+ @click.option("--agents", multiple=True, help="Sub-agent names or IDs to attach")
78
+ @click.option("--mcps", multiple=True, help="MCP names or IDs to attach")
79
+ @click.option(
80
+ "--timeout",
81
+ default=DEFAULT_AGENT_RUN_TIMEOUT,
82
+ type=int,
83
+ help="Agent execution timeout in seconds (default: 300s)",
84
+ )
85
+ @click.option(
86
+ "--import",
87
+ "import_file",
88
+ type=click.Path(exists=True, dir_okay=False),
89
+ help="Import agent configuration from JSON file",
90
+ )
91
+ @output_flags()
92
+ @click.pass_context
93
+ def create(
94
+ ctx: Any,
95
+ name: str,
96
+ instruction: str,
97
+ model: str | None,
98
+ tools: tuple[str, ...] | None,
99
+ agents: tuple[str, ...] | None,
100
+ mcps: tuple[str, ...] | None,
101
+ timeout: float | None,
102
+ import_file: str | None,
103
+ ) -> None:
104
+ r"""Create a new agent.
105
+
106
+ \b
107
+ Examples:
108
+ aip agents create --name "My Agent" --instruction "You are a helpful assistant"
109
+ aip agents create --import agent.json
110
+ """
111
+ try:
112
+ client = get_client(ctx)
113
+
114
+ if import_file is None:
115
+ if not name:
116
+ raise click.ClickException("Agent name is required (--name or --import)")
117
+ if not instruction:
118
+ raise click.ClickException("Agent instruction is required (--instruction or --import)")
119
+
120
+ if name is not None:
121
+ name = validate_agent_name(name)
122
+ if instruction is not None:
123
+ instruction = validate_agent_instruction(instruction)
124
+
125
+ timeout_value = coerce_timeout(timeout)
126
+ if timeout_value is not None:
127
+ timeout_value = validate_timeout(timeout_value)
128
+ if import_file is None and timeout_value == DEFAULT_AGENT_RUN_TIMEOUT:
129
+ timeout_value = None
130
+
131
+ tools = _split_comma_separated_refs(tools)
132
+ agents = _split_comma_separated_refs(agents)
133
+ mcps = _split_comma_separated_refs(mcps)
134
+
135
+ # Resolve resources
136
+ resolved_tools = _resolve_resources_by_name(client, tools, "tool", client.find_tools, "Tool")
137
+ resolved_agents = _resolve_resources_by_name(client, agents, "agent", client.find_agents, "Agent")
138
+ resolved_mcps = _resolve_resources_by_name(client, mcps, "mcp", client.find_mcps, "MCP")
139
+
140
+ agent = client.agents.create_agent(
141
+ file=import_file,
142
+ name=name,
143
+ instruction=instruction,
144
+ model=model,
145
+ tools=resolved_tools or None,
146
+ agents=resolved_agents or None,
147
+ mcps=resolved_mcps or None,
148
+ timeout=timeout_value,
149
+ )
150
+
151
+ # Handle successful creation
152
+ _handle_successful_creation(ctx, agent, model)
153
+
154
+ except Exception as e:
155
+ _handle_creation_exception(ctx, e)
@@ -0,0 +1,64 @@
1
+ """Delete agent command.
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
+ import click
12
+
13
+ from glaip_sdk.cli.context import output_flags
14
+ from glaip_sdk.cli.display import (
15
+ display_confirmation_prompt,
16
+ display_deletion_success,
17
+ handle_json_output,
18
+ handle_rich_output,
19
+ )
20
+ from glaip_sdk.cli.core.context import get_client
21
+
22
+ from ._common import (
23
+ _handle_click_exception_for_json,
24
+ _handle_command_exception,
25
+ agents_group,
26
+ )
27
+
28
+
29
+ @agents_group.command()
30
+ @click.argument("agent_id")
31
+ @click.option("-y", "--yes", is_flag=True, help="Skip confirmation")
32
+ @output_flags()
33
+ @click.pass_context
34
+ def delete(ctx: Any, agent_id: str, yes: bool) -> None:
35
+ """Delete an agent."""
36
+ try:
37
+ client = get_client(ctx)
38
+
39
+ # Get agent by ID (no ambiguity handling needed)
40
+ try:
41
+ agent = client.agents.get_agent_by_id(agent_id)
42
+ except Exception as e:
43
+ raise click.ClickException(f"Agent with ID '{agent_id}' not found: {e}") from e
44
+
45
+ # Confirm deletion when not forced
46
+ if not yes:
47
+ if not display_confirmation_prompt("Agent", agent.name):
48
+ return
49
+
50
+ client.agents.delete_agent(agent.id)
51
+
52
+ handle_json_output(
53
+ ctx,
54
+ {
55
+ "success": True,
56
+ "message": f"Agent '{agent.name}' deleted",
57
+ },
58
+ )
59
+ handle_rich_output(ctx, display_deletion_success("Agent", agent.name))
60
+
61
+ except click.ClickException as e:
62
+ _handle_click_exception_for_json(ctx, e)
63
+ except Exception as e:
64
+ _handle_command_exception(ctx, e)
@@ -0,0 +1,89 @@
1
+ """Get agent command.
2
+
3
+ Authors:
4
+ Raymond Christopher (raymond.christopher@gdplabs.id)
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ from pathlib import Path
10
+ from typing import Any
11
+
12
+ import click
13
+
14
+ from glaip_sdk.cli.context import output_flags
15
+ from glaip_sdk.cli.display import display_agent_run_suggestions, handle_rich_output
16
+ from glaip_sdk.cli.core.context import get_client
17
+ from glaip_sdk.cli.core.output import handle_resource_export
18
+
19
+ from ._common import _display_agent_details, _resolve_agent, agents_group, console
20
+
21
+
22
+ @agents_group.command()
23
+ @click.argument("agent_ref")
24
+ @click.option("--select", type=int, help="Choose among ambiguous matches (1-based)")
25
+ @click.option(
26
+ "--export",
27
+ type=click.Path(dir_okay=False, writable=True),
28
+ help="Export complete agent configuration to file (format auto-detected from .json/.yaml extension)",
29
+ )
30
+ @click.option(
31
+ "--instruction-preview",
32
+ type=int,
33
+ default=0,
34
+ show_default=True,
35
+ help="Instruction preview length when printing instructions (0 shows full prompt).",
36
+ )
37
+ @output_flags()
38
+ @click.pass_context
39
+ def get(
40
+ ctx: Any,
41
+ agent_ref: str,
42
+ select: int | None,
43
+ export: str | None,
44
+ instruction_preview: int,
45
+ ) -> None:
46
+ r"""Get agent details.
47
+
48
+ \b
49
+ Examples:
50
+ aip agents get my-agent
51
+ aip agents get my-agent --export agent.json # Exports complete configuration as JSON
52
+ aip agents get my-agent --export agent.yaml # Exports complete configuration as YAML
53
+ """
54
+ try:
55
+ # Initialize API client for agent retrieval
56
+ api_client = get_client(ctx)
57
+
58
+ # Resolve agent reference using questionary interface for better UX
59
+ agent = _resolve_agent(ctx, api_client, agent_ref, select, interface_preference="questionary")
60
+
61
+ if not agent:
62
+ raise click.ClickException(f"Agent '{agent_ref}' not found")
63
+
64
+ # Handle export option if requested
65
+ if export:
66
+ handle_resource_export(
67
+ ctx,
68
+ agent,
69
+ Path(export),
70
+ resource_type="agent",
71
+ get_by_id_func=api_client.agents.get_agent_by_id,
72
+ console_override=console,
73
+ )
74
+
75
+ # Display full agent details using the standardized helper
76
+ _display_agent_details(
77
+ ctx,
78
+ api_client,
79
+ agent,
80
+ instruction_preview_limit=instruction_preview,
81
+ )
82
+
83
+ # Show run suggestions via centralized display helper
84
+ handle_rich_output(ctx, display_agent_run_suggestions(agent))
85
+
86
+ except click.ClickException:
87
+ raise
88
+ except Exception as e:
89
+ raise click.ClickException(str(e)) from e
@@ -0,0 +1,129 @@
1
+ """List agents command.
2
+
3
+ Authors:
4
+ Raymond Christopher (raymond.christopher@gdplabs.id)
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import os
10
+ from typing import Any
11
+
12
+ import click
13
+
14
+ from glaip_sdk.branding import ACCENT_STYLE, INFO, SUCCESS, WARNING_STYLE
15
+ from glaip_sdk.cli.context import output_flags
16
+ from glaip_sdk.cli.display import display_agent_run_suggestions, handle_rich_output
17
+ from glaip_sdk.cli.core.output import coerce_to_row, output_list
18
+ from glaip_sdk.cli.core.prompting import _fuzzy_pick_for_resources
19
+ from glaip_sdk.cli.core.rendering import with_client_and_spinner
20
+ from glaip_sdk.icons import ICON_AGENT
21
+
22
+ from ._common import _display_agent_details, agents_group, console
23
+
24
+
25
+ @agents_group.command(name="list")
26
+ @click.option("--simple", is_flag=True, help="Show simple table without interactive picker")
27
+ @click.option("--type", "agent_type", help="Filter by agent type (config, code, a2a, langflow)")
28
+ @click.option("--framework", help="Filter by framework (langchain, langgraph, google_adk)")
29
+ @click.option("--name", help="Filter by partial name match (case-insensitive)")
30
+ @click.option("--version", help="Filter by exact version match")
31
+ @click.option(
32
+ "--sync-langflow",
33
+ is_flag=True,
34
+ help="Sync with LangFlow server before listing (only applies when filtering by langflow type)",
35
+ )
36
+ @output_flags()
37
+ @click.pass_context
38
+ def list_agents(
39
+ ctx: Any,
40
+ simple: bool,
41
+ agent_type: str | None,
42
+ framework: str | None,
43
+ name: str | None,
44
+ version: str | None,
45
+ sync_langflow: bool,
46
+ ) -> None:
47
+ """List agents with optional filtering."""
48
+ try:
49
+ with with_client_and_spinner(
50
+ ctx,
51
+ "[bold blue]Fetching agents…[/bold blue]",
52
+ console_override=console,
53
+ ) as client:
54
+ # Query agents with specified filters
55
+ filter_params = {
56
+ "agent_type": agent_type,
57
+ "framework": framework,
58
+ "name": name,
59
+ "version": version,
60
+ "sync_langflow_agents": sync_langflow,
61
+ }
62
+ agents = client.agents.list_agents(**filter_params)
63
+
64
+ # Define table columns: (data_key, header, style, width)
65
+ columns = [
66
+ ("id", "ID", "dim", 36),
67
+ ("name", "Name", ACCENT_STYLE, None),
68
+ ("type", "Type", WARNING_STYLE, None),
69
+ ("framework", "Framework", INFO, None),
70
+ ("version", "Version", SUCCESS, None),
71
+ ]
72
+
73
+ # Transform function for safe attribute access
74
+ def transform_agent(agent: Any) -> dict[str, Any]:
75
+ """Transform an agent object to a display row dictionary.
76
+
77
+ Args:
78
+ agent: Agent object to transform.
79
+
80
+ Returns:
81
+ Dictionary with id, name, type, framework, and version fields.
82
+ """
83
+ row = coerce_to_row(agent, ["id", "name", "type", "framework", "version"])
84
+ # Ensure id is always a string
85
+ row["id"] = str(row["id"])
86
+ return row
87
+
88
+ # Use fuzzy picker for interactive agent selection and details (default behavior)
89
+ # Skip if --simple flag is used, a name filter is applied, or non-rich output is requested
90
+ ctx_obj = ctx.obj if isinstance(getattr(ctx, "obj", None), dict) else {}
91
+ current_view = ctx_obj.get("view")
92
+ interactive_enabled = (
93
+ not simple
94
+ and name is None
95
+ and current_view not in {"json", "plain", "md"}
96
+ and console.is_terminal
97
+ and os.isatty(1)
98
+ and len(agents) > 0
99
+ )
100
+
101
+ # Track picker attempt so the fallback table doesn't re-open the palette
102
+ picker_attempted = False
103
+ if interactive_enabled:
104
+ picker_attempted = True
105
+ picked_agent = _fuzzy_pick_for_resources(agents, "agent", "")
106
+ if picked_agent:
107
+ _display_agent_details(ctx, client, picked_agent)
108
+ # Show run suggestions via centralized display helper
109
+ handle_rich_output(ctx, display_agent_run_suggestions(picked_agent))
110
+ return
111
+
112
+ # Show simple table (either --simple flag or non-interactive)
113
+ output_list(
114
+ ctx,
115
+ agents,
116
+ f"{ICON_AGENT} Available Agents",
117
+ columns,
118
+ transform_agent,
119
+ skip_picker=(
120
+ not interactive_enabled
121
+ or picker_attempted
122
+ or simple
123
+ or any(param is not None for param in (agent_type, framework, name, version))
124
+ ),
125
+ use_pager=False,
126
+ )
127
+
128
+ except Exception as e:
129
+ raise click.ClickException(str(e)) from e
@@ -0,0 +1,264 @@
1
+ """Run agent command.
2
+
3
+ Authors:
4
+ Raymond Christopher (raymond.christopher@gdplabs.id)
5
+ """
6
+
7
+ from __future__ import annotations
8
+
9
+ import json
10
+ from typing import Any
11
+
12
+ import click
13
+
14
+ from glaip_sdk.cli.context import get_ctx_value, output_flags
15
+ from glaip_sdk.cli.display import handle_json_output
16
+ from glaip_sdk.cli.core.context import get_client
17
+ from glaip_sdk.cli.core.rendering import build_renderer
18
+ from glaip_sdk.cli.transcript import maybe_launch_post_run_viewer, store_transcript_for_session
19
+ from glaip_sdk.cli.rich_helpers import print_markup
20
+ from glaip_sdk.config.constants import DEFAULT_AGENT_RUN_TIMEOUT
21
+ from glaip_sdk.exceptions import AgentTimeoutError
22
+ from glaip_sdk.utils.rendering.renderer.toggle import TranscriptToggleController
23
+
24
+ from ._common import (
25
+ _emit_verbose_guidance,
26
+ _get_agent_model_name,
27
+ _handle_command_exception,
28
+ _resolve_agent,
29
+ _running_in_slash_mode,
30
+ _safe_agent_attribute,
31
+ agents_group,
32
+ console,
33
+ )
34
+
35
+ from glaip_sdk.branding import SUCCESS_STYLE
36
+
37
+
38
+ def _validate_run_input(input_option: str | None, input_text: str | None) -> str:
39
+ """Validate and determine the final input text for agent run."""
40
+ final_input_text = input_option if input_option else input_text
41
+
42
+ if not final_input_text:
43
+ raise click.ClickException("Input text is required. Use either positional argument or --input option.")
44
+
45
+ return final_input_text
46
+
47
+
48
+ def _parse_chat_history(chat_history: str | None) -> list[dict[str, Any]] | None:
49
+ """Parse chat history JSON if provided."""
50
+ if not chat_history:
51
+ return None
52
+
53
+ try:
54
+ return json.loads(chat_history)
55
+ except json.JSONDecodeError as err:
56
+ raise click.ClickException("Invalid JSON in chat history") from err
57
+
58
+
59
+ def _setup_run_renderer(ctx: Any, save: str | None, verbose: bool) -> Any:
60
+ """Set up renderer and working console for agent run."""
61
+ tty_enabled = bool(get_ctx_value(ctx, "tty", True))
62
+ return build_renderer(
63
+ ctx,
64
+ save_path=save,
65
+ verbose=verbose,
66
+ _tty_enabled=tty_enabled,
67
+ )
68
+
69
+
70
+ def _maybe_attach_transcript_toggle(ctx: Any, renderer: Any) -> None:
71
+ """Attach transcript toggle controller when interactive TTY is available."""
72
+ if renderer is None:
73
+ return
74
+
75
+ console_obj = getattr(renderer, "console", None)
76
+ if console_obj is None or not getattr(console_obj, "is_terminal", False):
77
+ return
78
+
79
+ tty_enabled = bool(get_ctx_value(ctx, "tty", True))
80
+ if not tty_enabled:
81
+ return
82
+
83
+ controller = TranscriptToggleController(enabled=True)
84
+ renderer.transcript_controller = controller
85
+
86
+
87
+ def _prepare_run_kwargs(
88
+ agent: Any,
89
+ final_input_text: str,
90
+ files: list[str] | None,
91
+ parsed_chat_history: list[dict[str, Any]] | None,
92
+ renderer: Any,
93
+ tty_enabled: bool,
94
+ ) -> dict[str, Any]:
95
+ """Prepare kwargs for agent run."""
96
+ run_kwargs = {
97
+ "agent_id": agent.id,
98
+ "message": final_input_text,
99
+ "files": list(files),
100
+ "agent_name": agent.name,
101
+ "tty": tty_enabled,
102
+ }
103
+
104
+ if parsed_chat_history:
105
+ run_kwargs["chat_history"] = parsed_chat_history
106
+
107
+ if renderer is not None:
108
+ run_kwargs["renderer"] = renderer
109
+
110
+ return run_kwargs
111
+
112
+
113
+ def _handle_run_output(ctx: Any, result: Any, renderer: Any) -> None:
114
+ """Handle output formatting for agent run results."""
115
+ printed_by_renderer = bool(renderer)
116
+ selected_view = get_ctx_value(ctx, "view", "rich")
117
+
118
+ if not printed_by_renderer:
119
+ if selected_view == "json":
120
+ handle_json_output(ctx, {"output": result})
121
+ elif selected_view == "md":
122
+ click.echo(f"# Assistant\n\n{result}")
123
+ elif selected_view == "plain":
124
+ click.echo(result)
125
+
126
+
127
+ def _save_run_transcript(save: str | None, result: Any, working_console: Any) -> None:
128
+ """Save transcript to file if requested."""
129
+ if not save:
130
+ return
131
+
132
+ ext = (save.rsplit(".", 1)[-1] or "").lower()
133
+ if ext == "json":
134
+ save_data = {
135
+ "output": result or "",
136
+ "full_debug_output": getattr(working_console, "get_captured_output", lambda: "")(),
137
+ "timestamp": "captured during agent execution",
138
+ }
139
+ content = json.dumps(save_data, indent=2)
140
+ else:
141
+ full_output = getattr(working_console, "get_captured_output", lambda: "")()
142
+ if full_output:
143
+ content = f"# Agent Debug Log\n\n{full_output}\n\n---\n\n## Final Result\n\n{result or ''}\n"
144
+ else:
145
+ content = f"# Assistant\n\n{result or ''}\n"
146
+
147
+ with open(save, "w", encoding="utf-8") as f:
148
+ f.write(content)
149
+ print_markup(f"[{SUCCESS_STYLE}]Full debug output saved to: {save}[/]", console=console)
150
+
151
+
152
+ @agents_group.command()
153
+ @click.argument("agent_ref")
154
+ @click.argument("input_text", required=False)
155
+ @click.option("--select", type=int, help="Choose among ambiguous matches (1-based)")
156
+ @click.option("--input", "input_option", help="Input text for the agent")
157
+ @click.option("--chat-history", help="JSON string of chat history")
158
+ @click.option(
159
+ "--timeout",
160
+ default=DEFAULT_AGENT_RUN_TIMEOUT,
161
+ type=int,
162
+ help="Agent execution timeout in seconds (default: 300s)",
163
+ )
164
+ @click.option(
165
+ "--save",
166
+ type=click.Path(dir_okay=False, writable=True),
167
+ help="Save transcript to file (md or json)",
168
+ )
169
+ @click.option(
170
+ "--file",
171
+ "files",
172
+ multiple=True,
173
+ type=click.Path(exists=True),
174
+ help="Attach file(s)",
175
+ )
176
+ @click.option(
177
+ "--verbose/--no-verbose",
178
+ default=False,
179
+ help="Show detailed SSE events during streaming",
180
+ )
181
+ @output_flags()
182
+ @click.pass_context
183
+ def run(
184
+ ctx: Any,
185
+ agent_ref: str,
186
+ select: int | None,
187
+ input_text: str | None,
188
+ input_option: str | None,
189
+ chat_history: str | None,
190
+ timeout: float | None,
191
+ save: str | None,
192
+ files: tuple[str, ...] | None,
193
+ verbose: bool,
194
+ ) -> None:
195
+ r"""Run an agent with input text.
196
+
197
+ Usage: aip agents run <agent_ref> <input_text> [OPTIONS]
198
+
199
+ \b
200
+ Examples:
201
+ aip agents run my-agent "Hello world"
202
+ aip agents run agent-123 "Process this data" --timeout 600
203
+ aip agents run my-agent --input "Hello world" # Legacy style
204
+ """
205
+ final_input_text = _validate_run_input(input_option, input_text)
206
+
207
+ if verbose:
208
+ _emit_verbose_guidance(ctx)
209
+ return
210
+
211
+ try:
212
+ client = get_client(ctx)
213
+ agent = _resolve_agent(ctx, client, agent_ref, select, interface_preference="fuzzy")
214
+
215
+ parsed_chat_history = _parse_chat_history(chat_history)
216
+ renderer, working_console = _setup_run_renderer(ctx, save, verbose)
217
+ _maybe_attach_transcript_toggle(ctx, renderer)
218
+
219
+ try:
220
+ client.timeout = float(timeout)
221
+ except Exception: # pragma: no cover # Defensive - timeout is int per Click, so float() always succeeds
222
+ pass
223
+
224
+ run_kwargs = _prepare_run_kwargs(
225
+ agent,
226
+ final_input_text,
227
+ files,
228
+ parsed_chat_history,
229
+ renderer,
230
+ bool(get_ctx_value(ctx, "tty", True)),
231
+ )
232
+
233
+ result = client.agents.run_agent(**run_kwargs, timeout=timeout)
234
+
235
+ slash_mode = _running_in_slash_mode(ctx)
236
+ agent_id = str(_safe_agent_attribute(agent, "id") or "") or None
237
+ agent_name = _safe_agent_attribute(agent, "name")
238
+ model_hint = _get_agent_model_name(agent)
239
+
240
+ transcript_context = store_transcript_for_session(
241
+ ctx,
242
+ renderer,
243
+ final_result=result,
244
+ agent_id=agent_id,
245
+ agent_name=agent_name,
246
+ model=model_hint,
247
+ source="slash" if slash_mode else "cli",
248
+ )
249
+
250
+ _handle_run_output(ctx, result, renderer)
251
+ _save_run_transcript(save, result, working_console)
252
+ maybe_launch_post_run_viewer(
253
+ ctx,
254
+ transcript_context,
255
+ console=console,
256
+ slash_mode=slash_mode,
257
+ )
258
+
259
+ except AgentTimeoutError as e:
260
+ error_msg = str(e)
261
+ handle_json_output(ctx, error=Exception(error_msg))
262
+ raise click.ClickException(error_msg) from e
263
+ except Exception as e:
264
+ _handle_command_exception(ctx, e)